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