mirror of
git://git.gnupg.org/gnupg.git
synced 2025-02-01 16:33:02 +01:00
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 <arnaud.fontaine@ssi.gouv.fr> Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
This commit is contained in:
parent
f1845f25db
commit
34439da2d6
@ -1318,7 +1318,7 @@ get_public_key (app_t app, int keyno)
|
|||||||
if (!m)
|
if (!m)
|
||||||
{
|
{
|
||||||
err = gpg_error (GPG_ERR_CARD);
|
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;
|
goto leave;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2847,6 +2847,7 @@ change_keyattr_from_string (app_t app,
|
|||||||
size_t oid_len;
|
size_t oid_len;
|
||||||
|
|
||||||
oidstr = openpgp_curve_to_oid (string+n, NULL);
|
oidstr = openpgp_curve_to_oid (string+n, NULL);
|
||||||
|
gcry_mpi_release (oid);
|
||||||
if (!oidstr)
|
if (!oidstr)
|
||||||
{
|
{
|
||||||
err = gpg_error (GPG_ERR_INV_DATA);
|
err = gpg_error (GPG_ERR_INV_DATA);
|
||||||
@ -2864,7 +2865,6 @@ change_keyattr_from_string (app_t app,
|
|||||||
string[0] = algo;
|
string[0] = algo;
|
||||||
memcpy (string+1, oidbuf+1, oid_len-1);
|
memcpy (string+1, oidbuf+1, oid_len-1);
|
||||||
err = change_keyattr (app, keyno, string, oid_len, pincb, pincb_arg);
|
err = change_keyattr (app, keyno, string, oid_len, pincb, pincb_arg);
|
||||||
gcry_mpi_release (oid);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
|
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)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
oidbuf = gcry_mpi_get_opaque (oid, &n);
|
oidbuf = gcry_mpi_get_opaque (oid, &n);
|
||||||
oid_len = (n+7)/8;
|
|
||||||
if (!oidbuf)
|
if (!oidbuf)
|
||||||
{
|
{
|
||||||
err = gpg_error_from_syserror ();
|
err = gpg_error_from_syserror ();
|
||||||
gcry_mpi_release (oid);
|
gcry_mpi_release (oid);
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
gcry_mpi_release (oid);
|
||||||
|
oid_len = (n+7)/8;
|
||||||
|
|
||||||
if (app->app_local->keyattr[keyno].key_type != KEY_TYPE_ECC
|
if (app->app_local->keyattr[keyno].key_type != KEY_TYPE_ECC
|
||||||
|| app->app_local->keyattr[keyno].ecc.oid != oidstr
|
|| 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);
|
ecc_q, ecc_q_len, "\x03\x01\x08\x07", (size_t)4);
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
if (oidbuf)
|
|
||||||
gcry_mpi_release (oid);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3535,16 +3534,15 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
|
|||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
char numbuf[30];
|
char numbuf[30];
|
||||||
unsigned char fprbuf[20];
|
unsigned char fprbuf[20];
|
||||||
const unsigned char *keydata, *m, *e;
|
|
||||||
unsigned char *buffer = NULL;
|
unsigned char *buffer = NULL;
|
||||||
size_t buflen, keydatalen, mlen, elen;
|
const unsigned char *keydata;
|
||||||
|
size_t buflen, keydatalen;
|
||||||
u32 created_at;
|
u32 created_at;
|
||||||
int keyno = atoi (keynostr) - 1;
|
int keyno = atoi (keynostr) - 1;
|
||||||
int force = (flags & 1);
|
int force = (flags & 1);
|
||||||
time_t start_at;
|
time_t start_at;
|
||||||
int exmode;
|
int exmode = 0;
|
||||||
int le_value;
|
int le_value = 256; /* Use legacy value. */
|
||||||
unsigned int keybits;
|
|
||||||
|
|
||||||
if (keyno < 0 || keyno > 2)
|
if (keyno < 0 || keyno > 2)
|
||||||
return gpg_error (GPG_ERR_INV_ID);
|
return gpg_error (GPG_ERR_INV_ID);
|
||||||
@ -3564,19 +3562,17 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
|
|||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
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
|
/* Because we send the key parameter back via status lines we need
|
||||||
to put a limit on the max. allowed keysize. 2048 bit will
|
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
|
already lead to a 527 byte long status line and thus a 4096 bit
|
||||||
key would exceed the Assuan line length limit. */
|
key would exceed the Assuan line length limit. */
|
||||||
keybits = app->app_local->keyattr[keyno].rsa.n_bits;
|
|
||||||
if (keybits > 4096)
|
if (keybits > 4096)
|
||||||
return gpg_error (GPG_ERR_TOO_LARGE);
|
return gpg_error (GPG_ERR_TOO_LARGE);
|
||||||
|
|
||||||
/* Prepare for key generation by verifying the Admin PIN. */
|
|
||||||
err = verify_chv3 (app, pincb, pincb_arg);
|
|
||||||
if (err)
|
|
||||||
goto leave;
|
|
||||||
|
|
||||||
/* Test whether we will need extended length mode. (1900 is an
|
/* Test whether we will need extended length mode. (1900 is an
|
||||||
arbitrary length which for sure fits into a short apdu.) */
|
arbitrary length which for sure fits into a short apdu.) */
|
||||||
if (app->app_local->cardcap.ext_lc_le && keybits > 1900)
|
if (app->app_local->cardcap.ext_lc_le && keybits > 1900)
|
||||||
@ -3587,12 +3583,14 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
|
|||||||
value and thus can't create an overflow on a 32 bit
|
value and thus can't create an overflow on a 32 bit
|
||||||
system. */
|
system. */
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
exmode = 0;
|
|
||||||
le_value = 256; /* Use legacy value. */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Prepare for key generation by verifying the Admin PIN. */
|
||||||
|
err = verify_chv3 (app, pincb, pincb_arg);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
|
||||||
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);
|
||||||
err = iso7816_generate_keypair (app->slot, exmode,
|
err = iso7816_generate_keypair (app->slot, exmode,
|
||||||
@ -3601,9 +3599,8 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
|
|||||||
2, le_value, &buffer, &buflen);
|
2, le_value, &buffer, &buflen);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
err = gpg_error (GPG_ERR_CARD);
|
|
||||||
log_error (_("generating key failed\n"));
|
log_error (_("generating key failed\n"));
|
||||||
goto leave;
|
return gpg_error (GPG_ERR_CARD);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -3621,6 +3618,16 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
|
|||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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);
|
m = find_tlv (keydata, keydatalen, 0x0081, &mlen);
|
||||||
if (!m)
|
if (!m)
|
||||||
{
|
{
|
||||||
@ -3641,11 +3648,6 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
|
|||||||
/* log_printhex ("RSA e:", e, elen); */
|
/* log_printhex ("RSA e:", e, elen); */
|
||||||
send_key_data (ctrl, "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 (; mlen && !*m; mlen--, m++) /* strip leading zeroes */
|
||||||
;
|
;
|
||||||
for (; elen && !*e; elen--, e++) /* strip leading zeroes */
|
for (; elen && !*e; elen--, e++) /* strip leading zeroes */
|
||||||
@ -3653,6 +3655,80 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
|
|||||||
|
|
||||||
err = store_fpr (app, keyno, created_at, fprbuf, PUBKEY_ALGO_RSA,
|
err = store_fpr (app, keyno, created_at, fprbuf, PUBKEY_ALGO_RSA,
|
||||||
m, mlen, e, elen);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
send_fpr_if_not_null (ctrl, "KEY-FPR", -1, fprbuf);
|
send_fpr_if_not_null (ctrl, "KEY-FPR", -1, fprbuf);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user