1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /* _ _
18 * _ __ ___ ___ __| | ___ ___| | mod_ssl
19 * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
20 * | | | | | | (_) | (_| | \__ \__ \ |
21 * |_| |_| |_|\___/ \__,_|___|___/___/_|
22 * |_____|
23 * ssl_util.c
24 * Utility Functions
25 */
26 /* ``Every day of my life
27 I am forced to add another
28 name to the list of people
29 who piss me off!''
30 -- Calvin */
31
32 #include "ssl_private.h"
33 #include "ap_mpm.h"
34 #include "apr_thread_mutex.h"
35
36 /* _________________________________________________________________
37 **
38 ** Utility Functions
39 ** _________________________________________________________________
40 */
41
ssl_util_vhostid(apr_pool_t * p,server_rec * s)42 char *ssl_util_vhostid(apr_pool_t *p, server_rec *s)
43 {
44 char *id;
45 SSLSrvConfigRec *sc;
46 char *host;
47 apr_port_t port;
48
49 host = s->server_hostname;
50 if (s->port != 0)
51 port = s->port;
52 else {
53 sc = mySrvConfig(s);
54 if (sc->enabled == TRUE)
55 port = DEFAULT_HTTPS_PORT;
56 else
57 port = DEFAULT_HTTP_PORT;
58 }
59 id = apr_psprintf(p, "%s:%lu", host, (unsigned long)port);
60 return id;
61 }
62
ssl_util_ppopen(server_rec * s,apr_pool_t * p,const char * cmd,const char * const * argv)63 apr_file_t *ssl_util_ppopen(server_rec *s, apr_pool_t *p, const char *cmd,
64 const char * const *argv)
65 {
66 apr_procattr_t *procattr;
67 apr_proc_t *proc;
68
69 if (apr_procattr_create(&procattr, p) != APR_SUCCESS)
70 return NULL;
71 if (apr_procattr_io_set(procattr, APR_FULL_BLOCK, APR_FULL_BLOCK,
72 APR_FULL_BLOCK) != APR_SUCCESS)
73 return NULL;
74 if (apr_procattr_dir_set(procattr,
75 ap_make_dirstr_parent(p, cmd)) != APR_SUCCESS)
76 return NULL;
77 if (apr_procattr_cmdtype_set(procattr, APR_PROGRAM) != APR_SUCCESS)
78 return NULL;
79 proc = apr_pcalloc(p, sizeof(apr_proc_t));
80 if (apr_proc_create(proc, cmd, argv, NULL, procattr, p) != APR_SUCCESS)
81 return NULL;
82 return proc->out;
83 }
84
ssl_util_ppclose(server_rec * s,apr_pool_t * p,apr_file_t * fp)85 void ssl_util_ppclose(server_rec *s, apr_pool_t *p, apr_file_t *fp)
86 {
87 apr_file_close(fp);
88 return;
89 }
90
91 /*
92 * Run a filter program and read the first line of its stdout output
93 */
ssl_util_readfilter(server_rec * s,apr_pool_t * p,const char * cmd,const char * const * argv)94 char *ssl_util_readfilter(server_rec *s, apr_pool_t *p, const char *cmd,
95 const char * const *argv)
96 {
97 static char buf[MAX_STRING_LEN];
98 apr_file_t *fp;
99 apr_size_t nbytes = 1;
100 char c;
101 int k;
102
103 if ((fp = ssl_util_ppopen(s, p, cmd, argv)) == NULL)
104 return NULL;
105 /* XXX: we are reading 1 byte at a time here */
106 for (k = 0; apr_file_read(fp, &c, &nbytes) == APR_SUCCESS
107 && nbytes == 1 && (k < MAX_STRING_LEN-1) ; ) {
108 if (c == '\n' || c == '\r')
109 break;
110 buf[k++] = c;
111 }
112 buf[k] = NUL;
113 ssl_util_ppclose(s, p, fp);
114
115 return buf;
116 }
117
ssl_util_path_check(ssl_pathcheck_t pcm,const char * path,apr_pool_t * p)118 BOOL ssl_util_path_check(ssl_pathcheck_t pcm, const char *path, apr_pool_t *p)
119 {
120 apr_finfo_t finfo;
121
122 if (path == NULL)
123 return FALSE;
124 if (pcm & SSL_PCM_EXISTS && apr_stat(&finfo, path,
125 APR_FINFO_TYPE|APR_FINFO_SIZE, p) != 0)
126 return FALSE;
127 AP_DEBUG_ASSERT((pcm & SSL_PCM_EXISTS) ||
128 !(pcm & (SSL_PCM_ISREG|SSL_PCM_ISDIR|SSL_PCM_ISNONZERO)));
129 if (pcm & SSL_PCM_ISREG && finfo.filetype != APR_REG)
130 return FALSE;
131 if (pcm & SSL_PCM_ISDIR && finfo.filetype != APR_DIR)
132 return FALSE;
133 if (pcm & SSL_PCM_ISNONZERO && finfo.size <= 0)
134 return FALSE;
135 return TRUE;
136 }
137
ssl_util_algotypeof(X509 * pCert,EVP_PKEY * pKey)138 ssl_algo_t ssl_util_algotypeof(X509 *pCert, EVP_PKEY *pKey)
139 {
140 ssl_algo_t t;
141 EVP_PKEY *pFreeKey = NULL;
142
143 t = SSL_ALGO_UNKNOWN;
144 if (pCert != NULL)
145 pFreeKey = pKey = X509_get_pubkey(pCert);
146 if (pKey != NULL) {
147 switch (EVP_PKEY_type(pKey->type)) {
148 case EVP_PKEY_RSA:
149 t = SSL_ALGO_RSA;
150 break;
151 case EVP_PKEY_DSA:
152 t = SSL_ALGO_DSA;
153 break;
154 #ifndef OPENSSL_NO_EC
155 case EVP_PKEY_EC:
156 t = SSL_ALGO_ECC;
157 break;
158 #endif
159 default:
160 break;
161 }
162 }
163 if (pFreeKey != NULL)
164 EVP_PKEY_free(pFreeKey);
165 return t;
166 }
167
ssl_util_algotypestr(ssl_algo_t t)168 char *ssl_util_algotypestr(ssl_algo_t t)
169 {
170 char *cp;
171
172 cp = "UNKNOWN";
173 switch (t) {
174 case SSL_ALGO_RSA:
175 cp = "RSA";
176 break;
177 case SSL_ALGO_DSA:
178 cp = "DSA";
179 break;
180 #ifndef OPENSSL_NO_EC
181 case SSL_ALGO_ECC:
182 cp = "ECC";
183 break;
184 #endif
185 default:
186 break;
187 }
188 return cp;
189 }
190
191 /*
192 * certain key and cert data needs to survive restarts,
193 * which are stored in the user data table of s->process->pool.
194 * to prevent "leaking" of this data, we use malloc/free
195 * rather than apr_palloc and these wrappers to help make sure
196 * we do not leak the malloc-ed data.
197 */
ssl_asn1_table_set(apr_hash_t * table,const char * key,long int length)198 unsigned char *ssl_asn1_table_set(apr_hash_t *table,
199 const char *key,
200 long int length)
201 {
202 apr_ssize_t klen = strlen(key);
203 ssl_asn1_t *asn1 = apr_hash_get(table, key, klen);
204
205 /*
206 * if a value for this key already exists,
207 * reuse as much of the already malloc-ed data
208 * as possible.
209 */
210 if (asn1) {
211 if (asn1->nData != length) {
212 free(asn1->cpData); /* XXX: realloc? */
213 asn1->cpData = NULL;
214 }
215 }
216 else {
217 asn1 = ap_malloc(sizeof(*asn1));
218 asn1->source_mtime = 0; /* used as a note for encrypted private keys */
219 asn1->cpData = NULL;
220 }
221
222 asn1->nData = length;
223 if (!asn1->cpData) {
224 asn1->cpData = ap_malloc(length);
225 }
226
227 apr_hash_set(table, key, klen, asn1);
228
229 return asn1->cpData; /* caller will assign a value to this */
230 }
231
ssl_asn1_table_get(apr_hash_t * table,const char * key)232 ssl_asn1_t *ssl_asn1_table_get(apr_hash_t *table,
233 const char *key)
234 {
235 return (ssl_asn1_t *)apr_hash_get(table, key, APR_HASH_KEY_STRING);
236 }
237
ssl_asn1_table_unset(apr_hash_t * table,const char * key)238 void ssl_asn1_table_unset(apr_hash_t *table,
239 const char *key)
240 {
241 apr_ssize_t klen = strlen(key);
242 ssl_asn1_t *asn1 = apr_hash_get(table, key, klen);
243
244 if (!asn1) {
245 return;
246 }
247
248 if (asn1->cpData) {
249 free(asn1->cpData);
250 }
251 free(asn1);
252
253 apr_hash_set(table, key, klen, NULL);
254 }
255
256 #ifndef OPENSSL_NO_EC
257 static const char *ssl_asn1_key_types[] = {"RSA", "DSA", "ECC"};
258 #else
259 static const char *ssl_asn1_key_types[] = {"RSA", "DSA"};
260 #endif
261
ssl_asn1_keystr(int keytype)262 const char *ssl_asn1_keystr(int keytype)
263 {
264 if (keytype >= SSL_AIDX_MAX) {
265 return NULL;
266 }
267
268 return ssl_asn1_key_types[keytype];
269 }
270
ssl_asn1_table_keyfmt(apr_pool_t * p,const char * id,int keytype)271 const char *ssl_asn1_table_keyfmt(apr_pool_t *p,
272 const char *id,
273 int keytype)
274 {
275 const char *keystr = ssl_asn1_keystr(keytype);
276
277 return apr_pstrcat(p, id, ":", keystr, NULL);
278 }
279
STACK_OF(X509)280 STACK_OF(X509) *ssl_read_pkcs7(server_rec *s, const char *pkcs7)
281 {
282 PKCS7 *p7;
283 STACK_OF(X509) *certs = NULL;
284 FILE *f;
285
286 f = fopen(pkcs7, "r");
287 if (!f) {
288 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02212) "Can't open %s", pkcs7);
289 ssl_die(s);
290 }
291
292 p7 = PEM_read_PKCS7(f, NULL, NULL, NULL);
293 if (!p7) {
294 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02274)
295 "Can't read PKCS7 object %s", pkcs7);
296 ssl_log_ssl_error(SSLLOG_MARK, APLOG_CRIT, s);
297 exit(1);
298 }
299
300 switch (OBJ_obj2nid(p7->type)) {
301 case NID_pkcs7_signed:
302 certs = p7->d.sign->cert;
303 p7->d.sign->cert = NULL;
304 PKCS7_free(p7);
305 break;
306
307 case NID_pkcs7_signedAndEnveloped:
308 certs = p7->d.signed_and_enveloped->cert;
309 p7->d.signed_and_enveloped->cert = NULL;
310 PKCS7_free(p7);
311 break;
312
313 default:
314 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02213)
315 "Don't understand PKCS7 file %s", pkcs7);
316 ssl_die(s);
317 }
318
319 if (!certs) {
320 ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s, APLOGNO(02214)
321 "No certificates in %s", pkcs7);
322 ssl_die(s);
323 }
324
325 fclose(f);
326
327 return certs;
328 }
329
330
331 #if APR_HAS_THREADS
332 /*
333 * To ensure thread-safetyness in OpenSSL - work in progress
334 */
335
336 static apr_thread_mutex_t **lock_cs;
337 static int lock_num_locks;
338
ssl_util_thr_lock(int mode,int type,const char * file,int line)339 static void ssl_util_thr_lock(int mode, int type,
340 const char *file, int line)
341 {
342 if (type < lock_num_locks) {
343 if (mode & CRYPTO_LOCK) {
344 apr_thread_mutex_lock(lock_cs[type]);
345 }
346 else {
347 apr_thread_mutex_unlock(lock_cs[type]);
348 }
349 }
350 }
351
352 /* Dynamic lock structure */
353 struct CRYPTO_dynlock_value {
354 apr_pool_t *pool;
355 const char* file;
356 int line;
357 apr_thread_mutex_t *mutex;
358 };
359
360 /* Global reference to the pool passed into ssl_util_thread_setup() */
361 apr_pool_t *dynlockpool = NULL;
362
363 /*
364 * Dynamic lock creation callback
365 */
ssl_dyn_create_function(const char * file,int line)366 static struct CRYPTO_dynlock_value *ssl_dyn_create_function(const char *file,
367 int line)
368 {
369 struct CRYPTO_dynlock_value *value;
370 apr_pool_t *p;
371 apr_status_t rv;
372
373 /*
374 * We need a pool to allocate our mutex. Since we can't clear
375 * allocated memory from a pool, create a subpool that we can blow
376 * away in the destruction callback.
377 */
378 apr_pool_create(&p, dynlockpool);
379 ap_log_perror(file, line, APLOG_MODULE_INDEX, APLOG_TRACE1, 0, p,
380 "Creating dynamic lock");
381
382 value = apr_palloc(p, sizeof(struct CRYPTO_dynlock_value));
383 value->pool = p;
384 /* Keep our own copy of the place from which we were created,
385 using our own pool. */
386 value->file = apr_pstrdup(p, file);
387 value->line = line;
388 rv = apr_thread_mutex_create(&(value->mutex), APR_THREAD_MUTEX_DEFAULT,
389 p);
390 if (rv != APR_SUCCESS) {
391 ap_log_perror(file, line, APLOG_MODULE_INDEX, APLOG_ERR, rv, p, APLOGNO(02186)
392 "Failed to create thread mutex for dynamic lock");
393 apr_pool_destroy(p);
394 return NULL;
395 }
396 return value;
397 }
398
399 /*
400 * Dynamic locking and unlocking function
401 */
402
ssl_dyn_lock_function(int mode,struct CRYPTO_dynlock_value * l,const char * file,int line)403 static void ssl_dyn_lock_function(int mode, struct CRYPTO_dynlock_value *l,
404 const char *file, int line)
405 {
406 apr_status_t rv;
407
408 if (mode & CRYPTO_LOCK) {
409 ap_log_perror(file, line, APLOG_MODULE_INDEX, APLOG_TRACE3, 0, l->pool,
410 "Acquiring mutex %s:%d", l->file, l->line);
411 rv = apr_thread_mutex_lock(l->mutex);
412 ap_log_perror(file, line, APLOG_MODULE_INDEX, APLOG_TRACE3, rv, l->pool,
413 "Mutex %s:%d acquired!", l->file, l->line);
414 }
415 else {
416 ap_log_perror(file, line, APLOG_MODULE_INDEX, APLOG_TRACE3, 0, l->pool,
417 "Releasing mutex %s:%d", l->file, l->line);
418 rv = apr_thread_mutex_unlock(l->mutex);
419 ap_log_perror(file, line, APLOG_MODULE_INDEX, APLOG_TRACE3, rv, l->pool,
420 "Mutex %s:%d released!", l->file, l->line);
421 }
422 }
423
424 /*
425 * Dynamic lock destruction callback
426 */
ssl_dyn_destroy_function(struct CRYPTO_dynlock_value * l,const char * file,int line)427 static void ssl_dyn_destroy_function(struct CRYPTO_dynlock_value *l,
428 const char *file, int line)
429 {
430 apr_status_t rv;
431
432 ap_log_perror(file, line, APLOG_MODULE_INDEX, APLOG_TRACE1, 0, l->pool,
433 "Destroying dynamic lock %s:%d", l->file, l->line);
434 rv = apr_thread_mutex_destroy(l->mutex);
435 if (rv != APR_SUCCESS) {
436 ap_log_perror(file, line, APLOG_MODULE_INDEX, APLOG_ERR, rv, l->pool,
437 APLOGNO(02192) "Failed to destroy mutex for dynamic "
438 "lock %s:%d", l->file, l->line);
439 }
440
441 /* Trust that whomever owned the CRYPTO_dynlock_value we were
442 * passed has no future use for it...
443 */
444 apr_pool_destroy(l->pool);
445 }
446
ssl_util_thr_id(void)447 static unsigned long ssl_util_thr_id(void)
448 {
449 /* OpenSSL needs this to return an unsigned long. On OS/390, the pthread
450 * id is a structure twice that big. Use the TCB pointer instead as a
451 * unique unsigned long.
452 */
453 #ifdef __MVS__
454 struct PSA {
455 char unmapped[540];
456 unsigned long PSATOLD;
457 } *psaptr = 0;
458
459 return psaptr->PSATOLD;
460 #else
461 return (unsigned long) apr_os_thread_current();
462 #endif
463 }
464
ssl_util_thread_cleanup(void * data)465 static apr_status_t ssl_util_thread_cleanup(void *data)
466 {
467 CRYPTO_set_locking_callback(NULL);
468 CRYPTO_set_id_callback(NULL);
469
470 CRYPTO_set_dynlock_create_callback(NULL);
471 CRYPTO_set_dynlock_lock_callback(NULL);
472 CRYPTO_set_dynlock_destroy_callback(NULL);
473
474 dynlockpool = NULL;
475
476 /* Let the registered mutex cleanups do their own thing
477 */
478 return APR_SUCCESS;
479 }
480
ssl_util_thread_setup(apr_pool_t * p)481 void ssl_util_thread_setup(apr_pool_t *p)
482 {
483 int i;
484
485 lock_num_locks = CRYPTO_num_locks();
486 lock_cs = apr_palloc(p, lock_num_locks * sizeof(*lock_cs));
487
488 for (i = 0; i < lock_num_locks; i++) {
489 apr_thread_mutex_create(&(lock_cs[i]), APR_THREAD_MUTEX_DEFAULT, p);
490 }
491
492 CRYPTO_set_id_callback(ssl_util_thr_id);
493
494 CRYPTO_set_locking_callback(ssl_util_thr_lock);
495
496 /* Set up dynamic locking scaffolding for OpenSSL to use at its
497 * convenience.
498 */
499 dynlockpool = p;
500 CRYPTO_set_dynlock_create_callback(ssl_dyn_create_function);
501 CRYPTO_set_dynlock_lock_callback(ssl_dyn_lock_function);
502 CRYPTO_set_dynlock_destroy_callback(ssl_dyn_destroy_function);
503
504 apr_pool_cleanup_register(p, NULL, ssl_util_thread_cleanup,
505 apr_pool_cleanup_null);
506 }
507 #endif
508