aboutsummaryrefslogtreecommitdiffstats
path: root/scd/app-openpgp.c
diff options
context:
space:
mode:
authorNIIBE Yutaka <[email protected]>2016-10-18 13:46:37 +0000
committerNIIBE Yutaka <[email protected]>2016-10-18 13:58:00 +0000
commit34439da2d62b964a914ace66bae7e38f619582a4 (patch)
treefac3562eac9ce0dc7f02cc6b0a04d93a05d254c3 /scd/app-openpgp.c
parentscd: minor cleanup to merge other works. (diff)
downloadgnupg-34439da2d62b964a914ace66bae7e38f619582a4.tar.gz
gnupg-34439da2d62b964a914ace66bae7e38f619582a4.zip
scd: Support ECC key generation.
* scd/app-openpgp.c (get_public_key): Fix a message. (change_keyattr_from_string, ecc_writekey): Call mpi_release sooner. (do_genkey): Add ECC support. -- In OpenPGP card specification 3.0, ECC is introduced. So far, do_genkey only supported RSA. Since KDF spec. is needed to calculate the fingerprint, it is hard coded in app-openpgp.c. But it's defined by OpenPGP ECC (RFC-6637), and card does nothing with KDF in fact. Co-authored-by: Arnaud Fontaine <[email protected]> Signed-off-by: NIIBE Yutaka <[email protected]>
Diffstat (limited to '')
-rw-r--r--scd/app-openpgp.c198
1 files changed, 137 insertions, 61 deletions
diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
index ba16255ea..09e4800f6 100644
--- a/scd/app-openpgp.c
+++ b/scd/app-openpgp.c
@@ -1318,7 +1318,7 @@ get_public_key (app_t app, int keyno)
if (!m)
{
err = gpg_error (GPG_ERR_CARD);
- log_error (_("response does not contain the EC public point\n"));
+ log_error (_("response does not contain the EC public key\n"));
goto leave;
}
}
@@ -2847,6 +2847,7 @@ change_keyattr_from_string (app_t app,
size_t oid_len;
oidstr = openpgp_curve_to_oid (string+n, NULL);
+ gcry_mpi_release (oid);
if (!oidstr)
{
err = gpg_error (GPG_ERR_INV_DATA);
@@ -2864,7 +2865,6 @@ change_keyattr_from_string (app_t app,
string[0] = algo;
memcpy (string+1, oidbuf+1, oid_len-1);
err = change_keyattr (app, keyno, string, oid_len, pincb, pincb_arg);
- gcry_mpi_release (oid);
}
else
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
@@ -3355,13 +3355,14 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
if (err)
goto leave;
oidbuf = gcry_mpi_get_opaque (oid, &n);
- oid_len = (n+7)/8;
if (!oidbuf)
{
err = gpg_error_from_syserror ();
gcry_mpi_release (oid);
goto leave;
}
+ gcry_mpi_release (oid);
+ oid_len = (n+7)/8;
if (app->app_local->keyattr[keyno].key_type != KEY_TYPE_ECC
|| app->app_local->keyattr[keyno].ecc.oid != oidstr
@@ -3442,8 +3443,6 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
ecc_q, ecc_q_len, "\x03\x01\x08\x07", (size_t)4);
leave:
- if (oidbuf)
- gcry_mpi_release (oid);
return err;
}
@@ -3535,16 +3534,15 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
gpg_error_t err;
char numbuf[30];
unsigned char fprbuf[20];
- const unsigned char *keydata, *m, *e;
unsigned char *buffer = NULL;
- size_t buflen, keydatalen, mlen, elen;
+ const unsigned char *keydata;
+ size_t buflen, keydatalen;
u32 created_at;
int keyno = atoi (keynostr) - 1;
int force = (flags & 1);
time_t start_at;
- int exmode;
- int le_value;
- unsigned int keybits;
+ int exmode = 0;
+ int le_value = 256; /* Use legacy value. */
if (keyno < 0 || keyno > 2)
return gpg_error (GPG_ERR_INV_ID);
@@ -3564,34 +3562,34 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
if (err)
return err;
- /* Because we send the key parameter back via status lines we need
- to put a limit on the max. allowed keysize. 2048 bit will
- already lead to a 527 byte long status line and thus a 4096 bit
- key would exceed the Assuan line length limit. */
- keybits = app->app_local->keyattr[keyno].rsa.n_bits;
- if (keybits > 4096)
- return gpg_error (GPG_ERR_TOO_LARGE);
+ if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA)
+ {
+ unsigned int keybits = app->app_local->keyattr[keyno].rsa.n_bits;
+
+ /* Because we send the key parameter back via status lines we need
+ to put a limit on the max. allowed keysize. 2048 bit will
+ already lead to a 527 byte long status line and thus a 4096 bit
+ key would exceed the Assuan line length limit. */
+ if (keybits > 4096)
+ return gpg_error (GPG_ERR_TOO_LARGE);
+
+ /* Test whether we will need extended length mode. (1900 is an
+ arbitrary length which for sure fits into a short apdu.) */
+ if (app->app_local->cardcap.ext_lc_le && keybits > 1900)
+ {
+ exmode = 1; /* Use extended length w/o a limit. */
+ le_value = app->app_local->extcap.max_rsp_data;
+ /* No need to check le_value because it comes from a 16 bit
+ value and thus can't create an overflow on a 32 bit
+ system. */
+ }
+ }
/* Prepare for key generation by verifying the Admin PIN. */
err = verify_chv3 (app, pincb, pincb_arg);
if (err)
- goto leave;
+ return err;
- /* Test whether we will need extended length mode. (1900 is an
- arbitrary length which for sure fits into a short apdu.) */
- if (app->app_local->cardcap.ext_lc_le && keybits > 1900)
- {
- exmode = 1; /* Use extended length w/o a limit. */
- le_value = app->app_local->extcap.max_rsp_data;
- /* No need to check le_value because it comes from a 16 bit
- value and thus can't create an overflow on a 32 bit
- system. */
- }
- else
- {
- exmode = 0;
- le_value = 256; /* Use legacy value. */
- }
log_info (_("please wait while key is being generated ...\n"));
start_at = time (NULL);
@@ -3601,9 +3599,8 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
2, le_value, &buffer, &buflen);
if (err)
{
- err = gpg_error (GPG_ERR_CARD);
log_error (_("generating key failed\n"));
- goto leave;
+ return gpg_error (GPG_ERR_CARD);
}
{
@@ -3621,38 +3618,117 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
goto leave;
}
- m = find_tlv (keydata, keydatalen, 0x0081, &mlen);
- if (!m)
- {
- err = gpg_error (GPG_ERR_CARD);
- log_error (_("response does not contain the RSA modulus\n"));
- goto leave;
- }
- /* log_printhex ("RSA n:", m, mlen); */
- send_key_data (ctrl, "n", m, mlen);
-
- e = find_tlv (keydata, keydatalen, 0x0082, &elen);
- if (!e)
- {
- err = gpg_error (GPG_ERR_CARD);
- log_error (_("response does not contain the RSA public exponent\n"));
- goto leave;
- }
- /* log_printhex ("RSA e:", e, elen); */
- send_key_data (ctrl, "e", e, elen);
-
created_at = (u32)(createtime? createtime : gnupg_get_time ());
sprintf (numbuf, "%u", created_at);
send_status_info (ctrl, "KEY-CREATED-AT",
numbuf, (size_t)strlen(numbuf), NULL, 0);
- for (; mlen && !*m; mlen--, m++) /* strip leading zeroes */
- ;
- for (; elen && !*e; elen--, e++) /* strip leading zeroes */
- ;
+ if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA)
+ {
+ const unsigned char *m, *e;
+ size_t mlen, elen;
+
+ m = find_tlv (keydata, keydatalen, 0x0081, &mlen);
+ if (!m)
+ {
+ err = gpg_error (GPG_ERR_CARD);
+ log_error (_("response does not contain the RSA modulus\n"));
+ goto leave;
+ }
+ /* log_printhex ("RSA n:", m, mlen); */
+ send_key_data (ctrl, "n", m, mlen);
+
+ e = find_tlv (keydata, keydatalen, 0x0082, &elen);
+ if (!e)
+ {
+ err = gpg_error (GPG_ERR_CARD);
+ log_error (_("response does not contain the RSA public exponent\n"));
+ goto leave;
+ }
+ /* log_printhex ("RSA e:", e, elen); */
+ send_key_data (ctrl, "e", e, elen);
+
+ for (; mlen && !*m; mlen--, m++) /* strip leading zeroes */
+ ;
+ for (; elen && !*e; elen--, e++) /* strip leading zeroes */
+ ;
+
+ err = store_fpr (app, keyno, created_at, fprbuf, PUBKEY_ALGO_RSA,
+ m, mlen, e, elen);
+ }
+ else if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC)
+ {
+ const unsigned char *ecc_q;
+ size_t ecc_q_len;
+ gcry_mpi_t oid;
+ int n;
+ const unsigned char *oidbuf;
+ size_t oid_len;
+ int algo;
+
+ ecc_q = find_tlv (keydata, keydatalen, 0x0086, &ecc_q_len);
+ if (!ecc_q)
+ {
+ err = gpg_error (GPG_ERR_CARD);
+ log_error (_("response does not contain the EC public key\n"));
+ goto leave;
+ }
+
+ err = openpgp_oid_from_str (app->app_local->keyattr[keyno].ecc.oid, &oid);
+ if (err)
+ goto leave;
+
+ oidbuf = gcry_mpi_get_opaque (oid, &n);
+ if (!oidbuf)
+ {
+ err = gpg_error_from_syserror ();
+ gcry_mpi_release (oid);
+ goto leave;
+ }
+ gcry_mpi_release (oid);
+ oid_len = (n+7)/8;
+
+ if ((app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK))
+ { /* Prepend 0x40 prefix. */
+ unsigned char *q = xtrymalloc (ecc_q_len + 1);
+
+ if (!q)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ *q = 0x40;
+ memcpy (q+1, ecc_q, ecc_q_len);
+ send_key_data (ctrl, "q", q, ecc_q_len + 1);
+ xfree (q);
+ }
+ else
+ {
+ /* strip leading zeroes */
+ for (; ecc_q_len && !*ecc_q; ecc_q_len--, ecc_q++)
+ ;
+ send_key_data (ctrl, "q", ecc_q, ecc_q_len);
+ }
+
+ send_key_data (ctrl, "curve", oidbuf, oid_len);
+
+ if (keyno == 1)
+ {
+ send_key_data (ctrl, "kdf", "\x03\x01\x08\x07", (size_t)4);
+ algo = PUBKEY_ALGO_ECDH;
+ }
+ else
+ {
+ if ((app->app_local->keyattr[keyno].ecc.flags & ECC_FLAG_DJB_TWEAK))
+ algo = PUBKEY_ALGO_EDDSA;
+ else
+ algo = PUBKEY_ALGO_ECDSA;
+ }
+
+ err = store_fpr (app, keyno, created_at, fprbuf, algo, oidbuf, oid_len,
+ ecc_q, ecc_q_len, "\x03\x01\x08\x07", (size_t)4);
+ }
- err = store_fpr (app, keyno, created_at, fprbuf, PUBKEY_ALGO_RSA,
- m, mlen, e, elen);
if (err)
goto leave;
send_fpr_if_not_null (ctrl, "KEY-FPR", -1, fprbuf);