<p>Sean Bright has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/6641">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">dtls: Add support for ephemeral DTLS certificates<br><br>This mimics the behavior of Chrome and Firefox and creates an ephemeral<br>X.509 certificate for each DTLS session.<br><br>Currently, the only supported key type is ECDSA because of its faster<br>generation time, but other key types can be added in the future as<br>necessary.<br><br>Change-Id: I5122e5f4b83c6320cc17407a187fcf491daf30b4<br>---<br>M channels/chan_sip.c<br>M configs/samples/pjsip.conf.sample<br>M configs/samples/sip.conf.sample<br>M include/asterisk/rtp_engine.h<br>M main/rtp_engine.c<br>M res/res_pjsip.c<br>M res/res_pjsip/pjsip_configuration.c<br>M res/res_rtp_asterisk.c<br>8 files changed, 336 insertions(+), 74 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.asterisk.org:29418/asterisk refs/changes/41/6641/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">diff --git a/channels/chan_sip.c b/channels/chan_sip.c<br>index 8a30e0c..e31ba9b 100644<br>--- a/channels/chan_sip.c<br>+++ b/channels/chan_sip.c<br>@@ -32398,7 +32398,8 @@<br> default_tls_cfg.cipher = ast_strdup("");<br> default_tls_cfg.cafile = ast_strdup("");<br> default_tls_cfg.capath = ast_strdup("");<br>- /* Using the same idea fro DTLS as the code block above for TLS */<br>+ /* Using the same idea for DTLS as the code block above for TLS */<br>+ default_dtls_cfg.certtype = ast_strdup("file");<br> default_dtls_cfg.certfile = ast_strdup("");<br> default_dtls_cfg.pvtfile = ast_strdup("");<br> default_dtls_cfg.cipher = ast_strdup("");<br>diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample<br>index 9a2592b..436bb1a 100644<br>--- a/configs/samples/pjsip.conf.sample<br>+++ b/configs/samples/pjsip.conf.sample<br>@@ -744,6 +744,8 @@<br> ; "no")<br> ;dtls_rekey=0 ; Interval at which to renegotiate the TLS session and rekey<br> ; the SRTP session (default: "0")<br>+;dtls_cert_type= ; 'file' or 'ecdsa' depending on the type of certificate<br>+ ; you want to use (default: "file")<br> ;dtls_cert_file= ; Path to certificate file to present to peer (default:<br> ; "")<br> ;dtls_private_key= ; Path to private key for certificate file (default:<br>diff --git a/configs/samples/sip.conf.sample b/configs/samples/sip.conf.sample<br>index 9b52ec0..a813ff0 100644<br>--- a/configs/samples/sip.conf.sample<br>+++ b/configs/samples/sip.conf.sample<br>@@ -1342,6 +1342,7 @@<br> ; dtlsenable<br> ; dtlsverify<br> ; dtlsrekey<br>+; dtlscerttype<br> ; dtlscertfile<br> ; dtlsprivatekey<br> ; dtlscipher<br>@@ -1369,6 +1370,11 @@<br> ; ; A value of 'certificate' will perform ONLY certficiate verification<br> ; dtlsrekey = 60 ; Interval at which to renegotiate the TLS session and rekey the SRTP session<br> ; ; If this is not set or the value provided is 0 rekeying will be disabled<br>+; dtlscerttype = <file|ecdsa> ; The type of certificate to use:<br>+; ; * A value of 'file' means to use the values provided by dtlscertfile,<br>+; ; dtlscafile, dtlscapath, and dtlsprivatekey.<br>+; ; * A value of 'ecdsa' means to generate an ephemeral ECDSA key and X.509<br>+; ; certificate for each DTLS session<br> ; dtlscertfile = file ; Path to certificate file to present<br> ; dtlsprivatekey = file ; Path to private key for certificate file<br> ; dtlscipher = <SSL cipher string> ; Cipher to use for TLS negotiation<br>diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h<br>index 3ceac84..79e8ed3 100644<br>--- a/include/asterisk/rtp_engine.h<br>+++ b/include/asterisk/rtp_engine.h<br>@@ -508,6 +508,7 @@<br> char *cipher; /*!< Cipher to use */<br> char *cafile; /*!< Certificate authority file */<br> char *capath; /*!< Path to certificate authority */<br>+ char *certtype; /*!< The type of certificate (file or ecdsa) */<br> };<br> <br> /*! \brief Structure that represents the optional DTLS SRTP support within an RTP engine */<br>diff --git a/main/rtp_engine.c b/main/rtp_engine.c<br>index 226b229..7443c08 100644<br>--- a/main/rtp_engine.c<br>+++ b/main/rtp_engine.c<br>@@ -2717,6 +2717,13 @@<br> if (sscanf(value, "%30u", &dtls_cfg->rekey) != 1) {<br> return -1;<br> }<br>+ } else if (!strcasecmp(name, "dtlscerttype")) {<br>+ if (!ast_strlen_zero(value) && strcasecmp(value, "file") && strcasecmp(value, "ecdsa")) {<br>+ ast_log(LOG_ERROR, "%s must be either 'file' or 'ecdsa'\n", name);<br>+ return -1;<br>+ }<br>+ ast_free(dtls_cfg->certtype);<br>+ dtls_cfg->certtype = ast_strdup(value);<br> } else if (!strcasecmp(name, "dtlscertfile")) {<br> if (!ast_strlen_zero(value) && !ast_file_is_readable(value)) {<br> ast_log(LOG_ERROR, "%s file %s does not exist or is not readable\n", name, value);<br>@@ -2778,6 +2785,7 @@<br> dst_cfg->rekey = src_cfg->rekey;<br> dst_cfg->suite = src_cfg->suite;<br> dst_cfg->hash = src_cfg->hash;<br>+ dst_cfg->certtype = ast_strdup(src_cfg->certtype);<br> dst_cfg->certfile = ast_strdup(src_cfg->certfile);<br> dst_cfg->pvtfile = ast_strdup(src_cfg->pvtfile);<br> dst_cfg->cipher = ast_strdup(src_cfg->cipher);<br>@@ -2788,6 +2796,8 @@<br> <br> void ast_rtp_dtls_cfg_free(struct ast_rtp_dtls_cfg *dtls_cfg)<br> {<br>+ ast_free(dtls_cfg->certtype);<br>+ dtls_cfg->certtype = NULL;<br> ast_free(dtls_cfg->certfile);<br> dtls_cfg->certfile = NULL;<br> ast_free(dtls_cfg->pvtfile);<br>diff --git a/res/res_pjsip.c b/res/res_pjsip.c<br>index 6c1f776..0419d9a 100644<br>--- a/res/res_pjsip.c<br>+++ b/res/res_pjsip.c<br>@@ -765,6 +765,24 @@<br> If this is not set or the value provided is 0 rekeying will be disabled.<br> </para></description><br> </configOption><br>+ <configOption name="dtls_cert_type" default="file"><br>+ <synopsis>The type of DTLS certificate to present to peer</synopsis><br>+ <description><para><br>+ Specifies whether to use the X.509 certificate provided with the<br>+ <replaceable>dtls_cert_file</replaceable>, <replaceable>dtls_ca_file</replaceable>,<br>+ and <replaceable>dtls_private_key</replaceable> options, or a newly generated one<br>+ for each session. This option only applies if <replaceable>media_encryption</replaceable><br>+ is set to <literal>dtls</literal>.<br>+ </para></description><br>+ <enumlist><br>+ <enum name="file"><para><br>+ res_pjsip will use the configured certificate files.<br>+ </para></enum><br>+ <enum name="ecdsa"><para><br>+ res_pjsip will generate an ephemeral certificate.<br>+ </para></enum><br>+ </enumlist><br>+ </configOption><br> <configOption name="dtls_cert_file"><br> <synopsis>Path to certificate file to present to peer</synopsis><br> <description><para><br>diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c<br>index 3a752c9..41147fa 100644<br>--- a/res/res_pjsip/pjsip_configuration.c<br>+++ b/res/res_pjsip/pjsip_configuration.c<br>@@ -986,6 +986,13 @@<br> buf, "%u", endpoint->media.rtp.dtls_cfg.rekey) >=0 ? 0 : -1;<br> }<br> <br>+static int dtlscerttype_to_str(const void *obj, const intptr_t *args, char **buf)<br>+{<br>+ const struct ast_sip_endpoint *endpoint = obj;<br>+ *buf = ast_strdup(endpoint->media.rtp.dtls_cfg.certtype);<br>+ return 0;<br>+}<br>+<br> static int dtlscertfile_to_str(const void *obj, const intptr_t *args, char **buf)<br> {<br> const struct ast_sip_endpoint *endpoint = obj;<br>@@ -1363,9 +1370,11 @@<br> endpoint->media.rtp.dtls_cfg.default_setup = AST_RTP_DTLS_SETUP_ACTPASS;<br> endpoint->media.rtp.dtls_cfg.verify = AST_RTP_DTLS_VERIFY_FINGERPRINT;<br> <br>- if (ast_strlen_zero(endpoint->media.rtp.dtls_cfg.certfile)) {<br>+ if ((ast_strlen_zero(endpoint->media.rtp.dtls_cfg.certtype)<br>+ || !strcasecmp(endpoint->media.rtp.dtls_cfg.certtype, "file"))<br>+ && ast_strlen_zero(endpoint->media.rtp.dtls_cfg.certfile)) {<br> ast_log(LOG_ERROR, "WebRTC can't be enabled on endpoint '%s' - a DTLS cert "<br>- "has not been specified", ast_sorcery_object_get_id(endpoint));<br>+ "has not been specified", ast_sorcery_object_get_id(endpoint));<br> return -1;<br> }<br> }<br>@@ -1962,6 +1971,7 @@<br> ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_engine", "asterisk", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.rtp.engine));<br> ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_verify", "no", dtls_handler, dtlsverify_to_str, NULL, 0, 0);<br> ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_rekey", "0", dtls_handler, dtlsrekey_to_str, NULL, 0, 0);<br>+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_cert_type", "file", dtls_handler, dtlscerttype_to_str, NULL, 0, 0);<br> ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_cert_file", "", dtls_handler, dtlscertfile_to_str, NULL, 0, 0);<br> ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_private_key", "", dtls_handler, dtlsprivatekey_to_str, NULL, 0, 0);<br> ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_cipher", "", dtls_handler, dtlscipher_to_str, NULL, 0, 0);<br>diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c<br>index 7bf5b00..68c0551 100644<br>--- a/res/res_rtp_asterisk.c<br>+++ b/res/res_rtp_asterisk.c<br>@@ -1592,14 +1592,283 @@<br> return dtls_details_initialize(&rtp->rtcp->dtls, rtp->ssl_ctx, rtp->dtls.dtls_setup);<br> }<br> <br>+static const SSL_METHOD *get_dtls_method(void)<br>+{<br>+#if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(LIBRESSL_VERSION_NUMBER)<br>+ return DTLSv1_method();<br>+#else<br>+ return DTLS_method();<br>+#endif<br>+}<br>+<br>+struct dtls_cert_info {<br>+ EVP_PKEY *private_key;<br>+ X509 *certificate;<br>+};<br>+<br>+#ifdef HAVE_OPENSSL_EC<br>+<br>+static void configure_dhparams(const struct ast_rtp *rtp, const struct ast_rtp_dtls_cfg *dtls_cfg)<br>+{<br>+ EC_KEY *ecdh;<br>+<br>+ if (!ast_strlen_zero(dtls_cfg->pvtfile)) {<br>+ BIO *bio = BIO_new_file(dtls_cfg->pvtfile, "r");<br>+ if (bio) {<br>+ DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);<br>+ if (dh) {<br>+ if (SSL_CTX_set_tmp_dh(rtp->ssl_ctx, dh)) {<br>+ long options = SSL_OP_CIPHER_SERVER_PREFERENCE |<br>+ SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE;<br>+ options = SSL_CTX_set_options(rtp->ssl_ctx, options);<br>+ ast_verb(2, "DTLS DH initialized, PFS enabled\n");<br>+ }<br>+ DH_free(dh);<br>+ }<br>+ BIO_free(bio);<br>+ }<br>+ }<br>+<br>+ /* enables AES-128 ciphers, to get AES-256 use NID_secp384r1 */<br>+ ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);<br>+ if (ecdh) {<br>+ if (SSL_CTX_set_tmp_ecdh(rtp->ssl_ctx, ecdh)) {<br>+ #ifndef SSL_CTRL_SET_ECDH_AUTO<br>+ #define SSL_CTRL_SET_ECDH_AUTO 94<br>+ #endif<br>+ /* SSL_CTX_set_ecdh_auto(rtp->ssl_ctx, on); requires OpenSSL 1.0.2 which wraps: */<br>+ if (SSL_CTX_ctrl(rtp->ssl_ctx, SSL_CTRL_SET_ECDH_AUTO, 1, NULL)) {<br>+ ast_verb(2, "DTLS ECDH initialized (automatic), faster PFS enabled\n");<br>+ } else {<br>+ ast_verb(2, "DTLS ECDH initialized (secp256r1), faster PFS enabled\n");<br>+ }<br>+ }<br>+ EC_KEY_free(ecdh);<br>+ }<br>+}<br>+<br>+static int create_ephemeral_ec_keypair(EVP_PKEY **keypair)<br>+{<br>+ EC_KEY *eckey = NULL;<br>+ EC_GROUP *group = NULL;<br>+<br>+ group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);<br>+ if (!group) {<br>+ goto error;<br>+ }<br>+<br>+ EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);<br>+ EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED);<br>+<br>+ eckey = EC_KEY_new();<br>+ if (!eckey) {<br>+ goto error;<br>+ }<br>+<br>+ if (!EC_KEY_set_group(eckey, group)) {<br>+ goto error;<br>+ }<br>+<br>+ if (!EC_KEY_generate_key(eckey)) {<br>+ goto error;<br>+ }<br>+<br>+ *keypair = EVP_PKEY_new();<br>+ if (!*keypair) {<br>+ goto error;<br>+ }<br>+<br>+ EVP_PKEY_assign_EC_KEY(*keypair, eckey);<br>+ EC_GROUP_free(group);<br>+<br>+ return 0;<br>+<br>+error:<br>+ EC_KEY_free(eckey);<br>+ EC_GROUP_free(group);<br>+<br>+ return -1;<br>+}<br>+<br>+/* From OpenSSL's x509 command */<br>+#define SERIAL_RAND_BITS 159<br>+<br>+static int create_ephemeral_certificate(EVP_PKEY *keypair, X509 **certificate)<br>+{<br>+ X509 *cert = NULL;<br>+ BIGNUM *serial = NULL;<br>+ X509_NAME *name = NULL;<br>+<br>+ cert = X509_new();<br>+ if (!cert) {<br>+ goto error;<br>+ }<br>+<br>+ if (!X509_set_version(cert, 2)) {<br>+ goto error;<br>+ }<br>+<br>+ /* Set the public key */<br>+ X509_set_pubkey(cert, keypair);<br>+<br>+ /* Generate a random serial number */<br>+ if (!(serial = BN_new())<br>+ || !BN_rand(serial, SERIAL_RAND_BITS, -1, 0)<br>+ || !BN_to_ASN1_INTEGER(serial, X509_get_serialNumber(cert))) {<br>+ goto error;<br>+ }<br>+<br>+ /*<br>+ * Validity period - Current Chrome & Firefox make it 31 days starting<br>+ * with yesterday at the current time, so we will do the same.<br>+ */<br>+ if (!X509_time_adj_ex(X509_get_notBefore(cert), -1, 0, NULL)<br>+ || !X509_time_adj_ex(X509_get_notAfter(cert), 30, 0, NULL)) {<br>+ goto error;<br>+ }<br>+<br>+ /* Set the name and issuer */<br>+ if (!(name = X509_get_subject_name(cert))<br>+ || !X509_NAME_add_entry_by_NID(name, NID_commonName, MBSTRING_ASC,<br>+ (unsigned char *) "asterisk", -1, -1, 0)<br>+ || !X509_set_issuer_name(cert, name)) {<br>+ goto error;<br>+ }<br>+<br>+ /* Sign it */<br>+ if (!X509_sign(cert, keypair, EVP_sha256())) {<br>+ goto error;<br>+ }<br>+<br>+ *certificate = cert;<br>+<br>+ return 0;<br>+<br>+error:<br>+ BN_free(serial);<br>+ X509_free(cert);<br>+<br>+ return -1;<br>+}<br>+<br>+static int create_certificate_ephemeral(struct ast_rtp_instance *instance,<br>+ const struct ast_rtp_dtls_cfg *dtls_cfg,<br>+ struct dtls_cert_info *cert_info)<br>+{<br>+ /* Make sure these are initialized */<br>+ cert_info->private_key = NULL;<br>+ cert_info->certificate = NULL;<br>+<br>+ if (create_ephemeral_ec_keypair(&cert_info->private_key)) {<br>+ ast_log(LOG_ERROR, "Failed to create ephemeral ECDSA keypair\n");<br>+ goto error;<br>+ }<br>+<br>+ if (create_ephemeral_certificate(cert_info->private_key, &cert_info->certificate)) {<br>+ ast_log(LOG_ERROR, "Failed to create ephemeral X509 certificate\n");<br>+ goto error;<br>+ }<br>+<br>+ return 0;<br>+<br>+ error:<br>+ X509_free(cert_info->certificate);<br>+ EVP_PKEY_free(cert_info->private_key);<br>+<br>+ return -1;<br>+}<br>+<br>+#else<br>+<br>+static void configure_dhparams(const struct ast_rtp *rtp, const struct ast_rtp_dtls_cfg *dtls_cfg)<br>+{<br>+}<br>+<br>+static int create_certificate_ephemeral(struct ast_rtp_instance *instance,<br>+ const struct ast_rtp_dtls_cfg *dtls_cfg,<br>+ struct dtls_cert_info *cert_info)<br>+{<br>+ ast_log(LOG_ERROR, "Your version of OpenSSL does not support ECDSA keys\n");<br>+ return -1;<br>+}<br>+<br>+#endif /* HAVE_OPENSSL_EC */<br>+<br>+static int create_certificate_from_file(struct ast_rtp_instance *instance,<br>+ const struct ast_rtp_dtls_cfg *dtls_cfg,<br>+ struct dtls_cert_info *cert_info)<br>+{<br>+ FILE *fp;<br>+ BIO *certbio = NULL;<br>+ EVP_PKEY *private_key = NULL;<br>+ X509 *cert = NULL;<br>+ char *private_key_file = ast_strlen_zero(dtls_cfg->pvtfile) ? dtls_cfg->certfile : dtls_cfg->pvtfile;<br>+<br>+ fp = fopen(private_key_file, "r");<br>+ if (!fp) {<br>+ ast_log(LOG_ERROR, "Failed to read private key from file '%s': %s\n", private_key_file, strerror(errno));<br>+ goto error;<br>+ }<br>+<br>+ if (!PEM_read_PrivateKey(fp, &private_key, NULL, NULL)) {<br>+ ast_log(LOG_ERROR, "Failed to read private key from PEM file '%s'\n", private_key_file);<br>+ fclose(fp);<br>+ goto error;<br>+ }<br>+<br>+ if (fclose(fp)) {<br>+ ast_log(LOG_ERROR, "Failed to close private key file '%s': %s\n", private_key_file, strerror(errno));<br>+ goto error;<br>+ }<br>+<br>+ certbio = BIO_new(BIO_s_file());<br>+ if (!certbio) {<br>+ ast_log(LOG_ERROR, "Failed to allocate memory for certificate fingerprinting on RTP instance '%p'\n",<br>+ instance);<br>+ goto error;<br>+ }<br>+<br>+ if (!BIO_read_filename(certbio, dtls_cfg->certfile)<br>+ || !(cert = PEM_read_bio_X509(certbio, NULL, 0, NULL))) {<br>+ ast_log(LOG_ERROR, "Failed to read certificate from file '%s'\n", dtls_cfg->certfile);<br>+ goto error;<br>+ }<br>+<br>+ cert_info->private_key = private_key;<br>+ cert_info->certificate = cert;<br>+<br>+ BIO_free_all(certbio);<br>+<br>+ return 0;<br>+<br>+error:<br>+ X509_free(cert);<br>+ BIO_free_all(certbio);<br>+ EVP_PKEY_free(private_key);<br>+<br>+ return -1;<br>+}<br>+<br>+static int load_dtls_certificate(struct ast_rtp_instance *instance,<br>+ const struct ast_rtp_dtls_cfg *dtls_cfg,<br>+ struct dtls_cert_info *cert_info)<br>+{<br>+ if (!ast_strlen_zero(dtls_cfg->certfile)<br>+ && (ast_strlen_zero(dtls_cfg->certtype) || !strcasecmp(dtls_cfg->certtype, "file"))) {<br>+ return create_certificate_from_file(instance, dtls_cfg, cert_info);<br>+ } else if (!strcasecmp(dtls_cfg->certtype, "ecdsa")) {<br>+ return create_certificate_ephemeral(instance, dtls_cfg, cert_info);<br>+ } else {<br>+ return -1;<br>+ }<br>+}<br>+<br> /*! \pre instance is locked */<br> static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, const struct ast_rtp_dtls_cfg *dtls_cfg)<br> {<br> struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);<br>+ struct dtls_cert_info cert_info = { 0 };<br> int res;<br>-#ifdef HAVE_OPENSSL_EC<br>- EC_KEY *ecdh;<br>-#endif<br> <br> if (!dtls_cfg->enabled) {<br> return 0;<br>@@ -1614,53 +1883,14 @@<br> return 0;<br> }<br> <br>-#if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(LIBRESSL_VERSION_NUMBER)<br>- rtp->ssl_ctx = SSL_CTX_new(DTLSv1_method());<br>-#else<br>- rtp->ssl_ctx = SSL_CTX_new(DTLS_method());<br>-#endif<br>+ rtp->ssl_ctx = SSL_CTX_new(get_dtls_method());<br> if (!rtp->ssl_ctx) {<br> return -1;<br> }<br> <br> SSL_CTX_set_read_ahead(rtp->ssl_ctx, 1);<br> <br>-#ifdef HAVE_OPENSSL_EC<br>-<br>- if (!ast_strlen_zero(dtls_cfg->pvtfile)) {<br>- BIO *bio = BIO_new_file(dtls_cfg->pvtfile, "r");<br>- if (bio != NULL) {<br>- DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);<br>- if (dh != NULL) {<br>- if (SSL_CTX_set_tmp_dh(rtp->ssl_ctx, dh)) {<br>- long options = SSL_OP_CIPHER_SERVER_PREFERENCE |<br>- SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE;<br>- options = SSL_CTX_set_options(rtp->ssl_ctx, options);<br>- ast_verb(2, "DTLS DH initialized, PFS enabled\n");<br>- }<br>- DH_free(dh);<br>- }<br>- BIO_free(bio);<br>- }<br>- }<br>- /* enables AES-128 ciphers, to get AES-256 use NID_secp384r1 */<br>- ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);<br>- if (ecdh != NULL) {<br>- if (SSL_CTX_set_tmp_ecdh(rtp->ssl_ctx, ecdh)) {<br>- #ifndef SSL_CTRL_SET_ECDH_AUTO<br>- #define SSL_CTRL_SET_ECDH_AUTO 94<br>- #endif<br>- /* SSL_CTX_set_ecdh_auto(rtp->ssl_ctx, on); requires OpenSSL 1.0.2 which wraps: */<br>- if (SSL_CTX_ctrl(rtp->ssl_ctx, SSL_CTRL_SET_ECDH_AUTO, 1, NULL)) {<br>- ast_verb(2, "DTLS ECDH initialized (automatic), faster PFS enabled\n");<br>- } else {<br>- ast_verb(2, "DTLS ECDH initialized (secp256r1), faster PFS enabled\n");<br>- }<br>- }<br>- EC_KEY_free(ecdh);<br>- }<br>-<br>-#endif /* #ifdef HAVE_OPENSSL_EC */<br>+ configure_dhparams(rtp, dtls_cfg);<br> <br> rtp->dtls_verify = dtls_cfg->verify;<br> <br>@@ -1679,25 +1909,22 @@<br> <br> rtp->local_hash = dtls_cfg->hash;<br> <br>- if (!ast_strlen_zero(dtls_cfg->certfile)) {<br>- char *private = ast_strlen_zero(dtls_cfg->pvtfile) ? dtls_cfg->certfile : dtls_cfg->pvtfile;<br>- BIO *certbio;<br>- X509 *cert = NULL;<br>+ if (!load_dtls_certificate(instance, dtls_cfg, &cert_info)) {<br> const EVP_MD *type;<br> unsigned int size, i;<br> unsigned char fingerprint[EVP_MAX_MD_SIZE];<br> char *local_fingerprint = rtp->local_fingerprint;<br> <br>- if (!SSL_CTX_use_certificate_file(rtp->ssl_ctx, dtls_cfg->certfile, SSL_FILETYPE_PEM)) {<br>+ if (!SSL_CTX_use_certificate(rtp->ssl_ctx, cert_info.certificate)) {<br> ast_log(LOG_ERROR, "Specified certificate file '%s' for RTP instance '%p' could not be used\n",<br> dtls_cfg->certfile, instance);<br> return -1;<br> }<br> <br>- if (!SSL_CTX_use_PrivateKey_file(rtp->ssl_ctx, private, SSL_FILETYPE_PEM) ||<br>- !SSL_CTX_check_private_key(rtp->ssl_ctx)) {<br>- ast_log(LOG_ERROR, "Specified private key file '%s' for RTP instance '%p' could not be used\n",<br>- private, instance);<br>+ if (!SSL_CTX_use_PrivateKey(rtp->ssl_ctx, cert_info.private_key)<br>+ || !SSL_CTX_check_private_key(rtp->ssl_ctx)) {<br>+ ast_log(LOG_ERROR, "Specified private key file for RTP instance '%p' could not be used\n",<br>+ instance);<br> return -1;<br> }<br> <br>@@ -1711,22 +1938,9 @@<br> return -1;<br> }<br> <br>- if (!(certbio = BIO_new(BIO_s_file()))) {<br>- ast_log(LOG_ERROR, "Failed to allocate memory for certificate fingerprinting on RTP instance '%p'\n",<br>- instance);<br>- return -1;<br>- }<br>-<br>- if (!BIO_read_filename(certbio, dtls_cfg->certfile) ||<br>- !(cert = PEM_read_bio_X509(certbio, NULL, 0, NULL)) ||<br>- !X509_digest(cert, type, fingerprint, &size) ||<br>- !size) {<br>+ if (!X509_digest(cert_info.certificate, type, fingerprint, &size) || !size) {<br> ast_log(LOG_ERROR, "Could not produce fingerprint from certificate '%s' for RTP instance '%p'\n",<br>- dtls_cfg->certfile, instance);<br>- BIO_free_all(certbio);<br>- if (cert) {<br>- X509_free(cert);<br>- }<br>+ dtls_cfg->certfile, instance);<br> return -1;<br> }<br> <br>@@ -1735,10 +1949,10 @@<br> local_fingerprint += 3;<br> }<br> <br>- *(local_fingerprint-1) = 0;<br>+ *(local_fingerprint - 1) = 0;<br> <br>- BIO_free_all(certbio);<br>- X509_free(cert);<br>+ EVP_PKEY_free(cert_info.private_key);<br>+ X509_free(cert_info.certificate);<br> }<br> <br> if (!ast_strlen_zero(dtls_cfg->cipher)) {<br></pre><p>To view, visit <a href="https://gerrit.asterisk.org/6641">change 6641</a>. To unsubscribe, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/6641"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I5122e5f4b83c6320cc17407a187fcf491daf30b4 </div>
<div style="display:none"> Gerrit-Change-Number: 6641 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Sean Bright <sean.bright@gmail.com> </div>