opensslecdsa_link.c revision 262706
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/* $Id$ */
18243885Serwin
19243885Serwin#include <config.h>
20243885Serwin
21243885Serwin#ifdef HAVE_OPENSSL_ECDSA
22243885Serwin
23243885Serwin#if !defined(HAVE_EVP_SHA256) || !defined(HAVE_EVP_SHA384)
24243885Serwin#error "ECDSA without EVP for SHA2?"
25243885Serwin#endif
26243885Serwin
27243885Serwin#include <isc/entropy.h>
28243885Serwin#include <isc/mem.h>
29243885Serwin#include <isc/sha2.h>
30243885Serwin#include <isc/string.h>
31243885Serwin#include <isc/util.h>
32243885Serwin
33243885Serwin#include <dns/keyvalues.h>
34243885Serwin#include <dst/result.h>
35243885Serwin
36243885Serwin#include "dst_internal.h"
37243885Serwin#include "dst_openssl.h"
38243885Serwin#include "dst_parse.h"
39243885Serwin
40243885Serwin#include <openssl/err.h>
41243885Serwin#include <openssl/objects.h>
42243885Serwin#include <openssl/ecdsa.h>
43243885Serwin#include <openssl/bn.h>
44243885Serwin
45243885Serwin#ifndef NID_X9_62_prime256v1
46243885Serwin#error "P-256 group is not known (NID_X9_62_prime256v1)"
47243885Serwin#endif
48243885Serwin#ifndef NID_secp384r1
49243885Serwin#error "P-384 group is not known (NID_secp384r1)"
50243885Serwin#endif
51243885Serwin
52243885Serwin#define DST_RET(a) {ret = a; goto err;}
53243885Serwin
54243885Serwinstatic isc_result_t opensslecdsa_todns(const dst_key_t *key,
55243885Serwin				       isc_buffer_t *data);
56243885Serwin
57243885Serwinstatic isc_result_t
58243885Serwinopensslecdsa_createctx(dst_key_t *key, dst_context_t *dctx) {
59243885Serwin	EVP_MD_CTX *evp_md_ctx;
60243885Serwin	const EVP_MD *type = NULL;
61243885Serwin
62243885Serwin	UNUSED(key);
63243885Serwin	REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
64243885Serwin		dctx->key->key_alg == DST_ALG_ECDSA384);
65243885Serwin
66243885Serwin	evp_md_ctx = EVP_MD_CTX_create();
67243885Serwin	if (evp_md_ctx == NULL)
68243885Serwin		return (ISC_R_NOMEMORY);
69243885Serwin	if (dctx->key->key_alg == DST_ALG_ECDSA256)
70243885Serwin		type = EVP_sha256();
71243885Serwin	else
72243885Serwin		type = EVP_sha384();
73243885Serwin
74243885Serwin	if (!EVP_DigestInit_ex(evp_md_ctx, type, NULL)) {
75243885Serwin		EVP_MD_CTX_destroy(evp_md_ctx);
76254402Serwin		return (dst__openssl_toresult3(dctx->category,
77254402Serwin					       "EVP_DigestInit_ex",
78243885Serwin					       ISC_R_FAILURE));
79243885Serwin	}
80243885Serwin
81243885Serwin	dctx->ctxdata.evp_md_ctx = evp_md_ctx;
82243885Serwin
83243885Serwin	return (ISC_R_SUCCESS);
84243885Serwin}
85243885Serwin
86243885Serwinstatic void
87243885Serwinopensslecdsa_destroyctx(dst_context_t *dctx) {
88243885Serwin	EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
89243885Serwin
90243885Serwin	REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
91243885Serwin		dctx->key->key_alg == DST_ALG_ECDSA384);
92243885Serwin
93243885Serwin	if (evp_md_ctx != NULL) {
94243885Serwin		EVP_MD_CTX_destroy(evp_md_ctx);
95243885Serwin		dctx->ctxdata.evp_md_ctx = NULL;
96243885Serwin	}
97243885Serwin}
98243885Serwin
99243885Serwinstatic isc_result_t
100243885Serwinopensslecdsa_adddata(dst_context_t *dctx, const isc_region_t *data) {
101243885Serwin	EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
102243885Serwin
103243885Serwin	REQUIRE(dctx->key->key_alg == DST_ALG_ECDSA256 ||
104243885Serwin		dctx->key->key_alg == DST_ALG_ECDSA384);
105243885Serwin
106243885Serwin	if (!EVP_DigestUpdate(evp_md_ctx, data->base, data->length))
107254402Serwin		return (dst__openssl_toresult3(dctx->category,
108254402Serwin					       "EVP_DigestUpdate",
109243885Serwin					       ISC_R_FAILURE));
110243885Serwin
111243885Serwin	return (ISC_R_SUCCESS);
112243885Serwin}
113243885Serwin
114243885Serwinstatic int
115243885SerwinBN_bn2bin_fixed(BIGNUM *bn, unsigned char *buf, int size) {
116243885Serwin	int bytes = size - BN_num_bytes(bn);
117243885Serwin
118243885Serwin	while (bytes-- > 0)
119243885Serwin		*buf++ = 0;
120243885Serwin	BN_bn2bin(bn, buf);
121243885Serwin	return (size);
122243885Serwin}
123243885Serwin
124243885Serwinstatic isc_result_t
125243885Serwinopensslecdsa_sign(dst_context_t *dctx, isc_buffer_t *sig) {
126243885Serwin	isc_result_t ret;
127243885Serwin	dst_key_t *key = dctx->key;
128243885Serwin	isc_region_t r;
129243885Serwin	ECDSA_SIG *ecdsasig;
130243885Serwin	EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
131243885Serwin	EVP_PKEY *pkey = key->keydata.pkey;
132243885Serwin	EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(pkey);
133243885Serwin	unsigned int dgstlen, siglen;
134243885Serwin	unsigned char digest[EVP_MAX_MD_SIZE];
135243885Serwin
136243885Serwin	REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
137243885Serwin		key->key_alg == DST_ALG_ECDSA384);
138243885Serwin
139243885Serwin	if (eckey == NULL)
140243885Serwin		return (ISC_R_FAILURE);
141243885Serwin
142243885Serwin	if (key->key_alg == DST_ALG_ECDSA256)
143243885Serwin		siglen = DNS_SIG_ECDSA256SIZE;
144243885Serwin	else
145243885Serwin		siglen = DNS_SIG_ECDSA384SIZE;
146243885Serwin
147243885Serwin	isc_buffer_availableregion(sig, &r);
148243885Serwin	if (r.length < siglen)
149243885Serwin		DST_RET(ISC_R_NOSPACE);
150243885Serwin
151243885Serwin	if (!EVP_DigestFinal(evp_md_ctx, digest, &dgstlen))
152254402Serwin		DST_RET(dst__openssl_toresult3(dctx->category,
153254402Serwin					       "EVP_DigestFinal",
154243885Serwin					       ISC_R_FAILURE));
155243885Serwin
156243885Serwin	ecdsasig = ECDSA_do_sign(digest, dgstlen, eckey);
157243885Serwin	if (ecdsasig == NULL)
158254402Serwin		DST_RET(dst__openssl_toresult3(dctx->category,
159254402Serwin					       "ECDSA_do_sign",
160243885Serwin					       DST_R_SIGNFAILURE));
161243885Serwin	BN_bn2bin_fixed(ecdsasig->r, r.base, siglen / 2);
162243885Serwin	r.base += siglen / 2;
163243885Serwin	BN_bn2bin_fixed(ecdsasig->s, r.base, siglen / 2);
164243885Serwin	r.base += siglen / 2;
165243885Serwin	ECDSA_SIG_free(ecdsasig);
166243885Serwin	isc_buffer_add(sig, siglen);
167243885Serwin	ret = ISC_R_SUCCESS;
168243885Serwin
169243885Serwin err:
170243885Serwin	if (eckey != NULL)
171243885Serwin		EC_KEY_free(eckey);
172243885Serwin	return (ret);
173243885Serwin}
174243885Serwin
175243885Serwinstatic isc_result_t
176243885Serwinopensslecdsa_verify(dst_context_t *dctx, const isc_region_t *sig) {
177243885Serwin	isc_result_t ret;
178243885Serwin	dst_key_t *key = dctx->key;
179243885Serwin	int status;
180243885Serwin	unsigned char *cp = sig->base;
181243885Serwin	ECDSA_SIG *ecdsasig = NULL;
182243885Serwin	EVP_MD_CTX *evp_md_ctx = dctx->ctxdata.evp_md_ctx;
183243885Serwin	EVP_PKEY *pkey = key->keydata.pkey;
184243885Serwin	EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(pkey);
185243885Serwin	unsigned int dgstlen, siglen;
186243885Serwin	unsigned char digest[EVP_MAX_MD_SIZE];
187243885Serwin
188243885Serwin	REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
189243885Serwin		key->key_alg == DST_ALG_ECDSA384);
190243885Serwin
191243885Serwin	if (eckey == NULL)
192243885Serwin		return (ISC_R_FAILURE);
193243885Serwin
194243885Serwin	if (key->key_alg == DST_ALG_ECDSA256)
195243885Serwin		siglen = DNS_SIG_ECDSA256SIZE;
196243885Serwin	else
197243885Serwin		siglen = DNS_SIG_ECDSA384SIZE;
198243885Serwin
199243885Serwin	if (sig->length != siglen)
200243885Serwin		return (DST_R_VERIFYFAILURE);
201243885Serwin
202243885Serwin	if (!EVP_DigestFinal_ex(evp_md_ctx, digest, &dgstlen))
203254402Serwin		DST_RET (dst__openssl_toresult3(dctx->category,
204254402Serwin						"EVP_DigestFinal_ex",
205243885Serwin						ISC_R_FAILURE));
206243885Serwin
207243885Serwin	ecdsasig = ECDSA_SIG_new();
208243885Serwin	if (ecdsasig == NULL)
209243885Serwin		DST_RET (ISC_R_NOMEMORY);
210254402Serwin	if (ecdsasig->r != NULL)
211254402Serwin		BN_free(ecdsasig->r);
212243885Serwin	ecdsasig->r = BN_bin2bn(cp, siglen / 2, NULL);
213243885Serwin	cp += siglen / 2;
214254402Serwin	if (ecdsasig->s != NULL)
215254402Serwin		BN_free(ecdsasig->s);
216243885Serwin	ecdsasig->s = BN_bin2bn(cp, siglen / 2, NULL);
217243885Serwin	/* cp += siglen / 2; */
218243885Serwin
219243885Serwin	status = ECDSA_do_verify(digest, dgstlen, ecdsasig, eckey);
220243885Serwin	switch (status) {
221243885Serwin	case 1:
222243885Serwin		ret = ISC_R_SUCCESS;
223243885Serwin		break;
224243885Serwin	case 0:
225243885Serwin		ret = dst__openssl_toresult(DST_R_VERIFYFAILURE);
226243885Serwin		break;
227243885Serwin	default:
228254402Serwin		ret = dst__openssl_toresult3(dctx->category,
229254402Serwin					     "ECDSA_do_verify",
230243885Serwin					     DST_R_VERIFYFAILURE);
231243885Serwin		break;
232243885Serwin	}
233243885Serwin
234243885Serwin err:
235243885Serwin	if (ecdsasig != NULL)
236243885Serwin		ECDSA_SIG_free(ecdsasig);
237243885Serwin	if (eckey != NULL)
238243885Serwin		EC_KEY_free(eckey);
239243885Serwin	return (ret);
240243885Serwin}
241243885Serwin
242243885Serwinstatic isc_boolean_t
243243885Serwinopensslecdsa_compare(const dst_key_t *key1, const dst_key_t *key2) {
244243885Serwin	isc_boolean_t ret;
245243885Serwin	int status;
246243885Serwin	EVP_PKEY *pkey1 = key1->keydata.pkey;
247243885Serwin	EVP_PKEY *pkey2 = key2->keydata.pkey;
248243885Serwin	EC_KEY *eckey1 = NULL;
249243885Serwin	EC_KEY *eckey2 = NULL;
250243885Serwin	const BIGNUM *priv1, *priv2;
251243885Serwin
252243885Serwin	if (pkey1 == NULL && pkey2 == NULL)
253243885Serwin		return (ISC_TRUE);
254243885Serwin	else if (pkey1 == NULL || pkey2 == NULL)
255243885Serwin		return (ISC_FALSE);
256243885Serwin
257243885Serwin	eckey1 = EVP_PKEY_get1_EC_KEY(pkey1);
258243885Serwin	eckey2 = EVP_PKEY_get1_EC_KEY(pkey2);
259243885Serwin	if (eckey1 == NULL && eckey2 == NULL) {
260243885Serwin		DST_RET (ISC_TRUE);
261243885Serwin	} else if (eckey1 == NULL || eckey2 == NULL)
262243885Serwin		DST_RET (ISC_FALSE);
263243885Serwin
264243885Serwin	status = EVP_PKEY_cmp(pkey1, pkey2);
265243885Serwin	if (status != 1)
266243885Serwin		DST_RET (ISC_FALSE);
267243885Serwin
268243885Serwin	priv1 = EC_KEY_get0_private_key(eckey1);
269243885Serwin	priv2 = EC_KEY_get0_private_key(eckey2);
270243885Serwin	if (priv1 != NULL || priv2 != NULL) {
271243885Serwin		if (priv1 == NULL || priv2 == NULL)
272243885Serwin			DST_RET (ISC_FALSE);
273243885Serwin		if (BN_cmp(priv1, priv2) != 0)
274243885Serwin			DST_RET (ISC_FALSE);
275243885Serwin	}
276243885Serwin	ret = ISC_TRUE;
277243885Serwin
278243885Serwin err:
279243885Serwin	if (eckey1 != NULL)
280243885Serwin		EC_KEY_free(eckey1);
281243885Serwin	if (eckey2 != NULL)
282243885Serwin		EC_KEY_free(eckey2);
283243885Serwin	return (ret);
284243885Serwin}
285243885Serwin
286243885Serwinstatic isc_result_t
287243885Serwinopensslecdsa_generate(dst_key_t *key, int unused, void (*callback)(int)) {
288243885Serwin	isc_result_t ret;
289243885Serwin	EVP_PKEY *pkey;
290243885Serwin	EC_KEY *eckey = NULL;
291243885Serwin	int group_nid;
292243885Serwin
293243885Serwin	REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
294243885Serwin		key->key_alg == DST_ALG_ECDSA384);
295243885Serwin	UNUSED(unused);
296243885Serwin	UNUSED(callback);
297243885Serwin
298243885Serwin	if (key->key_alg == DST_ALG_ECDSA256)
299243885Serwin		group_nid = NID_X9_62_prime256v1;
300243885Serwin	else
301243885Serwin		group_nid = NID_secp384r1;
302243885Serwin
303243885Serwin	eckey = EC_KEY_new_by_curve_name(group_nid);
304243885Serwin	if (eckey == NULL)
305243885Serwin		return (dst__openssl_toresult2("EC_KEY_new_by_curve_name",
306243885Serwin					       DST_R_OPENSSLFAILURE));
307243885Serwin
308243885Serwin	if (EC_KEY_generate_key(eckey) != 1)
309243885Serwin		DST_RET (dst__openssl_toresult2("EC_KEY_generate_key",
310243885Serwin						DST_R_OPENSSLFAILURE));
311243885Serwin
312243885Serwin	pkey = EVP_PKEY_new();
313243885Serwin	if (pkey == NULL)
314243885Serwin		DST_RET (ISC_R_NOMEMORY);
315243885Serwin	if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) {
316243885Serwin		EVP_PKEY_free(pkey);
317243885Serwin		DST_RET (ISC_R_FAILURE);
318243885Serwin	}
319243885Serwin	key->keydata.pkey = pkey;
320243885Serwin	ret = ISC_R_SUCCESS;
321243885Serwin
322243885Serwin err:
323243885Serwin	if (eckey != NULL)
324243885Serwin		EC_KEY_free(eckey);
325243885Serwin	return (ret);
326243885Serwin}
327243885Serwin
328243885Serwinstatic isc_boolean_t
329243885Serwinopensslecdsa_isprivate(const dst_key_t *key) {
330243885Serwin	isc_boolean_t ret;
331243885Serwin	EVP_PKEY *pkey = key->keydata.pkey;
332243885Serwin	EC_KEY *eckey = EVP_PKEY_get1_EC_KEY(pkey);
333243885Serwin
334243885Serwin	ret = ISC_TF(eckey != NULL && EC_KEY_get0_private_key(eckey) != NULL);
335243885Serwin	if (eckey != NULL)
336243885Serwin		EC_KEY_free(eckey);
337243885Serwin	return (ret);
338243885Serwin}
339243885Serwin
340243885Serwinstatic void
341243885Serwinopensslecdsa_destroy(dst_key_t *key) {
342243885Serwin	EVP_PKEY *pkey = key->keydata.pkey;
343243885Serwin
344243885Serwin	EVP_PKEY_free(pkey);
345243885Serwin	key->keydata.pkey = NULL;
346243885Serwin}
347243885Serwin
348243885Serwinstatic isc_result_t
349243885Serwinopensslecdsa_todns(const dst_key_t *key, isc_buffer_t *data) {
350243885Serwin	isc_result_t ret;
351243885Serwin	EVP_PKEY *pkey;
352243885Serwin	EC_KEY *eckey = NULL;
353243885Serwin	isc_region_t r;
354243885Serwin	int len;
355243885Serwin	unsigned char *cp;
356243885Serwin	unsigned char buf[DNS_KEY_ECDSA384SIZE + 1];
357243885Serwin
358243885Serwin	REQUIRE(key->keydata.pkey != NULL);
359243885Serwin
360243885Serwin	pkey = key->keydata.pkey;
361243885Serwin	eckey = EVP_PKEY_get1_EC_KEY(pkey);
362243885Serwin	if (eckey == NULL)
363243885Serwin		return (dst__openssl_toresult(ISC_R_FAILURE));
364243885Serwin	len = i2o_ECPublicKey(eckey, NULL);
365243885Serwin	/* skip form */
366243885Serwin	len--;
367243885Serwin
368243885Serwin	isc_buffer_availableregion(data, &r);
369243885Serwin	if (r.length < (unsigned int) len)
370243885Serwin		DST_RET (ISC_R_NOSPACE);
371243885Serwin	cp = buf;
372243885Serwin	if (!i2o_ECPublicKey(eckey, &cp))
373243885Serwin		DST_RET (dst__openssl_toresult(ISC_R_FAILURE));
374262706Serwin	memmove(r.base, buf + 1, len);
375243885Serwin	isc_buffer_add(data, len);
376243885Serwin	ret = ISC_R_SUCCESS;
377243885Serwin
378243885Serwin err:
379243885Serwin	if (eckey != NULL)
380243885Serwin		EC_KEY_free(eckey);
381243885Serwin	return (ret);
382243885Serwin}
383243885Serwin
384243885Serwinstatic isc_result_t
385243885Serwinopensslecdsa_fromdns(dst_key_t *key, isc_buffer_t *data) {
386243885Serwin	isc_result_t ret;
387243885Serwin	EVP_PKEY *pkey;
388243885Serwin	EC_KEY *eckey = NULL;
389243885Serwin	isc_region_t r;
390243885Serwin	int group_nid;
391243885Serwin	unsigned int len;
392243885Serwin	const unsigned char *cp;
393243885Serwin	unsigned char buf[DNS_KEY_ECDSA384SIZE + 1];
394243885Serwin
395243885Serwin	REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
396243885Serwin		key->key_alg == DST_ALG_ECDSA384);
397243885Serwin
398243885Serwin	if (key->key_alg == DST_ALG_ECDSA256) {
399243885Serwin		len = DNS_KEY_ECDSA256SIZE;
400243885Serwin		group_nid = NID_X9_62_prime256v1;
401243885Serwin	} else {
402243885Serwin		len = DNS_KEY_ECDSA384SIZE;
403243885Serwin		group_nid = NID_secp384r1;
404243885Serwin	}
405243885Serwin
406243885Serwin	isc_buffer_remainingregion(data, &r);
407243885Serwin	if (r.length == 0)
408243885Serwin		return (ISC_R_SUCCESS);
409243885Serwin	if (r.length < len)
410243885Serwin		return (DST_R_INVALIDPUBLICKEY);
411243885Serwin
412243885Serwin	eckey = EC_KEY_new_by_curve_name(group_nid);
413243885Serwin	if (eckey == NULL)
414243885Serwin		return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
415243885Serwin
416243885Serwin	buf[0] = POINT_CONVERSION_UNCOMPRESSED;
417262706Serwin	memmove(buf + 1, r.base, len);
418243885Serwin	cp = buf;
419243885Serwin	if (o2i_ECPublicKey(&eckey,
420243885Serwin			    (const unsigned char **) &cp,
421243885Serwin			    (long) len + 1) == NULL)
422243885Serwin		DST_RET (dst__openssl_toresult(DST_R_INVALIDPUBLICKEY));
423243885Serwin	if (EC_KEY_check_key(eckey) != 1)
424243885Serwin		DST_RET (dst__openssl_toresult(DST_R_INVALIDPUBLICKEY));
425243885Serwin
426243885Serwin	pkey = EVP_PKEY_new();
427243885Serwin	if (pkey == NULL)
428243885Serwin		DST_RET (ISC_R_NOMEMORY);
429243885Serwin	if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) {
430243885Serwin		EVP_PKEY_free(pkey);
431243885Serwin		DST_RET (dst__openssl_toresult(ISC_R_FAILURE));
432243885Serwin	}
433243885Serwin
434243885Serwin	isc_buffer_forward(data, len);
435243885Serwin	key->keydata.pkey = pkey;
436243885Serwin	ret = ISC_R_SUCCESS;
437243885Serwin
438243885Serwin err:
439243885Serwin	if (eckey != NULL)
440243885Serwin		EC_KEY_free(eckey);
441243885Serwin	return (ret);
442243885Serwin}
443243885Serwin
444243885Serwinstatic isc_result_t
445243885Serwinopensslecdsa_tofile(const dst_key_t *key, const char *directory) {
446243885Serwin	isc_result_t ret;
447243885Serwin	EVP_PKEY *pkey;
448243885Serwin	EC_KEY *eckey = NULL;
449243885Serwin	const BIGNUM *privkey;
450243885Serwin	dst_private_t priv;
451243885Serwin	unsigned char *buf = NULL;
452243885Serwin
453243885Serwin	if (key->keydata.pkey == NULL)
454243885Serwin		return (DST_R_NULLKEY);
455243885Serwin
456262706Serwin	if (key->external) {
457262706Serwin		priv.nelements = 0;
458262706Serwin		return (dst__privstruct_writefile(key, &priv, directory));
459262706Serwin	}
460262706Serwin
461243885Serwin	pkey = key->keydata.pkey;
462243885Serwin	eckey = EVP_PKEY_get1_EC_KEY(pkey);
463243885Serwin	if (eckey == NULL)
464243885Serwin		return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
465243885Serwin	privkey = EC_KEY_get0_private_key(eckey);
466243885Serwin	if (privkey == NULL)
467243885Serwin		DST_RET (ISC_R_FAILURE);
468243885Serwin
469243885Serwin	buf = isc_mem_get(key->mctx, BN_num_bytes(privkey));
470243885Serwin	if (buf == NULL)
471243885Serwin		DST_RET (ISC_R_NOMEMORY);
472243885Serwin
473243885Serwin	priv.elements[0].tag = TAG_ECDSA_PRIVATEKEY;
474243885Serwin	priv.elements[0].length = BN_num_bytes(privkey);
475243885Serwin	BN_bn2bin(privkey, buf);
476243885Serwin	priv.elements[0].data = buf;
477243885Serwin	priv.nelements = ECDSA_NTAGS;
478243885Serwin	ret = dst__privstruct_writefile(key, &priv, directory);
479243885Serwin
480243885Serwin err:
481243885Serwin	if (eckey != NULL)
482243885Serwin		EC_KEY_free(eckey);
483243885Serwin	if (buf != NULL)
484243885Serwin		isc_mem_put(key->mctx, buf, BN_num_bytes(privkey));
485243885Serwin	return (ret);
486243885Serwin}
487243885Serwin
488243885Serwinstatic isc_result_t
489243885Serwinecdsa_check(EC_KEY *eckey, dst_key_t *pub)
490243885Serwin{
491243885Serwin	isc_result_t ret = ISC_R_FAILURE;
492243885Serwin	EVP_PKEY *pkey;
493243885Serwin	EC_KEY *pubeckey = NULL;
494243885Serwin	const EC_POINT *pubkey;
495243885Serwin
496243885Serwin	if (pub == NULL)
497243885Serwin		return (ISC_R_SUCCESS);
498243885Serwin	pkey = pub->keydata.pkey;
499243885Serwin	if (pkey == NULL)
500243885Serwin		return (ISC_R_SUCCESS);
501243885Serwin	pubeckey = EVP_PKEY_get1_EC_KEY(pkey);
502243885Serwin	if (pubeckey == NULL)
503243885Serwin		return (ISC_R_SUCCESS);
504243885Serwin	pubkey = EC_KEY_get0_public_key(pubeckey);
505243885Serwin	if (pubkey == NULL)
506243885Serwin		DST_RET (ISC_R_SUCCESS);
507243885Serwin	if (EC_KEY_set_public_key(eckey, pubkey) != 1)
508243885Serwin		DST_RET (ISC_R_SUCCESS);
509243885Serwin	if (EC_KEY_check_key(eckey) == 1)
510243885Serwin		DST_RET (ISC_R_SUCCESS);
511243885Serwin
512243885Serwin err:
513243885Serwin	if (pubeckey != NULL)
514243885Serwin		EC_KEY_free(pubeckey);
515243885Serwin	return (ret);
516243885Serwin}
517243885Serwin
518243885Serwinstatic isc_result_t
519243885Serwinopensslecdsa_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
520243885Serwin	dst_private_t priv;
521243885Serwin	isc_result_t ret;
522262706Serwin	EVP_PKEY *pkey, *pubpkey;
523262706Serwin	EC_KEY *eckey = NULL, *pubeckey = NULL;
524262706Serwin	const EC_POINT *pubkey;
525243885Serwin	BIGNUM *privkey;
526243885Serwin	int group_nid;
527243885Serwin	isc_mem_t *mctx = key->mctx;
528243885Serwin
529243885Serwin	REQUIRE(key->key_alg == DST_ALG_ECDSA256 ||
530243885Serwin		key->key_alg == DST_ALG_ECDSA384);
531243885Serwin
532243885Serwin	if (key->key_alg == DST_ALG_ECDSA256)
533243885Serwin		group_nid = NID_X9_62_prime256v1;
534243885Serwin	else
535243885Serwin		group_nid = NID_secp384r1;
536243885Serwin
537243885Serwin	eckey = EC_KEY_new_by_curve_name(group_nid);
538243885Serwin	if (eckey == NULL)
539243885Serwin		return (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
540243885Serwin
541243885Serwin	/* read private key file */
542243885Serwin	ret = dst__privstruct_parse(key, DST_ALG_ECDSA256, lexer, mctx, &priv);
543243885Serwin	if (ret != ISC_R_SUCCESS)
544243885Serwin		goto err;
545243885Serwin
546262706Serwin	if (key->external) {
547262706Serwin		/*
548262706Serwin		 * Copy the public key to this new key.
549262706Serwin		 */
550262706Serwin		if (pub == NULL)
551262706Serwin			DST_RET(DST_R_INVALIDPRIVATEKEY);
552262706Serwin		pubpkey = pub->keydata.pkey;
553262706Serwin		pubeckey = EVP_PKEY_get1_EC_KEY(pubpkey);
554262706Serwin		if (pubeckey == NULL)
555262706Serwin			DST_RET(DST_R_INVALIDPRIVATEKEY);
556262706Serwin		pubkey = EC_KEY_get0_public_key(pubeckey);
557262706Serwin		if (pubkey == NULL)
558262706Serwin			DST_RET(DST_R_INVALIDPRIVATEKEY);
559262706Serwin		if (EC_KEY_set_public_key(eckey, pubkey) != 1)
560262706Serwin			DST_RET(DST_R_INVALIDPRIVATEKEY);
561262706Serwin		if (EC_KEY_check_key(eckey) != 1)
562262706Serwin			DST_RET(DST_R_INVALIDPRIVATEKEY);
563262706Serwin	} else {
564262706Serwin		privkey = BN_bin2bn(priv.elements[0].data,
565262706Serwin				    priv.elements[0].length, NULL);
566262706Serwin		if (privkey == NULL)
567262706Serwin			DST_RET(ISC_R_NOMEMORY);
568262706Serwin		if (!EC_KEY_set_private_key(eckey, privkey))
569262706Serwin			DST_RET(ISC_R_NOMEMORY);
570262706Serwin		if (ecdsa_check(eckey, pub) != ISC_R_SUCCESS)
571262706Serwin			DST_RET(DST_R_INVALIDPRIVATEKEY);
572262706Serwin		dst__privstruct_free(&priv, mctx);
573262706Serwin		memset(&priv, 0, sizeof(priv));
574262706Serwin	}
575243885Serwin
576243885Serwin	pkey = EVP_PKEY_new();
577243885Serwin	if (pkey == NULL)
578243885Serwin		DST_RET (ISC_R_NOMEMORY);
579243885Serwin	if (!EVP_PKEY_set1_EC_KEY(pkey, eckey)) {
580243885Serwin		EVP_PKEY_free(pkey);
581243885Serwin		DST_RET (dst__openssl_toresult(DST_R_OPENSSLFAILURE));
582243885Serwin	}
583243885Serwin	key->keydata.pkey = pkey;
584243885Serwin	ret = ISC_R_SUCCESS;
585243885Serwin
586243885Serwin err:
587243885Serwin	if (eckey != NULL)
588243885Serwin		EC_KEY_free(eckey);
589262706Serwin	if (pubeckey != NULL)
590262706Serwin		EC_KEY_free(pubeckey);
591243885Serwin	dst__privstruct_free(&priv, mctx);
592243885Serwin	memset(&priv, 0, sizeof(priv));
593243885Serwin	return (ret);
594243885Serwin}
595243885Serwin
596243885Serwinstatic dst_func_t opensslecdsa_functions = {
597243885Serwin	opensslecdsa_createctx,
598243885Serwin	opensslecdsa_destroyctx,
599243885Serwin	opensslecdsa_adddata,
600243885Serwin	opensslecdsa_sign,
601243885Serwin	opensslecdsa_verify,
602254897Serwin	NULL, /*%< verify2 */
603243885Serwin	NULL, /*%< computesecret */
604243885Serwin	opensslecdsa_compare,
605243885Serwin	NULL, /*%< paramcompare */
606243885Serwin	opensslecdsa_generate,
607243885Serwin	opensslecdsa_isprivate,
608243885Serwin	opensslecdsa_destroy,
609243885Serwin	opensslecdsa_todns,
610243885Serwin	opensslecdsa_fromdns,
611243885Serwin	opensslecdsa_tofile,
612243885Serwin	opensslecdsa_parse,
613243885Serwin	NULL, /*%< cleanup */
614243885Serwin	NULL, /*%< fromlabel */
615243885Serwin	NULL, /*%< dump */
616243885Serwin	NULL, /*%< restore */
617243885Serwin};
618243885Serwin
619243885Serwinisc_result_t
620243885Serwindst__opensslecdsa_init(dst_func_t **funcp) {
621243885Serwin	REQUIRE(funcp != NULL);
622243885Serwin	if (*funcp == NULL)
623243885Serwin		*funcp = &opensslecdsa_functions;
624243885Serwin	return (ISC_R_SUCCESS);
625243885Serwin}
626243885Serwin
627243885Serwin#else /* HAVE_OPENSSL_ECDSA */
628243885Serwin
629243885Serwin#include <isc/util.h>
630243885Serwin
631243885SerwinEMPTY_TRANSLATION_UNIT
632243885Serwin
633243885Serwin#endif /* HAVE_OPENSSL_ECDSA */
634243885Serwin/*! \file */
635