blob: 7783e5998953ed535fc8b7b45cb015e65a101309 [file] [log] [blame]
James Kuszmaul4a42b182021-01-17 11:32:46 -08001#include "parameters.h"
2#include <rawrtc/config.h>
3#include <rawrtcc/code.h>
4#include <re.h>
5#include <openssl/bio.h> // BIO_new_mem_buf
6#include <openssl/dh.h> // DH, DH_check_params
7#include <openssl/err.h> // ERR_clear_error
8#include <openssl/pem.h> // PEM_read_bio_DHparams
9#include <openssl/ssl.h> // SSL_CTX_set_tmp_dh, SSL_CTX_set_ecdh_auto
10#include <limits.h> // INT_MAX, LONG_MAX
11
12#define DEBUG_MODULE "diffie-hellman-parameters"
13//#define RAWRTC_DEBUG_MODULE_LEVEL 7 // Note: Uncomment this to debug this module only
14#include <rawrtcc/debug.h>
15
16/*
17 * Apply Diffie-Hellman parameters on an OpenSSL context.
18 */
19static enum rawrtc_code set_dh_parameters(
20 struct ssl_ctx_st* const ssl_context, // not checked
21 DH const* const dh // not checked
22) {
23 int codes;
24
25 // Check that the parameters are "likely enough to be valid"
26#if OPENSSL_VERSION_NUMBER < 0x1010000fL || defined(OPENSSL_IS_BORINGSSL)
27 if (!DH_check(dh, &codes)) {
28 return RAWRTC_CODE_INVALID_ARGUMENT;
29 }
30#else
31 if (!DH_check_params(dh, &codes)) {
32 return RAWRTC_CODE_INVALID_ARGUMENT;
33 }
34#endif
35 if (codes) {
36#if defined(DH_CHECK_P_NOT_PRIME)
37 if (codes & DH_CHECK_P_NOT_PRIME) {
38 DEBUG_WARNING("set_dh_parameters: p is not prime\n");
39 }
40#endif
41#if defined(DH_CHECK_P_NOT_SAFE_PRIME)
42 if (codes & DH_CHECK_P_NOT_SAFE_PRIME) {
43 DEBUG_WARNING("set_dh_parameters: p is not safe prime\n");
44 }
45#endif
46#if defined(DH_UNABLE_TO_CHECK_GENERATOR)
47 if (codes & DH_UNABLE_TO_CHECK_GENERATOR) {
48 DEBUG_WARNING("set_dh_parameters: generator g cannot be checked\n");
49 }
50#endif
51#if defined(DH_NOT_SUITABLE_GENERATOR)
52 if (codes & DH_NOT_SUITABLE_GENERATOR) {
53 DEBUG_WARNING("set_dh_parameters: generator g is not suitable\n");
54 }
55#endif
56#if defined(DH_CHECK_Q_NOT_PRIME)
57 if (codes & DH_CHECK_Q_NOT_PRIME) {
58 DEBUG_WARNING("set_dh_parameters: q is not prime\n");
59 }
60#endif
61#if defined(DH_CHECK_INVALID_Q_VALUE)
62 if (codes & DH_CHECK_INVALID_Q_VALUE) {
63 DEBUG_WARNING("set_dh_parameters: q is invalid\n");
64 }
65#endif
66#if defined(DH_CHECK_INVALID_J_VALUE)
67 if (codes & DH_CHECK_INVALID_J_VALUE) {
68 DEBUG_WARNING("set_dh_parameters: j is invalid\n");
69 }
70#endif
71 return RAWRTC_CODE_INVALID_ARGUMENT;
72 }
73
74 // Apply Diffie-Hellman parameters
75 if (!SSL_CTX_set_tmp_dh(ssl_context, dh)) {
76 DEBUG_WARNING("set_dh_parameters: set_tmp_dh failed\n");
77 return RAWRTC_CODE_UNKNOWN_ERROR;
78 }
79
80 // Done
81 return RAWRTC_CODE_SUCCESS;
82}
83
84/*
85 * Set Diffie-Hellman parameters on an OpenSSL context using DER encoding.
86 */
87enum rawrtc_code rawrtc_set_dh_parameters_der(
88 struct tls* const tls, uint8_t const* const der, size_t const der_size) {
89 struct ssl_ctx_st* const ssl_context = tls_openssl_context(tls);
90 DH* dh = NULL;
91 enum rawrtc_code error = RAWRTC_CODE_UNKNOWN_ERROR;
92
93 // Check arguments
94 if (!ssl_context || !der || der_size == 0 || der_size > LONG_MAX) {
95 return RAWRTC_CODE_INVALID_ARGUMENT;
96 }
97
98 // Decode PKCS#3 Diffie-Hellman parameters
99 dh = d2i_DHparams(NULL, (unsigned char const**) &der, der_size);
100 if (!dh) {
101 goto out;
102 }
103
104 // Apply Diffie-Hellman parameters
105 error = set_dh_parameters(ssl_context, dh);
106 if (error) {
107 goto out;
108 }
109
110 // Done
111 error = RAWRTC_CODE_SUCCESS;
112
113out:
114 if (dh) {
115 DH_free(dh);
116 }
117 if (error) {
118 ERR_clear_error();
119 }
120 return error;
121}
122
123/**
124 * Set Diffie-Hellman parameters on an OpenSSL context using PEM encoding.
125 */
126enum rawrtc_code rawrtc_set_dh_parameters_pem(
127 struct tls* const tls, char const* const pem, size_t const pem_size) {
128 struct ssl_ctx_st* const ssl_context = tls_openssl_context(tls);
129 BIO* bio = NULL;
130 DH* dh = NULL;
131 enum rawrtc_code error = RAWRTC_CODE_NO_MEMORY;
132
133 // Check arguments
134 if (!ssl_context || !pem || pem_size == 0 || pem_size > INT_MAX) {
135 return RAWRTC_CODE_INVALID_ARGUMENT;
136 }
137
138 // Create memory sink
139 bio = BIO_new_mem_buf(pem, (int) pem_size);
140 if (!bio) {
141 goto out;
142 }
143
144 // Read Diffie-Hellman parameters into memory sink
145 dh = PEM_read_bio_DHparams(bio, NULL, 0, NULL);
146 if (!dh)
147 goto out;
148
149 // Apply Diffie-Hellman parameters
150 error = set_dh_parameters(ssl_context, dh);
151 if (error) {
152 goto out;
153 }
154
155 // Done
156 error = RAWRTC_CODE_SUCCESS;
157
158out:
159 if (dh) {
160 DH_free(dh);
161 }
162 if (bio) {
163 BIO_free(bio);
164 }
165 if (error) {
166 ERR_clear_error();
167 }
168 return error;
169}
170
171/*
172 * Enable elliptic-curve Diffie-Hellman on an OpenSSL context.
173 */
174enum rawrtc_code rawrtc_enable_ecdh(struct tls* const tls) {
175 struct ssl_ctx_st* const ssl_context = tls_openssl_context(tls);
176
177 // Check arguments
178 if (!ssl_context) {
179 return RAWRTC_CODE_INVALID_ARGUMENT;
180 }
181
182 // Enable elliptic-curve Diffie-Hellman
183 if (!SSL_CTX_set_ecdh_auto(ssl_context, (long) 1)) {
184 DEBUG_WARNING("set_dh_params: set_ecdh_auto failed\n");
185 return RAWRTC_CODE_UNKNOWN_ERROR;
186 }
187
188 // Done
189 return RAWRTC_CODE_SUCCESS;
190}