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 42char *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 63apr_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 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; 84} 85 86void ssl_util_ppclose(server_rec *s, apr_pool_t *p, apr_file_t *fp) 87{ 88 apr_file_close(fp); 89 return; 90} 91 92/* 93 * Run a filter program and read the first line of its stdout output 94 */ 95char *ssl_util_readfilter(server_rec *s, apr_pool_t *p, const char *cmd, 96 const char * const *argv) 97{ 98 static char buf[MAX_STRING_LEN]; 99 apr_file_t *fp; 100 apr_size_t nbytes = 1; 101 char c; 102 int k; 103 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; 112 } 113 buf[k] = NUL; 114 ssl_util_ppclose(s, p, fp); 115 116 return buf; 117} 118 119BOOL ssl_util_path_check(ssl_pathcheck_t pcm, const char *path, apr_pool_t *p) 120{ 121 apr_finfo_t finfo; 122 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; 135} 136 137ssl_algo_t ssl_util_algotypeof(X509 *pCert, EVP_PKEY *pKey) 138{ 139 ssl_algo_t t; 140 EVP_PKEY *pFreeKey = NULL; 141 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#ifndef OPENSSL_NO_EC 154 case EVP_PKEY_EC: 155 t = SSL_ALGO_ECC; 156 break; 157#endif 158 default: 159 break; 160 } 161 } 162#ifdef OPENSSL_VERSION_NUMBER 163 /* Only refcounted in OpenSSL */ 164 if (pFreeKey != NULL) 165 EVP_PKEY_free(pFreeKey); 166#endif 167 return t; 168} 169 170char *ssl_util_algotypestr(ssl_algo_t t) 171{ 172 char *cp; 173 174 cp = "UNKNOWN"; 175 switch (t) { 176 case SSL_ALGO_RSA: 177 cp = "RSA"; 178 break; 179 case SSL_ALGO_DSA: 180 cp = "DSA"; 181 break; 182#ifndef OPENSSL_NO_EC 183 case SSL_ALGO_ECC: 184 cp = "ECC"; 185 break; 186#endif 187 default: 188 break; 189 } 190 return cp; 191} 192 193/* 194 * certain key and cert data needs to survive restarts, 195 * which are stored in the user data table of s->process->pool. 196 * to prevent "leaking" of this data, we use malloc/free 197 * rather than apr_palloc and these wrappers to help make sure 198 * we do not leak the malloc-ed data. 199 */ 200unsigned char *ssl_asn1_table_set(apr_hash_t *table, 201 const char *key, 202 long int length) 203{ 204 apr_ssize_t klen = strlen(key); 205 ssl_asn1_t *asn1 = apr_hash_get(table, key, klen); 206 207 /* 208 * if a value for this key already exists, 209 * reuse as much of the already malloc-ed data 210 * as possible. 211 */ 212 if (asn1) { 213 if (asn1->nData != length) { 214 free(asn1->cpData); /* XXX: realloc? */ 215 asn1->cpData = NULL; 216 } 217 } 218 else { 219 asn1 = malloc(sizeof(*asn1)); 220 asn1->source_mtime = 0; /* used as a note for encrypted private keys */ 221 asn1->cpData = NULL; 222 } 223 224 asn1->nData = length; 225 if (!asn1->cpData) { 226 asn1->cpData = malloc(length); 227 } 228 229 apr_hash_set(table, key, klen, asn1); 230 231 return asn1->cpData; /* caller will assign a value to this */ 232} 233 234ssl_asn1_t *ssl_asn1_table_get(apr_hash_t *table, 235 const char *key) 236{ 237 return (ssl_asn1_t *)apr_hash_get(table, key, APR_HASH_KEY_STRING); 238} 239 240void ssl_asn1_table_unset(apr_hash_t *table, 241 const char *key) 242{ 243 apr_ssize_t klen = strlen(key); 244 ssl_asn1_t *asn1 = apr_hash_get(table, key, klen); 245 246 if (!asn1) { 247 return; 248 } 249 250 if (asn1->cpData) { 251 free(asn1->cpData); 252 } 253 free(asn1); 254 255 apr_hash_set(table, key, klen, NULL); 256} 257 258#ifndef OPENSSL_NO_EC 259static const char *ssl_asn1_key_types[] = {"RSA", "DSA", "ECC"}; 260#else 261static const char *ssl_asn1_key_types[] = {"RSA", "DSA"}; 262#endif 263 264const char *ssl_asn1_keystr(int keytype) 265{ 266 if (keytype >= SSL_AIDX_MAX) { 267 return NULL; 268 } 269 270 return ssl_asn1_key_types[keytype]; 271} 272 273const char *ssl_asn1_table_keyfmt(apr_pool_t *p, 274 const char *id, 275 int keytype) 276{ 277 const char *keystr = ssl_asn1_keystr(keytype); 278 279 return apr_pstrcat(p, id, ":", keystr, NULL); 280} 281 282 283#if APR_HAS_THREADS 284/* 285 * To ensure thread-safetyness in OpenSSL - work in progress 286 */ 287 288static apr_thread_mutex_t **lock_cs; 289static int lock_num_locks; 290 291#ifdef HAVE_SSLC 292#if SSLC_VERSION_NUMBER >= 0x2000 293static int ssl_util_thr_lock(int mode, int type, 294 char *file, int line) 295#else 296static void ssl_util_thr_lock(int mode, int type, 297 char *file, int line) 298#endif 299#else 300static void ssl_util_thr_lock(int mode, int type, 301 const char *file, int line) 302#endif 303{ 304 if (type < lock_num_locks) { 305 if (mode & CRYPTO_LOCK) { 306 apr_thread_mutex_lock(lock_cs[type]); 307 } 308 else { 309 apr_thread_mutex_unlock(lock_cs[type]); 310 } 311#ifdef HAVE_SSLC 312#if SSLC_VERSION_NUMBER >= 0x2000 313 return 1; 314 } 315 else { 316 return -1; 317#endif 318#endif 319 } 320} 321 322/* Dynamic lock structure */ 323struct CRYPTO_dynlock_value { 324 apr_pool_t *pool; 325 const char* file; 326 int line; 327 apr_thread_mutex_t *mutex; 328}; 329 330/* Global reference to the pool passed into ssl_util_thread_setup() */ 331apr_pool_t *dynlockpool = NULL; 332 333/* 334 * Dynamic lock creation callback 335 */ 336static struct CRYPTO_dynlock_value *ssl_dyn_create_function(const char *file, 337 int line) 338{ 339 struct CRYPTO_dynlock_value *value; 340 apr_pool_t *p; 341 apr_status_t rv; 342 343 /* 344 * We need a pool to allocate our mutex. Since we can't clear 345 * allocated memory from a pool, create a subpool that we can blow 346 * away in the destruction callback. 347 */ 348 rv = apr_pool_create(&p, dynlockpool); 349 if (rv != APR_SUCCESS) { 350 ap_log_perror(file, line, APLOG_ERR, rv, dynlockpool, 351 "Failed to create subpool for dynamic lock"); 352 return NULL; 353 } 354 355 ap_log_perror(file, line, APLOG_DEBUG, 0, p, 356 "Creating dynamic lock"); 357 358 value = (struct CRYPTO_dynlock_value *)apr_palloc(p, 359 sizeof(struct CRYPTO_dynlock_value)); 360 if (!value) { 361 ap_log_perror(file, line, APLOG_ERR, 0, p, 362 "Failed to allocate dynamic lock structure"); 363 return NULL; 364 } 365 366 value->pool = p; 367 /* Keep our own copy of the place from which we were created, 368 using our own pool. */ 369 value->file = apr_pstrdup(p, file); 370 value->line = line; 371 rv = apr_thread_mutex_create(&(value->mutex), APR_THREAD_MUTEX_DEFAULT, 372 p); 373 if (rv != APR_SUCCESS) { 374 ap_log_perror(file, line, APLOG_ERR, rv, p, 375 "Failed to create thread mutex for dynamic lock"); 376 apr_pool_destroy(p); 377 return NULL; 378 } 379 return value; 380} 381 382/* 383 * Dynamic locking and unlocking function 384 */ 385 386static void ssl_dyn_lock_function(int mode, struct CRYPTO_dynlock_value *l, 387 const char *file, int line) 388{ 389 apr_status_t rv; 390 391 if (mode & CRYPTO_LOCK) { 392 ap_log_perror(file, line, APLOG_DEBUG, 0, l->pool, 393 "Acquiring mutex %s:%d", l->file, l->line); 394 rv = apr_thread_mutex_lock(l->mutex); 395 ap_log_perror(file, line, APLOG_DEBUG, rv, l->pool, 396 "Mutex %s:%d acquired!", l->file, l->line); 397 } 398 else { 399 ap_log_perror(file, line, APLOG_DEBUG, 0, l->pool, 400 "Releasing mutex %s:%d", l->file, l->line); 401 rv = apr_thread_mutex_unlock(l->mutex); 402 ap_log_perror(file, line, APLOG_DEBUG, rv, l->pool, 403 "Mutex %s:%d released!", l->file, l->line); 404 } 405} 406 407/* 408 * Dynamic lock destruction callback 409 */ 410static void ssl_dyn_destroy_function(struct CRYPTO_dynlock_value *l, 411 const char *file, int line) 412{ 413 apr_status_t rv; 414 415 ap_log_perror(file, line, APLOG_DEBUG, 0, l->pool, 416 "Destroying dynamic lock %s:%d", l->file, l->line); 417 rv = apr_thread_mutex_destroy(l->mutex); 418 if (rv != APR_SUCCESS) { 419 ap_log_perror(file, line, APLOG_ERR, rv, l->pool, 420 "Failed to destroy mutex for dynamic lock %s:%d", 421 l->file, l->line); 422 } 423 424 /* Trust that whomever owned the CRYPTO_dynlock_value we were 425 * passed has no future use for it... 426 */ 427 apr_pool_destroy(l->pool); 428} 429 430static unsigned long ssl_util_thr_id(void) 431{ 432 /* OpenSSL needs this to return an unsigned long. On OS/390, the pthread 433 * id is a structure twice that big. Use the TCB pointer instead as a 434 * unique unsigned long. 435 */ 436#ifdef __MVS__ 437 struct PSA { 438 char unmapped[540]; 439 unsigned long PSATOLD; 440 } *psaptr = 0; 441 442 return psaptr->PSATOLD; 443#else 444 return (unsigned long) apr_os_thread_current(); 445#endif 446} 447 448static apr_status_t ssl_util_thread_cleanup(void *data) 449{ 450 CRYPTO_set_locking_callback(NULL); 451 CRYPTO_set_id_callback(NULL); 452 453 CRYPTO_set_dynlock_create_callback(NULL); 454 CRYPTO_set_dynlock_lock_callback(NULL); 455 CRYPTO_set_dynlock_destroy_callback(NULL); 456 457 dynlockpool = NULL; 458 459 /* Let the registered mutex cleanups do their own thing 460 */ 461 return APR_SUCCESS; 462} 463 464void ssl_util_thread_setup(apr_pool_t *p) 465{ 466 int i; 467 468 lock_num_locks = CRYPTO_num_locks(); 469 lock_cs = apr_palloc(p, lock_num_locks * sizeof(*lock_cs)); 470 471 for (i = 0; i < lock_num_locks; i++) { 472 apr_thread_mutex_create(&(lock_cs[i]), APR_THREAD_MUTEX_DEFAULT, p); 473 } 474 475 CRYPTO_set_id_callback(ssl_util_thr_id); 476 477 CRYPTO_set_locking_callback(ssl_util_thr_lock); 478 479 /* Set up dynamic locking scaffolding for OpenSSL to use at its 480 * convenience. 481 */ 482 dynlockpool = p; 483 CRYPTO_set_dynlock_create_callback(ssl_dyn_create_function); 484 CRYPTO_set_dynlock_lock_callback(ssl_dyn_lock_function); 485 CRYPTO_set_dynlock_destroy_callback(ssl_dyn_destroy_function); 486 487 apr_pool_cleanup_register(p, NULL, ssl_util_thread_cleanup, 488 apr_pool_cleanup_null); 489} 490#endif 491