1
0
Fork 0
mirror of git://git.gnupg.org/gnupg.git synced 2025-07-02 22:46:30 +02:00

* cardglue.c (send_status_info): Make CTRL optional.

(agent_scd_writekey, inq_writekey_parms): New.
(agent_openpgp_storekey): Removed.
* cardglue.h: Add a few more error code mappings.
* keygen.c (copy_mpi): Removed.
(save_unprotected_key_to_card): Changed to use agent_scd_writekey.
* app-common.h, app-openpgp.c, tlv.c, tlv.h: Updated from newer
version in gnupg 1.9 CVS.
This commit is contained in:
Werner Koch 2005-05-21 14:04:32 +00:00
parent bd644c8d45
commit be2aa37dbf
18 changed files with 724 additions and 209 deletions

View file

@ -1,3 +1,14 @@
2005-05-21 Werner Koch <wk@g10code.com>
* cardglue.c (send_status_info): Make CTRL optional.
(agent_scd_writekey, inq_writekey_parms): New.
(agent_openpgp_storekey): Removed.
* cardglue.h: Add a few more error code mappings.
* keygen.c (copy_mpi): Removed.
(save_unprotected_key_to_card): Changed to use agent_scd_writekey.
* app-common.h, app-openpgp.c, tlv.c, tlv.h: Updated from newer
version in gnupg 1.9 CVS.
2005-05-20 Werner Koch <wk@g10code.com>
* ccid-driver.c (ccid_transceive): Arghhh. The seqno is another

View file

@ -86,6 +86,11 @@ struct app_ctx_s {
void *pincb_arg,
const void *indata, size_t indatalen,
unsigned char **outdata, size_t *outdatalen);
gpg_error_t (*writekey) (app_t app, ctrl_t ctrl,
const char *certid, unsigned int flags,
gpg_error_t (*pincb)(void*,const char *,char **),
void *pincb_arg,
const unsigned char *pk, size_t pklen);
gpg_error_t (*genkey) (app_t app, ctrl_t ctrl,
const char *keynostr, unsigned int flags,
gpg_error_t (*pincb)(void*, const char *, char **),
@ -148,6 +153,11 @@ gpg_error_t app_decipher (app_t app, const char *keyidstr,
void *pincb_arg,
const void *indata, size_t indatalen,
unsigned char **outdata, size_t *outdatalen );
gpg_error_t app_writekey (app_t app, ctrl_t ctrl,
const char *keyidstr, unsigned int flags,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg,
const unsigned char *keydata, size_t keydatalen);
gpg_error_t app_genkey (app_t app, ctrl_t ctrl,
const char *keynostr, unsigned int flags,
gpg_error_t (*pincb)(void*, const char *, char **),

View file

@ -565,7 +565,7 @@ store_fpr (int slot, int keynumber, u32 timestamp,
n = 6 + 2 + mlen + 2 + elen;
p = buffer = xtrymalloc (3 + n);
if (!buffer)
return gpg_error (gpg_err_code_from_errno (errno));
return gpg_error_from_errno (errno);
*p++ = 0x99; /* ctb */
*p++ = n >> 8; /* 2 byte length header */
@ -1527,6 +1527,318 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr, int reset_mode,
}
/* Check whether a key already exists. KEYIDX is the index of the key
(0..2). If FORCE is TRUE a diagnositivc will be printed but no
error returned if the key already exists. */
static gpg_error_t
does_key_exist (app_t app, int keyidx, int force)
{
const unsigned char *fpr;
unsigned char *buffer;
size_t buflen, n;
int i;
assert (keyidx >=0 && keyidx <= 2);
if (iso7816_get_data (app->slot, 0x006E, &buffer, &buflen))
{
log_error (_("error reading application data\n"));
return gpg_error (GPG_ERR_GENERAL);
}
fpr = find_tlv (buffer, buflen, 0x00C5, &n);
if (!fpr || n < 60)
{
log_error (_("error reading fingerprint DO\n"));
xfree (buffer);
return gpg_error (GPG_ERR_GENERAL);
}
fpr += 20*keyidx;
for (i=0; i < 20 && !fpr[i]; i++)
;
xfree (buffer);
if (i!=20 && !force)
{
log_error (_("key already exists\n"));
return gpg_error (GPG_ERR_EEXIST);
}
else if (i!=20)
log_info (_("existing key will be replaced\n"));
else
log_info (_("generating new key\n"));
return 0;
}
/* Handle the WRITEKEY command for OpenPGP. This function expects a
canonical encoded S-expression with the secret key in KEYDATA and
its length (for assertions) in KEYDATALEN. KEYID needs to be the
usual keyid which for OpenPGP is the string "OPENPGP.n" with
n=1,2,3. Bit 0 of FLAGS indicates whether an existing key shall
get overwritten. PINCB and PINCB_ARG are the usual arguments for
the pinentry callback. */
static gpg_error_t
do_writekey (app_t app, ctrl_t ctrl,
const char *keyid, unsigned int flags,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg,
const unsigned char *keydata, size_t keydatalen)
{
gpg_error_t err;
int force = (flags & 1);
int keyno;
const unsigned char *buf, *tok;
size_t buflen, toklen;
int depth, last_depth1, last_depth2;
const unsigned char *rsa_n = NULL;
const unsigned char *rsa_e = NULL;
const unsigned char *rsa_p = NULL;
const unsigned char *rsa_q = NULL;
size_t rsa_n_len, rsa_e_len, rsa_p_len, rsa_q_len;
unsigned int nbits;
unsigned char *template = NULL;
unsigned char *tp;
size_t template_len;
unsigned char fprbuf[20];
u32 created_at = 0;
if (!strcmp (keyid, "OPENPGP.1"))
keyno = 0;
else if (!strcmp (keyid, "OPENPGP.2"))
keyno = 1;
else if (!strcmp (keyid, "OPENPGP.3"))
keyno = 2;
else
return gpg_error (GPG_ERR_INV_ID);
err = does_key_exist (app, keyno, force);
if (err)
return err;
/*
Parse the S-expression
*/
buf = keydata;
buflen = keydatalen;
depth = 0;
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
goto leave;
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
goto leave;
if (!tok || toklen != 11 || memcmp ("private-key", tok, toklen))
{
if (!tok)
;
else if (toklen == 21 && !memcmp ("protected-private-key", tok, toklen))
log_info ("protected-private-key passed to writekey\n");
else if (toklen == 20 && !memcmp ("shadowed-private-key", tok, toklen))
log_info ("shadowed-private-key passed to writekey\n");
err = gpg_error (GPG_ERR_BAD_SECKEY);
goto leave;
}
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
goto leave;
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
goto leave;
if (!tok || toklen != 3 || memcmp ("rsa", tok, toklen))
{
err = gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
goto leave;
}
last_depth1 = depth;
while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
&& depth && depth >= last_depth1)
{
if (tok)
{
err = gpg_error (GPG_ERR_UNKNOWN_SEXP);
goto leave;
}
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
goto leave;
if (tok && toklen == 1)
{
const unsigned char **mpi;
size_t *mpi_len;
switch (*tok)
{
case 'n': mpi = &rsa_n; mpi_len = &rsa_n_len; break;
case 'e': mpi = &rsa_e; mpi_len = &rsa_e_len; break;
case 'p': mpi = &rsa_p; mpi_len = &rsa_p_len; break;
case 'q': mpi = &rsa_q; mpi_len = &rsa_q_len;break;
default: mpi = NULL; mpi_len = NULL; break;
}
if (mpi && *mpi)
{
err = gpg_error (GPG_ERR_DUP_VALUE);
goto leave;
}
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
goto leave;
if (tok && mpi)
{
/* Strip off leading zero bytes and save. */
for (;toklen && !*tok; toklen--, tok++)
;
*mpi = tok;
*mpi_len = toklen;
}
}
/* Skip until end of list. */
last_depth2 = depth;
while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
&& depth && depth >= last_depth2)
;
if (err)
goto leave;
}
/* Parse other attributes. */
last_depth1 = depth;
while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
&& depth && depth >= last_depth1)
{
if (tok)
{
err = gpg_error (GPG_ERR_UNKNOWN_SEXP);
goto leave;
}
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
goto leave;
if (tok && toklen == 10 && !memcmp ("created-at", tok, toklen))
{
if ((err = parse_sexp (&buf,&buflen,&depth,&tok,&toklen)))
goto leave;
if (tok)
{
for (created_at=0; toklen && *tok && *tok >= '0' && *tok <= '9';
tok++, toklen--)
created_at = created_at*10 + (*tok - '0');
}
}
/* Skip until end of list. */
last_depth2 = depth;
while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
&& depth && depth >= last_depth2)
;
if (err)
goto leave;
}
/* Check that we have all parameters and that they match the card
description. */
if (!created_at)
{
log_error (_("creation timestamp missing\n"));
err = gpg_error (GPG_ERR_INV_VALUE);
goto leave;
}
nbits = rsa_n? count_bits (rsa_n, rsa_n_len) : 0;
if (nbits != 1024)
{
log_error (_("RSA modulus missing or not of size %d bits\n"), 1024);
err = gpg_error (GPG_ERR_BAD_SECKEY);
goto leave;
}
nbits = rsa_e? count_bits (rsa_e, rsa_e_len) : 0;
if (nbits < 2 || nbits > 32)
{
log_error (_("RSA public exponent missing or largerr than %d bits\n"),
32);
err = gpg_error (GPG_ERR_BAD_SECKEY);
goto leave;
}
nbits = rsa_p? count_bits (rsa_p, rsa_p_len) : 0;
if (nbits != 512)
{
log_error (_("RSA prime %s missing or not of size %d bits\n"), "P", 512);
err = gpg_error (GPG_ERR_BAD_SECKEY);
goto leave;
}
nbits = rsa_q? count_bits (rsa_q, rsa_q_len) : 0;
if (nbits != 512)
{
log_error (_("RSA prime %s missing or not of size %d bits\n"), "Q", 512);
err = gpg_error (GPG_ERR_BAD_SECKEY);
goto leave;
}
/* Build the private key template as described in section 4.3.3.6 of
the OpenPGP card specs:
0xC0 <length> public exponent
0xC1 <length> prime p
0xC2 <length> prime q
*/
assert (rsa_e_len <= 4);
template_len = (1 + 1 + 4
+ 1 + 1 + rsa_p_len
+ 1 + 1 + rsa_q_len);
template = tp = xtrymalloc_secure (template_len);
if (!template)
{
err = gpg_error_from_errno (errno);
goto leave;
}
*tp++ = 0xC0;
*tp++ = 4;
memcpy (tp, rsa_e, rsa_e_len);
if (rsa_e_len < 4)
{
/* Right justify E. */
memmove (tp+4-rsa_e_len, tp, 4-rsa_e_len);
memset (tp, 0, 4-rsa_e_len);
}
tp += 4;
*tp++ = 0xC1;
*tp++ = rsa_p_len;
memcpy (tp, rsa_p, rsa_p_len);
tp += rsa_p_len;
*tp++ = 0xC2;
*tp++ = rsa_q_len;
memcpy (tp, rsa_q, rsa_q_len);
tp += rsa_q_len;
assert (tp - template == template_len);
/* Obviously we need to remove the cached public key. */
xfree (app->app_local->pk[keyno].key);
app->app_local->pk[keyno].key = NULL;
app->app_local->pk[keyno].keylen = 0;
app->app_local->pk[keyno].read_done = 0;
/* Prepare for storing the key. */
err = verify_chv3 (app, pincb, pincb_arg);
if (err)
goto leave;
/* Store the key. */
err = iso7816_put_data (app->slot,
(app->card_version > 0x0007? 0xE0 : 0xE9) + keyno,
template, template_len);
if (err)
{
log_error (_("failed to store the key: %s\n"), gpg_strerror (err));
goto leave;
}
err = store_fpr (app->slot, keyno, created_at,
rsa_n, rsa_n_len, rsa_e, rsa_e_len,
fprbuf, app->card_version);
if (err)
goto leave;
leave:
xfree (template);
return err;
}
/* Handle the GENKEY command. */
static gpg_error_t
@ -1535,13 +1847,11 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
void *pincb_arg)
{
int rc;
int i;
char numbuf[30];
unsigned char fprbuf[20];
const unsigned char *fpr;
const unsigned char *keydata, *m, *e;
unsigned char *buffer;
size_t buflen, keydatalen, n, mlen, elen;
unsigned char *buffer = NULL;
size_t buflen, keydatalen, mlen, elen;
time_t created_at;
int keyno = atoi (keynostr);
int force = (flags & 1);
@ -1562,41 +1872,15 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
app->app_local->pk[keyno].read_done = 0;
/* Check whether a key already exists. */
rc = iso7816_get_data (app->slot, 0x006E, &buffer, &buflen);
rc = does_key_exist (app, keyno, force);
if (rc)
{
log_error (_("error reading application data\n"));
return gpg_error (GPG_ERR_GENERAL);
}
fpr = find_tlv (buffer, buflen, 0x00C5, &n);
if (!fpr || n != 60)
{
rc = gpg_error (GPG_ERR_GENERAL);
log_error (_("error reading fingerprint DO\n"));
goto leave;
}
fpr += 20*keyno;
for (i=0; i < 20 && !fpr[i]; i++)
;
if (i!=20 && !force)
{
rc = gpg_error (GPG_ERR_EEXIST);
log_error (_("key already exists\n"));
goto leave;
}
else if (i!=20)
log_info (_("existing key will be replaced\n"));
else
log_info (_("generating new key\n"));
return rc;
/* Prepare for key generation by verifying the ADmin PIN. */
rc = verify_chv3 (app, pincb, pincb_arg);
if (rc)
goto leave;
xfree (buffer); buffer = NULL;
#if 1
log_info (_("please wait while key is being generated ...\n"));
start_at = time (NULL);
@ -2220,6 +2504,7 @@ app_select_openpgp (app_t app)
app->fnc.readkey = do_readkey;
app->fnc.getattr = do_getattr;
app->fnc.setattr = do_setattr;
app->fnc.writekey = do_writekey;
app->fnc.genkey = do_genkey;
app->fnc.sign = do_sign;
app->fnc.auth = do_auth;

View file

@ -63,6 +63,15 @@ struct pincb_parm_s
};
struct writekey_parm_s
{
assuan_context_t ctx;
const unsigned char *keydata;
size_t keydatalen;
};
static char *default_reader_port;
static app_t current_app;
@ -100,7 +109,7 @@ serialno_and_fpr_from_sk (const unsigned char *sn, size_t snlen,
buffers. The variable elements are pairs of (char *, size_t),
terminated with a (NULL, 0). */
void
send_status_info (CTRL ctrl, const char *keyword, ...)
send_status_info (ctrl_t ctrl, const char *keyword, ...)
{
va_list arg_ptr;
const unsigned char *value;
@ -140,7 +149,8 @@ send_status_info (CTRL ctrl, const char *keyword, ...)
}
}
*p = 0;
ctrl->status_cb (ctrl->status_cb_arg, buf);
if (ctrl && ctrl->status_cb)
ctrl->status_cb (ctrl->status_cb_arg, buf);
va_end (arg_ptr);
}
@ -970,6 +980,59 @@ agent_scd_setattr (const char *name,
}
/* Handle a KEYDATA inquiry. Note, we only send the data,
assuan_transact takes care of flushing and writing the end */
static assuan_error_t
inq_writekey_parms (void *opaque, const char *keyword)
{
struct writekey_parm_s *parm = opaque;
return assuan_send_data (parm->ctx, parm->keydata, parm->keydatalen);
}
/* Send a WRITEKEY command to the SCdaemon. */
int
agent_scd_writekey (int keyno, const unsigned char *keydata, size_t keydatalen)
{
app_t app;
int rc;
char line[ASSUAN_LINELENGTH];
app = current_app? current_app : open_card ();
if (!app)
return gpg_error (GPG_ERR_CARD);
if (app->assuan_ctx)
{
struct writekey_parm_s parms;
snprintf (line, DIM(line)-1, "SCD WRITEKEY --force OPENPGP.%d", keyno);
line[DIM(line)-1] = 0;
parms.ctx = app->assuan_ctx;
parms.keydata = keydata;
parms.keydatalen = keydatalen;
rc = test_transact (assuan_transact (app->assuan_ctx, line,
NULL, NULL,
inq_writekey_parms, &parms,
NULL, NULL),
"SCD WRITEKEY");
}
else
{
snprintf (line, DIM(line)-1, "OPENPGP.%d", keyno);
line[DIM(line)-1] = 0;
rc = app->fnc.writekey (app, NULL, line, 0x0001,
pin_cb, NULL,
keydata, keydatalen);
}
if (rc)
write_status (STATUS_SC_OP_FAILURE);
return rc;
}
static assuan_error_t
genkey_status_cb (void *opaque, const char *line)
{
@ -1281,37 +1344,6 @@ agent_scd_checkpin (const char *serialnobuf)
}
/* Wrapper to call the store key helper function of app-openpgp.c. */
int
agent_openpgp_storekey (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)
{
app_t app;
int rc;
app = current_app? current_app : open_card ();
if (!app)
return gpg_error (GPG_ERR_CARD);
if (app->assuan_ctx)
{
rc = gpg_error (GPG_ERR_CARD);
}
else
{
rc = app_openpgp_storekey (app, keyno, template, template_len,
created_at, m, mlen, e, elen,
pin_cb, NULL);
}
if (rc)
write_status (STATUS_SC_OP_FAILURE);
return rc;
}
void
agent_clear_pin_cache (const char *sn)

