/src/bind9/lib/dns/openssleddsa_link.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) Internet Systems Consortium, Inc. ("ISC") |
3 | | * |
4 | | * SPDX-License-Identifier: MPL-2.0 |
5 | | * |
6 | | * This Source Code Form is subject to the terms of the Mozilla Public |
7 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
8 | | * file, you can obtain one at https://mozilla.org/MPL/2.0/. |
9 | | * |
10 | | * See the COPYRIGHT file distributed with this work for additional |
11 | | * information regarding copyright ownership. |
12 | | */ |
13 | | |
14 | | /*! \file */ |
15 | | |
16 | | #include <stdbool.h> |
17 | | |
18 | | #include <openssl/err.h> |
19 | | #include <openssl/evp.h> |
20 | | #include <openssl/objects.h> |
21 | | #include <openssl/x509.h> |
22 | | |
23 | | #include <isc/mem.h> |
24 | | #include <isc/result.h> |
25 | | #include <isc/safe.h> |
26 | | #include <isc/string.h> |
27 | | #include <isc/util.h> |
28 | | |
29 | | #include <dns/keyvalues.h> |
30 | | |
31 | | #include "dst_internal.h" |
32 | | #include "dst_openssl.h" |
33 | | #include "dst_parse.h" |
34 | | #include "openssl_shim.h" |
35 | | |
36 | | #define DST_RET(a) \ |
37 | 0 | { \ |
38 | 0 | ret = a; \ |
39 | 0 | goto err; \ |
40 | 0 | } |
41 | | |
42 | | #ifndef NID_ED25519 |
43 | | #error "Ed25519 group is not known (NID_ED25519)" |
44 | | #endif /* ifndef NID_ED25519 */ |
45 | | |
46 | | #if HAVE_OPENSSL_ED448 |
47 | | #ifndef NID_ED448 |
48 | | #error "Ed448 group is not known (NID_ED448)" |
49 | | #endif /* ifndef NID_ED448 */ |
50 | | #endif /* HAVE_OPENSSL_ED448 */ |
51 | | |
52 | | typedef struct eddsa_alginfo { |
53 | | int pkey_type, nid; |
54 | | unsigned int key_size, sig_size; |
55 | | } eddsa_alginfo_t; |
56 | | |
57 | | static const eddsa_alginfo_t * |
58 | 44 | openssleddsa_alg_info(unsigned int key_alg) { |
59 | 44 | if (key_alg == DST_ALG_ED25519) { |
60 | 22 | static const eddsa_alginfo_t ed25519_alginfo = { |
61 | 22 | .pkey_type = EVP_PKEY_ED25519, |
62 | 22 | .nid = NID_ED25519, |
63 | 22 | .key_size = DNS_KEY_ED25519SIZE, |
64 | 22 | .sig_size = DNS_SIG_ED25519SIZE, |
65 | 22 | }; |
66 | 22 | return &ed25519_alginfo; |
67 | 22 | } |
68 | 22 | #if HAVE_OPENSSL_ED448 |
69 | 22 | if (key_alg == DST_ALG_ED448) { |
70 | 22 | static const eddsa_alginfo_t ed448_alginfo = { |
71 | 22 | .pkey_type = EVP_PKEY_ED448, |
72 | 22 | .nid = NID_ED448, |
73 | 22 | .key_size = DNS_KEY_ED448SIZE, |
74 | 22 | .sig_size = DNS_SIG_ED448SIZE, |
75 | 22 | }; |
76 | 22 | return &ed448_alginfo; |
77 | 22 | } |
78 | 0 | #endif /* HAVE_OPENSSL_ED448 */ |
79 | 0 | return NULL; |
80 | 22 | } |
81 | | |
82 | | static isc_result_t |
83 | | raw_key_to_ossl(const eddsa_alginfo_t *alginfo, int private, |
84 | 44 | const unsigned char *key, size_t *key_len, EVP_PKEY **pkey) { |
85 | 44 | isc_result_t ret; |
86 | 44 | int pkey_type = alginfo->pkey_type; |
87 | 44 | size_t len = alginfo->key_size; |
88 | | |
89 | 44 | ret = (private ? DST_R_INVALIDPRIVATEKEY : DST_R_INVALIDPUBLICKEY); |
90 | 44 | if (*key_len < len) { |
91 | 0 | return ret; |
92 | 0 | } |
93 | | |
94 | 44 | if (private) { |
95 | 0 | *pkey = EVP_PKEY_new_raw_private_key(pkey_type, NULL, key, len); |
96 | 44 | } else { |
97 | 44 | *pkey = EVP_PKEY_new_raw_public_key(pkey_type, NULL, key, len); |
98 | 44 | } |
99 | 44 | if (*pkey == NULL) { |
100 | 0 | return dst__openssl_toresult(ret); |
101 | 0 | } |
102 | | |
103 | 44 | *key_len = len; |
104 | 44 | return ISC_R_SUCCESS; |
105 | 44 | } |
106 | | |
107 | | static isc_result_t |
108 | | openssleddsa_fromlabel(dst_key_t *key, const char *label, const char *pin); |
109 | | |
110 | | static isc_result_t |
111 | 0 | openssleddsa_createctx(dst_key_t *key, dst_context_t *dctx) { |
112 | 0 | isc_buffer_t *buf = NULL; |
113 | 0 | const eddsa_alginfo_t *alginfo = |
114 | 0 | openssleddsa_alg_info(dctx->key->key_alg); |
115 | |
|
116 | 0 | UNUSED(key); |
117 | 0 | REQUIRE(alginfo != NULL); |
118 | |
|
119 | 0 | isc_buffer_allocate(dctx->mctx, &buf, 64); |
120 | 0 | dctx->ctxdata.generic = buf; |
121 | |
|
122 | 0 | return ISC_R_SUCCESS; |
123 | 0 | } |
124 | | |
125 | | static void |
126 | 0 | openssleddsa_destroyctx(dst_context_t *dctx) { |
127 | 0 | isc_buffer_t *buf = (isc_buffer_t *)dctx->ctxdata.generic; |
128 | 0 | const eddsa_alginfo_t *alginfo = |
129 | 0 | openssleddsa_alg_info(dctx->key->key_alg); |
130 | |
|
131 | 0 | REQUIRE(alginfo != NULL); |
132 | 0 | if (buf != NULL) { |
133 | 0 | isc_buffer_free(&buf); |
134 | 0 | } |
135 | 0 | dctx->ctxdata.generic = NULL; |
136 | 0 | } |
137 | | |
138 | | static isc_result_t |
139 | 0 | openssleddsa_adddata(dst_context_t *dctx, const isc_region_t *data) { |
140 | 0 | isc_buffer_t *buf = (isc_buffer_t *)dctx->ctxdata.generic; |
141 | 0 | isc_buffer_t *nbuf = NULL; |
142 | 0 | isc_region_t r; |
143 | 0 | unsigned int length; |
144 | 0 | isc_result_t result; |
145 | 0 | const eddsa_alginfo_t *alginfo = |
146 | 0 | openssleddsa_alg_info(dctx->key->key_alg); |
147 | |
|
148 | 0 | REQUIRE(alginfo != NULL); |
149 | |
|
150 | 0 | result = isc_buffer_copyregion(buf, data); |
151 | 0 | if (result == ISC_R_SUCCESS) { |
152 | 0 | return ISC_R_SUCCESS; |
153 | 0 | } |
154 | | |
155 | 0 | length = isc_buffer_length(buf) + data->length + 64; |
156 | 0 | isc_buffer_allocate(dctx->mctx, &nbuf, length); |
157 | 0 | isc_buffer_usedregion(buf, &r); |
158 | 0 | (void)isc_buffer_copyregion(nbuf, &r); |
159 | 0 | (void)isc_buffer_copyregion(nbuf, data); |
160 | 0 | isc_buffer_free(&buf); |
161 | 0 | dctx->ctxdata.generic = nbuf; |
162 | |
|
163 | 0 | return ISC_R_SUCCESS; |
164 | 0 | } |
165 | | |
166 | | static isc_result_t |
167 | 0 | openssleddsa_sign(dst_context_t *dctx, isc_buffer_t *sig) { |
168 | 0 | isc_result_t ret; |
169 | 0 | dst_key_t *key = dctx->key; |
170 | 0 | isc_region_t tbsreg; |
171 | 0 | isc_region_t sigreg; |
172 | 0 | EVP_PKEY *pkey = key->keydata.pkeypair.priv; |
173 | 0 | EVP_MD_CTX *ctx = EVP_MD_CTX_new(); |
174 | 0 | isc_buffer_t *buf = (isc_buffer_t *)dctx->ctxdata.generic; |
175 | 0 | const eddsa_alginfo_t *alginfo = openssleddsa_alg_info(key->key_alg); |
176 | 0 | size_t siglen; |
177 | |
|
178 | 0 | REQUIRE(alginfo != NULL); |
179 | |
|
180 | 0 | if (ctx == NULL) { |
181 | 0 | return ISC_R_NOMEMORY; |
182 | 0 | } |
183 | | |
184 | 0 | siglen = alginfo->sig_size; |
185 | 0 | isc_buffer_availableregion(sig, &sigreg); |
186 | 0 | if (sigreg.length < (unsigned int)siglen) { |
187 | 0 | DST_RET(ISC_R_NOSPACE); |
188 | 0 | } |
189 | | |
190 | 0 | isc_buffer_usedregion(buf, &tbsreg); |
191 | |
|
192 | 0 | if (EVP_DigestSignInit(ctx, NULL, NULL, NULL, pkey) != 1) { |
193 | 0 | DST_RET(dst__openssl_toresult3( |
194 | 0 | dctx->category, "EVP_DigestSignInit", ISC_R_FAILURE)); |
195 | 0 | } |
196 | 0 | if (EVP_DigestSign(ctx, sigreg.base, &siglen, tbsreg.base, |
197 | 0 | tbsreg.length) != 1) |
198 | 0 | { |
199 | 0 | DST_RET(dst__openssl_toresult3(dctx->category, "EVP_DigestSign", |
200 | 0 | DST_R_SIGNFAILURE)); |
201 | 0 | } |
202 | 0 | isc_buffer_add(sig, (unsigned int)siglen); |
203 | 0 | ret = ISC_R_SUCCESS; |
204 | |
|
205 | 0 | err: |
206 | 0 | EVP_MD_CTX_free(ctx); |
207 | 0 | isc_buffer_free(&buf); |
208 | 0 | dctx->ctxdata.generic = NULL; |
209 | |
|
210 | 0 | return ret; |
211 | 0 | } |
212 | | |
213 | | static isc_result_t |
214 | 0 | openssleddsa_verify(dst_context_t *dctx, const isc_region_t *sig) { |
215 | 0 | isc_result_t ret; |
216 | 0 | dst_key_t *key = dctx->key; |
217 | 0 | int status; |
218 | 0 | isc_region_t tbsreg; |
219 | 0 | EVP_PKEY *pkey = key->keydata.pkeypair.pub; |
220 | 0 | EVP_MD_CTX *ctx = EVP_MD_CTX_new(); |
221 | 0 | isc_buffer_t *buf = (isc_buffer_t *)dctx->ctxdata.generic; |
222 | 0 | const eddsa_alginfo_t *alginfo = openssleddsa_alg_info(key->key_alg); |
223 | |
|
224 | 0 | REQUIRE(alginfo != NULL); |
225 | |
|
226 | 0 | if (ctx == NULL) { |
227 | 0 | return dst__openssl_toresult(ISC_R_NOMEMORY); |
228 | 0 | } |
229 | | |
230 | 0 | if (sig->length != alginfo->sig_size) { |
231 | 0 | DST_RET(DST_R_VERIFYFAILURE); |
232 | 0 | } |
233 | | |
234 | 0 | isc_buffer_usedregion(buf, &tbsreg); |
235 | |
|
236 | 0 | if (EVP_DigestVerifyInit(ctx, NULL, NULL, NULL, pkey) != 1) { |
237 | 0 | DST_RET(dst__openssl_toresult3( |
238 | 0 | dctx->category, "EVP_DigestVerifyInit", ISC_R_FAILURE)); |
239 | 0 | } |
240 | | |
241 | 0 | status = EVP_DigestVerify(ctx, sig->base, sig->length, tbsreg.base, |
242 | 0 | tbsreg.length); |
243 | |
|
244 | 0 | switch (status) { |
245 | 0 | case 1: |
246 | 0 | ret = ISC_R_SUCCESS; |
247 | 0 | break; |
248 | 0 | case 0: |
249 | 0 | ret = dst__openssl_toresult(DST_R_VERIFYFAILURE); |
250 | 0 | break; |
251 | 0 | default: |
252 | 0 | ret = dst__openssl_toresult3(dctx->category, "EVP_DigestVerify", |
253 | 0 | DST_R_VERIFYFAILURE); |
254 | 0 | break; |
255 | 0 | } |
256 | | |
257 | 0 | err: |
258 | 0 | EVP_MD_CTX_free(ctx); |
259 | 0 | isc_buffer_free(&buf); |
260 | 0 | dctx->ctxdata.generic = NULL; |
261 | |
|
262 | 0 | return ret; |
263 | 0 | } |
264 | | |
265 | | static isc_result_t |
266 | 0 | openssleddsa_generate(dst_key_t *key, int unused, void (*callback)(int)) { |
267 | 0 | isc_result_t ret; |
268 | 0 | EVP_PKEY *pkey = NULL; |
269 | 0 | EVP_PKEY_CTX *ctx = NULL; |
270 | 0 | const eddsa_alginfo_t *alginfo = openssleddsa_alg_info(key->key_alg); |
271 | 0 | int status; |
272 | |
|
273 | 0 | REQUIRE(alginfo != NULL); |
274 | 0 | UNUSED(unused); |
275 | 0 | UNUSED(callback); |
276 | |
|
277 | 0 | ctx = EVP_PKEY_CTX_new_id(alginfo->nid, NULL); |
278 | 0 | if (ctx == NULL) { |
279 | 0 | return dst__openssl_toresult2("EVP_PKEY_CTX_new_id", |
280 | 0 | DST_R_OPENSSLFAILURE); |
281 | 0 | } |
282 | | |
283 | 0 | status = EVP_PKEY_keygen_init(ctx); |
284 | 0 | if (status != 1) { |
285 | 0 | DST_RET(dst__openssl_toresult2("EVP_PKEY_keygen_init", |
286 | 0 | DST_R_OPENSSLFAILURE)); |
287 | 0 | } |
288 | | |
289 | 0 | status = EVP_PKEY_keygen(ctx, &pkey); |
290 | 0 | if (status != 1) { |
291 | 0 | DST_RET(dst__openssl_toresult2("EVP_PKEY_keygen", |
292 | 0 | DST_R_OPENSSLFAILURE)); |
293 | 0 | } |
294 | | |
295 | 0 | key->key_size = alginfo->key_size * 8; |
296 | 0 | key->keydata.pkeypair.priv = pkey; |
297 | 0 | key->keydata.pkeypair.pub = pkey; |
298 | 0 | ret = ISC_R_SUCCESS; |
299 | |
|
300 | 0 | err: |
301 | 0 | EVP_PKEY_CTX_free(ctx); |
302 | 0 | return ret; |
303 | 0 | } |
304 | | |
305 | | static isc_result_t |
306 | 0 | openssleddsa_todns(const dst_key_t *key, isc_buffer_t *data) { |
307 | 0 | const eddsa_alginfo_t *alginfo = openssleddsa_alg_info(key->key_alg); |
308 | 0 | EVP_PKEY *pkey = key->keydata.pkeypair.pub; |
309 | 0 | isc_region_t r; |
310 | 0 | size_t len; |
311 | |
|
312 | 0 | REQUIRE(pkey != NULL); |
313 | 0 | REQUIRE(alginfo != NULL); |
314 | |
|
315 | 0 | len = alginfo->key_size; |
316 | 0 | isc_buffer_availableregion(data, &r); |
317 | 0 | if (r.length < len) { |
318 | 0 | return ISC_R_NOSPACE; |
319 | 0 | } |
320 | | |
321 | 0 | if (EVP_PKEY_get_raw_public_key(pkey, r.base, &len) != 1) { |
322 | 0 | return dst__openssl_toresult(ISC_R_FAILURE); |
323 | 0 | } |
324 | | |
325 | 0 | isc_buffer_add(data, len); |
326 | 0 | return ISC_R_SUCCESS; |
327 | 0 | } |
328 | | |
329 | | static isc_result_t |
330 | 0 | openssleddsa_fromdns(dst_key_t *key, isc_buffer_t *data) { |
331 | 0 | const eddsa_alginfo_t *alginfo = openssleddsa_alg_info(key->key_alg); |
332 | 0 | isc_result_t ret; |
333 | 0 | isc_region_t r; |
334 | 0 | size_t len; |
335 | 0 | EVP_PKEY *pkey = NULL; |
336 | |
|
337 | 0 | REQUIRE(alginfo != NULL); |
338 | |
|
339 | 0 | isc_buffer_remainingregion(data, &r); |
340 | 0 | if (r.length == 0) { |
341 | 0 | return ISC_R_SUCCESS; |
342 | 0 | } |
343 | | |
344 | 0 | len = r.length; |
345 | 0 | ret = raw_key_to_ossl(alginfo, 0, r.base, &len, &pkey); |
346 | 0 | if (ret != ISC_R_SUCCESS) { |
347 | 0 | return ret; |
348 | 0 | } |
349 | | |
350 | 0 | isc_buffer_forward(data, len); |
351 | 0 | key->keydata.pkeypair.pub = pkey; |
352 | 0 | key->key_size = len * 8; |
353 | 0 | return ISC_R_SUCCESS; |
354 | 0 | } |
355 | | |
356 | | static isc_result_t |
357 | 0 | openssleddsa_tofile(const dst_key_t *key, const char *directory) { |
358 | 0 | const eddsa_alginfo_t *alginfo = openssleddsa_alg_info(key->key_alg); |
359 | 0 | isc_result_t ret; |
360 | 0 | dst_private_t priv; |
361 | 0 | unsigned char *buf = NULL; |
362 | 0 | size_t len; |
363 | 0 | int i; |
364 | |
|
365 | 0 | REQUIRE(alginfo != NULL); |
366 | |
|
367 | 0 | if (key->keydata.pkeypair.pub == NULL) { |
368 | 0 | return DST_R_NULLKEY; |
369 | 0 | } |
370 | | |
371 | 0 | if (key->external) { |
372 | 0 | priv.nelements = 0; |
373 | 0 | return dst__privstruct_writefile(key, &priv, directory); |
374 | 0 | } |
375 | | |
376 | 0 | i = 0; |
377 | |
|
378 | 0 | if (dst__openssl_keypair_isprivate(key)) { |
379 | 0 | len = alginfo->key_size; |
380 | 0 | buf = isc_mem_get(key->mctx, len); |
381 | 0 | if (EVP_PKEY_get_raw_private_key(key->keydata.pkeypair.priv, |
382 | 0 | buf, &len) != 1) |
383 | 0 | { |
384 | 0 | DST_RET(dst__openssl_toresult(ISC_R_FAILURE)); |
385 | 0 | } |
386 | 0 | priv.elements[i].tag = TAG_EDDSA_PRIVATEKEY; |
387 | 0 | priv.elements[i].length = len; |
388 | 0 | priv.elements[i].data = buf; |
389 | 0 | i++; |
390 | 0 | } |
391 | 0 | if (key->label != NULL) { |
392 | 0 | priv.elements[i].tag = TAG_EDDSA_LABEL; |
393 | 0 | priv.elements[i].length = (unsigned short)strlen(key->label) + |
394 | 0 | 1; |
395 | 0 | priv.elements[i].data = (unsigned char *)key->label; |
396 | 0 | i++; |
397 | 0 | } |
398 | |
|
399 | 0 | priv.nelements = i; |
400 | 0 | ret = dst__privstruct_writefile(key, &priv, directory); |
401 | |
|
402 | 0 | err: |
403 | 0 | if (buf != NULL) { |
404 | 0 | isc_mem_put(key->mctx, buf, len); |
405 | 0 | } |
406 | 0 | return ret; |
407 | 0 | } |
408 | | |
409 | | static isc_result_t |
410 | 0 | openssleddsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { |
411 | 0 | const eddsa_alginfo_t *alginfo = openssleddsa_alg_info(key->key_alg); |
412 | 0 | dst_private_t priv; |
413 | 0 | isc_result_t ret; |
414 | 0 | int i, privkey_index = -1; |
415 | 0 | const char *label = NULL; |
416 | 0 | EVP_PKEY *pkey = NULL; |
417 | 0 | size_t len; |
418 | 0 | isc_mem_t *mctx = key->mctx; |
419 | |
|
420 | 0 | REQUIRE(alginfo != NULL); |
421 | | |
422 | | /* read private key file */ |
423 | 0 | ret = dst__privstruct_parse(key, DST_ALG_ED25519, lexer, mctx, &priv); |
424 | 0 | if (ret != ISC_R_SUCCESS) { |
425 | 0 | goto err; |
426 | 0 | } |
427 | | |
428 | 0 | if (key->external) { |
429 | 0 | if (priv.nelements != 0) { |
430 | 0 | DST_RET(DST_R_INVALIDPRIVATEKEY); |
431 | 0 | } |
432 | 0 | if (pub == NULL) { |
433 | 0 | DST_RET(DST_R_INVALIDPRIVATEKEY); |
434 | 0 | } |
435 | 0 | key->keydata.pkeypair.priv = pub->keydata.pkeypair.priv; |
436 | 0 | key->keydata.pkeypair.pub = pub->keydata.pkeypair.pub; |
437 | 0 | pub->keydata.pkeypair.priv = NULL; |
438 | 0 | pub->keydata.pkeypair.pub = NULL; |
439 | 0 | DST_RET(ISC_R_SUCCESS); |
440 | 0 | } |
441 | | |
442 | 0 | for (i = 0; i < priv.nelements; i++) { |
443 | 0 | switch (priv.elements[i].tag) { |
444 | 0 | case TAG_EDDSA_ENGINE: |
445 | | /* The Engine: tag is explicitly ignored */ |
446 | 0 | break; |
447 | 0 | case TAG_EDDSA_LABEL: |
448 | 0 | label = (char *)priv.elements[i].data; |
449 | 0 | break; |
450 | 0 | case TAG_EDDSA_PRIVATEKEY: |
451 | 0 | privkey_index = i; |
452 | 0 | break; |
453 | 0 | default: |
454 | 0 | break; |
455 | 0 | } |
456 | 0 | } |
457 | | |
458 | 0 | if (label != NULL) { |
459 | 0 | ret = openssleddsa_fromlabel(key, label, NULL); |
460 | 0 | if (ret != ISC_R_SUCCESS) { |
461 | 0 | goto err; |
462 | 0 | } |
463 | | /* Check that the public component matches if given */ |
464 | 0 | if (pub != NULL && EVP_PKEY_eq(key->keydata.pkeypair.pub, |
465 | 0 | pub->keydata.pkeypair.pub) != 1) |
466 | 0 | { |
467 | 0 | DST_RET(DST_R_INVALIDPRIVATEKEY); |
468 | 0 | } |
469 | 0 | DST_RET(ISC_R_SUCCESS); |
470 | 0 | } |
471 | | |
472 | 0 | if (privkey_index < 0) { |
473 | 0 | DST_RET(DST_R_INVALIDPRIVATEKEY); |
474 | 0 | } |
475 | | |
476 | 0 | len = priv.elements[privkey_index].length; |
477 | 0 | ret = raw_key_to_ossl(alginfo, 1, priv.elements[privkey_index].data, |
478 | 0 | &len, &pkey); |
479 | 0 | if (ret != ISC_R_SUCCESS) { |
480 | 0 | goto err; |
481 | 0 | } |
482 | | /* Check that the public component matches if given */ |
483 | 0 | if (pub != NULL && EVP_PKEY_eq(pkey, pub->keydata.pkeypair.pub) != 1) { |
484 | 0 | DST_RET(DST_R_INVALIDPRIVATEKEY); |
485 | 0 | } |
486 | | |
487 | 0 | key->keydata.pkeypair.priv = pkey; |
488 | 0 | key->keydata.pkeypair.pub = pkey; |
489 | 0 | key->key_size = len * 8; |
490 | 0 | pkey = NULL; |
491 | 0 | ret = ISC_R_SUCCESS; |
492 | |
|
493 | 0 | err: |
494 | 0 | EVP_PKEY_free(pkey); |
495 | 0 | dst__privstruct_free(&priv, mctx); |
496 | 0 | isc_safe_memwipe(&priv, sizeof(priv)); |
497 | 0 | return ret; |
498 | 0 | } |
499 | | |
500 | | static isc_result_t |
501 | 0 | openssleddsa_fromlabel(dst_key_t *key, const char *label, const char *pin) { |
502 | 0 | const eddsa_alginfo_t *alginfo = openssleddsa_alg_info(key->key_alg); |
503 | 0 | EVP_PKEY *privpkey = NULL, *pubpkey = NULL; |
504 | 0 | isc_result_t ret; |
505 | |
|
506 | 0 | REQUIRE(alginfo != NULL); |
507 | 0 | UNUSED(pin); |
508 | |
|
509 | 0 | ret = dst__openssl_fromlabel(alginfo->pkey_type, label, pin, &pubpkey, |
510 | 0 | &privpkey); |
511 | 0 | if (ret != ISC_R_SUCCESS) { |
512 | 0 | goto err; |
513 | 0 | } |
514 | | |
515 | 0 | key->label = isc_mem_strdup(key->mctx, label); |
516 | 0 | key->key_size = EVP_PKEY_bits(privpkey); |
517 | 0 | key->keydata.pkeypair.priv = privpkey; |
518 | 0 | key->keydata.pkeypair.pub = pubpkey; |
519 | 0 | privpkey = NULL; |
520 | 0 | pubpkey = NULL; |
521 | |
|
522 | 0 | err: |
523 | 0 | EVP_PKEY_free(privpkey); |
524 | 0 | EVP_PKEY_free(pubpkey); |
525 | 0 | return ret; |
526 | 0 | } |
527 | | |
528 | | static dst_func_t openssleddsa_functions = { |
529 | | .createctx = openssleddsa_createctx, |
530 | | .destroyctx = openssleddsa_destroyctx, |
531 | | .adddata = openssleddsa_adddata, |
532 | | .sign = openssleddsa_sign, |
533 | | .verify = openssleddsa_verify, |
534 | | .compare = dst__openssl_keypair_compare, |
535 | | .generate = openssleddsa_generate, |
536 | | .isprivate = dst__openssl_keypair_isprivate, |
537 | | .destroy = dst__openssl_keypair_destroy, |
538 | | .todns = openssleddsa_todns, |
539 | | .fromdns = openssleddsa_fromdns, |
540 | | .tofile = openssleddsa_tofile, |
541 | | .parse = openssleddsa_parse, |
542 | | .fromlabel = openssleddsa_fromlabel, |
543 | | }; |
544 | | |
545 | | /* |
546 | | * The test vectors below where generated by util/gen-eddsa-vectors.c |
547 | | */ |
548 | | #if HAVE_OPENSSL_ED448 |
549 | | static unsigned char ed448_pub[] = |
550 | | "\x0a\x19\x36\xf0\x4c\x2d\xc1\xfe\xbe\xdc\xfa\xf6\xeb\xd2\x8f\x3b\x04" |
551 | | "\x14\x2e\x88\xc6\xb5\xdc\xe8\x2a\xc6\xb9\x7c\xa8\x22\xe8\x36\xfb\x06" |
552 | | "\x55\xa3\x3c\xdb\x9d\x68\x59\x7e\xa9\x5f\x93\x96\x87\x83\x28\xce\xdd" |
553 | | "\x12\xc9\xb8\x78\x02\x80"; |
554 | | static unsigned char ed448_sig[] = |
555 | | "\x7e\xec\x4e\x11\xd9\x79\x89\xd2\xe2\x85\x7a\x1c\xd7\x36\xe8\x24\x1f" |
556 | | "\x90\xa0\x9c\x84\xfb\x51\xcd\xdc\xfd\x05\xcd\x8c\x08\x51\x05\x18\xc8" |
557 | | "\x85\xb2\x28\x00\xea\xfe\x10\x46\xad\x52\xe6\xe9\x62\x35\x3b\x2a\x14" |
558 | | "\x8b\xe7\xf0\x66\x5f\x00\x66\x3c\xa1\x4d\x03\x95\xcc\x73\xfc\xf2\x40" |
559 | | "\x4b\x67\x85\x5b\x9f\xa9\x87\xb6\xbb\xa3\x9d\x73\x9f\xcb\x4e\x2c\xd2" |
560 | | "\x46\xc7\x84\xd3\x7d\x94\x32\x30\x27\xb0\xa7\xf6\x6d\xf4\x77\xe8\xf5" |
561 | | "\xb4\xee\x3f\x0e\x2b\x35\xdd\x5a\x35\xfe\x35\x00"; |
562 | | #endif |
563 | | |
564 | | static unsigned char ed25519_pub[] = |
565 | | "\x66\x5c\x21\x59\xe3\xa0\x6e\xa3\x7d\x82\x7c\xf1\xe7\xa3\xdd\xaf\xd1" |
566 | | "\x6d\x92\x81\xfb\x09\x0c\x7c\xfe\x6d\xf8\x87\x24\x7e\x6e\x25"; |
567 | | static unsigned char ed25519_sig[] = |
568 | | "\x26\x70\x5c\xc1\x85\xb6\x5e\x65\xe5\xa7\xd5\x85\x63\xc9\x1d\x45\x56" |
569 | | "\x38\xa3\x9c\xa3\x42\x4d\xc8\x89\xff\x84\xea\x2c\xa8\x8b\xfa\x2f\xab" |
570 | | "\x75\x7c\x68\x95\xfd\xdf\x62\x60\x4e\x4d\x10\xf8\x3c\xae\xcf\x18\x93" |
571 | | "\x90\x05\xa4\x54\x38\x45\x2f\x81\x71\x1e\x0f\x46\x04"; |
572 | | |
573 | | static isc_result_t |
574 | 44 | check_algorithm(unsigned char algorithm) { |
575 | 44 | EVP_MD_CTX *evp_md_ctx = EVP_MD_CTX_create(); |
576 | 44 | EVP_PKEY *pkey = NULL; |
577 | 44 | const eddsa_alginfo_t *alginfo = NULL; |
578 | 44 | const unsigned char *key = NULL; |
579 | 44 | const unsigned char *sig = NULL; |
580 | 44 | const unsigned char test[] = "test"; |
581 | 44 | isc_result_t ret = ISC_R_SUCCESS; |
582 | 44 | size_t key_len, sig_len; |
583 | | |
584 | 44 | if (evp_md_ctx == NULL) { |
585 | 0 | DST_RET(ISC_R_NOMEMORY); |
586 | 0 | } |
587 | | |
588 | 44 | switch (algorithm) { |
589 | 0 | #if HAVE_OPENSSL_ED448 |
590 | 22 | case DST_ALG_ED448: |
591 | 22 | sig = ed448_sig; |
592 | 22 | sig_len = sizeof(ed448_sig) - 1; |
593 | 22 | key = ed448_pub; |
594 | 22 | key_len = sizeof(ed448_pub) - 1; |
595 | 22 | alginfo = openssleddsa_alg_info(algorithm); |
596 | 22 | break; |
597 | 0 | #endif /* HAVE_OPENSSL_ED448 */ |
598 | 22 | case DST_ALG_ED25519: |
599 | 22 | sig = ed25519_sig; |
600 | 22 | sig_len = sizeof(ed25519_sig) - 1; |
601 | 22 | key = ed25519_pub; |
602 | 22 | key_len = sizeof(ed25519_pub) - 1; |
603 | 22 | alginfo = openssleddsa_alg_info(algorithm); |
604 | 22 | break; |
605 | 0 | default: |
606 | 0 | DST_RET(ISC_R_NOTIMPLEMENTED); |
607 | 44 | } |
608 | | |
609 | 44 | INSIST(alginfo != NULL); |
610 | 44 | ret = raw_key_to_ossl(alginfo, 0, key, &key_len, &pkey); |
611 | 44 | if (ret != ISC_R_SUCCESS) { |
612 | 0 | goto err; |
613 | 0 | } |
614 | | |
615 | | /* |
616 | | * Check that we can verify the signature. |
617 | | */ |
618 | 44 | if (EVP_DigestVerifyInit(evp_md_ctx, NULL, NULL, NULL, pkey) != 1 || |
619 | 44 | EVP_DigestVerify(evp_md_ctx, sig, sig_len, test, |
620 | 44 | sizeof(test) - 1) != 1) |
621 | 0 | { |
622 | 0 | DST_RET(ISC_R_NOTIMPLEMENTED); |
623 | 0 | } |
624 | | |
625 | 44 | err: |
626 | 44 | if (pkey != NULL) { |
627 | 44 | EVP_PKEY_free(pkey); |
628 | 44 | } |
629 | 44 | if (evp_md_ctx != NULL) { |
630 | 44 | EVP_MD_CTX_destroy(evp_md_ctx); |
631 | 44 | } |
632 | 44 | ERR_clear_error(); |
633 | 44 | return ret; |
634 | 44 | } |
635 | | |
636 | | void |
637 | 44 | dst__openssleddsa_init(dst_func_t **funcp, unsigned char algorithm) { |
638 | 44 | REQUIRE(funcp != NULL); |
639 | | |
640 | 44 | if (*funcp == NULL) { |
641 | 44 | if (check_algorithm(algorithm) == ISC_R_SUCCESS) { |
642 | 44 | *funcp = &openssleddsa_functions; |
643 | 44 | } |
644 | 44 | } |
645 | 44 | } |