scd: EdDSA support.

* scd/app-openpgp.c (KEY_TYPE_EDDSA, CURVE_ED25519): New.
(struct app_local_s): Add eddsa.
(get_algo_byte, store_fpr): Support KEY_TYPE_EDDSA.
(get_ecc_key_parameters, get_curve_name): Support CURVE_ED25519.
(send_key_attr, get_public_key): Support KEY_TYPE_EDDSA.
(build_ecc_privkey_template): Rename as it supports both of
ECDSA and EdDSA.
(ecc_writekey): Rename.  Support CURVE_ED25519, too.
(do_writekey): Follow the change of ecc_writekey.
(do_auth): Support KEY_TYPE_EDDSA.
(parse_ecc_curve): Support CURVE_ED25519.  Bug fix for other curves.
(parse_algorithm_attribute): Bug fix for ECDH.  Support EdDSA.
This commit is contained in:
NIIBE Yutaka 2014-04-09 09:30:19 +09:00
parent db85feceaf
commit 3132bd90dc
1 changed files with 120 additions and 42 deletions

View File

@ -122,6 +122,7 @@ typedef enum
{
KEY_TYPE_ECDH,
KEY_TYPE_ECDSA,
KEY_TYPE_EDDSA,
KEY_TYPE_RSA,
}
key_type_t;
@ -146,7 +147,8 @@ enum
CURVE_NIST_P384,
CURVE_NIST_P521,
CURVE_SEC_P256K1,
CURVE_UNKOWN,
CURVE_ED25519,
CURVE_UNKNOWN,
};
@ -235,6 +237,9 @@ struct app_local_s {
struct {
int curve;
} ecdsa;
struct {
int curve;
} eddsa;
struct {
int curve;
int hashalgo;
@ -746,6 +751,8 @@ get_algo_byte (key_type_t key_type)
return 19;
else if (key_type == KEY_TYPE_ECDH)
return 18;
else if (key_type == KEY_TYPE_EDDSA)
return 105; /* (experimental) */
else
return 1; /* RSA */
}
@ -770,7 +777,8 @@ store_fpr (app_t app, int keynumber, u32 timestamp,
int i;
n = 6; /* key packet version, 4-byte timestamps, and algorithm */
if (key_type == KEY_TYPE_RSA || key_type == KEY_TYPE_ECDSA)
if (key_type == KEY_TYPE_RSA || key_type == KEY_TYPE_ECDSA
|| key_type == KEY_TYPE_EDDSA)
argc = 2;
else if (key_type == KEY_TYPE_ECDH)
argc = 3;
@ -935,11 +943,21 @@ get_ecc_key_parameters (int curve, int *r_n_bits, const char **r_curve_oid)
*r_n_bits = 521;
*r_curve_oid = "1.3.132.0.35";
}
else
else if (curve == CURVE_SEC_P256K1)
{
*r_n_bits = 256;
*r_curve_oid = "1.3.132.0.10";
}
else if (curve == CURVE_ED25519)
{
*r_n_bits = 255;
*r_curve_oid = "1.3.6.1.4.1.11591.15.1";
}
else
{
*r_n_bits = 0;
*r_curve_oid = "1.3.6.1.4.1.11591.2.12242973"; /* gnu.gnupg.badoid */
}
}
static void
@ -973,6 +991,13 @@ send_key_attr (ctrl_t ctrl, app_t app, const char *keyword, int number)
app->app_local->keyattr[number].ecdh.hashalgo,
app->app_local->keyattr[number].ecdh.cipheralgo);
}
else if (app->app_local->keyattr[number].key_type == KEY_TYPE_EDDSA)
{
get_ecc_key_parameters (app->app_local->keyattr[number].eddsa.curve,
&n_bits, &curve_oid);
snprintf (buffer, sizeof buffer, "%d 105 %u %s",
number+1, n_bits, curve_oid);
}
else
snprintf (buffer, sizeof buffer, "0 0 UNKNOWN");
@ -1282,8 +1307,12 @@ get_curve_name (int curve)
return "NIST P-384";
else if (curve == CURVE_NIST_P521)
return "NIST P-521";
else
else if (curve == CURVE_SEC_P256K1)
return "secp256k1";
else if (curve == CURVE_ED25519)
return "Ed25519";
else
return "unknown";
}
@ -1455,7 +1484,8 @@ get_public_key (app_t app, int keyno)
goto leave;
}
/* Prepend numbers with a 0 if needed. */
if (mlen && (*m & 0x80))
if (app->app_local->keyattr[keyno].key_type != KEY_TYPE_EDDSA
&& mlen && (*m & 0x80))
{
*mbuf = 0;
memcpy (mbuf+1, m, mlen);
@ -1511,6 +1541,29 @@ get_public_key (app_t app, int keyno)
len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0);
keybuf = xtrymalloc (len);
if (!keybuf)
{
gcry_sexp_release (s_pkey);
err = gpg_error_from_syserror ();
goto leave;
}
gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, keybuf, len);
gcry_sexp_release (s_pkey);
}
else if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_EDDSA)
{
const char *curve_name
= get_curve_name (app->app_local->keyattr[keyno].eddsa.curve);
err = gcry_sexp_build (&s_pkey, NULL,
"(public-key(ecc(curve%s)(flags eddsa)(q%b)))",
curve_name, mlen, mbuf);
if (err)
goto leave;
len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0);
keybuf = xtrymalloc (len);
if (!keybuf)
{
@ -2695,9 +2748,9 @@ build_privkey_template (app_t app, int keyno,
}
static gpg_error_t
build_ecdsa_privkey_template (app_t app, int keyno,
const unsigned char *ecc_d, size_t ecc_d_len,
unsigned char **result, size_t *resultlen)
build_ecc_privkey_template (app_t app, int keyno,
const unsigned char *ecc_d, size_t ecc_d_len,
unsigned char **result, size_t *resultlen)
{
unsigned char privkey[2];
size_t privkey_len;
@ -3189,9 +3242,9 @@ ecdh_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
static gpg_error_t
ecdsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg, int keyno,
const unsigned char *buf, size_t buflen, int depth)
ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg, int keyno,
const unsigned char *buf, size_t buflen, int depth)
{
gpg_error_t err;
const unsigned char *tok;
@ -3204,10 +3257,14 @@ ecdsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
size_t template_len;
unsigned char fprbuf[20];
u32 created_at = 0;
int curve = CURVE_UNKOWN;
int curve = CURVE_UNKNOWN;
/* (private-key(ecdsa(curve%s)(q%m)(d%m))): curve = "1.2.840.10045.3.1.7" */
/* (private-key(ecc(curve%s)(q%m)(d%m))): curve = "secp256k1" */
/* (private-key(ecdsa(curve%s)(q%m)(d%m))(created-at%d)):
curve = "1.2.840.10045.3.1.7" */
/* (private-key(ecc(curve%s)(q%m)(d%m))(created-at%d)):
curve = "secp256k1" */
/* (private-key(ecc(curve%s)(flags eddsa)(q%m)(d%m))(created-at%d)):
curve = "Ed25519" */
last_depth1 = depth;
while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen))
&& depth && depth >= last_depth1)
@ -3229,33 +3286,34 @@ ecdsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
curve = CURVE_NIST_P256;
else if (tok && toklen == 9 && !memcmp (tok, "secp256k1", 9))
curve = CURVE_SEC_P256K1;
else if (tok && toklen == 7 && !memcmp (tok, "Ed25519", 7))
curve = CURVE_ED25519;
}
else if (tok && toklen == 1)
{
const unsigned char **mpi;
size_t *mpi_len;
const unsigned char **buf2;
size_t *buf2len;
switch (*tok)
{
case 'q': mpi = &ecc_q; mpi_len = &ecc_q_len; break;
case 'd': mpi = &ecc_d; mpi_len = &ecc_d_len; break;
default: mpi = NULL; mpi_len = NULL; break;
case 'q': buf2 = &ecc_q; buf2len = &ecc_q_len; break;
case 'd': buf2 = &ecc_d; buf2len = &ecc_d_len; break;
default: buf2 = NULL; buf2len = NULL; break;
}
if (mpi && *mpi)
if (buf2 && *buf2)
{
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;
}
if (tok && buf2 && curve != CURVE_ED25519)
/* It's MPI. Strip off leading zero bytes and save. */
for (;toklen && !*tok; toklen--, tok++)
;
*buf2 = tok;
*buf2len = toklen;
}
/* Skip until end of list. */
last_depth2 = depth;
@ -3322,9 +3380,9 @@ ecdsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
the OpenPGP card specs version 2.0. */
int exmode;
err = build_ecdsa_privkey_template (app, keyno,
ecc_d, ecc_d_len,
&template, &template_len);
err = build_ecc_privkey_template (app, keyno,
ecc_d, ecc_d_len,
&template, &template_len);
if (err)
goto leave;
@ -3353,11 +3411,14 @@ ecdsa_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **),
}
err = store_fpr (app, keyno, created_at, fprbuf, app->card_version,
KEY_TYPE_ECDSA,
curve == CURVE_NIST_P256?
curve == CURVE_ED25519 ? KEY_TYPE_EDDSA : KEY_TYPE_ECDSA,
curve == CURVE_ED25519 ?
"\x09\x2b\x06\x01\x04\x01\xda\x47\x0f\x01"
: curve == CURVE_NIST_P256 ?
"\x08\x2a\x86\x48\xce\x3d\x03\x01\x07"
: "\05\x2b\x81\x04\x00\x0a",
curve == CURVE_NIST_P256? 9 : 6,
curve == CURVE_ED25519 ? 10
: curve == CURVE_NIST_P256? 9 : 6,
ecc_q, ecc_q_len);
if (err)
goto leave;
@ -3435,7 +3496,7 @@ do_writekey (app_t app, ctrl_t ctrl,
else if ((tok && toklen == 3 && memcmp ("ecc", tok, toklen) == 0
&& (keyno == 0 || keyno == 2))
|| (tok && toklen == 5 && memcmp ("ecdsa", tok, toklen) == 0))
ecdsa_writekey (app, pincb, pincb_arg, keyno, buf, buflen, depth);
ecc_writekey (app, pincb, pincb_arg, keyno, buf, buflen, depth);
else if ((tok && toklen == 3 && memcmp ("ecc", tok, toklen) == 0
&& keyno == 1)
|| (tok && toklen == 4 && memcmp ("ecdh", tok, toklen) == 0))
@ -3922,7 +3983,8 @@ do_auth (app_t app, const char *keyidstr,
if (!keyidstr || !*keyidstr)
return gpg_error (GPG_ERR_INV_VALUE);
if (indatalen > 101) /* For a 2048 bit key. */
if (app->app_local->keyattr[2].key_type == KEY_TYPE_RSA
&& indatalen > 101) /* For a 2048 bit key. */
return gpg_error (GPG_ERR_INV_VALUE);
if (app->app_local->keyattr[2].key_type == KEY_TYPE_ECDSA
@ -3932,6 +3994,12 @@ do_auth (app_t app, const char *keyidstr,
indata = p;
indatalen -= 19;
}
else if (app->app_local->keyattr[2].key_type == KEY_TYPE_EDDSA)
{
const char *p = (const char *)indata + 15;
indata = p;
indatalen -= 15;
}
/* Check whether an OpenPGP card of any version has been requested. */
if (!strcmp (keyidstr, "OPENPGP.3"))
@ -4308,14 +4376,18 @@ parse_ecc_curve (const unsigned char *buffer, size_t buflen)
{
int curve;
if (buflen == 6 && buffer[5] == 0x22)
if (buflen == 5 && buffer[5] == 0x22)
curve = CURVE_NIST_P384;
else if (buflen == 6 && buffer[5] == 0x23)
else if (buflen == 5 && buffer[5] == 0x23)
curve = CURVE_NIST_P521;
else if (buflen == 9)
else if (buflen == 8)
curve = CURVE_NIST_P256;
else
else if (buflen == 5 && buffer[5] == 0x0a)
curve = CURVE_SEC_P256K1;
else if (buflen == 9)
curve = CURVE_ED25519;
else
curve = CURVE_UNKNOWN;
return curve;
}
@ -4384,10 +4456,16 @@ parse_algorithm_attribute (app_t app, int keyno)
else if (*buffer == 18 && buflen == 11) /* ECDH */
{
app->app_local->keyattr[keyno].key_type = KEY_TYPE_ECDH;
app->app_local->keyattr[keyno].ecdh.curve
= parse_ecc_curve (buffer + 1, buflen - 1);
app->app_local->keyattr[keyno].ecdh.hashalgo = buffer[1];
app->app_local->keyattr[keyno].ecdh.cipheralgo = buffer[2];
app->app_local->keyattr[keyno].ecdh.curve
= parse_ecc_curve (buffer + 3, buflen - 3);
}
else if (*buffer == 105) /* EdDSA (experimental) */
{
app->app_local->keyattr[keyno].key_type = KEY_TYPE_EDDSA;
app->app_local->keyattr[keyno].eddsa.curve
= parse_ecc_curve (buffer + 1, buflen - 1);
}
else if (opt.verbose)
log_printhex ("", buffer, buflen);