* Spelling fixes. Thanks Andreas Schulze
* Hyphen used as minus in manpages. Thanks Andreas Schulze.
* RFC7553 RR Type URI is supported by default.
+ * Fix ECDSA signature generation, do not omit leading zeroes.
1.6.17 2014-01-10
* Fix ldns_dnssec_zone_new_frm_fp_l to allow the last parsed line of a
#ifdef USE_ECDSA
#ifndef S_SPLINT_S
ldns_rdf *
-ldns_convert_ecdsa_rrsig_asn12rdf(const ldns_buffer *sig, const long sig_len)
+ldns_convert_ecdsa_rrsig_asn1len2rdf(const ldns_buffer *sig,
+ const long sig_len, int num_bytes)
{
ECDSA_SIG* ecdsa_sig;
unsigned char *data = (unsigned char*)ldns_buffer_begin(sig);
if(!ecdsa_sig) return NULL;
/* "r | s". */
- data = LDNS_XMALLOC(unsigned char,
- BN_num_bytes(ecdsa_sig->r) + BN_num_bytes(ecdsa_sig->s));
+ if(BN_num_bytes(ecdsa_sig->r) > num_bytes ||
+ BN_num_bytes(ecdsa_sig->s) > num_bytes) {
+ ECDSA_SIG_free(ecdsa_sig);
+ return NULL; /* numbers too big for passed curve size */
+ }
+ data = LDNS_XMALLOC(unsigned char, num_bytes*2);
if(!data) {
ECDSA_SIG_free(ecdsa_sig);
return NULL;
}
- BN_bn2bin(ecdsa_sig->r, data);
- BN_bn2bin(ecdsa_sig->s, data+BN_num_bytes(ecdsa_sig->r));
- rdf = ldns_rdf_new(LDNS_RDF_TYPE_B64, (size_t)(
- BN_num_bytes(ecdsa_sig->r) + BN_num_bytes(ecdsa_sig->s)), data);
+ /* write the bignums (in big-endian) a little offset if the BN code
+ * wants to write a shorter number of bytes, with zeroes prefixed */
+ memset(data, 0, num_bytes*2);
+ BN_bn2bin(ecdsa_sig->r, data+num_bytes-BN_num_bytes(ecdsa_sig->r));
+ BN_bn2bin(ecdsa_sig->s, data+num_bytes*2-BN_num_bytes(ecdsa_sig->s));
+ rdf = ldns_rdf_new(LDNS_RDF_TYPE_B64, (size_t)(num_bytes*2), data);
ECDSA_SIG_free(ecdsa_sig);
return rdf;
}
#ifdef USE_ECDSA
#ifndef S_SPLINT_S
+/** returns the number of bytes per signature-component (i.e. bits/8), or 0. */
static int
ldns_pkey_is_ecdsa(EVP_PKEY* pkey)
{
EC_KEY_free(ec);
return 0;
}
- if(EC_GROUP_get_curve_name(g) == NID_secp224r1 ||
- EC_GROUP_get_curve_name(g) == NID_X9_62_prime256v1 ||
- EC_GROUP_get_curve_name(g) == NID_secp384r1) {
+ if(EC_GROUP_get_curve_name(g) == NID_X9_62_prime256v1) {
EC_KEY_free(ec);
- return 1;
+ return 32; /* 256/8 */
+ }
+ if(EC_GROUP_get_curve_name(g) == NID_secp384r1) {
+ EC_KEY_free(ec);
+ return 48; /* 384/8 */
}
/* downref the eckey, the original is still inside the pkey */
EC_KEY_free(ec);
#ifdef USE_ECDSA
} else if(EVP_PKEY_type(key->type) == EVP_PKEY_EC &&
ldns_pkey_is_ecdsa(key)) {
- sigdata_rdf = ldns_convert_ecdsa_rrsig_asn12rdf(b64sig, siglen);
+ sigdata_rdf = ldns_convert_ecdsa_rrsig_asn1len2rdf(
+ b64sig, siglen, ldns_pkey_is_ecdsa(key));
#endif
} else {
/* ok output for other types is the same */
* Converts the ECDSA signature from ASN1 representation (as
* used by OpenSSL) to raw signature data as used in DNS
* This routine is only present if ldns is compiled with ecdsa support.
+ * The older ldns_convert_ecdsa_rrsig_asn12rdf routine could not (always)
+ * construct a valid rdf because it did not have the num_bytes parameter.
+ * The num_bytes parameter is 32 for p256 and 48 for p384 (bits/8).
*
* \param[in] sig The signature in ASN1 format
* \param[in] sig_len The length of the signature
+ * \param[in] num_bytes number of bytes for values in the curve, the curve
+ * size divided by 8.
* \return a new rdf with the signature
*/
ldns_rdf *
-ldns_convert_ecdsa_rrsig_asn12rdf(const ldns_buffer *sig, const long sig_len);
+ldns_convert_ecdsa_rrsig_asn1len2rdf(const ldns_buffer *sig,
+ const long sig_len, int num_bytes);
/**
* Converts the RRSIG signature RDF (from DNS) to a buffer with the