mirror of
https://github.com/isc-projects/bind9.git
synced 2026-02-28 04:21:07 -05:00
The coccinellery repository provides many little semantic patches to fix common
problems in the code. The number of semantic patches in the coccinellery
repository is high and most of the semantic patches apply only for Linux, so it
doesn't make sense to run them on regular basis as the processing takes a lot of
time.
The list of issue found in BIND 9, by no means complete, includes:
- double assignment to a variable
- `continue` at the end of the loop
- double checks for `NULL`
- useless checks for `NULL` (cannot be `NULL`, because of earlier return)
- using `0` instead of `NULL`
- useless extra condition (`if (foo) return; if (!foo) { ...; }`)
- removing & in front of static functions passed as arguments
768 lines
17 KiB
C
768 lines
17 KiB
C
/*
|
|
* Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
* information regarding copyright ownership.
|
|
*
|
|
* Portions Copyright (C) Network Associates, Inc.
|
|
*
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
|
|
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
|
|
* FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
|
|
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
/*! \file */
|
|
|
|
#include <pk11/site.h>
|
|
|
|
#include <ctype.h>
|
|
#include <inttypes.h>
|
|
#include <stdbool.h>
|
|
|
|
#include <isc/mem.h>
|
|
#include <isc/safe.h>
|
|
#include <isc/string.h>
|
|
#include <isc/util.h>
|
|
|
|
#include <dst/result.h>
|
|
|
|
#include <openssl/opensslv.h>
|
|
|
|
#include "dst_internal.h"
|
|
#include "dst_openssl.h"
|
|
#include "dst_parse.h"
|
|
|
|
#define PRIME2 "02"
|
|
|
|
#define PRIME768 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088" \
|
|
"A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25" \
|
|
"F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF"
|
|
|
|
#define PRIME1024 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" \
|
|
"8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF2" \
|
|
"5F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406" \
|
|
"B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF"
|
|
|
|
#define PRIME1536 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \
|
|
"29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \
|
|
"EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \
|
|
"E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
|
|
"EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \
|
|
"C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \
|
|
"83655D23DCA3AD961C62F356208552BB9ED529077096966D" \
|
|
"670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF"
|
|
|
|
|
|
static isc_result_t openssldh_todns(const dst_key_t *key, isc_buffer_t *data);
|
|
|
|
static BIGNUM *bn2 = NULL, *bn768 = NULL, *bn1024 = NULL, *bn1536 = NULL;
|
|
|
|
#if !HAVE_DH_GET0_KEY
|
|
/*
|
|
* DH_get0_key, DH_set0_key, DH_get0_pqg and DH_set0_pqg
|
|
* are from OpenSSL 1.1.0.
|
|
*/
|
|
static void
|
|
DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key) {
|
|
if (pub_key != NULL) {
|
|
*pub_key = dh->pub_key;
|
|
}
|
|
if (priv_key != NULL) {
|
|
*priv_key = dh->priv_key;
|
|
}
|
|
}
|
|
|
|
static int
|
|
DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key) {
|
|
if (pub_key != NULL) {
|
|
BN_free(dh->pub_key);
|
|
dh->pub_key = pub_key;
|
|
}
|
|
|
|
if (priv_key != NULL) {
|
|
BN_free(dh->priv_key);
|
|
dh->priv_key = priv_key;
|
|
}
|
|
|
|
return (1);
|
|
}
|
|
|
|
static void
|
|
DH_get0_pqg(const DH *dh,
|
|
const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
|
|
{
|
|
if (p != NULL) {
|
|
*p = dh->p;
|
|
}
|
|
if (q != NULL) {
|
|
*q = dh->q;
|
|
}
|
|
if (g != NULL) {
|
|
*g = dh->g;
|
|
}
|
|
}
|
|
|
|
static int
|
|
DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
|
|
{
|
|
/* If the fields p and g in d are NULL, the corresponding input
|
|
* parameters MUST be non-NULL. q may remain NULL.
|
|
*/
|
|
if ((dh->p == NULL && p == NULL)
|
|
|| (dh->g == NULL && g == NULL))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (p != NULL) {
|
|
BN_free(dh->p);
|
|
dh->p = p;
|
|
}
|
|
if (q != NULL) {
|
|
BN_free(dh->q);
|
|
dh->q = q;
|
|
}
|
|
if (g != NULL) {
|
|
BN_free(dh->g);
|
|
dh->g = g;
|
|
}
|
|
|
|
if (q != NULL) {
|
|
dh->length = BN_num_bits(q);
|
|
}
|
|
|
|
return (1);
|
|
}
|
|
|
|
#define DH_clear_flags(d, f) (d)->flags &= ~(f)
|
|
|
|
#endif /* !HAVE_DH_GET0_KEY */
|
|
|
|
static isc_result_t
|
|
openssldh_computesecret(const dst_key_t *pub, const dst_key_t *priv,
|
|
isc_buffer_t *secret)
|
|
{
|
|
DH *dhpub, *dhpriv;
|
|
const BIGNUM *pub_key = NULL;
|
|
int ret;
|
|
isc_region_t r;
|
|
unsigned int len;
|
|
|
|
REQUIRE(pub->keydata.dh != NULL);
|
|
REQUIRE(priv->keydata.dh != NULL);
|
|
|
|
dhpub = pub->keydata.dh;
|
|
dhpriv = priv->keydata.dh;
|
|
|
|
len = DH_size(dhpriv);
|
|
isc_buffer_availableregion(secret, &r);
|
|
if (r.length < len)
|
|
return (ISC_R_NOSPACE);
|
|
|
|
DH_get0_key(dhpub, &pub_key, NULL);
|
|
ret = DH_compute_key(r.base, pub_key, dhpriv);
|
|
if (ret <= 0)
|
|
return (dst__openssl_toresult2("DH_compute_key",
|
|
DST_R_COMPUTESECRETFAILURE));
|
|
isc_buffer_add(secret, len);
|
|
return (ISC_R_SUCCESS);
|
|
}
|
|
|
|
static bool
|
|
openssldh_compare(const dst_key_t *key1, const dst_key_t *key2) {
|
|
DH *dh1, *dh2;
|
|
const BIGNUM *pub_key1 = NULL, *pub_key2 = NULL;
|
|
const BIGNUM *priv_key1 = NULL, *priv_key2 = NULL;
|
|
const BIGNUM *p1 = NULL, *g1 = NULL, *p2 = NULL, *g2 = NULL;
|
|
|
|
dh1 = key1->keydata.dh;
|
|
dh2 = key2->keydata.dh;
|
|
|
|
if (dh1 == NULL && dh2 == NULL)
|
|
return (true);
|
|
else if (dh1 == NULL || dh2 == NULL)
|
|
return (false);
|
|
|
|
DH_get0_key(dh1, &pub_key1, &priv_key1);
|
|
DH_get0_key(dh2, &pub_key2, &priv_key2);
|
|
DH_get0_pqg(dh1, &p1, NULL, &g1);
|
|
DH_get0_pqg(dh2, &p2, NULL, &g2);
|
|
|
|
if (BN_cmp(p1, p2) != 0 || BN_cmp(g1, g2) != 0 ||
|
|
BN_cmp(pub_key1, pub_key2) != 0)
|
|
return (false);
|
|
|
|
if (priv_key1 != NULL || priv_key2 != NULL) {
|
|
if (priv_key1 == NULL || priv_key2 == NULL)
|
|
return (false);
|
|
if (BN_cmp(priv_key1, priv_key2) != 0)
|
|
return (false);
|
|
}
|
|
return (true);
|
|
}
|
|
|
|
static bool
|
|
openssldh_paramcompare(const dst_key_t *key1, const dst_key_t *key2) {
|
|
DH *dh1, *dh2;
|
|
const BIGNUM *p1 = NULL, *g1 = NULL, *p2 = NULL, *g2 = NULL;
|
|
|
|
dh1 = key1->keydata.dh;
|
|
dh2 = key2->keydata.dh;
|
|
|
|
if (dh1 == NULL && dh2 == NULL)
|
|
return (true);
|
|
else if (dh1 == NULL || dh2 == NULL)
|
|
return (false);
|
|
|
|
DH_get0_pqg(dh1, &p1, NULL, &g1);
|
|
DH_get0_pqg(dh2, &p2, NULL, &g2);
|
|
|
|
if (BN_cmp(p1, p2) != 0 || BN_cmp(g1, g2) != 0)
|
|
return (false);
|
|
return (true);
|
|
}
|
|
|
|
static int
|
|
progress_cb(int p, int n, BN_GENCB *cb) {
|
|
union {
|
|
void *dptr;
|
|
void (*fptr)(int);
|
|
} u;
|
|
|
|
UNUSED(n);
|
|
|
|
/* cppcheck-suppress unreadVariable */
|
|
u.dptr = BN_GENCB_get_arg(cb);
|
|
if (u.fptr != NULL)
|
|
u.fptr(p);
|
|
return (1);
|
|
}
|
|
|
|
static isc_result_t
|
|
openssldh_generate(dst_key_t *key, int generator, void (*callback)(int)) {
|
|
DH *dh = NULL;
|
|
BN_GENCB *cb;
|
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
|
|
BN_GENCB _cb;
|
|
#endif
|
|
union {
|
|
void *dptr;
|
|
void (*fptr)(int);
|
|
} u;
|
|
|
|
if (generator == 0) {
|
|
if (key->key_size == 768 ||
|
|
key->key_size == 1024 ||
|
|
key->key_size == 1536)
|
|
{
|
|
BIGNUM *p, *g;
|
|
dh = DH_new();
|
|
if (key->key_size == 768)
|
|
p = BN_dup(bn768);
|
|
else if (key->key_size == 1024)
|
|
p = BN_dup(bn1024);
|
|
else
|
|
p = BN_dup(bn1536);
|
|
g = BN_dup(bn2);
|
|
if (dh == NULL || p == NULL || g == NULL) {
|
|
if (dh != NULL)
|
|
DH_free(dh);
|
|
if (p != NULL)
|
|
BN_free(p);
|
|
if (g != NULL)
|
|
BN_free(g);
|
|
return (dst__openssl_toresult(ISC_R_NOMEMORY));
|
|
}
|
|
DH_set0_pqg(dh, p, NULL, g);
|
|
} else
|
|
generator = 2;
|
|
}
|
|
|
|
if (generator != 0) {
|
|
dh = DH_new();
|
|
if (dh == NULL)
|
|
return (dst__openssl_toresult(ISC_R_NOMEMORY));
|
|
cb = BN_GENCB_new();
|
|
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
|
|
if (cb == NULL) {
|
|
DH_free(dh);
|
|
return (dst__openssl_toresult(ISC_R_NOMEMORY));
|
|
}
|
|
#endif
|
|
if (callback == NULL) {
|
|
BN_GENCB_set_old(cb, NULL, NULL);
|
|
} else {
|
|
/* cppcheck-suppress unreadVariable */
|
|
u.fptr = callback;
|
|
BN_GENCB_set(cb, progress_cb, u.dptr);
|
|
}
|
|
|
|
if (!DH_generate_parameters_ex(dh, key->key_size, generator,
|
|
cb)) {
|
|
DH_free(dh);
|
|
BN_GENCB_free(cb);
|
|
return (dst__openssl_toresult2(
|
|
"DH_generate_parameters_ex",
|
|
DST_R_OPENSSLFAILURE));
|
|
}
|
|
BN_GENCB_free(cb);
|
|
cb = NULL;
|
|
}
|
|
|
|
if (DH_generate_key(dh) == 0) {
|
|
DH_free(dh);
|
|
return (dst__openssl_toresult2("DH_generate_key",
|
|
DST_R_OPENSSLFAILURE));
|
|
}
|
|
DH_clear_flags(dh, DH_FLAG_CACHE_MONT_P);
|
|
key->keydata.dh = dh;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
}
|
|
|
|
static bool
|
|
openssldh_isprivate(const dst_key_t *key) {
|
|
DH *dh = key->keydata.dh;
|
|
const BIGNUM *priv_key = NULL;
|
|
|
|
DH_get0_key(dh, NULL, &priv_key);
|
|
return (dh != NULL && priv_key != NULL);
|
|
}
|
|
|
|
static void
|
|
openssldh_destroy(dst_key_t *key) {
|
|
DH *dh = key->keydata.dh;
|
|
|
|
if (dh == NULL)
|
|
return;
|
|
|
|
DH_free(dh);
|
|
key->keydata.dh = NULL;
|
|
}
|
|
|
|
static void
|
|
uint16_toregion(uint16_t val, isc_region_t *region) {
|
|
*region->base = (val & 0xff00) >> 8;
|
|
isc_region_consume(region, 1);
|
|
*region->base = (val & 0x00ff);
|
|
isc_region_consume(region, 1);
|
|
}
|
|
|
|
static uint16_t
|
|
uint16_fromregion(isc_region_t *region) {
|
|
uint16_t val;
|
|
unsigned char *cp = region->base;
|
|
|
|
val = ((unsigned int)(cp[0])) << 8;
|
|
val |= ((unsigned int)(cp[1]));
|
|
|
|
isc_region_consume(region, 2);
|
|
|
|
return (val);
|
|
}
|
|
|
|
static isc_result_t
|
|
openssldh_todns(const dst_key_t *key, isc_buffer_t *data) {
|
|
DH *dh;
|
|
const BIGNUM *pub_key = NULL, *p = NULL, *g = NULL;
|
|
isc_region_t r;
|
|
uint16_t dnslen, plen, glen, publen;
|
|
|
|
REQUIRE(key->keydata.dh != NULL);
|
|
|
|
dh = key->keydata.dh;
|
|
|
|
isc_buffer_availableregion(data, &r);
|
|
|
|
DH_get0_pqg(dh, &p, NULL, &g);
|
|
if (BN_cmp(g, bn2) == 0 &&
|
|
(BN_cmp(p, bn768) == 0 ||
|
|
BN_cmp(p, bn1024) == 0 ||
|
|
BN_cmp(p, bn1536) == 0)) {
|
|
plen = 1;
|
|
glen = 0;
|
|
}
|
|
else {
|
|
plen = BN_num_bytes(p);
|
|
glen = BN_num_bytes(g);
|
|
}
|
|
DH_get0_key(dh, &pub_key, NULL);
|
|
publen = BN_num_bytes(pub_key);
|
|
dnslen = plen + glen + publen + 6;
|
|
if (r.length < (unsigned int) dnslen)
|
|
return (ISC_R_NOSPACE);
|
|
|
|
uint16_toregion(plen, &r);
|
|
if (plen == 1) {
|
|
if (BN_cmp(p, bn768) == 0)
|
|
*r.base = 1;
|
|
else if (BN_cmp(p, bn1024) == 0)
|
|
*r.base = 2;
|
|
else
|
|
*r.base = 3;
|
|
} else
|
|
BN_bn2bin(p, r.base);
|
|
isc_region_consume(&r, plen);
|
|
|
|
uint16_toregion(glen, &r);
|
|
if (glen > 0)
|
|
BN_bn2bin(g, r.base);
|
|
isc_region_consume(&r, glen);
|
|
|
|
uint16_toregion(publen, &r);
|
|
BN_bn2bin(pub_key, r.base);
|
|
isc_region_consume(&r, publen);
|
|
|
|
isc_buffer_add(data, dnslen);
|
|
|
|
return (ISC_R_SUCCESS);
|
|
}
|
|
|
|
static isc_result_t
|
|
openssldh_fromdns(dst_key_t *key, isc_buffer_t *data) {
|
|
DH *dh;
|
|
BIGNUM *pub_key = NULL, *p = NULL, *g = NULL;
|
|
isc_region_t r;
|
|
uint16_t plen, glen, publen;
|
|
int special = 0;
|
|
|
|
isc_buffer_remainingregion(data, &r);
|
|
if (r.length == 0)
|
|
return (ISC_R_SUCCESS);
|
|
|
|
dh = DH_new();
|
|
if (dh == NULL)
|
|
return (dst__openssl_toresult(ISC_R_NOMEMORY));
|
|
DH_clear_flags(dh, DH_FLAG_CACHE_MONT_P);
|
|
|
|
/*
|
|
* Read the prime length. 1 & 2 are table entries, > 16 means a
|
|
* prime follows, otherwise an error.
|
|
*/
|
|
if (r.length < 2) {
|
|
DH_free(dh);
|
|
return (DST_R_INVALIDPUBLICKEY);
|
|
}
|
|
plen = uint16_fromregion(&r);
|
|
if (plen < 16 && plen != 1 && plen != 2) {
|
|
DH_free(dh);
|
|
return (DST_R_INVALIDPUBLICKEY);
|
|
}
|
|
if (r.length < plen) {
|
|
DH_free(dh);
|
|
return (DST_R_INVALIDPUBLICKEY);
|
|
}
|
|
if (plen == 1 || plen == 2) {
|
|
if (plen == 1) {
|
|
special = *r.base;
|
|
isc_region_consume(&r, 1);
|
|
} else {
|
|
special = uint16_fromregion(&r);
|
|
}
|
|
switch (special) {
|
|
case 1:
|
|
p = BN_dup(bn768);
|
|
break;
|
|
case 2:
|
|
p = BN_dup(bn1024);
|
|
break;
|
|
case 3:
|
|
p = BN_dup(bn1536);
|
|
break;
|
|
default:
|
|
DH_free(dh);
|
|
return (DST_R_INVALIDPUBLICKEY);
|
|
}
|
|
} else {
|
|
p = BN_bin2bn(r.base, plen, NULL);
|
|
isc_region_consume(&r, plen);
|
|
}
|
|
|
|
/*
|
|
* Read the generator length. This should be 0 if the prime was
|
|
* special, but it might not be. If it's 0 and the prime is not
|
|
* special, we have a problem.
|
|
*/
|
|
if (r.length < 2) {
|
|
DH_free(dh);
|
|
return (DST_R_INVALIDPUBLICKEY);
|
|
}
|
|
glen = uint16_fromregion(&r);
|
|
if (r.length < glen) {
|
|
DH_free(dh);
|
|
return (DST_R_INVALIDPUBLICKEY);
|
|
}
|
|
if (special != 0) {
|
|
if (glen == 0)
|
|
g = BN_dup(bn2);
|
|
else {
|
|
g = BN_bin2bn(r.base, glen, NULL);
|
|
if (g != NULL && BN_cmp(g, bn2) != 0) {
|
|
DH_free(dh);
|
|
BN_free(g);
|
|
return (DST_R_INVALIDPUBLICKEY);
|
|
}
|
|
}
|
|
} else {
|
|
if (glen == 0) {
|
|
DH_free(dh);
|
|
return (DST_R_INVALIDPUBLICKEY);
|
|
}
|
|
g = BN_bin2bn(r.base, glen, NULL);
|
|
}
|
|
isc_region_consume(&r, glen);
|
|
|
|
if (p == NULL || g == NULL) {
|
|
DH_free(dh);
|
|
if (p != NULL)
|
|
BN_free(p);
|
|
if (g != NULL)
|
|
BN_free(g);
|
|
return (dst__openssl_toresult(ISC_R_NOMEMORY));
|
|
}
|
|
DH_set0_pqg(dh, p, NULL, g);
|
|
|
|
if (r.length < 2) {
|
|
DH_free(dh);
|
|
return (DST_R_INVALIDPUBLICKEY);
|
|
}
|
|
publen = uint16_fromregion(&r);
|
|
if (r.length < publen) {
|
|
DH_free(dh);
|
|
return (DST_R_INVALIDPUBLICKEY);
|
|
}
|
|
pub_key = BN_bin2bn(r.base, publen, NULL);
|
|
if (pub_key == NULL) {
|
|
DH_free(dh);
|
|
return (dst__openssl_toresult(ISC_R_NOMEMORY));
|
|
}
|
|
#if (LIBRESSL_VERSION_NUMBER >= 0x2070000fL) && (LIBRESSL_VERSION_NUMBER <= 0x2070200fL)
|
|
/*
|
|
* LibreSSL << 2.7.3 DH_get0_key requires priv_key to be set when
|
|
* DH structure is empty, hence we cannot use DH_get0_key().
|
|
*/
|
|
dh->pub_key = pub_key;
|
|
#else /* LIBRESSL_VERSION_NUMBER */
|
|
DH_set0_key(dh, pub_key, NULL);
|
|
#endif /* LIBRESSL_VERSION_NUMBER */
|
|
isc_region_consume(&r, publen);
|
|
|
|
key->key_size = BN_num_bits(p);
|
|
|
|
isc_buffer_forward(data, plen + glen + publen + 6);
|
|
|
|
key->keydata.dh = dh;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
}
|
|
|
|
static isc_result_t
|
|
openssldh_tofile(const dst_key_t *key, const char *directory) {
|
|
int i;
|
|
DH *dh;
|
|
const BIGNUM *pub_key = NULL, *priv_key = NULL, *p = NULL, *g = NULL;
|
|
dst_private_t priv;
|
|
unsigned char *bufs[4];
|
|
isc_result_t result;
|
|
|
|
if (key->keydata.dh == NULL)
|
|
return (DST_R_NULLKEY);
|
|
|
|
if (key->external)
|
|
return (DST_R_EXTERNALKEY);
|
|
|
|
dh = key->keydata.dh;
|
|
DH_get0_key(dh, &pub_key, &priv_key);
|
|
DH_get0_pqg(dh, &p, NULL, &g);
|
|
|
|
memset(bufs, 0, sizeof(bufs));
|
|
for (i = 0; i < 4; i++) {
|
|
bufs[i] = isc_mem_get(key->mctx, BN_num_bytes(p));
|
|
}
|
|
|
|
i = 0;
|
|
|
|
priv.elements[i].tag = TAG_DH_PRIME;
|
|
priv.elements[i].length = BN_num_bytes(p);
|
|
BN_bn2bin(p, bufs[i]);
|
|
priv.elements[i].data = bufs[i];
|
|
i++;
|
|
|
|
priv.elements[i].tag = TAG_DH_GENERATOR;
|
|
priv.elements[i].length = BN_num_bytes(g);
|
|
BN_bn2bin(g, bufs[i]);
|
|
priv.elements[i].data = bufs[i];
|
|
i++;
|
|
|
|
priv.elements[i].tag = TAG_DH_PRIVATE;
|
|
priv.elements[i].length = BN_num_bytes(priv_key);
|
|
BN_bn2bin(priv_key, bufs[i]);
|
|
priv.elements[i].data = bufs[i];
|
|
i++;
|
|
|
|
priv.elements[i].tag = TAG_DH_PUBLIC;
|
|
priv.elements[i].length = BN_num_bytes(pub_key);
|
|
BN_bn2bin(pub_key, bufs[i]);
|
|
priv.elements[i].data = bufs[i];
|
|
i++;
|
|
|
|
priv.nelements = i;
|
|
result = dst__privstruct_writefile(key, &priv, directory);
|
|
|
|
for (i = 0; i < 4; i++) {
|
|
if (bufs[i] == NULL)
|
|
break;
|
|
isc_mem_put(key->mctx, bufs[i], BN_num_bytes(p));
|
|
}
|
|
return (result);
|
|
}
|
|
|
|
static isc_result_t
|
|
openssldh_parse(dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) {
|
|
dst_private_t priv;
|
|
isc_result_t ret;
|
|
int i;
|
|
DH *dh = NULL;
|
|
BIGNUM *pub_key = NULL, *priv_key = NULL, *p = NULL, *g = NULL;
|
|
isc_mem_t *mctx;
|
|
#define DST_RET(a) {ret = a; goto err;}
|
|
|
|
UNUSED(pub);
|
|
mctx = key->mctx;
|
|
|
|
/* read private key file */
|
|
ret = dst__privstruct_parse(key, DST_ALG_DH, lexer, mctx, &priv);
|
|
if (ret != ISC_R_SUCCESS)
|
|
return (ret);
|
|
|
|
if (key->external)
|
|
DST_RET(DST_R_EXTERNALKEY);
|
|
|
|
dh = DH_new();
|
|
if (dh == NULL)
|
|
DST_RET(ISC_R_NOMEMORY);
|
|
DH_clear_flags(dh, DH_FLAG_CACHE_MONT_P);
|
|
key->keydata.dh = dh;
|
|
|
|
for (i = 0; i < priv.nelements; i++) {
|
|
BIGNUM *bn;
|
|
bn = BN_bin2bn(priv.elements[i].data,
|
|
priv.elements[i].length, NULL);
|
|
if (bn == NULL)
|
|
DST_RET(ISC_R_NOMEMORY);
|
|
|
|
switch (priv.elements[i].tag) {
|
|
case TAG_DH_PRIME:
|
|
p = bn;
|
|
break;
|
|
case TAG_DH_GENERATOR:
|
|
g = bn;
|
|
break;
|
|
case TAG_DH_PRIVATE:
|
|
priv_key = bn;
|
|
break;
|
|
case TAG_DH_PUBLIC:
|
|
pub_key = bn;
|
|
break;
|
|
}
|
|
}
|
|
dst__privstruct_free(&priv, mctx);
|
|
DH_set0_key(dh, pub_key, priv_key);
|
|
DH_set0_pqg(dh, p, NULL, g);
|
|
|
|
key->key_size = BN_num_bits(p);
|
|
return (ISC_R_SUCCESS);
|
|
|
|
err:
|
|
if (p != NULL)
|
|
BN_free(p);
|
|
if (g != NULL)
|
|
BN_free(g);
|
|
if (pub_key != NULL)
|
|
BN_free(pub_key);
|
|
if (priv_key != NULL)
|
|
BN_free(priv_key);
|
|
openssldh_destroy(key);
|
|
dst__privstruct_free(&priv, mctx);
|
|
isc_safe_memwipe(&priv, sizeof(priv));
|
|
return (ret);
|
|
}
|
|
|
|
static void
|
|
openssldh_cleanup(void) {
|
|
BN_free(bn2);
|
|
bn2 = NULL;
|
|
|
|
BN_free(bn768);
|
|
bn768 = NULL;
|
|
|
|
BN_free(bn1024);
|
|
bn1024 = NULL;
|
|
|
|
BN_free(bn1536);
|
|
bn1536 = NULL;
|
|
}
|
|
|
|
static dst_func_t openssldh_functions = {
|
|
NULL, /*%< createctx */
|
|
NULL, /*%< createctx2 */
|
|
NULL, /*%< destroyctx */
|
|
NULL, /*%< adddata */
|
|
NULL, /*%< openssldh_sign */
|
|
NULL, /*%< openssldh_verify */
|
|
NULL, /*%< openssldh_verify2 */
|
|
openssldh_computesecret,
|
|
openssldh_compare,
|
|
openssldh_paramcompare,
|
|
openssldh_generate,
|
|
openssldh_isprivate,
|
|
openssldh_destroy,
|
|
openssldh_todns,
|
|
openssldh_fromdns,
|
|
openssldh_tofile,
|
|
openssldh_parse,
|
|
openssldh_cleanup,
|
|
NULL, /*%< fromlabel */
|
|
NULL, /*%< dump */
|
|
NULL, /*%< restore */
|
|
};
|
|
|
|
isc_result_t
|
|
dst__openssldh_init(dst_func_t **funcp) {
|
|
REQUIRE(funcp != NULL);
|
|
if (*funcp == NULL) {
|
|
if (BN_hex2bn(&bn2, PRIME2) == 0 || bn2 == NULL) {
|
|
goto cleanup;
|
|
}
|
|
if (BN_hex2bn(&bn768, PRIME768) == 0 || bn768 == NULL) {
|
|
goto cleanup;
|
|
}
|
|
if (BN_hex2bn(&bn1024, PRIME1024) == 0 || bn1024 == NULL) {
|
|
goto cleanup;
|
|
}
|
|
if (BN_hex2bn(&bn1536, PRIME1536) == 0 || bn1536 == NULL) {
|
|
goto cleanup;
|
|
}
|
|
*funcp = &openssldh_functions;
|
|
}
|
|
return (ISC_R_SUCCESS);
|
|
|
|
cleanup:
|
|
if (bn2 != NULL) BN_free(bn2);
|
|
if (bn768 != NULL) BN_free(bn768);
|
|
if (bn1024 != NULL) BN_free(bn1024);
|
|
if (bn1536 != NULL) BN_free(bn1536);
|
|
return (ISC_R_NOMEMORY);
|
|
}
|