diff options
author | Werner Koch <[email protected]> | 2003-07-16 13:47:14 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2003-07-16 13:47:14 +0000 |
commit | fa2faef48f4ed13d7701368ed2332170531e7c1b (patch) | |
tree | a4012045d1af575712d35d0e3e0047745556ef79 /scd/app-openpgp.c | |
parent | * simple-pwquery.c, simple-pwquery.h: New; moved from ../agent. (diff) | |
download | gnupg-fa2faef48f4ed13d7701368ed2332170531e7c1b.tar.gz gnupg-fa2faef48f4ed13d7701368ed2332170531e7c1b.zip |
* Makefile.am: Add sc-copykeys program.
* sc-copykeys.c: New.
* app-openpgp.c (app_openpgp_storekey): New.
(app_openpgp_cardinfo): New.
(count_bits): New.
(store_fpr): And use it here to get the actual length in bit.
Diffstat (limited to 'scd/app-openpgp.c')
-rw-r--r-- | scd/app-openpgp.c | 256 |
1 files changed, 250 insertions, 6 deletions
diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index b546ed569..1f9ec56f0 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -341,6 +341,25 @@ dump_all_do (int slot) } } + +/* Count the number of bits, assuming the A represents an unsigned big + integer of length LEN bytes. */ +static unsigned int +count_bits (const unsigned char *a, size_t len) +{ + unsigned int n = len * 8; + int i; + + for (; len && !*a; len--, a++, n -=8) + ; + if (len) + { + for (i=7; i && !(*a & (1<<i)); i--) + n--; + } + return n; +} + /* Note, that FPR must be at least 20 bytes. */ static int store_fpr (int slot, int keynumber, u32 timestamp, @@ -348,10 +367,15 @@ store_fpr (int slot, int keynumber, u32 timestamp, const unsigned char *e, size_t elen, unsigned char *fpr) { - unsigned int n; + unsigned int n, nbits;; unsigned char *buffer, *p; int rc; + for (; mlen && !*m; mlen--, m++) /* strip leading zeroes */ + ; + for (; elen && !*e; elen--, e++) /* strip leading zeroes */ + ; + n = 6 + 2 + mlen + 2 + elen; p = buffer = xtrymalloc (3 + n); if (!buffer) @@ -366,13 +390,16 @@ store_fpr (int slot, int keynumber, u32 timestamp, *p++ = timestamp >> 8; *p++ = timestamp; *p++ = 1; /* RSA */ - *p++ = (mlen*8) >> 8; /* (we want number of bits here) */ - *p++ = (mlen*8); + nbits = count_bits (m, mlen); + *p++ = nbits >> 8; + *p++ = nbits; memcpy (p, m, mlen); p += mlen; - *p++ = (elen*8) >> 8; - *p++ = (elen*8); + nbits = count_bits (e, elen); + *p++ = nbits >> 8; + *p++ = nbits; memcpy (p, e, elen); p += elen; + log_printhex ("fprbuf:", buffer, n+3); gcry_md_hash_buffer (GCRY_MD_SHA1, fpr, buffer, n+3); xfree (buffer); @@ -603,7 +630,7 @@ do_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags, } xfree (buffer); buffer = NULL; -#if 1 +#if 0 log_info ("please wait while key is being generated ...\n"); start_at = time (NULL); rc = iso7816_generate_keypair @@ -627,6 +654,7 @@ do_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags, keydata = find_tlv (buffer, buflen, 0x7F49, &keydatalen, 0); if (!keydata) { + rc = gpg_error (GPG_ERR_CARD); log_error ("response does not contain the public key data\n"); goto leave; } @@ -634,6 +662,7 @@ do_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags, m = find_tlv (keydata, keydatalen, 0x0081, &mlen, 0); if (!m) { + rc = gpg_error (GPG_ERR_CARD); log_error ("response does not contain the RSA modulus\n"); goto leave; } @@ -643,6 +672,7 @@ do_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags, e = find_tlv (keydata, keydatalen, 0x0082, &elen, 0); if (!e) { + rc = gpg_error (GPG_ERR_CARD); log_error ("response does not contain the RSA public exponent\n"); goto leave; } @@ -996,4 +1026,218 @@ leave: +/* This function is a hack to retrieve essential information about the + card to be displayed by simple tools. It mostly resembles what the + LEARN command returns. All parameters return allocated strings or + buffers or NULL if the data object is not available. All returned + values are sanitized. */ +int +app_openpgp_cardinfo (APP app, + char **serialno, + char **disp_name, + char **pubkey_url, + unsigned char **fpr1, + unsigned char **fpr2, + unsigned char **fpr3) +{ + int rc; + void *relptr; + unsigned char *value; + size_t valuelen; + + if (serialno) + { + time_t dummy; + *serialno = NULL; + rc = app_get_serial_and_stamp (app, serialno, &dummy); + if (rc) + { + log_error ("error getting serial number: %s\n", gpg_strerror (rc)); + return rc; + } + } + + if (disp_name) + { + *disp_name = NULL; + relptr = get_one_do (app->slot, 0x005B, &value, &valuelen); + if (relptr) + { + *disp_name = make_printable_string (value, valuelen, 0); + xfree (relptr); + } + } + + if (pubkey_url) + { + *pubkey_url = NULL; + relptr = get_one_do (app->slot, 0x5F50, &value, &valuelen); + if (relptr) + { + *pubkey_url = make_printable_string (value, valuelen, 0); + xfree (relptr); + } + } + + if (fpr1) + *fpr1 = NULL; + if (fpr2) + *fpr2 = NULL; + if (fpr3) + *fpr3 = NULL; + relptr = get_one_do (app->slot, 0x00C5, &value, &valuelen); + if (relptr && valuelen >= 60) + { + if (fpr1) + { + *fpr1 = xmalloc (20); + memcpy (*fpr1, value + 0, 20); + } + if (fpr2) + { + *fpr2 = xmalloc (20); + memcpy (*fpr2, value + 20, 20); + } + if (fpr3) + { + *fpr3 = xmalloc (20); + memcpy (*fpr3, value + 40, 20); + } + } + xfree (relptr); + + return 0; +} + + + +/* This function is currently only used by the sc-copykeys program to + store a key on the smartcard. APP ist the application handle, + KEYNO is the number of the key and PINCB, PINCB_ARG are used to ask + for the SO PIN. TEMPLATE and TEMPLATE_LEN describe a buffer with + the key template to store. CREATED_AT is the timestamp used to + create the fingerprint. M, MLEN is the RSA modulus and E, ELEN the + RSA public exponent. This function silently overwrites an existing + key.*/ +int +app_openpgp_storekey (APP app, int keyno, + unsigned char *template, size_t template_len, + time_t created_at, + const unsigned char *m, size_t mlen, + const unsigned char *e, size_t elen, + int (*pincb)(void*, const char *, char **), + void *pincb_arg) +{ + int rc; + unsigned char fprbuf[20]; + + if (keyno < 1 || keyno > 3) + return gpg_error (GPG_ERR_INV_ID); + keyno--; + + { + char *pinvalue; + rc = pincb (pincb_arg, "Admin PIN", &pinvalue); + if (rc) + { + log_error ("error getting PIN: %s\n", gpg_strerror (rc)); + return rc; + } + rc = iso7816_verify (app->slot, 0x83, pinvalue, strlen (pinvalue)); + xfree (pinvalue); + } + if (rc) + { + log_error ("verify CHV3 failed: rc=%04X\n", rc); + goto leave; + } + + rc = iso7816_put_data (app->slot, 0xE9 + keyno, template, template_len); + if (rc) + { + log_error ("failed to store the key: rc=%04X\n", rc); + rc = gpg_error (GPG_ERR_CARD); + goto leave; + } + + log_printhex ("RSA n:", m, mlen); + log_printhex ("RSA e:", e, elen); + + rc = store_fpr (app->slot, keyno, (u32)created_at, + m, mlen, e, elen, fprbuf); + + leave: + return rc; +} + + +/* Utility function for external tools: Read the public RSA key at + KEYNO and return modulus and exponent in (M,MLEN) and (E,ELEN). */ +int +app_openpgp_readkey (APP app, int keyno, unsigned char **m, size_t *mlen, + unsigned char **e, size_t *elen) +{ + int rc; + const unsigned char *keydata, *a; + unsigned char *buffer; + size_t buflen, keydatalen, alen; + + *m = NULL; + *e = NULL; + + if (keyno < 1 || keyno > 3) + return gpg_error (GPG_ERR_INV_ID); + keyno--; + + rc = iso7816_read_public_key(app->slot, + keyno == 0? "\xB6" : + keyno == 1? "\xB8" : "\xA4", + 2, + &buffer, &buflen); + if (rc) + { + rc = gpg_error (GPG_ERR_CARD); + log_error ("reading key failed\n"); + goto leave; + } + + keydata = find_tlv (buffer, buflen, 0x7F49, &keydatalen, 0); + if (!keydata) + { + log_error ("response does not contain the public key data\n"); + rc = gpg_error (GPG_ERR_CARD); + goto leave; + } + + a = find_tlv (keydata, keydatalen, 0x0081, &alen, 0); + if (!a) + { + log_error ("response does not contain the RSA modulus\n"); + rc = gpg_error (GPG_ERR_CARD); + goto leave; + } + *mlen = alen; + *m = xmalloc (alen); + memcpy (*m, a, alen); + + a = find_tlv (keydata, keydatalen, 0x0082, &alen, 0); + if (!e) + { + log_error ("response does not contain the RSA public exponent\n"); + rc = gpg_error (GPG_ERR_CARD); + goto leave; + } + *elen = alen; + *e = xmalloc (alen); + memcpy (*e, a, alen); + + leave: + xfree (buffer); + if (rc) + { + xfree (*m); *m = NULL; + xfree (*e); *e = NULL; + } + return rc; +} |