xref: /dflybsd-src/crypto/openssh/kexc25519.c (revision 664f47636b7e6e9e2c54a4799ca4884a9c628df5)
1*664f4763Szrj /* $OpenBSD: kexc25519.c,v 1.17 2019/01/21 10:40:11 djm Exp $ */
236e94dc5SPeter Avalos /*
3*664f4763Szrj  * Copyright (c) 2019 Markus Friedl.  All rights reserved.
436e94dc5SPeter Avalos  * Copyright (c) 2010 Damien Miller.  All rights reserved.
536e94dc5SPeter Avalos  * Copyright (c) 2013 Aris Adamantiadis.  All rights reserved.
636e94dc5SPeter Avalos  *
736e94dc5SPeter Avalos  * Redistribution and use in source and binary forms, with or without
836e94dc5SPeter Avalos  * modification, are permitted provided that the following conditions
936e94dc5SPeter Avalos  * are met:
1036e94dc5SPeter Avalos  * 1. Redistributions of source code must retain the above copyright
1136e94dc5SPeter Avalos  *    notice, this list of conditions and the following disclaimer.
1236e94dc5SPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
1336e94dc5SPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
1436e94dc5SPeter Avalos  *    documentation and/or other materials provided with the distribution.
1536e94dc5SPeter Avalos  *
1636e94dc5SPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1736e94dc5SPeter Avalos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1836e94dc5SPeter Avalos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1936e94dc5SPeter Avalos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2036e94dc5SPeter Avalos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2136e94dc5SPeter Avalos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2236e94dc5SPeter Avalos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2336e94dc5SPeter Avalos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2436e94dc5SPeter Avalos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2536e94dc5SPeter Avalos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2636e94dc5SPeter Avalos  */
2736e94dc5SPeter Avalos 
2836e94dc5SPeter Avalos #include "includes.h"
2936e94dc5SPeter Avalos 
3036e94dc5SPeter Avalos #include <sys/types.h>
3136e94dc5SPeter Avalos 
32*664f4763Szrj #include <stdio.h>
3336e94dc5SPeter Avalos #include <string.h>
34*664f4763Szrj #include <signal.h>
3536e94dc5SPeter Avalos 
36e9778795SPeter Avalos #include "sshkey.h"
3736e94dc5SPeter Avalos #include "kex.h"
38*664f4763Szrj #include "sshbuf.h"
3936e94dc5SPeter Avalos #include "digest.h"
40e9778795SPeter Avalos #include "ssherr.h"
41*664f4763Szrj #include "ssh2.h"
4236e94dc5SPeter Avalos 
4336e94dc5SPeter Avalos extern int crypto_scalarmult_curve25519(u_char a[CURVE25519_SIZE],
4436e94dc5SPeter Avalos     const u_char b[CURVE25519_SIZE], const u_char c[CURVE25519_SIZE])
4536e94dc5SPeter Avalos 	__attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
4636e94dc5SPeter Avalos 	__attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)))
4736e94dc5SPeter Avalos 	__attribute__((__bounded__(__minbytes__, 3, CURVE25519_SIZE)));
4836e94dc5SPeter Avalos 
4936e94dc5SPeter Avalos void
kexc25519_keygen(u_char key[CURVE25519_SIZE],u_char pub[CURVE25519_SIZE])5036e94dc5SPeter Avalos kexc25519_keygen(u_char key[CURVE25519_SIZE], u_char pub[CURVE25519_SIZE])
5136e94dc5SPeter Avalos {
5236e94dc5SPeter Avalos 	static const u_char basepoint[CURVE25519_SIZE] = {9};
5336e94dc5SPeter Avalos 
5436e94dc5SPeter Avalos 	arc4random_buf(key, CURVE25519_SIZE);
5536e94dc5SPeter Avalos 	crypto_scalarmult_curve25519(pub, key, basepoint);
5636e94dc5SPeter Avalos }
5736e94dc5SPeter Avalos 
58e9778795SPeter Avalos int
kexc25519_shared_key_ext(const u_char key[CURVE25519_SIZE],const u_char pub[CURVE25519_SIZE],struct sshbuf * out,int raw)59*664f4763Szrj kexc25519_shared_key_ext(const u_char key[CURVE25519_SIZE],
60*664f4763Szrj     const u_char pub[CURVE25519_SIZE], struct sshbuf *out, int raw)
6136e94dc5SPeter Avalos {
6236e94dc5SPeter Avalos 	u_char shared_key[CURVE25519_SIZE];
63*664f4763Szrj 	u_char zero[CURVE25519_SIZE];
64e9778795SPeter Avalos 	int r;
65e9778795SPeter Avalos 
66*664f4763Szrj 	crypto_scalarmult_curve25519(shared_key, key, pub);
67*664f4763Szrj 
68*664f4763Szrj 	/* Check for all-zero shared secret */
69*664f4763Szrj 	explicit_bzero(zero, CURVE25519_SIZE);
70*664f4763Szrj 	if (timingsafe_bcmp(zero, shared_key, CURVE25519_SIZE) == 0)
71e9778795SPeter Avalos 		return SSH_ERR_KEY_INVALID_EC_VALUE;
7236e94dc5SPeter Avalos 
7336e94dc5SPeter Avalos #ifdef DEBUG_KEXECDH
7436e94dc5SPeter Avalos 	dump_digest("shared secret", shared_key, CURVE25519_SIZE);
7536e94dc5SPeter Avalos #endif
76*664f4763Szrj 	if (raw)
77*664f4763Szrj 		r = sshbuf_put(out, shared_key, CURVE25519_SIZE);
78*664f4763Szrj 	else
79e9778795SPeter Avalos 		r = sshbuf_put_bignum2_bytes(out, shared_key, CURVE25519_SIZE);
8036e94dc5SPeter Avalos 	explicit_bzero(shared_key, CURVE25519_SIZE);
81e9778795SPeter Avalos 	return r;
8236e94dc5SPeter Avalos }
8336e94dc5SPeter Avalos 
84e9778795SPeter Avalos int
kexc25519_shared_key(const u_char key[CURVE25519_SIZE],const u_char pub[CURVE25519_SIZE],struct sshbuf * out)85*664f4763Szrj kexc25519_shared_key(const u_char key[CURVE25519_SIZE],
86*664f4763Szrj     const u_char pub[CURVE25519_SIZE], struct sshbuf *out)
8736e94dc5SPeter Avalos {
88*664f4763Szrj 	return kexc25519_shared_key_ext(key, pub, out, 0);
89*664f4763Szrj }
90*664f4763Szrj 
91*664f4763Szrj int
kex_c25519_keypair(struct kex * kex)92*664f4763Szrj kex_c25519_keypair(struct kex *kex)
93*664f4763Szrj {
94*664f4763Szrj 	struct sshbuf *buf = NULL;
95*664f4763Szrj 	u_char *cp = NULL;
96e9778795SPeter Avalos 	int r;
9736e94dc5SPeter Avalos 
98*664f4763Szrj 	if ((buf = sshbuf_new()) == NULL)
99e9778795SPeter Avalos 		return SSH_ERR_ALLOC_FAIL;
100*664f4763Szrj 	if ((r = sshbuf_reserve(buf, CURVE25519_SIZE, &cp)) != 0)
101*664f4763Szrj 		goto out;
102*664f4763Szrj 	kexc25519_keygen(kex->c25519_client_key, cp);
103*664f4763Szrj #ifdef DEBUG_KEXECDH
104*664f4763Szrj 	dump_digest("client public key c25519:", cp, CURVE25519_SIZE);
105*664f4763Szrj #endif
106*664f4763Szrj 	kex->client_pub = buf;
107*664f4763Szrj 	buf = NULL;
108*664f4763Szrj  out:
109*664f4763Szrj 	sshbuf_free(buf);
110e9778795SPeter Avalos 	return r;
111e9778795SPeter Avalos }
112*664f4763Szrj 
113*664f4763Szrj int
kex_c25519_enc(struct kex * kex,const struct sshbuf * client_blob,struct sshbuf ** server_blobp,struct sshbuf ** shared_secretp)114*664f4763Szrj kex_c25519_enc(struct kex *kex, const struct sshbuf *client_blob,
115*664f4763Szrj    struct sshbuf **server_blobp, struct sshbuf **shared_secretp)
116*664f4763Szrj {
117*664f4763Szrj 	struct sshbuf *server_blob = NULL;
118*664f4763Szrj 	struct sshbuf *buf = NULL;
119*664f4763Szrj 	const u_char *client_pub;
120*664f4763Szrj 	u_char *server_pub;
121*664f4763Szrj 	u_char server_key[CURVE25519_SIZE];
122*664f4763Szrj 	int r;
123*664f4763Szrj 
124*664f4763Szrj 	*server_blobp = NULL;
125*664f4763Szrj 	*shared_secretp = NULL;
126*664f4763Szrj 
127*664f4763Szrj 	if (sshbuf_len(client_blob) != CURVE25519_SIZE) {
128*664f4763Szrj 		r = SSH_ERR_SIGNATURE_INVALID;
129*664f4763Szrj 		goto out;
130e9778795SPeter Avalos 	}
131*664f4763Szrj 	client_pub = sshbuf_ptr(client_blob);
132*664f4763Szrj #ifdef DEBUG_KEXECDH
133*664f4763Szrj 	dump_digest("client public key 25519:", client_pub, CURVE25519_SIZE);
134e9778795SPeter Avalos #endif
135*664f4763Szrj 	/* allocate space for encrypted KEM key and ECDH pub key */
136*664f4763Szrj 	if ((server_blob = sshbuf_new()) == NULL) {
137*664f4763Szrj 		r = SSH_ERR_ALLOC_FAIL;
138*664f4763Szrj 		goto out;
139*664f4763Szrj 	}
140*664f4763Szrj 	if ((r = sshbuf_reserve(server_blob, CURVE25519_SIZE, &server_pub)) != 0)
141*664f4763Szrj 		goto out;
142*664f4763Szrj 	kexc25519_keygen(server_key, server_pub);
143*664f4763Szrj 	/* allocate shared secret */
144*664f4763Szrj 	if ((buf = sshbuf_new()) == NULL) {
145*664f4763Szrj 		r = SSH_ERR_ALLOC_FAIL;
146*664f4763Szrj 		goto out;
147*664f4763Szrj 	}
148*664f4763Szrj 	if ((r = kexc25519_shared_key_ext(server_key, client_pub, buf, 0)) < 0)
149*664f4763Szrj 		goto out;
150*664f4763Szrj #ifdef DEBUG_KEXECDH
151*664f4763Szrj 	dump_digest("server public key 25519:", server_pub, CURVE25519_SIZE);
152*664f4763Szrj 	dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf));
153*664f4763Szrj #endif
154*664f4763Szrj 	*server_blobp = server_blob;
155*664f4763Szrj 	*shared_secretp = buf;
156*664f4763Szrj 	server_blob = NULL;
157*664f4763Szrj 	buf = NULL;
158*664f4763Szrj  out:
159*664f4763Szrj 	explicit_bzero(server_key, sizeof(server_key));
160*664f4763Szrj 	sshbuf_free(server_blob);
161*664f4763Szrj 	sshbuf_free(buf);
162*664f4763Szrj 	return r;
163*664f4763Szrj }
164*664f4763Szrj 
165*664f4763Szrj int
kex_c25519_dec(struct kex * kex,const struct sshbuf * server_blob,struct sshbuf ** shared_secretp)166*664f4763Szrj kex_c25519_dec(struct kex *kex, const struct sshbuf *server_blob,
167*664f4763Szrj     struct sshbuf **shared_secretp)
168*664f4763Szrj {
169*664f4763Szrj 	struct sshbuf *buf = NULL;
170*664f4763Szrj 	const u_char *server_pub;
171*664f4763Szrj 	int r;
172*664f4763Szrj 
173*664f4763Szrj 	*shared_secretp = NULL;
174*664f4763Szrj 
175*664f4763Szrj 	if (sshbuf_len(server_blob) != CURVE25519_SIZE) {
176*664f4763Szrj 		r = SSH_ERR_SIGNATURE_INVALID;
177*664f4763Szrj 		goto out;
178*664f4763Szrj 	}
179*664f4763Szrj 	server_pub = sshbuf_ptr(server_blob);
180*664f4763Szrj #ifdef DEBUG_KEXECDH
181*664f4763Szrj 	dump_digest("server public key c25519:", server_pub, CURVE25519_SIZE);
182*664f4763Szrj #endif
183*664f4763Szrj 	/* shared secret */
184*664f4763Szrj 	if ((buf = sshbuf_new()) == NULL) {
185*664f4763Szrj 		r = SSH_ERR_ALLOC_FAIL;
186*664f4763Szrj 		goto out;
187*664f4763Szrj 	}
188*664f4763Szrj 	if ((r = kexc25519_shared_key_ext(kex->c25519_client_key, server_pub,
189*664f4763Szrj 	    buf, 0)) < 0)
190*664f4763Szrj 		goto out;
191*664f4763Szrj #ifdef DEBUG_KEXECDH
192*664f4763Szrj 	dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf));
193*664f4763Szrj #endif
194*664f4763Szrj 	*shared_secretp = buf;
195*664f4763Szrj 	buf = NULL;
196*664f4763Szrj  out:
197*664f4763Szrj 	sshbuf_free(buf);
198*664f4763Szrj 	return r;
19936e94dc5SPeter Avalos }
200