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