bottleneck testcase based on rubbos
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / modules / ssl / ssl_util.c
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 "mod_ssl.h"
33 #include "ap_mpm.h"
34 #include "apr_thread_mutex.h"
35
36 /*  _________________________________________________________________
37 **
38 **  Utility Functions
39 **  _________________________________________________________________
40 */
41
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)
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
63 void ssl_util_strupper(char *s)
64 {
65     for (; *s; ++s)
66         *s = apr_toupper(*s);
67     return;
68 }
69
70 static const char ssl_util_uuencode_six2pr[64+1] =
71     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
72
73 void ssl_util_uuencode(char *szTo, const char *szFrom, BOOL bPad)
74 {
75     ssl_util_uuencode_binary((unsigned char *)szTo,
76                              (const unsigned char *)szFrom,
77                              strlen(szFrom), bPad);
78 }
79
80 void ssl_util_uuencode_binary(unsigned char *szTo,
81                               const unsigned char *szFrom,
82                               int nLength, BOOL bPad)
83 {
84     const unsigned char *s;
85     int nPad = 0;
86
87     for (s = szFrom; nLength > 0; s += 3) {
88         *szTo++ = ssl_util_uuencode_six2pr[s[0] >> 2];
89         *szTo++ = ssl_util_uuencode_six2pr[(s[0] << 4 | s[1] >> 4) & 0x3f];
90         if (--nLength == 0) {
91             nPad = 2;
92             break;
93         }
94         *szTo++ = ssl_util_uuencode_six2pr[(s[1] << 2 | s[2] >> 6) & 0x3f];
95         if (--nLength == 0) {
96             nPad = 1;
97             break;
98         }
99         *szTo++ = ssl_util_uuencode_six2pr[s[2] & 0x3f];
100         --nLength;
101     }
102     while(bPad && nPad--) {
103         *szTo++ = NUL;
104     }
105     *szTo = NUL;
106     return;
107 }
108
109 apr_file_t *ssl_util_ppopen(server_rec *s, apr_pool_t *p, const char *cmd,
110                             const char * const *argv)
111 {
112     apr_procattr_t *procattr;
113     apr_proc_t *proc;
114
115     if (apr_procattr_create(&procattr, p) != APR_SUCCESS) 
116         return NULL;
117     if (apr_procattr_io_set(procattr, APR_FULL_BLOCK, APR_FULL_BLOCK, 
118                             APR_FULL_BLOCK) != APR_SUCCESS)
119         return NULL;
120     if (apr_procattr_dir_set(procattr, 
121                              ap_make_dirstr_parent(p, cmd)) != APR_SUCCESS)
122         return NULL;
123     if (apr_procattr_cmdtype_set(procattr, APR_PROGRAM) != APR_SUCCESS)
124         return NULL;
125     if ((proc = (apr_proc_t *)apr_pcalloc(p, sizeof(apr_proc_t))) == NULL)
126         return NULL;
127     if (apr_proc_create(proc, cmd, argv, NULL, procattr, p) != APR_SUCCESS)
128         return NULL;
129     return proc->out;
130 }
131
132 void ssl_util_ppclose(server_rec *s, apr_pool_t *p, apr_file_t *fp)
133 {
134     apr_file_close(fp);
135     return;
136 }
137
138 /*
139  * Run a filter program and read the first line of its stdout output
140  */
141 char *ssl_util_readfilter(server_rec *s, apr_pool_t *p, const char *cmd,
142                           const char * const *argv)
143 {
144     static char buf[MAX_STRING_LEN];
145     apr_file_t *fp;
146     apr_size_t nbytes = 1;
147     char c;
148     int k;
149
150     if ((fp = ssl_util_ppopen(s, p, cmd, argv)) == NULL)
151         return NULL;
152     /* XXX: we are reading 1 byte at a time here */
153     for (k = 0; apr_file_read(fp, &c, &nbytes) == APR_SUCCESS
154                 && nbytes == 1 && (k < MAX_STRING_LEN-1)     ; ) {
155         if (c == '\n' || c == '\r')
156             break;
157         buf[k++] = c;
158     }
159     buf[k] = NUL;
160     ssl_util_ppclose(s, p, fp);
161
162     return buf;
163 }
164
165 BOOL ssl_util_path_check(ssl_pathcheck_t pcm, const char *path, apr_pool_t *p)
166 {
167     apr_finfo_t finfo;
168
169     if (path == NULL)
170         return FALSE;
171     if (pcm & SSL_PCM_EXISTS && apr_stat(&finfo, path, 
172                                 APR_FINFO_TYPE|APR_FINFO_SIZE, p) != 0)
173         return FALSE;
174     if (pcm & SSL_PCM_ISREG && finfo.filetype != APR_REG)
175         return FALSE;
176     if (pcm & SSL_PCM_ISDIR && finfo.filetype != APR_DIR)
177         return FALSE;
178     if (pcm & SSL_PCM_ISNONZERO && finfo.size <= 0)
179         return FALSE;
180     return TRUE;
181 }
182
183 ssl_algo_t ssl_util_algotypeof(X509 *pCert, EVP_PKEY *pKey) 
184 {
185     ssl_algo_t t;
186             
187     t = SSL_ALGO_UNKNOWN;
188     if (pCert != NULL)
189         pKey = X509_get_pubkey(pCert);
190     if (pKey != NULL) {
191         switch (EVP_PKEY_key_type(pKey)) {
192             case EVP_PKEY_RSA: 
193                 t = SSL_ALGO_RSA;
194                 break;
195             case EVP_PKEY_DSA: 
196                 t = SSL_ALGO_DSA;
197                 break;
198             default:
199                 break;
200         }
201     }
202     return t;
203 }
204
205 char *ssl_util_algotypestr(ssl_algo_t t) 
206 {
207     char *cp;
208
209     cp = "UNKNOWN";
210     switch (t) {
211         case SSL_ALGO_RSA: 
212             cp = "RSA";
213             break;
214         case SSL_ALGO_DSA: 
215             cp = "DSA";
216             break;
217         default:
218             break;
219     }
220     return cp;
221 }
222
223 char *ssl_util_ptxtsub(apr_pool_t *p, const char *cpLine,
224                        const char *cpMatch, char *cpSubst)
225 {
226 #define MAX_PTXTSUB 100
227     char *cppMatch[MAX_PTXTSUB];
228     char *cpResult;
229     int nResult;
230     int nLine;
231     int nSubst;
232     int nMatch;
233     char *cpI;
234     char *cpO;
235     char *cp;
236     int i;
237
238     /*
239      * Pass 1: find substitution locations and calculate sizes
240      */
241     nLine  = strlen(cpLine);
242     nMatch = strlen(cpMatch);
243     nSubst = strlen(cpSubst);
244     for (cpI = (char *)cpLine, i = 0, nResult = 0;
245          cpI < cpLine+nLine && i < MAX_PTXTSUB;    ) {
246         if ((cp = strstr(cpI, cpMatch)) != NULL) {
247             cppMatch[i++] = cp;
248             nResult += ((cp-cpI)+nSubst);
249             cpI = (cp+nMatch);
250         }
251         else {
252             nResult += strlen(cpI);
253             break;
254         }
255     }
256     cppMatch[i] = NULL;
257     if (i == 0)
258         return NULL;
259
260     /*
261      * Pass 2: allocate memory and assemble result
262      */
263     cpResult = apr_pcalloc(p, nResult+1);
264     for (cpI = (char *)cpLine, cpO = cpResult, i = 0;
265          cppMatch[i] != NULL;
266          i++) {
267         apr_cpystrn(cpO, cpI, cppMatch[i]-cpI+1);
268         cpO += (cppMatch[i]-cpI);
269         apr_cpystrn(cpO, cpSubst, nSubst+1);
270         cpO += nSubst;
271         cpI = (cppMatch[i]+nMatch);
272     }
273     apr_cpystrn(cpO, cpI, cpResult+nResult-cpO+1);
274
275     return cpResult;
276 }
277
278 /*
279  * certain key and cert data needs to survive restarts,
280  * which are stored in the user data table of s->process->pool.
281  * to prevent "leaking" of this data, we use malloc/free
282  * rather than apr_palloc and these wrappers to help make sure
283  * we do not leak the malloc-ed data.
284  */
285 unsigned char *ssl_asn1_table_set(apr_hash_t *table,
286                                   const char *key,
287                                   long int length)
288 {
289     apr_ssize_t klen = strlen(key);
290     ssl_asn1_t *asn1 = apr_hash_get(table, key, klen);
291
292     /*
293      * if a value for this key already exists,
294      * reuse as much of the already malloc-ed data
295      * as possible.
296      */
297     if (asn1) {
298         if (asn1->nData != length) {
299             free(asn1->cpData); /* XXX: realloc? */
300             asn1->cpData = NULL;
301         }
302     }
303     else {
304         asn1 = malloc(sizeof(*asn1));
305         asn1->source_mtime = 0; /* used as a note for encrypted private keys */
306         asn1->cpData = NULL;
307     }
308
309     asn1->nData = length;
310     if (!asn1->cpData) {
311         asn1->cpData = malloc(length);
312     }
313
314     apr_hash_set(table, key, klen, asn1);
315
316     return asn1->cpData; /* caller will assign a value to this */
317 }
318
319 ssl_asn1_t *ssl_asn1_table_get(apr_hash_t *table,
320                                const char *key)
321 {
322     return (ssl_asn1_t *)apr_hash_get(table, key, APR_HASH_KEY_STRING);
323 }
324
325 void ssl_asn1_table_unset(apr_hash_t *table,
326                           const char *key)
327 {
328     apr_ssize_t klen = strlen(key);
329     ssl_asn1_t *asn1 = apr_hash_get(table, key, klen);
330
331     if (!asn1) {
332         return;
333     }
334
335     if (asn1->cpData) {
336         free(asn1->cpData);
337     }
338     free(asn1);
339
340     apr_hash_set(table, key, klen, NULL);
341 }
342
343 static const char *ssl_asn1_key_types[] = {"RSA", "DSA"};
344
345 const char *ssl_asn1_keystr(int keytype)
346 {
347     if (keytype >= SSL_AIDX_MAX) {
348         return NULL;
349     }
350
351     return ssl_asn1_key_types[keytype];
352 }
353
354 const char *ssl_asn1_table_keyfmt(apr_pool_t *p,
355                                   const char *id,
356                                   int keytype)
357 {
358     const char *keystr = ssl_asn1_keystr(keytype);
359
360     return apr_pstrcat(p, id, ":", keystr, NULL);
361 }
362
363
364 #if APR_HAS_THREADS
365 /*
366  * To ensure thread-safetyness in OpenSSL - work in progress
367  */
368
369 static apr_thread_mutex_t **lock_cs;
370 static int                  lock_num_locks;
371
372 #ifdef SSLC_VERSION_NUMBER
373 #if SSLC_VERSION_NUMBER >= 0x2000
374 static int ssl_util_thr_lock(int mode, int type,
375                               const char *file, int line)
376 #else
377 static void ssl_util_thr_lock(int mode, int type,
378                               const char *file, int line)
379 #endif
380 #else
381 static void ssl_util_thr_lock(int mode, int type,
382                               const char *file, int line)
383 #endif
384 {
385     if (type < lock_num_locks) {
386         if (mode & CRYPTO_LOCK) {
387             apr_thread_mutex_lock(lock_cs[type]);
388         }
389         else {
390             apr_thread_mutex_unlock(lock_cs[type]);
391         }
392 #ifdef SSLC_VERSION_NUMBER
393 #if SSLC_VERSION_NUMBER >= 0x2000
394         return 1;
395     }
396     else {
397         return -1;
398 #endif
399 #endif
400     }
401 }
402
403 static unsigned long ssl_util_thr_id(void)
404 {
405     /* OpenSSL needs this to return an unsigned long.  On OS/390, the pthread 
406      * id is a structure twice that big.  Use the TCB pointer instead as a 
407      * unique unsigned long.
408      */
409 #ifdef __MVS__
410     struct PSA {
411         char unmapped[540];
412         unsigned long PSATOLD;
413     } *psaptr = 0;
414
415     return psaptr->PSATOLD;
416 #else
417     return (unsigned long) apr_os_thread_current();
418 #endif
419 }
420
421 static apr_status_t ssl_util_thread_cleanup(void *data)
422 {
423     CRYPTO_set_locking_callback(NULL);
424     CRYPTO_set_id_callback(NULL);
425
426     /* Let the registered mutex cleanups do their own thing 
427      */
428     return APR_SUCCESS;
429 }
430
431 void ssl_util_thread_setup(apr_pool_t *p)
432 {
433     int i;
434
435     lock_num_locks = CRYPTO_num_locks();
436     lock_cs = apr_palloc(p, lock_num_locks * sizeof(*lock_cs));
437
438     for (i = 0; i < lock_num_locks; i++) {
439         apr_thread_mutex_create(&(lock_cs[i]), APR_THREAD_MUTEX_DEFAULT, p);
440     }
441
442     CRYPTO_set_id_callback(ssl_util_thr_id);
443
444     CRYPTO_set_locking_callback(ssl_util_thr_lock);
445
446     apr_pool_cleanup_register(p, NULL, ssl_util_thread_cleanup,
447                                        apr_pool_cleanup_null);
448 }
449 #endif