]> granicus.if.org Git - apache/blob - modules/ssl/ssl_engine_vars.c
Change mostly all old module structure hooks and EAPI hooks to
[apache] / modules / ssl / ssl_engine_vars.c
1 /*                      _             _
2 **  _ __ ___   ___   __| |    ___ ___| |  mod_ssl
3 ** | '_ ` _ \ / _ \ / _` |   / __/ __| |  Apache Interface to OpenSSL
4 ** | | | | | | (_) | (_| |   \__ \__ \ |  www.modssl.org
5 ** |_| |_| |_|\___/ \__,_|___|___/___/_|  ftp.modssl.org
6 **                      |_____|
7 **  ssl_engine_vars.c
8 **  Variable Lookup Facility
9 */
10
11 /* ====================================================================
12  * The Apache Software License, Version 1.1
13  *
14  * Copyright (c) 2000-2001 The Apache Software Foundation.  All rights
15  * reserved.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions
19  * are met:
20  *
21  * 1. Redistributions of source code must retain the above copyright
22  *    notice, this list of conditions and the following disclaimer.
23  *
24  * 2. Redistributions in binary form must reproduce the above copyright
25  *    notice, this list of conditions and the following disclaimer in
26  *    the documentation and/or other materials provided with the
27  *    distribution.
28  *
29  * 3. The end-user documentation included with the redistribution,
30  *    if any, must include the following acknowledgment:
31  *       "This product includes software developed by the
32  *        Apache Software Foundation (http://www.apache.org/)."
33  *    Alternately, this acknowledgment may appear in the software itself,
34  *    if and wherever such third-party acknowledgments normally appear.
35  *
36  * 4. The names "Apache" and "Apache Software Foundation" must
37  *    not be used to endorse or promote products derived from this
38  *    software without prior written permission. For written
39  *    permission, please contact apache@apache.org.
40  *
41  * 5. Products derived from this software may not be called "Apache",
42  *    nor may "Apache" appear in their name, without prior written
43  *    permission of the Apache Software Foundation.
44  *
45  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
46  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
47  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
48  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
49  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
50  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
51  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
52  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
53  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
54  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
55  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56  * SUCH DAMAGE.
57  * ====================================================================
58  */
59                              /* ``Those of you who think they
60                                   know everything are very annoying
61                                   to those of us who do.''
62                                                   -- Unknown       */
63 #include "mod_ssl.h"
64
65 /*  _________________________________________________________________
66 **
67 **  Variable Lookup
68 **  _________________________________________________________________
69 */
70
71 #if 0 /* XXX */
72 static char *ssl_var_lookup_header(pool *p, request_rec *r, const char *name);
73 static char *ssl_var_lookup_ssl(pool *p, conn_rec *c, char *var);
74 static char *ssl_var_lookup_ssl_cert(pool *p, X509 *xs, char *var);
75 static char *ssl_var_lookup_ssl_cert_dn(pool *p, X509_NAME *xsname, char *var);
76 static char *ssl_var_lookup_ssl_cert_valid(pool *p, ASN1_UTCTIME *tm);
77 static char *ssl_var_lookup_ssl_cert_serial(pool *p, X509 *xs);
78 static char *ssl_var_lookup_ssl_cert_chain(pool *p, STACK_OF(X509) *sk, char *var);
79 static char *ssl_var_lookup_ssl_cert_PEM(pool *p, X509 *xs);
80 static char *ssl_var_lookup_ssl_cert_verify(pool *p, conn_rec *c);
81 static char *ssl_var_lookup_ssl_cipher(pool *p, conn_rec *c, char *var);
82 static void  ssl_var_lookup_ssl_cipher_bits(SSL *ssl, int *usekeysize, int *algkeysize);
83 static char *ssl_var_lookup_ssl_version(pool *p, char *var);
84 #endif /* XXX */
85
86 void ssl_var_register(void)
87 {
88 #if 0 /* XXX */
89     ap_hook_configure("ap::mod_ssl::var_lookup",
90                       AP_HOOK_SIG6(ptr,ptr,ptr,ptr,ptr,ptr), AP_HOOK_DECLINE(NULL));
91     ap_hook_register("ap::mod_ssl::var_lookup",
92                      ssl_var_lookup, AP_HOOK_NOCTX);
93 #endif /* XXX */
94     return;
95 }
96
97 void ssl_var_unregister(void)
98 {
99 #if 0 /* XXX */
100     ap_hook_unregister("ap::mod_ssl::var_lookup", ssl_var_lookup);
101 #endif /* XXX */
102     return;
103 }
104
105 #if 0 /* XXX */
106
107 char *ssl_var_lookup(pool *p, server_rec *s, conn_rec *c, request_rec *r, char *var)
108 {
109     SSLModConfigRec *mc = myModConfig();
110     char *result;
111     BOOL resdup;
112     time_t tc;
113     struct tm *tm;
114
115     result = NULL;
116     resdup = TRUE;
117
118     /*
119      * When no pool is given try to find one
120      */
121     if (p == NULL) {
122         if (r != NULL)
123             p = r->pool;
124         else if (c != NULL)
125             p = c->pool;
126         else
127             p = mc->pPool;
128     }
129
130     /*
131      * Request dependent stuff
132      */
133     if (r != NULL) {
134         if (strcEQ(var, "HTTP_USER_AGENT"))
135             result = ssl_var_lookup_header(p, r, "User-Agent");
136         else if (strcEQ(var, "HTTP_REFERER"))
137             result = ssl_var_lookup_header(p, r, "Referer");
138         else if (strcEQ(var, "HTTP_COOKIE"))
139             result = ssl_var_lookup_header(p, r, "Cookie");
140         else if (strcEQ(var, "HTTP_FORWARDED"))
141             result = ssl_var_lookup_header(p, r, "Forwarded");
142         else if (strcEQ(var, "HTTP_HOST"))
143             result = ssl_var_lookup_header(p, r, "Host");
144         else if (strcEQ(var, "HTTP_PROXY_CONNECTION"))
145             result = ssl_var_lookup_header(p, r, "Proxy-Connection");
146         else if (strcEQ(var, "HTTP_ACCEPT"))
147             result = ssl_var_lookup_header(p, r, "Accept");
148         else if (strlen(var) > 5 && strcEQn(var, "HTTP:", 5))
149             /* all other headers from which we are still not know about */
150             result = ssl_var_lookup_header(p, r, var+5);
151         else if (strcEQ(var, "THE_REQUEST"))
152             result = r->the_request;
153         else if (strcEQ(var, "REQUEST_METHOD"))
154             result = (char *)(r->method);
155         else if (strcEQ(var, "REQUEST_SCHEME"))
156             result = ap_http_method(r);
157         else if (strcEQ(var, "REQUEST_URI"))
158             result = r->uri;
159         else if (strcEQ(var, "SCRIPT_FILENAME") ||
160                  strcEQ(var, "REQUEST_FILENAME"))
161             result = r->filename;
162         else if (strcEQ(var, "PATH_INFO"))
163             result = r->path_info;
164         else if (strcEQ(var, "QUERY_STRING"))
165             result = r->args;
166         else if (strcEQ(var, "REMOTE_HOST"))
167             result = (char *)ap_get_remote_host(r->connection,
168                                                 r->per_dir_config, REMOTE_NAME);
169         else if (strcEQ(var, "REMOTE_IDENT"))
170             result = (char *)ap_get_remote_logname(r);
171         else if (strcEQ(var, "IS_SUBREQ"))
172             result = (r->main != NULL ? "true" : "false");
173         else if (strcEQ(var, "DOCUMENT_ROOT"))
174             result = (char *)ap_document_root(r);
175         else if (strcEQ(var, "SERVER_ADMIN"))
176             result = r->server->server_admin;
177         else if (strcEQ(var, "SERVER_NAME"))
178             result = (char *)ap_get_server_name(r);
179         else if (strcEQ(var, "SERVER_PORT"))
180             result = ap_psprintf(p, "%u", ap_get_server_port(r));
181         else if (strcEQ(var, "SERVER_PROTOCOL"))
182             result = r->protocol;
183     }
184
185     /*
186      * Connection stuff
187      */
188     if (result == NULL && c != NULL) {
189         if (strcEQ(var, "REMOTE_ADDR"))
190             result = c->remote_ip;
191         else if (strcEQ(var, "REMOTE_USER"))
192             result = c->user;
193         else if (strcEQ(var, "AUTH_TYPE"))
194             result = c->ap_auth_type;
195         else if (strlen(var) > 4 && strcEQn(var, "SSL_", 4))
196             result = ssl_var_lookup_ssl(p, c, var+4);
197         else if (strcEQ(var, "HTTPS")) {
198             if (ap_ctx_get(c->client->ctx, "ssl") != NULL)
199                 result = "on";
200             else
201                 result = "off";
202         }
203     }
204
205     /*
206      * Totally independent stuff
207      */
208     if (result == NULL) {
209         if (strlen(var) > 12 && strcEQn(var, "SSL_VERSION_", 12))
210             result = ssl_var_lookup_ssl_version(p, var+12);
211         else if (strcEQ(var, "SERVER_SOFTWARE"))
212             result = (char *)ap_get_server_version();
213         else if (strcEQ(var, "API_VERSION")) {
214             result = ap_psprintf(p, "%d", MODULE_MAGIC_NUMBER);
215             resdup = FALSE;
216         }
217         else if (strcEQ(var, "TIME_YEAR")) {
218             tc = time(NULL);
219             tm = localtime(&tc);
220             result = ap_psprintf(p, "%02d%02d",
221                                  (tm->tm_year / 100) + 19, tm->tm_year % 100);
222             resdup = FALSE;
223         }
224 #define MKTIMESTR(format, tmfield) \
225             tc = time(NULL); \
226             tm = localtime(&tc); \
227             result = ap_psprintf(p, format, tm->tmfield); \
228             resdup = FALSE;
229         else if (strcEQ(var, "TIME_MON")) {
230             MKTIMESTR("%02d", tm_mon+1)
231         }
232         else if (strcEQ(var, "TIME_DAY")) {
233             MKTIMESTR("%02d", tm_mday)
234         }
235         else if (strcEQ(var, "TIME_HOUR")) {
236             MKTIMESTR("%02d", tm_hour)
237         }
238         else if (strcEQ(var, "TIME_MIN")) {
239             MKTIMESTR("%02d", tm_min)
240         }
241         else if (strcEQ(var, "TIME_SEC")) {
242             MKTIMESTR("%02d", tm_sec)
243         }
244         else if (strcEQ(var, "TIME_WDAY")) {
245             MKTIMESTR("%d", tm_wday)
246         }
247         else if (strcEQ(var, "TIME")) {
248             tc = time(NULL);
249             tm = localtime(&tc);
250             result = ap_psprintf(p,
251                         "%02d%02d%02d%02d%02d%02d%02d", (tm->tm_year / 100) + 19,
252                         (tm->tm_year % 100), tm->tm_mon+1, tm->tm_mday,
253                         tm->tm_hour, tm->tm_min, tm->tm_sec);
254             resdup = FALSE;
255         }
256         /* all other env-variables from the parent Apache process */
257         else if (strlen(var) > 4 && strcEQn(var, "ENV:", 4)) {
258             result = (char *)ap_table_get(r->notes, var+4);
259             if (result == NULL)
260                 result = (char *)ap_table_get(r->subprocess_env, var+4);
261             if (result == NULL)
262                 result = getenv(var+4);
263         }
264     }
265
266     if (result != NULL && resdup)
267         result = ap_pstrdup(p, result);
268     if (result == NULL)
269         result = "";
270     return result;
271 }
272
273 static char *ssl_var_lookup_header(pool *p, request_rec *r, const char *name)
274 {
275     array_header *hdrs_arr;
276     table_entry *hdrs;
277     int i;
278
279     hdrs_arr = ap_table_elts(r->headers_in);
280     hdrs = (table_entry *)hdrs_arr->elts;
281     for (i = 0; i < hdrs_arr->nelts; ++i) {
282         if (hdrs[i].key == NULL)
283             continue;
284         if (strcEQ(hdrs[i].key, name))
285             return ap_pstrdup(p, hdrs[i].val);
286     }
287     return NULL;
288 }
289
290 static char *ssl_var_lookup_ssl(pool *p, conn_rec *c, char *var)
291 {
292     char *result;
293     X509 *xs;
294     STACK_OF(X509) *sk;
295     SSL *ssl;
296
297     result = NULL;
298
299     ssl = ap_ctx_get(c->client->ctx, "ssl");
300     if (strlen(var) > 8 && strcEQn(var, "VERSION_", 8)) {
301         result = ssl_var_lookup_ssl_version(p, var+8);
302     }
303     else if (ssl != NULL && strcEQ(var, "PROTOCOL")) {
304         result = (char *)SSL_get_version(ssl);
305     }
306     else if (ssl != NULL && strcEQ(var, "SESSION_ID")) {
307         SSL_SESSION *pSession = SSL_get_session(ssl);
308         result = ap_pstrdup(p, SSL_SESSION_id2sz(pSession->session_id, 
309                                                  pSession->session_id_length));
310     }
311     else if (ssl != NULL && strlen(var) >= 6 && strcEQn(var, "CIPHER", 6)) {
312         result = ssl_var_lookup_ssl_cipher(p, c, var+6);
313     }
314     else if (ssl != NULL && strlen(var) > 18 && strcEQn(var, "CLIENT_CERT_CHAIN_", 18)) {
315         sk = SSL_get_peer_cert_chain(ssl);
316         result = ssl_var_lookup_ssl_cert_chain(p, sk, var+17);
317     }
318     else if (ssl != NULL && strcEQ(var, "CLIENT_VERIFY")) {
319         result = ssl_var_lookup_ssl_cert_verify(p, c);
320     }
321     else if (ssl != NULL && strlen(var) > 7 && strcEQn(var, "CLIENT_", 7)) {
322         if ((xs = SSL_get_peer_certificate(ssl)) != NULL)
323             result = ssl_var_lookup_ssl_cert(p, xs, var+7);
324     }
325     else if (ssl != NULL && strlen(var) > 7 && strcEQn(var, "SERVER_", 7)) {
326         if ((xs = SSL_get_certificate(ssl)) != NULL)
327             result = ssl_var_lookup_ssl_cert(p, xs, var+7);
328     }
329     return result;
330 }
331
332 static char *ssl_var_lookup_ssl_cert(pool *p, X509 *xs, char *var)
333 {
334     char *result;
335     BOOL resdup;
336     X509_NAME *xsname;
337     int nid;
338     char *cp;
339
340     result = NULL;
341     resdup = TRUE;
342
343     if (strcEQ(var, "M_VERSION")) {
344         result = ap_psprintf(p, "%lu", X509_get_version(xs)+1);
345         resdup = FALSE;
346     }
347     else if (strcEQ(var, "M_SERIAL")) {
348         result = ssl_var_lookup_ssl_cert_serial(p, xs);
349     }
350     else if (strcEQ(var, "V_START")) {
351         result = ssl_var_lookup_ssl_cert_valid(p, X509_get_notBefore(xs));
352     }
353     else if (strcEQ(var, "V_END")) {
354         result = ssl_var_lookup_ssl_cert_valid(p, X509_get_notAfter(xs));
355     }
356     else if (strcEQ(var, "S_DN")) {
357         xsname = X509_get_subject_name(xs);
358         cp = X509_NAME_oneline(xsname, NULL, 0);
359         result = ap_pstrdup(p, cp);
360         free(cp);
361         resdup = FALSE;
362     }
363     else if (strlen(var) > 5 && strcEQn(var, "S_DN_", 5)) {
364         xsname = X509_get_subject_name(xs);
365         result = ssl_var_lookup_ssl_cert_dn(p, xsname, var+5);
366         resdup = FALSE;
367     }
368     else if (strcEQ(var, "I_DN")) {
369         xsname = X509_get_issuer_name(xs);
370         cp = X509_NAME_oneline(xsname, NULL, 0);
371         result = ap_pstrdup(p, cp);
372         free(cp);
373         resdup = FALSE;
374     }
375     else if (strlen(var) > 5 && strcEQn(var, "I_DN_", 5)) {
376         xsname = X509_get_issuer_name(xs);
377         result = ssl_var_lookup_ssl_cert_dn(p, xsname, var+5);
378         resdup = FALSE;
379     }
380     else if (strcEQ(var, "A_SIG")) {
381         nid = OBJ_obj2nid(xs->cert_info->signature->algorithm);
382         result = ap_pstrdup(p, (nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(nid));
383         resdup = FALSE;
384     }
385     else if (strcEQ(var, "A_KEY")) {
386         nid = OBJ_obj2nid(xs->cert_info->key->algor->algorithm);
387         result = ap_pstrdup(p, (nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(nid));
388         resdup = FALSE;
389     }
390     else if (strcEQ(var, "CERT")) {
391         result = ssl_var_lookup_ssl_cert_PEM(p, xs);
392     }
393
394     if (result != NULL && resdup)
395         result = ap_pstrdup(p, result);
396     return result;
397 }
398
399 static const struct {
400     char *name;
401     int   nid;
402 } ssl_var_lookup_ssl_cert_dn_rec[] = {
403     { "C",     NID_countryName            },
404     { "ST",    NID_stateOrProvinceName    }, /* officially    (RFC2156) */
405     { "SP",    NID_stateOrProvinceName    }, /* compatibility (SSLeay)  */
406     { "L",     NID_localityName           },
407     { "O",     NID_organizationName       },
408     { "OU",    NID_organizationalUnitName },
409     { "CN",    NID_commonName             },
410     { "T",     NID_title                  },
411     { "I",     NID_initials               },
412     { "G",     NID_givenName              },
413     { "S",     NID_surname                },
414     { "D",     NID_description            },
415     { "UID",   NID_uniqueIdentifier       },
416     { "Email", NID_pkcs9_emailAddress     },
417     { NULL,    0                          }
418 };
419
420 static char *ssl_var_lookup_ssl_cert_dn(pool *p, X509_NAME *xsname, char *var)
421 {
422     char *result;
423     X509_NAME_ENTRY *xsne;
424     int i, j, n;
425
426     result = NULL;
427
428     for (i = 0; ssl_var_lookup_ssl_cert_dn_rec[i].name != NULL; i++) {
429         if (strEQ(var, ssl_var_lookup_ssl_cert_dn_rec[i].name)) {
430             for (j = 0; j < sk_X509_NAME_ENTRY_num(xsname->entries); j++) {
431                 xsne = sk_X509_NAME_ENTRY_value(xsname->entries, j);
432                 n = OBJ_obj2nid(xsne->object);
433                 if (n == ssl_var_lookup_ssl_cert_dn_rec[i].nid) {
434                     result = ap_palloc(p, xsne->value->length+1);
435                     ap_cpystrn(result, (char *)xsne->value->data, xsne->value->length+1);
436 #ifdef CHARSET_EBCDIC
437                     ascii2ebcdic(result, result, xsne->value->length);
438 #endif /* CHARSET_EBCDIC */
439                     result[xsne->value->length] = NUL;
440                     break;
441                 }
442             }
443             break;
444         }
445     }
446     return result;
447 }
448
449 static char *ssl_var_lookup_ssl_cert_valid(pool *p, ASN1_UTCTIME *tm)
450 {
451     char *result;
452     BIO* bio;
453     int n;
454
455     if ((bio = BIO_new(BIO_s_mem())) == NULL)
456         return NULL;
457     ASN1_UTCTIME_print(bio, tm);
458     n = BIO_pending(bio);
459     result = ap_pcalloc(p, n+1);
460     n = BIO_read(bio, result, n);
461     result[n] = NUL;
462     BIO_free(bio);
463     return result;
464 }
465
466 static char *ssl_var_lookup_ssl_cert_serial(pool *p, X509 *xs)
467 {
468     char *result;
469     BIO *bio;
470     int n;
471
472     if ((bio = BIO_new(BIO_s_mem())) == NULL)
473         return NULL;
474     i2a_ASN1_INTEGER(bio, X509_get_serialNumber(xs));
475     n = BIO_pending(bio);
476     result = ap_pcalloc(p, n+1);
477     n = BIO_read(bio, result, n);
478     result[n] = NUL;
479     BIO_free(bio);
480     return result;
481 }
482
483 static char *ssl_var_lookup_ssl_cert_chain(pool *p, STACK_OF(X509) *sk, char *var)
484 {
485     char *result;
486     X509 *xs;
487     int n;
488
489     result = NULL;
490
491     if (strspn(var, "0123456789") == strlen(var)) {
492         n = atoi(var);
493         if (n < sk_X509_num(sk)) {
494             xs = sk_X509_value(sk, n);
495             result = ssl_var_lookup_ssl_cert_PEM(p, xs);
496         }
497     }
498
499     return result;
500 }
501
502 static char *ssl_var_lookup_ssl_cert_PEM(pool *p, X509 *xs)
503 {
504     char *result;
505     BIO *bio;
506     int n;
507
508     if ((bio = BIO_new(BIO_s_mem())) == NULL)
509         return NULL;
510     PEM_write_bio_X509(bio, xs);
511     n = BIO_pending(bio);
512     result = ap_pcalloc(p, n+1);
513     n = BIO_read(bio, result, n);
514     result[n] = NUL;
515     BIO_free(bio);
516     return result;
517 }
518
519 static char *ssl_var_lookup_ssl_cert_verify(pool *p, conn_rec *c)
520 {
521     char *result;
522     long vrc;
523     char *verr;
524     char *vinfo;
525     SSL *ssl;
526     X509 *xs;
527
528     result = NULL;
529     ssl   = ap_ctx_get(c->client->ctx, "ssl");
530     verr  = ap_ctx_get(c->client->ctx, "ssl::verify::error");
531     vinfo = ap_ctx_get(c->client->ctx, "ssl::verify::info");
532     vrc   = SSL_get_verify_result(ssl);
533     xs    = SSL_get_peer_certificate(ssl);
534
535     if (vrc == X509_V_OK && verr == NULL && vinfo == NULL && xs == NULL)
536         /* no client verification done at all */
537         result = "NONE";
538     else if (vrc == X509_V_OK && verr == NULL && vinfo == NULL && xs != NULL)
539         /* client verification done successful */
540         result = "SUCCESS";
541     else if (vrc == X509_V_OK && vinfo != NULL && strEQ(vinfo, "GENEROUS"))
542         /* client verification done in generous way */
543         result = "GENEROUS";
544     else
545         /* client verification failed */
546         result = ap_psprintf(p, "FAILED:%s", verr);
547     return result;
548 }
549
550 static char *ssl_var_lookup_ssl_cipher(pool *p, conn_rec *c, char *var)
551 {
552     char *result;
553     BOOL resdup;
554     int usekeysize, algkeysize;
555     SSL *ssl;
556
557     result = NULL;
558     resdup = TRUE;
559
560     ssl = ap_ctx_get(c->client->ctx, "ssl");
561     ssl_var_lookup_ssl_cipher_bits(ssl, &usekeysize, &algkeysize);
562
563     if (strEQ(var, ""))
564         result = (ssl != NULL ? (char *)SSL_get_cipher_name(ssl) : NULL);
565     else if (strcEQ(var, "_EXPORT"))
566         result = (usekeysize < 56 ? "true" : "false");
567     else if (strcEQ(var, "_USEKEYSIZE")) {
568         result = ap_psprintf(p, "%d", usekeysize);
569         resdup = FALSE;
570     }
571     else if (strcEQ(var, "_ALGKEYSIZE")) {
572         result = ap_psprintf(p, "%d", algkeysize);
573         resdup = FALSE;
574     }
575
576     if (result != NULL && resdup)
577         result = ap_pstrdup(p, result);
578     return result;
579 }
580
581 static void ssl_var_lookup_ssl_cipher_bits(SSL *ssl, int *usekeysize, int *algkeysize)
582 {
583     SSL_CIPHER *cipher;
584
585     *usekeysize = 0;
586     *algkeysize = 0;
587     if (ssl != NULL)
588         if ((cipher = SSL_get_current_cipher(ssl)) != NULL)
589             *usekeysize = SSL_CIPHER_get_bits(cipher, algkeysize);
590     return;
591 }
592
593 static char *ssl_var_lookup_ssl_version(pool *p, char *var)
594 {
595     char *result;
596     char *cp, *cp2;
597
598     result = NULL;
599
600     if (strEQ(var, "PRODUCT")) {
601 #if defined(SSL_PRODUCT_NAME) && defined(SSL_PRODUCT_VERSION)
602         result = ap_psprintf(p, "%s/%s", SSL_PRODUCT_NAME, SSL_PRODUCT_VERSION);
603 #else
604         result = NULL;
605 #endif
606     }
607     else if (strEQ(var, "INTERFACE")) {
608         result = ap_psprintf(p, "mod_ssl/%s", MOD_SSL_VERSION);
609     }
610     else if (strEQ(var, "LIBRARY")) {
611         result = ap_pstrdup(p, SSL_LIBRARY_TEXT);
612         if ((cp = strchr(result, ' ')) != NULL) {
613             *cp = '/';
614             if ((cp2 = strchr(cp, ' ')) != NULL)
615                 *cp2 = NUL;
616         }
617     }
618     return result;
619 }
620
621 #endif /* XXX */
622
623