mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-03 12:11:33 +01: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:
parent
bd644c8d45
commit
be2aa37dbf
17
NEWS
17
NEWS
@ -1,6 +1,23 @@
|
|||||||
Noteworthy changes in version 1.4.2
|
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)
|
Noteworthy changes in version 1.4.1 (2005-03-15)
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
|
@ -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>
|
2005-05-20 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
* ccid-driver.c (ccid_transceive): Arghhh. The seqno is another
|
* ccid-driver.c (ccid_transceive): Arghhh. The seqno is another
|
||||||
|
@ -86,6 +86,11 @@ struct app_ctx_s {
|
|||||||
void *pincb_arg,
|
void *pincb_arg,
|
||||||
const void *indata, size_t indatalen,
|
const void *indata, size_t indatalen,
|
||||||
unsigned char **outdata, size_t *outdatalen);
|
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,
|
gpg_error_t (*genkey) (app_t app, ctrl_t ctrl,
|
||||||
const char *keynostr, unsigned int flags,
|
const char *keynostr, unsigned int flags,
|
||||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
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,
|
void *pincb_arg,
|
||||||
const void *indata, size_t indatalen,
|
const void *indata, size_t indatalen,
|
||||||
unsigned char **outdata, size_t *outdatalen );
|
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,
|
gpg_error_t app_genkey (app_t app, ctrl_t ctrl,
|
||||||
const char *keynostr, unsigned int flags,
|
const char *keynostr, unsigned int flags,
|
||||||
gpg_error_t (*pincb)(void*, const char *, char **),
|
gpg_error_t (*pincb)(void*, const char *, char **),
|
||||||
|
@ -565,7 +565,7 @@ store_fpr (int slot, int keynumber, u32 timestamp,
|
|||||||
n = 6 + 2 + mlen + 2 + elen;
|
n = 6 + 2 + mlen + 2 + elen;
|
||||||
p = buffer = xtrymalloc (3 + n);
|
p = buffer = xtrymalloc (3 + n);
|
||||||
if (!buffer)
|
if (!buffer)
|
||||||
return gpg_error (gpg_err_code_from_errno (errno));
|
return gpg_error_from_errno (errno);
|
||||||
|
|
||||||
*p++ = 0x99; /* ctb */
|
*p++ = 0x99; /* ctb */
|
||||||
*p++ = n >> 8; /* 2 byte length header */
|
*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. */
|
/* Handle the GENKEY command. */
|
||||||
static gpg_error_t
|
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)
|
void *pincb_arg)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
int i;
|
|
||||||
char numbuf[30];
|
char numbuf[30];
|
||||||
unsigned char fprbuf[20];
|
unsigned char fprbuf[20];
|
||||||
const unsigned char *fpr;
|
|
||||||
const unsigned char *keydata, *m, *e;
|
const unsigned char *keydata, *m, *e;
|
||||||
unsigned char *buffer;
|
unsigned char *buffer = NULL;
|
||||||
size_t buflen, keydatalen, n, mlen, elen;
|
size_t buflen, keydatalen, mlen, elen;
|
||||||
time_t created_at;
|
time_t created_at;
|
||||||
int keyno = atoi (keynostr);
|
int keyno = atoi (keynostr);
|
||||||
int force = (flags & 1);
|
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;
|
app->app_local->pk[keyno].read_done = 0;
|
||||||
|
|
||||||
/* Check whether a key already exists. */
|
/* Check whether a key already exists. */
|
||||||
rc = iso7816_get_data (app->slot, 0x006E, &buffer, &buflen);
|
rc = does_key_exist (app, keyno, force);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
return 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"));
|
|
||||||
|
|
||||||
|
|
||||||
/* Prepare for key generation by verifying the ADmin PIN. */
|
/* Prepare for key generation by verifying the ADmin PIN. */
|
||||||
rc = verify_chv3 (app, pincb, pincb_arg);
|
rc = verify_chv3 (app, pincb, pincb_arg);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
xfree (buffer); buffer = NULL;
|
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
log_info (_("please wait while key is being generated ...\n"));
|
log_info (_("please wait while key is being generated ...\n"));
|
||||||
start_at = time (NULL);
|
start_at = time (NULL);
|
||||||
@ -2220,6 +2504,7 @@ app_select_openpgp (app_t app)
|
|||||||
app->fnc.readkey = do_readkey;
|
app->fnc.readkey = do_readkey;
|
||||||
app->fnc.getattr = do_getattr;
|
app->fnc.getattr = do_getattr;
|
||||||
app->fnc.setattr = do_setattr;
|
app->fnc.setattr = do_setattr;
|
||||||
|
app->fnc.writekey = do_writekey;
|
||||||
app->fnc.genkey = do_genkey;
|
app->fnc.genkey = do_genkey;
|
||||||
app->fnc.sign = do_sign;
|
app->fnc.sign = do_sign;
|
||||||
app->fnc.auth = do_auth;
|
app->fnc.auth = do_auth;
|
||||||
|
@ -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 char *default_reader_port;
|
||||||
static app_t current_app;
|
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),
|
buffers. The variable elements are pairs of (char *, size_t),
|
||||||
terminated with a (NULL, 0). */
|
terminated with a (NULL, 0). */
|
||||||
void
|
void
|
||||||
send_status_info (CTRL ctrl, const char *keyword, ...)
|
send_status_info (ctrl_t ctrl, const char *keyword, ...)
|
||||||
{
|
{
|
||||||
va_list arg_ptr;
|
va_list arg_ptr;
|
||||||
const unsigned char *value;
|
const unsigned char *value;
|
||||||
@ -140,7 +149,8 @@ send_status_info (CTRL ctrl, const char *keyword, ...)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
*p = 0;
|
*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);
|
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
|
static assuan_error_t
|
||||||
genkey_status_cb (void *opaque, const char *line)
|
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
|
void
|
||||||
agent_clear_pin_cache (const char *sn)
|
agent_clear_pin_cache (const char *sn)
|
||||||
|
@ -81,6 +81,7 @@ typedef struct ctrl_ctx_s *ctrl_t;
|
|||||||
|
|
||||||
#define GPG_ERR_GENERAL G10ERR_GENERAL
|
#define GPG_ERR_GENERAL G10ERR_GENERAL
|
||||||
#define GPG_ERR_BAD_PIN G10ERR_BAD_PASS
|
#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_CARD G10ERR_GENERAL
|
||||||
#define GPG_ERR_EEXIST G10ERR_FILE_EXISTS
|
#define GPG_ERR_EEXIST G10ERR_FILE_EXISTS
|
||||||
#define GPG_ERR_ENOMEM G10ERR_RESOURCE_LIMIT
|
#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_EOF (-1)
|
||||||
#define GPG_ERR_CARD_NOT_PRESENT G10ERR_NO_CARD
|
#define GPG_ERR_CARD_NOT_PRESENT G10ERR_NO_CARD
|
||||||
#define GPG_ERR_CARD_RESET G10ERR_GENERAL
|
#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_EBUSY G10ERR_GENERAL
|
||||||
#define GPG_ERR_ENOENT G10ERR_OPEN_FILE
|
#define GPG_ERR_ENOENT G10ERR_OPEN_FILE
|
||||||
@ -129,6 +134,7 @@ typedef int gpg_err_code_t;
|
|||||||
#define xtrymalloc(n) xmalloc((n))
|
#define xtrymalloc(n) xmalloc((n))
|
||||||
#define xtrycalloc(n,m) xcalloc((n),(m))
|
#define xtrycalloc(n,m) xcalloc((n),(m))
|
||||||
#define xtryrealloc(n,m) xrealloc((n),(m))
|
#define xtryrealloc(n,m) xrealloc((n),(m))
|
||||||
|
#define xtrymalloc_secure(n) xmalloc_secure((n))
|
||||||
#define out_of_core() (-1)
|
#define out_of_core() (-1)
|
||||||
|
|
||||||
#define gnupg_get_time() make_timestamp ()
|
#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,
|
int agent_scd_setattr (const char *name,
|
||||||
const unsigned char *value, size_t valuelen);
|
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. */
|
/* Send a GENKEY command to the SCdaemon. */
|
||||||
int agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force);
|
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. */
|
/* Send a CHECKPIN command. */
|
||||||
int agent_scd_checkpin (const char *serialnobuf);
|
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. */
|
/* Clear a cached PIN. */
|
||||||
void agent_clear_pin_cache (const char *sn);
|
void agent_clear_pin_cache (const char *sn);
|
||||||
|
|
||||||
|
168
g10/keygen.c
168
g10/keygen.c
@ -128,42 +128,6 @@ static int gen_card_key_with_backup (int algo, int keyno, int is_primary,
|
|||||||
const char *backup_dir);
|
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
|
static void
|
||||||
print_status_key_created (int letter, PKT_public_key *pk, const char *handle)
|
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)
|
save_unprotected_key_to_card (PKT_secret_key *sk, int keyno)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
size_t n;
|
unsigned char *rsa_n = NULL;
|
||||||
MPI rsa_n, rsa_e, rsa_p, rsa_q;
|
unsigned char *rsa_e = NULL;
|
||||||
unsigned int nbits;
|
unsigned char *rsa_p = NULL;
|
||||||
unsigned char *template = NULL;
|
unsigned char *rsa_q = NULL;
|
||||||
unsigned char *tp;
|
unsigned int rsa_n_len, rsa_e_len, rsa_p_len, rsa_q_len;
|
||||||
unsigned char m[128], e[4];
|
unsigned char *sexp = NULL;
|
||||||
size_t mlen, elen;
|
unsigned char *p;
|
||||||
|
char numbuf[55], numbuf2[50];
|
||||||
|
|
||||||
assert (is_RSA (sk->pubkey_algo));
|
assert (is_RSA (sk->pubkey_algo));
|
||||||
assert (!sk->is_protected);
|
assert (!sk->is_protected);
|
||||||
|
|
||||||
rc = -1;
|
/* Copy the parameters into straight buffers. */
|
||||||
/* Some basic checks on the key parameters. */
|
rsa_n = mpi_get_secure_buffer (sk->skey[0], &rsa_n_len, NULL);
|
||||||
rsa_n = sk->skey[0];
|
rsa_e = mpi_get_secure_buffer (sk->skey[1], &rsa_e_len, NULL);
|
||||||
rsa_e = sk->skey[1];
|
rsa_p = mpi_get_secure_buffer (sk->skey[3], &rsa_p_len, NULL);
|
||||||
rsa_p = sk->skey[3];
|
rsa_q = mpi_get_secure_buffer (sk->skey[4], &rsa_q_len, NULL);
|
||||||
rsa_q = sk->skey[4];
|
if (!rsa_n || !rsa_e || !rsa_p || !rsa_q)
|
||||||
|
|
||||||
nbits = GET_NBITS (rsa_n);
|
|
||||||
if (nbits != 1024)
|
|
||||||
{
|
{
|
||||||
log_error (_("length of RSA modulus is not %d\n"), 1024);
|
rc = G10ERR_INV_ARG;
|
||||||
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);
|
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Put the key into an S-expression. */
|
||||||
/* We need the modulus later to calculate the fingerprint. */
|
sexp = p = xmalloc_secure (30
|
||||||
rc = copy_mpi (rsa_n, m, 128, &n);
|
+ rsa_n_len + rsa_e_len + rsa_p_len + rsa_q_len
|
||||||
if (rc)
|
+ 4*sizeof (numbuf) + 25 + sizeof(numbuf) + 20);
|
||||||
goto leave;
|
|
||||||
assert (n == 128);
|
|
||||||
mlen = 128;
|
|
||||||
|
|
||||||
/* Build the private key template as described in section 4.3.3.6 of
|
p = stpcpy (p,"(11:private-key(3:rsa(1:n");
|
||||||
the OpenPGP card specs:
|
sprintf (numbuf, "%u:", rsa_n_len);
|
||||||
0xC0 <length> public exponent
|
p = stpcpy (p, numbuf);
|
||||||
0xC1 <length> prime p
|
memcpy (p, rsa_n, rsa_n_len);
|
||||||
0xC2 <length> prime q
|
p += rsa_n_len;
|
||||||
*/
|
|
||||||
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;
|
|
||||||
|
|
||||||
*tp++ = 0xC1;
|
sprintf (numbuf, ")(1:e%u:", rsa_e_len);
|
||||||
*tp++ = 64;
|
p = stpcpy (p, numbuf);
|
||||||
rc = copy_mpi (rsa_p, tp, 64, &n);
|
memcpy (p, rsa_e, rsa_e_len);
|
||||||
if (rc)
|
p += rsa_e_len;
|
||||||
goto leave;
|
|
||||||
assert (n == 64);
|
|
||||||
tp += 64;
|
|
||||||
|
|
||||||
*tp++ = 0xC2;
|
sprintf (numbuf, ")(1:p%u:", rsa_p_len);
|
||||||
*tp++ = 64;
|
p = stpcpy (p, numbuf);
|
||||||
rc = copy_mpi (rsa_q, tp, 64, &n);
|
memcpy (p, rsa_p, rsa_p_len);
|
||||||
if (rc)
|
p += rsa_p_len;
|
||||||
goto leave;
|
|
||||||
assert (n == 64);
|
|
||||||
tp += 64;
|
|
||||||
assert (tp - template == 138);
|
|
||||||
|
|
||||||
rc = agent_openpgp_storekey (keyno,
|
sprintf (numbuf, ")(1:q%u:", rsa_q_len);
|
||||||
template, tp - template,
|
p = stpcpy (p, numbuf);
|
||||||
sk->timestamp,
|
memcpy (p, rsa_q, rsa_q_len);
|
||||||
m, mlen,
|
p += rsa_q_len;
|
||||||
e, elen);
|
|
||||||
|
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:
|
leave:
|
||||||
xfree (template);
|
xfree (sexp);
|
||||||
|
xfree (rsa_n);
|
||||||
|
xfree (rsa_e);
|
||||||
|
xfree (rsa_p);
|
||||||
|
xfree (rsa_q);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
#endif /*ENABLE_CARD_SUPPORT*/
|
#endif /*ENABLE_CARD_SUPPORT*/
|
||||||
|
73
g10/tlv.c
73
g10/tlv.c
@ -221,3 +221,76 @@ parse_ber_header (unsigned char const **buffer, size_t *size,
|
|||||||
*size = length;
|
*size = length;
|
||||||
return 0;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
17
g10/tlv.h
17
g10/tlv.h
@ -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 */
|
#endif /* SCD_TLV_H */
|
||||||
|
@ -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>
|
2005-05-05 David Shaw <dshaw@jabberwocky.com>
|
||||||
|
|
||||||
* util.h: Remove add_days_to_timestamp as unused.
|
* util.h: Remove add_days_to_timestamp as unused.
|
||||||
|
@ -222,6 +222,24 @@ int strncasecmp (const char *, const char *b, size_t n);
|
|||||||
#define memmove(d, s, n) bcopy((s), (d), (n))
|
#define memmove(d, s, n) bcopy((s), (d), (n))
|
||||||
#endif
|
#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)
|
#if defined (_WIN32)
|
||||||
/*-- w32reg.c --*/
|
/*-- w32reg.c --*/
|
||||||
char *read_w32_registry_string( const char *root,
|
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 --*/
|
/*-- strgutil.c --*/
|
||||||
int vasprintf (char **result, const char *format, va_list args);
|
int vasprintf (char **result, const char *format, va_list args);
|
||||||
int asprintf (char **buf, const char *fmt, ...);
|
int asprintf (char **buf, const char *fmt, ...);
|
||||||
#endif
|
#endif /*_WIN32*/
|
||||||
|
|
||||||
|
|
||||||
/**** other missing stuff ****/
|
/**** other missing stuff ****/
|
||||||
#ifndef HAVE_ATEXIT /* For SunOS */
|
#ifndef HAVE_ATEXIT /* For SunOS */
|
||||||
|
@ -57,7 +57,7 @@ X.509 specific are noted like [X.509: xxx]
|
|||||||
b20 The keys fingerprint
|
b20 The keys fingerprint
|
||||||
(fingerprints are always 20 bytes, MD5 left padded with zeroes)
|
(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)
|
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
|
u16 special key flags
|
||||||
bit 0 =
|
bit 0 =
|
||||||
u16 reserved
|
u16 reserved
|
||||||
@ -72,7 +72,7 @@ X.509 specific are noted like [X.509: xxx]
|
|||||||
bit 0 =
|
bit 0 =
|
||||||
byte validity
|
byte validity
|
||||||
byte reserved
|
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]
|
and the others are subjectAltNames]
|
||||||
u16 number of signatures
|
u16 number of signatures
|
||||||
u16 size of signature information (4)
|
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
|
b16 MD5 checksum (useful for KS syncronisation), we might also want to use
|
||||||
a mac here.
|
a mac here.
|
||||||
b4 resevered
|
b4 reserved
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -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>
|
2005-03-11 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
* Makefile.am (ASFLAGS): Renamed to AM_CCASFLAGS and added the
|
* Makefile.am (ASFLAGS): Renamed to AM_CCASFLAGS and added the
|
||||||
|
@ -18,8 +18,8 @@
|
|||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "mpi-internal.h"
|
#include "mpi-internal.h"
|
||||||
#include "longlong.h"
|
#include "longlong.h"
|
||||||
@ -31,6 +31,7 @@
|
|||||||
*
|
*
|
||||||
* FIXME: This code is VERY ugly!
|
* FIXME: This code is VERY ugly!
|
||||||
*/
|
*/
|
||||||
|
#if 0 /* Code is not used */
|
||||||
int
|
int
|
||||||
mpi_getbyte( MPI a, unsigned idx )
|
mpi_getbyte( MPI a, unsigned idx )
|
||||||
{
|
{
|
||||||
@ -48,14 +49,19 @@ mpi_getbyte( MPI a, unsigned idx )
|
|||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
#endif /* Code is not used */
|
||||||
|
|
||||||
|
|
||||||
/****************
|
/****************
|
||||||
* Put a value at position IDX into A. idx counts from lsb to msb
|
* 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
|
void
|
||||||
mpi_putbyte( MPI a, unsigned idx, int xc )
|
mpi_putbyte( MPI a, unsigned idx, int xc )
|
||||||
{
|
{
|
||||||
|
|
||||||
int i, j;
|
int i, j;
|
||||||
unsigned n;
|
unsigned n;
|
||||||
mpi_ptr_t ap;
|
mpi_ptr_t ap;
|
||||||
@ -104,12 +110,13 @@ mpi_putbyte( MPI a, unsigned idx, int xc )
|
|||||||
}
|
}
|
||||||
abort(); /* index out of range */
|
abort(); /* index out of range */
|
||||||
}
|
}
|
||||||
|
#endif /* Code is not used */
|
||||||
|
|
||||||
|
|
||||||
/****************
|
/****************
|
||||||
* Count the number of zerobits at the low end of A
|
* Count the number of zerobits at the low end of A
|
||||||
*/
|
*/
|
||||||
unsigned
|
unsigned int
|
||||||
mpi_trailing_zeros( MPI a )
|
mpi_trailing_zeros( MPI a )
|
||||||
{
|
{
|
||||||
unsigned n, count = 0;
|
unsigned n, count = 0;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* mpicoder.c - Coder for the external representation of MPIs
|
/* 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.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -74,20 +74,23 @@ mpi_read(IOBUF inp, unsigned *ret_nread, int secure)
|
|||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
int c, i, j;
|
int c, i, j;
|
||||||
|
unsigned int nmax = *ret_nread;
|
||||||
unsigned nbits, nbytes, nlimbs, nread=0;
|
unsigned nbits, nbytes, nlimbs, nread=0;
|
||||||
mpi_limb_t a;
|
mpi_limb_t a;
|
||||||
MPI val = MPI_NULL;
|
MPI val = MPI_NULL;
|
||||||
|
|
||||||
if( (c = iobuf_get(inp)) == -1 )
|
if( (c = iobuf_get(inp)) == -1 )
|
||||||
goto leave;
|
goto leave;
|
||||||
nread++;
|
if (++nread >= nmax)
|
||||||
|
goto overflow;
|
||||||
nbits = c << 8;
|
nbits = c << 8;
|
||||||
if( (c = iobuf_get(inp)) == -1 )
|
if( (c = iobuf_get(inp)) == -1 )
|
||||||
goto leave;
|
goto leave;
|
||||||
nread++;
|
if (++nread >= nmax)
|
||||||
|
goto overflow;
|
||||||
nbits |= c;
|
nbits |= c;
|
||||||
if( nbits > MAX_EXTERN_MPI_BITS ) {
|
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;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,6 +111,15 @@ mpi_read(IOBUF inp, unsigned *ret_nread, int secure)
|
|||||||
for( ; j > 0; j-- ) {
|
for( ; j > 0; j-- ) {
|
||||||
a = 0;
|
a = 0;
|
||||||
for(; i < BYTES_PER_MPI_LIMB; i++ ) {
|
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 <<= 8;
|
||||||
a |= iobuf_get(inp) & 0xff; nread++;
|
a |= iobuf_get(inp) & 0xff; nread++;
|
||||||
}
|
}
|
||||||
@ -116,10 +128,11 @@ mpi_read(IOBUF inp, unsigned *ret_nread, int secure)
|
|||||||
}
|
}
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
if( nread > *ret_nread )
|
*ret_nread = nread;
|
||||||
log_bug("mpi crosses packet border\n");
|
return val;
|
||||||
else
|
overflow:
|
||||||
*ret_nread = nread;
|
log_error ("mpi larger than indicated length (%u bytes)\n", nmax);
|
||||||
|
*ret_nread = nread;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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>
|
2005-05-05 David Shaw <dshaw@jabberwocky.com>
|
||||||
|
|
||||||
* miscutil.c (add_days_to_timestamp): Remove as unused.
|
* miscutil.c (add_days_to_timestamp): Remove as unused.
|
||||||
|
@ -39,7 +39,7 @@ endif
|
|||||||
libutil_a_SOURCES = logger.c fileutil.c miscutil.c strgutil.c \
|
libutil_a_SOURCES = logger.c fileutil.c miscutil.c strgutil.c \
|
||||||
ttyio.c argparse.c memory.c secmem.c errors.c iobuf.c \
|
ttyio.c argparse.c memory.c secmem.c errors.c iobuf.c \
|
||||||
dotlock.c http.c srv.h srv.c simple-gettext.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@
|
libutil_a_DEPENDENCIES = @LIBOBJS@ @REGEX_O@
|
||||||
# LIBOBJS is for the replacement functions
|
# LIBOBJS is for the replacement functions
|
||||||
|
83
util/membuf.c
Normal file
83
util/membuf.c
Normal 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;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user