]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - crypto/openssh/ssh-ed25519-sk.c
bsddialog: import version 1.0
[FreeBSD/FreeBSD.git] / crypto / openssh / ssh-ed25519-sk.c
1 /* $OpenBSD: ssh-ed25519-sk.c,v 1.15 2022/10/28 00:44:44 djm Exp $ */
2 /*
3  * Copyright (c) 2019 Markus Friedl.  All rights reserved.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* #define DEBUG_SK 1 */
19
20 #include "includes.h"
21
22 #define SSHKEY_INTERNAL
23 #include <sys/types.h>
24 #include <limits.h>
25
26 #include "crypto_api.h"
27
28 #include <string.h>
29 #include <stdarg.h>
30
31 #include "log.h"
32 #include "sshbuf.h"
33 #include "sshkey.h"
34 #include "ssherr.h"
35 #include "ssh.h"
36 #include "digest.h"
37
38 /* Reuse some ED25519 internals */
39 extern struct sshkey_impl_funcs sshkey_ed25519_funcs;
40
41 static void
42 ssh_ed25519_sk_cleanup(struct sshkey *k)
43 {
44         sshkey_sk_cleanup(k);
45         sshkey_ed25519_funcs.cleanup(k);
46 }
47
48 static int
49 ssh_ed25519_sk_equal(const struct sshkey *a, const struct sshkey *b)
50 {
51         if (!sshkey_sk_fields_equal(a, b))
52                 return 0;
53         if (!sshkey_ed25519_funcs.equal(a, b))
54                 return 0;
55         return 1;
56 }
57
58 static int
59 ssh_ed25519_sk_serialize_public(const struct sshkey *key, struct sshbuf *b,
60     enum sshkey_serialize_rep opts)
61 {
62         int r;
63
64         if ((r = sshkey_ed25519_funcs.serialize_public(key, b, opts)) != 0)
65                 return r;
66         if ((r = sshkey_serialize_sk(key, b)) != 0)
67                 return r;
68
69         return 0;
70 }
71
72 static int
73 ssh_ed25519_sk_serialize_private(const struct sshkey *key, struct sshbuf *b,
74     enum sshkey_serialize_rep opts)
75 {
76         int r;
77
78         if ((r = sshkey_ed25519_funcs.serialize_public(key, b, opts)) != 0)
79                 return r;
80         if ((r = sshkey_serialize_private_sk(key, b)) != 0)
81                 return r;
82
83         return 0;
84 }
85
86 static int
87 ssh_ed25519_sk_copy_public(const struct sshkey *from, struct sshkey *to)
88 {
89         int r;
90
91         if ((r = sshkey_ed25519_funcs.copy_public(from, to)) != 0)
92                 return r;
93         if ((r = sshkey_copy_public_sk(from, to)) != 0)
94                 return r;
95         return 0;
96 }
97
98 static int
99 ssh_ed25519_sk_deserialize_public(const char *ktype, struct sshbuf *b,
100     struct sshkey *key)
101 {
102         int r;
103
104         if ((r = sshkey_ed25519_funcs.deserialize_public(ktype, b, key)) != 0)
105                 return r;
106         if ((r = sshkey_deserialize_sk(b, key)) != 0)
107                 return r;
108         return 0;
109 }
110
111 static int
112 ssh_ed25519_sk_deserialize_private(const char *ktype, struct sshbuf *b,
113     struct sshkey *key)
114 {
115         int r;
116
117         if ((r = sshkey_ed25519_funcs.deserialize_public(ktype, b, key)) != 0)
118                 return r;
119         if ((r = sshkey_private_deserialize_sk(b, key)) != 0)
120                 return r;
121         return 0;
122 }
123
124 static int
125 ssh_ed25519_sk_verify(const struct sshkey *key,
126     const u_char *sig, size_t siglen,
127     const u_char *data, size_t dlen, const char *alg, u_int compat,
128     struct sshkey_sig_details **detailsp)
129 {
130         struct sshbuf *b = NULL;
131         struct sshbuf *encoded = NULL;
132         char *ktype = NULL;
133         const u_char *sigblob;
134         const u_char *sm;
135         u_char *m = NULL;
136         u_char apphash[32];
137         u_char msghash[32];
138         u_char sig_flags;
139         u_int sig_counter;
140         size_t len;
141         unsigned long long smlen = 0, mlen = 0;
142         int r = SSH_ERR_INTERNAL_ERROR;
143         int ret;
144         struct sshkey_sig_details *details = NULL;
145
146         if (detailsp != NULL)
147                 *detailsp = NULL;
148
149         if (key == NULL ||
150             sshkey_type_plain(key->type) != KEY_ED25519_SK ||
151             key->ed25519_pk == NULL ||
152             sig == NULL || siglen == 0)
153                 return SSH_ERR_INVALID_ARGUMENT;
154
155         if ((b = sshbuf_from(sig, siglen)) == NULL)
156                 return SSH_ERR_ALLOC_FAIL;
157         if (sshbuf_get_cstring(b, &ktype, NULL) != 0 ||
158             sshbuf_get_string_direct(b, &sigblob, &len) != 0 ||
159             sshbuf_get_u8(b, &sig_flags) != 0 ||
160             sshbuf_get_u32(b, &sig_counter) != 0) {
161                 r = SSH_ERR_INVALID_FORMAT;
162                 goto out;
163         }
164 #ifdef DEBUG_SK
165         fprintf(stderr, "%s: data:\n", __func__);
166         /* sshbuf_dump_data(data, datalen, stderr); */
167         fprintf(stderr, "%s: sigblob:\n", __func__);
168         sshbuf_dump_data(sigblob, len, stderr);
169         fprintf(stderr, "%s: sig_flags = 0x%02x, sig_counter = %u\n",
170             __func__, sig_flags, sig_counter);
171 #endif
172         if (strcmp(sshkey_ssh_name_plain(key), ktype) != 0) {
173                 r = SSH_ERR_KEY_TYPE_MISMATCH;
174                 goto out;
175         }
176         if (sshbuf_len(b) != 0) {
177                 r = SSH_ERR_UNEXPECTED_TRAILING_DATA;
178                 goto out;
179         }
180         if (len > crypto_sign_ed25519_BYTES) {
181                 r = SSH_ERR_INVALID_FORMAT;
182                 goto out;
183         }
184         if (ssh_digest_memory(SSH_DIGEST_SHA256, key->sk_application,
185             strlen(key->sk_application), apphash, sizeof(apphash)) != 0 ||
186             ssh_digest_memory(SSH_DIGEST_SHA256, data, dlen,
187             msghash, sizeof(msghash)) != 0) {
188                 r = SSH_ERR_INVALID_ARGUMENT;
189                 goto out;
190         }
191 #ifdef DEBUG_SK
192         fprintf(stderr, "%s: hashed application:\n", __func__);
193         sshbuf_dump_data(apphash, sizeof(apphash), stderr);
194         fprintf(stderr, "%s: hashed message:\n", __func__);
195         sshbuf_dump_data(msghash, sizeof(msghash), stderr);
196 #endif
197         if ((details = calloc(1, sizeof(*details))) == NULL) {
198                 r = SSH_ERR_ALLOC_FAIL;
199                 goto out;
200         }
201         details->sk_counter = sig_counter;
202         details->sk_flags = sig_flags;
203         if ((encoded = sshbuf_new()) == NULL) {
204                 r = SSH_ERR_ALLOC_FAIL;
205                 goto out;
206         }
207         if (sshbuf_put(encoded, sigblob, len) != 0 ||
208             sshbuf_put(encoded, apphash, sizeof(apphash)) != 0 ||
209             sshbuf_put_u8(encoded, sig_flags) != 0 ||
210             sshbuf_put_u32(encoded, sig_counter) != 0 ||
211             sshbuf_put(encoded, msghash, sizeof(msghash)) != 0) {
212                 r = SSH_ERR_ALLOC_FAIL;
213                 goto out;
214         }
215 #ifdef DEBUG_SK
216         fprintf(stderr, "%s: signed buf:\n", __func__);
217         sshbuf_dump(encoded, stderr);
218 #endif
219         sm = sshbuf_ptr(encoded);
220         smlen = sshbuf_len(encoded);
221         mlen = smlen;
222         if ((m = malloc(smlen)) == NULL) {
223                 r = SSH_ERR_ALLOC_FAIL;
224                 goto out;
225         }
226         if ((ret = crypto_sign_ed25519_open(m, &mlen, sm, smlen,
227             key->ed25519_pk)) != 0) {
228                 debug2_f("crypto_sign_ed25519_open failed: %d", ret);
229         }
230         if (ret != 0 || mlen != smlen - len) {
231                 r = SSH_ERR_SIGNATURE_INVALID;
232                 goto out;
233         }
234         /* XXX compare 'm' and 'sm + len' ? */
235         /* success */
236         r = 0;
237         if (detailsp != NULL) {
238                 *detailsp = details;
239                 details = NULL;
240         }
241  out:
242         if (m != NULL)
243                 freezero(m, smlen); /* NB mlen may be invalid if r != 0 */
244         sshkey_sig_details_free(details);
245         sshbuf_free(b);
246         sshbuf_free(encoded);
247         free(ktype);
248         return r;
249 }
250
251 static const struct sshkey_impl_funcs sshkey_ed25519_sk_funcs = {
252         /* .size = */           NULL,
253         /* .alloc = */          NULL,
254         /* .cleanup = */        ssh_ed25519_sk_cleanup,
255         /* .equal = */          ssh_ed25519_sk_equal,
256         /* .ssh_serialize_public = */ ssh_ed25519_sk_serialize_public,
257         /* .ssh_deserialize_public = */ ssh_ed25519_sk_deserialize_public,
258         /* .ssh_serialize_private = */ ssh_ed25519_sk_serialize_private,
259         /* .ssh_deserialize_private = */ ssh_ed25519_sk_deserialize_private,
260         /* .generate = */       NULL,
261         /* .copy_public = */    ssh_ed25519_sk_copy_public,
262         /* .sign = */           NULL,
263         /* .verify = */         ssh_ed25519_sk_verify,
264 };
265
266 const struct sshkey_impl sshkey_ed25519_sk_impl = {
267         /* .name = */           "sk-ssh-ed25519@openssh.com",
268         /* .shortname = */      "ED25519-SK",
269         /* .sigalg = */         NULL,
270         /* .type = */           KEY_ED25519_SK,
271         /* .nid = */            0,
272         /* .cert = */           0,
273         /* .sigonly = */        0,
274         /* .keybits = */        256,
275         /* .funcs = */          &sshkey_ed25519_sk_funcs,
276 };
277
278 const struct sshkey_impl sshkey_ed25519_sk_cert_impl = {
279         /* .name = */           "sk-ssh-ed25519-cert-v01@openssh.com",
280         /* .shortname = */      "ED25519-SK-CERT",
281         /* .sigalg = */         NULL,
282         /* .type = */           KEY_ED25519_SK_CERT,
283         /* .nid = */            0,
284         /* .cert = */           1,
285         /* .sigonly = */        0,
286         /* .keybits = */        256,
287         /* .funcs = */          &sshkey_ed25519_sk_funcs,
288 };