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