1 |
|
|
/* $OpenBSD: ssh-ed25519.c,v 1.7 2016/04/21 06:08:02 djm Exp $ */ |
2 |
|
|
/* |
3 |
|
|
* Copyright (c) 2013 Markus Friedl <markus@openbsd.org> |
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 |
|
|
#define SSHKEY_INTERNAL |
18 |
|
|
#include <sys/types.h> |
19 |
|
|
#include <limits.h> |
20 |
|
|
|
21 |
|
|
#include "crypto_api.h" |
22 |
|
|
|
23 |
|
|
#include <string.h> |
24 |
|
|
#include <stdarg.h> |
25 |
|
|
|
26 |
|
|
#include "log.h" |
27 |
|
|
#include "sshbuf.h" |
28 |
|
|
#include "sshkey.h" |
29 |
|
|
#include "ssherr.h" |
30 |
|
|
#include "ssh.h" |
31 |
|
|
|
32 |
|
|
int |
33 |
|
|
ssh_ed25519_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, |
34 |
|
|
const u_char *data, size_t datalen, u_int compat) |
35 |
|
|
{ |
36 |
|
|
u_char *sig = NULL; |
37 |
|
|
size_t slen = 0, len; |
38 |
|
|
unsigned long long smlen; |
39 |
|
|
int r, ret; |
40 |
|
|
struct sshbuf *b = NULL; |
41 |
|
|
|
42 |
|
|
if (lenp != NULL) |
43 |
|
|
*lenp = 0; |
44 |
|
|
if (sigp != NULL) |
45 |
|
|
*sigp = NULL; |
46 |
|
|
|
47 |
|
|
if (key == NULL || |
48 |
|
|
sshkey_type_plain(key->type) != KEY_ED25519 || |
49 |
|
|
key->ed25519_sk == NULL || |
50 |
|
|
datalen >= INT_MAX - crypto_sign_ed25519_BYTES) |
51 |
|
|
return SSH_ERR_INVALID_ARGUMENT; |
52 |
|
|
smlen = slen = datalen + crypto_sign_ed25519_BYTES; |
53 |
|
|
if ((sig = malloc(slen)) == NULL) |
54 |
|
|
return SSH_ERR_ALLOC_FAIL; |
55 |
|
|
|
56 |
|
|
if ((ret = crypto_sign_ed25519(sig, &smlen, data, datalen, |
57 |
|
|
key->ed25519_sk)) != 0 || smlen <= datalen) { |
58 |
|
|
r = SSH_ERR_INVALID_ARGUMENT; /* XXX better error? */ |
59 |
|
|
goto out; |
60 |
|
|
} |
61 |
|
|
/* encode signature */ |
62 |
|
|
if ((b = sshbuf_new()) == NULL) { |
63 |
|
|
r = SSH_ERR_ALLOC_FAIL; |
64 |
|
|
goto out; |
65 |
|
|
} |
66 |
|
|
if ((r = sshbuf_put_cstring(b, "ssh-ed25519")) != 0 || |
67 |
|
|
(r = sshbuf_put_string(b, sig, smlen - datalen)) != 0) |
68 |
|
|
goto out; |
69 |
|
|
len = sshbuf_len(b); |
70 |
|
|
if (sigp != NULL) { |
71 |
|
|
if ((*sigp = malloc(len)) == NULL) { |
72 |
|
|
r = SSH_ERR_ALLOC_FAIL; |
73 |
|
|
goto out; |
74 |
|
|
} |
75 |
|
|
memcpy(*sigp, sshbuf_ptr(b), len); |
76 |
|
|
} |
77 |
|
|
if (lenp != NULL) |
78 |
|
|
*lenp = len; |
79 |
|
|
/* success */ |
80 |
|
|
r = 0; |
81 |
|
|
out: |
82 |
|
|
sshbuf_free(b); |
83 |
|
|
if (sig != NULL) { |
84 |
|
|
explicit_bzero(sig, slen); |
85 |
|
|
free(sig); |
86 |
|
|
} |
87 |
|
|
|
88 |
|
|
return r; |
89 |
|
|
} |
90 |
|
|
|
91 |
|
|
int |
92 |
|
|
ssh_ed25519_verify(const struct sshkey *key, |
93 |
|
|
const u_char *signature, size_t signaturelen, |
94 |
|
|
const u_char *data, size_t datalen, u_int compat) |
95 |
|
|
{ |
96 |
|
|
struct sshbuf *b = NULL; |
97 |
|
|
char *ktype = NULL; |
98 |
|
|
const u_char *sigblob; |
99 |
|
|
u_char *sm = NULL, *m = NULL; |
100 |
|
|
size_t len; |
101 |
|
|
unsigned long long smlen = 0, mlen = 0; |
102 |
|
|
int r, ret; |
103 |
|
|
|
104 |
|
|
if (key == NULL || |
105 |
|
|
sshkey_type_plain(key->type) != KEY_ED25519 || |
106 |
|
|
key->ed25519_pk == NULL || |
107 |
|
|
datalen >= INT_MAX - crypto_sign_ed25519_BYTES || |
108 |
|
|
signature == NULL || signaturelen == 0) |
109 |
|
|
return SSH_ERR_INVALID_ARGUMENT; |
110 |
|
|
|
111 |
|
|
if ((b = sshbuf_from(signature, signaturelen)) == NULL) |
112 |
|
|
return SSH_ERR_ALLOC_FAIL; |
113 |
|
|
if ((r = sshbuf_get_cstring(b, &ktype, NULL)) != 0 || |
114 |
|
|
(r = sshbuf_get_string_direct(b, &sigblob, &len)) != 0) |
115 |
|
|
goto out; |
116 |
|
|
if (strcmp("ssh-ed25519", ktype) != 0) { |
117 |
|
|
r = SSH_ERR_KEY_TYPE_MISMATCH; |
118 |
|
|
goto out; |
119 |
|
|
} |
120 |
|
|
if (sshbuf_len(b) != 0) { |
121 |
|
|
r = SSH_ERR_UNEXPECTED_TRAILING_DATA; |
122 |
|
|
goto out; |
123 |
|
|
} |
124 |
|
|
if (len > crypto_sign_ed25519_BYTES) { |
125 |
|
|
r = SSH_ERR_INVALID_FORMAT; |
126 |
|
|
goto out; |
127 |
|
|
} |
128 |
|
|
if (datalen >= SIZE_MAX - len) { |
129 |
|
|
r = SSH_ERR_INVALID_ARGUMENT; |
130 |
|
|
goto out; |
131 |
|
|
} |
132 |
|
|
smlen = len + datalen; |
133 |
|
|
mlen = smlen; |
134 |
|
|
if ((sm = malloc(smlen)) == NULL || (m = malloc(mlen)) == NULL) { |
135 |
|
|
r = SSH_ERR_ALLOC_FAIL; |
136 |
|
|
goto out; |
137 |
|
|
} |
138 |
|
|
memcpy(sm, sigblob, len); |
139 |
|
|
memcpy(sm+len, data, datalen); |
140 |
|
|
if ((ret = crypto_sign_ed25519_open(m, &mlen, sm, smlen, |
141 |
|
|
key->ed25519_pk)) != 0) { |
142 |
|
|
debug2("%s: crypto_sign_ed25519_open failed: %d", |
143 |
|
|
__func__, ret); |
144 |
|
|
} |
145 |
|
|
if (ret != 0 || mlen != datalen) { |
146 |
|
|
r = SSH_ERR_SIGNATURE_INVALID; |
147 |
|
|
goto out; |
148 |
|
|
} |
149 |
|
|
/* XXX compare 'm' and 'data' ? */ |
150 |
|
|
/* success */ |
151 |
|
|
r = 0; |
152 |
|
|
out: |
153 |
|
|
if (sm != NULL) { |
154 |
|
|
explicit_bzero(sm, smlen); |
155 |
|
|
free(sm); |
156 |
|
|
} |
157 |
|
|
if (m != NULL) { |
158 |
|
|
explicit_bzero(m, smlen); /* NB mlen may be invalid if r != 0 */ |
159 |
|
|
free(m); |
160 |
|
|
} |
161 |
|
|
sshbuf_free(b); |
162 |
|
|
free(ktype); |
163 |
|
|
return r; |
164 |
|
|
} |