Squashed 'third_party/rawrtc/rawrtc/' content from commit aa3ae4b24
Change-Id: I38a655a4259b62f591334e90a1315bd4e7e4d8ec
git-subtree-dir: third_party/rawrtc/rawrtc
git-subtree-split: aa3ae4b247275cc6e69c30613b3a4ba7fdc82d1b
diff --git a/src/diffie_hellman_parameters/parameters.c b/src/diffie_hellman_parameters/parameters.c
new file mode 100644
index 0000000..7783e59
--- /dev/null
+++ b/src/diffie_hellman_parameters/parameters.c
@@ -0,0 +1,190 @@
+#include "parameters.h"
+#include <rawrtc/config.h>
+#include <rawrtcc/code.h>
+#include <re.h>
+#include <openssl/bio.h> // BIO_new_mem_buf
+#include <openssl/dh.h> // DH, DH_check_params
+#include <openssl/err.h> // ERR_clear_error
+#include <openssl/pem.h> // PEM_read_bio_DHparams
+#include <openssl/ssl.h> // SSL_CTX_set_tmp_dh, SSL_CTX_set_ecdh_auto
+#include <limits.h> // INT_MAX, LONG_MAX
+
+#define DEBUG_MODULE "diffie-hellman-parameters"
+//#define RAWRTC_DEBUG_MODULE_LEVEL 7 // Note: Uncomment this to debug this module only
+#include <rawrtcc/debug.h>
+
+/*
+ * Apply Diffie-Hellman parameters on an OpenSSL context.
+ */
+static enum rawrtc_code set_dh_parameters(
+ struct ssl_ctx_st* const ssl_context, // not checked
+ DH const* const dh // not checked
+) {
+ int codes;
+
+ // Check that the parameters are "likely enough to be valid"
+#if OPENSSL_VERSION_NUMBER < 0x1010000fL || defined(OPENSSL_IS_BORINGSSL)
+ if (!DH_check(dh, &codes)) {
+ return RAWRTC_CODE_INVALID_ARGUMENT;
+ }
+#else
+ if (!DH_check_params(dh, &codes)) {
+ return RAWRTC_CODE_INVALID_ARGUMENT;
+ }
+#endif
+ if (codes) {
+#if defined(DH_CHECK_P_NOT_PRIME)
+ if (codes & DH_CHECK_P_NOT_PRIME) {
+ DEBUG_WARNING("set_dh_parameters: p is not prime\n");
+ }
+#endif
+#if defined(DH_CHECK_P_NOT_SAFE_PRIME)
+ if (codes & DH_CHECK_P_NOT_SAFE_PRIME) {
+ DEBUG_WARNING("set_dh_parameters: p is not safe prime\n");
+ }
+#endif
+#if defined(DH_UNABLE_TO_CHECK_GENERATOR)
+ if (codes & DH_UNABLE_TO_CHECK_GENERATOR) {
+ DEBUG_WARNING("set_dh_parameters: generator g cannot be checked\n");
+ }
+#endif
+#if defined(DH_NOT_SUITABLE_GENERATOR)
+ if (codes & DH_NOT_SUITABLE_GENERATOR) {
+ DEBUG_WARNING("set_dh_parameters: generator g is not suitable\n");
+ }
+#endif
+#if defined(DH_CHECK_Q_NOT_PRIME)
+ if (codes & DH_CHECK_Q_NOT_PRIME) {
+ DEBUG_WARNING("set_dh_parameters: q is not prime\n");
+ }
+#endif
+#if defined(DH_CHECK_INVALID_Q_VALUE)
+ if (codes & DH_CHECK_INVALID_Q_VALUE) {
+ DEBUG_WARNING("set_dh_parameters: q is invalid\n");
+ }
+#endif
+#if defined(DH_CHECK_INVALID_J_VALUE)
+ if (codes & DH_CHECK_INVALID_J_VALUE) {
+ DEBUG_WARNING("set_dh_parameters: j is invalid\n");
+ }
+#endif
+ return RAWRTC_CODE_INVALID_ARGUMENT;
+ }
+
+ // Apply Diffie-Hellman parameters
+ if (!SSL_CTX_set_tmp_dh(ssl_context, dh)) {
+ DEBUG_WARNING("set_dh_parameters: set_tmp_dh failed\n");
+ return RAWRTC_CODE_UNKNOWN_ERROR;
+ }
+
+ // Done
+ return RAWRTC_CODE_SUCCESS;
+}
+
+/*
+ * Set Diffie-Hellman parameters on an OpenSSL context using DER encoding.
+ */
+enum rawrtc_code rawrtc_set_dh_parameters_der(
+ struct tls* const tls, uint8_t const* const der, size_t const der_size) {
+ struct ssl_ctx_st* const ssl_context = tls_openssl_context(tls);
+ DH* dh = NULL;
+ enum rawrtc_code error = RAWRTC_CODE_UNKNOWN_ERROR;
+
+ // Check arguments
+ if (!ssl_context || !der || der_size == 0 || der_size > LONG_MAX) {
+ return RAWRTC_CODE_INVALID_ARGUMENT;
+ }
+
+ // Decode PKCS#3 Diffie-Hellman parameters
+ dh = d2i_DHparams(NULL, (unsigned char const**) &der, der_size);
+ if (!dh) {
+ goto out;
+ }
+
+ // Apply Diffie-Hellman parameters
+ error = set_dh_parameters(ssl_context, dh);
+ if (error) {
+ goto out;
+ }
+
+ // Done
+ error = RAWRTC_CODE_SUCCESS;
+
+out:
+ if (dh) {
+ DH_free(dh);
+ }
+ if (error) {
+ ERR_clear_error();
+ }
+ return error;
+}
+
+/**
+ * Set Diffie-Hellman parameters on an OpenSSL context using PEM encoding.
+ */
+enum rawrtc_code rawrtc_set_dh_parameters_pem(
+ struct tls* const tls, char const* const pem, size_t const pem_size) {
+ struct ssl_ctx_st* const ssl_context = tls_openssl_context(tls);
+ BIO* bio = NULL;
+ DH* dh = NULL;
+ enum rawrtc_code error = RAWRTC_CODE_NO_MEMORY;
+
+ // Check arguments
+ if (!ssl_context || !pem || pem_size == 0 || pem_size > INT_MAX) {
+ return RAWRTC_CODE_INVALID_ARGUMENT;
+ }
+
+ // Create memory sink
+ bio = BIO_new_mem_buf(pem, (int) pem_size);
+ if (!bio) {
+ goto out;
+ }
+
+ // Read Diffie-Hellman parameters into memory sink
+ dh = PEM_read_bio_DHparams(bio, NULL, 0, NULL);
+ if (!dh)
+ goto out;
+
+ // Apply Diffie-Hellman parameters
+ error = set_dh_parameters(ssl_context, dh);
+ if (error) {
+ goto out;
+ }
+
+ // Done
+ error = RAWRTC_CODE_SUCCESS;
+
+out:
+ if (dh) {
+ DH_free(dh);
+ }
+ if (bio) {
+ BIO_free(bio);
+ }
+ if (error) {
+ ERR_clear_error();
+ }
+ return error;
+}
+
+/*
+ * Enable elliptic-curve Diffie-Hellman on an OpenSSL context.
+ */
+enum rawrtc_code rawrtc_enable_ecdh(struct tls* const tls) {
+ struct ssl_ctx_st* const ssl_context = tls_openssl_context(tls);
+
+ // Check arguments
+ if (!ssl_context) {
+ return RAWRTC_CODE_INVALID_ARGUMENT;
+ }
+
+ // Enable elliptic-curve Diffie-Hellman
+ if (!SSL_CTX_set_ecdh_auto(ssl_context, (long) 1)) {
+ DEBUG_WARNING("set_dh_params: set_ecdh_auto failed\n");
+ return RAWRTC_CODE_UNKNOWN_ERROR;
+ }
+
+ // Done
+ return RAWRTC_CODE_SUCCESS;
+}