diff --git a/CHANGES b/CHANGES
index 39b62d05c225437fa51eb6808a1e10a3beb93077..12fe0fe42ac43d5df5a86095d59531b8e691d0b6 100644
--- a/CHANGES
+++ b/CHANGES
@@ -30,6 +30,14 @@ chan_sip
 --- Functionality changes from Asterisk 15.1.0 to Asterisk 15.2.0 ------------
 ------------------------------------------------------------------------------
 
+res_rtp_asterisk
+------------------
+ * The X.509 certificate used for DTLS negotation can now be automatically
+   generated. This is supported by res_pjsip by specifying
+   "dtls_auto_generate_cert = yes" on a PJSIP endpoint. For chan_sip, you
+   would set "dtlsautogeneratecert = yes" either in the [general] section of
+   sip.conf or on a specific peer.
+
 res_pjsip
 ------------------
  * The "identify_by" on endpoints can now be set to "ip" to restrict an endpoint
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index fd780b61f53fb9b8a5a3c327dbcbe16e9e06e678..bd68ec096c835b30c0bd4cc3313fbb4f1848447a 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -31946,6 +31946,14 @@ static struct sip_peer *build_peer(const char *name, struct ast_variable *v_head
 			}
 		}
 
+		/* Validate DTLS configuration */
+		if (ast_rtp_dtls_cfg_validate(&peer->dtls_cfg)) {
+			sip_unref_peer(peer, "Removing peer due to bad DTLS configuration");
+			return NULL;
+		}
+
+		/* SRB */
+
 		/* Apply the encryption tag length to the DTLS configuration, in case DTLS is in use */
 		peer->dtls_cfg.suite = (ast_test_flag(&peer->flags[2], SIP_PAGE3_SRTP_TAG_32) ? AST_AES_CM_128_HMAC_SHA1_32 : AST_AES_CM_128_HMAC_SHA1_80);
 
@@ -33145,6 +33153,11 @@ static int reload_config(enum channelreloadreason reason)
 		}
 	}
 
+	/* Validate DTLS configuration */
+	if (ast_rtp_dtls_cfg_validate(&default_dtls_cfg)) {
+		return -1;
+	}
+
 	/* Override global defaults if setting found in general section */
 	ast_copy_flags(&global_flags[0], &setflags[0], mask[0].flags);
 	ast_copy_flags(&global_flags[1], &setflags[1], mask[1].flags);
diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample
index 800ff0f444248fc8c8961d937ece17bc3f1fa0a4..302899a1743a6718a0ce83d12dfeb711ad952393 100644
--- a/configs/samples/pjsip.conf.sample
+++ b/configs/samples/pjsip.conf.sample
@@ -746,10 +746,12 @@
                 ; "no")
 ;dtls_rekey=0   ; Interval at which to renegotiate the TLS session and rekey
                 ; the SRTP session (default: "0")
-;dtls_cert_file=        ; Path to certificate file to present to peer (default:
-                        ; "")
-;dtls_private_key=      ; Path to private key for certificate file (default:
-                        ; "")
+;dtls_auto_generate_cert= ; Enable ephemeral DTLS certificate generation (default:
+                          ; "no")
+;dtls_cert_file=          ; Path to certificate file to present to peer (default:
+                          ; "")
+;dtls_private_key=        ; Path to private key for certificate file (default:
+                          ; "")
 ;dtls_cipher=   ; Cipher to use for DTLS negotiation (default: "")
 ;dtls_ca_file=  ; Path to certificate authority certificate (default: "")
 ;dtls_ca_path=  ; Path to a directory containing certificate authority
diff --git a/configs/samples/sip.conf.sample b/configs/samples/sip.conf.sample
index 9b52ec06c0d3245549a12bced7b35284cb180194..ace5097596f0e729e78cc246ea4c4fc7cfbfa41c 100644
--- a/configs/samples/sip.conf.sample
+++ b/configs/samples/sip.conf.sample
@@ -1340,6 +1340,7 @@ srvlookup=yes                   ; Enable DNS SRV lookups on outbound calls
 ; encryption
 ; description		; Used to provide a description of the peer in console output
 ; dtlsenable
+; dtlsautogeneratecert
 ; dtlsverify
 ; dtlsrekey
 ; dtlscertfile
