diff options
author | djm@openbsd.org <djm@openbsd.org> | 2019-11-26 23:41:23 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2019-11-27 10:47:28 +1100 |
commit | c6efa8a91af1d4fdb43909a23a0a4ffa012155ad (patch) | |
tree | 5908cdd00c3051d889da7c8f8a25750326fd7af1 | |
parent | 8635afa1cdc21366d61730d943f3cf61861899c8 (diff) |
upstream: add dummy security key middleware based on work by
markus@
This will allow us to test U2F/FIDO2 support in OpenSSH without
requiring real hardware.
ok markus@
OpenBSD-Regress-ID: 88b309464b8850c320cf7513f26d97ee1fdf9aae
-rw-r--r-- | regress/misc/Makefile | 2 | ||||
-rw-r--r-- | regress/misc/sk-dummy/Makefile | 67 | ||||
-rw-r--r-- | regress/misc/sk-dummy/sk-dummy.c | 522 |
3 files changed, 590 insertions, 1 deletions
diff --git a/regress/misc/Makefile b/regress/misc/Makefile index 14c0c279f..cf95f265c 100644 --- a/regress/misc/Makefile +++ b/regress/misc/Makefile | |||
@@ -1,3 +1,3 @@ | |||
1 | SUBDIR= kexfuzz | 1 | SUBDIR= kexfuzz sk-dummy |
2 | 2 | ||
3 | .include <bsd.subdir.mk> | 3 | .include <bsd.subdir.mk> |
diff --git a/regress/misc/sk-dummy/Makefile b/regress/misc/sk-dummy/Makefile new file mode 100644 index 000000000..db229aa1f --- /dev/null +++ b/regress/misc/sk-dummy/Makefile | |||
@@ -0,0 +1,67 @@ | |||
1 | # $OpenBSD: Makefile,v 1.1 2019/11/26 23:41:23 djm Exp $ | ||
2 | |||
3 | .include <bsd.own.mk> | ||
4 | .include <bsd.obj.mk> | ||
5 | |||
6 | PROG= sk-dummy.so | ||
7 | NOMAN= | ||
8 | |||
9 | SSHREL=../../../../../usr.bin/ssh | ||
10 | .PATH: ${.CURDIR}/${SSHREL} | ||
11 | |||
12 | SRCS=sk-dummy.c | ||
13 | # From usr.bin/ssh | ||
14 | SRCS+=ed25519.c hash.c ge25519.c fe25519.c sc25519.c verify.c | ||
15 | SRCS+=digest-openssl.c ssherr.c fatal.c sshbuf.c log.c cleanup.c | ||
16 | OPENSSL?= yes | ||
17 | |||
18 | CFLAGS+= -fPIC | ||
19 | |||
20 | .if (${OPENSSL:L} == "yes") | ||
21 | CFLAGS+= -DWITH_OPENSSL | ||
22 | .endif | ||
23 | |||
24 | # enable warnings | ||
25 | WARNINGS=Yes | ||
26 | |||
27 | DEBUG=-g | ||
28 | CFLAGS+= -fstack-protector-all | ||
29 | CDIAGFLAGS= -Wall | ||
30 | CDIAGFLAGS+= -Wextra | ||
31 | CDIAGFLAGS+= -Werror | ||
32 | CDIAGFLAGS+= -Wchar-subscripts | ||
33 | CDIAGFLAGS+= -Wcomment | ||
34 | CDIAGFLAGS+= -Wformat | ||
35 | CDIAGFLAGS+= -Wformat-security | ||
36 | CDIAGFLAGS+= -Wimplicit | ||
37 | CDIAGFLAGS+= -Winline | ||
38 | CDIAGFLAGS+= -Wmissing-declarations | ||
39 | CDIAGFLAGS+= -Wmissing-prototypes | ||
40 | CDIAGFLAGS+= -Wparentheses | ||
41 | CDIAGFLAGS+= -Wpointer-arith | ||
42 | CDIAGFLAGS+= -Wreturn-type | ||
43 | CDIAGFLAGS+= -Wshadow | ||
44 | CDIAGFLAGS+= -Wsign-compare | ||
45 | CDIAGFLAGS+= -Wstrict-aliasing | ||
46 | CDIAGFLAGS+= -Wstrict-prototypes | ||
47 | CDIAGFLAGS+= -Wswitch | ||
48 | CDIAGFLAGS+= -Wtrigraphs | ||
49 | CDIAGFLAGS+= -Wuninitialized | ||
50 | CDIAGFLAGS+= -Wunused | ||
51 | CDIAGFLAGS+= -Wno-unused-parameter | ||
52 | .if ${COMPILER_VERSION:L} != "gcc3" | ||
53 | CDIAGFLAGS+= -Wold-style-definition | ||
54 | .endif | ||
55 | |||
56 | CFLAGS+=-I${.CURDIR}/${SSHREL} | ||
57 | |||
58 | .if (${OPENSSL:L} == "yes") | ||
59 | LDADD+= -lcrypto | ||
60 | DPADD+= ${LIBCRYPTO} | ||
61 | .endif | ||
62 | |||
63 | $(PROG): $(OBJS) | ||
64 | $(CC) $(LDFLAGS) -shared -o $@ $(OBJS) $(LDADD) | ||
65 | |||
66 | .include <bsd.prog.mk> | ||
67 | |||
diff --git a/regress/misc/sk-dummy/sk-dummy.c b/regress/misc/sk-dummy/sk-dummy.c new file mode 100644 index 000000000..b223b1a0f --- /dev/null +++ b/regress/misc/sk-dummy/sk-dummy.c | |||
@@ -0,0 +1,522 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2019 Markus Friedl | ||
3 | * | ||
4 | * Permission to use, copy, modify, and distribute this software for any | ||
5 | * purpose with or without fee is hereby granted, provided that the above | ||
6 | * copyright notice and this permission notice appear in all copies. | ||
7 | * | ||
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
15 | */ | ||
16 | |||
17 | #include <stdint.h> | ||
18 | #include <stdlib.h> | ||
19 | #include <string.h> | ||
20 | #include <stdio.h> | ||
21 | #include <stddef.h> | ||
22 | #include <stdarg.h> | ||
23 | |||
24 | #include "crypto_api.h" | ||
25 | |||
26 | #include <openssl/opensslv.h> | ||
27 | #include <openssl/crypto.h> | ||
28 | #include <openssl/evp.h> | ||
29 | #include <openssl/bn.h> | ||
30 | #include <openssl/ec.h> | ||
31 | #include <openssl/ecdsa.h> | ||
32 | #include <openssl/pem.h> | ||
33 | |||
34 | /* #define SK_DEBUG 1 */ | ||
35 | |||
36 | /* Compatibility with OpenSSH 1.0.x */ | ||
37 | #if (OPENSSL_VERSION_NUMBER < 0x10100000L) | ||
38 | #define ECDSA_SIG_get0(sig, pr, ps) \ | ||
39 | do { \ | ||
40 | (*pr) = sig->r; \ | ||
41 | (*ps) = sig->s; \ | ||
42 | } while (0) | ||
43 | #endif | ||
44 | |||
45 | #define SK_VERSION_MAJOR 0x00020000 /* current API version */ | ||
46 | |||
47 | /* Flags */ | ||
48 | #define SK_USER_PRESENCE_REQD 0x01 | ||
49 | |||
50 | /* Algs */ | ||
51 | #define SK_ECDSA 0x00 | ||
52 | #define SK_ED25519 0x01 | ||
53 | |||
54 | struct sk_enroll_response { | ||
55 | uint8_t *public_key; | ||
56 | size_t public_key_len; | ||
57 | uint8_t *key_handle; | ||
58 | size_t key_handle_len; | ||
59 | uint8_t *signature; | ||
60 | size_t signature_len; | ||
61 | uint8_t *attestation_cert; | ||
62 | size_t attestation_cert_len; | ||
63 | }; | ||
64 | |||
65 | struct sk_sign_response { | ||
66 | uint8_t flags; | ||
67 | uint32_t counter; | ||
68 | uint8_t *sig_r; | ||
69 | size_t sig_r_len; | ||
70 | uint8_t *sig_s; | ||
71 | size_t sig_s_len; | ||
72 | }; | ||
73 | |||
74 | /* Return the version of the middleware API */ | ||
75 | uint32_t sk_api_version(void); | ||
76 | |||
77 | /* Enroll a U2F key (private key generation) */ | ||
78 | int sk_enroll(int alg, const uint8_t *challenge, size_t challenge_len, | ||
79 | const char *application, uint8_t flags, | ||
80 | struct sk_enroll_response **enroll_response); | ||
81 | |||
82 | /* Sign a challenge */ | ||
83 | int sk_sign(int alg, const uint8_t *message, size_t message_len, | ||
84 | const char *application, const uint8_t *key_handle, size_t key_handle_len, | ||
85 | uint8_t flags, struct sk_sign_response **sign_response); | ||
86 | |||
87 | static void skdebug(const char *func, const char *fmt, ...) | ||
88 | __attribute__((__format__ (printf, 2, 3))); | ||
89 | |||
90 | static void | ||
91 | skdebug(const char *func, const char *fmt, ...) | ||
92 | { | ||
93 | #if defined(SK_DEBUG) | ||
94 | va_list ap; | ||
95 | |||
96 | va_start(ap, fmt); | ||
97 | fprintf(stderr, "sk-dummy %s: ", func); | ||
98 | vfprintf(stderr, fmt, ap); | ||
99 | fputc('\n', stderr); | ||
100 | va_end(ap); | ||
101 | #else | ||
102 | (void)func; /* XXX */ | ||
103 | (void)fmt; /* XXX */ | ||
104 | #endif | ||
105 | } | ||
106 | |||
107 | uint32_t | ||
108 | sk_api_version(void) | ||
109 | { | ||
110 | return SK_VERSION_MAJOR; | ||
111 | } | ||
112 | |||
113 | static int | ||
114 | pack_key_ecdsa(struct sk_enroll_response *response) | ||
115 | { | ||
116 | EC_KEY *key = NULL; | ||
117 | const EC_GROUP *g; | ||
118 | const EC_POINT *q; | ||
119 | int ret = -1; | ||
120 | long privlen; | ||
121 | BIO *bio = NULL; | ||
122 | char *privptr; | ||
123 | |||
124 | response->public_key = NULL; | ||
125 | response->public_key_len = 0; | ||
126 | response->key_handle = NULL; | ||
127 | response->key_handle_len = 0; | ||
128 | |||
129 | if ((key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)) == NULL) { | ||
130 | skdebug(__func__, "EC_KEY_new_by_curve_name"); | ||
131 | goto out; | ||
132 | } | ||
133 | if (EC_KEY_generate_key(key) != 1) { | ||
134 | skdebug(__func__, "EC_KEY_generate_key"); | ||
135 | goto out; | ||
136 | } | ||
137 | EC_KEY_set_asn1_flag(key, OPENSSL_EC_NAMED_CURVE); | ||
138 | if ((bio = BIO_new(BIO_s_mem())) == NULL || | ||
139 | (g = EC_KEY_get0_group(key)) == NULL || | ||
140 | (q = EC_KEY_get0_public_key(key)) == NULL) { | ||
141 | skdebug(__func__, "couldn't get key parameters"); | ||
142 | goto out; | ||
143 | } | ||
144 | response->public_key_len = EC_POINT_point2oct(g, q, | ||
145 | POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL); | ||
146 | if (response->public_key_len == 0 || response->public_key_len > 2048) { | ||
147 | skdebug(__func__, "bad pubkey length %zu", | ||
148 | response->public_key_len); | ||
149 | goto out; | ||
150 | } | ||
151 | if ((response->public_key = malloc(response->public_key_len)) == NULL) { | ||
152 | skdebug(__func__, "malloc pubkey failed"); | ||
153 | goto out; | ||
154 | } | ||
155 | if (EC_POINT_point2oct(g, q, POINT_CONVERSION_UNCOMPRESSED, | ||
156 | response->public_key, response->public_key_len, NULL) == 0) { | ||
157 | skdebug(__func__, "EC_POINT_point2oct failed"); | ||
158 | goto out; | ||
159 | } | ||
160 | /* Key handle contains PEM encoded private key */ | ||
161 | if (!PEM_write_bio_ECPrivateKey(bio, key, NULL, NULL, 0, NULL, NULL)) { | ||
162 | skdebug(__func__, "PEM_write_bio_ECPrivateKey failed"); | ||
163 | goto out; | ||
164 | } | ||
165 | if ((privlen = BIO_get_mem_data(bio, &privptr)) <= 0) { | ||
166 | skdebug(__func__, "BIO_get_mem_data failed"); | ||
167 | goto out; | ||
168 | } | ||
169 | if ((response->key_handle = malloc(privlen)) == NULL) { | ||
170 | skdebug(__func__, "malloc key_handle failed"); | ||
171 | goto out; | ||
172 | } | ||
173 | response->key_handle_len = (size_t)privlen; | ||
174 | memcpy(response->key_handle, privptr, response->key_handle_len); | ||
175 | /* success */ | ||
176 | ret = 0; | ||
177 | out: | ||
178 | if (ret != 0) { | ||
179 | if (response->public_key != NULL) { | ||
180 | memset(response->public_key, 0, | ||
181 | response->public_key_len); | ||
182 | free(response->public_key); | ||
183 | response->public_key = NULL; | ||
184 | } | ||
185 | if (response->key_handle != NULL) { | ||
186 | memset(response->key_handle, 0, | ||
187 | response->key_handle_len); | ||
188 | free(response->key_handle); | ||
189 | response->key_handle = NULL; | ||
190 | } | ||
191 | } | ||
192 | BIO_free(bio); | ||
193 | EC_KEY_free(key); | ||
194 | return ret; | ||
195 | } | ||
196 | |||
197 | static int | ||
198 | pack_key_ed25519(struct sk_enroll_response *response) | ||
199 | { | ||
200 | int ret = -1; | ||
201 | u_char pk[crypto_sign_ed25519_PUBLICKEYBYTES]; | ||
202 | u_char sk[crypto_sign_ed25519_SECRETKEYBYTES]; | ||
203 | |||
204 | response->public_key = NULL; | ||
205 | response->public_key_len = 0; | ||
206 | response->key_handle = NULL; | ||
207 | response->key_handle_len = 0; | ||
208 | |||
209 | memset(pk, 0, sizeof(pk)); | ||
210 | memset(sk, 0, sizeof(sk)); | ||
211 | crypto_sign_ed25519_keypair(pk, sk); | ||
212 | |||
213 | response->public_key_len = sizeof(pk); | ||
214 | if ((response->public_key = malloc(response->public_key_len)) == NULL) { | ||
215 | skdebug(__func__, "malloc pubkey failed"); | ||
216 | goto out; | ||
217 | } | ||
218 | memcpy(response->public_key, pk, sizeof(pk)); | ||
219 | /* Key handle contains sk */ | ||
220 | response->key_handle_len = sizeof(sk); | ||
221 | if ((response->key_handle = malloc(response->key_handle_len)) == NULL) { | ||
222 | skdebug(__func__, "malloc key_handle failed"); | ||
223 | goto out; | ||
224 | } | ||
225 | memcpy(response->key_handle, sk, sizeof(sk)); | ||
226 | /* success */ | ||
227 | ret = 0; | ||
228 | out: | ||
229 | if (ret != 0) | ||
230 | free(response->public_key); | ||
231 | return ret; | ||
232 | } | ||
233 | |||
234 | int | ||
235 | sk_enroll(int alg, const uint8_t *challenge, size_t challenge_len, | ||
236 | const char *application, uint8_t flags, | ||
237 | struct sk_enroll_response **enroll_response) | ||
238 | { | ||
239 | struct sk_enroll_response *response = NULL; | ||
240 | int ret = -1; | ||
241 | |||
242 | (void)flags; /* XXX; unused */ | ||
243 | |||
244 | if (enroll_response == NULL) { | ||
245 | skdebug(__func__, "enroll_response == NULL"); | ||
246 | goto out; | ||
247 | } | ||
248 | *enroll_response = NULL; | ||
249 | if ((response = calloc(1, sizeof(*response))) == NULL) { | ||
250 | skdebug(__func__, "calloc response failed"); | ||
251 | goto out; | ||
252 | } | ||
253 | switch(alg) { | ||
254 | case SK_ECDSA: | ||
255 | if (pack_key_ecdsa(response) != 0) | ||
256 | goto out; | ||
257 | break; | ||
258 | case SK_ED25519: | ||
259 | if (pack_key_ed25519(response) != 0) | ||
260 | goto out; | ||
261 | break; | ||
262 | default: | ||
263 | skdebug(__func__, "unsupported key type %d", alg); | ||
264 | return -1; | ||
265 | } | ||
266 | /* Have to return something here */ | ||
267 | if ((response->signature = calloc(1, 1)) == NULL) { | ||
268 | skdebug(__func__, "calloc signature failed"); | ||
269 | goto out; | ||
270 | } | ||
271 | response->signature_len = 0; | ||
272 | |||
273 | *enroll_response = response; | ||
274 | response = NULL; | ||
275 | ret = 0; | ||
276 | out: | ||
277 | if (response != NULL) { | ||
278 | free(response->public_key); | ||
279 | free(response->key_handle); | ||
280 | free(response->signature); | ||
281 | free(response->attestation_cert); | ||
282 | free(response); | ||
283 | } | ||
284 | return ret; | ||
285 | } | ||
286 | |||
287 | static void | ||
288 | dump(const char *preamble, const void *sv, size_t l) | ||
289 | { | ||
290 | #ifdef SK_DEBUG | ||
291 | const u_char *s = (const u_char *)sv; | ||
292 | size_t i; | ||
293 | |||
294 | fprintf(stderr, "%s (len %zu):\n", preamble, l); | ||
295 | for (i = 0; i < l; i++) { | ||
296 | if (i % 16 == 0) | ||
297 | fprintf(stderr, "%04zu: ", i); | ||
298 | fprintf(stderr, "%02x", s[i]); | ||
299 | if (i % 16 == 15 || i == l - 1) | ||
300 | fprintf(stderr, "\n"); | ||
301 | } | ||
302 | #endif | ||
303 | } | ||
304 | |||
305 | static int | ||
306 | sig_ecdsa(const uint8_t *message, size_t message_len, | ||
307 | const char *application, uint32_t counter, uint8_t flags, | ||
308 | const uint8_t *key_handle, size_t key_handle_len, | ||
309 | struct sk_sign_response *response) | ||
310 | { | ||
311 | ECDSA_SIG *sig = NULL; | ||
312 | const BIGNUM *sig_r, *sig_s; | ||
313 | int ret = -1; | ||
314 | BIO *bio = NULL; | ||
315 | EVP_PKEY *pk = NULL; | ||
316 | EC_KEY *ec = NULL; | ||
317 | SHA256_CTX ctx; | ||
318 | uint8_t apphash[SHA256_DIGEST_LENGTH]; | ||
319 | uint8_t sighash[SHA256_DIGEST_LENGTH]; | ||
320 | uint8_t countbuf[4]; | ||
321 | |||
322 | /* Decode EC_KEY from key handle */ | ||
323 | if ((bio = BIO_new(BIO_s_mem())) == NULL || | ||
324 | BIO_write(bio, key_handle, key_handle_len) != (int)key_handle_len) { | ||
325 | skdebug(__func__, "BIO setup failed"); | ||
326 | goto out; | ||
327 | } | ||
328 | if ((pk = PEM_read_bio_PrivateKey(bio, NULL, NULL, "")) == NULL) { | ||
329 | skdebug(__func__, "PEM_read_bio_PrivateKey failed"); | ||
330 | goto out; | ||
331 | } | ||
332 | if (EVP_PKEY_base_id(pk) != EVP_PKEY_EC) { | ||
333 | skdebug(__func__, "Not an EC key: %d", EVP_PKEY_base_id(pk)); | ||
334 | goto out; | ||
335 | } | ||
336 | if ((ec = EVP_PKEY_get1_EC_KEY(pk)) == NULL) { | ||
337 | skdebug(__func__, "EVP_PKEY_get1_EC_KEY failed"); | ||
338 | goto out; | ||
339 | } | ||
340 | /* Expect message to be pre-hashed */ | ||
341 | if (message_len != SHA256_DIGEST_LENGTH) { | ||
342 | skdebug(__func__, "bad message len %zu", message_len); | ||
343 | goto out; | ||
344 | } | ||
345 | /* Prepare data to be signed */ | ||
346 | dump("message", message, message_len); | ||
347 | SHA256_Init(&ctx); | ||
348 | SHA256_Update(&ctx, application, strlen(application)); | ||
349 | SHA256_Final(apphash, &ctx); | ||
350 | dump("apphash", apphash, sizeof(apphash)); | ||
351 | countbuf[0] = (counter >> 24) & 0xff; | ||
352 | countbuf[1] = (counter >> 16) & 0xff; | ||
353 | countbuf[2] = (counter >> 8) & 0xff; | ||
354 | countbuf[3] = counter & 0xff; | ||
355 | dump("countbuf", countbuf, sizeof(countbuf)); | ||
356 | dump("flags", &flags, sizeof(flags)); | ||
357 | SHA256_Init(&ctx); | ||
358 | SHA256_Update(&ctx, apphash, sizeof(apphash)); | ||
359 | SHA256_Update(&ctx, &flags, sizeof(flags)); | ||
360 | SHA256_Update(&ctx, countbuf, sizeof(countbuf)); | ||
361 | SHA256_Update(&ctx, message, message_len); | ||
362 | SHA256_Final(sighash, &ctx); | ||
363 | dump("sighash", sighash, sizeof(sighash)); | ||
364 | /* create and encode signature */ | ||
365 | if ((sig = ECDSA_do_sign(sighash, sizeof(sighash), ec)) == NULL) { | ||
366 | skdebug(__func__, "ECDSA_do_sign failed"); | ||
367 | goto out; | ||
368 | } | ||
369 | ECDSA_SIG_get0(sig, &sig_r, &sig_s); | ||
370 | response->sig_r_len = BN_num_bytes(sig_r); | ||
371 | response->sig_s_len = BN_num_bytes(sig_s); | ||
372 | if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL || | ||
373 | (response->sig_s = calloc(1, response->sig_s_len)) == NULL) { | ||
374 | skdebug(__func__, "calloc signature failed"); | ||
375 | goto out; | ||
376 | } | ||
377 | BN_bn2bin(sig_r, response->sig_r); | ||
378 | BN_bn2bin(sig_s, response->sig_s); | ||
379 | ret = 0; | ||
380 | out: | ||
381 | explicit_bzero(&ctx, sizeof(ctx)); | ||
382 | explicit_bzero(&apphash, sizeof(apphash)); | ||
383 | explicit_bzero(&sighash, sizeof(sighash)); | ||
384 | ECDSA_SIG_free(sig); | ||
385 | if (ret != 0) { | ||
386 | free(response->sig_r); | ||
387 | free(response->sig_s); | ||
388 | response->sig_r = NULL; | ||
389 | response->sig_s = NULL; | ||
390 | } | ||
391 | BIO_free(bio); | ||
392 | EC_KEY_free(ec); | ||
393 | EVP_PKEY_free(pk); | ||
394 | return ret; | ||
395 | } | ||
396 | |||
397 | static int | ||
398 | sig_ed25519(const uint8_t *message, size_t message_len, | ||
399 | const char *application, uint32_t counter, uint8_t flags, | ||
400 | const uint8_t *key_handle, size_t key_handle_len, | ||
401 | struct sk_sign_response *response) | ||
402 | { | ||
403 | size_t o; | ||
404 | int ret = -1; | ||
405 | SHA256_CTX ctx; | ||
406 | uint8_t apphash[SHA256_DIGEST_LENGTH]; | ||
407 | uint8_t signbuf[sizeof(apphash) + sizeof(flags) + | ||
408 | sizeof(counter) + SHA256_DIGEST_LENGTH]; | ||
409 | uint8_t sig[crypto_sign_ed25519_BYTES + sizeof(signbuf)]; | ||
410 | unsigned long long smlen; | ||
411 | |||
412 | if (key_handle_len != crypto_sign_ed25519_SECRETKEYBYTES) { | ||
413 | skdebug(__func__, "bad key handle length %zu", key_handle_len); | ||
414 | goto out; | ||
415 | } | ||
416 | /* Expect message to be pre-hashed */ | ||
417 | if (message_len != SHA256_DIGEST_LENGTH) { | ||
418 | skdebug(__func__, "bad message len %zu", message_len); | ||
419 | goto out; | ||
420 | } | ||
421 | /* Prepare data to be signed */ | ||
422 | dump("message", message, message_len); | ||
423 | SHA256_Init(&ctx); | ||
424 | SHA256_Update(&ctx, application, strlen(application)); | ||
425 | SHA256_Final(apphash, &ctx); | ||
426 | dump("apphash", apphash, sizeof(apphash)); | ||
427 | |||
428 | memcpy(signbuf, apphash, sizeof(apphash)); | ||
429 | o = sizeof(apphash); | ||
430 | signbuf[o++] = flags; | ||
431 | signbuf[o++] = (counter >> 24) & 0xff; | ||
432 | signbuf[o++] = (counter >> 16) & 0xff; | ||
433 | signbuf[o++] = (counter >> 8) & 0xff; | ||
434 | signbuf[o++] = counter & 0xff; | ||
435 | memcpy(signbuf + o, message, message_len); | ||
436 | o += message_len; | ||
437 | if (o != sizeof(signbuf)) { | ||
438 | skdebug(__func__, "bad sign buf len %zu, expected %zu", | ||
439 | o, sizeof(signbuf)); | ||
440 | goto out; | ||
441 | } | ||
442 | dump("signbuf", signbuf, sizeof(signbuf)); | ||
443 | /* create and encode signature */ | ||
444 | smlen = sizeof(signbuf); | ||
445 | if (crypto_sign_ed25519(sig, &smlen, signbuf, sizeof(signbuf), | ||
446 | key_handle) != 0) { | ||
447 | skdebug(__func__, "crypto_sign_ed25519 failed"); | ||
448 | goto out; | ||
449 | } | ||
450 | if (smlen <= sizeof(signbuf)) { | ||
451 | skdebug(__func__, "bad sign smlen %llu, expected min %zu", | ||
452 | smlen, sizeof(signbuf) + 1); | ||
453 | goto out; | ||
454 | } | ||
455 | response->sig_r_len = (size_t)(smlen - sizeof(signbuf)); | ||
456 | if ((response->sig_r = calloc(1, response->sig_r_len)) == NULL) { | ||
457 | skdebug(__func__, "calloc signature failed"); | ||
458 | goto out; | ||
459 | } | ||
460 | memcpy(response->sig_r, sig, response->sig_r_len); | ||
461 | dump("sig_r", response->sig_r, response->sig_r_len); | ||
462 | ret = 0; | ||
463 | out: | ||
464 | explicit_bzero(&ctx, sizeof(ctx)); | ||
465 | explicit_bzero(&apphash, sizeof(apphash)); | ||
466 | explicit_bzero(&signbuf, sizeof(signbuf)); | ||
467 | explicit_bzero(&sig, sizeof(sig)); | ||
468 | if (ret != 0) { | ||
469 | free(response->sig_r); | ||
470 | response->sig_r = NULL; | ||
471 | } | ||
472 | return ret; | ||
473 | } | ||
474 | |||
475 | int | ||
476 | sk_sign(int alg, const uint8_t *message, size_t message_len, | ||
477 | const char *application, | ||
478 | const uint8_t *key_handle, size_t key_handle_len, | ||
479 | uint8_t flags, struct sk_sign_response **sign_response) | ||
480 | { | ||
481 | struct sk_sign_response *response = NULL; | ||
482 | int ret = -1; | ||
483 | |||
484 | if (sign_response == NULL) { | ||
485 | skdebug(__func__, "sign_response == NULL"); | ||
486 | goto out; | ||
487 | } | ||
488 | *sign_response = NULL; | ||
489 | if ((response = calloc(1, sizeof(*response))) == NULL) { | ||
490 | skdebug(__func__, "calloc response failed"); | ||
491 | goto out; | ||
492 | } | ||
493 | response->flags = flags; | ||
494 | response->counter = 0x12345678; | ||
495 | switch(alg) { | ||
496 | case SK_ECDSA: | ||
497 | if (sig_ecdsa(message, message_len, application, | ||
498 | response->counter, flags, key_handle, key_handle_len, | ||
499 | response) != 0) | ||
500 | goto out; | ||
501 | break; | ||
502 | case SK_ED25519: | ||
503 | if (sig_ed25519(message, message_len, application, | ||
504 | response->counter, flags, key_handle, key_handle_len, | ||
505 | response) != 0) | ||
506 | goto out; | ||
507 | break; | ||
508 | default: | ||
509 | skdebug(__func__, "unsupported key type %d", alg); | ||
510 | return -1; | ||
511 | } | ||
512 | *sign_response = response; | ||
513 | response = NULL; | ||
514 | ret = 0; | ||
515 | out: | ||
516 | if (response != NULL) { | ||
517 | free(response->sig_r); | ||
518 | free(response->sig_s); | ||
519 | free(response); | ||
520 | } | ||
521 | return ret; | ||
522 | } | ||