summaryrefslogtreecommitdiff
path: root/sshconnect2.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2019-10-31 21:18:28 +0000
committerDamien Miller <djm@mindrot.org>2019-11-01 09:46:09 +1100
commit884416bdb10468f1252e4d7c13d51b43dccba7f6 (patch)
treef81dc3ed23cddcda6163102363c5dc75a63430e6 /sshconnect2.c
parent01a0670f69c5b86e471e033b92145d6c7cc77c58 (diff)
upstream: ssh client support for U2F/FIDO keys
OpenBSD-Commit-ID: eb2cfa6cf7419a1895e06e398ea6d41516c5b0bc
Diffstat (limited to 'sshconnect2.c')
-rw-r--r--sshconnect2.c111
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 *
601format_identity(Identity *id) 602format_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
1140identity_sign(struct identity *id, u_char **sigp, size_t *lenp, 1147identity_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;