From 0751571cac0f5aef2862c34a184f7f09ad9cb203 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Wed, 5 Aug 2015 07:59:50 +0900 Subject: [PATCH] scd: Fix ECC support. * scd/app-openpgp.c (send_key_attr): Send KEYNO. (get_public_key): Fix SEXP composing. (ecc_writekey): Fix OID length calculation. (ecc_oid): Prepend the length before query. (parse_algorithm_attribute): Handle the case the curve is not available. --- scd/app-openpgp.c | 61 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 87208f44c..83465f4aa 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -914,7 +914,7 @@ send_key_attr (ctrl_t ctrl, app_t app, const char *keyword, int keyno) openpgp_oid_to_curve (app->app_local->keyattr[keyno].ecc.oid)); } else - snprintf (buffer, sizeof buffer, "0 0 UNKNOWN"); + snprintf (buffer, sizeof buffer, "%d 0 0 UNKNOWN", keyno+1); send_status_direct (ctrl, keyword, buffer); } @@ -1434,11 +1434,15 @@ get_public_key (app_t app, int keyno) } else if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC) { - err = gcry_sexp_build (&s_pkey, NULL, - "(public-key(ecc(curve%s)%s(q%b)))", - openpgp_oid_to_curve (app->app_local->keyattr[keyno].ecc.oid), - app->app_local->keyattr[keyno].ecc.flags? - "(flags eddsa)" : "", + char *format; + + if (!app->app_local->keyattr[keyno].ecc.flags) + format = "(public-key(ecc(curve%s)(q%b)))"; + else + format = "(public-key(ecc(curve%s)(flags eddsa)(q%b)))"; + + err = gcry_sexp_build (&s_pkey, NULL, format, + openpgp_oid_to_curve (app->app_local->keyattr[keyno].ecc.oid), (int)mlen, mbuf); if (err) goto leave; @@ -3375,7 +3379,7 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), goto leave; oidbuf = gcry_mpi_get_opaque (oid, &n); - oid_len = n; + oid_len = (n+7)/8; if (!oidbuf) { err = gpg_error_from_syserror (); @@ -3383,8 +3387,8 @@ ecc_writekey (app_t app, gpg_error_t (*pincb)(void*, const char *, char **), goto leave; } err = store_fpr (app, keyno, created_at, fprbuf, algo, - oidbuf, oid_len, ecc_q, ecc_q_len, - "\x03\x01\x08\x07", (size_t)4); + oidbuf, oid_len, ecc_q, ecc_q_len, + "\x03\x01\x08\x07", (size_t)4); gcry_mpi_release (oid); } @@ -4362,16 +4366,32 @@ parse_historical (struct app_local_s *apploc, } +/* + * Check if the OID in an DER encoding is available by GnuPG/libgcrypt, + * and return the constant string in dotted decimal form. + * Return NULL if not available. + * The constant string is not allocated dynamically, never free it. + */ static const char * ecc_oid (unsigned char *buf, size_t buflen) { gcry_mpi_t oid; char *oidstr; const char *result; + unsigned char *oidbuf; + oidbuf = xtrymalloc (buflen + 1); + if (!oidbuf) + return NULL; + + memcpy (oidbuf+1, buf, buflen); + oidbuf[0] = buflen; oid = gcry_mpi_set_opaque (NULL, buf, buflen * 8); if (!oid) - return NULL; + { + xfree (oidbuf); + return NULL; + } oidstr = openpgp_oid_to_str (oid); gcry_mpi_release (oid); @@ -4441,13 +4461,20 @@ parse_algorithm_attribute (app_t app, int keyno) else if (*buffer == PUBKEY_ALGO_ECDH || *buffer == PUBKEY_ALGO_ECDSA || *buffer == PUBKEY_ALGO_EDDSA) { - app->app_local->keyattr[keyno].key_type = KEY_TYPE_ECC; - app->app_local->keyattr[keyno].ecc.oid = ecc_oid (buffer + 1, buflen - 1); - app->app_local->keyattr[keyno].ecc.flags = (*buffer == PUBKEY_ALGO_EDDSA); - if (opt.verbose) - log_printf - ("ECC, curve=%s%s\n", app->app_local->keyattr[keyno].ecc.oid, - app->app_local->keyattr[keyno].ecc.flags ? " (eddsa)": ""); + const char *oid = ecc_oid (buffer + 1, buflen - 1); + + if (!oid) + log_printhex ("Curve with OID not supported: ", buffer+1, buflen-1); + else + { + app->app_local->keyattr[keyno].key_type = KEY_TYPE_ECC; + app->app_local->keyattr[keyno].ecc.oid = oid; + app->app_local->keyattr[keyno].ecc.flags = (*buffer == PUBKEY_ALGO_EDDSA); + if (opt.verbose) + log_printf + ("ECC, curve=%s%s\n", app->app_local->keyattr[keyno].ecc.oid, + app->app_local->keyattr[keyno].ecc.flags ? " (eddsa)": ""); + } } else if (opt.verbose) log_printhex ("", buffer, buflen);