diff --git a/src/anchor.c b/src/anchor.c index 4db8cef5..9a2f76d1 100644 --- a/src/anchor.c +++ b/src/anchor.c @@ -37,14 +37,13 @@ #include #include #include +#include "types-internal.h" +#include "context.h" #define P7SIGNER "dnssec@iana.org" -static const char* -get_builtin_cert(void) -{ - return /* The ICANN CA fetched at 24 Sep 2010. Valid to 2028 */ +static const char* _getdns_builtin_cert = "-----BEGIN CERTIFICATE-----\n" "MIIDdzCCAl+gAwIBAgIBATANBgkqhkiG9w0BAQsFADBdMQ4wDAYDVQQKEwVJQ0FO\n" "TjEmMCQGA1UECxMdSUNBTk4gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFjAUBgNV\n" @@ -66,14 +65,14 @@ get_builtin_cert(void) "0/wsHNeP22qNyVO+XVBzrM8fk8BSUFuiT/6tZTYXRtEt5aKQZgXbKU5dUF3jT9qg\n" "j/Br5BZw3X/zd325TvnswzMC1+ljLzHnQGGk\n" "-----END CERTIFICATE-----\n"; -} /* get key usage out of its extension, returns 0 if no key_usage extension */ static unsigned long -get_usage_of_ex(X509* cert) +_getdns_get_usage_of_ex(X509* cert) { unsigned long val = 0; ASN1_BIT_STRING* s; + if((s=X509_get_ext_d2i(cert, NID_key_usage, NULL, NULL))) { if(s->length > 0) { val = s->data[0]; @@ -89,75 +88,57 @@ get_usage_of_ex(X509* cert) static STACK_OF(X509)* get_valid_signers(PKCS7* p7, const char* p7signer) { - const int verb = 5; int i; STACK_OF(X509)* validsigners = sk_X509_new_null(); STACK_OF(X509)* signers = PKCS7_get0_signers(p7, NULL, 0); unsigned long usage = 0; if(!validsigners) { - if(verb) printf("out of memory\n"); + DEBUG_ANCHOR("ERROR %s(): Failed to allocated validsigners\n" + , __FUNC__); sk_X509_free(signers); return NULL; } if(!signers) { - if(verb) printf("no signers in pkcs7 signature\n"); + DEBUG_ANCHOR("ERROR %s(): Failed to allocated signers\n" + , __FUNC__); sk_X509_free(validsigners); return NULL; } for(i=0; i= 3 && X509_NAME_get_text_by_NID(nm, - NID_commonName, buf, (int)sizeof(buf))) - printf("commonName: %s\n", buf); - if(verb >= 3 && X509_NAME_get_text_by_NID(nm, - NID_pkcs9_emailAddress, buf, (int)sizeof(buf))) - printf("emailAddress: %s\n", buf); - } - if(verb) { - int ku_loc = X509_get_ext_by_NID( - sk_X509_value(signers, i), NID_key_usage, -1); - if(verb >= 3 && ku_loc >= 0) { - X509_EXTENSION *ex = X509_get_ext( - sk_X509_value(signers, i), ku_loc); - if(ex) { - printf("keyUsage: "); - X509V3_EXT_print_fp(stdout, ex, 0, 0); - printf("\n"); - } - } - } if(!p7signer || strcmp(p7signer, "")==0) { /* there is no name to check, return all records */ - if(verb) printf("did not check commonName of signer\n"); + DEBUG_ANCHOR("%s(): did not check commonName of signer\n" + , __FUNC__); } else { if(!X509_NAME_get_text_by_NID(nm, NID_pkcs9_emailAddress, buf, (int)sizeof(buf))) { - if(verb) printf("removed cert with no name\n"); + DEBUG_ANCHOR("%s(): removed cert with no name\n" + , __FUNC__); continue; /* no name, no use */ } if(strcmp(buf, p7signer) != 0) { - if(verb) printf("removed cert with wrong name\n"); + DEBUG_ANCHOR("%s(): removed cert with wrong name\n" + , __FUNC__); continue; /* wrong name, skip it */ } } /* check that the key usage allows digital signatures * (the p7s) */ - usage = get_usage_of_ex(sk_X509_value(signers, i)); + usage = _getdns_get_usage_of_ex(sk_X509_value(signers, i)); if(!(usage & KU_DIGITAL_SIGNATURE)) { - if(verb) printf("removed cert with no key usage Digital Signature allowed\n"); + DEBUG_ANCHOR("%s(): removed cert with no key usage " + "Digital Signature allowed\n" + , __FUNC__); continue; } @@ -170,47 +151,34 @@ get_valid_signers(PKCS7* p7, const char* p7signer) } static int -verify_p7sig(BIO* data, BIO* p7s, X509_STORE *store, const char* p7signer) +_getdns_verify_p7sig(BIO* data, BIO* p7s, X509_STORE *store, const char* p7signer) { - const int verb = 5; PKCS7* p7; STACK_OF(X509)* validsigners; int secure = 0; #ifdef X509_V_FLAG_CHECK_SS_SIGNATURE X509_VERIFY_PARAM* param = X509_VERIFY_PARAM_new(); if(!param) { - if(verb) printf("out of memory\n"); - X509_STORE_free(store); + DEBUG_ANCHOR("ERROR %s(): Failed to allocated param\n" + , __FUNC__); return 0; } /* do the selfcheck on the root certificate; it checks that the * input is valid */ X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CHECK_SS_SIGNATURE); - if(store) X509_STORE_set1_param(store, param); -#endif - if(!store) { - if(verb) printf("out of memory\n"); -#ifdef X509_V_FLAG_CHECK_SS_SIGNATURE - X509_VERIFY_PARAM_free(param); -#endif - return 0; - } -#ifdef X509_V_FLAG_CHECK_SS_SIGNATURE + X509_STORE_set1_param(store, param); X509_VERIFY_PARAM_free(param); #endif - (void)BIO_reset(p7s); (void)BIO_reset(data); /* convert p7s to p7 (the signature) */ p7 = d2i_PKCS7_bio(p7s, NULL); if(!p7) { - if(verb) printf("could not parse p7s signature file\n"); - X509_STORE_free(store); + DEBUG_ANCHOR("ERROR %s(): could not parse p7s signature file\n" + , __FUNC__); return 0; } - if(verb >= 2) printf("parsed the PKCS7 signature\n"); - /* check what is in the Subject name of the certificates, * and build a stack that contains only the right certificates */ validsigners = get_valid_signers(p7, p7signer); @@ -218,19 +186,16 @@ verify_p7sig(BIO* data, BIO* p7s, X509_STORE *store, const char* p7signer) PKCS7_free(p7); return 0; } - BIO *out = BIO_new_fd(fileno(stdout), BIO_NOCLOSE); - BIO_printf(out, "Hello World\n"); - if(PKCS7_verify(p7, validsigners, store, data, out, PKCS7_NOINTERN) == 1) { + if(PKCS7_verify(p7, validsigners, store, data, NULL, PKCS7_NOINTERN) == 1) { secure = 1; - if(verb) printf("the PKCS7 signature verified\n"); - } else { - if(verb) printf("the PKCS7 signature did not verify\n"); - if(verb) { - ERR_print_errors_fp(stdout); - } } - BIO_free(out); - +#if defined(ANCHOR_DEBUG) && ANCHOR_DEBUG + else { + DEBUG_ANCHOR("ERROR %s(): the PKCS7 signature did not verify\n" + , __FUNC__); + ERR_print_errors_cb(_getdns_ERR_print_errors_cb_f, NULL); + } +#endif sk_X509_free(validsigners); PKCS7_free(p7); return secure; @@ -238,68 +203,60 @@ verify_p7sig(BIO* data, BIO* p7s, X509_STORE *store, const char* p7signer) void _getdns_context_equip_with_anchor(getdns_context *context) { - char fn[1024]; - int xml_fd, p7s_fd; - int n; - BIO *xml, *p7s, *crt; - X509 *x; - X509_STORE *store; - char *crt_str; + uint8_t xml_spc[16384], *xml_data = xml_spc; + uint8_t p7s_spc[16384], *p7s_data = p7s_spc; + size_t xml_len, p7s_len; - DEBUG_ANCHOR("entering %s\n", __FUNC__); + BIO *xml = NULL, *p7s = NULL, *crt = NULL; + X509 *x = NULL; + X509_STORE *store = NULL; + + if (!(xml_data = _getdns_context_get_priv_file(context, + "root-anchors.xml", xml_spc, sizeof(xml_spc), &xml_len))) + ; /* pass */ + + else if (!(p7s_data = _getdns_context_get_priv_file(context, + "root-anchors.p7s", p7s_spc, sizeof(p7s_spc), &p7s_len))) + ; /* pass */ + + else if (!(xml = BIO_new_mem_buf(xml_data, xml_len))) + DEBUG_ANCHOR("ERROR %s(): Failed allocating xml BIO\n" + , __FUNC__); + + else if (!(p7s = BIO_new_mem_buf(p7s_data, p7s_len))) + DEBUG_ANCHOR("ERROR %s(): Failed allocating p7s BIO\n" + , __FUNC__); - n = snprintf( fn, sizeof(fn) - , "%s/.getdns/root-anchors.xml", getenv("HOME")); + else if (!(crt = BIO_new_mem_buf(_getdns_builtin_cert, -1))) + DEBUG_ANCHOR("ERROR %s(): Failed allocating crt BIO\n" + , __FUNC__); - if (n < 0 || n >= (int)sizeof(fn)) - return; + else if (!(x = PEM_read_bio_X509(crt, NULL, 0, NULL))) + DEBUG_ANCHOR("ERROR %s(): Parsing builtin certificate\n" + , __FUNC__); - if ((xml_fd = open(fn, O_RDONLY)) < 0) - return; + else if (!(store = X509_STORE_new())) + DEBUG_ANCHOR("ERROR %s(): Failed allocating store\n" + , __FUNC__); - (void) snprintf( fn, sizeof(fn) - , "%s/.getdns/root-anchors.p7s", getenv("HOME")); + else if (!X509_STORE_add_cert(store, x)) + DEBUG_ANCHOR("ERROR %s(): Adding certificate to store\n" + , __FUNC__); - if ((p7s_fd = open(fn, O_RDONLY)) < 0) { - close(xml_fd); - return; - } - if (!(xml = BIO_new_fd(xml_fd, 1))) { - close(xml_fd); - close(p7s_fd); - return; - } - if (!(p7s = BIO_new_fd(p7s_fd, 1))) { - BIO_free(xml); - close(p7s_fd); - return; - } - if (!(crt_str = strdup(get_builtin_cert()))) - goto error_free_xml; - if (!(crt = BIO_new_mem_buf(crt_str, (int)strlen(crt_str)))) - goto error_free_str; - if (!(store = X509_STORE_new())) - goto error_free_crt; - if (!(x = PEM_read_bio_X509(crt, NULL, 0, NULL))) - goto error_free_store; - if (!X509_STORE_add_cert(store, x)) - goto error_free_store; - if (verify_p7sig(xml, p7s, store, "dnssec@iana.org")) { + else if (_getdns_verify_p7sig(xml, p7s, store, "dnssec@iana.org")) { DEBUG_ANCHOR("Verifying trust-anchors SUCCEEDED, Yay!\n"); - ; } else { DEBUG_ANCHOR("Verifying trust-anchors failed!\n"); - ; } -error_free_store: - X509_STORE_free(store); -error_free_crt: - BIO_free(crt); -error_free_str: - free(crt_str); -error_free_xml: - BIO_free(xml); - BIO_free(p7s); + if (store) X509_STORE_free(store); + if (x) X509_free(x); + if (crt) BIO_free(crt); + if (xml) BIO_free(xml); + if (p7s) BIO_free(p7s); + if (xml_data && xml_data != xml_spc) + GETDNS_FREE(context->mf, xml_data); + if (p7s_data && p7s_data != p7s_spc) + GETDNS_FREE(context->mf, p7s_data); } /* anchor.c */ diff --git a/src/context.c b/src/context.c index 4bfc8a24..3d6144b6 100644 --- a/src/context.c +++ b/src/context.c @@ -4456,4 +4456,37 @@ getdns_context_config(getdns_context *context, const getdns_dict *config_dict) return r; } +uint8_t *_getdns_context_get_priv_file(getdns_context *context, + const char *fn, uint8_t *buf, size_t buf_len, size_t *file_sz) +{ + char path[FILENAME_MAX]; + int n; + FILE *f; + + n = snprintf(path, sizeof(path), "%s/.getdns/%s", getenv("HOME"), fn); + if (n < 0 || n > FILENAME_MAX) + return NULL; + + if (!(f = fopen(path, "r"))) + return NULL; + + if ((*file_sz = fread(buf, 1, buf_len, f)) < buf_len && feof(f)) + ; /* pass */ + + else if (fseek(f, 0, SEEK_END) < 0) + buf = NULL; + + else if ((buf = GETDNS_XMALLOC( + context->mf, uint8_t, (buf_len = ftell(f) + 1)))) { + + rewind(f); + if ((*file_sz = fread(buf, 1, buf_len, f)) >= buf_len || !feof(f)) { + GETDNS_FREE(context->mf, buf); + buf = NULL; + } + } + (void) fclose(f); + return buf; +} + /* context.c */ diff --git a/src/context.h b/src/context.h index 21090da1..862460b5 100644 --- a/src/context.h +++ b/src/context.h @@ -455,4 +455,7 @@ void _getdns_upstreams_dereference(getdns_upstreams *upstreams); void _getdns_upstream_shutdown(getdns_upstream *upstream); +uint8_t *_getdns_context_get_priv_file(getdns_context *context, + const char *fn, uint8_t *buf, size_t buf_len, size_t *file_sz); + #endif /* _GETDNS_CONTEXT_H_ */ diff --git a/src/debug.h b/src/debug.h index 7f1766af..647d712f 100644 --- a/src/debug.h +++ b/src/debug.h @@ -179,6 +179,9 @@ static inline void debug_req(const char *msg, getdns_network_req *netreq) (defined(MDNS_DEBUG) && MDNS_DEBUG) || \ (defined(ANCHOR_DEBUG) && ANCHOR_DEBUG) #define DEBUGGING 1 +static inline int +_getdns_ERR_print_errors_cb_f(const char *str, size_t len, void *u) +{ DEBUG_ON("%.*s (u: %p)\n", (int)len, str, u); return 1; } #endif #endif