* 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

17
NEWS
View File

@ -1,6 +1,23 @@
Noteworthy changes in version 1.4.2
------------------------------------------------
* New command "verify" in the card-edit menu to display
the Private-DO-3. The Admin command has been enhanced to take
the optional arguments "on", "off" and "verify". The latter may
be used to verify the ADmin Pin without modifying data; this
allows displayin the Private-DO-4 with the "list" command.
* Rewrote large parts of the card code to optionally make use of a
running gpg-agent. If --use-agent is beeing used and a
gpg-agent with enabled scdaemon is active, gpg will now divert
all card operations to that daemon. This is required because
bot, scdaemon and gpg require exclusive access to the card
reader. By delegating the work to scdaemon, both can peacefully
coexist and scdaemon is able to control the use of the reader.
Note that this requires at least gnupg 1.9.17.
* Fixed a couple of problems with the card reader.
Noteworthy changes in version 1.4.1 (2005-03-15)
------------------------------------------------

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 */

View File

@ -1,3 +1,7 @@
2005-05-19 Werner Koch <wk@g10code.com>
* util.h: Add definitions for membuf functions.
2005-05-05 David Shaw <dshaw@jabberwocky.com>
* util.h: Remove add_days_to_timestamp as unused.

View File

@ -222,6 +222,24 @@ int strncasecmp (const char *, const char *b, size_t n);
#define memmove(d, s, n) bcopy((s), (d), (n))
#endif
/*-- membuf.c --*/
/* The definition of the structure is private, we only need it here,
so it can be allocated on the stack. */
struct private_membuf_s {
size_t len;
size_t size;
char *buf;
int out_of_core;
};
typedef struct private_membuf_s membuf_t;
void init_membuf (membuf_t *mb, int initiallen);
void put_membuf (membuf_t *mb, const void *buf, size_t len);
void *get_membuf (membuf_t *mb, size_t *len);
#if defined (_WIN32)
/*-- w32reg.c --*/
char *read_w32_registry_string( const char *root,
@ -232,7 +250,8 @@ int write_w32_registry_string(const char *root, const char *dir,
/*-- strgutil.c --*/
int vasprintf (char **result, const char *format, va_list args);
int asprintf (char **buf, const char *fmt, ...);
#endif
#endif /*_WIN32*/
/**** other missing stuff ****/
#ifndef HAVE_ATEXIT /* For SunOS */

View File

@ -57,7 +57,7 @@ X.509 specific are noted like [X.509: xxx]
b20 The keys fingerprint
(fingerprints are always 20 bytes, MD5 left padded with zeroes)
u32 offset to the n-th key's keyID (a keyID is always 8 byte)
or 0 if not known which is the case opnly for X509.
or 0 if not known which is the case only for X509.
u16 special key flags
bit 0 =
u16 reserved
@ -72,7 +72,7 @@ X.509 specific are noted like [X.509: xxx]
bit 0 =
byte validity
byte reserved
[For X509, the first user ID is the ISsuer, the second the subject
[For X509, the first user ID is the issuer, the second the subject
and the others are subjectAltNames]
u16 number of signatures
u16 size of signature information (4)
@ -99,7 +99,7 @@ X.509 specific are noted like [X.509: xxx]
b16 MD5 checksum (useful for KS syncronisation), we might also want to use
a mac here.
b4 resevered
b4 reserved
*/

View File

@ -1,3 +1,12 @@
2005-05-06 Werner Koch <wk@g10code.com>
* mpi-scan.c (mpi_putbyte, mpi_getbyte): Removed. Not used.
2005-04-21 Werner Koch <wk@g10code.com>
* mpicoder.c (mpi_read): Changed error detection to always return
an error while maintaining the actual number of bytes read.
2005-03-11 Werner Koch <wk@g10code.com>
* Makefile.am (ASFLAGS): Renamed to AM_CCASFLAGS and added the

View File

@ -18,8 +18,8 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdio.h>
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include "mpi-internal.h"
#include "longlong.h"
@ -31,6 +31,7 @@
*
* FIXME: This code is VERY ugly!
*/
#if 0 /* Code is not used */
int
mpi_getbyte( MPI a, unsigned idx )
{
@ -48,14 +49,19 @@ mpi_getbyte( MPI a, unsigned idx )
}
return -1;
}
#endif /* Code is not used */
/****************
* Put a value at position IDX into A. idx counts from lsb to msb
*/
/* FIXME: There is a problem with the long constants which should have
a LL prefix or better the macros we use at other places. */
#if 0 /* Code is not used */
void
mpi_putbyte( MPI a, unsigned idx, int xc )
{
int i, j;
unsigned n;
mpi_ptr_t ap;
@ -104,12 +110,13 @@ mpi_putbyte( MPI a, unsigned idx, int xc )
}
abort(); /* index out of range */
}
#endif /* Code is not used */
/****************
* Count the number of zerobits at the low end of A
*/
unsigned
unsigned int
mpi_trailing_zeros( MPI a )
{
unsigned n, count = 0;

View File

@ -1,5 +1,5 @@
/* mpicoder.c - Coder for the external representation of MPIs
* Copyright (C) 1998, 1999 Free Software Foundation, Inc.
* Copyright (C) 1998, 1999, 2005 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -74,20 +74,23 @@ mpi_read(IOBUF inp, unsigned *ret_nread, int secure)
#endif
{
int c, i, j;
unsigned int nmax = *ret_nread;
unsigned nbits, nbytes, nlimbs, nread=0;
mpi_limb_t a;
MPI val = MPI_NULL;
if( (c = iobuf_get(inp)) == -1 )
goto leave;
nread++;
if (++nread >= nmax)
goto overflow;
nbits = c << 8;
if( (c = iobuf_get(inp)) == -1 )
goto leave;
nread++;
if (++nread >= nmax)
goto overflow;
nbits |= c;
if( nbits > MAX_EXTERN_MPI_BITS ) {
log_error("mpi too large (%u bits)\n", nbits);
log_error("mpi too large for this implementation (%u bits)\n", nbits);
goto leave;
}
@ -108,6 +111,15 @@ mpi_read(IOBUF inp, unsigned *ret_nread, int secure)
for( ; j > 0; j-- ) {
a = 0;
for(; i < BYTES_PER_MPI_LIMB; i++ ) {
if (nread >= nmax) {
#ifdef M_DEBUG
mpi_debug_free (val);
#else
mpi_free (val);
#endif
val = NULL;
goto overflow;
}
a <<= 8;
a |= iobuf_get(inp) & 0xff; nread++;
}
@ -116,10 +128,11 @@ mpi_read(IOBUF inp, unsigned *ret_nread, int secure)
}
leave:
if( nread > *ret_nread )
log_bug("mpi crosses packet border\n");
else
*ret_nread = nread;
*ret_nread = nread;
return val;
overflow:
log_error ("mpi larger than indicated length (%u bytes)\n", nmax);
*ret_nread = nread;
return val;
}

View File

@ -1,3 +1,7 @@
2005-05-19 Werner Koch <wk@g10code.com>
* membuf.c: New. Taken from gnupg 1.9.
2005-05-05 David Shaw <dshaw@jabberwocky.com>
* miscutil.c (add_days_to_timestamp): Remove as unused.

View File

@ -39,7 +39,7 @@ endif
libutil_a_SOURCES = logger.c fileutil.c miscutil.c strgutil.c \
ttyio.c argparse.c memory.c secmem.c errors.c iobuf.c \
dotlock.c http.c srv.h srv.c simple-gettext.c \
w32reg.c $(assuan_source)
membuf.c w32reg.c $(assuan_source)
libutil_a_DEPENDENCIES = @LIBOBJS@ @REGEX_O@
# LIBOBJS is for the replacement functions

83
util/membuf.c Normal file
View File

@ -0,0 +1,83 @@
/* membuf.c - A simple implementation of a dynamic buffer
* Copyright (C) 2001, 2003 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <config.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include "util.h"
/* A simple implementation of a dynamic buffer. Use init_membuf() to
create a buffer, put_membuf to append bytes and get_membuf to
release and return the buffer. Allocation errors are detected but
only returned at the final get_membuf(), this helps not to clutter
the code with out of core checks. */
void
init_membuf (membuf_t *mb, int initiallen)
{
mb->len = 0;
mb->size = initiallen;
mb->out_of_core = 0;
mb->buf = xmalloc (initiallen);
if (!mb->buf)
mb->out_of_core = errno;
}
void
put_membuf (membuf_t *mb, const void *buf, size_t len)
{
if (mb->out_of_core)
return;
if (mb->len + len >= mb->size)
{
char *p;
mb->size += len + 1024;
p = xrealloc (mb->buf, mb->size);
mb->buf = p;
}
memcpy (mb->buf + mb->len, buf, len);
mb->len += len;
}
void *
get_membuf (membuf_t *mb, size_t *len)
{
char *p;
if (mb->out_of_core)
{
xfree (mb->buf);
mb->buf = NULL;
return NULL;
}
p = mb->buf;
*len = mb->len;
mb->buf = NULL;
mb->out_of_core = ENOMEM; /* hack to make sure it won't get reused. */
return p;
}