eg. with the @port suffix, as this port number, they provide dns over TLS
service. Can list multiple, each on a new statement.
.TP
+.B tls-session-ticket-keys: \fI<file>
+If not "", lists files with 80 bytes of random contents that are used to
+perform TLS session resumption for clients using the unbound server.
+These files contain the secret key for the TLS session tickets.
+First key use to encrypt and decrypt TLS session tickets.
+Other keys use to decrypt only. With this you can roll over to new keys,
+by generating a new first file and allowing decrypt of the old file by
+listing it after the first file for some time, after the wait clients are not
+using the old key any more and the old key can be removed.
+.TP
.B tls\-ciphers: \fI<string with cipher list>
Set the list of ciphers to allow when serving TLS. Use "" for defaults,
and that is the default.
int LOG_TAG_QUERYREPLY = 0;
static struct tls_session_ticket_key {
- unsigned char *key_name;
- unsigned char *aes_key;
- unsigned char *hmac_key;
+ unsigned char *key_name;
+ unsigned char *aes_key;
+ unsigned char *hmac_key;
} *ticket_keys;
/* returns true is string addr is an ip6 specced address */
s++;
}
keys = calloc(s, sizeof(struct tls_session_ticket_key));
- memset(keys, 0, sizeof(*keys));
+ memset(keys, 0, s*sizeof(*keys));
ticket_keys = keys;
for(p = tls_session_ticket_keys; p; p = p->next) {
keys->hmac_key = data + 48;
keys++;
}
+ /* terminate array with NULL key name entry */
keys->key_name = NULL;
- if(SSL_CTX_set_tlsext_ticket_key_cb(sslctx, tls_session_ticket_key_cb) == 0) {
+ if(SSL_CTX_set_tlsext_ticket_key_cb(sslctx, tls_session_ticket_key_cb) == 0) {
log_err("no support for TLS session ticket");
return 0;
- }
- return 1;
+ }
+ return 1;
#else
return 0;
#endif
}
-int tls_session_ticket_key_cb(void *ATTR_UNUSED(sslctx), unsigned char* key_name,unsigned char* iv, void *evp_sctx, void *hmac_ctx, int enc)
+int tls_session_ticket_key_cb(void *ATTR_UNUSED(sslctx), unsigned char* key_name, unsigned char* iv, void *evp_sctx, void *hmac_ctx, int enc)
{
#ifdef HAVE_SSL
- const EVP_MD *digest;
- const EVP_CIPHER *cipher;
- int evp_chiper_length;
+ const EVP_MD *digest;
+ const EVP_CIPHER *cipher;
+ int evp_cipher_length;
digest = EVP_sha256();
cipher = EVP_aes_256_cbc();
- evp_chiper_length = EVP_CIPHER_iv_length(cipher);
+ evp_cipher_length = EVP_CIPHER_iv_length(cipher);
if( enc == 1 ) {
/* encrypt */
verbose(VERB_CLIENT, "start session encrypt");
memcpy(key_name, ticket_keys->key_name, 16);
- if (RAND_bytes(iv, evp_chiper_length) != 1) {
+ if (RAND_bytes(iv, evp_cipher_length) != 1) {
verbose(VERB_CLIENT, "RAND_bytes failed");
- return -1;
+ return -1;
}
- if (EVP_EncryptInit_ex(evp_sctx, cipher, NULL, ticket_keys->aes_key, iv) != 1) {
+ if (EVP_EncryptInit_ex(evp_sctx, cipher, NULL, ticket_keys->aes_key, iv) != 1) {
verbose(VERB_CLIENT, "EVP_EncryptInit_ex failed");
- return -1;
+ return -1;
}
- if (HMAC_Init_ex(hmac_ctx, ticket_keys->hmac_key, 32, digest, NULL) != 1) {
+ if (HMAC_Init_ex(hmac_ctx, ticket_keys->hmac_key, 32, digest, NULL) != 1) {
verbose(VERB_CLIENT, "HMAC_Init_ex failed");
- return -1;
- }
- return 1;
- } else if (enc == 0) {
+ return -1;
+ }
+ return 1;
+ } else if (enc == 0) {
/* decrypt */
struct tls_session_ticket_key *key;
verbose(VERB_CLIENT, "start session decrypt");
for(key = ticket_keys; key->key_name != NULL; key++) {
- if (!memcmp(key_name, key->key_name, 16)) {
+ if (!memcmp(key_name, key->key_name, 16)) {
verbose(VERB_CLIENT, "Found session_key");
break;
}
return 0;
}
- if (HMAC_Init_ex(hmac_ctx, key->hmac_key, 32, digest, NULL) != 1) {
+ if (HMAC_Init_ex(hmac_ctx, key->hmac_key, 32, digest, NULL) != 1) {
verbose(VERB_CLIENT, "HMAC_Init_ex failed");
- return -1;
- }
- if (EVP_DecryptInit_ex(evp_sctx, cipher, NULL, key->aes_key, iv) != 1) {
+ return -1;
+ }
+ if (EVP_DecryptInit_ex(evp_sctx, cipher, NULL, key->aes_key, iv) != 1) {
log_err("EVP_DecryptInit_ex failed");
- return -1;
- }
+ return -1;
+ }
return (key == ticket_keys) ? 1 : 2;
}
- return -1;
+ return -1;
#else
return 0;
#endif
+}
+void
+listen_sslctx_delete_ticket_keys(void)
+{
+ struct tls_session_ticket_key *key;
+ if(!ticket_keys) return;
+ for(key = ticket_keys; key->key_name != NULL; key++) {
+ free(key->key_name);
+ }
+ free(ticket_keys);
+ ticket_keys = NULL;
}
* @param tls_session_ticket_keys: TLS ticket secret filenames
* @return false on failure (alloc failure).
*/
-int listen_sslctx_setup_ticket_keys(void* sslctx, struct config_strlist* tls_session_ticket_keys);
+int listen_sslctx_setup_ticket_keys(void* sslctx,
+ struct config_strlist* tls_session_ticket_keys);
/**
* callback TLS session ticket encrypt and decrypt
+ * For use with SSL_CTX_set_tlsext_ticket_key_cb
* @param s: the SSL_CTX to use (from connect_sslctx_create())
- * @param key_name: secret name
- * @param iv:
- * @param evp_ctx:
- * @param hmac_ctx:
+ * @param key_name: secret name, 16 bytes
+ * @param iv: up to EVP_MAX_IV_LENGTH.
+ * @param evp_ctx: the evp cipher context, function sets this.
+ * @param hmac_ctx: the hmax context, function sets this.
* @param enc: 1 is encrypt, 0 is decrypt
- * @return false on failure (alloc failure).
+ * @return 0 on no ticket, 1 for okay, and 2 for okay but renew the ticket
+ * (the ticket is decrypt only). and <0 for failures.
*/
-
int tls_session_ticket_key_cb(void *s, unsigned char* key_name,unsigned char* iv, void *evp_ctx, void *hmac_ctx, int enc);
+
+/** Free memory used for TLS session ticket keys */
+void listen_sslctx_delete_ticket_keys(void);
+
#endif /* NET_HELP_H */