Home | History | Annotate | Line # | Download | only in dist
      1 /* $OpenBSD: kexc25519.c,v 1.18 2024/09/02 12:13:56 djm Exp $ */
      2 /*
      3  * Copyright (c) 2019 Markus Friedl.  All rights reserved.
      4  * Copyright (c) 2010 Damien Miller.  All rights reserved.
      5  * Copyright (c) 2013 Aris Adamantiadis.  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 #include "includes.h"
     28 __RCSID("$NetBSD: kexc25519.c,v 1.9 2024/09/24 21:32:18 christos Exp $");
     29 
     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 "ssh2.h"
     42 
     43 extern int crypto_scalarmult_curve25519(u_char a[CURVE25519_SIZE],
     44     const u_char b[CURVE25519_SIZE], const u_char c[CURVE25519_SIZE])
     45 	__attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE)))
     46 	__attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE)))
     47 	__attribute__((__bounded__(__minbytes__, 3, CURVE25519_SIZE)));
     48 
     49 void
     50 kexc25519_keygen(u_char key[CURVE25519_SIZE], u_char pub[CURVE25519_SIZE])
     51 {
     52 	static const u_char basepoint[CURVE25519_SIZE] = {9};
     53 
     54 	arc4random_buf(key, CURVE25519_SIZE);
     55 	crypto_scalarmult_curve25519(pub, key, basepoint);
     56 }
     57 
     58 int
     59 kexc25519_shared_key_ext(const u_char key[CURVE25519_SIZE],
     60     const u_char pub[CURVE25519_SIZE], struct sshbuf *out, int raw)
     61 {
     62 	u_char shared_key[CURVE25519_SIZE];
     63 	u_char zero[CURVE25519_SIZE];
     64 	int r;
     65 
     66 	crypto_scalarmult_curve25519(shared_key, key, pub);
     67 
     68 	/* Check for all-zero shared secret */
     69 	explicit_bzero(zero, CURVE25519_SIZE);
     70 	if (timingsafe_bcmp(zero, shared_key, CURVE25519_SIZE) == 0)
     71 		return SSH_ERR_KEY_INVALID_EC_VALUE;
     72 
     73 #ifdef DEBUG_KEXECDH
     74 	dump_digest("shared secret 25519", shared_key, CURVE25519_SIZE);
     75 #endif
     76 	if (raw)
     77 		r = sshbuf_put(out, shared_key, CURVE25519_SIZE);
     78 	else
     79 		r = sshbuf_put_bignum2_bytes(out, shared_key, CURVE25519_SIZE);
     80 	explicit_bzero(shared_key, CURVE25519_SIZE);
     81 	return r;
     82 }
     83 
     84 int
     85 kexc25519_shared_key(const u_char key[CURVE25519_SIZE],
     86     const u_char pub[CURVE25519_SIZE], struct sshbuf *out)
     87 {
     88 	return kexc25519_shared_key_ext(key, pub, out, 0);
     89 }
     90 
     91 int
     92 kex_c25519_keypair(struct kex *kex)
     93 {
     94 	struct sshbuf *buf = NULL;
     95 	u_char *cp = NULL;
     96 	int r;
     97 
     98 	if ((buf = sshbuf_new()) == NULL)
     99 		return SSH_ERR_ALLOC_FAIL;
    100 	if ((r = sshbuf_reserve(buf, CURVE25519_SIZE, &cp)) != 0)
    101 		goto out;
    102 	kexc25519_keygen(kex->c25519_client_key, cp);
    103 #ifdef DEBUG_KEXECDH
    104 	dump_digest("client public key c25519:", cp, CURVE25519_SIZE);
    105 #endif
    106 	kex->client_pub = buf;
    107 	buf = NULL;
    108  out:
    109 	sshbuf_free(buf);
    110 	return r;
    111 }
    112 
    113 int
    114 kex_c25519_enc(struct kex *kex, const struct sshbuf *client_blob,
    115    struct sshbuf **server_blobp, struct sshbuf **shared_secretp)
    116 {
    117 	struct sshbuf *server_blob = NULL;
    118 	struct sshbuf *buf = NULL;
    119 	const u_char *client_pub;
    120 	u_char *server_pub;
    121 	u_char server_key[CURVE25519_SIZE];
    122 	int r;
    123 
    124 	*server_blobp = NULL;
    125 	*shared_secretp = NULL;
    126 
    127 	if (sshbuf_len(client_blob) != CURVE25519_SIZE) {
    128 		r = SSH_ERR_SIGNATURE_INVALID;
    129 		goto out;
    130 	}
    131 	client_pub = sshbuf_ptr(client_blob);
    132 #ifdef DEBUG_KEXECDH
    133 	dump_digest("client public key 25519:", client_pub, CURVE25519_SIZE);
    134 #endif
    135 	/* allocate space for encrypted KEM key and ECDH pub key */
    136 	if ((server_blob = sshbuf_new()) == NULL) {
    137 		r = SSH_ERR_ALLOC_FAIL;
    138 		goto out;
    139 	}
    140 	if ((r = sshbuf_reserve(server_blob, CURVE25519_SIZE, &server_pub)) != 0)
    141 		goto out;
    142 	kexc25519_keygen(server_key, server_pub);
    143 	/* allocate shared secret */
    144 	if ((buf = sshbuf_new()) == NULL) {
    145 		r = SSH_ERR_ALLOC_FAIL;
    146 		goto out;
    147 	}
    148 	if ((r = kexc25519_shared_key_ext(server_key, client_pub, buf, 0)) < 0)
    149 		goto out;
    150 #ifdef DEBUG_KEXECDH
    151 	dump_digest("server public key 25519:", server_pub, CURVE25519_SIZE);
    152 	dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf));
    153 #endif
    154 	*server_blobp = server_blob;
    155 	*shared_secretp = buf;
    156 	server_blob = NULL;
    157 	buf = NULL;
    158  out:
    159 	explicit_bzero(server_key, sizeof(server_key));
    160 	sshbuf_free(server_blob);
    161 	sshbuf_free(buf);
    162 	return r;
    163 }
    164 
    165 int
    166 kex_c25519_dec(struct kex *kex, const struct sshbuf *server_blob,
    167     struct sshbuf **shared_secretp)
    168 {
    169 	struct sshbuf *buf = NULL;
    170 	const u_char *server_pub;
    171 	int r;
    172 
    173 	*shared_secretp = NULL;
    174 
    175 	if (sshbuf_len(server_blob) != CURVE25519_SIZE) {
    176 		r = SSH_ERR_SIGNATURE_INVALID;
    177 		goto out;
    178 	}
    179 	server_pub = sshbuf_ptr(server_blob);
    180 #ifdef DEBUG_KEXECDH
    181 	dump_digest("server public key c25519:", server_pub, CURVE25519_SIZE);
    182 #endif
    183 	/* shared secret */
    184 	if ((buf = sshbuf_new()) == NULL) {
    185 		r = SSH_ERR_ALLOC_FAIL;
    186 		goto out;
    187 	}
    188 	if ((r = kexc25519_shared_key_ext(kex->c25519_client_key, server_pub,
    189 	    buf, 0)) < 0)
    190 		goto out;
    191 #ifdef DEBUG_KEXECDH
    192 	dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf));
    193 #endif
    194 	*shared_secretp = buf;
    195 	buf = NULL;
    196  out:
    197 	sshbuf_free(buf);
    198 	return r;
    199 }
    200