<p>Sean Bright has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.asterisk.org/6640">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/40/6640/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 909a5c8..7ed2d22 100644<br>--- a/channels/chan_sip.c<br>+++ b/channels/chan_sip.c<br>@@ -32237,7 +32237,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/6640">change 6640</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/6640"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 15 </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: 6640 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Sean Bright <sean.bright@gmail.com> </div>