@@ -1369,6 +1370,7 @@ srvlookup=yes                   ; Enable DNS SRV lookups on outbound calls
 ;				     ; A value of 'certificate' will perform ONLY certficiate verification
 ; dtlsrekey = 60                     ; Interval at which to renegotiate the TLS session and rekey the SRTP session
 ;                                    ; If this is not set or the value provided is 0 rekeying will be disabled
+; dtlsautogeneratecert = yes         ; Enable ephemeral DTLS certificate generation. The default is 'no.'
 ; dtlscertfile = file                ; Path to certificate file to present
 ; dtlsprivatekey = file              ; Path to private key for certificate file
 ; dtlscipher = <SSL cipher string>   ; Cipher to use for TLS negotiation
diff --git a/contrib/ast-db-manage/config/versions/041c0d3d1857_add_dtls_auto_gen_cert.py b/contrib/ast-db-manage/config/versions/041c0d3d1857_add_dtls_auto_gen_cert.py
new file mode 100644
index 0000000000000000000000000000000000000000..2733b35cc12bd7f62eb47e8e23c645d7e981ecc1
--- /dev/null
+++ b/contrib/ast-db-manage/config/versions/041c0d3d1857_add_dtls_auto_gen_cert.py
@@ -0,0 +1,33 @@
+"""add_dtls_auto_generate_cert
+
+Revision ID: 041c0d3d1857
+Revises: de83fac997e2
+Create Date: 2017-10-30 14:28:10.548395
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '041c0d3d1857'
+down_revision = 'de83fac997e2'
+
+from alembic import op
+import sqlalchemy as sa
+from sqlalchemy.dialects.postgresql import ENUM
+
+YESNO_NAME = 'yesno_values'
+YESNO_VALUES = ['yes', 'no']
+
+def upgrade():
+    ############################# Enums ##############################
+
+    # yesno_values have already been created, so use postgres enum object
+    # type to get around "already created" issue - works okay with mysql
+    yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False)
+
+    op.add_column('ps_endpoints', sa.Column('dtls_auto_generate_cert', yesno_values))
+
+
+def downgrade():
+    if op.get_context().bind.dialect.name == 'mssql':
+        op.drop_constraint('ck_ps_endpoints_dtls_auto_generate_cert_yesno_values', 'ps_endpoints')
+    op.drop_column('ps_endpoints', 'dtls_auto_generate_cert')
diff --git a/include/asterisk/rtp_engine.h b/include/asterisk/rtp_engine.h
index 3ceac8467e17ee409094736fd21a82fad6e330c1..f9d686aca81011fcd48194983d9d28ffe393dcc5 100644
--- a/include/asterisk/rtp_engine.h
+++ b/include/asterisk/rtp_engine.h
@@ -508,6 +508,7 @@ struct ast_rtp_dtls_cfg {
 	char *cipher;                          /*!< Cipher to use */
 	char *cafile;                          /*!< Certificate authority file */
 	char *capath;                          /*!< Path to certificate authority */
+	unsigned int ephemeral_cert:1;         /*!< Whether to not to generate an ephemeral certificate - defaults to 0 (off) */
 };
 
 /*! \brief Structure that represents the optional DTLS SRTP support within an RTP engine */
@@ -2349,6 +2350,16 @@ struct ast_rtp_engine_dtls *ast_rtp_instance_get_dtls(struct ast_rtp_instance *i
  */
 int ast_rtp_dtls_cfg_parse(struct ast_rtp_dtls_cfg *dtls_cfg, const char *name, const char *value);
 
+/*!
+ * \brief Validates DTLS related configuration options
+ *
+ * \param dtls_cfg a DTLS configuration structure
+ *
+ * \retval 0 if valid
+ * \retval -1 if invalid
+ */
+int ast_rtp_dtls_cfg_validate(struct ast_rtp_dtls_cfg *dtls_cfg);
+
 /*!
  * \brief Copy contents of a DTLS configuration structure
  *
diff --git a/main/rtp_engine.c b/main/rtp_engine.c
index 226b229f29c972f9c908028718b97a652ebc9e9d..0aed8e97c36c7e185724fe5314fbefd84ae8807e 100644
--- a/main/rtp_engine.c
+++ b/main/rtp_engine.c
@@ -2717,6 +2717,8 @@ int ast_rtp_dtls_cfg_parse(struct ast_rtp_dtls_cfg *dtls_cfg, const char *name,
 		if (sscanf(value, "%30u", &dtls_cfg->rekey) != 1) {
 			return -1;
 		}
+	} else if (!strcasecmp(name, "dtlsautogeneratecert")) {
+		dtls_cfg->ephemeral_cert = ast_true(value) ? 1 : 0;
 	} else if (!strcasecmp(name, "dtlscertfile")) {
 		if (!ast_strlen_zero(value) && !ast_file_is_readable(value)) {
 			ast_log(LOG_ERROR, "%s file %s does not exist or is not readable\n", name, value);
@@ -2769,6 +2771,25 @@ int ast_rtp_dtls_cfg_parse(struct ast_rtp_dtls_cfg *dtls_cfg, const char *name,
 	return 0;
 }
 
+int ast_rtp_dtls_cfg_validate(struct ast_rtp_dtls_cfg *dtls_cfg)
+{
+	if (dtls_cfg->ephemeral_cert) {
+		if (!ast_strlen_zero(dtls_cfg->certfile)) {
+			ast_log(LOG_ERROR, "You cannot request automatically generated certificates"
+				" (dtls_auto_generate_cert) and also specify a certificate file"
+				" (dtls_cert_file) at the same time\n");
+			return -1;
+		} else if (!ast_strlen_zero(dtls_cfg->pvtfile)
+				  || !ast_strlen_zero(dtls_cfg->cafile)
+				  || !ast_strlen_zero(dtls_cfg->capath)) {
+			ast_log(LOG_NOTICE, "dtls_pvt_file, dtls_cafile, and dtls_ca_path are"
+				" ignored when dtls_auto_generate_cert is enabled\n");
+		}
+	}
+
+	return 0;
+}
+
 void ast_rtp_dtls_cfg_copy(const struct ast_rtp_dtls_cfg *src_cfg, struct ast_rtp_dtls_cfg *dst_cfg)
 {
 	ast_rtp_dtls_cfg_free(dst_cfg);         /* Prevent a double-call leaking memory via ast_strdup */
@@ -2778,6 +2799,7 @@ void ast_rtp_dtls_cfg_copy(const struct ast_rtp_dtls_cfg *src_cfg, struct ast_rt
 	dst_cfg->rekey = src_cfg->rekey;
 	dst_cfg->suite = src_cfg->suite;
 	dst_cfg->hash = src_cfg->hash;
+	dst_cfg->ephemeral_cert = src_cfg->ephemeral_cert;
 	dst_cfg->certfile = ast_strdup(src_cfg->certfile);
 	dst_cfg->pvtfile = ast_strdup(src_cfg->pvtfile);
 	dst_cfg->cipher = ast_strdup(src_cfg->cipher);
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index 7499ded3e1ceb7769eb7c692a9618038f91cde76..1b59b28344e4f62fe4baee2bff99aad81cc4a64d 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -772,6 +772,18 @@
 						If this is not set or the value provided is 0 rekeying will be disabled.
 					</para></description>
 				</configOption>
+				<configOption name="dtls_auto_generate_cert" default="no">
+					<synopsis>Whether or not to automatically generate an ephemeral X.509 certificate</synopsis>
+					<description>
+						<para>
+							If enabled, Asterisk will generate an X.509 certificate for each DTLS session.
+							This option only applies if <replaceable>media_encryption</replaceable> is set
+							to <literal>dtls</literal>. This option will be automatically enabled if
+							<literal>webrtc</literal> is enabled and <literal>dtls_cert_file</literal> is
+							not specified.
+						</para>
+					</description>
+				</configOption>
 				<configOption name="dtls_cert_file">
 					<synopsis>Path to certificate file to present to peer</synopsis>
 					<description><para>
@@ -1028,6 +1040,7 @@
 						use_received_transport. The following configuration settings also get defaulted
 						as follows:</para>
 						<para>media_encryption=dtls</para>
+						<para>dtls_auto_generate_cert=yes (if dtls_cert_file is not set)</para>
 						<para>dtls_verify=fingerprint</para>
 						<para>dtls_setup=actpass</para>
 					</description>
diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c
index 6db5b38985ab1c204a3f2b38d2ab49090361f3c2..2b6a2bb2a74575f53ee0df60f8cf23bc08b05af6 100644
--- a/res/res_pjsip/pjsip_configuration.c
+++ b/res/res_pjsip/pjsip_configuration.c
@@ -991,6 +991,13 @@ static int dtlsrekey_to_str(const void *obj, const intptr_t *args, char **buf)
 		buf, "%u", endpoint->media.rtp.dtls_cfg.rekey) >=0 ? 0 : -1;
 }
 
+static int dtlsautogeneratecert_to_str(const void *obj, const intptr_t *args, char **buf)
+{
+	const struct ast_sip_endpoint *endpoint = obj;
+	*buf = ast_strdup(AST_YESNO(endpoint->media.rtp.dtls_cfg.ephemeral_cert));
+	return 0;
+}
+
 static int dtlscertfile_to_str(const void *obj, const intptr_t *args, char **buf)
 {
 	const struct ast_sip_endpoint *endpoint = obj;
@@ -1353,6 +1360,10 @@ static int sip_endpoint_apply_handler(const struct ast_sorcery *sorcery, void *o
 		return -1;
 	}
 
+	if (ast_rtp_dtls_cfg_validate(&endpoint->media.rtp.dtls_cfg)) {
+		return -1;
+	}
+
 	endpoint->media.topology = ast_stream_topology_create_from_format_cap(endpoint->media.codecs);
 	if (!endpoint->media.topology) {
 		return -1;
@@ -1377,9 +1388,8 @@ static int sip_endpoint_apply_handler(const struct ast_sorcery *sorcery, void *o
 		endpoint->media.rtp.dtls_cfg.verify = AST_RTP_DTLS_VERIFY_FINGERPRINT;
 
 		if (ast_strlen_zero(endpoint->media.rtp.dtls_cfg.certfile)) {
-			ast_log(LOG_ERROR, "WebRTC can't be enabled on endpoint '%s' - a DTLS cert "
-				"has not been specified", ast_sorcery_object_get_id(endpoint));
-			return -1;
+			/* If no certificate has been specified, try to automatically create one */
+			endpoint->media.rtp.dtls_cfg.ephemeral_cert = 1;
 		}
 	}
 
@@ -1967,6 +1977,7 @@ int ast_res_pjsip_initialize_configuration(void)
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_engine", "asterisk", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.rtp.engine));
 	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_verify", "no", dtls_handler, dtlsverify_to_str, NULL, 0, 0);
 	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_rekey", "0", dtls_handler, dtlsrekey_to_str, NULL, 0, 0);
+	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_auto_generate_cert", "no", dtls_handler, dtlsautogeneratecert_to_str, NULL, 0, 0);
 	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_cert_file", "", dtls_handler, dtlscertfile_to_str, NULL, 0, 0);
 	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_private_key", "", dtls_handler, dtlsprivatekey_to_str, NULL, 0, 0);
 	ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_cipher", "", dtls_handler, dtlscipher_to_str, NULL, 0, 0);
diff --git a/res/res_rtp_asterisk.c b/res/res_rtp_asterisk.c
index f5d91345832d6eb859c44fcbeac7b152043771b5..15ca1503b1ebe004d27afd6b57c4277581cdd8c4 100644
--- a/res/res_rtp_asterisk.c
+++ b/res/res_rtp_asterisk.c
@@ -1593,46 +1593,31 @@ static int dtls_setup_rtcp(struct ast_rtp_instance *instance)
 	return dtls_details_initialize(&rtp->rtcp->dtls, rtp->ssl_ctx, rtp->dtls.dtls_setup);
 }
 
-/*! \pre instance is locked */
-static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, const struct ast_rtp_dtls_cfg *dtls_cfg)
+static const SSL_METHOD *get_dtls_method(void)
 {
-	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
-	int res;
-#ifdef HAVE_OPENSSL_EC
-	EC_KEY *ecdh;
-#endif
-
-	if (!dtls_cfg->enabled) {
-		return 0;
-	}
-
-	if (!ast_rtp_engine_srtp_is_registered()) {
-		ast_log(LOG_ERROR, "SRTP support module is not loaded or available. Try loading res_srtp.so.\n");
-		return -1;
-	}
-
-	if (rtp->ssl_ctx) {
-		return 0;
-	}
-
 #if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(LIBRESSL_VERSION_NUMBER)
-	rtp->ssl_ctx = SSL_CTX_new(DTLSv1_method());
+	return DTLSv1_method();
 #else
-	rtp->ssl_ctx = SSL_CTX_new(DTLS_method());
+	return DTLS_method();
 #endif
-	if (!rtp->ssl_ctx) {
-		return -1;
-	}
+}
 
-	SSL_CTX_set_read_ahead(rtp->ssl_ctx, 1);
+struct dtls_cert_info {
+	EVP_PKEY *private_key;
+	X509 *certificate;
+};
 
 #ifdef HAVE_OPENSSL_EC
 
+static void configure_dhparams(const struct ast_rtp *rtp, const struct ast_rtp_dtls_cfg *dtls_cfg)
+{
+	EC_KEY *ecdh;
+
 	if (!ast_strlen_zero(dtls_cfg->pvtfile)) {
 		BIO *bio = BIO_new_file(dtls_cfg->pvtfile, "r");
-		if (bio != NULL) {
+		if (bio) {
 			DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
-			if (dh != NULL) {
+			if (dh) {
 				if (SSL_CTX_set_tmp_dh(rtp->ssl_ctx, dh)) {
 					long options = SSL_OP_CIPHER_SERVER_PREFERENCE |
 						SSL_OP_SINGLE_DH_USE | SSL_OP_SINGLE_ECDH_USE;
@@ -1644,9 +1629,10 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con
 			BIO_free(bio);
 		}
 	}
+
 	/* enables AES-128 ciphers, to get AES-256 use NID_secp384r1 */
 	ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
-	if (ecdh != NULL) {
+	if (ecdh) {
 		if (SSL_CTX_set_tmp_ecdh(rtp->ssl_ctx, ecdh)) {
 			#ifndef SSL_CTRL_SET_ECDH_AUTO
 				#define SSL_CTRL_SET_ECDH_AUTO 94
@@ -1660,8 +1646,251 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con
 		}
 		EC_KEY_free(ecdh);
 	}
+}
+
+static int create_ephemeral_ec_keypair(EVP_PKEY **keypair)
+{
+	EC_KEY *eckey = NULL;
+	EC_GROUP *group = NULL;
+
+	group = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
+	if (!group) {
+		goto error;
+	}
+
+	EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
+	EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED);
+
+	eckey = EC_KEY_new();
+	if (!eckey) {
+		goto error;
+	}
+
+	if (!EC_KEY_set_group(eckey, group)) {
+		goto error;
+	}
+
+	if (!EC_KEY_generate_key(eckey)) {
+		goto error;
+	}
+
+	*keypair = EVP_PKEY_new();
+	if (!*keypair) {
+		goto error;
+	}
+
+	EVP_PKEY_assign_EC_KEY(*keypair, eckey);
+	EC_GROUP_free(group);
+
+	return 0;
+
+error:
+	EC_KEY_free(eckey);
+	EC_GROUP_free(group);
+
+	return -1;
+}
+
+/* From OpenSSL's x509 command */
+#define SERIAL_RAND_BITS 159
+
+static int create_ephemeral_certificate(EVP_PKEY *keypair, X509 **certificate)
+{
+	X509 *cert = NULL;
+	BIGNUM *serial = NULL;
+	X509_NAME *name = NULL;
+
+	cert = X509_new();
+	if (!cert) {
+		goto error;
+	}
+
+	if (!X509_set_version(cert, 2)) {
+		goto error;
+	}
+
+	/* Set the public key */
+	X509_set_pubkey(cert, keypair);
+
+	/* Generate a random serial number */
+	if (!(serial = BN_new())
+	   || !BN_rand(serial, SERIAL_RAND_BITS, -1, 0)
+	   || !BN_to_ASN1_INTEGER(serial, X509_get_serialNumber(cert))) {
+		goto error;
+	}
+
+	/*
+	 * Validity period - Current Chrome & Firefox make it 31 days starting
+	 * with yesterday at the current time, so we will do the same.
+	 */
+	if (!X509_time_adj_ex(X509_get_notBefore(cert), -1, 0, NULL)
+	   || !X509_time_adj_ex(X509_get_notAfter(cert), 30, 0, NULL)) {
+		goto error;
+	}
+
+	/* Set the name and issuer */
+	if (!(name = X509_get_subject_name(cert))
+	   || !X509_NAME_add_entry_by_NID(name, NID_commonName, MBSTRING_ASC,
+									  (unsigned char *) "asterisk", -1, -1, 0)
+	   || !X509_set_issuer_name(cert, name)) {
+		goto error;
+	}
+
+	/* Sign it */
+	if (!X509_sign(cert, keypair, EVP_sha256())) {
+		goto error;
+	}
+
+	*certificate = cert;
+
+	return 0;
+
+error:
+	BN_free(serial);
+	X509_free(cert);
+
+	return -1;
+}
+
+static int create_certificate_ephemeral(struct ast_rtp_instance *instance,
+										const struct ast_rtp_dtls_cfg *dtls_cfg,
+										struct dtls_cert_info *cert_info)
+{
+	/* Make sure these are initialized */
+	cert_info->private_key = NULL;
+	cert_info->certificate = NULL;
+
+	if (create_ephemeral_ec_keypair(&cert_info->private_key)) {
+		ast_log(LOG_ERROR, "Failed to create ephemeral ECDSA keypair\n");
+		goto error;
+	}
+
+	if (create_ephemeral_certificate(cert_info->private_key, &cert_info->certificate)) {
+		ast_log(LOG_ERROR, "Failed to create ephemeral X509 certificate\n");
+		goto error;
+	}
+
+	return 0;
+
+  error:
+	X509_free(cert_info->certificate);
+	EVP_PKEY_free(cert_info->private_key);
+
+	return -1;
+}
+
+#else
+
+static void configure_dhparams(const struct ast_rtp *rtp, const struct ast_rtp_dtls_cfg *dtls_cfg)
+{
+}
+
+static int create_certificate_ephemeral(struct ast_rtp_instance *instance,
+										const struct ast_rtp_dtls_cfg *dtls_cfg,
+										struct dtls_cert_info *cert_info)
+{
+	ast_log(LOG_ERROR, "Your version of OpenSSL does not support ECDSA keys\n");
+	return -1;
+}
+
+#endif /* HAVE_OPENSSL_EC */
+
+static int create_certificate_from_file(struct ast_rtp_instance *instance,
+										const struct ast_rtp_dtls_cfg *dtls_cfg,
+										struct dtls_cert_info *cert_info)
+{
+	FILE *fp;
+	BIO *certbio = NULL;
+	EVP_PKEY *private_key = NULL;
+	X509 *cert = NULL;
+	char *private_key_file = ast_strlen_zero(dtls_cfg->pvtfile) ? dtls_cfg->certfile : dtls_cfg->pvtfile;
+
+	fp = fopen(private_key_file, "r");
+	if (!fp) {
+		ast_log(LOG_ERROR, "Failed to read private key from file '%s': %s\n", private_key_file, strerror(errno));
+		goto error;
+	}
+
+	if (!PEM_read_PrivateKey(fp, &private_key, NULL, NULL)) {
+		ast_log(LOG_ERROR, "Failed to read private key from PEM file '%s'\n", private_key_file);
+		fclose(fp);
+		goto error;
+	}
+
+	if (fclose(fp)) {
+		ast_log(LOG_ERROR, "Failed to close private key file '%s': %s\n", private_key_file, strerror(errno));
+		goto error;
+	}
+
+	certbio = BIO_new(BIO_s_file());
+	if (!certbio) {
+		ast_log(LOG_ERROR, "Failed to allocate memory for certificate fingerprinting on RTP instance '%p'\n",
+				instance);
+		goto error;
+	}
+
+	if (!BIO_read_filename(certbio, dtls_cfg->certfile)
+	   || !(cert = PEM_read_bio_X509(certbio, NULL, 0, NULL))) {
+		ast_log(LOG_ERROR, "Failed to read certificate from file '%s'\n", dtls_cfg->certfile);
+		goto error;
+	}
+
+	cert_info->private_key = private_key;
+	cert_info->certificate = cert;
+
+	BIO_free_all(certbio);
+
+	return 0;
+
+error:
+	X509_free(cert);
+	BIO_free_all(certbio);
+	EVP_PKEY_free(private_key);
+
+	return -1;
+}
+
+static int load_dtls_certificate(struct ast_rtp_instance *instance,
+								 const struct ast_rtp_dtls_cfg *dtls_cfg,
+								 struct dtls_cert_info *cert_info)
+{
+	if (dtls_cfg->ephemeral_cert) {
+		return create_certificate_ephemeral(instance, dtls_cfg, cert_info);
+	} else if (!ast_strlen_zero(dtls_cfg->certfile)) {
+		return create_certificate_from_file(instance, dtls_cfg, cert_info);
+	} else {
+		return -1;
+	}
+}
 
-#endif /* #ifdef HAVE_OPENSSL_EC */
+/*! \pre instance is locked */
+static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, const struct ast_rtp_dtls_cfg *dtls_cfg)
+{
+	struct ast_rtp *rtp = ast_rtp_instance_get_data(instance);
+	struct dtls_cert_info cert_info = { 0 };
+	int res;
+
+	if (!dtls_cfg->enabled) {
+		return 0;
+	}
+
+	if (!ast_rtp_engine_srtp_is_registered()) {
+		ast_log(LOG_ERROR, "SRTP support module is not loaded or available. Try loading res_srtp.so.\n");
+		return -1;
+	}
+
+	if (rtp->ssl_ctx) {
+		return 0;
+	}
+
+	rtp->ssl_ctx = SSL_CTX_new(get_dtls_method());
+	if (!rtp->ssl_ctx) {
+		return -1;
+	}
+
+	SSL_CTX_set_read_ahead(rtp->ssl_ctx, 1);
+
+	configure_dhparams(rtp, dtls_cfg);
 
 	rtp->dtls_verify = dtls_cfg->verify;
 
@@ -1680,25 +1909,22 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con
 
 	rtp->local_hash = dtls_cfg->hash;
 
-	if (!ast_strlen_zero(dtls_cfg->certfile)) {
-		char *private = ast_strlen_zero(dtls_cfg->pvtfile) ? dtls_cfg->certfile : dtls_cfg->pvtfile;
-		BIO *certbio;
-		X509 *cert = NULL;
+	if (!load_dtls_certificate(instance, dtls_cfg, &cert_info)) {
 		const EVP_MD *type;
 		unsigned int size, i;
 		unsigned char fingerprint[EVP_MAX_MD_SIZE];
 		char *local_fingerprint = rtp->local_fingerprint;
 
-		if (!SSL_CTX_use_certificate_file(rtp->ssl_ctx, dtls_cfg->certfile, SSL_FILETYPE_PEM)) {
-			ast_log(LOG_ERROR, "Specified certificate file '%s' for RTP instance '%p' could not be used\n",
-				dtls_cfg->certfile, instance);
+		if (!SSL_CTX_use_certificate(rtp->ssl_ctx, cert_info.certificate)) {
+			ast_log(LOG_ERROR, "Specified certificate for RTP instance '%p' could not be used\n",
+					instance);
 			return -1;
 		}
 
-		if (!SSL_CTX_use_PrivateKey_file(rtp->ssl_ctx, private, SSL_FILETYPE_PEM) ||
-		    !SSL_CTX_check_private_key(rtp->ssl_ctx)) {
-			ast_log(LOG_ERROR, "Specified private key file '%s' for RTP instance '%p' could not be used\n",
-				private, instance);
+		if (!SSL_CTX_use_PrivateKey(rtp->ssl_ctx, cert_info.private_key)
+		    || !SSL_CTX_check_private_key(rtp->ssl_ctx)) {
+			ast_log(LOG_ERROR, "Specified private key for RTP instance '%p' could not be used\n",
+					instance);
 			return -1;
 		}
 
@@ -1712,22 +1938,9 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con
 			return -1;
 		}
 
-		if (!(certbio = BIO_new(BIO_s_file()))) {
-			ast_log(LOG_ERROR, "Failed to allocate memory for certificate fingerprinting on RTP instance '%p'\n",
-				instance);
-			return -1;
-		}
-
-		if (!BIO_read_filename(certbio, dtls_cfg->certfile) ||
-		    !(cert = PEM_read_bio_X509(certbio, NULL, 0, NULL)) ||
-		    !X509_digest(cert, type, fingerprint, &size) ||
-		    !size) {
-			ast_log(LOG_ERROR, "Could not produce fingerprint from certificate '%s' for RTP instance '%p'\n",
-				dtls_cfg->certfile, instance);
-			BIO_free_all(certbio);
-			if (cert) {
-				X509_free(cert);
-			}
+		if (!X509_digest(cert_info.certificate, type, fingerprint, &size) || !size) {
+			ast_log(LOG_ERROR, "Could not produce fingerprint from certificate for RTP instance '%p'\n",
+					instance);
 			return -1;
 		}
 
@@ -1736,10 +1949,10 @@ static int ast_rtp_dtls_set_configuration(struct ast_rtp_instance *instance, con
 			local_fingerprint += 3;
 		}
 
-		*(local_fingerprint-1) = 0;
+		*(local_fingerprint - 1) = 0;
 
-		BIO_free_all(certbio);
-		X509_free(cert);
+		EVP_PKEY_free(cert_info.private_key);
+		X509_free(cert_info.certificate);
 	}
 
 	if (!ast_strlen_zero(dtls_cfg->cipher)) {