]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - crypto/openssh/kexsntrup761x25519.c
ssh: update to OpenSSH v8.9p1
[FreeBSD/FreeBSD.git] / crypto / openssh / kexsntrup761x25519.c
1 /* $OpenBSD: kexsntrup761x25519.c,v 1.2 2021/12/05 12:28:27 jsg Exp $ */
2 /*
3  * Copyright (c) 2019 Markus Friedl.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "includes.h"
27
28 #ifdef USE_SNTRUP761X25519
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
42 int
43 kex_kem_sntrup761x25519_keypair(struct kex *kex)
44 {
45         struct sshbuf *buf = NULL;
46         u_char *cp = NULL;
47         size_t need;
48         int r;
49
50         if ((buf = sshbuf_new()) == NULL)
51                 return SSH_ERR_ALLOC_FAIL;
52         need = crypto_kem_sntrup761_PUBLICKEYBYTES + CURVE25519_SIZE;
53         if ((r = sshbuf_reserve(buf, need, &cp)) != 0)
54                 goto out;
55         crypto_kem_sntrup761_keypair(cp, kex->sntrup761_client_key);
56 #ifdef DEBUG_KEXECDH
57         dump_digest("client public key sntrup761:", cp,
58             crypto_kem_sntrup761_PUBLICKEYBYTES);
59 #endif
60         cp += crypto_kem_sntrup761_PUBLICKEYBYTES;
61         kexc25519_keygen(kex->c25519_client_key, cp);
62 #ifdef DEBUG_KEXECDH
63         dump_digest("client public key c25519:", cp, CURVE25519_SIZE);
64 #endif
65         kex->client_pub = buf;
66         buf = NULL;
67  out:
68         sshbuf_free(buf);
69         return r;
70 }
71
72 int
73 kex_kem_sntrup761x25519_enc(struct kex *kex,
74    const struct sshbuf *client_blob, struct sshbuf **server_blobp,
75    struct sshbuf **shared_secretp)
76 {
77         struct sshbuf *server_blob = NULL;
78         struct sshbuf *buf = NULL;
79         const u_char *client_pub;
80         u_char *kem_key, *ciphertext, *server_pub;
81         u_char server_key[CURVE25519_SIZE];
82         u_char hash[SSH_DIGEST_MAX_LENGTH];
83         size_t need;
84         int r;
85
86         *server_blobp = NULL;
87         *shared_secretp = NULL;
88
89         /* client_blob contains both KEM and ECDH client pubkeys */
90         need = crypto_kem_sntrup761_PUBLICKEYBYTES + CURVE25519_SIZE;
91         if (sshbuf_len(client_blob) != need) {
92                 r = SSH_ERR_SIGNATURE_INVALID;
93                 goto out;
94         }
95         client_pub = sshbuf_ptr(client_blob);
96 #ifdef DEBUG_KEXECDH
97         dump_digest("client public key sntrup761:", client_pub,
98             crypto_kem_sntrup761_PUBLICKEYBYTES);
99         dump_digest("client public key 25519:",
100             client_pub + crypto_kem_sntrup761_PUBLICKEYBYTES,
101             CURVE25519_SIZE);
102 #endif
103         /* allocate buffer for concatenation of KEM key and ECDH shared key */
104         /* the buffer will be hashed and the result is the shared secret */
105         if ((buf = sshbuf_new()) == NULL) {
106                 r = SSH_ERR_ALLOC_FAIL;
107                 goto out;
108         }
109         if ((r = sshbuf_reserve(buf, crypto_kem_sntrup761_BYTES,
110             &kem_key)) != 0)
111                 goto out;
112         /* allocate space for encrypted KEM key and ECDH pub key */
113         if ((server_blob = sshbuf_new()) == NULL) {
114                 r = SSH_ERR_ALLOC_FAIL;
115                 goto out;
116         }
117         need = crypto_kem_sntrup761_CIPHERTEXTBYTES + CURVE25519_SIZE;
118         if ((r = sshbuf_reserve(server_blob, need, &ciphertext)) != 0)
119                 goto out;
120         /* generate and encrypt KEM key with client key */
121         crypto_kem_sntrup761_enc(ciphertext, kem_key, client_pub);
122         /* generate ECDH key pair, store server pubkey after ciphertext */
123         server_pub = ciphertext + crypto_kem_sntrup761_CIPHERTEXTBYTES;
124         kexc25519_keygen(server_key, server_pub);
125         /* append ECDH shared key */
126         client_pub += crypto_kem_sntrup761_PUBLICKEYBYTES;
127         if ((r = kexc25519_shared_key_ext(server_key, client_pub, buf, 1)) < 0)
128                 goto out;
129         if ((r = ssh_digest_buffer(kex->hash_alg, buf, hash, sizeof(hash))) != 0)
130                 goto out;
131 #ifdef DEBUG_KEXECDH
132         dump_digest("server public key 25519:", server_pub, CURVE25519_SIZE);
133         dump_digest("server cipher text:", ciphertext,
134             crypto_kem_sntrup761_CIPHERTEXTBYTES);
135         dump_digest("server kem key:", kem_key, crypto_kem_sntrup761_BYTES);
136         dump_digest("concatenation of KEM key and ECDH shared key:",
137             sshbuf_ptr(buf), sshbuf_len(buf));
138 #endif
139         /* string-encoded hash is resulting shared secret */
140         sshbuf_reset(buf);
141         if ((r = sshbuf_put_string(buf, hash,
142             ssh_digest_bytes(kex->hash_alg))) != 0)
143                 goto out;
144 #ifdef DEBUG_KEXECDH
145         dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf));
146 #endif
147         *server_blobp = server_blob;
148         *shared_secretp = buf;
149         server_blob = NULL;
150         buf = NULL;
151  out:
152         explicit_bzero(hash, sizeof(hash));
153         explicit_bzero(server_key, sizeof(server_key));
154         sshbuf_free(server_blob);
155         sshbuf_free(buf);
156         return r;
157 }
158
159 int
160 kex_kem_sntrup761x25519_dec(struct kex *kex,
161     const struct sshbuf *server_blob, struct sshbuf **shared_secretp)
162 {
163         struct sshbuf *buf = NULL;
164         u_char *kem_key = NULL;
165         const u_char *ciphertext, *server_pub;
166         u_char hash[SSH_DIGEST_MAX_LENGTH];
167         size_t need;
168         int r, decoded;
169
170         *shared_secretp = NULL;
171
172         need = crypto_kem_sntrup761_CIPHERTEXTBYTES + CURVE25519_SIZE;
173         if (sshbuf_len(server_blob) != need) {
174                 r = SSH_ERR_SIGNATURE_INVALID;
175                 goto out;
176         }
177         ciphertext = sshbuf_ptr(server_blob);
178         server_pub = ciphertext + crypto_kem_sntrup761_CIPHERTEXTBYTES;
179 #ifdef DEBUG_KEXECDH
180         dump_digest("server cipher text:", ciphertext,
181             crypto_kem_sntrup761_CIPHERTEXTBYTES);
182         dump_digest("server public key c25519:", server_pub, CURVE25519_SIZE);
183 #endif
184         /* hash concatenation of KEM key and ECDH shared key */
185         if ((buf = sshbuf_new()) == NULL) {
186                 r = SSH_ERR_ALLOC_FAIL;
187                 goto out;
188         }
189         if ((r = sshbuf_reserve(buf, crypto_kem_sntrup761_BYTES,
190             &kem_key)) != 0)
191                 goto out;
192         decoded = crypto_kem_sntrup761_dec(kem_key, ciphertext,
193             kex->sntrup761_client_key);
194         if ((r = kexc25519_shared_key_ext(kex->c25519_client_key, server_pub,
195             buf, 1)) < 0)
196                 goto out;
197         if ((r = ssh_digest_buffer(kex->hash_alg, buf, hash, sizeof(hash))) != 0)
198                 goto out;
199 #ifdef DEBUG_KEXECDH
200         dump_digest("client kem key:", kem_key, crypto_kem_sntrup761_BYTES);
201         dump_digest("concatenation of KEM key and ECDH shared key:",
202             sshbuf_ptr(buf), sshbuf_len(buf));
203 #endif
204         sshbuf_reset(buf);
205         if ((r = sshbuf_put_string(buf, hash,
206             ssh_digest_bytes(kex->hash_alg))) != 0)
207                 goto out;
208 #ifdef DEBUG_KEXECDH
209         dump_digest("encoded shared secret:", sshbuf_ptr(buf), sshbuf_len(buf));
210 #endif
211         if (decoded != 0) {
212                 r = SSH_ERR_SIGNATURE_INVALID;
213                 goto out;
214         }
215         *shared_secretp = buf;
216         buf = NULL;
217  out:
218         explicit_bzero(hash, sizeof(hash));
219         sshbuf_free(buf);
220         return r;
221 }
222
223 #else
224
225 #include "ssherr.h"
226
227 struct kex;
228 struct sshbuf;
229 struct sshkey;
230
231 int
232 kex_kem_sntrup761x25519_keypair(struct kex *kex)
233 {
234         return SSH_ERR_SIGN_ALG_UNSUPPORTED;
235 }
236
237 int
238 kex_kem_sntrup761x25519_enc(struct kex *kex,
239    const struct sshbuf *client_blob, struct sshbuf **server_blobp,
240    struct sshbuf **shared_secretp)
241 {
242         return SSH_ERR_SIGN_ALG_UNSUPPORTED;
243 }
244
245 int
246 kex_kem_sntrup761x25519_dec(struct kex *kex,
247     const struct sshbuf *server_blob, struct sshbuf **shared_secretp)
248 {
249         return SSH_ERR_SIGN_ALG_UNSUPPORTED;
250 }
251 #endif /* USE_SNTRUP761X25519 */