switch to a 60 bit hash
[httpd-crcsyncproxy.git] / modules / ssl / ssl_util.c
blob27c035144f06eb6049cedc13df40f37b3541227a
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 /* _ _
18 * _ __ ___ ___ __| | ___ ___| | mod_ssl
19 * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
20 * | | | | | | (_) | (_| | \__ \__ \ |
21 * |_| |_| |_|\___/ \__,_|___|___/___/_|
22 * |_____|
23 * ssl_util.c
24 * Utility Functions
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 */
32 #include "ssl_private.h"
33 #include "ap_mpm.h"
34 #include "apr_thread_mutex.h"
36 /* _________________________________________________________________
38 ** Utility Functions
39 ** _________________________________________________________________
42 char *ssl_util_vhostid(apr_pool_t *p, server_rec *s)
44 char *id;
45 SSLSrvConfigRec *sc;
46 char *host;
47 apr_port_t port;
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;
59 id = apr_psprintf(p, "%s:%lu", host, (unsigned long)port);
60 return id;
63 apr_file_t *ssl_util_ppopen(server_rec *s, apr_pool_t *p, const char *cmd,
64 const char * const *argv)
66 apr_procattr_t *procattr;
67 apr_proc_t *proc;
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 if ((proc = (apr_proc_t *)apr_pcalloc(p, sizeof(apr_proc_t))) == NULL)
80 return NULL;
81 if (apr_proc_create(proc, cmd, argv, NULL, procattr, p) != APR_SUCCESS)
82 return NULL;
83 return proc->out;
86 void ssl_util_ppclose(server_rec *s, apr_pool_t *p, apr_file_t *fp)
88 apr_file_close(fp);
89 return;
93 * Run a filter program and read the first line of its stdout output
95 char *ssl_util_readfilter(server_rec *s, apr_pool_t *p, const char *cmd,
96 const char * const *argv)
98 static char buf[MAX_STRING_LEN];
99 apr_file_t *fp;
100 apr_size_t nbytes = 1;
101 char c;
102 int k;
104 if ((fp = ssl_util_ppopen(s, p, cmd, argv)) == NULL)
105 return NULL;
106 /* XXX: we are reading 1 byte at a time here */
107 for (k = 0; apr_file_read(fp, &c, &nbytes) == APR_SUCCESS
108 && nbytes == 1 && (k < MAX_STRING_LEN-1) ; ) {
109 if (c == '\n' || c == '\r')
110 break;
111 buf[k++] = c;
113 buf[k] = NUL;
114 ssl_util_ppclose(s, p, fp);
116 return buf;
119 BOOL ssl_util_path_check(ssl_pathcheck_t pcm, const char *path, apr_pool_t *p)
121 apr_finfo_t finfo;
123 if (path == NULL)
124 return FALSE;
125 if (pcm & SSL_PCM_EXISTS && apr_stat(&finfo, path,
126 APR_FINFO_TYPE|APR_FINFO_SIZE, p) != 0)
127 return FALSE;
128 if (pcm & SSL_PCM_ISREG && finfo.filetype != APR_REG)
129 return FALSE;
130 if (pcm & SSL_PCM_ISDIR && finfo.filetype != APR_DIR)
131 return FALSE;
132 if (pcm & SSL_PCM_ISNONZERO && finfo.size <= 0)
133 return FALSE;
134 return TRUE;
137 ssl_algo_t ssl_util_algotypeof(X509 *pCert, EVP_PKEY *pKey)
139 ssl_algo_t t;
140 EVP_PKEY *pFreeKey = NULL;
142 t = SSL_ALGO_UNKNOWN;
143 if (pCert != NULL)
144 pFreeKey = pKey = X509_get_pubkey(pCert);
145 if (pKey != NULL) {
146 switch (EVP_PKEY_key_type(pKey)) {
147 case EVP_PKEY_RSA:
148 t = SSL_ALGO_RSA;
149 break;
150 case EVP_PKEY_DSA:
151 t = SSL_ALGO_DSA;
152 break;
153 default:
154 break;
157 #ifdef OPENSSL_VERSION_NUMBER
158 /* Only refcounted in OpenSSL */
159 if (pFreeKey != NULL)
160 EVP_PKEY_free(pFreeKey);
161 #endif
162 return t;
165 char *ssl_util_algotypestr(ssl_algo_t t)
167 char *cp;
169 cp = "UNKNOWN";
170 switch (t) {
171 case SSL_ALGO_RSA:
172 cp = "RSA";
173 break;
174 case SSL_ALGO_DSA:
175 cp = "DSA";
176 break;
177 default:
178 break;
180 return cp;
184 * certain key and cert data needs to survive restarts,
185 * which are stored in the user data table of s->process->pool.
186 * to prevent "leaking" of this data, we use malloc/free
187 * rather than apr_palloc and these wrappers to help make sure
188 * we do not leak the malloc-ed data.
190 unsigned char *ssl_asn1_table_set(apr_hash_t *table,
191 const char *key,
192 long int length)
194 apr_ssize_t klen = strlen(key);
195 ssl_asn1_t *asn1 = apr_hash_get(table, key, klen);
198 * if a value for this key already exists,
199 * reuse as much of the already malloc-ed data
200 * as possible.
202 if (asn1) {
203 if (asn1->nData != length) {
204 free(asn1->cpData); /* XXX: realloc? */
205 asn1->cpData = NULL;
208 else {
209 asn1 = malloc(sizeof(*asn1));
210 asn1->source_mtime = 0; /* used as a note for encrypted private keys */
211 asn1->cpData = NULL;
214 asn1->nData = length;
215 if (!asn1->cpData) {
216 asn1->cpData = malloc(length);
219 apr_hash_set(table, key, klen, asn1);
221 return asn1->cpData; /* caller will assign a value to this */
224 ssl_asn1_t *ssl_asn1_table_get(apr_hash_t *table,
225 const char *key)
227 return (ssl_asn1_t *)apr_hash_get(table, key, APR_HASH_KEY_STRING);
230 void ssl_asn1_table_unset(apr_hash_t *table,
231 const char *key)
233 apr_ssize_t klen = strlen(key);
234 ssl_asn1_t *asn1 = apr_hash_get(table, key, klen);
236 if (!asn1) {
237 return;
240 if (asn1->cpData) {
241 free(asn1->cpData);
243 free(asn1);
245 apr_hash_set(table, key, klen, NULL);
248 static const char *ssl_asn1_key_types[] = {"RSA", "DSA"};
250 const char *ssl_asn1_keystr(int keytype)
252 if (keytype >= SSL_AIDX_MAX) {
253 return NULL;
256 return ssl_asn1_key_types[keytype];
259 const char *ssl_asn1_table_keyfmt(apr_pool_t *p,
260 const char *id,
261 int keytype)
263 const char *keystr = ssl_asn1_keystr(keytype);
265 return apr_pstrcat(p, id, ":", keystr, NULL);
268 STACK_OF(X509) *ssl_read_pkcs7(server_rec *s, const char *pkcs7)
270 PKCS7 *p7;
271 STACK_OF(X509) *certs = NULL;
272 FILE *f;
274 f = fopen(pkcs7, "r");
275 if (!f) {
276 ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "Can't open %s", pkcs7);
277 ssl_die();
280 p7 = PEM_read_PKCS7(f, NULL, NULL, NULL);
281 if (!p7) {
282 ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, s,
283 "Can't read PKCS7 object %s", pkcs7);
284 ssl_log_ssl_error(APLOG_MARK, APLOG_CRIT, s);
285 exit(1);
288 switch (OBJ_obj2nid(p7->type)) {
289 case NID_pkcs7_signed:
290 certs = p7->d.sign->cert;
291 break;
293 case NID_pkcs7_signedAndEnveloped:
294 certs = p7->d.signed_and_enveloped->cert;
295 break;
297 default:
298 ap_log_error(APLOG_MARK, APLOG_CRIT|APLOG_NOERRNO, 0, s,
299 "Don't understand PKCS7 file %s", pkcs7);
300 ssl_die();
303 if (!certs) {
304 ap_log_error(APLOG_MARK, APLOG_CRIT|APLOG_NOERRNO, 0, s,
305 "No certificates in %s", pkcs7);
306 ssl_die();
309 fclose(f);
311 return certs;
315 #if APR_HAS_THREADS
317 * To ensure thread-safetyness in OpenSSL - work in progress
320 static apr_thread_mutex_t **lock_cs;
321 static int lock_num_locks;
323 #ifdef HAVE_SSLC
324 #if SSLC_VERSION_NUMBER >= 0x2000
325 static int ssl_util_thr_lock(int mode, int type,
326 char *file, int line)
327 #else
328 static void ssl_util_thr_lock(int mode, int type,
329 char *file, int line)
330 #endif
331 #else
332 static void ssl_util_thr_lock(int mode, int type,
333 const char *file, int line)
334 #endif
336 if (type < lock_num_locks) {
337 if (mode & CRYPTO_LOCK) {
338 apr_thread_mutex_lock(lock_cs[type]);
340 else {
341 apr_thread_mutex_unlock(lock_cs[type]);
343 #ifdef HAVE_SSLC
344 #if SSLC_VERSION_NUMBER >= 0x2000
345 return 1;
347 else {
348 return -1;
349 #endif
350 #endif
354 /* Dynamic lock structure */
355 struct CRYPTO_dynlock_value {
356 apr_pool_t *pool;
357 const char* file;
358 int line;
359 apr_thread_mutex_t *mutex;
362 /* Global reference to the pool passed into ssl_util_thread_setup() */
363 apr_pool_t *dynlockpool = NULL;
366 * Dynamic lock creation callback
368 static struct CRYPTO_dynlock_value *ssl_dyn_create_function(const char *file,
369 int line)
371 struct CRYPTO_dynlock_value *value;
372 apr_pool_t *p;
373 apr_status_t rv;
376 * We need a pool to allocate our mutex. Since we can't clear
377 * allocated memory from a pool, create a subpool that we can blow
378 * away in the destruction callback.
380 rv = apr_pool_create(&p, dynlockpool);
381 if (rv != APR_SUCCESS) {
382 ap_log_perror(file, line, APLOG_ERR, rv, dynlockpool,
383 "Failed to create subpool for dynamic lock");
384 return NULL;
387 ap_log_perror(file, line, APLOG_DEBUG, 0, p,
388 "Creating dynamic lock");
390 value = (struct CRYPTO_dynlock_value *)apr_palloc(p,
391 sizeof(struct CRYPTO_dynlock_value));
392 if (!value) {
393 ap_log_perror(file, line, APLOG_ERR, 0, p,
394 "Failed to allocate dynamic lock structure");
395 return NULL;
398 value->pool = p;
399 /* Keep our own copy of the place from which we were created,
400 using our own pool. */
401 value->file = apr_pstrdup(p, file);
402 value->line = line;
403 rv = apr_thread_mutex_create(&(value->mutex), APR_THREAD_MUTEX_DEFAULT,
405 if (rv != APR_SUCCESS) {
406 ap_log_perror(file, line, APLOG_ERR, rv, p,
407 "Failed to create thread mutex for dynamic lock");
408 apr_pool_destroy(p);
409 return NULL;
411 return value;
415 * Dynamic locking and unlocking function
418 static void ssl_dyn_lock_function(int mode, struct CRYPTO_dynlock_value *l,
419 const char *file, int line)
421 apr_status_t rv;
423 if (mode & CRYPTO_LOCK) {
424 ap_log_perror(file, line, APLOG_DEBUG, 0, l->pool,
425 "Acquiring mutex %s:%d", l->file, l->line);
426 rv = apr_thread_mutex_lock(l->mutex);
427 ap_log_perror(file, line, APLOG_DEBUG, rv, l->pool,
428 "Mutex %s:%d acquired!", l->file, l->line);
430 else {
431 ap_log_perror(file, line, APLOG_DEBUG, 0, l->pool,
432 "Releasing mutex %s:%d", l->file, l->line);
433 rv = apr_thread_mutex_unlock(l->mutex);
434 ap_log_perror(file, line, APLOG_DEBUG, rv, l->pool,
435 "Mutex %s:%d released!", l->file, l->line);
440 * Dynamic lock destruction callback
442 static void ssl_dyn_destroy_function(struct CRYPTO_dynlock_value *l,
443 const char *file, int line)
445 apr_status_t rv;
447 ap_log_perror(file, line, APLOG_DEBUG, 0, l->pool,
448 "Destroying dynamic lock %s:%d", l->file, l->line);
449 rv = apr_thread_mutex_destroy(l->mutex);
450 if (rv != APR_SUCCESS) {
451 ap_log_perror(file, line, APLOG_ERR, rv, l->pool,
452 "Failed to destroy mutex for dynamic lock %s:%d",
453 l->file, l->line);
456 /* Trust that whomever owned the CRYPTO_dynlock_value we were
457 * passed has no future use for it...
459 apr_pool_destroy(l->pool);
462 static unsigned long ssl_util_thr_id(void)
464 /* OpenSSL needs this to return an unsigned long. On OS/390, the pthread
465 * id is a structure twice that big. Use the TCB pointer instead as a
466 * unique unsigned long.
468 #ifdef __MVS__
469 struct PSA {
470 char unmapped[540];
471 unsigned long PSATOLD;
472 } *psaptr = 0;
474 return psaptr->PSATOLD;
475 #else
476 return (unsigned long) apr_os_thread_current();
477 #endif
480 static apr_status_t ssl_util_thread_cleanup(void *data)
482 CRYPTO_set_locking_callback(NULL);
483 CRYPTO_set_id_callback(NULL);
485 CRYPTO_set_dynlock_create_callback(NULL);
486 CRYPTO_set_dynlock_lock_callback(NULL);
487 CRYPTO_set_dynlock_destroy_callback(NULL);
489 dynlockpool = NULL;
491 /* Let the registered mutex cleanups do their own thing
493 return APR_SUCCESS;
496 void ssl_util_thread_setup(apr_pool_t *p)
498 int i;
500 lock_num_locks = CRYPTO_num_locks();
501 lock_cs = apr_palloc(p, lock_num_locks * sizeof(*lock_cs));
503 for (i = 0; i < lock_num_locks; i++) {
504 apr_thread_mutex_create(&(lock_cs[i]), APR_THREAD_MUTEX_DEFAULT, p);
507 CRYPTO_set_id_callback(ssl_util_thr_id);
509 CRYPTO_set_locking_callback(ssl_util_thr_lock);
511 /* Set up dynamic locking scaffolding for OpenSSL to use at its
512 * convenience.
514 dynlockpool = p;
515 CRYPTO_set_dynlock_create_callback(ssl_dyn_create_function);
516 CRYPTO_set_dynlock_lock_callback(ssl_dyn_lock_function);
517 CRYPTO_set_dynlock_destroy_callback(ssl_dyn_destroy_function);
519 apr_pool_cleanup_register(p, NULL, ssl_util_thread_cleanup,
520 apr_pool_cleanup_null);
522 #endif