1/* $NetBSD: kexdh.c,v 1.10 2021/03/05 17:47:16 christos Exp $ */ 2/* $OpenBSD: kexdh.c,v 1.34 2020/12/04 02:29:25 djm Exp $ */ 3 4/* 5 * Copyright (c) 2019 Markus Friedl. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include "includes.h" 29__RCSID("$NetBSD: kexdh.c,v 1.10 2021/03/05 17:47:16 christos Exp $"); 30#include <sys/types.h> 31 32#include <stdio.h> 33#include <string.h> 34#include <signal.h> 35 36#include "sshkey.h" 37#include "kex.h" 38#include "sshbuf.h" 39#include "digest.h" 40#include "ssherr.h" 41#include "dh.h" 42#include "log.h" 43 44int 45kex_dh_keygen(struct kex *kex) 46{ 47 switch (kex->kex_type) { 48 case KEX_DH_GRP1_SHA1: 49 kex->dh = dh_new_group1(); 50 break; 51 case KEX_DH_GRP14_SHA1: 52 case KEX_DH_GRP14_SHA256: 53 kex->dh = dh_new_group14(); 54 break; 55 case KEX_DH_GRP16_SHA512: 56 kex->dh = dh_new_group16(); 57 break; 58 case KEX_DH_GRP18_SHA512: 59 kex->dh = dh_new_group18(); 60 break; 61 default: 62 return SSH_ERR_INVALID_ARGUMENT; 63 } 64 if (kex->dh == NULL) 65 return SSH_ERR_ALLOC_FAIL; 66 return (dh_gen_key(kex->dh, kex->we_need * 8)); 67} 68 69int 70kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out) 71{ 72 BIGNUM *shared_secret = NULL; 73 u_char *kbuf = NULL; 74 size_t klen = 0; 75 int kout, r; 76 77#ifdef DEBUG_KEXDH 78 fprintf(stderr, "dh_pub= "); 79 BN_print_fp(stderr, dh_pub); 80 fprintf(stderr, "\n"); 81 debug("bits %d", BN_num_bits(dh_pub)); 82 DHparams_print_fp(stderr, kex->dh); 83 fprintf(stderr, "\n"); 84#endif 85 86 if (!dh_pub_is_valid(kex->dh, dh_pub)) { 87 r = SSH_ERR_MESSAGE_INCOMPLETE; 88 goto out; 89 } 90 klen = DH_size(kex->dh); 91 if ((kbuf = malloc(klen)) == NULL || 92 (shared_secret = BN_new()) == NULL) { 93 r = SSH_ERR_ALLOC_FAIL; 94 goto out; 95 } 96 if ((kout = DH_compute_key(kbuf, dh_pub, kex->dh)) < 0 || 97 BN_bin2bn(kbuf, kout, shared_secret) == NULL) { 98 r = SSH_ERR_LIBCRYPTO_ERROR; 99 goto out; 100 } 101#ifdef DEBUG_KEXDH 102 dump_digest("shared secret", kbuf, kout); 103#endif 104 r = sshbuf_put_bignum2(out, shared_secret); 105 out: 106 freezero(kbuf, klen); 107 BN_clear_free(shared_secret); 108 return r; 109} 110 111int 112kex_dh_keypair(struct kex *kex) 113{ 114 const BIGNUM *pub_key; 115 struct sshbuf *buf = NULL; 116 int r; 117 118 if ((r = kex_dh_keygen(kex)) != 0) 119 return r; 120 DH_get0_key(kex->dh, &pub_key, NULL); 121 if ((buf = sshbuf_new()) == NULL) 122 return SSH_ERR_ALLOC_FAIL; 123 if ((r = sshbuf_put_bignum2(buf, pub_key)) != 0 || 124 (r = sshbuf_get_u32(buf, NULL)) != 0) 125 goto out; 126#ifdef DEBUG_KEXDH 127 DHparams_print_fp(stderr, kex->dh); 128 fprintf(stderr, "pub= "); 129 BN_print_fp(stderr, pub_key); 130 fprintf(stderr, "\n"); 131#endif 132 kex->client_pub = buf; 133 buf = NULL; 134 out: 135 sshbuf_free(buf); 136 return r; 137} 138 139int 140kex_dh_enc(struct kex *kex, const struct sshbuf *client_blob, 141 struct sshbuf **server_blobp, struct sshbuf **shared_secretp) 142{ 143 const BIGNUM *pub_key; 144 struct sshbuf *server_blob = NULL; 145 int r; 146 147 *server_blobp = NULL; 148 *shared_secretp = NULL; 149 150 if ((r = kex_dh_keygen(kex)) != 0) 151 goto out; 152 DH_get0_key(kex->dh, &pub_key, NULL); 153 if ((server_blob = sshbuf_new()) == NULL) { 154 r = SSH_ERR_ALLOC_FAIL; 155 goto out; 156 } 157 if ((r = sshbuf_put_bignum2(server_blob, pub_key)) != 0 || 158 (r = sshbuf_get_u32(server_blob, NULL)) != 0) 159 goto out; 160 if ((r = kex_dh_dec(kex, client_blob, shared_secretp)) != 0) 161 goto out; 162 *server_blobp = server_blob; 163 server_blob = NULL; 164 out: 165 DH_free(kex->dh); 166 kex->dh = NULL; 167 sshbuf_free(server_blob); 168 return r; 169} 170 171int 172kex_dh_dec(struct kex *kex, const struct sshbuf *dh_blob, 173 struct sshbuf **shared_secretp) 174{ 175 struct sshbuf *buf = NULL; 176 BIGNUM *dh_pub = NULL; 177 int r; 178 179 *shared_secretp = NULL; 180 181 if ((buf = sshbuf_new()) == NULL) { 182 r = SSH_ERR_ALLOC_FAIL; 183 goto out; 184 } 185 if ((r = sshbuf_put_stringb(buf, dh_blob)) != 0 || 186 (r = sshbuf_get_bignum2(buf, &dh_pub)) != 0) 187 goto out; 188 sshbuf_reset(buf); 189 if ((r = kex_dh_compute_key(kex, dh_pub, buf)) != 0) 190 goto out; 191 *shared_secretp = buf; 192 buf = NULL; 193 out: 194 BN_free(dh_pub); 195 DH_free(kex->dh); 196 kex->dh = NULL; 197 sshbuf_free(buf); 198 return r; 199} 200