Annotation of src/usr.bin/ssh/kexgen.c, Revision 1.1
1.1 ! djm 1: /* $OpenBSD: kexkemc.c,v 1.5 2019/01/21 10:35:09 djm Exp $ */
! 2: /*
! 3: * Copyright (c) 2019 Markus Friedl. All rights reserved.
! 4: *
! 5: * Redistribution and use in source and binary forms, with or without
! 6: * modification, are permitted provided that the following conditions
! 7: * are met:
! 8: * 1. Redistributions of source code must retain the above copyright
! 9: * notice, this list of conditions and the following disclaimer.
! 10: * 2. Redistributions in binary form must reproduce the above copyright
! 11: * notice, this list of conditions and the following disclaimer in the
! 12: * documentation and/or other materials provided with the distribution.
! 13: *
! 14: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 15: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 16: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 17: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 18: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 19: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 20: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 21: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 22: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 23: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 24: */
! 25:
! 26: #include <sys/types.h>
! 27:
! 28: #include <stdio.h>
! 29: #include <string.h>
! 30: #include <signal.h>
! 31:
! 32: #include "sshkey.h"
! 33: #include "kex.h"
! 34: #include "log.h"
! 35: #include "packet.h"
! 36: #include "ssh2.h"
! 37: #include "sshbuf.h"
! 38: #include "digest.h"
! 39: #include "ssherr.h"
! 40:
! 41: static int input_kex_gen_init(int, u_int32_t, struct ssh *);
! 42: static int input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh);
! 43:
! 44: static int
! 45: kex_gen_hash(
! 46: int hash_alg,
! 47: const struct sshbuf *client_version,
! 48: const struct sshbuf *server_version,
! 49: const u_char *ckexinit, size_t ckexinitlen,
! 50: const u_char *skexinit, size_t skexinitlen,
! 51: const u_char *serverhostkeyblob, size_t sbloblen,
! 52: const struct sshbuf *client_pub,
! 53: const struct sshbuf *server_pub,
! 54: const struct sshbuf *shared_secret,
! 55: u_char *hash, size_t *hashlen)
! 56: {
! 57: struct sshbuf *b;
! 58: int r;
! 59:
! 60: if (*hashlen < ssh_digest_bytes(hash_alg))
! 61: return SSH_ERR_INVALID_ARGUMENT;
! 62: if ((b = sshbuf_new()) == NULL)
! 63: return SSH_ERR_ALLOC_FAIL;
! 64: if ((r = sshbuf_put_stringb(b, client_version)) != 0 ||
! 65: (r = sshbuf_put_stringb(b, server_version)) != 0 ||
! 66: /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
! 67: (r = sshbuf_put_u32(b, ckexinitlen+1)) != 0 ||
! 68: (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
! 69: (r = sshbuf_put(b, ckexinit, ckexinitlen)) != 0 ||
! 70: (r = sshbuf_put_u32(b, skexinitlen+1)) != 0 ||
! 71: (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 ||
! 72: (r = sshbuf_put(b, skexinit, skexinitlen)) != 0 ||
! 73: (r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) != 0 ||
! 74: (r = sshbuf_put_stringb(b, client_pub)) != 0 ||
! 75: (r = sshbuf_put_stringb(b, server_pub)) != 0 ||
! 76: (r = sshbuf_putb(b, shared_secret)) != 0) {
! 77: sshbuf_free(b);
! 78: return r;
! 79: }
! 80: #ifdef DEBUG_KEX
! 81: sshbuf_dump(b, stderr);
! 82: #endif
! 83: if (ssh_digest_buffer(hash_alg, b, hash, *hashlen) != 0) {
! 84: sshbuf_free(b);
! 85: return SSH_ERR_LIBCRYPTO_ERROR;
! 86: }
! 87: sshbuf_free(b);
! 88: *hashlen = ssh_digest_bytes(hash_alg);
! 89: #ifdef DEBUG_KEX
! 90: dump_digest("hash", hash, *hashlen);
! 91: #endif
! 92: return 0;
! 93: }
! 94:
! 95: int
! 96: kex_gen_client(struct ssh *ssh)
! 97: {
! 98: struct kex *kex = ssh->kex;
! 99: int r;
! 100:
! 101: switch (kex->kex_type) {
! 102: case KEX_DH_GRP1_SHA1:
! 103: case KEX_DH_GRP14_SHA1:
! 104: case KEX_DH_GRP14_SHA256:
! 105: case KEX_DH_GRP16_SHA512:
! 106: case KEX_DH_GRP18_SHA512:
! 107: r = kex_dh_keypair(kex);
! 108: break;
! 109: case KEX_ECDH_SHA2:
! 110: r = kex_ecdh_keypair(kex);
! 111: break;
! 112: case KEX_C25519_SHA256:
! 113: r = kex_c25519_keypair(kex);
! 114: break;
! 115: case KEX_KEM_SNTRUP4591761X25519_SHA512:
! 116: r = kex_kem_sntrup4591761x25519_keypair(kex);
! 117: break;
! 118: default:
! 119: r = SSH_ERR_INVALID_ARGUMENT;
! 120: break;
! 121: }
! 122: if (r != 0)
! 123: return r;
! 124: if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_INIT)) != 0 ||
! 125: (r = sshpkt_put_stringb(ssh, kex->client_pub)) != 0 ||
! 126: (r = sshpkt_send(ssh)) != 0)
! 127: return r;
! 128: debug("expecting SSH2_MSG_KEX_ECDH_REPLY");
! 129: ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_REPLY, &input_kex_gen_reply);
! 130: return 0;
! 131: }
! 132:
! 133: static int
! 134: input_kex_gen_reply(int type, u_int32_t seq, struct ssh *ssh)
! 135: {
! 136: struct kex *kex = ssh->kex;
! 137: struct sshkey *server_host_key = NULL;
! 138: struct sshbuf *shared_secret = NULL;
! 139: struct sshbuf *server_blob = NULL;
! 140: u_char *server_host_key_blob = NULL, *signature = NULL;
! 141: u_char hash[SSH_DIGEST_MAX_LENGTH];
! 142: size_t slen, sbloblen, hashlen;
! 143: int r;
! 144:
! 145: /* hostkey */
! 146: if ((r = sshpkt_get_string(ssh, &server_host_key_blob,
! 147: &sbloblen)) != 0 ||
! 148: (r = sshkey_from_blob(server_host_key_blob, sbloblen,
! 149: &server_host_key)) != 0)
! 150: goto out;
! 151: if ((r = kex_verify_host_key(ssh, server_host_key)) != 0)
! 152: goto out;
! 153:
! 154: /* Q_S, server public key */
! 155: /* signed H */
! 156: if ((r = sshpkt_getb_froms(ssh, &server_blob)) != 0 ||
! 157: (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 ||
! 158: (r = sshpkt_get_end(ssh)) != 0)
! 159: goto out;
! 160:
! 161: /* compute shared secret */
! 162: switch (kex->kex_type) {
! 163: case KEX_DH_GRP1_SHA1:
! 164: case KEX_DH_GRP14_SHA1:
! 165: case KEX_DH_GRP14_SHA256:
! 166: case KEX_DH_GRP16_SHA512:
! 167: case KEX_DH_GRP18_SHA512:
! 168: r = kex_dh_dec(kex, server_blob, &shared_secret);
! 169: break;
! 170: case KEX_ECDH_SHA2:
! 171: r = kex_ecdh_dec(kex, server_blob, &shared_secret);
! 172: break;
! 173: case KEX_C25519_SHA256:
! 174: r = kex_c25519_dec(kex, server_blob, &shared_secret);
! 175: break;
! 176: case KEX_KEM_SNTRUP4591761X25519_SHA512:
! 177: r = kex_kem_sntrup4591761x25519_dec(kex, server_blob,
! 178: &shared_secret);
! 179: break;
! 180: default:
! 181: r = SSH_ERR_INVALID_ARGUMENT;
! 182: break;
! 183: }
! 184: if (r !=0 )
! 185: goto out;
! 186:
! 187: /* calc and verify H */
! 188: hashlen = sizeof(hash);
! 189: if ((r = kex_gen_hash(
! 190: kex->hash_alg,
! 191: kex->client_version,
! 192: kex->server_version,
! 193: sshbuf_ptr(kex->my), sshbuf_len(kex->my),
! 194: sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
! 195: server_host_key_blob, sbloblen,
! 196: kex->client_pub,
! 197: server_blob,
! 198: shared_secret,
! 199: hash, &hashlen)) != 0)
! 200: goto out;
! 201:
! 202: if ((r = sshkey_verify(server_host_key, signature, slen, hash, hashlen,
! 203: kex->hostkey_alg, ssh->compat)) != 0)
! 204: goto out;
! 205:
! 206: if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0)
! 207: r = kex_send_newkeys(ssh);
! 208: out:
! 209: explicit_bzero(hash, sizeof(hash));
! 210: explicit_bzero(kex->c25519_client_key, sizeof(kex->c25519_client_key));
! 211: explicit_bzero(kex->sntrup4591761_client_key,
! 212: sizeof(kex->sntrup4591761_client_key));
! 213: free(server_host_key_blob);
! 214: free(signature);
! 215: sshkey_free(server_host_key);
! 216: sshbuf_free(server_blob);
! 217: sshbuf_free(shared_secret);
! 218: sshbuf_free(kex->client_pub);
! 219: kex->client_pub = NULL;
! 220: return r;
! 221: }
! 222:
! 223: int
! 224: kex_gen_server(struct ssh *ssh)
! 225: {
! 226: debug("expecting SSH2_MSG_KEX_ECDH_INIT");
! 227: ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_INIT, &input_kex_gen_init);
! 228: return 0;
! 229: }
! 230:
! 231: static int
! 232: input_kex_gen_init(int type, u_int32_t seq, struct ssh *ssh)
! 233: {
! 234: struct kex *kex = ssh->kex;
! 235: struct sshkey *server_host_private, *server_host_public;
! 236: struct sshbuf *shared_secret = NULL;
! 237: struct sshbuf *server_pubkey = NULL;
! 238: struct sshbuf *client_pubkey = NULL;
! 239: u_char *server_host_key_blob = NULL, *signature = NULL;
! 240: u_char hash[SSH_DIGEST_MAX_LENGTH];
! 241: size_t slen, sbloblen, hashlen;
! 242: int r;
! 243:
! 244: if ((r = kex_load_hostkey(ssh, &server_host_private,
! 245: &server_host_public)) != 0)
! 246: goto out;
! 247:
! 248: if ((r = sshpkt_getb_froms(ssh, &client_pubkey)) != 0 ||
! 249: (r = sshpkt_get_end(ssh)) != 0)
! 250: goto out;
! 251:
! 252: /* compute shared secret */
! 253: switch (kex->kex_type) {
! 254: case KEX_DH_GRP1_SHA1:
! 255: case KEX_DH_GRP14_SHA1:
! 256: case KEX_DH_GRP14_SHA256:
! 257: case KEX_DH_GRP16_SHA512:
! 258: case KEX_DH_GRP18_SHA512:
! 259: r = kex_dh_enc(kex, client_pubkey, &server_pubkey,
! 260: &shared_secret);
! 261: break;
! 262: case KEX_ECDH_SHA2:
! 263: r = kex_ecdh_enc(kex, client_pubkey, &server_pubkey,
! 264: &shared_secret);
! 265: break;
! 266: case KEX_C25519_SHA256:
! 267: r = kex_c25519_enc(kex, client_pubkey, &server_pubkey,
! 268: &shared_secret);
! 269: break;
! 270: case KEX_KEM_SNTRUP4591761X25519_SHA512:
! 271: r = kex_kem_sntrup4591761x25519_enc(kex, client_pubkey,
! 272: &server_pubkey, &shared_secret);
! 273: break;
! 274: default:
! 275: r = SSH_ERR_INVALID_ARGUMENT;
! 276: break;
! 277: }
! 278: if (r !=0 )
! 279: goto out;
! 280:
! 281: /* calc H */
! 282: if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob,
! 283: &sbloblen)) != 0)
! 284: goto out;
! 285: hashlen = sizeof(hash);
! 286: if ((r = kex_gen_hash(
! 287: kex->hash_alg,
! 288: kex->client_version,
! 289: kex->server_version,
! 290: sshbuf_ptr(kex->peer), sshbuf_len(kex->peer),
! 291: sshbuf_ptr(kex->my), sshbuf_len(kex->my),
! 292: server_host_key_blob, sbloblen,
! 293: client_pubkey,
! 294: server_pubkey,
! 295: shared_secret,
! 296: hash, &hashlen)) != 0)
! 297: goto out;
! 298:
! 299: /* sign H */
! 300: if ((r = kex->sign(ssh, server_host_private, server_host_public,
! 301: &signature, &slen, hash, hashlen, kex->hostkey_alg)) != 0)
! 302: goto out;
! 303:
! 304: /* send server hostkey, ECDH pubkey 'Q_S' and signed H */
! 305: if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_REPLY)) != 0 ||
! 306: (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 ||
! 307: (r = sshpkt_put_stringb(ssh, server_pubkey)) != 0 ||
! 308: (r = sshpkt_put_string(ssh, signature, slen)) != 0 ||
! 309: (r = sshpkt_send(ssh)) != 0)
! 310: goto out;
! 311:
! 312: if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0)
! 313: r = kex_send_newkeys(ssh);
! 314: out:
! 315: explicit_bzero(hash, sizeof(hash));
! 316: free(server_host_key_blob);
! 317: free(signature);
! 318: sshbuf_free(shared_secret);
! 319: sshbuf_free(client_pubkey);
! 320: sshbuf_free(server_pubkey);
! 321: return r;
! 322: }