From: Miek Gieben Date: Thu, 24 Feb 2005 15:01:06 +0000 (+0000) Subject: added dnssec.c file. It's not compiled X-Git-Tag: release-0.50~372 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5442ab5bd84619df91ffb8e9eeeefc6ffad39238;p=thirdparty%2Fldns.git added dnssec.c file. It's not compiled --- diff --git a/dnssec.c b/dnssec.c new file mode 100644 index 00000000..990031c8 --- /dev/null +++ b/dnssec.c @@ -0,0 +1,318 @@ +/* + * dnssec.c + * + * contains the cryptographic function needed for DNSSEC + * The crypto library used is openssl + * + * (c) NLnet Labs, 2004 + * a Net::DNS like library for C + * + * See the file LICENSE for the license + */ + +#include "common.h" +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +/** + * Verify an rrsig with the DSA algorithm, see RFC 2536 + */ +int +verify_rrsig_dsa(uint8_t *verifybuf, unsigned long length, unsigned char *sigbuf, unsigned int siglen, + unsigned char *key_bytes, unsigned int keylen) +{ + uint8_t T = (uint8_t) key_bytes[0]; + int numberlength; + int offset = 1; + + BIGNUM *Q; + BIGNUM *P; + BIGNUM *G; + BIGNUM *Y; + uint8_t t_sig; + + BIGNUM *R; + BIGNUM *S; + DSA *dsa; + uint8_t *hash; + DSA_SIG *sig; + int dsa_res; + int result; + + + numberlength = (int) (64 + T * 8); + + if (T > 8) { + warning("DSA type > 8 not implemented, unable to verify signature"); + return RET_FAIL; + } + + Q = BN_bin2bn(&key_bytes[offset], 20, NULL); + offset += 20; + + P = BN_bin2bn(&key_bytes[offset], numberlength, NULL); + offset += numberlength; + + G = BN_bin2bn(&key_bytes[offset], numberlength, NULL); + offset += numberlength; + + Y = BN_bin2bn(&key_bytes[offset], numberlength, NULL); + offset += numberlength; + + t_sig = (uint8_t) sigbuf[0]; + + if (t_sig != T) { + warning("Values for T are different in key and signature, verification of DSA sig failed"); + return RET_FAIL; + } + + + R = BN_bin2bn(&sigbuf[1], 20, NULL); + + S = BN_bin2bn(&sigbuf[21], 20, NULL); + + dsa = DSA_new(); + + dsa->p = P; + dsa->q = Q; + dsa->g = G; + dsa->pub_key = Y; + + //hash = xmalloc(20); + + hash = SHA1((unsigned char *) verifybuf, length, NULL); + + sig = DSA_SIG_new(); + sig->r = R; + sig->s = S; + + dsa_res = DSA_do_verify((unsigned char *) hash, 20, sig, dsa); + + if (dsa_res == 1) { + result = RET_SUC; + } else if (dsa_res == 0) { + result = RET_FAIL; + } else { + warning("internal error when verifying: %d", dsa_res); + ERR_print_errors_fp(stdout); + result = RET_FAIL; + } + + return result; +} + + + +/** + * Verify an rrsig with the RSA algorithm and SHA1 hash, see RFC 3110 + */ +int +verify_rrsig_rsasha1(uint8_t *verifybuf, unsigned long length, unsigned char *sigbuf, unsigned int siglen, + unsigned char *key_bytes, unsigned int keylen) +{ + BIGNUM *modulus; + BIGNUM *exponent; + unsigned char *modulus_bytes; + unsigned char *exponent_bytes; + unsigned char *digest; + int offset; + int explength; + uint16_t int16; + RSA *rsa; + int rsa_res; + + int result; + + if(key_bytes[0] == 0) { + memcpy(&int16, &key_bytes[1], 2); + int16 = ntohs(int16); + explength = (int) int16; + offset = 3; + } else { + explength = (int) key_bytes[0]; + offset = 1; + } + + /* Exponent */ + exponent_bytes = xmalloc(explength*sizeof(char)); + memcpy(exponent_bytes, &key_bytes[offset], explength*sizeof(char)); + exponent = BN_new(); + (void) BN_bin2bn(exponent_bytes, explength, exponent); + offset += explength; + + /* Modulus */ + modulus_bytes = xmalloc((keylen-offset)*sizeof(char)); + memcpy(modulus_bytes, &key_bytes[offset], (keylen-offset)*sizeof(char)); + modulus = BN_new(); + (void) BN_bin2bn(&modulus_bytes[0], (int) keylen-offset, modulus); + offset = (int) keylen; + + rsa = RSA_new(); + rsa->n = modulus; + rsa->e = exponent; + + digest = SHA1((unsigned char *) verifybuf, length, NULL); + if (digest == NULL) { + error("Error digesting"); + exit(EXIT_FAILURE); + } + + rsa_res = RSA_verify(NID_sha1, digest, 20, sigbuf, siglen, rsa); + if (rsa_res == 1) { + result = RET_SUC; + } else if (rsa_res == 0) { + result = RET_FAIL; + } else { + warning("internal error when verifying: %d\n", rsa_res); + ERR_print_errors_fp(stdout); + result = RET_FAIL; + } + + xfree(modulus_bytes); + xfree(exponent_bytes); + RSA_free(rsa); + return result; +} + +int +verify_rrsig_rsamd5(uint8_t *verifybuf, unsigned long length, unsigned char *sigbuf, unsigned int siglen, + unsigned char *key_bytes, unsigned int keylen) +{ + BIGNUM *modulus; + BIGNUM *exponent; + unsigned char *modulus_bytes; + unsigned char *exponent_bytes; + int offset, explength; + unsigned char *digest; + uint16_t int16; + RSA *rsa; + int rsa_res; + + int result; + + if(key_bytes[0] == 0) { + memcpy(&int16, &key_bytes[1], 2); + int16 = ntohs(int16); + explength = (int) int16; + offset = 3; + } else { + explength = (int) key_bytes[0]; + offset = 1; + } + + /* Exponent */ + exponent_bytes = xmalloc(explength*sizeof(char)); + memcpy(exponent_bytes, &key_bytes[offset], explength*sizeof(char)); + exponent = BN_new(); + (void) BN_bin2bn(exponent_bytes, explength, exponent); + offset += explength; + + /* Modulus */ + modulus_bytes = xmalloc((keylen-offset)*sizeof(char)); + memcpy(modulus_bytes, &key_bytes[offset], (keylen-offset)*sizeof(char)); + modulus = BN_new(); + (void) BN_bin2bn(&modulus_bytes[0], (int) keylen-offset, modulus); + offset = (int) keylen; + + rsa = RSA_new(); + rsa->n = modulus; + rsa->e = exponent; + + digest = xmalloc(16); + digest = MD5((unsigned char *) verifybuf, length, digest); + if (digest == NULL) { + error("Error digesting\n"); + exit(EXIT_FAILURE); + } + + rsa_res = RSA_verify(NID_md5, digest, 16, sigbuf, siglen, rsa); + if (rsa_res == 1) { + result = RET_SUC; + } else if (rsa_res == 0) { + result = RET_FAIL; + } else { + warning("internal error when verifying: %d\n", rsa_res); + ERR_print_errors_fp(stdout); + result = RET_FAIL; + } + + xfree(digest); + xfree(modulus_bytes); + xfree(exponent_bytes); + RSA_free(rsa); + return result; +} + +/** + * Verifies the rrsig of the rrset with the dnskey + * What does result? + */ +int +verify_rrsig(struct t_rr *rrset, struct t_rr *rrsig, struct t_rr *dnskey) +{ + /* translate rrsig+rrset to binary data */ + uint8_t *verifybuf; + unsigned char *sigbuf; + unsigned char *key_bytes; + uint32_t int32; + unsigned long length = 0; + unsigned int siglen; + unsigned int keylen; + int result; + + verifybuf = xmalloc(MAX_PACKET); + sigbuf = (unsigned char *) base64_decode((unsigned char *) rrsig->rdata[8]->data, + (int) rrsig->rdata[8]->length, (size_t *) &siglen); + + length += sig2verifybytes(rrsig, verifybuf, length, MAX_PACKET); + rrset_sort(&rrset); + + /* set the ttl in the rrset... */ + int32 = rdata2uint32(rrsig->rdata[3]); + rrset_set_ttl(rrset, int32); + length += rrset2wire(rrset, verifybuf, length, MAX_PACKET); + key_bytes = (unsigned char *) base64_decode((unsigned char *) dnskey->rdata[3]->data, + (int) dnskey->rdata[3]->length, (size_t *) &keylen); + + if (keylen < 0) { + warning("Error in base64 decode of key data:"); + /* XXX TODO */ + print_rd(dnskey->rdata[3]); + printf("\n"); + return RET_FAIL; + } + switch (rdata2uint8(rrsig->rdata[1])) { + case ALG_DSA: + result = verify_rrsig_dsa(verifybuf, length, sigbuf, + siglen, key_bytes, keylen); + break; + case ALG_RSASHA1: + result = verify_rrsig_rsasha1(verifybuf, length, sigbuf, + siglen, key_bytes, keylen); + break; + case ALG_RSAMD5: + result = verify_rrsig_rsamd5(verifybuf, length, sigbuf, + siglen, key_bytes, keylen); + break; + default: + warning("unknown or unimplemented algorithm (alg %s nr %d)", namebyint(rdata2uint8(rrsig->rdata[1]), dnssec_algos), rdata2uint8(rrsig->rdata[1])); +print_rr(rrsig, FOLLOW); + exit(EXIT_FAILURE); + break; + } + + xfree(key_bytes); + xfree(verifybuf); + xfree(sigbuf); + + return result; +}