mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 23:00:56 -05:00
RSA with nss.
git-svn-id: file:///svn/unbound/trunk@2697 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
d051dfaf19
commit
cd8e4a0bc5
2 changed files with 170 additions and 41 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
21 June 2012: Wouter
|
21 June 2012: Wouter
|
||||||
- fix error handling of alloc failure during rrsig verification.
|
- fix error handling of alloc failure during rrsig verification.
|
||||||
- nss check for verification failure.
|
- nss check for verification failure.
|
||||||
|
- nss crypto works for RSA and DSA.
|
||||||
|
|
||||||
20 June 2012: Wouter
|
20 June 2012: Wouter
|
||||||
- work on --with-nss build option (for now, --with-libunbound-only).
|
- work on --with-nss build option (for now, --with-libunbound-only).
|
||||||
|
|
|
||||||
|
|
@ -554,6 +554,7 @@ verify_canonrrset(ldns_buffer* buf, int algo, unsigned char* sigblock,
|
||||||
#include <nss3/pk11pub.h>
|
#include <nss3/pk11pub.h>
|
||||||
#include <nss3/keyhi.h>
|
#include <nss3/keyhi.h>
|
||||||
#include <nss3/secerr.h>
|
#include <nss3/secerr.h>
|
||||||
|
#include <nss3/cryptohi.h>
|
||||||
#include <nspr4/prerror.h>
|
#include <nspr4/prerror.h>
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
|
|
@ -659,6 +660,90 @@ static SECKEYPublicKey* nss_key_create(KeyType ktype)
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SECKEYPublicKey* nss_buf2ecdsa(unsigned char* key, size_t len, int algo)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
#if 0
|
||||||
|
/* TODO */
|
||||||
|
SECKEYPublicKey* pk;
|
||||||
|
unsigned char buf[256+2]; /* sufficient for 2*384/8+1 */
|
||||||
|
const unsigned char* pp = buf;
|
||||||
|
ECGroup* ecg;
|
||||||
|
|
||||||
|
|
||||||
|
/* check length, which uncompressed must be 2 bignums */
|
||||||
|
if(algo == LDNS_ECDSAP256SHA256) {
|
||||||
|
if(keylen != 2*256/8) return NULL;
|
||||||
|
ecg = ECGroup_fromName(ECCurve_X9_62_PRIME_256V1);
|
||||||
|
} else if(algo == LDNS_ECDSAP384SHA384) {
|
||||||
|
if(keylen != 2*384/8) return NULL;
|
||||||
|
ecg = ECGroup_fromName(ECCurve_X9_62_PRIME_384R1);
|
||||||
|
} else ecg= NULL;
|
||||||
|
if(!ecg) return NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static SECKEYPublicKey* nss_buf2dsa(unsigned char* key, size_t len)
|
||||||
|
{
|
||||||
|
SECKEYPublicKey* pk;
|
||||||
|
uint8_t T;
|
||||||
|
uint16_t length;
|
||||||
|
uint16_t offset;
|
||||||
|
SECItem Q = {siBuffer, NULL, 0};
|
||||||
|
SECItem P = {siBuffer, NULL, 0};
|
||||||
|
SECItem G = {siBuffer, NULL, 0};
|
||||||
|
SECItem Y = {siBuffer, NULL, 0};
|
||||||
|
|
||||||
|
if(len == 0)
|
||||||
|
return NULL;
|
||||||
|
T = (uint8_t)key[0];
|
||||||
|
length = (64 + T * 8);
|
||||||
|
offset = 1;
|
||||||
|
|
||||||
|
if (T > 8) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if(len < (size_t)1 + SHA1_LENGTH + 3*length)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
Q.data = key+offset;
|
||||||
|
Q.len = SHA1_LENGTH;
|
||||||
|
offset += SHA1_LENGTH;
|
||||||
|
|
||||||
|
P.data = key+offset;
|
||||||
|
P.len = length;
|
||||||
|
offset += length;
|
||||||
|
|
||||||
|
G.data = key+offset;
|
||||||
|
G.len = length;
|
||||||
|
offset += length;
|
||||||
|
|
||||||
|
Y.data = key+offset;
|
||||||
|
Y.len = length;
|
||||||
|
offset += length;
|
||||||
|
|
||||||
|
pk = nss_key_create(dsaKey);
|
||||||
|
if(!pk)
|
||||||
|
return NULL;
|
||||||
|
if(SECITEM_CopyItem(pk->arena, &pk->u.dsa.params.prime, &P)) {
|
||||||
|
SECKEY_DestroyPublicKey(pk);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if(SECITEM_CopyItem(pk->arena, &pk->u.dsa.params.subPrime, &Q)) {
|
||||||
|
SECKEY_DestroyPublicKey(pk);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if(SECITEM_CopyItem(pk->arena, &pk->u.dsa.params.base, &G)) {
|
||||||
|
SECKEY_DestroyPublicKey(pk);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if(SECITEM_CopyItem(pk->arena, &pk->u.dsa.publicValue, &Y)) {
|
||||||
|
SECKEY_DestroyPublicKey(pk);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return pk;
|
||||||
|
}
|
||||||
|
|
||||||
static SECKEYPublicKey* nss_buf2rsa(unsigned char* key, size_t len)
|
static SECKEYPublicKey* nss_buf2rsa(unsigned char* key, size_t len)
|
||||||
{
|
{
|
||||||
SECKEYPublicKey* pk;
|
SECKEYPublicKey* pk;
|
||||||
|
|
@ -692,6 +777,8 @@ static SECKEYPublicKey* nss_buf2rsa(unsigned char* key, size_t len)
|
||||||
modulus.len = (len - offset);
|
modulus.len = (len - offset);
|
||||||
|
|
||||||
pk = nss_key_create(rsaKey);
|
pk = nss_key_create(rsaKey);
|
||||||
|
if(!pk)
|
||||||
|
return NULL;
|
||||||
if(SECITEM_CopyItem(pk->arena, &pk->u.rsa.modulus, &modulus)) {
|
if(SECITEM_CopyItem(pk->arena, &pk->u.rsa.modulus, &modulus)) {
|
||||||
SECKEY_DestroyPublicKey(pk);
|
SECKEY_DestroyPublicKey(pk);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -711,39 +798,42 @@ static SECKEYPublicKey* nss_buf2rsa(unsigned char* key, size_t len)
|
||||||
* @param digest_type: digest type to use
|
* @param digest_type: digest type to use
|
||||||
* @param key: key to setup for.
|
* @param key: key to setup for.
|
||||||
* @param keylen: length of key.
|
* @param keylen: length of key.
|
||||||
|
* @param prefix: if returned, the ASN prefix for the hashblob.
|
||||||
|
* @param prefixlen: length of the prefix.
|
||||||
* @return false on failure.
|
* @return false on failure.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
nss_setup_key_digest(int algo, SECKEYPublicKey** pubkey, HASH_HashType* htype,
|
nss_setup_key_digest(int algo, SECKEYPublicKey** pubkey, HASH_HashType* htype,
|
||||||
unsigned char* key, size_t keylen)
|
unsigned char* key, size_t keylen, unsigned char** prefix,
|
||||||
|
size_t* prefixlen)
|
||||||
{
|
{
|
||||||
/* TODO uses libNSS */
|
/* uses libNSS */
|
||||||
|
|
||||||
|
/* hash prefix for md5, RFC2537 */
|
||||||
|
unsigned char p_md5[] = {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a,
|
||||||
|
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10};
|
||||||
|
/* hash prefix to prepend to hash output, from RFC3110 */
|
||||||
|
unsigned char p_sha1[] = {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2B,
|
||||||
|
0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00, 0x04, 0x14};
|
||||||
|
/* from RFC5702 */
|
||||||
|
unsigned char p_sha256[] = {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60,
|
||||||
|
0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20};
|
||||||
|
unsigned char p_sha512[] = {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60,
|
||||||
|
0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40};
|
||||||
|
/* from RFC6234 */
|
||||||
|
unsigned char p_sha384[] = {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60,
|
||||||
|
0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30};
|
||||||
|
|
||||||
switch(algo) {
|
switch(algo) {
|
||||||
case LDNS_DSA:
|
case LDNS_DSA:
|
||||||
case LDNS_DSA_NSEC3:
|
case LDNS_DSA_NSEC3:
|
||||||
/* TODO */
|
*pubkey = nss_buf2dsa(key, keylen);
|
||||||
/*
|
if(!*pubkey) {
|
||||||
*evp_key = EVP_PKEY_new();
|
|
||||||
if(!*evp_key) {
|
|
||||||
log_err("verify: malloc failure in crypto");
|
log_err("verify: malloc failure in crypto");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
dsa = ldns_key_buf2dsa_raw(key, keylen);
|
|
||||||
if(!dsa) {
|
|
||||||
verbose(VERB_QUERY, "verify: "
|
|
||||||
"ldns_key_buf2dsa_raw failed");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if(EVP_PKEY_assign_DSA(*evp_key, dsa) == 0) {
|
|
||||||
verbose(VERB_QUERY, "verify: "
|
|
||||||
"EVP_PKEY_assign_DSA failed");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
*digest_type = EVP_dss1();
|
|
||||||
*/
|
|
||||||
*htype = HASH_AlgSHA1;
|
*htype = HASH_AlgSHA1;
|
||||||
|
/* no prefix for DSA verification */
|
||||||
break;
|
break;
|
||||||
case LDNS_RSASHA1:
|
case LDNS_RSASHA1:
|
||||||
case LDNS_RSASHA1_NSEC3:
|
case LDNS_RSASHA1_NSEC3:
|
||||||
|
|
@ -760,16 +850,24 @@ nss_setup_key_digest(int algo, SECKEYPublicKey** pubkey, HASH_HashType* htype,
|
||||||
}
|
}
|
||||||
/* select SHA version */
|
/* select SHA version */
|
||||||
#if defined(HAVE_EVP_SHA256) && defined(USE_SHA2)
|
#if defined(HAVE_EVP_SHA256) && defined(USE_SHA2)
|
||||||
if(algo == LDNS_RSASHA256)
|
if(algo == LDNS_RSASHA256) {
|
||||||
*htype = HASH_AlgSHA256;
|
*htype = HASH_AlgSHA256;
|
||||||
else
|
*prefix = p_sha256;
|
||||||
|
*prefixlen = sizeof(p_sha256);
|
||||||
|
} else
|
||||||
#endif
|
#endif
|
||||||
#if defined(HAVE_EVP_SHA512) && defined(USE_SHA2)
|
#if defined(HAVE_EVP_SHA512) && defined(USE_SHA2)
|
||||||
if(algo == LDNS_RSASHA512)
|
if(algo == LDNS_RSASHA512) {
|
||||||
*htype = HASH_AlgSHA512;
|
*htype = HASH_AlgSHA512;
|
||||||
else
|
*prefix = p_sha512;
|
||||||
|
*prefixlen = sizeof(p_sha512);
|
||||||
|
} else
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
*htype = HASH_AlgSHA1;
|
*htype = HASH_AlgSHA1;
|
||||||
|
*prefix = p_sha1;
|
||||||
|
*prefixlen = sizeof(p_sha1);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case LDNS_RSAMD5:
|
case LDNS_RSAMD5:
|
||||||
|
|
@ -779,32 +877,32 @@ nss_setup_key_digest(int algo, SECKEYPublicKey** pubkey, HASH_HashType* htype,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
*htype = HASH_AlgMD5;
|
*htype = HASH_AlgMD5;
|
||||||
|
*prefix = p_md5;
|
||||||
|
*prefixlen = sizeof(p_md5);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
#ifdef USE_ECDSA
|
#ifdef USE_ECDSA
|
||||||
case LDNS_ECDSAP256SHA256:
|
case LDNS_ECDSAP256SHA256:
|
||||||
/* TODO
|
*pubkey = nss_buf2ecdsa(key, keylen,
|
||||||
*evp_key = ldns_ecdsa2pkey_raw(key, keylen,
|
|
||||||
LDNS_ECDSAP256SHA256);
|
LDNS_ECDSAP256SHA256);
|
||||||
if(!*evp_key) {
|
if(!*pubkey) {
|
||||||
verbose(VERB_QUERY, "verify: "
|
log_err("verify: malloc failure in crypto");
|
||||||
"ldns_ecdsa2pkey_raw failed");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
*htype = HASH_AlgSHA256;
|
*htype = HASH_AlgSHA256;
|
||||||
|
*prefix = p_sha256;
|
||||||
|
*prefixlen = sizeof(p_sha256);
|
||||||
break;
|
break;
|
||||||
case LDNS_ECDSAP384SHA384:
|
case LDNS_ECDSAP384SHA384:
|
||||||
/* TODO
|
*pubkey = nss_buf2ecdsa(key, keylen,
|
||||||
*evp_key = ldns_ecdsa2pkey_raw(key, keylen,
|
|
||||||
LDNS_ECDSAP384SHA384);
|
LDNS_ECDSAP384SHA384);
|
||||||
if(!*evp_key) {
|
if(!*pubkey) {
|
||||||
verbose(VERB_QUERY, "verify: "
|
log_err("verify: malloc failure in crypto");
|
||||||
"ldns_ecdsa2pkey_raw failed");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
*htype = HASH_AlgSHA384;
|
*htype = HASH_AlgSHA384;
|
||||||
|
*prefix = p_sha384;
|
||||||
|
*prefixlen = sizeof(p_sha384);
|
||||||
break;
|
break;
|
||||||
#endif /* USE_ECDSA */
|
#endif /* USE_ECDSA */
|
||||||
case LDNS_ECC_GOST:
|
case LDNS_ECC_GOST:
|
||||||
|
|
@ -834,7 +932,7 @@ verify_canonrrset(ldns_buffer* buf, int algo, unsigned char* sigblock,
|
||||||
unsigned int sigblock_len, unsigned char* key, unsigned int keylen,
|
unsigned int sigblock_len, unsigned char* key, unsigned int keylen,
|
||||||
char** reason)
|
char** reason)
|
||||||
{
|
{
|
||||||
/* TODO uses libNSS */
|
/* uses libNSS */
|
||||||
/* large enough for the different hashes */
|
/* large enough for the different hashes */
|
||||||
unsigned char hash[HASH_LENGTH_MAX];
|
unsigned char hash[HASH_LENGTH_MAX];
|
||||||
HASH_HashType htype = 0;
|
HASH_HashType htype = 0;
|
||||||
|
|
@ -842,18 +940,40 @@ verify_canonrrset(ldns_buffer* buf, int algo, unsigned char* sigblock,
|
||||||
SECItem secsig = {siBuffer, sigblock, sigblock_len};
|
SECItem secsig = {siBuffer, sigblock, sigblock_len};
|
||||||
SECItem sechash = {siBuffer, hash, 0};
|
SECItem sechash = {siBuffer, hash, 0};
|
||||||
SECStatus res;
|
SECStatus res;
|
||||||
|
unsigned char* prefix = NULL; /* prefix for hash, RFC3110, RFC5702 */
|
||||||
|
size_t prefixlen = 0;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
// extern SECKEYPublicKey *SECKEY_DecodeDERPublicKey(SECItem *pubkder);
|
if(!nss_setup_key_digest(algo, &pubkey, &htype, key, keylen,
|
||||||
// SECKEYPublicKey* SECKEY_ImportDERPublicKey(SECItem *derKey, CK_KEY_TYPE type);
|
&prefix, &prefixlen)) {
|
||||||
if(!nss_setup_key_digest(algo, &pubkey, &htype, key, keylen)) {
|
|
||||||
verbose(VERB_QUERY, "verify: failed to setup key");
|
verbose(VERB_QUERY, "verify: failed to setup key");
|
||||||
*reason = "use of key for crypto failed";
|
*reason = "use of key for crypto failed";
|
||||||
SECKEY_DestroyPublicKey(pubkey);
|
SECKEY_DestroyPublicKey(pubkey);
|
||||||
return sec_status_bogus;
|
return sec_status_bogus;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: need to convert DSA, ECDSA signatures? */
|
/* need to convert DSA, ECDSA signatures? */
|
||||||
|
if((algo == LDNS_DSA || algo == LDNS_DSA_NSEC3)) {
|
||||||
|
if(sigblock_len == 1+2*SHA1_LENGTH) {
|
||||||
|
secsig.data ++;
|
||||||
|
secsig.len --;
|
||||||
|
} else {
|
||||||
|
SECItem* p = DSAU_DecodeDerSig(&secsig);
|
||||||
|
if(!p) {
|
||||||
|
verbose(VERB_QUERY, "verify: failed DER decode");
|
||||||
|
*reason = "signature DER decode failed";
|
||||||
|
SECKEY_DestroyPublicKey(pubkey);
|
||||||
|
return sec_status_bogus;
|
||||||
|
}
|
||||||
|
if(SECITEM_CopyItem(pubkey->arena, &secsig, p)) {
|
||||||
|
log_err("alloc failure in DER decode");
|
||||||
|
SECKEY_DestroyPublicKey(pubkey);
|
||||||
|
SECITEM_FreeItem(p, PR_TRUE);
|
||||||
|
return sec_status_unchecked;
|
||||||
|
}
|
||||||
|
SECITEM_FreeItem(p, PR_TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* do the signature cryptography work */
|
/* do the signature cryptography work */
|
||||||
/* hash the data */
|
/* hash the data */
|
||||||
|
|
@ -869,6 +989,14 @@ verify_canonrrset(ldns_buffer* buf, int algo, unsigned char* sigblock,
|
||||||
SECKEY_DestroyPublicKey(pubkey);
|
SECKEY_DestroyPublicKey(pubkey);
|
||||||
return sec_status_unchecked;
|
return sec_status_unchecked;
|
||||||
}
|
}
|
||||||
|
if(prefix) {
|
||||||
|
int hashlen = sechash.len;
|
||||||
|
sechash.data = PORT_ArenaAlloc(pubkey->arena, prefixlen+hashlen);
|
||||||
|
sechash.len = prefixlen+hashlen;
|
||||||
|
memcpy(sechash.data, prefix, prefixlen);
|
||||||
|
memmove(sechash.data+prefixlen, hash, hashlen);
|
||||||
|
}
|
||||||
|
|
||||||
/* verify the signature */
|
/* verify the signature */
|
||||||
res = PK11_Verify(pubkey, &secsig, &sechash, NULL /*wincx*/);
|
res = PK11_Verify(pubkey, &secsig, &sechash, NULL /*wincx*/);
|
||||||
SECKEY_DestroyPublicKey(pubkey);
|
SECKEY_DestroyPublicKey(pubkey);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue