xref: /openssh-portable/kexdh.c (revision 3b98b6e2)
1*3b98b6e2Sdjm@openbsd.org /* $OpenBSD: kexdh.c,v 1.34 2020/12/04 02:29:25 djm Exp $ */
222b19b43SBen Lindstrom /*
39c9c97e1Sdjm@openbsd.org  * Copyright (c) 2019 Markus Friedl.  All rights reserved.
422b19b43SBen Lindstrom  *
522b19b43SBen Lindstrom  * Redistribution and use in source and binary forms, with or without
622b19b43SBen Lindstrom  * modification, are permitted provided that the following conditions
722b19b43SBen Lindstrom  * are met:
822b19b43SBen Lindstrom  * 1. Redistributions of source code must retain the above copyright
922b19b43SBen Lindstrom  *    notice, this list of conditions and the following disclaimer.
1022b19b43SBen Lindstrom  * 2. Redistributions in binary form must reproduce the above copyright
1122b19b43SBen Lindstrom  *    notice, this list of conditions and the following disclaimer in the
1222b19b43SBen Lindstrom  *    documentation and/or other materials provided with the distribution.
1322b19b43SBen Lindstrom  *
1422b19b43SBen Lindstrom  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1522b19b43SBen Lindstrom  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1622b19b43SBen Lindstrom  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1722b19b43SBen Lindstrom  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1822b19b43SBen Lindstrom  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1922b19b43SBen Lindstrom  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2022b19b43SBen Lindstrom  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2122b19b43SBen Lindstrom  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2222b19b43SBen Lindstrom  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2322b19b43SBen Lindstrom  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2422b19b43SBen Lindstrom  */
2522b19b43SBen Lindstrom 
2622b19b43SBen Lindstrom #include "includes.h"
2722b19b43SBen Lindstrom 
2872ef7c14SDamien Miller #ifdef WITH_OPENSSL
2972ef7c14SDamien Miller 
30d7834353SDamien Miller #include <sys/types.h>
31d7834353SDamien Miller 
32d7834353SDamien Miller #include <signal.h>
339c9c97e1Sdjm@openbsd.org #include <stdio.h>
349c9c97e1Sdjm@openbsd.org #include <string.h>
35d7834353SDamien Miller 
362de9cec5SDamien Miller #include "openbsd-compat/openssl-compat.h"
37d5520393SDamien Miller #include <openssl/dh.h>
382de9cec5SDamien Miller 
3957d10cbeSmarkus@openbsd.org #include "sshkey.h"
408e7fb335SDamien Miller #include "kex.h"
4157d10cbeSmarkus@openbsd.org #include "sshbuf.h"
42b3051d01SDamien Miller #include "digest.h"
43b7235721SDamien Miller #include "ssherr.h"
44dec5e9d3Sdjm@openbsd.org #include "dh.h"
45ecb2c02dSdjm@openbsd.org #include "log.h"
4622b19b43SBen Lindstrom 
4757d10cbeSmarkus@openbsd.org int
kex_dh_keygen(struct kex * kex)48e93bd98eSdjm@openbsd.org kex_dh_keygen(struct kex *kex)
49e93bd98eSdjm@openbsd.org {
50e93bd98eSdjm@openbsd.org 	switch (kex->kex_type) {
51e93bd98eSdjm@openbsd.org 	case KEX_DH_GRP1_SHA1:
52e93bd98eSdjm@openbsd.org 		kex->dh = dh_new_group1();
53e93bd98eSdjm@openbsd.org 		break;
54e93bd98eSdjm@openbsd.org 	case KEX_DH_GRP14_SHA1:
55e93bd98eSdjm@openbsd.org 	case KEX_DH_GRP14_SHA256:
56e93bd98eSdjm@openbsd.org 		kex->dh = dh_new_group14();
57e93bd98eSdjm@openbsd.org 		break;
58e93bd98eSdjm@openbsd.org 	case KEX_DH_GRP16_SHA512:
59e93bd98eSdjm@openbsd.org 		kex->dh = dh_new_group16();
60e93bd98eSdjm@openbsd.org 		break;
61e93bd98eSdjm@openbsd.org 	case KEX_DH_GRP18_SHA512:
62e93bd98eSdjm@openbsd.org 		kex->dh = dh_new_group18();
63e93bd98eSdjm@openbsd.org 		break;
64e93bd98eSdjm@openbsd.org 	default:
65e93bd98eSdjm@openbsd.org 		return SSH_ERR_INVALID_ARGUMENT;
66e93bd98eSdjm@openbsd.org 	}
67e93bd98eSdjm@openbsd.org 	if (kex->dh == NULL)
68e93bd98eSdjm@openbsd.org 		return SSH_ERR_ALLOC_FAIL;
69e93bd98eSdjm@openbsd.org 	return (dh_gen_key(kex->dh, kex->we_need * 8));
70e93bd98eSdjm@openbsd.org }
71e93bd98eSdjm@openbsd.org 
72e93bd98eSdjm@openbsd.org int
kex_dh_compute_key(struct kex * kex,BIGNUM * dh_pub,struct sshbuf * out)73dec5e9d3Sdjm@openbsd.org kex_dh_compute_key(struct kex *kex, BIGNUM *dh_pub, struct sshbuf *out)
74dec5e9d3Sdjm@openbsd.org {
75dec5e9d3Sdjm@openbsd.org 	BIGNUM *shared_secret = NULL;
76dec5e9d3Sdjm@openbsd.org 	u_char *kbuf = NULL;
77dec5e9d3Sdjm@openbsd.org 	size_t klen = 0;
78dec5e9d3Sdjm@openbsd.org 	int kout, r;
79dec5e9d3Sdjm@openbsd.org 
80dec5e9d3Sdjm@openbsd.org #ifdef DEBUG_KEXDH
81dec5e9d3Sdjm@openbsd.org 	fprintf(stderr, "dh_pub= ");
82dec5e9d3Sdjm@openbsd.org 	BN_print_fp(stderr, dh_pub);
83dec5e9d3Sdjm@openbsd.org 	fprintf(stderr, "\n");
84dec5e9d3Sdjm@openbsd.org 	debug("bits %d", BN_num_bits(dh_pub));
85dec5e9d3Sdjm@openbsd.org 	DHparams_print_fp(stderr, kex->dh);
86dec5e9d3Sdjm@openbsd.org 	fprintf(stderr, "\n");
87dec5e9d3Sdjm@openbsd.org #endif
88dec5e9d3Sdjm@openbsd.org 
89dec5e9d3Sdjm@openbsd.org 	if (!dh_pub_is_valid(kex->dh, dh_pub)) {
90dec5e9d3Sdjm@openbsd.org 		r = SSH_ERR_MESSAGE_INCOMPLETE;
91dec5e9d3Sdjm@openbsd.org 		goto out;
92dec5e9d3Sdjm@openbsd.org 	}
93dec5e9d3Sdjm@openbsd.org 	klen = DH_size(kex->dh);
94dec5e9d3Sdjm@openbsd.org 	if ((kbuf = malloc(klen)) == NULL ||
95dec5e9d3Sdjm@openbsd.org 	    (shared_secret = BN_new()) == NULL) {
96dec5e9d3Sdjm@openbsd.org 		r = SSH_ERR_ALLOC_FAIL;
97dec5e9d3Sdjm@openbsd.org 		goto out;
98dec5e9d3Sdjm@openbsd.org 	}
99dec5e9d3Sdjm@openbsd.org 	if ((kout = DH_compute_key(kbuf, dh_pub, kex->dh)) < 0 ||
100dec5e9d3Sdjm@openbsd.org 	    BN_bin2bn(kbuf, kout, shared_secret) == NULL) {
101dec5e9d3Sdjm@openbsd.org 		r = SSH_ERR_LIBCRYPTO_ERROR;
102dec5e9d3Sdjm@openbsd.org 		goto out;
103dec5e9d3Sdjm@openbsd.org 	}
104dec5e9d3Sdjm@openbsd.org #ifdef DEBUG_KEXDH
105dec5e9d3Sdjm@openbsd.org 	dump_digest("shared secret", kbuf, kout);
106dec5e9d3Sdjm@openbsd.org #endif
107dec5e9d3Sdjm@openbsd.org 	r = sshbuf_put_bignum2(out, shared_secret);
108dec5e9d3Sdjm@openbsd.org  out:
109dec5e9d3Sdjm@openbsd.org 	freezero(kbuf, klen);
110dec5e9d3Sdjm@openbsd.org 	BN_clear_free(shared_secret);
111dec5e9d3Sdjm@openbsd.org 	return r;
112dec5e9d3Sdjm@openbsd.org }
113dec5e9d3Sdjm@openbsd.org 
114dec5e9d3Sdjm@openbsd.org int
kex_dh_keypair(struct kex * kex)1159c9c97e1Sdjm@openbsd.org kex_dh_keypair(struct kex *kex)
11622b19b43SBen Lindstrom {
1179c9c97e1Sdjm@openbsd.org 	const BIGNUM *pub_key;
1189c9c97e1Sdjm@openbsd.org 	struct sshbuf *buf = NULL;
11957d10cbeSmarkus@openbsd.org 	int r;
12022b19b43SBen Lindstrom 
1219c9c97e1Sdjm@openbsd.org 	if ((r = kex_dh_keygen(kex)) != 0)
1229c9c97e1Sdjm@openbsd.org 		return r;
1239c9c97e1Sdjm@openbsd.org 	DH_get0_key(kex->dh, &pub_key, NULL);
1249c9c97e1Sdjm@openbsd.org 	if ((buf = sshbuf_new()) == NULL)
12557d10cbeSmarkus@openbsd.org 		return SSH_ERR_ALLOC_FAIL;
1269c9c97e1Sdjm@openbsd.org 	if ((r = sshbuf_put_bignum2(buf, pub_key)) != 0 ||
1279c9c97e1Sdjm@openbsd.org 	    (r = sshbuf_get_u32(buf, NULL)) != 0)
1289c9c97e1Sdjm@openbsd.org 		goto out;
1299c9c97e1Sdjm@openbsd.org #ifdef DEBUG_KEXDH
1309c9c97e1Sdjm@openbsd.org 	DHparams_print_fp(stderr, kex->dh);
1319c9c97e1Sdjm@openbsd.org 	fprintf(stderr, "pub= ");
1329c9c97e1Sdjm@openbsd.org 	BN_print_fp(stderr, pub_key);
1339c9c97e1Sdjm@openbsd.org 	fprintf(stderr, "\n");
1349c9c97e1Sdjm@openbsd.org #endif
135aaca72d6Sdjm@openbsd.org 	kex->client_pub = buf;
1369c9c97e1Sdjm@openbsd.org 	buf = NULL;
1379c9c97e1Sdjm@openbsd.org  out:
1389c9c97e1Sdjm@openbsd.org 	sshbuf_free(buf);
13957d10cbeSmarkus@openbsd.org 	return r;
14057d10cbeSmarkus@openbsd.org }
1419c9c97e1Sdjm@openbsd.org 
1429c9c97e1Sdjm@openbsd.org int
kex_dh_enc(struct kex * kex,const struct sshbuf * client_blob,struct sshbuf ** server_blobp,struct sshbuf ** shared_secretp)14371e67fffSdjm@openbsd.org kex_dh_enc(struct kex *kex, const struct sshbuf *client_blob,
1449c9c97e1Sdjm@openbsd.org     struct sshbuf **server_blobp, struct sshbuf **shared_secretp)
1459c9c97e1Sdjm@openbsd.org {
1469c9c97e1Sdjm@openbsd.org 	const BIGNUM *pub_key;
1479c9c97e1Sdjm@openbsd.org 	struct sshbuf *server_blob = NULL;
1489c9c97e1Sdjm@openbsd.org 	int r;
1499c9c97e1Sdjm@openbsd.org 
1509c9c97e1Sdjm@openbsd.org 	*server_blobp = NULL;
1519c9c97e1Sdjm@openbsd.org 	*shared_secretp = NULL;
1529c9c97e1Sdjm@openbsd.org 
1539c9c97e1Sdjm@openbsd.org 	if ((r = kex_dh_keygen(kex)) != 0)
1549c9c97e1Sdjm@openbsd.org 		goto out;
1559c9c97e1Sdjm@openbsd.org 	DH_get0_key(kex->dh, &pub_key, NULL);
1569c9c97e1Sdjm@openbsd.org 	if ((server_blob = sshbuf_new()) == NULL) {
1579c9c97e1Sdjm@openbsd.org 		r = SSH_ERR_ALLOC_FAIL;
1589c9c97e1Sdjm@openbsd.org 		goto out;
15957d10cbeSmarkus@openbsd.org 	}
1609c9c97e1Sdjm@openbsd.org 	if ((r = sshbuf_put_bignum2(server_blob, pub_key)) != 0 ||
1619c9c97e1Sdjm@openbsd.org 	    (r = sshbuf_get_u32(server_blob, NULL)) != 0)
1629c9c97e1Sdjm@openbsd.org 		goto out;
16371e67fffSdjm@openbsd.org 	if ((r = kex_dh_dec(kex, client_blob, shared_secretp)) != 0)
1649c9c97e1Sdjm@openbsd.org 		goto out;
1659c9c97e1Sdjm@openbsd.org 	*server_blobp = server_blob;
1669c9c97e1Sdjm@openbsd.org 	server_blob = NULL;
1679c9c97e1Sdjm@openbsd.org  out:
1689c9c97e1Sdjm@openbsd.org 	DH_free(kex->dh);
1699c9c97e1Sdjm@openbsd.org 	kex->dh = NULL;
1709c9c97e1Sdjm@openbsd.org 	sshbuf_free(server_blob);
1719c9c97e1Sdjm@openbsd.org 	return r;
1729c9c97e1Sdjm@openbsd.org }
1739c9c97e1Sdjm@openbsd.org 
1749c9c97e1Sdjm@openbsd.org int
kex_dh_dec(struct kex * kex,const struct sshbuf * dh_blob,struct sshbuf ** shared_secretp)17571e67fffSdjm@openbsd.org kex_dh_dec(struct kex *kex, const struct sshbuf *dh_blob,
1769c9c97e1Sdjm@openbsd.org     struct sshbuf **shared_secretp)
1779c9c97e1Sdjm@openbsd.org {
1789c9c97e1Sdjm@openbsd.org 	struct sshbuf *buf = NULL;
1799c9c97e1Sdjm@openbsd.org 	BIGNUM *dh_pub = NULL;
1809c9c97e1Sdjm@openbsd.org 	int r;
1819c9c97e1Sdjm@openbsd.org 
1829c9c97e1Sdjm@openbsd.org 	*shared_secretp = NULL;
1839c9c97e1Sdjm@openbsd.org 
1849c9c97e1Sdjm@openbsd.org 	if ((buf = sshbuf_new()) == NULL) {
1859c9c97e1Sdjm@openbsd.org 		r = SSH_ERR_ALLOC_FAIL;
1869c9c97e1Sdjm@openbsd.org 		goto out;
1879c9c97e1Sdjm@openbsd.org 	}
18871e67fffSdjm@openbsd.org 	if ((r = sshbuf_put_stringb(buf, dh_blob)) != 0 ||
18971e67fffSdjm@openbsd.org 	    (r = sshbuf_get_bignum2(buf, &dh_pub)) != 0)
1909c9c97e1Sdjm@openbsd.org 		goto out;
1919c9c97e1Sdjm@openbsd.org 	sshbuf_reset(buf);
1929c9c97e1Sdjm@openbsd.org 	if ((r = kex_dh_compute_key(kex, dh_pub, buf)) != 0)
1939c9c97e1Sdjm@openbsd.org 		goto out;
1949c9c97e1Sdjm@openbsd.org 	*shared_secretp = buf;
1959c9c97e1Sdjm@openbsd.org 	buf = NULL;
1969c9c97e1Sdjm@openbsd.org  out:
197*3b98b6e2Sdjm@openbsd.org 	BN_free(dh_pub);
1989c9c97e1Sdjm@openbsd.org 	DH_free(kex->dh);
1999c9c97e1Sdjm@openbsd.org 	kex->dh = NULL;
2009c9c97e1Sdjm@openbsd.org 	sshbuf_free(buf);
2019c9c97e1Sdjm@openbsd.org 	return r;
20222b19b43SBen Lindstrom }
20372ef7c14SDamien Miller #endif /* WITH_OPENSSL */
204