diff --git a/g10/ChangeLog b/g10/ChangeLog index 23f5db587..324b96e07 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,14 @@ +2003-10-09 Werner Koch + + * ccid-driver.c (ccid_transceive): Add T=1 chaining for sending. + + * sign.c (do_sign) [!ENABLE_CARD_SUPPORT]: Return an error for + card keys. + + * cardglue.c (agent_scd_pkdecrypt): Implemented. + * pubkey-enc.c (get_it) [ENABLE_CARD_SUPPORT]: Divert decryption + to card + 2003-10-08 Werner Koch * cardglue.c (pin_cb): Detect whether an admin or regular PIN is diff --git a/g10/cardglue.c b/g10/cardglue.c index fd7cf8b3d..91637a776 100644 --- a/g10/cardglue.c +++ b/g10/cardglue.c @@ -631,10 +631,21 @@ agent_scd_pksign (const char *serialno, int hashalgo, int agent_scd_pkdecrypt (const char *serialno, const unsigned char *indata, size_t indatalen, - char **r_buf, size_t *r_buflen) + unsigned char **r_buf, size_t *r_buflen) { - return gpg_error (GPG_ERR_CARD); + APP app; + + *r_buf = NULL; + *r_buflen = 0; + app = current_app? current_app : open_card (); + if (!app) + return gpg_error (GPG_ERR_CARD); + + return app->fnc.decipher (app, serialno, + pin_cb, NULL, + indata, indatalen, + r_buf, r_buflen); } /* Change the PIN of an OpenPGP card or reset the retry counter. */ diff --git a/g10/cardglue.h b/g10/cardglue.h index 273b99313..fcd372682 100644 --- a/g10/cardglue.h +++ b/g10/cardglue.h @@ -151,7 +151,7 @@ int agent_scd_pksign (const char *keyid, int hashalgo, /* Send a PKDECRYPT command to the SCdaemon. */ int agent_scd_pkdecrypt (const char *serialno, const unsigned char *indata, size_t indatalen, - char **r_buf, size_t *r_buflen); + unsigned char **r_buf, size_t *r_buflen); /* Change the PIN of an OpenPGP card or reset the retry counter. */ int agent_scd_change_pin (int chvno); diff --git a/g10/ccid-driver.c b/g10/ccid-driver.c index b4fbc0b21..35f0329db 100644 --- a/g10/ccid-driver.c +++ b/g10/ccid-driver.c @@ -132,6 +132,11 @@ #endif /* This source not used by scdaemon. */ +/* Define to print information pertaining the T=1 protocol. */ +#undef DEBUG_T1 1 + + + enum { RDR_to_PC_NotifySlotChange= 0x50, RDR_to_PC_HardwareError = 0x51, @@ -566,7 +571,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, return -1; } - DEBUGOUT_3 ("status: %02X error: %02X clock-status: %02X\n" + DEBUGOUT_3 ("status: %02X error: %02X octet[9]: %02X\n" " data:", buffer[7], buffer[8], buffer[9] ); for (i=10; i < msglen; i++) DEBUGOUT_CONT_1 (" %02X", buffer[i]); @@ -753,44 +758,62 @@ ccid_get_atr (ccid_driver_t handle, int ccid_transceive (ccid_driver_t handle, - const unsigned char *apdu, size_t apdulen, + const unsigned char *apdu_buf, size_t apdu_buflen, unsigned char *resp, size_t maxresplen, size_t *nresp) { int rc; unsigned char send_buffer[10+258], recv_buffer[10+258]; + const unsigned char *apdu; + size_t apdulen; unsigned char *msg, *tpdu, *p; size_t msglen, tpdulen, n; unsigned char seqno; int i; unsigned char crc; size_t dummy_nresp; + int next_chunk = 1; int sending = 1; if (!nresp) nresp = &dummy_nresp; - *nresp = 0; - - /* Construct an I-Block. */ - if (apdulen > 254) - return -1; /* Invalid length. */ + tpdulen = 0; /* Avoid compiler warning about no initialization. */ msg = send_buffer; - - tpdu = msg+10; - tpdu[0] = ((1 << 4) | 0); /* NAD: DAD=1, SAD=0 */ - tpdu[1] = ((handle->t1_ns & 1) << 6); /* I-block */ - tpdu[2] = apdulen; - memcpy (tpdu+3, apdu, apdulen); - crc = 0; - for (i=0,p=tpdu; i < apdulen+3; i++) - crc ^= *p++; - tpdu[3+apdulen] = crc; - - tpdulen = apdulen + 4; - for (;;) { + if (next_chunk) + { + next_chunk = 0; + + apdu = apdu_buf; + apdulen = apdu_buflen; + assert (apdulen); + + /* Construct an I-Block. */ + if (apdulen > 254) + return -1; /* Invalid length. */ + + tpdu = msg+10; + tpdu[0] = ((1 << 4) | 0); /* NAD: DAD=1, SAD=0 */ + tpdu[1] = ((handle->t1_ns & 1) << 6); /* I-block */ + if (apdulen > 128 /* fixme: replace by ifsc */) + { + apdulen = 128; + apdu_buf += 128; + apdu_buflen -= 128; + tpdu[1] |= (1 << 5); /* Set more bit. */ + } + tpdu[2] = apdulen; + memcpy (tpdu+3, apdu, apdulen); + crc = 0; + for (i=0,p=tpdu; i < apdulen+3; i++) + crc ^= *p++; + tpdu[3+apdulen] = crc; + + tpdulen = apdulen + 4; + } + msg[0] = PC_to_RDR_XfrBlock; msg[5] = 0; /* slot */ msg[6] = seqno = handle->seqno++; @@ -804,12 +827,14 @@ ccid_transceive (ccid_driver_t handle, for (i=0; i < msglen; i++) DEBUGOUT_CONT_1 (" %02X", msg[i]); DEBUGOUT_LF (); - -/* fprintf (stderr, "T1: put %c-block seq=%d\n", */ -/* ((msg[11] & 0xc0) == 0x80)? 'R' : */ -/* (msg[11] & 0x80)? 'S' : 'I', */ -/* ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40))); */ - + +#ifdef DEBUG_T1 + fprintf (stderr, "T1: put %c-block seq=%d\n", + ((msg[11] & 0xc0) == 0x80)? 'R' : + (msg[11] & 0x80)? 'S' : 'I', + ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40))); +#endif + rc = bulk_out (handle, msg, msglen); if (rc) return rc; @@ -829,12 +854,14 @@ ccid_transceive (ccid_driver_t handle, return -1; } -/* fprintf (stderr, "T1: got %c-block seq=%d err=%d\n", */ -/* ((msg[11] & 0xc0) == 0x80)? 'R' : */ -/* (msg[11] & 0x80)? 'S' : 'I', */ -/* ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)), */ -/* ((msg[11] & 0xc0) == 0x80)? (msg[11] & 0x0f) : 0 */ -/* ); */ +#ifdef DEBUG_T1 + fprintf (stderr, "T1: got %c-block seq=%d err=%d\n", + ((msg[11] & 0xc0) == 0x80)? 'R' : + (msg[11] & 0x80)? 'S' : 'I', + ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)), + ((msg[11] & 0xc0) == 0x80)? (msg[11] & 0x0f) : 0 + ); +#endif if (!(tpdu[1] & 0x80)) { /* This is an I-block. */ @@ -899,9 +926,20 @@ ccid_transceive (ccid_driver_t handle, { /* Error: repeat last block */ msg = send_buffer; } + else if (sending && !!(tpdu[1] & 0x40) == handle->t1_ns) + { /* Reponse does not match our sequence number. */ + DEBUGOUT ("R-block with wrong seqno received on more bit\n"); + return -1; + } + else if (sending) + { /* Send next chunk. */ + msg = send_buffer; + next_chunk = 1; + handle->t1_ns ^= 1; + } else { - DEBUGOUT ("unxpectec ACK R-block received\n"); + DEBUGOUT ("unexpected ACK R-block received\n"); return -1; } } diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c index 4e02cedc4..d61bd0125 100644 --- a/g10/pubkey-enc.c +++ b/g10/pubkey-enc.c @@ -34,6 +34,7 @@ #include "options.h" #include "main.h" #include "i18n.h" +#include "cardglue.h" static int get_it( PKT_pubkey_enc *k, DEK *dek, PKT_secret_key *sk, u32 *keyid ); @@ -132,17 +133,51 @@ get_session_key( PKT_pubkey_enc *k, DEK *dek ) static int get_it( PKT_pubkey_enc *enc, DEK *dek, PKT_secret_key *sk, u32 *keyid ) { - int rc; - MPI plain_dek = NULL; - byte *frame = NULL; - unsigned n, nframe; - u16 csum, csum2; + int rc; + MPI plain_dek = NULL; + byte *frame = NULL; + unsigned n, nframe; + u16 csum, csum2; + + int card = 0; - rc = pubkey_decrypt(sk->pubkey_algo, &plain_dek, enc->data, sk->skey ); - if( rc ) + if (sk->is_protected && sk->protect.s2k.mode == 1002) + { /* Note, that we only support RSA for now. */ +#ifdef ENABLE_CARD_SUPPORT + unsigned char *rbuf; + size_t rbuflen; + char *snbuf; + unsigned char *indata = NULL; + unsigned int indatalen; + + snbuf = serialno_and_fpr_from_sk (sk->protect.iv, sk->protect.ivlen, sk); + + indata = mpi_get_buffer (enc->data[0], &indatalen, NULL); + if (!indata) + BUG (); + + rc = agent_scd_pkdecrypt (snbuf, indata, indatalen, &rbuf, &rbuflen); + xfree (snbuf); + xfree (indata); + if (rc) + goto leave; + + frame = rbuf; + nframe = rbuflen; + card = 1; +#else + rc = G10ERR_UNSUPPORTED; + goto leave; +#endif /*!ENABLE_CARD_SUPPORT*/ + } + else + { + rc = pubkey_decrypt(sk->pubkey_algo, &plain_dek, enc->data, sk->skey ); + if( rc ) goto leave; - frame = mpi_get_buffer( plain_dek, &nframe, NULL ); - mpi_free( plain_dek ); plain_dek = NULL; + frame = mpi_get_buffer( plain_dek, &nframe, NULL ); + mpi_free( plain_dek ); plain_dek = NULL; + } /* Now get the DEK (data encryption key) from the frame * @@ -164,18 +199,22 @@ get_it( PKT_pubkey_enc *enc, DEK *dek, PKT_secret_key *sk, u32 *keyid ) if( DBG_CIPHER ) log_hexdump("DEK frame:", frame, nframe ); n=0; - if( n + 7 > nframe ) - { rc = G10ERR_WRONG_SECKEY; goto leave; } - if( frame[n] == 1 && frame[nframe-1] == 2 ) { - log_info(_("old encoding of the DEK is not supported\n")); - rc = G10ERR_CIPHER_ALGO; - goto leave; - } - if( frame[n] != 2 ) /* somethink is wrong */ - { rc = G10ERR_WRONG_SECKEY; goto leave; } - for(n++; n < nframe && frame[n]; n++ ) /* skip the random bytes */ - ; - n++; /* and the zero byte */ + if (!card) + { + if( n + 7 > nframe ) + { rc = G10ERR_WRONG_SECKEY; goto leave; } + if( frame[n] == 1 && frame[nframe-1] == 2 ) { + log_info(_("old encoding of the DEK is not supported\n")); + rc = G10ERR_CIPHER_ALGO; + goto leave; + } + if( frame[n] != 2 ) /* somethink is wrong */ + { rc = G10ERR_WRONG_SECKEY; goto leave; } + for(n++; n < nframe && frame[n]; n++ ) /* skip the random bytes */ + ; + n++; /* and the zero byte */ + } + if( n + 4 > nframe ) { rc = G10ERR_WRONG_SECKEY; goto leave; } diff --git a/g10/sign.c b/g10/sign.c index 9826c2abf..3bfe602b2 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -306,9 +306,9 @@ do_sign( PKT_secret_key *sk, PKT_signature *sig, sig->digest_algo = digest_algo; sig->digest_start[0] = dp[0]; sig->digest_start[1] = dp[1]; -#ifdef ENABLE_CARD_SUPPORT if (sk->is_protected && sk->protect.s2k.mode == 1002) { +#ifdef ENABLE_CARD_SUPPORT unsigned char *rbuf; size_t rbuflen; char *snbuf; @@ -327,9 +327,11 @@ do_sign( PKT_secret_key *sk, PKT_signature *sig, mpi_set_buffer (sig->data[0], rbuf, rbuflen, 0); xfree (rbuf); } +#else + return G10ERR_UNSUPPORTED; +#endif /* ENABLE_CARD_SUPPORT */ } else -#endif /* ENABLE_CARD_SUPPORT */ { frame = encode_md_value( sk->pubkey_algo, md, digest_algo, mpi_get_nbits(sk->skey[0]), 0 );