xref: /freebsd/crypto/openssh/kexc25519.c (revision 19261079b74319502c6ffa1249920079f0f69a72)
1*19261079SEd Maste /* $OpenBSD: kexc25519.c,v 1.17 2019/01/21 10:40:11 djm Exp $ */
2f7167e0eSDag-Erling Smørgrav /*
3*19261079SEd Maste  * Copyright (c) 2019 Markus Friedl.  All rights reserved.
4f7167e0eSDag-Erling Smørgrav  * Copyright (c) 2010 Damien Miller.  All rights reserved.
5f7167e0eSDag-Erling Smørgrav  * Copyright (c) 2013 Aris Adamantiadis.  All rights reserved.
6f7167e0eSDag-Erling Smørgrav  *
7f7167e0eSDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
8f7167e0eSDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
9f7167e0eSDag-Erling Smørgrav  * are met:
10f7167e0eSDag-Erling Smørgrav  * 1. Redistributions of source code must retain the above copyright
11f7167e0eSDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer.
12f7167e0eSDag-Erling Smørgrav  * 2. Redistributions in binary form must reproduce the above copyright
13f7167e0eSDag-Erling Smørgrav  *    notice, this list of conditions and the following disclaimer in the
14f7167e0eSDag-Erling Smørgrav  *    documentation and/or other materials provided with the distribution.
15f7167e0eSDag-Erling Smørgrav  *
16f7167e0eSDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17f7167e0eSDag-Erling Smørgrav  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18f7167e0eSDag-Erling Smørgrav  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19f7167e0eSDag-Erling Smørgrav  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20f7167e0eSDag-Erling Smørgrav  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21f7167e0eSDag-Erling Smørgrav  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22f7167e0eSDag-Erling Smørgrav  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23f7167e0eSDag-Erling Smørgrav  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24f7167e0eSDag-Erling Smørgrav  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25f7167e0eSDag-Erling Smørgrav  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26f7167e0eSDag-Erling Smørgrav  */
27f7167e0eSDag-Erling Smørgrav 
28f7167e0eSDag-Erling Smørgrav #include "includes.h"
29f7167e0eSDag-Erling Smørgrav 
30f7167e0eSDag-Erling Smørgrav #include <sys/types.h>
31f7167e0eSDag-Erling Smørgrav 
32*19261079SEd Maste #include <stdio.h>
33f7167e0eSDag-Erling Smørgrav #include <string.h>
34*19261079SEd Maste #include <signal.h>
35f7167e0eSDag-Erling Smørgrav 
36bc5531deSDag-Erling Smørgrav #include "sshkey.h"
37f7167e0eSDag-Erling Smørgrav #include "kex.h"
38*19261079SEd Maste #include "sshbuf.h"
39f7167e0eSDag-Erling Smørgrav #include "digest.h"
40bc5531deSDag-Erling Smørgrav #include "ssherr.h"
41*19261079SEd Maste #include "ssh2.h"
42f7167e0eSDag-Erling Smørgrav 
43f7167e0eSDag-Erling Smørgrav extern int crypto_scalarmult_curve25519(u_char a[CURVE25519_SIZE],
44f7167e0eSDag-Erling Smørgrav     const u_char b[CURVE25519_SIZE], const u_char c[CURVE25519_SIZE])
45f7167e0eSDag-Erling Smørgrav 	__attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
46f7167e0eSDag-Erling Smørgrav 	__attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)))
47f7167e0eSDag-Erling Smørgrav 	__attribute__((__bounded__(__minbytes__, 3, CURVE25519_SIZE)));
48f7167e0eSDag-Erling Smørgrav 
49f7167e0eSDag-Erling Smørgrav void
kexc25519_keygen(u_char key[CURVE25519_SIZE],u_char pub[CURVE25519_SIZE])50f7167e0eSDag-Erling Smørgrav kexc25519_keygen(u_char key[CURVE25519_SIZE], u_char pub[CURVE25519_SIZE])
51f7167e0eSDag-Erling Smørgrav {
52f7167e0eSDag-Erling Smørgrav 	static const u_char basepoint[CURVE25519_SIZE] = {9};
53f7167e0eSDag-Erling Smørgrav 
54f7167e0eSDag-Erling Smørgrav 	arc4random_buf(key, CURVE25519_SIZE);
55f7167e0eSDag-Erling Smørgrav 	crypto_scalarmult_curve25519(pub, key, basepoint);
56f7167e0eSDag-Erling Smørgrav }
57f7167e0eSDag-Erling Smørgrav 
58bc5531deSDag-Erling Smørgrav int
kexc25519_shared_key_ext(const u_char key[CURVE25519_SIZE],const u_char pub[CURVE25519_SIZE],struct sshbuf * out,int raw)59*19261079SEd Maste kexc25519_shared_key_ext(const u_char key[CURVE25519_SIZE],
60*19261079SEd Maste     const u_char pub[CURVE25519_SIZE], struct sshbuf *out, int raw)
61f7167e0eSDag-Erling Smørgrav {
62f7167e0eSDag-Erling Smørgrav 	u_char shared_key[CURVE25519_SIZE];
63*19261079SEd Maste 	u_char zero[CURVE25519_SIZE];
64bc5531deSDag-Erling Smørgrav 	int r;
65f7167e0eSDag-Erling Smørgrav 
66*19261079SEd Maste 	crypto_scalarmult_curve25519(shared_key, key, pub);
67*19261079SEd Maste 
68*19261079SEd Maste 	/* Check for all-zero shared secret */
69*19261079SEd Maste 	explicit_bzero(zero, CURVE25519_SIZE);
70*19261079SEd Maste 	if (timingsafe_bcmp(zero, shared_key, CURVE25519_SIZE) == 0)
71557f75e5SDag-Erling Smørgrav 		return SSH_ERR_KEY_INVALID_EC_VALUE;
72557f75e5SDag-Erling Smørgrav 
73f7167e0eSDag-Erling Smørgrav #ifdef DEBUG_KEXECDH
74f7167e0eSDag-Erling Smørgrav 	dump_digest("shared secret", shared_key, CURVE25519_SIZE);
75f7167e0eSDag-Erling Smørgrav #endif
76*19261079SEd Maste 	if (raw)
77*19261079SEd Maste 		r = sshbuf_put(out, shared_key, CURVE25519_SIZE);
78*19261079SEd Maste 	else
79bc5531deSDag-Erling Smørgrav 		r = sshbuf_put_bignum2_bytes(out, shared_key, CURVE25519_SIZE);
80b83788ffSDag-Erling Smørgrav 	explicit_bzero(shared_key, CURVE25519_SIZE);
81bc5531deSDag-Erling Smørgrav 	return r;
82f7167e0eSDag-Erling Smørgrav }
83f7167e0eSDag-Erling Smørgrav 
84bc5531deSDag-Erling Smørgrav int
kexc25519_shared_key(const u_char key[CURVE25519_SIZE],const u_char pub[CURVE25519_SIZE],struct sshbuf * out)85*19261079SEd Maste kexc25519_shared_key(const u_char key[CURVE25519_SIZE],
86*19261079SEd Maste     const u_char pub[CURVE25519_SIZE], struct sshbuf *out)
87f7167e0eSDag-Erling Smørgrav {
88*19261079SEd Maste 	return kexc25519_shared_key_ext(key, pub, out, 0);
89*19261079SEd Maste }
90*19261079SEd Maste 
91*19261079SEd Maste int
kex_c25519_keypair(struct kex * kex)92*19261079SEd Maste kex_c25519_keypair(struct kex *kex)
93*19261079SEd Maste {
94*19261079SEd Maste 	struct sshbuf *buf = NULL;
95*19261079SEd Maste 	u_char *cp = NULL;
96bc5531deSDag-Erling Smørgrav 	int r;
97f7167e0eSDag-Erling Smørgrav 
98*19261079SEd Maste 	if ((buf = sshbuf_new()) == NULL)
99bc5531deSDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL;
100*19261079SEd Maste 	if ((r = sshbuf_reserve(buf, CURVE25519_SIZE, &cp)) != 0)
101*19261079SEd Maste 		goto out;
102*19261079SEd Maste 	kexc25519_keygen(kex->c25519_client_key, cp);
103*19261079SEd Maste #ifdef DEBUG_KEXECDH
104*19261079SEd Maste 	dump_digest("client public key c25519:", cp, CURVE25519_SIZE);
105*19261079SEd Maste #endif
106*19261079SEd Maste 	kex->client_pub = buf;
107*19261079SEd Maste 	buf = NULL;
108*19261079SEd Maste  out:
109*19261079SEd Maste 	sshbuf_free(buf);
110bc5531deSDag-Erling Smørgrav 	return r;
111bc5531deSDag-Erling Smørgrav }
112*19261079SEd Maste 
113*19261079SEd Maste int
kex_c25519_enc(struct kex * kex,const struct sshbuf * client_blob,struct sshbuf ** server_blobp,struct sshbuf ** shared_secretp)114*19261079SEd Maste kex_c25519_enc(struct kex *kex, const struct sshbuf *client_blob,
115*19261079SEd Maste    struct sshbuf **server_blobp, struct sshbuf **shared_secretp)
116*19261079SEd Maste {
117*19261079SEd Maste 	struct sshbuf *server_blob = NULL;
118*19261079SEd Maste 	struct sshbuf *buf = NULL;
119*19261079SEd Maste 	const u_char *client_pub;
120*19261079SEd Maste 	u_char *server_pub;
121*19261079SEd Maste 	u_char server_key[CURVE25519_SIZE];
122*19261079SEd Maste 	int r;
123*19261079SEd Maste 
124*19261079SEd Maste 	*server_blobp = NULL;
125*19261079SEd Maste 	*shared_secretp = NULL;
126*19261079SEd Maste 
127*19261079SEd Maste 	if (sshbuf_len(client_blob) != CURVE25519_SIZE) {
128*19261079SEd Maste 		r = SSH_ERR_SIGNATURE_INVALID;
129*19261079SEd Maste 		goto out;
130bc5531deSDag-Erling Smørgrav 	}
131*19261079SEd Maste 	client_pub = sshbuf_ptr(client_blob);
132*19261079SEd Maste #ifdef DEBUG_KEXECDH
133*19261079SEd Maste 	dump_digest("client public key 25519:", client_pub, CURVE25519_SIZE);
134bc5531deSDag-Erling Smørgrav #endif
135*19261079SEd Maste 	/* allocate space for encrypted KEM key and ECDH pub key */
136*19261079SEd Maste 	if ((server_blob = sshbuf_new()) == NULL) {
137*19261079SEd Maste 		r = SSH_ERR_ALLOC_FAIL;
138*19261079SEd Maste 		goto out;
139*19261079SEd Maste 	}
140*19261079SEd Maste 	if ((r = sshbuf_reserve(server_blob, CURVE25519_SIZE, &server_pub)) != 0)
141*19261079SEd Maste 		goto out;
142*19261079SEd Maste 	kexc25519_keygen(server_key, server_pub);
143*19261079SEd Maste 	/* allocate shared secret */
144*19261079SEd Maste 	if ((buf = sshbuf_new()) == NULL) {
145*19261079SEd Maste 		r = SSH_ERR_ALLOC_FAIL;
146*19261079SEd Maste 		goto out;
147*19261079SEd Maste 	}
148*19261079SEd Maste 	if ((r = kexc25519_shared_key_ext(server_key, client_pub, buf, 0)) < 0)
149*19261079SEd Maste 		goto out;
150*19261079SEd Maste #ifdef DEBUG_KEXECDH
151*19261079SEd Maste 	dump_digest("server public key 25519:", server_pub, CURVE25519_SIZE);
152*19261079SEd Maste 	dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf));
153*19261079SEd Maste #endif
154*19261079SEd Maste 	*server_blobp = server_blob;
155*19261079SEd Maste 	*shared_secretp = buf;
156*19261079SEd Maste 	server_blob = NULL;
157*19261079SEd Maste 	buf = NULL;
158*19261079SEd Maste  out:
159*19261079SEd Maste 	explicit_bzero(server_key, sizeof(server_key));
160*19261079SEd Maste 	sshbuf_free(server_blob);
161*19261079SEd Maste 	sshbuf_free(buf);
162*19261079SEd Maste 	return r;
163*19261079SEd Maste }
164*19261079SEd Maste 
165*19261079SEd Maste int
kex_c25519_dec(struct kex * kex,const struct sshbuf * server_blob,struct sshbuf ** shared_secretp)166*19261079SEd Maste kex_c25519_dec(struct kex *kex, const struct sshbuf *server_blob,
167*19261079SEd Maste     struct sshbuf **shared_secretp)
168*19261079SEd Maste {
169*19261079SEd Maste 	struct sshbuf *buf = NULL;
170*19261079SEd Maste 	const u_char *server_pub;
171*19261079SEd Maste 	int r;
172*19261079SEd Maste 
173*19261079SEd Maste 	*shared_secretp = NULL;
174*19261079SEd Maste 
175*19261079SEd Maste 	if (sshbuf_len(server_blob) != CURVE25519_SIZE) {
176*19261079SEd Maste 		r = SSH_ERR_SIGNATURE_INVALID;
177*19261079SEd Maste 		goto out;
178*19261079SEd Maste 	}
179*19261079SEd Maste 	server_pub = sshbuf_ptr(server_blob);
180*19261079SEd Maste #ifdef DEBUG_KEXECDH
181*19261079SEd Maste 	dump_digest("server public key c25519:", server_pub, CURVE25519_SIZE);
182*19261079SEd Maste #endif
183*19261079SEd Maste 	/* shared secret */
184*19261079SEd Maste 	if ((buf = sshbuf_new()) == NULL) {
185*19261079SEd Maste 		r = SSH_ERR_ALLOC_FAIL;
186*19261079SEd Maste 		goto out;
187*19261079SEd Maste 	}
188*19261079SEd Maste 	if ((r = kexc25519_shared_key_ext(kex->c25519_client_key, server_pub,
189*19261079SEd Maste 	    buf, 0)) < 0)
190*19261079SEd Maste 		goto out;
191*19261079SEd Maste #ifdef DEBUG_KEXECDH
192*19261079SEd Maste 	dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf));
193*19261079SEd Maste #endif
194*19261079SEd Maste 	*shared_secretp = buf;
195*19261079SEd Maste 	buf = NULL;
196*19261079SEd Maste  out:
197*19261079SEd Maste 	sshbuf_free(buf);
198*19261079SEd Maste 	return r;
199f7167e0eSDag-Erling Smørgrav }
200