diff options
Diffstat (limited to 'sshconnect2.c')
-rw-r--r-- | sshconnect2.c | 111 |
1 files changed, 86 insertions, 25 deletions
diff --git a/sshconnect2.c b/sshconnect2.c index 87fa70a40..62f0c3e76 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshconnect2.c,v 1.308 2019/08/05 11:50:33 dtucker Exp $ */ | 1 | /* $OpenBSD: sshconnect2.c,v 1.309 2019/10/31 21:18:28 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * Copyright (c) 2008 Damien Miller. All rights reserved. | 4 | * Copyright (c) 2008 Damien Miller. All rights reserved. |
@@ -72,6 +72,7 @@ | |||
72 | #include "hostfile.h" | 72 | #include "hostfile.h" |
73 | #include "ssherr.h" | 73 | #include "ssherr.h" |
74 | #include "utf8.h" | 74 | #include "utf8.h" |
75 | #include "ssh-sk.h" | ||
75 | 76 | ||
76 | #ifdef GSSAPI | 77 | #ifdef GSSAPI |
77 | #include "ssh-gss.h" | 78 | #include "ssh-gss.h" |
@@ -601,17 +602,23 @@ static char * | |||
601 | format_identity(Identity *id) | 602 | format_identity(Identity *id) |
602 | { | 603 | { |
603 | char *fp = NULL, *ret = NULL; | 604 | char *fp = NULL, *ret = NULL; |
605 | const char *note = ""; | ||
604 | 606 | ||
605 | if (id->key != NULL) { | 607 | if (id->key != NULL) { |
606 | fp = sshkey_fingerprint(id->key, options.fingerprint_hash, | 608 | fp = sshkey_fingerprint(id->key, options.fingerprint_hash, |
607 | SSH_FP_DEFAULT); | 609 | SSH_FP_DEFAULT); |
608 | } | 610 | } |
611 | if (id->key) { | ||
612 | if ((id->key->flags & SSHKEY_FLAG_EXT) != 0) | ||
613 | note = " token"; | ||
614 | else if (sshkey_type_plain(id->key->type) == KEY_ECDSA_SK) | ||
615 | note = " security-key"; | ||
616 | } | ||
609 | xasprintf(&ret, "%s %s%s%s%s%s%s", | 617 | xasprintf(&ret, "%s %s%s%s%s%s%s", |
610 | id->filename, | 618 | id->filename, |
611 | id->key ? sshkey_type(id->key) : "", id->key ? " " : "", | 619 | id->key ? sshkey_type(id->key) : "", id->key ? " " : "", |
612 | fp ? fp : "", | 620 | fp ? fp : "", |
613 | id->userprovided ? " explicit" : "", | 621 | id->userprovided ? " explicit" : "", note, |
614 | (id->key && (id->key->flags & SSHKEY_FLAG_EXT)) ? " token" : "", | ||
615 | id->agent_fd != -1 ? " agent" : ""); | 622 | id->agent_fd != -1 ? " agent" : ""); |
616 | free(fp); | 623 | free(fp); |
617 | return ret; | 624 | return ret; |
@@ -1140,8 +1147,11 @@ static int | |||
1140 | identity_sign(struct identity *id, u_char **sigp, size_t *lenp, | 1147 | identity_sign(struct identity *id, u_char **sigp, size_t *lenp, |
1141 | const u_char *data, size_t datalen, u_int compat, const char *alg) | 1148 | const u_char *data, size_t datalen, u_int compat, const char *alg) |
1142 | { | 1149 | { |
1143 | struct sshkey *prv; | 1150 | struct sshkey *sign_key = NULL, *prv = NULL; |
1144 | int r; | 1151 | int r = SSH_ERR_INTERNAL_ERROR; |
1152 | |||
1153 | *sigp = NULL; | ||
1154 | *lenp = 0; | ||
1145 | 1155 | ||
1146 | /* The agent supports this key. */ | 1156 | /* The agent supports this key. */ |
1147 | if (id->key != NULL && id->agent_fd != -1) { | 1157 | if (id->key != NULL && id->agent_fd != -1) { |
@@ -1155,27 +1165,46 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp, | |||
1155 | */ | 1165 | */ |
1156 | if (id->key != NULL && | 1166 | if (id->key != NULL && |
1157 | (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT))) { | 1167 | (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT))) { |
1158 | if ((r = sshkey_sign(id->key, sigp, lenp, data, datalen, | 1168 | sign_key = id->key; |
1159 | alg, compat)) != 0) | 1169 | } else { |
1160 | return r; | 1170 | /* Load the private key from the file. */ |
1161 | /* | 1171 | if ((prv = load_identity_file(id)) == NULL) |
1162 | * PKCS#11 tokens may not support all signature algorithms, | 1172 | return SSH_ERR_KEY_NOT_FOUND; |
1163 | * so check what we get back. | 1173 | if (id->key != NULL && !sshkey_equal_public(prv, id->key)) { |
1164 | */ | 1174 | error("%s: private key %s contents do not match public", |
1165 | if ((r = sshkey_check_sigtype(*sigp, *lenp, alg)) != 0) | 1175 | __func__, id->filename); |
1166 | return r; | 1176 | r = SSH_ERR_KEY_NOT_FOUND; |
1167 | return 0; | 1177 | goto out; |
1178 | } | ||
1179 | sign_key = prv; | ||
1168 | } | 1180 | } |
1169 | 1181 | ||
1170 | /* Load the private key from the file. */ | 1182 | if (sshkey_type_plain(sign_key->type) == KEY_ECDSA_SK) { |
1171 | if ((prv = load_identity_file(id)) == NULL) | 1183 | if (options.sk_provider == NULL) { |
1172 | return SSH_ERR_KEY_NOT_FOUND; | 1184 | /* Shouldn't happen here; checked in pubkey_prepare() */ |
1173 | if (id->key != NULL && !sshkey_equal_public(prv, id->key)) { | 1185 | fatal("%s: missing SecurityKeyProvider", __func__); |
1174 | error("%s: private key %s contents do not match public", | 1186 | } |
1175 | __func__, id->filename); | 1187 | if ((r = sshsk_ecdsa_sign(options.sk_provider, sign_key, |
1176 | return SSH_ERR_KEY_NOT_FOUND; | 1188 | sigp, lenp, data, datalen, compat)) != 0) { |
1189 | debug("%s: sshsk_ecdsa_sign: %s", __func__, ssh_err(r)); | ||
1190 | goto out; | ||
1191 | } | ||
1192 | } else if ((r = sshkey_sign(sign_key, sigp, lenp, data, datalen, | ||
1193 | alg, compat)) != 0) { | ||
1194 | debug("%s: sshkey_sign: %s", __func__, ssh_err(r)); | ||
1195 | goto out; | ||
1177 | } | 1196 | } |
1178 | r = sshkey_sign(prv, sigp, lenp, data, datalen, alg, compat); | 1197 | /* |
1198 | * PKCS#11 tokens may not support all signature algorithms, | ||
1199 | * so check what we get back. | ||
1200 | */ | ||
1201 | if ((r = sshkey_check_sigtype(*sigp, *lenp, alg)) != 0) { | ||
1202 | debug("%s: sshkey_check_sigtype: %s", __func__, ssh_err(r)); | ||
1203 | goto out; | ||
1204 | } | ||
1205 | /* success */ | ||
1206 | r = 0; | ||
1207 | out: | ||
1179 | sshkey_free(prv); | 1208 | sshkey_free(prv); |
1180 | return r; | 1209 | return r; |
1181 | } | 1210 | } |
@@ -1450,6 +1479,15 @@ load_identity_file(Identity *id) | |||
1450 | quit = 1; | 1479 | quit = 1; |
1451 | break; | 1480 | break; |
1452 | } | 1481 | } |
1482 | if (private != NULL && | ||
1483 | sshkey_type_plain(private->type) == KEY_ECDSA_SK && | ||
1484 | options.sk_provider == NULL) { | ||
1485 | debug("key \"%s\" is a security key, but no " | ||
1486 | "provider specified", id->filename); | ||
1487 | sshkey_free(private); | ||
1488 | private = NULL; | ||
1489 | quit = 1; | ||
1490 | } | ||
1453 | if (!quit && private != NULL && id->agent_fd == -1 && | 1491 | if (!quit && private != NULL && id->agent_fd == -1 && |
1454 | !(id->key && id->isprivate)) | 1492 | !(id->key && id->isprivate)) |
1455 | maybe_add_key_to_agent(id->filename, private, comment, | 1493 | maybe_add_key_to_agent(id->filename, private, comment, |
@@ -1520,8 +1558,20 @@ pubkey_prepare(Authctxt *authctxt) | |||
1520 | /* list of keys stored in the filesystem and PKCS#11 */ | 1558 | /* list of keys stored in the filesystem and PKCS#11 */ |
1521 | for (i = 0; i < options.num_identity_files; i++) { | 1559 | for (i = 0; i < options.num_identity_files; i++) { |
1522 | key = options.identity_keys[i]; | 1560 | key = options.identity_keys[i]; |
1523 | if (key && key->cert && key->cert->type != SSH2_CERT_TYPE_USER) | 1561 | if (key && key->cert && |
1562 | key->cert->type != SSH2_CERT_TYPE_USER) { | ||
1563 | debug("%s: ignoring certificate %s: not a user " | ||
1564 | "certificate", __func__, | ||
1565 | options.identity_files[i]); | ||
1566 | continue; | ||
1567 | } | ||
1568 | if (key && sshkey_type_plain(key->type) == KEY_ECDSA_SK && | ||
1569 | options.sk_provider == NULL) { | ||
1570 | debug("%s: ignoring security key %s as no " | ||
1571 | "SecurityKeyProvider has been specified", | ||
1572 | __func__, options.identity_files[i]); | ||
1524 | continue; | 1573 | continue; |
1574 | } | ||
1525 | options.identity_keys[i] = NULL; | 1575 | options.identity_keys[i] = NULL; |
1526 | id = xcalloc(1, sizeof(*id)); | 1576 | id = xcalloc(1, sizeof(*id)); |
1527 | id->agent_fd = -1; | 1577 | id->agent_fd = -1; |
@@ -1534,8 +1584,19 @@ pubkey_prepare(Authctxt *authctxt) | |||
1534 | for (i = 0; i < options.num_certificate_files; i++) { | 1584 | for (i = 0; i < options.num_certificate_files; i++) { |
1535 | key = options.certificates[i]; | 1585 | key = options.certificates[i]; |
1536 | if (!sshkey_is_cert(key) || key->cert == NULL || | 1586 | if (!sshkey_is_cert(key) || key->cert == NULL || |
1537 | key->cert->type != SSH2_CERT_TYPE_USER) | 1587 | key->cert->type != SSH2_CERT_TYPE_USER) { |
1588 | debug("%s: ignoring certificate %s: not a user " | ||
1589 | "certificate", __func__, | ||
1590 | options.identity_files[i]); | ||
1538 | continue; | 1591 | continue; |
1592 | } | ||
1593 | if (key && sshkey_type_plain(key->type) == KEY_ECDSA_SK && | ||
1594 | options.sk_provider == NULL) { | ||
1595 | debug("%s: ignoring security key certificate %s as no " | ||
1596 | "SecurityKeyProvider has been specified", | ||
1597 | __func__, options.identity_files[i]); | ||
1598 | continue; | ||
1599 | } | ||
1539 | id = xcalloc(1, sizeof(*id)); | 1600 | id = xcalloc(1, sizeof(*id)); |
1540 | id->agent_fd = -1; | 1601 | id->agent_fd = -1; |
1541 | id->key = key; | 1602 | id->key = key; |