aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--NEWS17
-rw-r--r--g10/ChangeLog11
-rw-r--r--g10/app-common.h10
-rw-r--r--g10/app-openpgp.c351
-rw-r--r--g10/cardglue.c98
-rw-r--r--g10/cardglue.h17
-rw-r--r--g10/keygen.c172
-rw-r--r--g10/tlv.c73
-rw-r--r--g10/tlv.h17
-rw-r--r--include/ChangeLog4
-rw-r--r--include/util.h21
-rw-r--r--kbx/keybox-blob.c6
-rw-r--r--mpi/ChangeLog9
-rw-r--r--mpi/mpi-scan.c13
-rw-r--r--mpi/mpicoder.c29
-rw-r--r--util/ChangeLog4
-rw-r--r--util/Makefile.am2
-rw-r--r--util/membuf.c83
18 files changed, 726 insertions, 211 deletions
diff --git a/NEWS b/NEWS
index 6a58be674..edcc648b7 100644
--- a/NEWS
+++ b/NEWS
@@ -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)
------------------------------------------------
diff --git a/g10/ChangeLog b/g10/ChangeLog
index 8f05b7e5b..fc36891dd 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,3 +1,14 @@
+2005-05-21 Werner Koch <[email protected]>
+
+ * 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 <[email protected]>
* ccid-driver.c (ccid_transceive): Arghhh. The seqno is another
diff --git a/g10/app-common.h b/g10/app-common.h
index f1058dda1..c2c302395 100644
--- a/g10/app-common.h
+++ b/g10/app-common.h
@@ -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 **),
diff --git a/g10/app-openpgp.c b/g10/app-openpgp.c
index 6f4778ba5..1165ec683 100644
--- a/g10/app-openpgp.c
+++ b/g10/app-openpgp.c
@@ -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;
diff --git a/g10/cardglue.c b/g10/cardglue.c
index 940ec64a3..01d8b4292 100644
--- a/g10/cardglue.c
+++ b/g10/cardglue.c
@@ -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)
diff --git a/g10/cardglue.h b/g10/cardglue.h
index 068a1aacf..a679dbb95 100644
--- a/g10/cardglue.h
+++ b/g10/cardglue.h
@@ -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);
diff --git a/g10/keygen.c b/g10/keygen.c
index c4b9dab8f..b5408a6aa 100644
--- a/g10/keygen.c
+++ b/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);
-#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;
-
- /* 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;
-
- *tp++ = 0xC1;
- *tp++ = 64;
- rc = copy_mpi (rsa_p, tp, 64, &n);
- if (rc)
- goto leave;
- assert (n == 64);
- tp += 64;
+ /* 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);
- *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);
+ 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;
+
+ sprintf (numbuf, ")(1:e%u:", rsa_e_len);
+ p = stpcpy (p, numbuf);
+ memcpy (p, rsa_e, rsa_e_len);
+ p += rsa_e_len;
+
+ sprintf (numbuf, ")(1:p%u:", rsa_p_len);
+ p = stpcpy (p, numbuf);
+ memcpy (p, rsa_p, rsa_p_len);
+ p += rsa_p_len;
+
+ 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_openpgp_storekey (keyno,
- template, tp - template,
- sk->timestamp,
- m, mlen,
- e, elen);
+ 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*/
diff --git a/g10/tlv.c b/g10/tlv.c
index 3a81ea6d9..b5dcd4021 100644
--- a/g10/tlv.c
+++ b/g10/tlv.c
@@ -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;
+}
+
diff --git a/g10/tlv.h b/g10/tlv.h
index 628580431..f587dd9df 100644
--- a/g10/tlv.h
+++ b/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 */
diff --git a/include/ChangeLog b/include/ChangeLog
index 428105045..e17b96df1 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,7 @@
+2005-05-19 Werner Koch <[email protected]>
+
+ * util.h: Add definitions for membuf functions.
+
2005-05-05 David Shaw <[email protected]>
* util.h: Remove add_days_to_timestamp as unused.
diff --git a/include/util.h b/include/util.h
index 97943afa9..b32d771af 100644
--- a/include/util.h
+++ b/include/util.h
@@ -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 */
diff --git a/kbx/keybox-blob.c b/kbx/keybox-blob.c
index 5ad1d2610..8a85e0270 100644
--- a/kbx/keybox-blob.c
+++ b/kbx/keybox-blob.c
@@ -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
*/
diff --git a/mpi/ChangeLog b/mpi/ChangeLog
index 00e0e3e6a..775f437b4 100644
--- a/mpi/ChangeLog
+++ b/mpi/ChangeLog
@@ -1,3 +1,12 @@
+2005-05-06 Werner Koch <[email protected]>
+
+ * mpi-scan.c (mpi_putbyte, mpi_getbyte): Removed. Not used.
+
+2005-04-21 Werner Koch <[email protected]>
+
+ * 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 <[email protected]>
* Makefile.am (ASFLAGS): Renamed to AM_CCASFLAGS and added the
diff --git a/mpi/mpi-scan.c b/mpi/mpi-scan.c
index 615b9464f..fe093adea 100644
--- a/mpi/mpi-scan.c
+++ b/mpi/mpi-scan.c
@@ -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;
diff --git a/mpi/mpicoder.c b/mpi/mpicoder.c
index 4d4e45553..ab913861d 100644
--- a/mpi/mpicoder.c
+++ b/mpi/mpicoder.c
@@ -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;
}
diff --git a/util/ChangeLog b/util/ChangeLog
index e16df58ee..f1b36ff49 100644
--- a/util/ChangeLog
+++ b/util/ChangeLog
@@ -1,3 +1,7 @@
+2005-05-19 Werner Koch <[email protected]>
+
+ * membuf.c: New. Taken from gnupg 1.9.
+
2005-05-05 David Shaw <[email protected]>
* miscutil.c (add_days_to_timestamp): Remove as unused.
diff --git a/util/Makefile.am b/util/Makefile.am
index cb241da3f..d54aa7a97 100644
--- a/util/Makefile.am
+++ b/util/Makefile.am
@@ -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
diff --git a/util/membuf.c b/util/membuf.c
new file mode 100644
index 000000000..ea69ee953
--- /dev/null
+++ b/util/membuf.c
@@ -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;
+}