54
54
55
55
extern ConnectionType CT_Socket ;
56
56
57
- SSL_CTX * redis_tls_ctx ;
57
+ SSL_CTX * redis_tls_ctx = NULL ;
58
+ SSL_CTX * redis_tls_client_ctx = NULL ;
58
59
59
60
static int parseProtocolsConfig (const char * str ) {
60
61
int i , count = 0 ;
@@ -163,50 +164,22 @@ void tlsInit(void) {
163
164
pending_list = listCreate ();
164
165
}
165
166
166
- /* Attempt to configure/reconfigure TLS. This operation is atomic and will
167
- * leave the SSL_CTX unchanged if fails .
167
+ /* Create a *base* SSL_CTX using the SSL configuration provided. The base context
168
+ * includes everything that's common for both client-side and server-side connections .
168
169
*/
169
- int tlsConfigure (redisTLSContextConfig * ctx_config ) {
170
+ static SSL_CTX * createSSLContext (redisTLSContextConfig * ctx_config , int protocols ,
171
+ const char * cert_file , const char * key_file ) {
170
172
char errbuf [256 ];
171
173
SSL_CTX * ctx = NULL ;
172
174
173
- if (!ctx_config -> cert_file ) {
174
- serverLog (LL_WARNING , "No tls-cert-file configured!" );
175
- goto error ;
176
- }
177
-
178
- if (!ctx_config -> key_file ) {
179
- serverLog (LL_WARNING , "No tls-key-file configured!" );
180
- goto error ;
181
- }
182
-
183
- if (((server .tls_auth_clients != TLS_CLIENT_AUTH_NO ) || server .tls_cluster || server .tls_replication ) &&
184
- !ctx_config -> ca_cert_file && !ctx_config -> ca_cert_dir ) {
185
- serverLog (LL_WARNING , "Either tls-ca-cert-file or tls-ca-cert-dir must be specified when tls-cluster, tls-replication or tls-auth-clients are enabled!" );
186
- goto error ;
187
- }
188
-
189
175
ctx = SSL_CTX_new (SSLv23_method ());
190
176
191
177
SSL_CTX_set_options (ctx , SSL_OP_NO_SSLv2 |SSL_OP_NO_SSLv3 );
192
- SSL_CTX_set_options (ctx , SSL_OP_SINGLE_DH_USE );
193
178
194
179
#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
195
180
SSL_CTX_set_options (ctx , SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS );
196
181
#endif
197
182
198
- if (ctx_config -> session_caching ) {
199
- SSL_CTX_set_session_cache_mode (ctx , SSL_SESS_CACHE_SERVER );
200
- SSL_CTX_sess_set_cache_size (ctx , ctx_config -> session_cache_size );
201
- SSL_CTX_set_timeout (ctx , ctx_config -> session_cache_timeout );
202
- SSL_CTX_set_session_id_context (ctx , (void * ) "redis" , 5 );
203
- } else {
204
- SSL_CTX_set_session_cache_mode (ctx , SSL_SESS_CACHE_OFF );
205
- }
206
-
207
- int protocols = parseProtocolsConfig (ctx_config -> protocols );
208
- if (protocols == -1 ) goto error ;
209
-
210
183
if (!(protocols & REDIS_TLS_PROTO_TLSv1 ))
211
184
SSL_CTX_set_options (ctx , SSL_OP_NO_TLSv1 );
212
185
if (!(protocols & REDIS_TLS_PROTO_TLSv1_1 ))
@@ -224,38 +197,99 @@ int tlsConfigure(redisTLSContextConfig *ctx_config) {
224
197
SSL_CTX_set_options (ctx , SSL_OP_NO_COMPRESSION );
225
198
#endif
226
199
227
- #ifdef SSL_OP_NO_CLIENT_RENEGOTIATION
228
- SSL_CTX_set_options (ctx , SSL_OP_NO_CLIENT_RENEGOTIATION );
229
- #endif
230
-
231
- if (ctx_config -> prefer_server_ciphers )
232
- SSL_CTX_set_options (ctx , SSL_OP_CIPHER_SERVER_PREFERENCE );
233
-
234
200
SSL_CTX_set_mode (ctx , SSL_MODE_ENABLE_PARTIAL_WRITE |SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER );
235
201
SSL_CTX_set_verify (ctx , SSL_VERIFY_PEER |SSL_VERIFY_FAIL_IF_NO_PEER_CERT , NULL );
236
- #if defined(SSL_CTX_set_ecdh_auto )
237
- SSL_CTX_set_ecdh_auto (ctx , 1 );
238
- #endif
239
202
240
- if (SSL_CTX_use_certificate_chain_file (ctx , ctx_config -> cert_file ) <= 0 ) {
203
+ if (SSL_CTX_use_certificate_chain_file (ctx , cert_file ) <= 0 ) {
241
204
ERR_error_string_n (ERR_get_error (), errbuf , sizeof (errbuf ));
242
- serverLog (LL_WARNING , "Failed to load certificate: %s: %s" , ctx_config -> cert_file , errbuf );
205
+ serverLog (LL_WARNING , "Failed to load certificate: %s: %s" , cert_file , errbuf );
243
206
goto error ;
244
207
}
245
-
246
- if (SSL_CTX_use_PrivateKey_file (ctx , ctx_config -> key_file , SSL_FILETYPE_PEM ) <= 0 ) {
208
+
209
+ if (SSL_CTX_use_PrivateKey_file (ctx , key_file , SSL_FILETYPE_PEM ) <= 0 ) {
247
210
ERR_error_string_n (ERR_get_error (), errbuf , sizeof (errbuf ));
248
- serverLog (LL_WARNING , "Failed to load private key: %s: %s" , ctx_config -> key_file , errbuf );
211
+ serverLog (LL_WARNING , "Failed to load private key: %s: %s" , key_file , errbuf );
249
212
goto error ;
250
213
}
251
-
214
+
252
215
if ((ctx_config -> ca_cert_file || ctx_config -> ca_cert_dir ) &&
253
216
SSL_CTX_load_verify_locations (ctx , ctx_config -> ca_cert_file , ctx_config -> ca_cert_dir ) <= 0 ) {
254
217
ERR_error_string_n (ERR_get_error (), errbuf , sizeof (errbuf ));
255
218
serverLog (LL_WARNING , "Failed to configure CA certificate(s) file/directory: %s" , errbuf );
256
219
goto error ;
257
220
}
258
221
222
+ if (ctx_config -> ciphers && !SSL_CTX_set_cipher_list (ctx , ctx_config -> ciphers )) {
223
+ serverLog (LL_WARNING , "Failed to configure ciphers: %s" , ctx_config -> ciphers );
224
+ goto error ;
225
+ }
226
+
227
+ #ifdef TLS1_3_VERSION
228
+ if (ctx_config -> ciphersuites && !SSL_CTX_set_ciphersuites (ctx , ctx_config -> ciphersuites )) {
229
+ serverLog (LL_WARNING , "Failed to configure ciphersuites: %s" , ctx_config -> ciphersuites );
230
+ goto error ;
231
+ }
232
+ #endif
233
+
234
+ return ctx ;
235
+
236
+ error :
237
+ if (ctx ) SSL_CTX_free (ctx );
238
+ return NULL ;
239
+ }
240
+
241
+ /* Attempt to configure/reconfigure TLS. This operation is atomic and will
242
+ * leave the SSL_CTX unchanged if fails.
243
+ */
244
+ int tlsConfigure (redisTLSContextConfig * ctx_config ) {
245
+ char errbuf [256 ];
246
+ SSL_CTX * ctx = NULL ;
247
+ SSL_CTX * client_ctx = NULL ;
248
+
249
+ if (!ctx_config -> cert_file ) {
250
+ serverLog (LL_WARNING , "No tls-cert-file configured!" );
251
+ goto error ;
252
+ }
253
+
254
+ if (!ctx_config -> key_file ) {
255
+ serverLog (LL_WARNING , "No tls-key-file configured!" );
256
+ goto error ;
257
+ }
258
+
259
+ if (((server .tls_auth_clients != TLS_CLIENT_AUTH_NO ) || server .tls_cluster || server .tls_replication ) &&
260
+ !ctx_config -> ca_cert_file && !ctx_config -> ca_cert_dir ) {
261
+ serverLog (LL_WARNING , "Either tls-ca-cert-file or tls-ca-cert-dir must be specified when tls-cluster, tls-replication or tls-auth-clients are enabled!" );
262
+ goto error ;
263
+ }
264
+
265
+ int protocols = parseProtocolsConfig (ctx_config -> protocols );
266
+ if (protocols == -1 ) goto error ;
267
+
268
+ /* Create server side/generla context */
269
+ ctx = createSSLContext (ctx_config , protocols , ctx_config -> cert_file , ctx_config -> key_file );
270
+ if (!ctx ) goto error ;
271
+
272
+ if (ctx_config -> session_caching ) {
273
+ SSL_CTX_set_session_cache_mode (ctx , SSL_SESS_CACHE_SERVER );
274
+ SSL_CTX_sess_set_cache_size (ctx , ctx_config -> session_cache_size );
275
+ SSL_CTX_set_timeout (ctx , ctx_config -> session_cache_timeout );
276
+ SSL_CTX_set_session_id_context (ctx , (void * ) "redis" , 5 );
277
+ } else {
278
+ SSL_CTX_set_session_cache_mode (ctx , SSL_SESS_CACHE_OFF );
279
+ }
280
+
281
+ #ifdef SSL_OP_NO_CLIENT_RENEGOTIATION
282
+ SSL_CTX_set_options (ctx , SSL_OP_NO_CLIENT_RENEGOTIATION );
283
+ #endif
284
+
285
+ if (ctx_config -> prefer_server_ciphers )
286
+ SSL_CTX_set_options (ctx , SSL_OP_CIPHER_SERVER_PREFERENCE );
287
+
288
+ #if defined(SSL_CTX_set_ecdh_auto )
289
+ SSL_CTX_set_ecdh_auto (ctx , 1 );
290
+ #endif
291
+ SSL_CTX_set_options (ctx , SSL_OP_SINGLE_DH_USE );
292
+
259
293
if (ctx_config -> dh_params_file ) {
260
294
FILE * dhfile = fopen (ctx_config -> dh_params_file , "r" );
261
295
DH * dh = NULL ;
@@ -281,25 +315,22 @@ int tlsConfigure(redisTLSContextConfig *ctx_config) {
281
315
DH_free (dh );
282
316
}
283
317
284
- if (ctx_config -> ciphers && !SSL_CTX_set_cipher_list (ctx , ctx_config -> ciphers )) {
285
- serverLog (LL_WARNING , "Failed to configure ciphers: %s" , ctx_config -> ciphers );
286
- goto error ;
318
+ /* If a client-side certificate is configured, create an explicit client context */
319
+ if (ctx_config -> client_cert_file && ctx_config -> client_key_file ) {
320
+ client_ctx = createSSLContext (ctx_config , protocols , ctx_config -> client_cert_file , ctx_config -> client_key_file );
321
+ if (!client_ctx ) goto error ;
287
322
}
288
323
289
- #ifdef TLS1_3_VERSION
290
- if (ctx_config -> ciphersuites && !SSL_CTX_set_ciphersuites (ctx , ctx_config -> ciphersuites )) {
291
- serverLog (LL_WARNING , "Failed to configure ciphersuites: %s" , ctx_config -> ciphersuites );
292
- goto error ;
293
- }
294
- #endif
295
-
296
324
SSL_CTX_free (redis_tls_ctx );
325
+ SSL_CTX_free (redis_tls_client_ctx );
297
326
redis_tls_ctx = ctx ;
327
+ redis_tls_client_ctx = client_ctx ;
298
328
299
329
return C_OK ;
300
330
301
331
error :
302
332
if (ctx ) SSL_CTX_free (ctx );
333
+ if (client_ctx ) SSL_CTX_free (client_ctx );
303
334
return C_ERR ;
304
335
}
305
336
@@ -344,14 +375,21 @@ typedef struct tls_connection {
344
375
listNode * pending_list_node ;
345
376
} tls_connection ;
346
377
347
- connection * connCreateTLS (void ) {
378
+ static connection * createTLSConnection (bool client_side ) {
379
+ SSL_CTX * ctx = redis_tls_ctx ;
380
+ if (client_side && redis_tls_client_ctx )
381
+ ctx = redis_tls_client_ctx ;
348
382
tls_connection * conn = zcalloc (sizeof (tls_connection ));
349
383
conn -> c .type = & CT_TLS ;
350
384
conn -> c .fd = -1 ;
351
- conn -> ssl = SSL_new (redis_tls_ctx );
385
+ conn -> ssl = SSL_new (ctx );
352
386
return (connection * ) conn ;
353
387
}
354
388
389
+ connection * connCreateTLS (void ) {
390
+ return createTLSConnection (true);
391
+ }
392
+
355
393
/* Fetch the latest OpenSSL error and store it in the connection */
356
394
static void updateTLSError (tls_connection * conn ) {
357
395
conn -> c .last_errno = 0 ;
@@ -370,7 +408,7 @@ static void updateTLSError(tls_connection *conn) {
370
408
* is not in an error state.
371
409
*/
372
410
connection * connCreateAcceptedTLS (int fd , int require_auth ) {
373
- tls_connection * conn = (tls_connection * ) connCreateTLS ( );
411
+ tls_connection * conn = (tls_connection * ) createTLSConnection (false );
374
412
conn -> c .fd = fd ;
375
413
conn -> c .state = CONN_STATE_ACCEPTING ;
376
414
0 commit comments