diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index bdb55eb4d..72b27ecfa 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -824,10 +824,12 @@ parse_login_data (app_t app) #define MAX_ARGS_STORE_FPR 3 -/* Note, that FPR must be at least 20 bytes. */ +/* Note, that FPR must be at least 20 bytes. If UPDATE is not set, + * the fingerprint and the creation date is not actually stored but + * the fingerprint is only returned in FPR. */ static gpg_error_t -store_fpr (app_t app, int keynumber, u32 timestamp, unsigned char *fpr, - int algo, ...) +store_fpr (app_t app, int update, int keynumber, u32 timestamp, + unsigned char *fpr, int algo, ...) { unsigned int n, nbits; unsigned char *buffer, *p; @@ -892,6 +894,9 @@ store_fpr (app_t app, int keynumber, u32 timestamp, unsigned char *fpr, xfree (buffer); + if (!update) + return 0; + tag = (app->appversion > 0x0007? 0xC7 : 0xC6) + keynumber; flush_cache_item (app, 0xC5); tag2 = 0xCE + keynumber; @@ -1539,7 +1544,8 @@ retrieve_key_material (FILE *fp, const char *hexkeyid, static gpg_error_t -rsa_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at, int keyno, +rsa_read_pubkey (app_t app, ctrl_t ctrl, int meta_update, + u32 created_at, int keyno, const unsigned char *data, size_t datalen, gcry_sexp_t *r_sexp) { gpg_error_t err; @@ -1576,7 +1582,11 @@ rsa_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at, int keyno, { unsigned char fprbuf[20]; - err = store_fpr (app, keyno, created_at, fprbuf, PUBKEY_ALGO_RSA, + /* If META_UPDATE is not set we only compute but not store the + * fingerprint. This might return a wrong fingerprint if + * CREATED_AT is not set. */ + err = store_fpr (app, meta_update, keyno, + created_at, fprbuf, PUBKEY_ALGO_RSA, m, mlen, e, elen); if (err) return err; @@ -1638,6 +1648,8 @@ ecdh_params (const char *curve) 0x01: Version for this parameter format KDF hash algo KEK symmetric cipher algo + Take care: They should match the parameters as used in g10/ecdh.c + as long as the ecdh-param is not fully support (as in gnupg 2.2). */ if (nbits <= 256) return (const unsigned char*)"\x03\x01\x08\x07"; @@ -1648,7 +1660,8 @@ ecdh_params (const char *curve) } static gpg_error_t -ecc_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at, int keyno, +ecc_read_pubkey (app_t app, ctrl_t ctrl, int meta_update, + u32 created_at, int keyno, const unsigned char *data, size_t datalen, gcry_sexp_t *r_sexp) { gpg_error_t err; @@ -1724,7 +1737,12 @@ ecc_read_pubkey (app_t app, ctrl_t ctrl, u32 created_at, int keyno, { unsigned char fprbuf[20]; - err = store_fpr (app, keyno, created_at, fprbuf, algo, oidbuf, oid_len, + /* If META_UPDATE is not set we only compute but not store the + * fingerprint. This might return a wrong fingerprint if + * CREATED_AT is not set or the ECDH params do not match the + * current defaults. */ + err = store_fpr (app, meta_update, keyno, + created_at, fprbuf, algo, oidbuf, oid_len, qbuf, ecc_q_len, ecdh_params (curve), (size_t)4); if (err) goto leave; @@ -1768,13 +1786,15 @@ store_keygrip (app_t app, int keyno) /* Parse tag-length-value data for public key in BUFFER of BUFLEN - length. Key of KEYNO in APP is updated with an S-expression of - public key. When CTRL is not NULL, fingerprint is computed with - CREATED_AT, and fingerprint is written to the card, and key data - and fingerprint are send back to the client side. + * length. Key of KEYNO in APP is updated with an S-expression of + * public key. If CTRL is not NULL, the fingerprint is computed with + * CREATED_AT and key data and fingerprint are send back to the client + * side. If also META_UPDATE is true the fingerprint and the creation + * date are also written to the card. */ static gpg_error_t -read_public_key (app_t app, ctrl_t ctrl, u32 created_at, int keyno, +read_public_key (app_t app, ctrl_t ctrl, int meta_update, + u32 created_at, int keyno, const unsigned char *buffer, size_t buflen) { gpg_error_t err; @@ -1790,10 +1810,10 @@ read_public_key (app_t app, ctrl_t ctrl, u32 created_at, int keyno, } if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA) - err = rsa_read_pubkey (app, ctrl, created_at, keyno, + err = rsa_read_pubkey (app, ctrl, meta_update, created_at, keyno, data, datalen, &s_pkey); else if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_ECC) - err = ecc_read_pubkey (app, ctrl, created_at, keyno, + err = ecc_read_pubkey (app, ctrl, meta_update, created_at, keyno, data, datalen, &s_pkey); else err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); @@ -1897,7 +1917,11 @@ get_public_key (app_t app, int keyno) goto leave; } - err = read_public_key (app, NULL, 0U, keyno, buffer, buflen); + /* Note that we use 0 for the creation date and thus the - via + * status lines - returned fingerprint will only be valid if the + * key has also been created with that date. A similar problem + * occurs with the ECDH params which are fixed in the code. */ + err = read_public_key (app, NULL, 0, 0U, keyno, buffer, buflen); } else { @@ -4156,7 +4180,7 @@ rsa_writekey (app_t app, ctrl_t ctrl, goto leave; } - err = store_fpr (app, keyno, created_at, fprbuf, PUBKEY_ALGO_RSA, + err = store_fpr (app, 1, keyno, created_at, fprbuf, PUBKEY_ALGO_RSA, rsa_n, rsa_n_len, rsa_e, rsa_e_len); if (err) goto leave; @@ -4181,6 +4205,8 @@ ecc_writekey (app_t app, ctrl_t ctrl, const unsigned char *ecc_q = NULL; const unsigned char *ecc_d = NULL; size_t ecc_q_len, ecc_d_len; + const unsigned char *ecdh_param = NULL; + size_t ecdh_param_len = 0; const char *curve = NULL; u32 created_at = 0; const char *oidstr; @@ -4193,7 +4219,7 @@ ecc_writekey (app_t app, ctrl_t ctrl, unsigned char fprbuf[20]; size_t ecc_d_fixed_len; - /* (private-key(ecc(curve%s)(q%m)(d%m))(created-at%d)): + /* (private-key(ecc(curve%s)(q%m)(d%m))(created-at%d)(ecdh-params%s)): curve = "NIST P-256" */ /* (private-key(ecc(curve%s)(q%m)(d%m))(created-at%d)): curve = "secp256k1" */ @@ -4292,6 +4318,7 @@ ecc_writekey (app_t app, ctrl_t ctrl, } 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))) @@ -4303,6 +4330,17 @@ ecc_writekey (app_t app, ctrl_t ctrl, created_at = created_at*10 + (*tok - '0'); } } + else if (tok && toklen == 11 && !memcmp ("ecdh-params", tok, toklen)) + { + if ((err = parse_sexp (&buf,&buflen,&depth,&tok,&toklen))) + goto leave; + if (tok) + { + ecdh_param = tok; + ecdh_param_len = toklen; + } + } + /* Skip until end of list. */ last_depth2 = depth; while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)) @@ -4334,6 +4372,20 @@ ecc_writekey (app_t app, ctrl_t ctrl, else algo = PUBKEY_ALGO_ECDSA; + /* Not provided by GnuPG 2.2 - take the default value. */ + if (algo == PUBKEY_ALGO_ECDH && !ecdh_param) + { + ecdh_param = ecdh_params (curve); + ecdh_param_len = 4; + } + + if (algo == PUBKEY_ALGO_ECDH && !ecdh_param) + { + log_error ("opgp: ecdh parameters missing\n"); + err = gpg_error (GPG_ERR_INV_VALUE); + goto leave; + } + oidstr = openpgp_curve_to_oid (curve, &n, NULL); ecc_d_fixed_len = (n+7)/8; err = openpgp_oid_from_str (oidstr, &oid); @@ -4435,8 +4487,8 @@ ecc_writekey (app_t app, ctrl_t ctrl, goto leave; } - err = store_fpr (app, keyno, created_at, fprbuf, algo, oidbuf, oid_len, - ecc_q, ecc_q_len, ecdh_params (curve), (size_t)4); + err = store_fpr (app, 1, keyno, created_at, fprbuf, algo, oidbuf, oid_len, + ecc_q, ecc_q_len, ecdh_param, ecdh_param_len); leave: gcry_mpi_release (oid); @@ -4661,7 +4713,7 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keyref, const char *keyalgo, send_status_info (ctrl, "KEY-CREATED-AT", numbuf, (size_t)strlen(numbuf), NULL, 0); - err = read_public_key (app, ctrl, created_at, keyno, buffer, buflen); + err = read_public_key (app, ctrl, 1, created_at, keyno, buffer, buflen); leave: xfree (buffer); return err;