Zonemaster-LDNS

 view release on metacpan or  search on metacpan

ldns/keys.c  view on Meta::CPAN

        { LDNS_SIGN_HMACSHA384, "hmac-sha384" },
        { LDNS_SIGN_HMACSHA512, "hmac-sha512" },
        { 0, NULL }
};

ldns_key_list *
ldns_key_list_new(void)
{
	ldns_key_list *key_list = LDNS_MALLOC(ldns_key_list);
	if (!key_list) {
		return NULL;
	} else {
		key_list->_key_count = 0;
		key_list->_keys = NULL;
		return key_list;
	}
}

ldns_key *
ldns_key_new(void)
{
	ldns_key *newkey;

	newkey = LDNS_MALLOC(ldns_key);
	if (!newkey) {
		return NULL;
	} else {
		/* some defaults - not sure whether to do this */
		ldns_key_set_use(newkey, true);
		ldns_key_set_flags(newkey, LDNS_KEY_ZONE_KEY);
		ldns_key_set_origttl(newkey, 0);
		ldns_key_set_keytag(newkey, 0);
		ldns_key_set_inception(newkey, 0);
		ldns_key_set_expiration(newkey, 0);
		ldns_key_set_pubkey_owner(newkey, NULL);
#ifdef HAVE_SSL
		ldns_key_set_evp_key(newkey, NULL);
#endif /* HAVE_SSL */
		ldns_key_set_hmac_key(newkey, NULL);
		ldns_key_set_external_key(newkey, NULL);
		return newkey;
	}
}

ldns_status
ldns_key_new_frm_fp(ldns_key **k, FILE *fp)
{
	return ldns_key_new_frm_fp_l(k, fp, NULL);
}

#if defined(HAVE_SSL) && !defined(OPENSSL_NO_ENGINE)
ldns_status
ldns_key_new_frm_engine(ldns_key **key, ENGINE *e, char *key_id, ldns_algorithm alg)
{
	ldns_key *k;

	k = ldns_key_new();
        if(!k) return LDNS_STATUS_MEM_ERR;
#ifndef S_SPLINT_S
	ldns_key_set_algorithm(k, (ldns_signing_algorithm) alg);
	k->_key.key = ENGINE_load_private_key(e, key_id, UI_OpenSSL(), NULL);
	if (!k->_key.key) {
                ldns_key_free(k);
		return LDNS_STATUS_ENGINE_KEY_NOT_LOADED;
	}
#endif /* splint */
	*key = k;
	return LDNS_STATUS_OK;
}
#endif

#if defined(USE_GOST) && !defined(OPENSSL_NO_ENGINE)
/** store GOST engine reference loaded into OpenSSL library */
ENGINE* ldns_gost_engine = NULL;

int
ldns_key_EVP_load_gost_id(void)
{
	static int gost_id = 0;
	const EVP_PKEY_ASN1_METHOD* meth;
	ENGINE* e;

	if(gost_id) return gost_id;

	/* see if configuration loaded gost implementation from other engine*/
	meth = EVP_PKEY_asn1_find_str(NULL, "gost2001", -1);
	if(meth) {
		EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth);
		return gost_id;
	}

	/* see if engine can be loaded already */
	e = ENGINE_by_id("gost");
	if(!e) {
		/* load it ourself, in case statically linked */
		ENGINE_load_builtin_engines();
		ENGINE_load_dynamic();
		e = ENGINE_by_id("gost");
	}
	if(!e) {
		/* no gost engine in openssl */
		return 0;
	}
	if(!ENGINE_set_default(e, ENGINE_METHOD_ALL)) {
		ENGINE_finish(e);
		ENGINE_free(e);
		return 0;
	}

	meth = EVP_PKEY_asn1_find_str(&e, "gost2001", -1);
	if(!meth) {
		/* algo not found */
		ENGINE_finish(e);
		ENGINE_free(e);
		return 0;
	}
        /* Note: do not ENGINE_finish and ENGINE_free the acquired engine
         * on some platforms this frees up the meth and unloads gost stuff */
        ldns_gost_engine = e;
	
	EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth);
	return gost_id;
} 

void ldns_key_EVP_unload_gost(void)
{
        if(ldns_gost_engine) {
                ENGINE_finish(ldns_gost_engine);
                ENGINE_free(ldns_gost_engine);
                ldns_gost_engine = NULL;
        }
}

/** read GOST private key */
static EVP_PKEY*
ldns_key_new_frm_fp_gost_l(FILE* fp, int* line_nr)
{
	char token[16384];
	const unsigned char* pp;
	int gost_id;
	EVP_PKEY* pkey;
	ldns_rdf* b64rdf = NULL;

	gost_id = ldns_key_EVP_load_gost_id();
	if(!gost_id)
		return NULL;

	if (ldns_fget_keyword_data_l(fp, "GostAsn1", ": ", token, "\n", 
		sizeof(token), line_nr) == -1)
		return NULL;
	while(strlen(token) < 96) {
		/* read more b64 from the file, b64 split on multiple lines */
		if(ldns_fget_token_l(fp, token+strlen(token), "\n",
			sizeof(token)-strlen(token), line_nr) == -1)
			return NULL;
	}
	if(ldns_str2rdf_b64(&b64rdf, token) != LDNS_STATUS_OK)
		return NULL;
	pp = (unsigned char*)ldns_rdf_data(b64rdf);
	pkey = d2i_PrivateKey(gost_id, NULL, &pp, (int)ldns_rdf_size(b64rdf));
	ldns_rdf_deep_free(b64rdf);
	return pkey;
}
#endif

#ifdef USE_ECDSA
/** calculate public key from private key */
static int
ldns_EC_KEY_calc_public(EC_KEY* ec)
{
        EC_POINT* pub_key;
        const EC_GROUP* group;
        group = EC_KEY_get0_group(ec);
        pub_key = EC_POINT_new(group);
        if(!pub_key) return 0;
        if(!EC_POINT_copy(pub_key, EC_GROUP_get0_generator(group))) {
                EC_POINT_free(pub_key);
                return 0;
        }
        if(!EC_POINT_mul(group, pub_key, EC_KEY_get0_private_key(ec),
                NULL, NULL, NULL)) {
                EC_POINT_free(pub_key);
                return 0;
        }
        if(EC_KEY_set_public_key(ec, pub_key) == 0) {
                EC_POINT_free(pub_key);
                return 0;
        }
        EC_POINT_free(pub_key);
        return 1;
}

/** read ECDSA private key */
static EVP_PKEY*
ldns_key_new_frm_fp_ecdsa_l(FILE* fp, ldns_algorithm alg, int* line_nr)
{
	char token[16384];
        ldns_rdf* b64rdf = NULL;
        unsigned char* pp;
        BIGNUM* bn;
        EVP_PKEY* evp_key;
        EC_KEY* ec;
	if (ldns_fget_keyword_data_l(fp, "PrivateKey", ": ", token, "\n",
		sizeof(token), line_nr) == -1)
		return NULL;
	if(ldns_str2rdf_b64(&b64rdf, token) != LDNS_STATUS_OK)
		return NULL;
        pp = (unsigned char*)ldns_rdf_data(b64rdf);

        if(alg == LDNS_ECDSAP256SHA256)
                ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
        else if(alg == LDNS_ECDSAP384SHA384)
                ec = EC_KEY_new_by_curve_name(NID_secp384r1);
        else    ec = NULL;
        if(!ec) {
	        ldns_rdf_deep_free(b64rdf);
                return NULL;
        }
	bn = BN_bin2bn(pp, (int)ldns_rdf_size(b64rdf), NULL);
	ldns_rdf_deep_free(b64rdf);
        if(!bn) {
                EC_KEY_free(ec);
                return NULL;
        }
        EC_KEY_set_private_key(ec, bn);
        BN_free(bn);
        if(!ldns_EC_KEY_calc_public(ec)) {
                EC_KEY_free(ec);
                return NULL;
        }

        evp_key = EVP_PKEY_new();
        if(!evp_key) {
                EC_KEY_free(ec);
                return NULL;
        }
        if (!EVP_PKEY_assign_EC_KEY(evp_key, ec)) {
		EVP_PKEY_free(evp_key);
                EC_KEY_free(ec);
                return NULL;
	}
        return evp_key;
}
#endif

#ifdef USE_ED25519
/** turn private key buffer into EC_KEY structure */
static EVP_PKEY*
ldns_ed25519_priv_raw(uint8_t* pkey, int plen)
{
	const unsigned char* pp;
	uint8_t buf[256];
	int buflen = 0;
	uint8_t pre[] = {0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06,
		0x03, 0x2b, 0x65, 0x70, 0x04, 0x22, 0x04, 0x20};
	int pre_len = 16;
	/* ASN looks like this for ED25519 public key
	 * 302a300506032b6570032100 <32byteskey>
	 * for ED25519 private key
	 * 302e020100300506032b657004220420 <32bytes>
	 *
	 * for X25519 this was
	 * 30320201010420 <32byteskey>
	 * andparameters a00b06092b06010401da470f01
	 * (noparameters, preamble is 30250201010420).
	 * the key is reversed (little endian).
	 */
	buflen = pre_len + plen;
	if((size_t)buflen > sizeof(buf))
		return NULL;
	memmove(buf, pre, pre_len);
	memmove(buf+pre_len, pkey, plen);
	/* reverse the pkey into the buf - key is not reversed it seems */
	/* for(i=0; i<plen; i++)
		buf[pre_len+i] = pkey[plen-1-i]; */
	pp = buf;
	return d2i_PrivateKey(NID_ED25519, NULL, &pp, buflen);
}

/** read ED25519 private key */
static EVP_PKEY*
ldns_key_new_frm_fp_ed25519_l(FILE* fp, int* line_nr)
{
	char token[16384];
        ldns_rdf* b64rdf = NULL;
        EVP_PKEY* evp_key;
	if (ldns_fget_keyword_data_l(fp, "PrivateKey", ": ", token, "\n",
		sizeof(token), line_nr) == -1)
		return NULL;
	if(ldns_str2rdf_b64(&b64rdf, token) != LDNS_STATUS_OK)
		return NULL;

	/* we use d2i_ECPrivateKey because it calculates the public key
	 * from the private part, which others, EC_KEY_set_private_key,
	 * and o2i methods, do not do */
	/* for that the private key has to be encoded in ASN1 notation
	 * with a ED25519 prefix on it */

	evp_key = ldns_ed25519_priv_raw(ldns_rdf_data(b64rdf),
		(int)ldns_rdf_size(b64rdf));
	ldns_rdf_deep_free(b64rdf);
        return evp_key;
}
#endif

#ifdef USE_ED448
/** turn private key buffer into EC_KEY structure */
static EVP_PKEY*
ldns_ed448_priv_raw(uint8_t* pkey, int plen)
{
	const unsigned char* pp;
	uint8_t buf[256];
	int buflen = 0;
	uint8_t pre[] = {0x30, 0x47, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x71, 0x04, 0x3b, 0x04, 0x39};
	int pre_len = 16;
	/* ASN looks like this for ED448
	 * 3047020100300506032b6571043b0439 <57bytekey>
	 * the key is reversed (little endian).
	 */
	buflen = pre_len + plen;
	if((size_t)buflen > sizeof(buf))
		return NULL;
	memmove(buf, pre, pre_len);
	memmove(buf+pre_len, pkey, plen);
	/* reverse the pkey into the buf - key is not reversed it seems */
	/* for(i=0; i<plen; i++)
		buf[pre_len+i] = pkey[plen-1-i]; */
	pp = buf;
	return d2i_PrivateKey(NID_ED448, NULL, &pp, buflen);
}

/** read ED448 private key */
static EVP_PKEY*
ldns_key_new_frm_fp_ed448_l(FILE* fp, int* line_nr)
{
	char token[16384];
        ldns_rdf* b64rdf = NULL;
        EVP_PKEY* evp_key;
	if (ldns_fget_keyword_data_l(fp, "PrivateKey", ": ", token, "\n", 
		sizeof(token), line_nr) == -1)
		return NULL;
	if(ldns_str2rdf_b64(&b64rdf, token) != LDNS_STATUS_OK)
		return NULL;

	/* convert private key into ASN notation and then convert that */
	evp_key = ldns_ed448_priv_raw(ldns_rdf_data(b64rdf),
		(int)ldns_rdf_size(b64rdf));
	ldns_rdf_deep_free(b64rdf);
	return evp_key;
}
#endif

ldns_status
ldns_key_new_frm_fp_l(ldns_key **key, FILE *fp, int *line_nr)



( run in 1.685 second using v1.01-cache-2.11-cpan-ceb78f64989 )