1 /* $OpenBSD: kexdh.c,v 1.32 2019/01/21 10:40:11 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 "includes.h" 27 28 #ifdef WITH_OPENSSL 29 30 #include <sys/types.h> 31 32 #include <signal.h> 33 #include <stdio.h> 34 #include <string.h> 35 36 #include "openbsd-compat/openssl-compat.h" 37 #include <openssl/dh.h> 38 39 #include "sshkey.h" 40 #include "kex.h" 41 #include "sshbuf.h" 42 #include "digest.h" 43 #include "ssherr.h" 44 #include "dh.h" 45 46 int 47 kex_dh_keygen(struct kex *kex) 48 { 49 switch (kex->kex_type) { 50 case KEX_DH_GRP1_SHA1: 51 kex->dh = dh_new_group1(); 52 break; 53 case KEX_DH_GRP14_SHA1: 54 case KEX_DH_GRP14_SHA256: 55 kex->dh = dh_new_group14(); 56 break; 57 case KEX_DH_GRP16_SHA512: 58 kex->dh = dh_new_group16(); 59 break; 60 case KEX_DH_GRP18_SHA512: 61 kex->dh = dh_new_group18(); 62 break; 63 default: 64 return SSH_ERR_INVALID_ARGUMENT; 65 } 66 if (kex->dh == NULL) 67 return SSH_ERR_ALLOC_FAIL; 68 return (dh_gen_key(kex->dh, kex->we_need * 8)); 69 } 70 71 int 72 kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out) 73 { 74 BIGNUM *shared_secret = NULL; 75 u_char *kbuf = NULL; 76 size_t klen = 0; 77 int kout, r; 78 79 #ifdef DEBUG_KEXDH 80 fprintf(stderr, "dh_pub= "); 81 BN_print_fp(stderr, dh_pub); 82 fprintf(stderr, "\n"); 83 debug("bits %d", BN_num_bits(dh_pub)); 84 DHparams_print_fp(stderr, kex->dh); 85 fprintf(stderr, "\n"); 86 #endif 87 88 if (!dh_pub_is_valid(kex->dh, dh_pub)) { 89 r = SSH_ERR_MESSAGE_INCOMPLETE; 90 goto out; 91 } 92 klen = DH_size(kex->dh); 93 if ((kbuf = malloc(klen)) == NULL || 94 (shared_secret = BN_new()) == NULL) { 95 r = SSH_ERR_ALLOC_FAIL; 96 goto out; 97 } 98 if ((kout = DH_compute_key(kbuf, dh_pub, kex->dh)) < 0 || 99 BN_bin2bn(kbuf, kout, shared_secret) == NULL) { 100 r = SSH_ERR_LIBCRYPTO_ERROR; 101 goto out; 102 } 103 #ifdef DEBUG_KEXDH 104 dump_digest("shared secret", kbuf, kout); 105 #endif 106 r = sshbuf_put_bignum2(out, shared_secret); 107 out: 108 freezero(kbuf, klen); 109 BN_clear_free(shared_secret); 110 return r; 111 } 112 113 int 114 kex_dh_keypair(struct kex *kex) 115 { 116 const BIGNUM *pub_key; 117 struct sshbuf *buf = NULL; 118 int r; 119 120 if ((r = kex_dh_keygen(kex)) != 0) 121 return r; 122 DH_get0_key(kex->dh, &pub_key, NULL); 123 if ((buf = sshbuf_new()) == NULL) 124 return SSH_ERR_ALLOC_FAIL; 125 if ((r = sshbuf_put_bignum2(buf, pub_key)) != 0 || 126 (r = sshbuf_get_u32(buf, NULL)) != 0) 127 goto out; 128 #ifdef DEBUG_KEXDH 129 DHparams_print_fp(stderr, kex->dh); 130 fprintf(stderr, "pub= "); 131 BN_print_fp(stderr, pub_key); 132 fprintf(stderr, "\n"); 133 #endif 134 kex->client_pub = buf; 135 buf = NULL; 136 out: 137 sshbuf_free(buf); 138 return r; 139 } 140 141 int 142 kex_dh_enc(struct kex *kex, const struct sshbuf *client_blob, 143 struct sshbuf **server_blobp, struct sshbuf **shared_secretp) 144 { 145 const BIGNUM *pub_key; 146 struct sshbuf *server_blob = NULL; 147 int r; 148 149 *server_blobp = NULL; 150 *shared_secretp = NULL; 151 152 if ((r = kex_dh_keygen(kex)) != 0) 153 goto out; 154 DH_get0_key(kex->dh, &pub_key, NULL); 155 if ((server_blob = sshbuf_new()) == NULL) { 156 r = SSH_ERR_ALLOC_FAIL; 157 goto out; 158 } 159 if ((r = sshbuf_put_bignum2(server_blob, pub_key)) != 0 || 160 (r = sshbuf_get_u32(server_blob, NULL)) != 0) 161 goto out; 162 if ((r = kex_dh_dec(kex, client_blob, shared_secretp)) != 0) 163 goto out; 164 *server_blobp = server_blob; 165 server_blob = NULL; 166 out: 167 DH_free(kex->dh); 168 kex->dh = NULL; 169 sshbuf_free(server_blob); 170 return r; 171 } 172 173 int 174 kex_dh_dec(struct kex *kex, const struct sshbuf *dh_blob, 175 struct sshbuf **shared_secretp) 176 { 177 struct sshbuf *buf = NULL; 178 BIGNUM *dh_pub = NULL; 179 int r; 180 181 *shared_secretp = NULL; 182 183 if ((buf = sshbuf_new()) == NULL) { 184 r = SSH_ERR_ALLOC_FAIL; 185 goto out; 186 } 187 if ((r = sshbuf_put_stringb(buf, dh_blob)) != 0 || 188 (r = sshbuf_get_bignum2(buf, &dh_pub)) != 0) 189 goto out; 190 sshbuf_reset(buf); 191 if ((r = kex_dh_compute_key(kex, dh_pub, buf)) != 0) 192 goto out; 193 *shared_secretp = buf; 194 buf = NULL; 195 out: 196 DH_free(kex->dh); 197 kex->dh = NULL; 198 sshbuf_free(buf); 199 return r; 200 } 201 #endif /* WITH_OPENSSL */ 202