1 /* $OpenBSD: kexecdh.c,v 1.10 2019/01/21 10:40:11 djm Exp $ */ 2 /* 3 * Copyright (c) 2010 Damien Miller. All rights reserved. 4 * Copyright (c) 2019 Markus Friedl. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/types.h> 28 29 #include <stdio.h> 30 #include <string.h> 31 #include <signal.h> 32 33 #include <openssl/ecdh.h> 34 35 #include "sshkey.h" 36 #include "kex.h" 37 #include "sshbuf.h" 38 #include "digest.h" 39 #include "ssherr.h" 40 41 static int 42 kex_ecdh_dec_key_group(struct kex *, const struct sshbuf *, EC_KEY *key, 43 const EC_GROUP *, struct sshbuf **); 44 45 int 46 kex_ecdh_keypair(struct kex *kex) 47 { 48 EC_KEY *client_key = NULL; 49 const EC_GROUP *group; 50 const EC_POINT *public_key; 51 struct sshbuf *buf = NULL; 52 int r; 53 54 if ((client_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) { 55 r = SSH_ERR_ALLOC_FAIL; 56 goto out; 57 } 58 if (EC_KEY_generate_key(client_key) != 1) { 59 r = SSH_ERR_LIBCRYPTO_ERROR; 60 goto out; 61 } 62 group = EC_KEY_get0_group(client_key); 63 public_key = EC_KEY_get0_public_key(client_key); 64 65 if ((buf = sshbuf_new()) == NULL) { 66 r = SSH_ERR_ALLOC_FAIL; 67 goto out; 68 } 69 if ((r = sshbuf_put_ec(buf, public_key, group)) != 0 || 70 (r = sshbuf_get_u32(buf, NULL)) != 0) 71 goto out; 72 #ifdef DEBUG_KEXECDH 73 fputs("client private key:\n", stderr); 74 sshkey_dump_ec_key(client_key); 75 #endif 76 kex->ec_client_key = client_key; 77 kex->ec_group = group; 78 client_key = NULL; /* owned by the kex */ 79 kex->client_pub = buf; 80 buf = NULL; 81 out: 82 EC_KEY_free(client_key); 83 sshbuf_free(buf); 84 return r; 85 } 86 87 int 88 kex_ecdh_enc(struct kex *kex, const struct sshbuf *client_blob, 89 struct sshbuf **server_blobp, struct sshbuf **shared_secretp) 90 { 91 const EC_GROUP *group; 92 const EC_POINT *pub_key; 93 EC_KEY *server_key = NULL; 94 struct sshbuf *server_blob = NULL; 95 int r; 96 97 *server_blobp = NULL; 98 *shared_secretp = NULL; 99 100 if ((server_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) { 101 r = SSH_ERR_ALLOC_FAIL; 102 goto out; 103 } 104 if (EC_KEY_generate_key(server_key) != 1) { 105 r = SSH_ERR_LIBCRYPTO_ERROR; 106 goto out; 107 } 108 group = EC_KEY_get0_group(server_key); 109 110 #ifdef DEBUG_KEXECDH 111 fputs("server private key:\n", stderr); 112 sshkey_dump_ec_key(server_key); 113 #endif 114 pub_key = EC_KEY_get0_public_key(server_key); 115 if ((server_blob = sshbuf_new()) == NULL) { 116 r = SSH_ERR_ALLOC_FAIL; 117 goto out; 118 } 119 if ((r = sshbuf_put_ec(server_blob, pub_key, group)) != 0 || 120 (r = sshbuf_get_u32(server_blob, NULL)) != 0) 121 goto out; 122 if ((r = kex_ecdh_dec_key_group(kex, client_blob, server_key, group, 123 shared_secretp)) != 0) 124 goto out; 125 *server_blobp = server_blob; 126 server_blob = NULL; 127 out: 128 EC_KEY_free(server_key); 129 sshbuf_free(server_blob); 130 return r; 131 } 132 133 static int 134 kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob, 135 EC_KEY *key, const EC_GROUP *group, struct sshbuf **shared_secretp) 136 { 137 struct sshbuf *buf = NULL; 138 BIGNUM *shared_secret = NULL; 139 EC_POINT *dh_pub = NULL; 140 u_char *kbuf = NULL; 141 size_t klen = 0; 142 int r; 143 144 *shared_secretp = NULL; 145 146 if ((buf = sshbuf_new()) == NULL) { 147 r = SSH_ERR_ALLOC_FAIL; 148 goto out; 149 } 150 if ((r = sshbuf_put_stringb(buf, ec_blob)) != 0) 151 goto out; 152 if ((dh_pub = EC_POINT_new(group)) == NULL) { 153 r = SSH_ERR_ALLOC_FAIL; 154 goto out; 155 } 156 if ((r = sshbuf_get_ec(buf, dh_pub, group)) != 0) { 157 goto out; 158 } 159 sshbuf_reset(buf); 160 161 #ifdef DEBUG_KEXECDH 162 fputs("public key:\n", stderr); 163 sshkey_dump_ec_point(group, dh_pub); 164 #endif 165 if (sshkey_ec_validate_public(group, dh_pub) != 0) { 166 r = SSH_ERR_MESSAGE_INCOMPLETE; 167 goto out; 168 } 169 klen = (EC_GROUP_get_degree(group) + 7) / 8; 170 if ((kbuf = malloc(klen)) == NULL || 171 (shared_secret = BN_new()) == NULL) { 172 r = SSH_ERR_ALLOC_FAIL; 173 goto out; 174 } 175 if (ECDH_compute_key(kbuf, klen, dh_pub, key, NULL) != (int)klen || 176 BN_bin2bn(kbuf, klen, shared_secret) == NULL) { 177 r = SSH_ERR_LIBCRYPTO_ERROR; 178 goto out; 179 } 180 #ifdef DEBUG_KEXECDH 181 dump_digest("shared secret", kbuf, klen); 182 #endif 183 if ((r = sshbuf_put_bignum2(buf, shared_secret)) != 0) 184 goto out; 185 *shared_secretp = buf; 186 buf = NULL; 187 out: 188 EC_POINT_clear_free(dh_pub); 189 BN_clear_free(shared_secret); 190 freezero(kbuf, klen); 191 sshbuf_free(buf); 192 return r; 193 } 194 195 int 196 kex_ecdh_dec(struct kex *kex, const struct sshbuf *server_blob, 197 struct sshbuf **shared_secretp) 198 { 199 int r; 200 201 r = kex_ecdh_dec_key_group(kex, server_blob, kex->ec_client_key, 202 kex->ec_group, shared_secretp); 203 EC_KEY_free(kex->ec_client_key); 204 kex->ec_client_key = NULL; 205 return r; 206 } 207