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 "includes.h" 28 29 #if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) 30 31 #include <sys/types.h> 32 33 #include <stdio.h> 34 #include <string.h> 35 #include <signal.h> 36 37 #include <openssl/ecdh.h> 38 39 #include "sshkey.h" 40 #include "kex.h" 41 #include "sshbuf.h" 42 #include "digest.h" 43 #include "ssherr.h" 44 45 static int 46 kex_ecdh_dec_key_group(struct kex *, const struct sshbuf *, EC_KEY *key, 47 const EC_GROUP *, struct sshbuf **); 48 49 int 50 kex_ecdh_keypair(struct kex *kex) 51 { 52 EC_KEY *client_key = NULL; 53 const EC_GROUP *group; 54 const EC_POINT *public_key; 55 struct sshbuf *buf = NULL; 56 int r; 57 58 if ((client_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) { 59 r = SSH_ERR_ALLOC_FAIL; 60 goto out; 61 } 62 if (EC_KEY_generate_key(client_key) != 1) { 63 r = SSH_ERR_LIBCRYPTO_ERROR; 64 goto out; 65 } 66 group = EC_KEY_get0_group(client_key); 67 public_key = EC_KEY_get0_public_key(client_key); 68 69 if ((buf = sshbuf_new()) == NULL) { 70 r = SSH_ERR_ALLOC_FAIL; 71 goto out; 72 } 73 if ((r = sshbuf_put_ec(buf, public_key, group)) != 0 || 74 (r = sshbuf_get_u32(buf, NULL)) != 0) 75 goto out; 76 #ifdef DEBUG_KEXECDH 77 fputs("client private key:\n", stderr); 78 sshkey_dump_ec_key(client_key); 79 #endif 80 kex->ec_client_key = client_key; 81 kex->ec_group = group; 82 client_key = NULL; /* owned by the kex */ 83 kex->client_pub = buf; 84 buf = NULL; 85 out: 86 EC_KEY_free(client_key); 87 sshbuf_free(buf); 88 return r; 89 } 90 91 int 92 kex_ecdh_enc(struct kex *kex, const struct sshbuf *client_blob, 93 struct sshbuf **server_blobp, struct sshbuf **shared_secretp) 94 { 95 const EC_GROUP *group; 96 const EC_POINT *pub_key; 97 EC_KEY *server_key = NULL; 98 struct sshbuf *server_blob = NULL; 99 int r; 100 101 *server_blobp = NULL; 102 *shared_secretp = NULL; 103 104 if ((server_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) { 105 r = SSH_ERR_ALLOC_FAIL; 106 goto out; 107 } 108 if (EC_KEY_generate_key(server_key) != 1) { 109 r = SSH_ERR_LIBCRYPTO_ERROR; 110 goto out; 111 } 112 group = EC_KEY_get0_group(server_key); 113 114 #ifdef DEBUG_KEXECDH 115 fputs("server private key:\n", stderr); 116 sshkey_dump_ec_key(server_key); 117 #endif 118 pub_key = EC_KEY_get0_public_key(server_key); 119 if ((server_blob = sshbuf_new()) == NULL) { 120 r = SSH_ERR_ALLOC_FAIL; 121 goto out; 122 } 123 if ((r = sshbuf_put_ec(server_blob, pub_key, group)) != 0 || 124 (r = sshbuf_get_u32(server_blob, NULL)) != 0) 125 goto out; 126 if ((r = kex_ecdh_dec_key_group(kex, client_blob, server_key, group, 127 shared_secretp)) != 0) 128 goto out; 129 *server_blobp = server_blob; 130 server_blob = NULL; 131 out: 132 EC_KEY_free(server_key); 133 sshbuf_free(server_blob); 134 return r; 135 } 136 137 static int 138 kex_ecdh_dec_key_group(struct kex *kex, const struct sshbuf *ec_blob, 139 EC_KEY *key, const EC_GROUP *group, struct sshbuf **shared_secretp) 140 { 141 struct sshbuf *buf = NULL; 142 BIGNUM *shared_secret = NULL; 143 EC_POINT *dh_pub = NULL; 144 u_char *kbuf = NULL; 145 size_t klen = 0; 146 int r; 147 148 *shared_secretp = NULL; 149 150 if ((buf = sshbuf_new()) == NULL) { 151 r = SSH_ERR_ALLOC_FAIL; 152 goto out; 153 } 154 if ((r = sshbuf_put_stringb(buf, ec_blob)) != 0) 155 goto out; 156 if ((dh_pub = EC_POINT_new(group)) == NULL) { 157 r = SSH_ERR_ALLOC_FAIL; 158 goto out; 159 } 160 if ((r = sshbuf_get_ec(buf, dh_pub, group)) != 0) { 161 goto out; 162 } 163 sshbuf_reset(buf); 164 165 #ifdef DEBUG_KEXECDH 166 fputs("public key:\n", stderr); 167 sshkey_dump_ec_point(group, dh_pub); 168 #endif 169 if (sshkey_ec_validate_public(group, dh_pub) != 0) { 170 r = SSH_ERR_MESSAGE_INCOMPLETE; 171 goto out; 172 } 173 klen = (EC_GROUP_get_degree(group) + 7) / 8; 174 if ((kbuf = malloc(klen)) == NULL || 175 (shared_secret = BN_new()) == NULL) { 176 r = SSH_ERR_ALLOC_FAIL; 177 goto out; 178 } 179 if (ECDH_compute_key(kbuf, klen, dh_pub, key, NULL) != (int)klen || 180 BN_bin2bn(kbuf, klen, shared_secret) == NULL) { 181 r = SSH_ERR_LIBCRYPTO_ERROR; 182 goto out; 183 } 184 #ifdef DEBUG_KEXECDH 185 dump_digest("shared secret", kbuf, klen); 186 #endif 187 if ((r = sshbuf_put_bignum2(buf, shared_secret)) != 0) 188 goto out; 189 *shared_secretp = buf; 190 buf = NULL; 191 out: 192 EC_POINT_clear_free(dh_pub); 193 BN_clear_free(shared_secret); 194 freezero(kbuf, klen); 195 sshbuf_free(buf); 196 return r; 197 } 198 199 int 200 kex_ecdh_dec(struct kex *kex, const struct sshbuf *server_blob, 201 struct sshbuf **shared_secretp) 202 { 203 int r; 204 205 r = kex_ecdh_dec_key_group(kex, server_blob, kex->ec_client_key, 206 kex->ec_group, shared_secretp); 207 EC_KEY_free(kex->ec_client_key); 208 kex->ec_client_key = NULL; 209 return r; 210 } 211 212 #else 213 214 #include "ssherr.h" 215 216 struct kex; 217 struct sshbuf; 218 struct sshkey; 219 220 int 221 kex_ecdh_keypair(struct kex *kex) 222 { 223 return SSH_ERR_SIGN_ALG_UNSUPPORTED; 224 } 225 226 int 227 kex_ecdh_enc(struct kex *kex, const struct sshbuf *client_blob, 228 struct sshbuf **server_blobp, struct sshbuf **shared_secretp) 229 { 230 return SSH_ERR_SIGN_ALG_UNSUPPORTED; 231 } 232 233 int 234 kex_ecdh_dec(struct kex *kex, const struct sshbuf *server_blob, 235 struct sshbuf **shared_secretp) 236 { 237 return SSH_ERR_SIGN_ALG_UNSUPPORTED; 238 } 239 #endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */ 240