openssldh_link.c revision 40f53fa8d9c6a4fc38c0014495e7a42b08f52481
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt/*
b68401ccae92ee0e92c699a10d28ce44badbc4aaTinderbox User * Portions Copyright (C) 1999, 2000 Internet Software Consortium.
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews *
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * Permission to use, copy, modify, and distribute this software for any
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * purpose with or without fee is hereby granted, provided that the above
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt * copyright notice and this permission notice appear in all copies.
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt *
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM AND
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt * NETWORK ASSOCIATES DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt * SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt * FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE CONSORTIUM OR NETWORK
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt * ASSOCIATES BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews * PERFORMANCE OF THIS SOFTWARE.
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt */
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt/*
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt * Principal Author: Brian Wellington
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt * $Id: openssldh_link.c,v 1.27 2000/08/01 01:27:54 tale Exp $
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt */
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt#if defined(OPENSSL)
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt#include <config.h>
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt#include <ctype.h>
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt#include <isc/string.h>
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt#include <isc/util.h>
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt#include <dst/result.h>
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt#include "dst_internal.h"
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt#include "dst_parse.h"
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt#include <openssl/dh.h>
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt#define PRIME768 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088" \
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt "A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25" \
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt "F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF"
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt#define PRIME1024 "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" \
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF2" \
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt "5F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406" \
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt "B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF"
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Huntstatic isc_result_t openssldh_todns(const dst_key_t *key, isc_buffer_t *data);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Huntstatic BIGNUM bn2, bn768, bn1024;
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Huntstatic isc_result_t
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Huntopenssldh_computesecret(const dst_key_t *pub, const dst_key_t *priv,
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt isc_buffer_t *secret)
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt{
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt DH *dhpub, *dhpriv;
b454c0319685041db3f3e8fd7671e1b364fd20c5Evan Hunt int ret;
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt isc_region_t r;
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt unsigned int len;
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt REQUIRE(pub->opaque != NULL);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt REQUIRE(priv->opaque != NULL);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt dhpub = (DH *) pub->opaque;
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt dhpriv = (DH *) priv->opaque;
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt len = DH_size(dhpriv);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt isc_buffer_availableregion(secret, &r);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt if (r.length < len)
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt return (ISC_R_NOSPACE);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt ret = DH_compute_key(r.base, dhpub->pub_key, dhpriv);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt if (ret == 0)
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt return (DST_R_COMPUTESECRETFAILURE);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt isc_buffer_add(secret, len);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt return (ISC_R_SUCCESS);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt}
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Huntstatic isc_boolean_t
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Huntopenssldh_compare(const dst_key_t *key1, const dst_key_t *key2) {
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt int status;
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt DH *dh1, *dh2;
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt dh1 = (DH *) key1->opaque;
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt dh2 = (DH *) key2->opaque;
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt if (dh1 == NULL && dh2 == NULL)
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt return (ISC_TRUE);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt else if (dh1 == NULL || dh2 == NULL)
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt return (ISC_FALSE);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt status = BN_cmp(dh1->p, dh2->p) ||
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt BN_cmp(dh1->g, dh2->g) ||
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt BN_cmp(dh1->pub_key, dh2->pub_key);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt if (status != 0)
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt return (ISC_FALSE);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt if (dh1->priv_key != NULL || dh2->priv_key != NULL) {
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt if (dh1->priv_key == NULL || dh2->priv_key == NULL)
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt return (ISC_FALSE);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt if (BN_cmp(dh1->priv_key, dh2->priv_key) != 0)
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt return (ISC_FALSE);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt }
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt return (ISC_TRUE);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt}
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Huntstatic isc_boolean_t
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Huntopenssldh_paramcompare(const dst_key_t *key1, const dst_key_t *key2) {
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt int status;
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt DH *dh1, *dh2;
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt dh1 = (DH *) key1->opaque;
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt dh2 = (DH *) key2->opaque;
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt if (dh1 == NULL && dh2 == NULL)
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt return (ISC_TRUE);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt else if (dh1 == NULL || dh2 == NULL)
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt return (ISC_FALSE);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt status = BN_cmp(dh1->p, dh2->p) ||
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt BN_cmp(dh1->g, dh2->g);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt if (status != 0)
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt return (ISC_FALSE);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt return (ISC_TRUE);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt}
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Huntstatic isc_result_t
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Huntopenssldh_generate(dst_key_t *key, int generator) {
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt DH *dh = NULL;
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt unsigned char dns_array[DST_KEY_MAXSIZE];
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt isc_buffer_t dns;
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt isc_region_t r;
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt isc_result_t result;
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt if (generator == 0) {
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt if (key->key_size == 768 || key->key_size == 1024) {
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews dh = DH_new();
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews if (dh == NULL)
3525200d9fb0e70aec4f6a3c7e0ed5a7dd8398afEvan Hunt return (ISC_R_NOMEMORY);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews if (key->key_size == 768)
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews dh->p = &bn768;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews else
3525200d9fb0e70aec4f6a3c7e0ed5a7dd8398afEvan Hunt dh->p = &bn1024;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews dh->g = &bn2;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews }
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews else
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews generator = 2;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews }
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews if (generator != 0)
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews dh = DH_generate_parameters(key->key_size, generator,
3525200d9fb0e70aec4f6a3c7e0ed5a7dd8398afEvan Hunt NULL, NULL);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews if (dh == NULL)
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews return (DST_R_INVALIDPARAM);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews
2cf0fe3b8092f64f8f68ae3693fe2e73e90ad1a4Mark Andrews if (DH_generate_key(dh) == 0) {
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews DH_free(dh);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews return (ISC_R_NOMEMORY);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews }
2cf0fe3b8092f64f8f68ae3693fe2e73e90ad1a4Mark Andrews
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews key->opaque = dh;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews isc_buffer_init(&dns, dns_array, sizeof(dns_array));
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews result = openssldh_todns(key, &dns);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews if (result != ISC_R_SUCCESS) {
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews DH_free(dh);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews return (result);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews }
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews isc_buffer_usedregion(&dns, &r);
3525200d9fb0e70aec4f6a3c7e0ed5a7dd8398afEvan Hunt key->key_id = dst_region_computeid(&r);
3525200d9fb0e70aec4f6a3c7e0ed5a7dd8398afEvan Hunt
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews return (ISC_R_SUCCESS);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews}
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrewsstatic isc_boolean_t
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrewsopenssldh_isprivate(const dst_key_t *key) {
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews DH *dh = (DH *) key->opaque;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews return (ISC_TF(dh != NULL && dh->priv_key != NULL));
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews}
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrewsstatic void
3525200d9fb0e70aec4f6a3c7e0ed5a7dd8398afEvan Huntopenssldh_destroy(dst_key_t *key) {
3525200d9fb0e70aec4f6a3c7e0ed5a7dd8398afEvan Hunt DH *dh = key->opaque;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews if (dh == NULL)
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews return;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews if (dh->p == &bn768 || dh->p == &bn1024)
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews dh->p = NULL;
02ceed9f83f82f0de35c7bd73c27a33d4f0fe9cbMark Andrews if (dh->g == &bn2)
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews dh->g = NULL;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews DH_free(dh);
02ceed9f83f82f0de35c7bd73c27a33d4f0fe9cbMark Andrews}
02ceed9f83f82f0de35c7bd73c27a33d4f0fe9cbMark Andrews
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrewsstatic void
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrewsuint16_toregion(isc_uint16_t val, isc_region_t *region) {
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews *region->base++ = (val & 0xff00) >> 8;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews *region->base++ = (val & 0x00ff);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews}
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews
02ceed9f83f82f0de35c7bd73c27a33d4f0fe9cbMark Andrewsstatic isc_uint16_t
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrewsuint16_fromregion(isc_region_t *region) {
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews isc_uint16_t val;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews unsigned char *cp = region->base;
02ceed9f83f82f0de35c7bd73c27a33d4f0fe9cbMark Andrews
02ceed9f83f82f0de35c7bd73c27a33d4f0fe9cbMark Andrews val = ((unsigned int)(cp[0])) << 8;
02ceed9f83f82f0de35c7bd73c27a33d4f0fe9cbMark Andrews val |= ((unsigned int)(cp[1]));
02ceed9f83f82f0de35c7bd73c27a33d4f0fe9cbMark Andrews
02ceed9f83f82f0de35c7bd73c27a33d4f0fe9cbMark Andrews region->base += 2;
02ceed9f83f82f0de35c7bd73c27a33d4f0fe9cbMark Andrews return (val);
02ceed9f83f82f0de35c7bd73c27a33d4f0fe9cbMark Andrews}
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrewsstatic isc_result_t
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrewsopenssldh_todns(const dst_key_t *key, isc_buffer_t *data) {
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews DH *dh;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews isc_region_t r;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews isc_uint16_t dnslen, plen, glen, publen;
02ceed9f83f82f0de35c7bd73c27a33d4f0fe9cbMark Andrews
02ceed9f83f82f0de35c7bd73c27a33d4f0fe9cbMark Andrews REQUIRE(key->opaque != NULL);
02ceed9f83f82f0de35c7bd73c27a33d4f0fe9cbMark Andrews
02ceed9f83f82f0de35c7bd73c27a33d4f0fe9cbMark Andrews dh = (DH *) key->opaque;
02ceed9f83f82f0de35c7bd73c27a33d4f0fe9cbMark Andrews
02ceed9f83f82f0de35c7bd73c27a33d4f0fe9cbMark Andrews isc_buffer_availableregion(data, &r);
02ceed9f83f82f0de35c7bd73c27a33d4f0fe9cbMark Andrews
02ceed9f83f82f0de35c7bd73c27a33d4f0fe9cbMark Andrews if (dh->g == &bn2 && (dh->p == &bn768 || dh->p == &bn1024)) {
02ceed9f83f82f0de35c7bd73c27a33d4f0fe9cbMark Andrews plen = 1;
02ceed9f83f82f0de35c7bd73c27a33d4f0fe9cbMark Andrews glen = 0;
02ceed9f83f82f0de35c7bd73c27a33d4f0fe9cbMark Andrews }
02ceed9f83f82f0de35c7bd73c27a33d4f0fe9cbMark Andrews else {
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews plen = BN_num_bytes(dh->p);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews glen = BN_num_bytes(dh->g);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews }
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews publen = BN_num_bytes(dh->pub_key);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews dnslen = plen + glen + publen + 6;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews if (r.length < (unsigned int) dnslen)
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews return (ISC_R_NOSPACE);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews uint16_toregion(plen, &r);
3525200d9fb0e70aec4f6a3c7e0ed5a7dd8398afEvan Hunt if (plen == 1) {
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews if (dh->p == &bn768)
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews *r.base = 1;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews else
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews *r.base = 2;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews }
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews else
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews BN_bn2bin(dh->p, r.base);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews r.base += plen;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews
02ceed9f83f82f0de35c7bd73c27a33d4f0fe9cbMark Andrews uint16_toregion(glen, &r);
02ceed9f83f82f0de35c7bd73c27a33d4f0fe9cbMark Andrews if (glen > 0)
02ceed9f83f82f0de35c7bd73c27a33d4f0fe9cbMark Andrews BN_bn2bin(dh->g, r.base);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews r.base += glen;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews uint16_toregion(publen, &r);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews BN_bn2bin(dh->pub_key, r.base);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews r.base += publen;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews isc_buffer_add(data, dnslen);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews return (ISC_R_SUCCESS);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews}
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrewsstatic isc_result_t
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrewsopenssldh_fromdns(dst_key_t *key, isc_buffer_t *data) {
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews DH *dh;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews isc_region_t r;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews isc_uint16_t plen, glen, publen;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews int special = 0;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews isc_buffer_remainingregion(data, &r);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews if (r.length == 0)
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews return (ISC_R_SUCCESS);
3525200d9fb0e70aec4f6a3c7e0ed5a7dd8398afEvan Hunt
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews dh = DH_new();
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews if (dh == NULL)
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews return (ISC_R_NOMEMORY);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews
3525200d9fb0e70aec4f6a3c7e0ed5a7dd8398afEvan Hunt /*
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews * Read the prime length. 1 & 2 are table entries, > 16 means a
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews * prime follows, otherwise an error.
3525200d9fb0e70aec4f6a3c7e0ed5a7dd8398afEvan Hunt */
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews if (r.length < 2) {
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews DH_free(dh);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews return (DST_R_INVALIDPUBLICKEY);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews }
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews plen = uint16_fromregion(&r);
3525200d9fb0e70aec4f6a3c7e0ed5a7dd8398afEvan Hunt if (plen < 16 && plen != 1 && plen != 2) {
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews DH_free(dh);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews return (DST_R_INVALIDPUBLICKEY);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews }
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews if (r.length < plen) {
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews DH_free(dh);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews return (DST_R_INVALIDPUBLICKEY);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews }
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews if (plen == 1 || plen == 2) {
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews if (plen == 1)
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews special = *r.base++;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews else
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews special = uint16_fromregion(&r);
02ceed9f83f82f0de35c7bd73c27a33d4f0fe9cbMark Andrews switch (special) {
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews case 1:
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews dh->p = &bn768;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews break;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews case 2:
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews dh->p = &bn1024;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews break;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews default:
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews DH_free(dh);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews return (DST_R_INVALIDPUBLICKEY);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews }
3525200d9fb0e70aec4f6a3c7e0ed5a7dd8398afEvan Hunt }
3525200d9fb0e70aec4f6a3c7e0ed5a7dd8398afEvan Hunt else {
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews dh->p = BN_bin2bn(r.base, plen, NULL);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews r.base += plen;
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews }
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews /*
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews * Read the generator length. This should be 0 if the prime was
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews * special, but it might not be. If it's 0 and the prime is not
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews * special, we have a problem.
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews */
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews if (r.length < 2) {
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt DH_free(dh);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt return (DST_R_INVALIDPUBLICKEY);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt }
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt glen = uint16_fromregion(&r);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt if (r.length < glen) {
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt DH_free(dh);
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt return (DST_R_INVALIDPUBLICKEY);
35c014cb1d151983c455ad1ac99093591cbda97aMark Andrews }
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt if (special != 0) {
4e8fe357a619ae2b789b15df7e3d6abf782b4a71Evan Hunt if (glen == 0)
dh->g = &bn2;
else {
dh->g = BN_bin2bn(r.base, glen, NULL);
if (BN_cmp(dh->g, &bn2) == 0) {
BN_free(dh->g);
dh->g = &bn2;
}
else {
DH_free(dh);
return (DST_R_INVALIDPUBLICKEY);
}
}
}
else {
if (glen == 0) {
DH_free(dh);
return (DST_R_INVALIDPUBLICKEY);
}
dh->g = BN_bin2bn(r.base, glen, NULL);
}
r.base += glen;
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);
}
dh->pub_key = BN_bin2bn(r.base, publen, NULL);
r.base += publen;
isc_buffer_remainingregion(data, &r);
key->key_id = dst_region_computeid(&r);
key->key_size = BN_num_bits(dh->p);
isc_buffer_forward(data, plen + glen + publen + 6);
key->opaque = (void *) dh;
return (ISC_R_SUCCESS);
}
static isc_result_t
openssldh_tofile(const dst_key_t *key, const char *directory) {
int cnt = 0;
DH *dh;
dst_private_t priv;
unsigned char bufs[4][128];
if (key->opaque == NULL)
return (DST_R_NULLKEY);
dh = (DH *) key->opaque;
priv.elements[cnt].tag = TAG_DH_PRIME;
priv.elements[cnt].length = BN_num_bytes(dh->p);
BN_bn2bin(dh->p, bufs[cnt]);
priv.elements[cnt].data = bufs[cnt];
cnt++;
priv.elements[cnt].tag = TAG_DH_GENERATOR;
priv.elements[cnt].length = BN_num_bytes(dh->g);
BN_bn2bin(dh->g, bufs[cnt]);
priv.elements[cnt].data = bufs[cnt];
cnt++;
priv.elements[cnt].tag = TAG_DH_PRIVATE;
priv.elements[cnt].length = BN_num_bytes(dh->priv_key);
BN_bn2bin(dh->priv_key, bufs[cnt]);
priv.elements[cnt].data = bufs[cnt];
cnt++;
priv.elements[cnt].tag = TAG_DH_PUBLIC;
priv.elements[cnt].length = BN_num_bytes(dh->pub_key);
BN_bn2bin(dh->pub_key, bufs[cnt]);
priv.elements[cnt].data = bufs[cnt];
cnt++;
priv.nelements = cnt;
return (dst__privstruct_writefile(key, &priv, directory));
}
static isc_result_t
openssldh_fromfile(dst_key_t *key, const isc_uint16_t id, const char *filename)
{
dst_private_t priv;
isc_result_t ret;
isc_buffer_t dns;
isc_region_t r;
unsigned char dns_array[1024];
int i;
DH *dh = NULL;
isc_mem_t *mctx;
#define DST_RET(a) {ret = a; goto err;}
mctx = key->mctx;
/* read private key file */
ret = dst__privstruct_parsefile(key, id, filename, mctx, &priv);
if (ret != ISC_R_SUCCESS)
return (ret);
dh = DH_new();
if (dh == NULL)
DST_RET(ISC_R_NOMEMORY);
key->opaque = 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:
dh->p = bn;
break;
case TAG_DH_GENERATOR:
dh->g = bn;
break;
case TAG_DH_PRIVATE:
dh->priv_key = bn;
break;
case TAG_DH_PUBLIC:
dh->pub_key = bn;
break;
}
}
dst__privstruct_free(&priv, mctx);
key->key_size = BN_num_bits(dh->p);
if ((key->key_size == 768 || key->key_size == 1024) &&
BN_cmp(dh->g, &bn2) == 0)
{
if (key->key_size == 768 && BN_cmp(dh->p, &bn768) == 0) {
BN_free(dh->p);
BN_free(dh->g);
dh->p = &bn768;
dh->g = &bn2;
} else if (key->key_size == 1024 &&
BN_cmp(dh->p, &bn1024) == 0) {
BN_free(dh->p);
BN_free(dh->g);
dh->p = &bn1024;
dh->g = &bn2;
}
}
isc_buffer_init(&dns, dns_array, sizeof(dns_array));
ret = openssldh_todns(key, &dns);
if (ret != ISC_R_SUCCESS)
DST_RET(ret);
isc_buffer_usedregion(&dns, &r);
key->key_id = dst_region_computeid(&r);
if (key->key_id != id)
DST_RET(DST_R_INVALIDPRIVATEKEY);
return (ISC_R_SUCCESS);
err:
openssldh_destroy(key);
dst__privstruct_free(&priv, mctx);
memset(&priv, 0, sizeof(priv));
return (ret);
}
static void
BN_fromhex(BIGNUM *b, const char *str) {
static const char hexdigits[] = "0123456789abcdef";
unsigned char data[512];
unsigned int i;
BIGNUM *out;
RUNTIME_CHECK(strlen(str) < 1024 && strlen(str) % 2 == 0);
for (i = 0; i < strlen(str); i += 2) {
char *s;
unsigned int high, low;
s = strchr(hexdigits, tolower((unsigned char)str[i]));
RUNTIME_CHECK(s != NULL);
high = s - hexdigits;
s = strchr(hexdigits, tolower((unsigned char)str[i + 1]));
RUNTIME_CHECK(s != NULL);
low = s - hexdigits;
data[i/2] = (unsigned char)((high << 4) + low);
}
out = BN_bin2bn(data, strlen(str)/2, b);
RUNTIME_CHECK(out != NULL);
}
static dst_func_t openssldh_functions = {
NULL, /* createctx */
NULL, /* destroyctx */
NULL, /* adddata */
NULL, /* openssldh_sign */
NULL, /* openssldh_verify */
openssldh_computesecret,
openssldh_compare,
openssldh_paramcompare,
openssldh_generate,
openssldh_isprivate,
openssldh_destroy,
openssldh_todns,
openssldh_fromdns,
openssldh_tofile,
openssldh_fromfile,
};
isc_result_t
dst__openssldh_init(dst_func_t **funcp) {
REQUIRE(funcp != NULL && *funcp == NULL);
BN_init(&bn2);
BN_init(&bn768);
BN_init(&bn1024);
BN_set_word(&bn2, 2);
BN_fromhex(&bn768, PRIME768);
BN_fromhex(&bn1024, PRIME1024);
*funcp = &openssldh_functions;
return (ISC_R_SUCCESS);
}
void
dst__openssldh_destroy(void) {
BN_free(&bn2);
BN_free(&bn768);
BN_free(&bn1024);
}
#endif /* OPENSSL */