mirror of https://github.com/getdnsapi/getdns.git
Start with getting files from user area
This commit is contained in:
parent
b0af051809
commit
e496d13777
201
src/anchor.c
201
src/anchor.c
|
@ -37,14 +37,13 @@
|
|||
#include <openssl/x509.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#include <openssl/err.h>
|
||||
#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<sk_X509_num(signers); i++) {
|
||||
char buf[1024];
|
||||
X509_NAME* nm = X509_get_subject_name(
|
||||
sk_X509_value(signers, i));
|
||||
char buf[1024];
|
||||
if(!nm) {
|
||||
if(verb) printf("signer %d: cert has no subject name\n", i);
|
||||
DEBUG_ANCHOR("%s(): cert %d has no subject name\n"
|
||||
, __FUNC__, i);
|
||||
continue;
|
||||
}
|
||||
if(verb && nm) {
|
||||
char* nmline = X509_NAME_oneline(nm, buf,
|
||||
(int)sizeof(buf));
|
||||
printf("signer %d: Subject: %s\n", i,
|
||||
nmline?nmline:"no subject");
|
||||
if(verb >= 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_STORE_set1_param(store, param);
|
||||
X509_VERIFY_PARAM_free(param);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#ifdef X509_V_FLAG_CHECK_SS_SIGNATURE
|
||||
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);
|
||||
}
|
||||
#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);
|
||||
}
|
||||
BIO_free(out);
|
||||
|
||||
#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;
|
||||
|
||||
n = snprintf( fn, sizeof(fn)
|
||||
, "%s/.getdns/root-anchors.xml", getenv("HOME"));
|
||||
if (!(xml_data = _getdns_context_get_priv_file(context,
|
||||
"root-anchors.xml", xml_spc, sizeof(xml_spc), &xml_len)))
|
||||
; /* pass */
|
||||
|
||||
if (n < 0 || n >= (int)sizeof(fn))
|
||||
return;
|
||||
else if (!(p7s_data = _getdns_context_get_priv_file(context,
|
||||
"root-anchors.p7s", p7s_spc, sizeof(p7s_spc), &p7s_len)))
|
||||
; /* pass */
|
||||
|
||||
if ((xml_fd = open(fn, O_RDONLY)) < 0)
|
||||
return;
|
||||
else if (!(xml = BIO_new_mem_buf(xml_data, xml_len)))
|
||||
DEBUG_ANCHOR("ERROR %s(): Failed allocating xml BIO\n"
|
||||
, __FUNC__);
|
||||
|
||||
(void) snprintf( fn, sizeof(fn)
|
||||
, "%s/.getdns/root-anchors.p7s", getenv("HOME"));
|
||||
else if (!(p7s = BIO_new_mem_buf(p7s_data, p7s_len)))
|
||||
DEBUG_ANCHOR("ERROR %s(): Failed allocating p7s BIO\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 (!(crt = BIO_new_mem_buf(_getdns_builtin_cert, -1)))
|
||||
DEBUG_ANCHOR("ERROR %s(): Failed allocating crt BIO\n"
|
||||
, __FUNC__);
|
||||
|
||||
else if (!(x = PEM_read_bio_X509(crt, NULL, 0, NULL)))
|
||||
DEBUG_ANCHOR("ERROR %s(): Parsing builtin certificate\n"
|
||||
, __FUNC__);
|
||||
|
||||
else if (!(store = X509_STORE_new()))
|
||||
DEBUG_ANCHOR("ERROR %s(): Failed allocating store\n"
|
||||
, __FUNC__);
|
||||
|
||||
else if (!X509_STORE_add_cert(store, x))
|
||||
DEBUG_ANCHOR("ERROR %s(): Adding certificate to store\n"
|
||||
, __FUNC__);
|
||||
|
||||
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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue