summaryrefslogtreecommitdiff
path: root/sshconnect2.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2017-03-11 23:40:26 +0000
committerDamien Miller <djm@mindrot.org>2017-03-12 10:50:19 +1100
commit1e24552716194db8f2f620587b876158a9ef56ad (patch)
tree595f0fb3e56020a561c18e8f09ef1001cec6439c /sshconnect2.c
parent0fb1a617a07b8df5de188dd5a0c8bf293d4bfc0e (diff)
upstream commit
allow ssh to use certificates accompanied by a private key file but no corresponding plain *.pub public key. bz#2617 based on patch from Adam Eijdenberg; ok dtucker@ markus@ Upstream-ID: 295668dca2c39505281577217583ddd2bd4b00b9
Diffstat (limited to 'sshconnect2.c')
-rw-r--r--sshconnect2.c67
1 files changed, 52 insertions, 15 deletions
diff --git a/sshconnect2.c b/sshconnect2.c
index 2abb86679..f8a54beea 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshconnect2.c,v 1.254 2017/02/03 02:56:00 dtucker Exp $ */ 1/* $OpenBSD: sshconnect2.c,v 1.255 2017/03/11 23:40:26 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.
@@ -996,11 +996,11 @@ input_userauth_passwd_changereq(int type, u_int32_t seqnr, void *ctxt)
996} 996}
997 997
998static const char * 998static const char *
999identity_sign_encode(struct identity *id) 999key_sign_encode(const struct sshkey *key)
1000{ 1000{
1001 struct ssh *ssh = active_state; 1001 struct ssh *ssh = active_state;
1002 1002
1003 if (id->key->type == KEY_RSA) { 1003 if (key->type == KEY_RSA) {
1004 switch (ssh->kex->rsa_sha2) { 1004 switch (ssh->kex->rsa_sha2) {
1005 case 256: 1005 case 256:
1006 return "rsa-sha2-256"; 1006 return "rsa-sha2-256";
@@ -1008,7 +1008,7 @@ identity_sign_encode(struct identity *id)
1008 return "rsa-sha2-512"; 1008 return "rsa-sha2-512";
1009 } 1009 }
1010 } 1010 }
1011 return key_ssh_name(id->key); 1011 return key_ssh_name(key);
1012} 1012}
1013 1013
1014static int 1014static int
@@ -1017,31 +1017,50 @@ identity_sign(struct identity *id, u_char **sigp, size_t *lenp,
1017{ 1017{
1018 Key *prv; 1018 Key *prv;
1019 int ret; 1019 int ret;
1020 const char *alg;
1021
1022 alg = identity_sign_encode(id);
1023 1020
1024 /* the agent supports this key */ 1021 /* the agent supports this key */
1025 if (id->agent_fd != -1) 1022 if (id->key != NULL && id->agent_fd != -1)
1026 return ssh_agent_sign(id->agent_fd, id->key, sigp, lenp, 1023 return ssh_agent_sign(id->agent_fd, id->key, sigp, lenp,
1027 data, datalen, alg, compat); 1024 data, datalen, key_sign_encode(id->key), compat);
1028 1025
1029 /* 1026 /*
1030 * we have already loaded the private key or 1027 * we have already loaded the private key or
1031 * the private key is stored in external hardware 1028 * the private key is stored in external hardware
1032 */ 1029 */
1033 if (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT)) 1030 if (id->key != NULL &&
1034 return (sshkey_sign(id->key, sigp, lenp, data, datalen, alg, 1031 (id->isprivate || (id->key->flags & SSHKEY_FLAG_EXT)))
1035 compat)); 1032 return (sshkey_sign(id->key, sigp, lenp, data, datalen,
1033 key_sign_encode(id->key), compat));
1034
1036 /* load the private key from the file */ 1035 /* load the private key from the file */
1037 if ((prv = load_identity_file(id)) == NULL) 1036 if ((prv = load_identity_file(id)) == NULL)
1038 return SSH_ERR_KEY_NOT_FOUND; 1037 return SSH_ERR_KEY_NOT_FOUND;
1039 ret = sshkey_sign(prv, sigp, lenp, data, datalen, alg, compat); 1038 ret = sshkey_sign(prv, sigp, lenp, data, datalen,
1039 key_sign_encode(prv), compat);
1040 sshkey_free(prv); 1040 sshkey_free(prv);
1041 return (ret); 1041 return (ret);
1042} 1042}
1043 1043
1044static int 1044static int
1045id_filename_matches(Identity *id, Identity *private_id)
1046{
1047 const char *suffixes[] = { ".pub", "-cert.pub", NULL };
1048 size_t len = strlen(id->filename), plen = strlen(private_id->filename);
1049 size_t i, slen;
1050
1051 if (strcmp(id->filename, private_id->filename) == 0)
1052 return 1;
1053 for (i = 0; suffixes[i]; i++) {
1054 slen = strlen(suffixes[i]);
1055 if (len > slen && plen == len - slen &&
1056 strcmp(id->filename + (len - slen), suffixes[i]) == 0 &&
1057 memcmp(id->filename, private_id->filename, plen) == 0)
1058 return 1;
1059 }
1060 return 0;
1061}
1062
1063static int
1045sign_and_send_pubkey(Authctxt *authctxt, Identity *id) 1064sign_and_send_pubkey(Authctxt *authctxt, Identity *id)
1046{ 1065{
1047 Buffer b; 1066 Buffer b;
@@ -1083,7 +1102,7 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id)
1083 } else { 1102 } else {
1084 buffer_put_cstring(&b, authctxt->method->name); 1103 buffer_put_cstring(&b, authctxt->method->name);
1085 buffer_put_char(&b, have_sig); 1104 buffer_put_char(&b, have_sig);
1086 buffer_put_cstring(&b, identity_sign_encode(id)); 1105 buffer_put_cstring(&b, key_sign_encode(id->key));
1087 } 1106 }
1088 buffer_put_string(&b, blob, bloblen); 1107 buffer_put_string(&b, blob, bloblen);
1089 1108
@@ -1103,6 +1122,24 @@ sign_and_send_pubkey(Authctxt *authctxt, Identity *id)
1103 break; 1122 break;
1104 } 1123 }
1105 } 1124 }
1125 /*
1126 * Exact key matches are preferred, but also allow
1127 * filename matches for non-PKCS#11/agent keys that
1128 * didn't load public keys. This supports the case
1129 * of keeping just a private key file and public
1130 * certificate on disk.
1131 */
1132 if (!matched && !id->isprivate && id->agent_fd == -1 &&
1133 (id->key->flags & SSHKEY_FLAG_EXT) == 0) {
1134 TAILQ_FOREACH(private_id, &authctxt->keys, next) {
1135 if (private_id->key == NULL &&
1136 id_filename_matches(id, private_id)) {
1137 id = private_id;
1138 matched = 1;
1139 break;
1140 }
1141 }
1142 }
1106 if (matched) { 1143 if (matched) {
1107 debug2("%s: using private key \"%s\"%s for " 1144 debug2("%s: using private key \"%s\"%s for "
1108 "certificate", __func__, id->filename, 1145 "certificate", __func__, id->filename,
@@ -1181,7 +1218,7 @@ send_pubkey_test(Authctxt *authctxt, Identity *id)
1181 packet_put_cstring(authctxt->method->name); 1218 packet_put_cstring(authctxt->method->name);
1182 packet_put_char(have_sig); 1219 packet_put_char(have_sig);
1183 if (!(datafellows & SSH_BUG_PKAUTH)) 1220 if (!(datafellows & SSH_BUG_PKAUTH))
1184 packet_put_cstring(identity_sign_encode(id)); 1221 packet_put_cstring(key_sign_encode(id->key));
1185 packet_put_string(blob, bloblen); 1222 packet_put_string(blob, bloblen);
1186 free(blob); 1223 free(blob);
1187 packet_send(); 1224 packet_send();