=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/sshkey.c,v retrieving revision 1.84 retrieving revision 1.85 diff -u -r1.84 -r1.85 --- src/usr.bin/ssh/sshkey.c 2019/10/09 00:04:42 1.84 +++ src/usr.bin/ssh/sshkey.c 2019/10/31 21:15:14 1.85 @@ -1,4 +1,4 @@ -/* $OpenBSD: sshkey.c,v 1.84 2019/10/09 00:04:42 djm Exp $ */ +/* $OpenBSD: sshkey.c,v 1.85 2019/10/31 21:15:14 djm Exp $ */ /* * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. * Copyright (c) 2008 Alexander von Gernler. All rights reserved. @@ -115,6 +115,8 @@ KEY_ECDSA, NID_secp384r1, 0, 0 }, { "ecdsa-sha2-nistp521", "ECDSA", NULL, KEY_ECDSA, NID_secp521r1, 0, 0 }, + { "sk-ecdsa-sha2-nistp256@openssh.com", "ECDSA-SK", NULL, + KEY_ECDSA_SK, NID_X9_62_prime256v1, 0, 0 }, { "ssh-rsa-cert-v01@openssh.com", "RSA-CERT", NULL, KEY_RSA_CERT, 0, 1, 0 }, { "rsa-sha2-256-cert-v01@openssh.com", "RSA-CERT", @@ -129,6 +131,8 @@ KEY_ECDSA_CERT, NID_secp384r1, 1, 0 }, { "ecdsa-sha2-nistp521-cert-v01@openssh.com", "ECDSA-CERT", NULL, KEY_ECDSA_CERT, NID_secp521r1, 1, 0 }, + { "sk-ecdsa-sha2-nistp256-cert-v01@openssh.com", "ECDSA-SK-CERT", NULL, + KEY_ECDSA_SK_CERT, NID_X9_62_prime256v1, 1, 0 }, #endif /* WITH_OPENSSL */ { NULL, NULL, NULL, -1, -1, 0, 0 } }; @@ -196,13 +200,26 @@ return KEY_UNSPEC; } +static int +key_type_is_ecdsa_variant(int type) +{ + switch (type) { + case KEY_ECDSA: + case KEY_ECDSA_CERT: + case KEY_ECDSA_SK: + case KEY_ECDSA_SK_CERT: + return 1; + } + return 0; +} + int sshkey_ecdsa_nid_from_name(const char *name) { const struct keytype *kt; for (kt = keytypes; kt->type != -1; kt++) { - if (kt->type != KEY_ECDSA && kt->type != KEY_ECDSA_CERT) + if (!key_type_is_ecdsa_variant(kt->type)) continue; if (kt->name != NULL && strcmp(name, kt->name) == 0) return kt->nid; @@ -298,6 +315,8 @@ return BN_num_bits(dsa_p); case KEY_ECDSA: case KEY_ECDSA_CERT: + case KEY_ECDSA_SK: + case KEY_ECDSA_SK_CERT: return sshkey_curve_nid_to_bits(k->ecdsa_nid); #endif /* WITH_OPENSSL */ case KEY_ED25519: @@ -316,6 +335,7 @@ case KEY_RSA: case KEY_DSA: case KEY_ECDSA: + case KEY_ECDSA_SK: case KEY_ED25519: case KEY_XMSS: return 1; @@ -343,6 +363,8 @@ return KEY_DSA; case KEY_ECDSA_CERT: return KEY_ECDSA; + case KEY_ECDSA_SK_CERT: + return KEY_ECDSA_SK; case KEY_ED25519_CERT: return KEY_ED25519; case KEY_XMSS_CERT: @@ -510,6 +532,8 @@ break; case KEY_ECDSA: case KEY_ECDSA_CERT: + case KEY_ECDSA_SK: + case KEY_ECDSA_SK_CERT: /* Cannot do anything until we know the group */ break; #endif /* WITH_OPENSSL */ @@ -553,6 +577,12 @@ DSA_free(k->dsa); k->dsa = NULL; break; + case KEY_ECDSA_SK: + case KEY_ECDSA_SK_CERT: + free(k->sk_application); + sshbuf_free(k->sk_key_handle); + sshbuf_free(k->sk_reserved); + /* FALLTHROUGH */ case KEY_ECDSA: case KEY_ECDSA_CERT: EC_KEY_free(k->ecdsa); @@ -648,6 +678,13 @@ BN_cmp(dsa_q_a, dsa_q_b) == 0 && BN_cmp(dsa_g_a, dsa_g_b) == 0 && BN_cmp(dsa_pub_key_a, dsa_pub_key_b) == 0; + case KEY_ECDSA_SK: + case KEY_ECDSA_SK_CERT: + if (a->sk_application == NULL || b->sk_application == NULL) + return 0; + if (strcmp(a->sk_application, b->sk_application) != 0) + return 0; + /* FALLTHROUGH */ case KEY_ECDSA_CERT: case KEY_ECDSA: if (a->ecdsa == NULL || b->ecdsa == NULL || @@ -722,6 +759,7 @@ #ifdef WITH_OPENSSL case KEY_DSA_CERT: case KEY_ECDSA_CERT: + case KEY_ECDSA_SK_CERT: case KEY_RSA_CERT: #endif /* WITH_OPENSSL */ case KEY_ED25519_CERT: @@ -747,6 +785,7 @@ return ret; break; case KEY_ECDSA: + case KEY_ECDSA_SK: if (key->ecdsa == NULL) return SSH_ERR_INVALID_ARGUMENT; if ((ret = sshbuf_put_cstring(b, typename)) != 0 || @@ -754,6 +793,11 @@ sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 || (ret = sshbuf_put_eckey(b, key->ecdsa)) != 0) return ret; + if (type == KEY_ECDSA_SK) { + if ((ret = sshbuf_put_cstring(b, + key->sk_application)) != 0) + return ret; + } break; case KEY_RSA: if (key->rsa == NULL) @@ -1186,7 +1230,7 @@ continue; if (memcmp(s, kt->name, l) == 0) { *nid = -1; - if (kt->type == KEY_ECDSA || kt->type == KEY_ECDSA_CERT) + if (key_type_is_ecdsa_variant(kt->type)) *nid = kt->nid; return kt->type; } @@ -1213,9 +1257,11 @@ case KEY_RSA: case KEY_DSA: case KEY_ECDSA: + case KEY_ECDSA_SK: case KEY_ED25519: case KEY_DSA_CERT: case KEY_ECDSA_CERT: + case KEY_ECDSA_SK_CERT: case KEY_RSA_CERT: case KEY_ED25519_CERT: #ifdef WITH_XMSS @@ -1272,7 +1318,7 @@ sshkey_free(k); return SSH_ERR_KEY_TYPE_MISMATCH; } - if (sshkey_type_plain(type) == KEY_ECDSA && curve_nid != k->ecdsa_nid) { + if (key_type_is_ecdsa_variant(type) && curve_nid != k->ecdsa_nid) { sshkey_free(k); return SSH_ERR_EC_CURVE_MISMATCH; } @@ -1317,6 +1363,19 @@ sshkey_dump_ec_key(ret->ecdsa); #endif break; + case KEY_ECDSA_SK: + EC_KEY_free(ret->ecdsa); + ret->ecdsa = k->ecdsa; + ret->ecdsa_nid = k->ecdsa_nid; + ret->sk_application = k->sk_application; + k->ecdsa = NULL; + k->ecdsa_nid = -1; + k->sk_application = NULL; +#ifdef DEBUG_PK + sshkey_dump_ec_key(ret->ecdsa); + fprintf(stderr, "App: %s\n", ret->sk_application); +#endif + break; #endif /* WITH_OPENSSL */ case KEY_ED25519: freezero(ret->ed25519_pk, ED25519_PK_SZ); @@ -1708,15 +1767,14 @@ #endif /* WITH_OPENSSL */ *pkp = NULL; + if ((n = sshkey_new(k->type)) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } switch (k->type) { #ifdef WITH_OPENSSL case KEY_DSA: case KEY_DSA_CERT: - if ((n = sshkey_new(k->type)) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } - DSA_get0_pqg(k->dsa, &dsa_p, &dsa_q, &dsa_g); DSA_get0_key(k->dsa, &dsa_pub_key, NULL); if ((dsa_p_dup = BN_dup(dsa_p)) == NULL || @@ -1740,10 +1798,8 @@ break; case KEY_ECDSA: case KEY_ECDSA_CERT: - if ((n = sshkey_new(k->type)) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } + case KEY_ECDSA_SK: + case KEY_ECDSA_SK_CERT: n->ecdsa_nid = k->ecdsa_nid; n->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid); if (n->ecdsa == NULL) { @@ -1755,13 +1811,14 @@ r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } + if (k->type != KEY_ECDSA_SK && k->type != KEY_ECDSA_SK_CERT) + break; + /* Append security-key application string */ + if ((n->sk_application = strdup(k->sk_application)) == NULL) + goto out; break; case KEY_RSA: case KEY_RSA_CERT: - if ((n = sshkey_new(k->type)) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } RSA_get0_key(k->rsa, &rsa_n, &rsa_e, NULL); if ((rsa_n_dup = BN_dup(rsa_n)) == NULL || (rsa_e_dup = BN_dup(rsa_e)) == NULL) { @@ -1777,10 +1834,6 @@ #endif /* WITH_OPENSSL */ case KEY_ED25519: case KEY_ED25519_CERT: - if ((n = sshkey_new(k->type)) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } if (k->ed25519_pk != NULL) { if ((n->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL) { r = SSH_ERR_ALLOC_FAIL; @@ -1792,10 +1845,6 @@ #ifdef WITH_XMSS case KEY_XMSS: case KEY_XMSS_CERT: - if ((n = sshkey_new(k->type)) == NULL) { - r = SSH_ERR_ALLOC_FAIL; - goto out; - } if ((r = sshkey_xmss_init(n, k->xmss_name)) != 0) goto out; if (k->xmss_pk != NULL) { @@ -2286,6 +2335,7 @@ #endif break; case KEY_ECDSA_CERT: + case KEY_ECDSA_SK_CERT: /* Skip nonce */ if (sshbuf_get_string_direct(b, NULL, NULL) != 0) { ret = SSH_ERR_INVALID_FORMAT; @@ -2293,6 +2343,7 @@ } /* FALLTHROUGH */ case KEY_ECDSA: + case KEY_ECDSA_SK: if ((key = sshkey_new(type)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; @@ -2333,6 +2384,17 @@ #ifdef DEBUG_PK sshkey_dump_ec_point(EC_KEY_get0_group(key->ecdsa), q); #endif + if (type == KEY_ECDSA_SK || type == KEY_ECDSA_SK_CERT) { + /* Parse additional security-key application string */ + if (sshbuf_get_cstring(b, &key->sk_application, + NULL) != 0) { + ret = SSH_ERR_INVALID_FORMAT; + goto out; + } +#ifdef DEBUG_PK + fprintf(stderr, "App: %s\n", key->sk_application); +#endif + } break; #endif /* WITH_OPENSSL */ case KEY_ED25519_CERT: @@ -2615,6 +2677,10 @@ case KEY_ECDSA_CERT: case KEY_ECDSA: return ssh_ecdsa_verify(key, sig, siglen, data, dlen, compat); + case KEY_ECDSA_SK_CERT: + case KEY_ECDSA_SK: + return ssh_ecdsa_sk_verify(key, sig, siglen, data, dlen, + compat); case KEY_RSA_CERT: case KEY_RSA: return ssh_rsa_verify(key, sig, siglen, data, dlen, alg); @@ -2649,6 +2715,9 @@ case KEY_ECDSA: newtype = KEY_ECDSA_CERT; break; + case KEY_ECDSA_SK: + newtype = KEY_ECDSA_SK_CERT; + break; #endif /* WITH_OPENSSL */ case KEY_ED25519: newtype = KEY_ED25519_CERT; @@ -2745,12 +2814,18 @@ goto out; break; case KEY_ECDSA_CERT: + case KEY_ECDSA_SK_CERT: if ((ret = sshbuf_put_cstring(cert, sshkey_curve_nid_to_name(k->ecdsa_nid))) != 0 || (ret = sshbuf_put_ec(cert, EC_KEY_get0_public_key(k->ecdsa), EC_KEY_get0_group(k->ecdsa))) != 0) goto out; + if (k->type == KEY_ECDSA_SK_CERT) { + if ((ret = sshbuf_put_cstring(cert, + k->sk_application)) != 0) + goto out; + } break; case KEY_RSA_CERT: RSA_get0_key(k->rsa, &rsa_n, &rsa_e, NULL); @@ -3028,6 +3103,28 @@ EC_KEY_get0_private_key(key->ecdsa))) != 0) goto out; break; + case KEY_ECDSA_SK: + if ((r = sshbuf_put_cstring(b, + sshkey_curve_nid_to_name(key->ecdsa_nid))) != 0 || + (r = sshbuf_put_eckey(b, key->ecdsa)) != 0 || + (r = sshbuf_put_cstring(b, key->sk_application)) != 0 || + (r = sshbuf_put_u8(b, key->sk_flags)) != 0 || + (r = sshbuf_put_stringb(b, key->sk_key_handle)) != 0 || + (r = sshbuf_put_stringb(b, key->sk_reserved)) != 0) + goto out; + break; + case KEY_ECDSA_SK_CERT: + if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0) { + r = SSH_ERR_INVALID_ARGUMENT; + goto out; + } + if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 || + (r = sshbuf_put_cstring(b, key->sk_application)) != 0 || + (r = sshbuf_put_u8(b, key->sk_flags)) != 0 || + (r = sshbuf_put_stringb(b, key->sk_key_handle)) != 0 || + (r = sshbuf_put_stringb(b, key->sk_reserved)) != 0) + goto out; + break; #endif /* WITH_OPENSSL */ case KEY_ED25519: if ((r = sshbuf_put_string(b, key->ed25519_pk, @@ -3214,6 +3311,60 @@ (r = sshkey_ec_validate_private(k->ecdsa)) != 0) goto out; break; + case KEY_ECDSA_SK: + if ((k = sshkey_new(type)) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + if ((k->ecdsa_nid = sshkey_ecdsa_nid_from_name(tname)) == -1) { + r = SSH_ERR_INVALID_ARGUMENT; + goto out; + } + if ((r = sshbuf_get_cstring(buf, &curve, NULL)) != 0) + goto out; + if (k->ecdsa_nid != sshkey_curve_name_to_nid(curve)) { + r = SSH_ERR_EC_CURVE_MISMATCH; + goto out; + } + if ((k->sk_key_handle = sshbuf_new()) == NULL || + (k->sk_reserved = sshbuf_new()) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + k->ecdsa = EC_KEY_new_by_curve_name(k->ecdsa_nid); + if (k->ecdsa == NULL) { + r = SSH_ERR_LIBCRYPTO_ERROR; + goto out; + } + if ((r = sshbuf_get_eckey(buf, k->ecdsa)) != 0 || + (r = sshbuf_get_cstring(buf, &k->sk_application, + NULL)) != 0 || + (r = sshbuf_get_u8(buf, &k->sk_flags)) != 0 || + (r = sshbuf_get_stringb(buf, k->sk_key_handle)) != 0 || + (r = sshbuf_get_stringb(buf, k->sk_reserved)) != 0) + goto out; + if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(k->ecdsa), + EC_KEY_get0_public_key(k->ecdsa))) != 0) + goto out; + break; + case KEY_ECDSA_SK_CERT: + if ((r = sshkey_froms(buf, &k)) != 0) + goto out; + if ((k->sk_key_handle = sshbuf_new()) == NULL || + (k->sk_reserved = sshbuf_new()) == NULL) { + r = SSH_ERR_ALLOC_FAIL; + goto out; + } + if ((r = sshbuf_get_cstring(buf, &k->sk_application, + NULL)) != 0 || + (r = sshbuf_get_u8(buf, &k->sk_flags)) != 0 || + (r = sshbuf_get_stringb(buf, k->sk_key_handle)) != 0 || + (r = sshbuf_get_stringb(buf, k->sk_reserved)) != 0) + goto out; + if ((r = sshkey_ec_validate_public(EC_KEY_get0_group(k->ecdsa), + EC_KEY_get0_public_key(k->ecdsa))) != 0) + goto out; + break; case KEY_RSA: if ((k = sshkey_new(type)) == NULL) { r = SSH_ERR_ALLOC_FAIL; @@ -4031,6 +4182,9 @@ #ifdef WITH_XMSS case KEY_XMSS: #endif /* WITH_XMSS */ +#ifdef WITH_OPENSSL + case KEY_ECDSA_SK: +#endif /* WITH_OPENSSL */ return sshkey_private_to_blob2(key, blob, passphrase, comment, openssh_format_cipher, openssh_format_rounds); default: @@ -4051,7 +4205,6 @@ } #endif /* WITH_OPENSSL */ } - #ifdef WITH_OPENSSL static int