diff --git a/ChangeLog b/ChangeLog index 6b372592..b53a7b64 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,8 @@ * 2018-0?-??: Version 1.?.? + * Specify the supported curves with getdns_context_set_tls_curves_list() + An upstream specific list of supported curves may also be given + with the tls_curves_list setting in the upstream dict with + getdns_context_set_upstream_recursive_servers() * libidn2 support. Thanks Paul Wouters * 2017-12-21: Version 1.3.0 diff --git a/configure.ac b/configure.ac index caf2cdf3..fd85d72d 100644 --- a/configure.ac +++ b/configure.ac @@ -409,7 +409,7 @@ AC_CHECK_HEADERS([openssl/conf.h],,, [AC_INCLUDES_DEFAULT]) AC_CHECK_HEADERS([openssl/engine.h],,, [AC_INCLUDES_DEFAULT]) AC_CHECK_HEADERS([openssl/bn.h openssl/rsa.h openssl/dsa.h],,, [AC_INCLUDES_DEFAULT]) AC_CHECK_FUNCS([OPENSSL_config EVP_md5 EVP_sha1 EVP_sha224 EVP_sha256 EVP_sha384 EVP_sha512 FIPS_mode ENGINE_load_cryptodev EVP_PKEY_keygen ECDSA_SIG_get0 EVP_MD_CTX_new EVP_PKEY_base_id HMAC_CTX_new HMAC_CTX_free TLS_client_method DSA_SIG_set0 EVP_dss1 EVP_DigestVerify SSL_CTX_set_min_proto_version OpenSSL_version_num OpenSSL_version]) -AC_CHECK_DECLS([SSL_COMP_get_compression_methods,sk_SSL_COMP_pop_free,SSL_CTX_set_ecdh_auto], [], [], [ +AC_CHECK_DECLS([SSL_COMP_get_compression_methods,sk_SSL_COMP_pop_free,SSL_CTX_set_ecdh_auto,SSL_CTX_set1_curves_list,SSL_set1_curves_list], [], [], [ AC_INCLUDES_DEFAULT #ifdef HAVE_OPENSSL_ERR_H #include diff --git a/src/context.c b/src/context.c index c8f14363..8163309b 100644 --- a/src/context.c +++ b/src/context.c @@ -738,6 +738,8 @@ _getdns_upstreams_dereference(getdns_upstreams *upstreams) upstream->tls_pubkey_pinset = NULL; if (upstream->tls_cipher_list) GETDNS_FREE(upstreams->mf, upstream->tls_cipher_list); + if (upstream->tls_curves_list) + GETDNS_FREE(upstreams->mf, upstream->tls_curves_list); } GETDNS_FREE(upstreams->mf, upstreams); } @@ -1022,6 +1024,7 @@ upstream_init(getdns_upstream *upstream, upstream->tls_obj = NULL; upstream->tls_session = NULL; upstream->tls_cipher_list = NULL; + upstream->tls_curves_list = NULL; upstream->transport = GETDNS_TRANSPORT_TCP; upstream->tls_hs_state = GETDNS_HS_NONE; upstream->tls_auth_name[0] = '\0'; @@ -1535,6 +1538,7 @@ getdns_context_create_with_extended_memory_functions( result->tls_ca_path = NULL; result->tls_ca_file = NULL; result->tls_cipher_list = NULL; + result->tls_curves_list = NULL; (void) memset(&result->root_ksk, 0, sizeof(result->root_ksk)); @@ -1805,6 +1809,8 @@ getdns_context_destroy(struct getdns_context *context) GETDNS_FREE(context->mf, context->tls_ca_file); if (context->tls_cipher_list) GETDNS_FREE(context->mf, context->tls_cipher_list); + if (context->tls_curves_list) + GETDNS_FREE(context->mf, context->tls_curves_list); #ifdef USE_WINSOCK WSACleanup(); @@ -2996,6 +3002,7 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context, if (dict && getdns_upstream_transports[j] == GETDNS_TRANSPORT_TLS) { getdns_list *pubkey_pinset = NULL; getdns_bindata *tls_cipher_list = NULL; + getdns_bindata *tls_curves_list = NULL; if ((r = getdns_dict_get_bindata( dict, "tls_auth_name", &tls_auth_name)) == GETDNS_RETURN_GOOD) { @@ -3007,6 +3014,7 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context, * into account, should not * be larger than 1024 bytes. */ + freeaddrinfo(ai); goto invalid_parameter; } memcpy(upstream->tls_auth_name, @@ -3022,8 +3030,10 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context, r = _getdns_get_pubkey_pinset_from_list(pubkey_pinset, &(upstreams->mf), &(upstream->tls_pubkey_pinset)); - if (r != GETDNS_RETURN_GOOD) + if (r != GETDNS_RETURN_GOOD) { + freeaddrinfo(ai); goto invalid_parameter; + } } (void) getdns_dict_get_bindata( dict, "tls_cipher_list", &tls_cipher_list); @@ -3031,6 +3041,19 @@ getdns_context_set_upstream_recursive_servers(struct getdns_context *context, ? _getdns_strdup2(&upstreams->mf , tls_cipher_list) : NULL; + (void) getdns_dict_get_bindata( + dict, "tls_curves_list", &tls_curves_list); + if (tls_curves_list) { +#if defined(HAVE_DECL_SSL_SET1_CURVES_LIST) && HAVE_DECL_SSL_SET1_CURVES_LIST + upstream->tls_curves_list = + _getdns_strdup2(&upstreams->mf + , tls_curves_list); +#else + freeaddrinfo(ai); + goto not_implemented; +#endif + } else + upstream->tls_curves_list = NULL; } if ((upstream->tsig_alg = tsig_alg)) { if (tsig_name) { @@ -3068,6 +3091,11 @@ invalid_parameter: error: _getdns_upstreams_dereference(upstreams); return GETDNS_RETURN_CONTEXT_UPDATE_FAIL; +#if !defined(HAVE_DECL_SSL_SET1_CURVES_LIST) || !HAVE_DECL_SSL_SET1_CURVES_LIST +not_implemented: + _getdns_upstreams_dereference(upstreams); + return GETDNS_RETURN_NOT_IMPLEMENTED; +#endif } /* getdns_context_set_upstream_recursive_servers */ @@ -3608,6 +3636,12 @@ _getdns_context_prepare_for_resolution(getdns_context *context) context->tls_cipher_list ? context->tls_cipher_list : _getdns_default_tls_cipher_list)) return GETDNS_RETURN_BAD_CONTEXT; + +# if defined(HAVE_DECL_SSL_CTX_SET1_CURVES_LIST) && HAVE_DECL_SSL_CTX_SET1_CURVES_LIST + if (context->tls_curves_list && + !SSL_CTX_set1_curves_list(context->tls_ctx, context->tls_curves_list)) + return GETDNS_RETURN_BAD_CONTEXT; +# endif /* For strict authentication, we must have local root certs available Set up is done only when the tls_ctx is created (per getdns_context)*/ if ((context->tls_ca_file || context->tls_ca_path) && @@ -3924,6 +3958,8 @@ _get_context_settings(getdns_context* context) (void) getdns_dict_util_set_string(result, "tls_ca_file", str_value); if (!getdns_context_get_tls_cipher_list(context, &str_value) && str_value) (void) getdns_dict_util_set_string(result, "tls_cipher_list", str_value); + if (!getdns_context_get_tls_curves_list(context, &str_value) && str_value) + (void) getdns_dict_util_set_string(result, "tls_curves_list", str_value); /* Default settings for extensions */ (void)getdns_dict_set_int( @@ -4513,6 +4549,11 @@ getdns_context_get_upstream_recursive_servers(getdns_context *context, d, "tls_cipher_list", upstream->tls_cipher_list); } + if (upstream->tls_curves_list) { + (void) getdns_dict_util_set_string( + d, "tls_curves_list", + upstream->tls_curves_list); + } } } if (!r) @@ -4722,6 +4763,7 @@ _getdns_context_config_setting(getdns_context *context, CONTEXT_SETTING_STRING(tls_ca_path) CONTEXT_SETTING_STRING(tls_ca_file) CONTEXT_SETTING_STRING(tls_cipher_list) + CONTEXT_SETTING_STRING(tls_curves_list) /**************************************/ /**** ****/ @@ -5301,5 +5343,35 @@ getdns_context_get_tls_cipher_list( return GETDNS_RETURN_GOOD; } +getdns_return_t +getdns_context_set_tls_curves_list( + getdns_context *context, const char *tls_curves_list) +{ + if (!context) + return GETDNS_RETURN_INVALID_PARAMETER; +#if defined(HAVE_DECL_SSL_CTX_SET1_CURVES_LIST) && HAVE_DECL_SSL_CTX_SET1_CURVES_LIST + if (context->tls_curves_list) + GETDNS_FREE(context->mf, context->tls_curves_list); + context->tls_curves_list = tls_curves_list + ? _getdns_strdup(&context->mf, tls_curves_list) + : NULL; + + dispatch_updated(context, GETDNS_CONTEXT_CODE_TLS_CIPHER_LIST); + return GETDNS_RETURN_GOOD; +#else + (void)tls_curves_list; + return GETDNS_RETURN_NOT_IMPLEMENTED; +#endif +} + +getdns_return_t +getdns_context_get_tls_curves_list( + getdns_context *context, const char **tls_curves_list) +{ + if (!context || !tls_curves_list) + return GETDNS_RETURN_INVALID_PARAMETER; + *tls_curves_list = context->tls_curves_list; + return GETDNS_RETURN_GOOD; +} /* context.c */ diff --git a/src/context.h b/src/context.h index b4319403..7d8a4a6d 100644 --- a/src/context.h +++ b/src/context.h @@ -206,6 +206,7 @@ typedef struct getdns_upstream { getdns_auth_state_t tls_auth_state; unsigned tls_fallback_ok : 1; char *tls_cipher_list; + char *tls_curves_list; /* Auth credentials*/ char tls_auth_name[256]; sha256_pin_t *tls_pubkey_pinset; @@ -347,6 +348,7 @@ struct getdns_context { char *tls_ca_path; char *tls_ca_file; char *tls_cipher_list; + char *tls_curves_list; getdns_upstreams *upstreams; uint16_t limit_outstanding_queries; diff --git a/src/getdns/getdns_extra.h.in b/src/getdns/getdns_extra.h.in index f8cec882..4837771c 100644 --- a/src/getdns/getdns_extra.h.in +++ b/src/getdns/getdns_extra.h.in @@ -100,6 +100,8 @@ extern "C" { #define GETDNS_CONTEXT_CODE_TLS_CA_FILE_TEXT "Change related to getdns_context_set_tls_ca_file" #define GETDNS_CONTEXT_CODE_TLS_CIPHER_LIST 633 #define GETDNS_CONTEXT_CODE_TLS_CIPHER_LIST_TEXT "Change related to getdns_context_set_tls_cipher_list" +#define GETDNS_CONTEXT_CODE_TLS_CURVES_LIST 634 +#define GETDNS_CONTEXT_CODE_TLS_CURVES_LIST_TEXT "Change related to getdns_context_set_tls_curves_list" /** @} */ @@ -753,6 +755,20 @@ getdns_return_t getdns_context_set_tls_cipher_list( getdns_context *context, const char *cipher_list); +/** + * Sets the supported curves TLS upstreams. + * @see getdns_context_get_tls_curves_list + * @param[in] context The context to configure + * @param[in] curves_list The string is a colon separated list of curve + * NIDs or names, for example "P-521:P-384:P-256". + * @return GETDNS_RETURN_GOOD when successful + * @return GETDNS_RETURN_INVALID_PARAMETER when context was NULL. + */ +getdns_return_t +getdns_context_set_tls_curves_list( + getdns_context *context, const char *curves_list); + + /** * Get the current resolution type setting from this context. * @see getdns_context_set_resolution_type @@ -1272,6 +1288,21 @@ getdns_return_t getdns_context_get_tls_cipher_list( getdns_context *context, const char **cipher_list); +/** + * Get the supported curves list if one has been set earlier. + * @see getdns_context_set_tls_curves_list + * @param[in] context The configured context + * @param[out] curves_list The string is a colon separated list of curve + * NIDs or names, for example "P-521:P-384:P-256", + * when one has been configured on the context, + * or NULL when none has been set before. + * @return GETDNS_RETURN_GOOD when successful + * @return GETDNS_RETURN_INVALID_PARAMETER when context was NULL. + */ +getdns_return_t +getdns_context_get_tls_curves_list( + getdns_context *context, const char **curves_list); + /** @} */ diff --git a/src/stub.c b/src/stub.c index a9ec8240..beb20cc6 100644 --- a/src/stub.c +++ b/src/stub.c @@ -925,6 +925,10 @@ tls_create_object(getdns_dns_req *dnsreq, int fd, getdns_upstream *upstream) SSL_free(ssl); return NULL; } +#if defined(HAVE_DECL_SSL_SET1_CURVES_LIST) && HAVE_DECL_SSL_SET1_CURVES_LIST + if (upstream->tls_curves_list) + (void) SSL_set1_curves_list(ssl, upstream->tls_curves_list); +#endif /* make sure we'll be able to find the context again when we need it */ if (_getdns_associate_upstream_with_SSL(ssl, upstream) != GETDNS_RETURN_GOOD) { SSL_free(ssl);