RSA with nss.

git-svn-id: file:///svn/unbound/trunk@2697 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2012-06-21 15:19:16 +00:00
parent d051dfaf19
commit cd8e4a0bc5
2 changed files with 170 additions and 41 deletions

View file

@ -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).

View file

@ -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);