1243885Serwin/*
2262706Serwin * Copyright (C) 2012-2014  Internet Systems Consortium, Inc. ("ISC")
3243885Serwin *
4243885Serwin * Permission to use, copy, modify, and/or distribute this software for any
5243885Serwin * purpose with or without fee is hereby granted, provided that the above
6243885Serwin * copyright notice and this permission notice appear in all copies.
7243885Serwin *
8243885Serwin * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9243885Serwin * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10243885Serwin * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11243885Serwin * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12243885Serwin * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13243885Serwin * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14243885Serwin * PERFORMANCE OF THIS SOFTWARE.
15243885Serwin */
16243885Serwin
17243885Serwin#include <config.h>
18243885Serwin
19243885Serwin#ifdef HAVE_OPENSSL_ECDSA
20243885Serwin
21243885Serwin#if !defined(HAVE_EVP_SHA256) || !defined(HAVE_EVP_SHA384)
22243885Serwin#error "ECDSA without EVP for SHA2?"
23243885Serwin#endif
24243885Serwin
25243885Serwin#include <isc/entropy.h>
26243885Serwin#include <isc/mem.h>
27243885Serwin#include <isc/sha2.h>
28243885Serwin#include <isc/string.h>
29243885Serwin#include <isc/util.h>
30243885Serwin
31243885Serwin#include <dns/keyvalues.h>
32243885Serwin#include <dst/result.h>
33243885Serwin
34243885Serwin#include "dst_internal.h"
35243885Serwin#include "dst_openssl.h"
36243885Serwin#include "dst_parse.h"
37243885Serwin
38243885Serwin#include <openssl/err.h>
39243885Serwin#include <openssl/objects.h>
40243885Serwin#include <openssl/ecdsa.h>
41243885Serwin#include <openssl/bn.h>
42243885Serwin
43243885Serwin#ifndef NID_X9_62_prime256v1
44243885Serwin#error "P-256 group is not known (NID_X9_62_prime256v1)"
45243885Serwin#endif
46243885Serwin#ifndef NID_secp384r1
47243885Serwin#error "P-384 group is not known (NID_secp384r1)"
48243885Serwin#endif
49243885Serwin
50243885Serwin#define DST_RET(a) {ret = a; goto err;}
51243885Serwin
52243885Serwinstatic isc_result_t opensslecdsa_todns(const dst_key_t *key,
53243885Serwin				       isc_buffer_t *data);
54243885Serwin
55243885Serwinstatic isc_result_t
56243885Serwinopensslecdsa_createctx(dst_key_t *key, dst_context_t *dctx) {
57243885Serwin	EVP_MD_CTX *evp_md_ctx;
58243885Serwin	const EVP_MD *type = NULL;
59243885Serwin
60243885Serwin	UNUSED(key);
61243885Serwin	REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
62243885Serwin		dctx->key->key_alg == DST_ALG_ECDSA384);
63243885Serwin
64243885Serwin	evp_md_ctx = EVP_MD_CTX_create();
65243885Serwin	if (evp_md_ctx == NULL)
66243885Serwin		return (ISC_R_NOMEMORY);
67243885Serwin	if (dctx->key->key_alg == DST_ALG_ECDSA256)
68243885Serwin		type = EVP_sha256();
69243885Serwin	else
70243885Serwin		type = EVP_sha384();
71243885Serwin
72243885Serwin	if (!EVP_DigestInit_ex(evp_md_ctx, type, NULL)) {
73243885Serwin		EVP_MD_CTX_destroy(evp_md_ctx);
74254402Serwin		return (dst__openssl_toresult3(dctx->category,
75254402Serwin					       "EVP_DigestInit_ex",
76243885Serwin					       ISC_R_FAILURE));
77243885Serwin	}
78243885Serwin
79243885Serwin	dctx->ctxdata.evp_md_ctx = evp_md_ctx;
80243885Serwin
81243885Serwin	return (ISC_R_SUCCESS);
82243885Serwin}
83243885Serwin
84243885Serwinstatic void
85243885Serwinopensslecdsa_destroyctx(dst_context_t *dctx) {
86243885Serwin	EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
87243885Serwin
88243885Serwin	REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
89243885Serwin		dctx->key->key_alg == DST_ALG_ECDSA384);
90243885Serwin
91243885Serwin	if (evp_md_ctx != NULL) {
92243885Serwin		EVP_MD_CTX_destroy(evp_md_ctx);
93243885Serwin		dctx->ctxdata.evp_md_ctx = NULL;
94243885Serwin	}
95243885Serwin}
96243885Serwin
97243885Serwinstatic isc_result_t
98243885Serwinopensslecdsa_adddata(dst_context_t *dctx, const isc_region_t *data) {
99243885Serwin	EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
100243885Serwin
101243885Serwin	REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
102243885Serwin		dctx->key->key_alg == DST_ALG_ECDSA384);
103243885Serwin
104243885Serwin	if (!EVP_DigestUpdate(evp_md_ctx, data->base, data->length))
105254402Serwin		return (dst__openssl_toresult3(dctx->category,
106254402Serwin					       "EVP_DigestUpdate",
107243885Serwin					       ISC_R_FAILURE));
108243885Serwin
109243885Serwin	return (ISC_R_SUCCESS);
110243885Serwin}
111243885Serwin
112243885Serwinstatic int
113243885SerwinBN_bn2bin_fixed(BIGNUM *bn, unsigned char *buf, int size) {
114243885Serwin	int bytes = size - BN_num_bytes(bn);
115243885Serwin
116243885Serwin	while (bytes-- > 0)
117243885Serwin		*buf++ = 0;
118243885Serwin	BN_bn2bin(bn, buf);
119243885Serwin	return (size);
120243885Serwin}
121243885Serwin
122243885Serwinstatic isc_result_t
123243885Serwinopensslecdsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
124243885Serwin	isc_result_t ret;
125243885Serwin	dst_key_t *key = dctx->key;
126243885Serwin	isc_region_t r;
127243885Serwin	ECDSA_SIG *ecdsasig;
128243885Serwin	EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
129243885Serwin	EVP_PKEY *pkey = key->keydata.pkey;
130243885Serwin	EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(pkey);
131243885Serwin	unsigned int dgstlen, siglen;
132243885Serwin	unsigned char digest[EVP_MAX_MD_SIZE];
133243885Serwin
134243885Serwin	REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
135243885Serwin		key->key_alg == DST_ALG_ECDSA384);
136243885Serwin
137243885Serwin	if (eckey == NULL)
138243885Serwin		return (ISC_R_FAILURE);
139243885Serwin
140243885Serwin	if (key->key_alg == DST_ALG_ECDSA256)
141243885Serwin		siglen = DNS_SIG_ECDSA256SIZE;
142243885Serwin	else
143243885Serwin		siglen = DNS_SIG_ECDSA384SIZE;
144243885Serwin
145243885Serwin	isc_buffer_availableregion(sig, &r);
146243885Serwin	if (r.length < siglen)
147243885Serwin		DST_RET(ISC_R_NOSPACE);
148243885Serwin
149243885Serwin	if (!EVP_DigestFinal(evp_md_ctx, digest, &dgstlen))
150254402Serwin		DST_RET(dst__openssl_toresult3(dctx->category,
151254402Serwin					       "EVP_DigestFinal",
152243885Serwin					       ISC_R_FAILURE));
153243885Serwin
154243885Serwin	ecdsasig = ECDSA_do_sign(digest, dgstlen, eckey);
155243885Serwin	if (ecdsasig == NULL)
156254402Serwin		DST_RET(dst__openssl_toresult3(dctx->category,
157254402Serwin					       "ECDSA_do_sign",
158243885Serwin					       DST_R_SIGNFAILURE));
159243885Serwin	BN_bn2bin_fixed(ecdsasig->r, r.base, siglen / 2);
160287410Sdelphij	isc_region_consume(&r, siglen / 2);
161243885Serwin	BN_bn2bin_fixed(ecdsasig->s, r.base, siglen / 2);
162287410Sdelphij	isc_region_consume(&r, siglen / 2);
163243885Serwin	ECDSA_SIG_free(ecdsasig);
164243885Serwin	isc_buffer_add(sig, siglen);
165243885Serwin	ret = ISC_R_SUCCESS;
166243885Serwin
167243885Serwin err:
168243885Serwin	if (eckey != NULL)
169243885Serwin		EC_KEY_free(eckey);
170243885Serwin	return (ret);
171243885Serwin}
172243885Serwin
173243885Serwinstatic isc_result_t
174243885Serwinopensslecdsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
175243885Serwin	isc_result_t ret;
176243885Serwin	dst_key_t *key = dctx->key;
177243885Serwin	int status;
178243885Serwin	unsigned char *cp = sig->base;
179243885Serwin	ECDSA_SIG *ecdsasig = NULL;
180243885Serwin	EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
181243885Serwin	EVP_PKEY *pkey = key->keydata.pkey;
182243885Serwin	EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(pkey);
183243885Serwin	unsigned int dgstlen, siglen;
184243885Serwin	unsigned char digest[EVP_MAX_MD_SIZE];
185243885Serwin
186243885Serwin	REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
187243885Serwin		key->key_alg == DST_ALG_ECDSA384);
188243885Serwin
189243885Serwin	if (eckey == NULL)
190243885Serwin		return (ISC_R_FAILURE);
191243885Serwin
192243885Serwin	if (key->key_alg == DST_ALG_ECDSA256)
193243885Serwin		siglen = DNS_SIG_ECDSA256SIZE;
194243885Serwin	else
195243885Serwin		siglen = DNS_SIG_ECDSA384SIZE;
196243885Serwin
197243885Serwin	if (sig->length != siglen)
198243885Serwin		return (DST_R_VERIFYFAILURE);
199243885Serwin
200243885Serwin	if (!EVP_DigestFinal_ex(evp_md_ctx, digest, &dgstlen))
201254402Serwin		DST_RET (dst__openssl_toresult3(dctx->category,
202254402Serwin						"EVP_DigestFinal_ex",
203243885Serwin						ISC_R_FAILURE));
204243885Serwin
205243885Serwin	ecdsasig = ECDSA_SIG_new();
206243885Serwin	if (ecdsasig == NULL)
207243885Serwin		DST_RET (ISC_R_NOMEMORY);
208254402Serwin	if (ecdsasig->r != NULL)
209254402Serwin		BN_free(ecdsasig->r);
210243885Serwin	ecdsasig->r = BN_bin2bn(cp, siglen / 2, NULL);
211243885Serwin	cp += siglen / 2;
212254402Serwin	if (ecdsasig->s != NULL)
213254402Serwin		BN_free(ecdsasig->s);
214243885Serwin	ecdsasig->s = BN_bin2bn(cp, siglen / 2, NULL);
215243885Serwin	/* cp += siglen / 2; */
216243885Serwin
217243885Serwin	status = ECDSA_do_verify(digest, dgstlen, ecdsasig, eckey);
218243885Serwin	switch (status) {
219243885Serwin	case 1:
220243885Serwin		ret = ISC_R_SUCCESS;
221243885Serwin		break;
222243885Serwin	case 0:
223243885Serwin		ret = dst__openssl_toresult(DST_R_VERIFYFAILURE);
224243885Serwin		break;
225243885Serwin	default:
226254402Serwin		ret = dst__openssl_toresult3(dctx->category,
227254402Serwin					     "ECDSA_do_verify",
228243885Serwin					     DST_R_VERIFYFAILURE);
229243885Serwin		break;
230243885Serwin	}
231243885Serwin
232243885Serwin err:
233243885Serwin	if (ecdsasig != NULL)
234243885Serwin		ECDSA_SIG_free(ecdsasig);
235243885Serwin	if (eckey != NULL)
236243885Serwin		EC_KEY_free(eckey);
237243885Serwin	return (ret);
238243885Serwin}
239243885Serwin
240243885Serwinstatic isc_boolean_t
241243885Serwinopensslecdsa_compare(const dst_key_t *key1, const dst_key_t *key2) {
242243885Serwin	isc_boolean_t ret;
243243885Serwin	int status;
244243885Serwin	EVP_PKEY *pkey1 = key1->keydata.pkey;
245243885Serwin	EVP_PKEY *pkey2 = key2->keydata.pkey;
246243885Serwin	EC_KEY *eckey1 = NULL;
247243885Serwin	EC_KEY *eckey2 = NULL;
248243885Serwin	const BIGNUM *priv1, *priv2;
249243885Serwin
250243885Serwin	if (pkey1 == NULL && pkey2 == NULL)
251243885Serwin		return (ISC_TRUE);
252243885Serwin	else if (pkey1 == NULL || pkey2 == NULL)
253243885Serwin		return (ISC_FALSE);
254243885Serwin
255243885Serwin	eckey1 = EVP_PKEY_get1_EC_KEY(pkey1);
256243885Serwin	eckey2 = EVP_PKEY_get1_EC_KEY(pkey2);
257243885Serwin	if (eckey1 == NULL && eckey2 == NULL) {
258243885Serwin		DST_RET (ISC_TRUE);
259243885Serwin	} else if (eckey1 == NULL || eckey2 == NULL)
260243885Serwin		DST_RET (ISC_FALSE);
261243885Serwin
262243885Serwin	status = EVP_PKEY_cmp(pkey1, pkey2);
263243885Serwin	if (status != 1)
264243885Serwin		DST_RET (ISC_FALSE);
265243885Serwin
266243885Serwin	priv1 = EC_KEY_get0_private_key(eckey1);
267243885Serwin	priv2 = EC_KEY_get0_private_key(eckey2);
268243885Serwin	if (priv1 != NULL || priv2 != NULL) {
269243885Serwin		if (priv1 == NULL || priv2 == NULL)
270243885Serwin			DST_RET (ISC_FALSE);
271243885Serwin		if (BN_cmp(priv1, priv2) != 0)
272243885Serwin			DST_RET (ISC_FALSE);
273243885Serwin	}
274243885Serwin	ret = ISC_TRUE;
275243885Serwin
276243885Serwin err:
277243885Serwin	if (eckey1 != NULL)
278243885Serwin		EC_KEY_free(eckey1);
279243885Serwin	if (eckey2 != NULL)
280243885Serwin		EC_KEY_free(eckey2);
281243885Serwin	return (ret);
282243885Serwin}
283243885Serwin
284243885Serwinstatic isc_result_t
285243885Serwinopensslecdsa_generate(dst_key_t *key, int unused, void (*callback)(int)) {
286243885Serwin	isc_result_t ret;
287243885Serwin	EVP_PKEY *pkey;
288243885Serwin	EC_KEY *eckey = NULL;
289243885Serwin	int group_nid;
290243885Serwin
291243885Serwin	REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
292243885Serwin		key->key_alg == DST_ALG_ECDSA384);
293243885Serwin	UNUSED(unused);
294243885Serwin	UNUSED(callback);
295243885Serwin
296243885Serwin	if (key->key_alg == DST_ALG_ECDSA256)
297243885Serwin		group_nid = NID_X9_62_prime256v1;
298243885Serwin	else
299243885Serwin		group_nid = NID_secp384r1;
300243885Serwin
301243885Serwin	eckey = EC_KEY_new_by_curve_name(group_nid);
302243885Serwin	if (eckey == NULL)
303243885Serwin		return (dst__openssl_toresult2("EC_KEY_new_by_curve_name",
304243885Serwin					       DST_R_OPENSSLFAILURE));
305243885Serwin
306243885Serwin	if (EC_KEY_generate_key(eckey) != 1)
307243885Serwin		DST_RET (dst__openssl_toresult2("EC_KEY_generate_key",
308243885Serwin						DST_R_OPENSSLFAILURE));
309243885Serwin
310243885Serwin	pkey = EVP_PKEY_new();
311243885Serwin	if (pkey == NULL)
312243885Serwin		DST_RET (ISC_R_NOMEMORY);
313243885Serwin	if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) {
314243885Serwin		EVP_PKEY_free(pkey);
315243885Serwin		DST_RET (ISC_R_FAILURE);
316243885Serwin	}
317243885Serwin	key->keydata.pkey = pkey;
318243885Serwin	ret = ISC_R_SUCCESS;
319243885Serwin
320243885Serwin err:
321243885Serwin	if (eckey != NULL)
322243885Serwin		EC_KEY_free(eckey);
323243885Serwin	return (ret);
324243885Serwin}
325243885Serwin
326243885Serwinstatic isc_boolean_t
327243885Serwinopensslecdsa_isprivate(const dst_key_t *key) {
328243885Serwin	isc_boolean_t ret;
329243885Serwin	EVP_PKEY *pkey = key->keydata.pkey;
330243885Serwin	EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(pkey);
331243885Serwin
332243885Serwin	ret = ISC_TF(eckey != NULL && EC_KEY_get0_private_key(eckey) != NULL);
333243885Serwin	if (eckey != NULL)
334243885Serwin		EC_KEY_free(eckey);
335243885Serwin	return (ret);
336243885Serwin}
337243885Serwin
338243885Serwinstatic void
339243885Serwinopensslecdsa_destroy(dst_key_t *key) {
340243885Serwin	EVP_PKEY *pkey = key->keydata.pkey;
341243885Serwin
342243885Serwin	EVP_PKEY_free(pkey);
343243885Serwin	key->keydata.pkey = NULL;
344243885Serwin}
345243885Serwin
346243885Serwinstatic isc_result_t
347243885Serwinopensslecdsa_todns(const dst_key_t *key, isc_buffer_t *data) {
348243885Serwin	isc_result_t ret;
349243885Serwin	EVP_PKEY *pkey;
350243885Serwin	EC_KEY *eckey = NULL;
351243885Serwin	isc_region_t r;
352243885Serwin	int len;
353243885Serwin	unsigned char *cp;
354243885Serwin	unsigned char buf[DNS_KEY_ECDSA384SIZE + 1];
355243885Serwin
356243885Serwin	REQUIRE(key->keydata.pkey != NULL);
357243885Serwin
358243885Serwin	pkey = key->keydata.pkey;
359243885Serwin	eckey = EVP_PKEY_get1_EC_KEY(pkey);
360243885Serwin	if (eckey == NULL)
361243885Serwin		return (dst__openssl_toresult(ISC_R_FAILURE));
362243885Serwin	len = i2o_ECPublicKey(eckey, NULL);
363243885Serwin	/* skip form */
364243885Serwin	len--;
365243885Serwin
366243885Serwin	isc_buffer_availableregion(data, &r);
367243885Serwin	if (r.length < (unsigned int) len)
368243885Serwin		DST_RET (ISC_R_NOSPACE);
369243885Serwin	cp = buf;
370243885Serwin	if (!i2o_ECPublicKey(eckey, &cp))
371243885Serwin		DST_RET (dst__openssl_toresult(ISC_R_FAILURE));
372262706Serwin	memmove(r.base, buf + 1, len);
373243885Serwin	isc_buffer_add(data, len);
374243885Serwin	ret = ISC_R_SUCCESS;
375243885Serwin
376243885Serwin err:
377243885Serwin	if (eckey != NULL)
378243885Serwin		EC_KEY_free(eckey);
379243885Serwin	return (ret);
380243885Serwin}
381243885Serwin
382243885Serwinstatic isc_result_t
383243885Serwinopensslecdsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
384243885Serwin	isc_result_t ret;
385243885Serwin	EVP_PKEY *pkey;
386243885Serwin	EC_KEY *eckey = NULL;
387243885Serwin	isc_region_t r;
388243885Serwin	int group_nid;
389243885Serwin	unsigned int len;
390243885Serwin	const unsigned char *cp;
391243885Serwin	unsigned char buf[DNS_KEY_ECDSA384SIZE + 1];
392243885Serwin
393243885Serwin	REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
394243885Serwin		key->key_alg == DST_ALG_ECDSA384);
395243885Serwin
396243885Serwin	if (key->key_alg == DST_ALG_ECDSA256) {
397243885Serwin		len = DNS_KEY_ECDSA256SIZE;
398243885Serwin		group_nid = NID_X9_62_prime256v1;
399243885Serwin	} else {
400243885Serwin		len = DNS_KEY_ECDSA384SIZE;
401243885Serwin		group_nid = NID_secp384r1;
402243885Serwin	}
403243885Serwin
404243885Serwin	isc_buffer_remainingregion(data, &r);
405243885Serwin	if (r.length == 0)
406243885Serwin		return (ISC_R_SUCCESS);
407243885Serwin	if (r.length < len)
408243885Serwin		return (DST_R_INVALIDPUBLICKEY);
409243885Serwin
410243885Serwin	eckey = EC_KEY_new_by_curve_name(group_nid);
411243885Serwin	if (eckey == NULL)
412243885Serwin		return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
413243885Serwin
414243885Serwin	buf[0] = POINT_CONVERSION_UNCOMPRESSED;
415262706Serwin	memmove(buf + 1, r.base, len);
416243885Serwin	cp = buf;
417243885Serwin	if (o2i_ECPublicKey(&eckey,
418243885Serwin			    (const unsigned char **) &cp,
419243885Serwin			    (long) len + 1) == NULL)
420243885Serwin		DST_RET (dst__openssl_toresult(DST_R_INVALIDPUBLICKEY));
421243885Serwin	if (EC_KEY_check_key(eckey) != 1)
422243885Serwin		DST_RET (dst__openssl_toresult(DST_R_INVALIDPUBLICKEY));
423243885Serwin
424243885Serwin	pkey = EVP_PKEY_new();
425243885Serwin	if (pkey == NULL)
426243885Serwin		DST_RET (ISC_R_NOMEMORY);
427243885Serwin	if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) {
428243885Serwin		EVP_PKEY_free(pkey);
429243885Serwin		DST_RET (dst__openssl_toresult(ISC_R_FAILURE));
430243885Serwin	}
431243885Serwin
432243885Serwin	isc_buffer_forward(data, len);
433243885Serwin	key->keydata.pkey = pkey;
434243885Serwin	ret = ISC_R_SUCCESS;
435243885Serwin
436243885Serwin err:
437243885Serwin	if (eckey != NULL)
438243885Serwin		EC_KEY_free(eckey);
439243885Serwin	return (ret);
440243885Serwin}
441243885Serwin
442243885Serwinstatic isc_result_t
443243885Serwinopensslecdsa_tofile(const dst_key_t *key, const char *directory) {
444243885Serwin	isc_result_t ret;
445243885Serwin	EVP_PKEY *pkey;
446243885Serwin	EC_KEY *eckey = NULL;
447243885Serwin	const BIGNUM *privkey;
448243885Serwin	dst_private_t priv;
449243885Serwin	unsigned char *buf = NULL;
450243885Serwin
451243885Serwin	if (key->keydata.pkey == NULL)
452243885Serwin		return (DST_R_NULLKEY);
453243885Serwin
454262706Serwin	if (key->external) {
455262706Serwin		priv.nelements = 0;
456262706Serwin		return (dst__privstruct_writefile(key, &priv, directory));
457262706Serwin	}
458262706Serwin
459243885Serwin	pkey = key->keydata.pkey;
460243885Serwin	eckey = EVP_PKEY_get1_EC_KEY(pkey);
461243885Serwin	if (eckey == NULL)
462243885Serwin		return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
463243885Serwin	privkey = EC_KEY_get0_private_key(eckey);
464243885Serwin	if (privkey == NULL)
465243885Serwin		DST_RET (ISC_R_FAILURE);
466243885Serwin
467243885Serwin	buf = isc_mem_get(key->mctx, BN_num_bytes(privkey));
468243885Serwin	if (buf == NULL)
469243885Serwin		DST_RET (ISC_R_NOMEMORY);
470243885Serwin
471243885Serwin	priv.elements[0].tag = TAG_ECDSA_PRIVATEKEY;
472243885Serwin	priv.elements[0].length = BN_num_bytes(privkey);
473243885Serwin	BN_bn2bin(privkey, buf);
474243885Serwin	priv.elements[0].data = buf;
475243885Serwin	priv.nelements = ECDSA_NTAGS;
476243885Serwin	ret = dst__privstruct_writefile(key, &priv, directory);
477243885Serwin
478243885Serwin err:
479243885Serwin	if (eckey != NULL)
480243885Serwin		EC_KEY_free(eckey);
481243885Serwin	if (buf != NULL)
482243885Serwin		isc_mem_put(key->mctx, buf, BN_num_bytes(privkey));
483243885Serwin	return (ret);
484243885Serwin}
485243885Serwin
486243885Serwinstatic isc_result_t
487243885Serwinecdsa_check(EC_KEY *eckey, dst_key_t *pub)
488243885Serwin{
489243885Serwin	isc_result_t ret = ISC_R_FAILURE;
490243885Serwin	EVP_PKEY *pkey;
491243885Serwin	EC_KEY *pubeckey = NULL;
492243885Serwin	const EC_POINT *pubkey;
493243885Serwin
494243885Serwin	if (pub == NULL)
495243885Serwin		return (ISC_R_SUCCESS);
496243885Serwin	pkey = pub->keydata.pkey;
497243885Serwin	if (pkey == NULL)
498243885Serwin		return (ISC_R_SUCCESS);
499243885Serwin	pubeckey = EVP_PKEY_get1_EC_KEY(pkey);
500243885Serwin	if (pubeckey == NULL)
501243885Serwin		return (ISC_R_SUCCESS);
502243885Serwin	pubkey = EC_KEY_get0_public_key(pubeckey);
503243885Serwin	if (pubkey == NULL)
504243885Serwin		DST_RET (ISC_R_SUCCESS);
505243885Serwin	if (EC_KEY_set_public_key(eckey, pubkey) != 1)
506243885Serwin		DST_RET (ISC_R_SUCCESS);
507243885Serwin	if (EC_KEY_check_key(eckey) == 1)
508243885Serwin		DST_RET (ISC_R_SUCCESS);
509243885Serwin
510243885Serwin err:
511243885Serwin	if (pubeckey != NULL)
512243885Serwin		EC_KEY_free(pubeckey);
513243885Serwin	return (ret);
514243885Serwin}
515243885Serwin
516243885Serwinstatic isc_result_t
517243885Serwinopensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
518243885Serwin	dst_private_t priv;
519243885Serwin	isc_result_t ret;
520262706Serwin	EVP_PKEY *pkey, *pubpkey;
521262706Serwin	EC_KEY *eckey = NULL, *pubeckey = NULL;
522262706Serwin	const EC_POINT *pubkey;
523243885Serwin	BIGNUM *privkey;
524243885Serwin	int group_nid;
525243885Serwin	isc_mem_t *mctx = key->mctx;
526243885Serwin
527243885Serwin	REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
528243885Serwin		key->key_alg == DST_ALG_ECDSA384);
529243885Serwin
530243885Serwin	if (key->key_alg == DST_ALG_ECDSA256)
531243885Serwin		group_nid = NID_X9_62_prime256v1;
532243885Serwin	else
533243885Serwin		group_nid = NID_secp384r1;
534243885Serwin
535243885Serwin	eckey = EC_KEY_new_by_curve_name(group_nid);
536243885Serwin	if (eckey == NULL)
537243885Serwin		return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
538243885Serwin
539243885Serwin	/* read private key file */
540243885Serwin	ret = dst__privstruct_parse(key, DST_ALG_ECDSA256, lexer, mctx, &priv);
541243885Serwin	if (ret != ISC_R_SUCCESS)
542243885Serwin		goto err;
543243885Serwin
544262706Serwin	if (key->external) {
545262706Serwin		/*
546262706Serwin		 * Copy the public key to this new key.
547262706Serwin		 */
548262706Serwin		if (pub == NULL)
549262706Serwin			DST_RET(DST_R_INVALIDPRIVATEKEY);
550262706Serwin		pubpkey = pub->keydata.pkey;
551262706Serwin		pubeckey = EVP_PKEY_get1_EC_KEY(pubpkey);
552262706Serwin		if (pubeckey == NULL)
553262706Serwin			DST_RET(DST_R_INVALIDPRIVATEKEY);
554262706Serwin		pubkey = EC_KEY_get0_public_key(pubeckey);
555262706Serwin		if (pubkey == NULL)
556262706Serwin			DST_RET(DST_R_INVALIDPRIVATEKEY);
557262706Serwin		if (EC_KEY_set_public_key(eckey, pubkey) != 1)
558262706Serwin			DST_RET(DST_R_INVALIDPRIVATEKEY);
559262706Serwin		if (EC_KEY_check_key(eckey) != 1)
560262706Serwin			DST_RET(DST_R_INVALIDPRIVATEKEY);
561262706Serwin	} else {
562262706Serwin		privkey = BN_bin2bn(priv.elements[0].data,
563262706Serwin				    priv.elements[0].length, NULL);
564262706Serwin		if (privkey == NULL)
565262706Serwin			DST_RET(ISC_R_NOMEMORY);
566262706Serwin		if (!EC_KEY_set_private_key(eckey, privkey))
567262706Serwin			DST_RET(ISC_R_NOMEMORY);
568262706Serwin		if (ecdsa_check(eckey, pub) != ISC_R_SUCCESS)
569262706Serwin			DST_RET(DST_R_INVALIDPRIVATEKEY);
570262706Serwin		dst__privstruct_free(&priv, mctx);
571262706Serwin		memset(&priv, 0, sizeof(priv));
572262706Serwin	}
573243885Serwin
574243885Serwin	pkey = EVP_PKEY_new();
575243885Serwin	if (pkey == NULL)
576243885Serwin		DST_RET (ISC_R_NOMEMORY);
577243885Serwin	if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) {
578243885Serwin		EVP_PKEY_free(pkey);
579243885Serwin		DST_RET (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
580243885Serwin	}
581243885Serwin	key->keydata.pkey = pkey;
582243885Serwin	ret = ISC_R_SUCCESS;
583243885Serwin
584243885Serwin err:
585243885Serwin	if (eckey != NULL)
586243885Serwin		EC_KEY_free(eckey);
587262706Serwin	if (pubeckey != NULL)
588262706Serwin		EC_KEY_free(pubeckey);
589243885Serwin	dst__privstruct_free(&priv, mctx);
590243885Serwin	memset(&priv, 0, sizeof(priv));
591243885Serwin	return (ret);
592243885Serwin}
593243885Serwin
594243885Serwinstatic dst_func_t opensslecdsa_functions = {
595243885Serwin	opensslecdsa_createctx,
596243885Serwin	opensslecdsa_destroyctx,
597243885Serwin	opensslecdsa_adddata,
598243885Serwin	opensslecdsa_sign,
599243885Serwin	opensslecdsa_verify,
600254897Serwin	NULL, /*%< verify2 */
601243885Serwin	NULL, /*%< computesecret */
602243885Serwin	opensslecdsa_compare,
603243885Serwin	NULL, /*%< paramcompare */
604243885Serwin	opensslecdsa_generate,
605243885Serwin	opensslecdsa_isprivate,
606243885Serwin	opensslecdsa_destroy,
607243885Serwin	opensslecdsa_todns,
608243885Serwin	opensslecdsa_fromdns,
609243885Serwin	opensslecdsa_tofile,
610243885Serwin	opensslecdsa_parse,
611243885Serwin	NULL, /*%< cleanup */
612243885Serwin	NULL, /*%< fromlabel */
613243885Serwin	NULL, /*%< dump */
614243885Serwin	NULL, /*%< restore */
615243885Serwin};
616243885Serwin
617243885Serwinisc_result_t
618243885Serwindst__opensslecdsa_init(dst_func_t **funcp) {
619243885Serwin	REQUIRE(funcp != NULL);
620243885Serwin	if (*funcp == NULL)
621243885Serwin		*funcp = &opensslecdsa_functions;
622243885Serwin	return (ISC_R_SUCCESS);
623243885Serwin}
624243885Serwin
625243885Serwin#else /* HAVE_OPENSSL_ECDSA */
626243885Serwin
627243885Serwin#include <isc/util.h>
628243885Serwin
629243885SerwinEMPTY_TRANSLATION_UNIT
630243885Serwin
631243885Serwin#endif /* HAVE_OPENSSL_ECDSA */
632243885Serwin/*! \file */
633