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