- [dnscrypt] prevent dnscrypt-secret-key, dnscrypt-provider-cert

duplicates
- [dnscrypt] introduce dnscrypt-provider-cert-rotated option,
  from Manu Bretelle.
	This option allows handling multiple cert/key pairs while only
	distributing some of them.
	In order to reliably match a client magic with a given key without
	strong assumption as to how those were generated, we need both key and
	cert. Likewise, in order to know which ES version should be used.
	On the other hand, when rotating a cert, it can be desirable to only
	serve the new cert but still be able to handle clients that are still
	using the old certs's public key.
	The `dnscrypt-provider-cert-rotated` allow to instruct unbound to not
	publish the cert as part of the DNS's provider_name's TXT answer.



git-svn-id: file:///svn/unbound/trunk@4373 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards
2017-10-17 07:34:49 +00:00
parent 5ad3bbb27f
commit 52e2331dd4
11 changed files with 1819 additions and 1666 deletions
+46 -3
View File
@@ -5,6 +5,7 @@
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#include <inttypes.h>
#include <sys/time.h>
#include <sys/types.h>
#include "sldns/sbuffer.h"
@@ -588,18 +589,26 @@ dnsc_chroot_path(struct config_file *cfg, char *path)
static int
dnsc_parse_certs(struct dnsc_env *env, struct config_file *cfg)
{
struct config_strlist *head;
struct config_strlist *head, *head2;
size_t signed_cert_id;
size_t rotated_cert_id;
char *nm;
env->signed_certs_count = 0U;
env->rotated_certs_count = 0U;
for (head = cfg->dnscrypt_provider_cert; head; head = head->next) {
env->signed_certs_count++;
}
for (head = cfg->dnscrypt_provider_cert_rotated; head; head = head->next) {
env->rotated_certs_count++;
}
env->signed_certs = sodium_allocarray(env->signed_certs_count,
sizeof *env->signed_certs);
env->rotated_certs = sodium_allocarray(env->rotated_certs_count,
sizeof env->signed_certs);
signed_cert_id = 0U;
rotated_cert_id = 0U;
for(head = cfg->dnscrypt_provider_cert; head; head = head->next, signed_cert_id++) {
nm = dnsc_chroot_path(cfg, head->str);
if(dnsc_read_from_file(
@@ -608,6 +617,14 @@ dnsc_parse_certs(struct dnsc_env *env, struct config_file *cfg)
sizeof(struct SignedCert)) != 0) {
fatal_exit("dnsc_parse_certs: failed to load %s: %s", head->str, strerror(errno));
}
for(head2 = cfg->dnscrypt_provider_cert_rotated; head2; head2 = head2->next) {
if(strcmp(head->str, head2->str) == 0) {
*(env->rotated_certs + rotated_cert_id) = env->signed_certs + signed_cert_id;
rotated_cert_id++;
verbose(VERB_OPS, "Cert %s is rotated and will not be distributed via DNS", head->str);
break;
}
}
verbose(VERB_OPS, "Loaded cert %s", head->str);
}
return signed_cert_id;
@@ -692,7 +709,27 @@ dnsc_load_local_data(struct dnsc_env* dnscenv, struct config_file *cfg)
// 2.dnscrypt-cert.example.com 86400 IN TXT "DNSC......"
for(i=0; i<dnscenv->signed_certs_count; i++) {
const char *ttl_class_type = " 86400 IN TXT \"";
int rotated_cert = 0;
uint32_t serial;
struct SignedCert *cert = dnscenv->signed_certs + i;
// Check if the certificate is being rotated and should not be published
for(j=0; j<dnscenv->rotated_certs_count; j++){
if(cert == dnscenv->rotated_certs[j]) {
rotated_cert = 1;
break;
}
}
memcpy(&serial, cert->serial, sizeof serial);
serial = htonl(serial);
if(rotated_cert) {
verbose(VERB_OPS,
"DNSCrypt: not adding cert with serial #%"
PRIu32
" to local-data as it is rotated",
serial
);
continue;
}
uint16_t rrlen = strlen(dnscenv->provider_name) +
strlen(ttl_class_type) +
4 * sizeof(struct SignedCert) + // worst case scenario
@@ -705,14 +742,19 @@ dnsc_load_local_data(struct dnsc_env* dnscenv, struct config_file *cfg)
}
snprintf(rr, rrlen - 1, "%s 86400 IN TXT \"", dnscenv->provider_name);
for(j=0; j<sizeof(struct SignedCert); j++) {
int c = (int)*((const uint8_t *) cert + j);
int c = (int)*((const uint8_t *) cert + j);
if (isprint(c) && c != '"' && c != '\\') {
snprintf(rr + strlen(rr), rrlen - 1 - strlen(rr), "%c", c);
} else {
snprintf(rr + strlen(rr), rrlen - 1 - strlen(rr), "\\%03d", c);
}
}
verbose(VERB_OPS, "DNSCrypt: adding local data to config: %s", rr);
verbose(VERB_OPS,
"DNSCrypt: adding cert with serial #%"
PRIu32
" to local-data to config: %s",
serial, rr
);
snprintf(rr + strlen(rr), rrlen - 1 - strlen(rr), "\"");
cfg_strlist_insert(&cfg->local_data, strdup(rr));
free(rr);
@@ -957,6 +999,7 @@ dnsc_delete(struct dnsc_env *env)
}
verbose(VERB_OPS, "DNSCrypt: Freeing environment.");
sodium_free(env->signed_certs);
sodium_free(env->rotated_certs);
sodium_free(env->certs);
sodium_free(env->keypairs);
slabhash_delete(env->shared_secrets_cache);
+2
View File
@@ -54,8 +54,10 @@ typedef struct cert_ {
struct dnsc_env {
struct SignedCert *signed_certs;
struct SignedCert **rotated_certs;
dnsccert *certs;
size_t signed_certs_count;
size_t rotated_certs_count;
uint8_t provider_publickey[crypto_sign_ed25519_PUBLICKEYBYTES];
uint8_t provider_secretkey[crypto_sign_ed25519_SECRETKEYBYTES];
KeyPair *keypairs;
+15 -1
View File
@@ -1,6 +1,20 @@
11 October 2017: Wouter
17 October 2017: Wouter
- Fix #1749: With harden-referral-path: performance drops, due to
circular dependency in NS and DS lookups.
- [dnscrypt] prevent dnscrypt-secret-key, dnscrypt-provider-cert
duplicates
- [dnscrypt] introduce dnscrypt-provider-cert-rotated option,
from Manu Bretelle.
This option allows handling multiple cert/key pairs while only
distributing some of them.
In order to reliably match a client magic with a given key without
strong assumption as to how those were generated, we need both key and
cert. Likewise, in order to know which ES version should be used.
On the other hand, when rotating a cert, it can be desirable to only
serve the new cert but still be able to handle clients that are still
using the old certs's public key.
The `dnscrypt-provider-cert-rotated` allow to instruct unbound to not
publish the cert as part of the DNS's provider_name's TXT answer.
10 October 2017: Wouter
- tag 1.6.7
+13
View File
@@ -1513,6 +1513,19 @@ times.
Path to the certificate related to the \fBdnscrypt\-secret\-key\fRs.
This option may be specified multiple times.
.TP
.B dnscrypt\-provider\-cert\-rotated: \fI<path to cert file>\fR
Path to a certificate that we should be able to serve existing connection from
but do not want to advertise over \fBdnscrypt\-provider\fR's TXT record certs
distribution.
A typical use case is when rotating certificates, existing clients may still use
the client magic from the old cert in their queries until they fetch and update
the new cert. Likewise, it would allow to prime the new cert/key without
distributing the new cert yet, this can be useful when using a network of
servers using anycast and on which the configuration may not get updated at the
exact same time. By priming the cert, the servers can handle both old and new
certs traffic while distributing only one.
This option may be specified multiple times.
.TP
.B dnscrypt\-shared\-secret\-cache\-size: \fI<memory size>
Give the size of the data structure in which the shared secret keys are kept
in. Default 4m. In bytes or use m(mega), k(kilo), g(giga).
+25 -2
View File
@@ -282,6 +282,7 @@ config_create(void)
cfg->dnscrypt_port = 0;
cfg->dnscrypt_provider = NULL;
cfg->dnscrypt_provider_cert = NULL;
cfg->dnscrypt_provider_cert_rotated = NULL;
cfg->dnscrypt_secret_key = NULL;
cfg->dnscrypt_shared_secret_cache_size = 4*1024*1024;
cfg->dnscrypt_shared_secret_cache_slabs = 4;
@@ -374,6 +375,10 @@ struct config_file* config_create_forlib(void)
/** put string into strlist */
#define S_STRLIST(str, var) if(strcmp(opt, str)==0) \
{ return cfg_strlist_insert(&cfg->var, strdup(val)); }
/** put string into strlist if not present yet*/
#define S_STRLIST_UNIQ(str, var) if(strcmp(opt, str)==0) \
{ if(cfg_strlist_find(cfg->var, val)) { return 0;} \
return cfg_strlist_insert(&cfg->var, strdup(val)); }
int config_set_option(struct config_file* cfg, const char* opt,
const char* val)
@@ -570,8 +575,9 @@ int config_set_option(struct config_file* cfg, const char* opt,
else S_YNO("dnscrypt-enable:", dnscrypt)
else S_NUMBER_NONZERO("dnscrypt-port:", dnscrypt_port)
else S_STR("dnscrypt-provider:", dnscrypt_provider)
else S_STRLIST("dnscrypt-provider-cert:", dnscrypt_provider_cert)
else S_STRLIST("dnscrypt-secret-key:", dnscrypt_secret_key)
else S_STRLIST_UNIQ("dnscrypt-provider-cert:", dnscrypt_provider_cert)
else S_STRLIST("dnscrypt-provider-cert-rotated:", dnscrypt_provider_cert_rotated)
else S_STRLIST_UNIQ("dnscrypt-secret-key:", dnscrypt_secret_key)
else S_MEMSIZE("dnscrypt-shared-secret-cache-size:",
dnscrypt_shared_secret_cache_size)
else S_POW2("dnscrypt-shared-secret-cache-slabs:",
@@ -941,6 +947,7 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_DEC(opt, "dnscrypt-port", dnscrypt_port)
else O_STR(opt, "dnscrypt-provider", dnscrypt_provider)
else O_LST(opt, "dnscrypt-provider-cert", dnscrypt_provider_cert)
else O_LST(opt, "dnscrypt-provider-cert-rotated", dnscrypt_provider_cert_rotated)
else O_LST(opt, "dnscrypt-secret-key", dnscrypt_secret_key)
else O_MEM(opt, "dnscrypt-shared-secret-cache-size",
dnscrypt_shared_secret_cache_size)
@@ -1458,6 +1465,22 @@ cfg_region_strlist_insert(struct regional* region,
return 1;
}
struct config_strlist*
cfg_strlist_find(struct config_strlist* head, const char *item)
{
struct config_strlist *s = head;
if(!head){
return NULL;
}
while(s) {
if(strcmp(s->str, item) == 0) {
return s;
}
s = s->next;
}
return NULL;
}
int
cfg_strlist_insert(struct config_strlist** head, char* item)
{
+13
View File
@@ -466,6 +466,10 @@ struct config_file {
struct config_strlist* dnscrypt_secret_key;
/** dnscrypt provider certs 1.cert */
struct config_strlist* dnscrypt_provider_cert;
/** dnscrypt provider certs 1.cert which have been rotated and should not be
* advertised through DNS's providername TXT record but are required to be
* able to handle existing traffic using the old cert. */
struct config_strlist* dnscrypt_provider_cert_rotated;
/** memory size in bytes for dnscrypt shared secrets cache */
size_t dnscrypt_shared_secret_cache_size;
/** number of slabs for dnscrypt shared secrets cache */
@@ -720,6 +724,15 @@ char* config_collate_cat(struct config_strlist* list);
*/
int cfg_strlist_append(struct config_strlist_head* list, char* item);
/**
* Find string in strlist.
* @param head: pointer to strlist head variable.
* @param item: the item to search for.
* @return: the element in the list when found, NULL otherwise.
*/
struct config_strlist* cfg_strlist_find(struct config_strlist* head,
const char* item);
/**
* Insert string into strlist.
* @param head: pointer to strlist head variable.
+795 -783
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -417,6 +417,7 @@ dnscrypt-port{COLON} { YDVAR(1, VAR_DNSCRYPT_PORT) }
dnscrypt-provider{COLON} { YDVAR(1, VAR_DNSCRYPT_PROVIDER) }
dnscrypt-secret-key{COLON} { YDVAR(1, VAR_DNSCRYPT_SECRET_KEY) }
dnscrypt-provider-cert{COLON} { YDVAR(1, VAR_DNSCRYPT_PROVIDER_CERT) }
dnscrypt-provider-cert-rotated{COLON} { YDVAR(1, VAR_DNSCRYPT_PROVIDER_CERT_ROTATED) }
dnscrypt-shared-secret-cache-size{COLON} {
YDVAR(1, VAR_DNSCRYPT_SHARED_SECRET_CACHE_SIZE) }
dnscrypt-shared-secret-cache-slabs{COLON} {
+865 -848
View File
File diff suppressed because it is too large Load Diff
+31 -29
View File
@@ -252,20 +252,21 @@ extern int yydebug;
VAR_DNSCRYPT_PROVIDER = 462,
VAR_DNSCRYPT_SECRET_KEY = 463,
VAR_DNSCRYPT_PROVIDER_CERT = 464,
VAR_DNSCRYPT_SHARED_SECRET_CACHE_SIZE = 465,
VAR_DNSCRYPT_SHARED_SECRET_CACHE_SLABS = 466,
VAR_DNSCRYPT_NONCE_CACHE_SIZE = 467,
VAR_DNSCRYPT_NONCE_CACHE_SLABS = 468,
VAR_IPSECMOD_ENABLED = 469,
VAR_IPSECMOD_HOOK = 470,
VAR_IPSECMOD_IGNORE_BOGUS = 471,
VAR_IPSECMOD_MAX_TTL = 472,
VAR_IPSECMOD_WHITELIST = 473,
VAR_IPSECMOD_STRICT = 474,
VAR_CACHEDB = 475,
VAR_CACHEDB_BACKEND = 476,
VAR_CACHEDB_SECRETSEED = 477,
VAR_UDP_UPSTREAM_WITHOUT_DOWNSTREAM = 478
VAR_DNSCRYPT_PROVIDER_CERT_ROTATED = 465,
VAR_DNSCRYPT_SHARED_SECRET_CACHE_SIZE = 466,
VAR_DNSCRYPT_SHARED_SECRET_CACHE_SLABS = 467,
VAR_DNSCRYPT_NONCE_CACHE_SIZE = 468,
VAR_DNSCRYPT_NONCE_CACHE_SLABS = 469,
VAR_IPSECMOD_ENABLED = 470,
VAR_IPSECMOD_HOOK = 471,
VAR_IPSECMOD_IGNORE_BOGUS = 472,
VAR_IPSECMOD_MAX_TTL = 473,
VAR_IPSECMOD_WHITELIST = 474,
VAR_IPSECMOD_STRICT = 475,
VAR_CACHEDB = 476,
VAR_CACHEDB_BACKEND = 477,
VAR_CACHEDB_SECRETSEED = 478,
VAR_UDP_UPSTREAM_WITHOUT_DOWNSTREAM = 479
};
#endif
/* Tokens. */
@@ -476,20 +477,21 @@ extern int yydebug;
#define VAR_DNSCRYPT_PROVIDER 462
#define VAR_DNSCRYPT_SECRET_KEY 463
#define VAR_DNSCRYPT_PROVIDER_CERT 464
#define VAR_DNSCRYPT_SHARED_SECRET_CACHE_SIZE 465
#define VAR_DNSCRYPT_SHARED_SECRET_CACHE_SLABS 466
#define VAR_DNSCRYPT_NONCE_CACHE_SIZE 467
#define VAR_DNSCRYPT_NONCE_CACHE_SLABS 468
#define VAR_IPSECMOD_ENABLED 469
#define VAR_IPSECMOD_HOOK 470
#define VAR_IPSECMOD_IGNORE_BOGUS 471
#define VAR_IPSECMOD_MAX_TTL 472
#define VAR_IPSECMOD_WHITELIST 473
#define VAR_IPSECMOD_STRICT 474
#define VAR_CACHEDB 475
#define VAR_CACHEDB_BACKEND 476
#define VAR_CACHEDB_SECRETSEED 477
#define VAR_UDP_UPSTREAM_WITHOUT_DOWNSTREAM 478
#define VAR_DNSCRYPT_PROVIDER_CERT_ROTATED 465
#define VAR_DNSCRYPT_SHARED_SECRET_CACHE_SIZE 466
#define VAR_DNSCRYPT_SHARED_SECRET_CACHE_SLABS 467
#define VAR_DNSCRYPT_NONCE_CACHE_SIZE 468
#define VAR_DNSCRYPT_NONCE_CACHE_SLABS 469
#define VAR_IPSECMOD_ENABLED 470
#define VAR_IPSECMOD_HOOK 471
#define VAR_IPSECMOD_IGNORE_BOGUS 472
#define VAR_IPSECMOD_MAX_TTL 473
#define VAR_IPSECMOD_WHITELIST 474
#define VAR_IPSECMOD_STRICT 475
#define VAR_CACHEDB 476
#define VAR_CACHEDB_BACKEND 477
#define VAR_CACHEDB_SECRETSEED 478
#define VAR_UDP_UPSTREAM_WITHOUT_DOWNSTREAM 479
/* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
@@ -500,7 +502,7 @@ union YYSTYPE
char* str;
#line 504 "util/configparser.h" /* yacc.c:1909 */
#line 506 "util/configparser.h" /* yacc.c:1909 */
};
typedef union YYSTYPE YYSTYPE;
+13
View File
@@ -144,6 +144,7 @@ extern struct config_parser_state* cfg_parser;
%token VAR_USE_SYSTEMD VAR_SHM_ENABLE VAR_SHM_KEY
%token VAR_DNSCRYPT VAR_DNSCRYPT_ENABLE VAR_DNSCRYPT_PORT VAR_DNSCRYPT_PROVIDER
%token VAR_DNSCRYPT_SECRET_KEY VAR_DNSCRYPT_PROVIDER_CERT
%token VAR_DNSCRYPT_PROVIDER_CERT_ROTATED
%token VAR_DNSCRYPT_SHARED_SECRET_CACHE_SIZE
%token VAR_DNSCRYPT_SHARED_SECRET_CACHE_SLABS
%token VAR_DNSCRYPT_NONCE_CACHE_SIZE
@@ -2339,6 +2340,7 @@ contents_dnsc: contents_dnsc content_dnsc
content_dnsc:
dnsc_dnscrypt_enable | dnsc_dnscrypt_port | dnsc_dnscrypt_provider |
dnsc_dnscrypt_secret_key | dnsc_dnscrypt_provider_cert |
dnsc_dnscrypt_provider_cert_rotated |
dnsc_dnscrypt_shared_secret_cache_size |
dnsc_dnscrypt_shared_secret_cache_slabs |
dnsc_dnscrypt_nonce_cache_size |
@@ -2374,13 +2376,24 @@ dnsc_dnscrypt_provider: VAR_DNSCRYPT_PROVIDER STRING_ARG
dnsc_dnscrypt_provider_cert: VAR_DNSCRYPT_PROVIDER_CERT STRING_ARG
{
OUTYY(("P(dnsc_dnscrypt_provider_cert:%s)\n", $2));
if(cfg_strlist_find(cfg_parser->cfg->dnscrypt_provider_cert, $2))
fatal_exit("dnscrypt-provider-cert %s is a duplicate", $2);
if(!cfg_strlist_insert(&cfg_parser->cfg->dnscrypt_provider_cert, $2))
fatal_exit("out of memory adding dnscrypt-provider-cert");
}
;
dnsc_dnscrypt_provider_cert_rotated: VAR_DNSCRYPT_PROVIDER_CERT_ROTATED STRING_ARG
{
OUTYY(("P(dnsc_dnscrypt_provider_cert_rotated:%s)\n", $2));
if(!cfg_strlist_insert(&cfg_parser->cfg->dnscrypt_provider_cert_rotated, $2))
fatal_exit("out of memory adding dnscrypt-provider-cert-rotated");
}
;
dnsc_dnscrypt_secret_key: VAR_DNSCRYPT_SECRET_KEY STRING_ARG
{
OUTYY(("P(dnsc_dnscrypt_secret_key:%s)\n", $2));
if(cfg_strlist_find(cfg_parser->cfg->dnscrypt_secret_key, $2))
fatal_exit("dnscrypt-secret-key: %s is a duplicate", $2);
if(!cfg_strlist_insert(&cfg_parser->cfg->dnscrypt_secret_key, $2))
fatal_exit("out of memory adding dnscrypt-secret-key");
}