View file

@ -81,6 +81,7 @@ typedef struct ctrl_ctx_s *ctrl_t;
#define GPG_ERR_GENERAL G10ERR_GENERAL
#define GPG_ERR_BAD_PIN G10ERR_BAD_PASS
#define GPG_ERR_BAD_KEy G10ERR_BAD_KEY
#define GPG_ERR_CARD G10ERR_GENERAL
#define GPG_ERR_EEXIST G10ERR_FILE_EXISTS
#define GPG_ERR_ENOMEM G10ERR_RESOURCE_LIMIT
@ -105,6 +106,10 @@ typedef struct ctrl_ctx_s *ctrl_t;
#define GPG_ERR_EOF (-1)
#define GPG_ERR_CARD_NOT_PRESENT G10ERR_NO_CARD
#define GPG_ERR_CARD_RESET G10ERR_GENERAL
#define GPG_ERR_WRONG_PUBKEY_ALGO G10ERR_PUBKEY_ALGO
#define GPG_ERR_UNKNOWN_SEXP G10ERR_INV_ARG
#define GPG_ERR_DUP_VALUE G10ERR_INV_ARG
#define GPG_ERR_BAD_SECKEY G10ERR_BAD_SECKEY
#define GPG_ERR_EBUSY G10ERR_GENERAL
#define GPG_ERR_ENOENT G10ERR_OPEN_FILE
@ -129,6 +134,7 @@ typedef int gpg_err_code_t;
#define xtrymalloc(n) xmalloc((n))
#define xtrycalloc(n,m) xcalloc((n),(m))
#define xtryrealloc(n,m) xrealloc((n),(m))
#define xtrymalloc_secure(n) xmalloc_secure((n))
#define out_of_core() (-1)
#define gnupg_get_time() make_timestamp ()
@ -168,6 +174,10 @@ int agent_scd_getattr (const char *name, struct agent_card_info_s *info);
int agent_scd_setattr (const char *name,
const unsigned char *value, size_t valuelen);
/* Send a WRITEKEY command to the SCdaemon. */
int agent_scd_writekey (int keyno,
const unsigned char *keydata, size_t keydatalen);
/* Send a GENKEY command to the SCdaemon. */
int agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force);
@ -187,13 +197,6 @@ int agent_scd_change_pin (int chvno);
/* Send a CHECKPIN command. */
int agent_scd_checkpin (const char *serialnobuf);
/* Call the store key utility command. */
int agent_openpgp_storekey (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);
/* Clear a cached PIN. */
void agent_clear_pin_cache (const char *sn);

View file

@ -128,42 +128,6 @@ static int gen_card_key_with_backup (int algo, int keyno, int is_primary,
const char *backup_dir);
#if GNUPG_MAJOR_VERSION == 1
#define GET_NBITS(a) mpi_get_nbits (a)
#else
#define GET_NBITS(a) gcry_mpi_get_nbits (a)
#endif
#ifdef ENABLE_CARD_SUPPORT
static int
copy_mpi (MPI a, unsigned char *buffer, size_t len, size_t *ncopied)
{
int rc;
#if GNUPG_MAJOR_VERSION == 1
unsigned char *tmp;
unsigned int n;
tmp = mpi_get_secure_buffer (a, &n, NULL);
if (n > len)
rc = G10ERR_GENERAL;
else
{
rc = 0;
memcpy (buffer, tmp, n);
*ncopied = n;
}
xfree (tmp);
#else /* GNUPG_MAJOR_VERSION != 1 */
rc = gcry_mpi_print (GCRYMPI_FMT_USG, buffer, len, ncopied, a);
#endif /* GNUPG_MAJOR_VERSION != 1 */
if (rc)
log_error ("mpi_copy failed: %s\n", gpg_strerror (rc));
return rc;
}
#endif /* ENABLE_CARD_SUPPORT */
static void
print_status_key_created (int letter, PKT_public_key *pk, const char *handle)
{
@ -3527,104 +3491,68 @@ int
save_unprotected_key_to_card (PKT_secret_key *sk, int keyno)
{
int rc;
size_t n;
MPI rsa_n, rsa_e, rsa_p, rsa_q;
unsigned int nbits;
unsigned char *template = NULL;
unsigned char *tp;
unsigned char m[128], e[4];
size_t mlen, elen;
unsigned char *rsa_n = NULL;
unsigned char *rsa_e = NULL;
unsigned char *rsa_p = NULL;
unsigned char *rsa_q = NULL;
unsigned int rsa_n_len, rsa_e_len, rsa_p_len, rsa_q_len;
unsigned char *sexp = NULL;
unsigned char *p;
char numbuf[55], numbuf2[50];
assert (is_RSA (sk->pubkey_algo));
assert (!sk->is_protected);
rc = -1;
/* Some basic checks on the key parameters. */
rsa_n = sk->skey[0];
rsa_e = sk->skey[1];
rsa_p = sk->skey[3];
rsa_q = sk->skey[4];
nbits = GET_NBITS (rsa_n);
if (nbits != 1024)
/* Copy the parameters into straight buffers. */
rsa_n = mpi_get_secure_buffer (sk->skey[0], &rsa_n_len, NULL);
rsa_e = mpi_get_secure_buffer (sk->skey[1], &rsa_e_len, NULL);
rsa_p = mpi_get_secure_buffer (sk->skey[3], &rsa_p_len, NULL);
rsa_q = mpi_get_secure_buffer (sk->skey[4], &rsa_q_len, NULL);
if (!rsa_n || !rsa_e || !rsa_p || !rsa_q)
{
log_error (_("length of RSA modulus is not %d\n"), 1024);
goto leave;
}
nbits = GET_NBITS (rsa_e);
if (nbits < 2 || nbits > 32)
{
log_error (_("public exponent too large (more than 32 bits)\n"));
goto leave;
}
nbits = GET_NBITS (rsa_p);
if (nbits != 512)
{
log_error (_("length of an RSA prime is not %d\n"), 512);
goto leave;
}
nbits = GET_NBITS (rsa_q);
if (nbits != 512)
{
log_error (_("length of an RSA prime is not %d\n"), 512);
rc = G10ERR_INV_ARG;
goto leave;
}
/* We need the modulus later to calculate the fingerprint. */
rc = copy_mpi (rsa_n, m, 128, &n);
if (rc)
goto leave;
assert (n == 128);
mlen = 128;
/* Put the key into an S-expression. */
sexp = p = xmalloc_secure (30
+ rsa_n_len + rsa_e_len + rsa_p_len + rsa_q_len
+ 4*sizeof (numbuf) + 25 + sizeof(numbuf) + 20);
/* Build the private key template as described in section 4.3.3.6 of
the OpenPGP card specs:
0xC0 <length> public exponent
0xC1 <length> prime p
0xC2 <length> prime q
*/
template = tp = xmalloc_secure (1+2 + 1+1+4 + 1+1+(512/8) + 1+1+(512/8));
*tp++ = 0xC0;
*tp++ = 4;
rc = copy_mpi (rsa_e, tp, 4, &n);
if (rc)
goto leave;
assert (n <= 4);
memcpy (e, tp, n); /* Save a copy of the exponent for later use. */
elen = n;
if (n != 4)
{
memmove (tp+4-n, tp, 4-n);
memset (tp, 0, 4-n);
}
tp += 4;
p = stpcpy (p,"(11:private-key(3:rsa(1:n");
sprintf (numbuf, "%u:", rsa_n_len);
p = stpcpy (p, numbuf);
memcpy (p, rsa_n, rsa_n_len);
p += rsa_n_len;
*tp++ = 0xC1;
*tp++ = 64;
rc = copy_mpi (rsa_p, tp, 64, &n);
if (rc)
goto leave;
assert (n == 64);
tp += 64;
sprintf (numbuf, ")(1:e%u:", rsa_e_len);
p = stpcpy (p, numbuf);
memcpy (p, rsa_e, rsa_e_len);
p += rsa_e_len;
*tp++ = 0xC2;
*tp++ = 64;
rc = copy_mpi (rsa_q, tp, 64, &n);
if (rc)
goto leave;
assert (n == 64);
tp += 64;
assert (tp - template == 138);
sprintf (numbuf, ")(1:p%u:", rsa_p_len);
p = stpcpy (p, numbuf);
memcpy (p, rsa_p, rsa_p_len);
p += rsa_p_len;
rc = agent_openpgp_storekey (keyno,
template, tp - template,
sk->timestamp,
m, mlen,
e, elen);
sprintf (numbuf, ")(1:q%u:", rsa_q_len);
p = stpcpy (p, numbuf);
memcpy (p, rsa_q, rsa_q_len);
p += rsa_q_len;
p = stpcpy (p,"))(10:created-at");
sprintf (numbuf2, "%lu", (unsigned long)sk->timestamp);
sprintf (numbuf, "%d:", strlen (numbuf2));
p = stpcpy (stpcpy (stpcpy (p, numbuf), numbuf2), "))");
rc = agent_scd_writekey (keyno, sexp, p - sexp);
leave:
xfree (template);
xfree (sexp);
xfree (rsa_n);
xfree (rsa_e);
xfree (rsa_p);
xfree (rsa_q);
return rc;
}
#endif /*ENABLE_CARD_SUPPORT*/

View file

@ -221,3 +221,76 @@ parse_ber_header (unsigned char const **buffer, size_t *size,
*size = length;
return 0;
}
/* FIXME: The following function should not go into this file but for
now it is easier to keep it here. */
/* Return the next token of an canconical encoded S-expression. BUF
is the pointer to the S-expression and BUFLEN is a pointer to the
length of this S-expression (used to validate the syntax). Both
are updated to reflect the new position. The token itself is
returned as a pointer into the orginal buffer at TOK and TOKLEN.
If a parentheses is the next token, TOK will be set to NULL.
TOKLEN is checked to be within the bounds. On error a error code
is returned and all pointers should are not guaranteed to point to
a meanigful value. DEPTH should be initialized to 0 and will
reflect on return the actual depth of the tree. To detect the end
of the S-expression it is advisable to check DEPTH after a
successful return:
depth = 0;
while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
&& depth)
process_token (tok, toklen);
if (err)
handle_error ();
*/
gpg_error_t
parse_sexp (unsigned char const **buf, size_t *buflen,
int *depth, unsigned char const **tok, size_t *toklen)
{
const unsigned char *s;
size_t n, vlen;
s = *buf;
n = *buflen;
*tok = NULL;
*toklen = 0;
if (!n)
return *depth ? gpg_error (GPG_ERR_INV_SEXP) : 0;
if (*s == '(')
{
s++; n--;
(*depth)++;
*buf = s;
*buflen = n;
return 0;
}
if (*s == ')')
{
if (!*depth)
return gpg_error (GPG_ERR_INV_SEXP);
*toklen = 1;
s++; n--;
(*depth)--;
*buf = s;
*buflen = n;
return 0;
}
for (vlen=0; n && *s && *s != ':' && (*s >= '0' && *s <= '9'); s++, n--)
vlen = vlen*10 + (*s - '0');
if (!n || *s != ':')
return gpg_error (GPG_ERR_INV_SEXP);
s++; n--;
if (vlen > n)
return gpg_error (GPG_ERR_INV_SEXP);
*tok = s;
*toklen = vlen;
s += vlen;
n -= vlen;
*buf = s;
*buflen = n;
return 0;
}

View file

@ -88,4 +88,21 @@ gpg_error_t parse_ber_header (unsigned char const **buffer, size_t *size,
/* Return the next token of an canconical encoded S-expression. BUF
is the pointer to the S-expression and BUFLEN is a pointer to the
length of this S-expression (used to validate the syntax). Both
are updated to reflect the new position. The token itself is
returned as a pointer into the orginal buffer at TOK and TOKLEN.
If a parentheses is the next token, TOK will be set to NULL.
TOKLEN is checked to be within the bounds. On error a error code
is returned and all pointers should are not guaranteed to point to
a meanigful value. DEPTH should be initialized to 0 and will
reflect on return the actual depth of the tree. To detect the end
of the S-expression it is advisable to check DEPTH after a
successful return. */
gpg_error_t parse_sexp (unsigned char const **buf, size_t *buflen,
int *depth, unsigned char const **tok, size_t *toklen);
#endif /* SCD_TLV_H */