]> granicus.if.org Git - apache/blob - modules/ssl/ssl_engine_vars.c
hostname: Test and log useragent_host per-request across various modules,
[apache] / modules / ssl / ssl_engine_vars.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_engine_vars.c
24  *  Variable Lookup Facility
25  */
26                              /* ``Those of you who think they
27                                   know everything are very annoying
28                                   to those of us who do.''
29                                                   -- Unknown       */
30 #include "ssl_private.h"
31 #include "mod_ssl.h"
32 #include "ap_expr.h"
33
34 #include "apr_time.h"
35
36 /*  _________________________________________________________________
37 **
38 **  Variable Lookup
39 **  _________________________________________________________________
40 */
41
42 static char *ssl_var_lookup_ssl(apr_pool_t *p, SSLConnRec *sslconn, request_rec *r, char *var);
43 static char *ssl_var_lookup_ssl_cert(apr_pool_t *p, request_rec *r, X509 *xs, char *var);
44 static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, char *var);
45 static char *ssl_var_lookup_ssl_cert_san(apr_pool_t *p, X509 *xs, char *var);
46 static char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_TIME *tm);
47 static char *ssl_var_lookup_ssl_cert_remain(apr_pool_t *p, ASN1_TIME *tm);
48 static char *ssl_var_lookup_ssl_cert_serial(apr_pool_t *p, X509 *xs);
49 static char *ssl_var_lookup_ssl_cert_chain(apr_pool_t *p, STACK_OF(X509) *sk, char *var);
50 static char *ssl_var_lookup_ssl_cert_rfc4523_cea(apr_pool_t *p, SSL *ssl);
51 static char *ssl_var_lookup_ssl_cert_PEM(apr_pool_t *p, X509 *xs);
52 static char *ssl_var_lookup_ssl_cert_verify(apr_pool_t *p, SSLConnRec *sslconn);
53 static char *ssl_var_lookup_ssl_cipher(apr_pool_t *p, SSLConnRec *sslconn, char *var);
54 static void  ssl_var_lookup_ssl_cipher_bits(SSL *ssl, int *usekeysize, int *algkeysize);
55 static char *ssl_var_lookup_ssl_version(apr_pool_t *p, char *var);
56 static char *ssl_var_lookup_ssl_compress_meth(SSL *ssl);
57
58 static SSLConnRec *ssl_get_effective_config(conn_rec *c)
59 {
60     SSLConnRec *sslconn = myConnConfig(c);
61     if (!(sslconn && sslconn->ssl) && c->master) {
62         /* use master connection if no SSL defined here */
63         sslconn = myConnConfig(c->master);
64     }
65     return sslconn;
66 }
67
68 static int ssl_is_https(conn_rec *c)
69 {
70     SSLConnRec *sslconn = ssl_get_effective_config(c);
71     return sslconn && sslconn->ssl;
72 }
73
74 /* SSLv3 uses 36 bytes for Finishd messages, TLS1.0 12 bytes,
75  * So tls-unique is max 36 bytes, however with tls-server-end-point,
76  * the CB data is the certificate signature, so we use the maximum
77  * hash size known to the library (currently 64).
78  * */
79 #define TLS_CB_MAX EVP_MAX_MD_SIZE
80 #define TLS_UNIQUE_PREFIX "tls-unique:"
81 #define TLS_SERVER_END_POINT_PREFIX "tls-server-end-point:"
82
83 static apr_status_t ssl_get_tls_cb(apr_pool_t *p, conn_rec *c, const char *type,
84                                    unsigned char **buf, apr_size_t *size)
85 {
86     SSLConnRec *sslconn = ssl_get_effective_config(c);
87     const char *prefix;
88     apr_size_t preflen;
89     const unsigned char *data;
90     unsigned char cb[TLS_CB_MAX], *retbuf;
91     unsigned int l = 0;
92     X509 *x = NULL;
93
94     if (!sslconn || !sslconn->ssl) {
95         return APR_EGENERAL;
96     }
97     if (strcEQ(type, "SERVER_TLS_UNIQUE")) {
98         l = SSL_get_peer_finished(sslconn->ssl, cb, TLS_CB_MAX);
99     }
100     else if (strcEQ(type, "CLIENT_TLS_UNIQUE")) {
101         l = SSL_get_finished(sslconn->ssl, cb, TLS_CB_MAX);
102     }
103     else if (strcEQ(type, "SERVER_TLS_SERVER_END_POINT")) {
104         x = SSL_get_certificate(sslconn->ssl);
105     }
106     else if (strcEQ(type, "CLIENT_TLS_SERVER_END_POINT")) {
107         x = SSL_get_peer_certificate(sslconn->ssl);
108     }
109     if (l > 0) {
110         preflen = sizeof(TLS_UNIQUE_PREFIX) -1;
111         prefix = TLS_UNIQUE_PREFIX;
112         data = cb;
113     } 
114     else if (x != NULL) {
115         const EVP_MD *md;
116
117 #if OPENSSL_VERSION_NUMBER < 0x10100000L
118         md = EVP_get_digestbynid(OBJ_obj2nid(x->sig_alg->algorithm));
119 #else
120         md = EVP_get_digestbynid(X509_get_signature_nid(x));
121 #endif
122         /* Override digest as specified by RFC 5929 section 4.1. */
123         if (md == NULL || md == EVP_md5() || md == EVP_sha1()) {
124             md = EVP_sha256();
125         }
126         if (!X509_digest(x, md, cb, &l)) {
127             return APR_EGENERAL;
128         }
129
130         preflen = sizeof(TLS_SERVER_END_POINT_PREFIX) - 1;
131         prefix = TLS_SERVER_END_POINT_PREFIX;
132         data = cb;
133     } 
134     else {
135         return APR_EGENERAL;
136     }
137
138     retbuf = apr_palloc(p, preflen + l);
139     memcpy(retbuf, prefix, preflen);
140     memcpy(&retbuf[preflen], data, l);
141     *size = preflen + l;
142     *buf = retbuf;
143
144     return APR_SUCCESS;
145 }
146
147 static const char var_interface[] = "mod_ssl/" AP_SERVER_BASEREVISION;
148 static char var_library_interface[] = MODSSL_LIBRARY_TEXT;
149 static char *var_library = NULL;
150
151 static apr_array_header_t *expr_peer_ext_list_fn(ap_expr_eval_ctx_t *ctx,
152                                                  const void *dummy,
153                                                  const char *arg)
154 {
155     return ssl_ext_list(ctx->p, ctx->c, 1, arg);
156 }
157
158 static const char *expr_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
159 {
160     char *var = (char *)data;
161     SSLConnRec *sslconn = ssl_get_effective_config(ctx->c);
162
163     return sslconn ? ssl_var_lookup_ssl(ctx->p, sslconn, ctx->r, var) : NULL;
164 }
165
166 static const char *expr_func_fn(ap_expr_eval_ctx_t *ctx, const void *data,
167                                 const char *arg)
168 {
169     char *var = (char *)arg;
170
171     return var ? ssl_var_lookup(ctx->p, ctx->s, ctx->c, ctx->r, var) : NULL;
172 }
173
174 static int ssl_expr_lookup(ap_expr_lookup_parms *parms)
175 {
176     switch (parms->type) {
177     case AP_EXPR_FUNC_VAR:
178         /* for now, we just handle everything that starts with SSL_, but
179          * register our hook as APR_HOOK_LAST
180          * XXX: This can be optimized
181          */
182         if (strcEQn(parms->name, "SSL_", 4)) {
183             *parms->func = expr_var_fn;
184             *parms->data = parms->name + 4;
185             return OK;
186         }
187         break;
188     case AP_EXPR_FUNC_STRING:
189         /* Function SSL() is implemented by us.
190          */
191         if (strcEQ(parms->name, "SSL")) {
192             *parms->func = expr_func_fn;
193             *parms->data = NULL;
194             return OK;
195         }
196         break;
197     case AP_EXPR_FUNC_LIST:
198         if (strcEQ(parms->name, "PeerExtList")) {
199             *parms->func = expr_peer_ext_list_fn;
200             *parms->data = "PeerExtList";
201             return OK;
202         }
203         break;
204     }
205     return DECLINED;
206 }
207
208
209 void ssl_var_register(apr_pool_t *p)
210 {
211     char *cp, *cp2;
212
213     APR_REGISTER_OPTIONAL_FN(ssl_is_https);
214     APR_REGISTER_OPTIONAL_FN(ssl_get_tls_cb);
215     APR_REGISTER_OPTIONAL_FN(ssl_var_lookup);
216     APR_REGISTER_OPTIONAL_FN(ssl_ext_list);
217
218     /* Perform once-per-process library version determination: */
219     var_library = apr_pstrdup(p, MODSSL_LIBRARY_DYNTEXT);
220
221     if ((cp = strchr(var_library, ' ')) != NULL) {
222         *cp = '/';
223         if ((cp2 = strchr(cp, ' ')) != NULL)
224             *cp2 = NUL;
225     }
226
227     if ((cp = strchr(var_library_interface, ' ')) != NULL) {
228         *cp = '/';
229         if ((cp2 = strchr(cp, ' ')) != NULL)
230             *cp2 = NUL;
231     }
232
233     ap_hook_expr_lookup(ssl_expr_lookup, NULL, NULL, APR_HOOK_MIDDLE);
234 }
235
236 /* This function must remain safe to use for a non-SSL connection. */
237 char *ssl_var_lookup(apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, char *var)
238 {
239     SSLModConfigRec *mc = myModConfig(s);
240     const char *result;
241     BOOL resdup;
242     apr_time_exp_t tm;
243
244     result = NULL;
245     resdup = TRUE;
246
247     /*
248      * When no pool is given try to find one
249      */
250     if (p == NULL) {
251         if (r != NULL)
252             p = r->pool;
253         else if (c != NULL)
254             p = c->pool;
255         else
256             p = mc->pPool;
257     }
258
259     /*
260      * Request dependent stuff
261      */
262     if (r != NULL) {
263         switch (var[0]) {
264         case 'H':
265         case 'h':
266             if (strcEQ(var, "HTTP_USER_AGENT"))
267                 result = apr_table_get(r->headers_in, "User-Agent");
268             else if (strcEQ(var, "HTTP_REFERER"))
269                 result = apr_table_get(r->headers_in, "Referer");
270             else if (strcEQ(var, "HTTP_COOKIE"))
271                 result = apr_table_get(r->headers_in, "Cookie");
272             else if (strcEQ(var, "HTTP_FORWARDED"))
273                 result = apr_table_get(r->headers_in, "Forwarded");
274             else if (strcEQ(var, "HTTP_HOST"))
275                 result = apr_table_get(r->headers_in, "Host");
276             else if (strcEQ(var, "HTTP_PROXY_CONNECTION"))
277                 result = apr_table_get(r->headers_in, "Proxy-Connection");
278             else if (strcEQ(var, "HTTP_ACCEPT"))
279                 result = apr_table_get(r->headers_in, "Accept");
280             else if (strlen(var) > 5 && strcEQn(var, "HTTP:", 5))
281                 /* all other headers from which we are still not know about */
282                 result = apr_table_get(r->headers_in, var+5);
283             break;
284
285         case 'R':
286         case 'r':
287             if (strcEQ(var, "REQUEST_METHOD"))
288                 result = r->method;
289             else if (strcEQ(var, "REQUEST_SCHEME"))
290                 result = ap_http_scheme(r);
291             else if (strcEQ(var, "REQUEST_URI"))
292                 result = r->uri;
293             else if (strcEQ(var, "REQUEST_FILENAME"))
294                 result = r->filename;
295             else if (strcEQ(var, "REMOTE_ADDR"))
296                 result = r->useragent_ip;
297             else if (strcEQ(var, "REMOTE_HOST"))
298                 result = ap_get_useragent_host(r, REMOTE_NAME, NULL);
299             else if (strcEQ(var, "REMOTE_IDENT"))
300                 result = ap_get_remote_logname(r);
301             else if (strcEQ(var, "REMOTE_USER"))
302                 result = r->user;
303             break;
304
305         case 'S':
306         case 's':
307             if (strcEQn(var, "SSL", 3)) break; /* shortcut common case */
308
309             if (strcEQ(var, "SERVER_ADMIN"))
310                 result = r->server->server_admin;
311             else if (strcEQ(var, "SERVER_NAME"))
312                 result = ap_get_server_name_for_url(r);
313             else if (strcEQ(var, "SERVER_PORT"))
314                 result = apr_psprintf(p, "%u", ap_get_server_port(r));
315             else if (strcEQ(var, "SERVER_PROTOCOL"))
316                 result = r->protocol;
317             else if (strcEQ(var, "SCRIPT_FILENAME"))
318                 result = r->filename;
319             break;
320
321         default:
322             if (strcEQ(var, "PATH_INFO"))
323                 result = r->path_info;
324             else if (strcEQ(var, "QUERY_STRING"))
325                 result = r->args;
326             else if (strcEQ(var, "IS_SUBREQ"))
327                 result = (r->main != NULL ? "true" : "false");
328             else if (strcEQ(var, "DOCUMENT_ROOT"))
329                 result = ap_document_root(r);
330             else if (strcEQ(var, "AUTH_TYPE"))
331                 result = r->ap_auth_type;
332             else if (strcEQ(var, "THE_REQUEST"))
333                 result = r->the_request;
334             else if (strlen(var) > 4 && strcEQn(var, "ENV:", 4)) {
335                 result = apr_table_get(r->notes, var+4);
336                 if (result == NULL)
337                     result = apr_table_get(r->subprocess_env, var+4);
338             }
339             break;
340         }
341     }
342
343     /*
344      * Connection stuff
345      */
346     if (result == NULL && c != NULL) {
347         SSLConnRec *sslconn = ssl_get_effective_config(c);
348         if (strlen(var) > 4 && strcEQn(var, "SSL_", 4)
349             && sslconn && sslconn->ssl)
350             result = ssl_var_lookup_ssl(p, sslconn, r, var+4);
351         else if (strcEQ(var, "HTTPS")) {
352             if (sslconn && sslconn->ssl)
353                 result = "on";
354             else
355                 result = "off";
356         }
357     }
358
359     /*
360      * Totally independent stuff
361      */
362     if (result == NULL) {
363         if (strlen(var) > 12 && strcEQn(var, "SSL_VERSION_", 12))
364             result = ssl_var_lookup_ssl_version(p, var+12);
365         else if (strcEQ(var, "SERVER_SOFTWARE"))
366             result = ap_get_server_banner();
367         else if (strcEQ(var, "API_VERSION")) {
368             result = apr_itoa(p, MODULE_MAGIC_NUMBER_MAJOR);
369             resdup = FALSE;
370         }
371         else if (strcEQ(var, "TIME_YEAR")) {
372             apr_time_exp_lt(&tm, apr_time_now());
373             result = apr_psprintf(p, "%02d%02d",
374                                  (tm.tm_year / 100) + 19, tm.tm_year % 100);
375             resdup = FALSE;
376         }
377 #define MKTIMESTR(format, tmfield) \
378             apr_time_exp_lt(&tm, apr_time_now()); \
379             result = apr_psprintf(p, format, tm.tmfield); \
380             resdup = FALSE;
381         else if (strcEQ(var, "TIME_MON")) {
382             MKTIMESTR("%02d", tm_mon+1)
383         }
384         else if (strcEQ(var, "TIME_DAY")) {
385             MKTIMESTR("%02d", tm_mday)
386         }
387         else if (strcEQ(var, "TIME_HOUR")) {
388             MKTIMESTR("%02d", tm_hour)
389         }
390         else if (strcEQ(var, "TIME_MIN")) {
391             MKTIMESTR("%02d", tm_min)
392         }
393         else if (strcEQ(var, "TIME_SEC")) {
394             MKTIMESTR("%02d", tm_sec)
395         }
396         else if (strcEQ(var, "TIME_WDAY")) {
397             MKTIMESTR("%d", tm_wday)
398         }
399         else if (strcEQ(var, "TIME")) {
400             apr_time_exp_lt(&tm, apr_time_now());
401             result = apr_psprintf(p,
402                         "%02d%02d%02d%02d%02d%02d%02d", (tm.tm_year / 100) + 19,
403                         (tm.tm_year % 100), tm.tm_mon+1, tm.tm_mday,
404                         tm.tm_hour, tm.tm_min, tm.tm_sec);
405             resdup = FALSE;
406         }
407         /* all other env-variables from the parent Apache process */
408         else if (strlen(var) > 4 && strcEQn(var, "ENV:", 4)) {
409             result = getenv(var+4);
410         }
411     }
412
413     if (result != NULL && resdup)
414         result = apr_pstrdup(p, result);
415     if (result == NULL)
416         result = "";
417     return (char *)result;
418 }
419
420 static char *ssl_var_lookup_ssl(apr_pool_t *p, SSLConnRec *sslconn, 
421                                 request_rec *r, char *var)
422 {
423     char *result;
424     X509 *xs;
425     STACK_OF(X509) *sk;
426     SSL *ssl;
427
428     result = NULL;
429
430     ssl = sslconn->ssl;
431     if (strlen(var) > 8 && strcEQn(var, "VERSION_", 8)) {
432         result = ssl_var_lookup_ssl_version(p, var+8);
433     }
434     else if (ssl != NULL && strcEQ(var, "PROTOCOL")) {
435         result = (char *)SSL_get_version(ssl);
436     }
437     else if (ssl != NULL && strcEQ(var, "SESSION_ID")) {
438         char buf[MODSSL_SESSION_ID_STRING_LEN];
439         SSL_SESSION *pSession = SSL_get_session(ssl);
440         if (pSession) {
441             unsigned char *id;
442             unsigned int idlen;
443
444 #ifdef OPENSSL_NO_SSL_INTERN
445             id = (unsigned char *)SSL_SESSION_get_id(pSession, &idlen);
446 #else
447             id = pSession->session_id;
448             idlen = pSession->session_id_length;
449 #endif
450
451             result = apr_pstrdup(p, modssl_SSL_SESSION_id2sz(id, idlen,
452                                                              buf, sizeof(buf)));
453         }
454     }
455     else if(ssl != NULL && strcEQ(var, "SESSION_RESUMED")) {
456         if (SSL_session_reused(ssl) == 1)
457             result = "Resumed";
458         else
459             result = "Initial";
460     }
461     else if (ssl != NULL && strlen(var) >= 6 && strcEQn(var, "CIPHER", 6)) {
462         result = ssl_var_lookup_ssl_cipher(p, sslconn, var+6);
463     }
464     else if (ssl != NULL && strlen(var) > 18 && strcEQn(var, "CLIENT_CERT_CHAIN_", 18)) {
465         sk = SSL_get_peer_cert_chain(ssl);
466         result = ssl_var_lookup_ssl_cert_chain(p, sk, var+18);
467     }
468     else if (ssl != NULL && strcEQ(var, "CLIENT_CERT_RFC4523_CEA")) {
469         result = ssl_var_lookup_ssl_cert_rfc4523_cea(p, ssl);
470     }
471     else if (ssl != NULL && strcEQ(var, "CLIENT_VERIFY")) {
472         result = ssl_var_lookup_ssl_cert_verify(p, sslconn);
473     }
474     else if (ssl != NULL && strlen(var) > 7 && strcEQn(var, "CLIENT_", 7)) {
475         if ((xs = SSL_get_peer_certificate(ssl)) != NULL) {
476             result = ssl_var_lookup_ssl_cert(p, r, xs, var+7);
477             X509_free(xs);
478         }
479     }
480     else if (ssl != NULL && strlen(var) > 7 && strcEQn(var, "SERVER_", 7)) {
481         if ((xs = SSL_get_certificate(ssl)) != NULL) {
482             result = ssl_var_lookup_ssl_cert(p, r, xs, var+7);
483             /* SSL_get_certificate is different from SSL_get_peer_certificate.
484              * No need to X509_free(xs).
485              */
486         }
487     }
488     else if (ssl != NULL && strcEQ(var, "COMPRESS_METHOD")) {
489         result = ssl_var_lookup_ssl_compress_meth(ssl);
490     }
491 #ifdef HAVE_TLSEXT
492     else if (ssl != NULL && strcEQ(var, "TLS_SNI")) {
493         result = apr_pstrdup(p, SSL_get_servername(ssl,
494                                                    TLSEXT_NAMETYPE_host_name));
495     }
496 #endif
497     else if (ssl != NULL && strcEQ(var, "SECURE_RENEG")) {
498         int flag = 0;
499 #ifdef SSL_get_secure_renegotiation_support
500         flag = SSL_get_secure_renegotiation_support(ssl);
501 #endif
502         result = apr_pstrdup(p, flag ? "true" : "false");
503     }
504 #ifdef HAVE_SRP
505     else if (ssl != NULL && strcEQ(var, "SRP_USER")) {
506         if ((result = SSL_get_srp_username(ssl)) != NULL) {
507             result = apr_pstrdup(p, result);
508         }
509     }
510     else if (ssl != NULL && strcEQ(var, "SRP_USERINFO")) {
511         if ((result = SSL_get_srp_userinfo(ssl)) != NULL) {
512             result = apr_pstrdup(p, result);
513         }
514     }
515 #endif
516
517     return result;
518 }
519
520 static char *ssl_var_lookup_ssl_cert_dn_oneline(apr_pool_t *p, request_rec *r,
521                                                 X509_NAME *xsname)
522 {
523     char *result = NULL;
524     SSLDirConfigRec *dc;
525     int legacy_format = 0;
526     if (r) {
527         dc = myDirConfig(r);
528         legacy_format = dc->nOptions & SSL_OPT_LEGACYDNFORMAT;
529     }
530     if (legacy_format) {
531         char *cp = X509_NAME_oneline(xsname, NULL, 0);
532         result = apr_pstrdup(p, cp);
533         OPENSSL_free(cp);
534     }
535     else {
536         BIO* bio;
537         int n;
538         unsigned long flags = XN_FLAG_RFC2253 & ~ASN1_STRFLGS_ESC_MSB;
539         if ((bio = BIO_new(BIO_s_mem())) == NULL)
540             return NULL;
541         X509_NAME_print_ex(bio, xsname, 0, flags);
542         n = BIO_pending(bio);
543         if (n > 0) {
544             result = apr_palloc(p, n+1);
545             n = BIO_read(bio, result, n);
546             result[n] = NUL;
547         }
548         BIO_free(bio);
549     }
550     return result;
551 }
552
553 static char *ssl_var_lookup_ssl_cert(apr_pool_t *p, request_rec *r, X509 *xs,
554                                      char *var)
555 {
556     char *result;
557     BOOL resdup;
558     X509_NAME *xsname;
559     int nid;
560
561     result = NULL;
562     resdup = TRUE;
563
564     if (strcEQ(var, "M_VERSION")) {
565         result = apr_psprintf(p, "%lu", X509_get_version(xs)+1);
566         resdup = FALSE;
567     }
568     else if (strcEQ(var, "M_SERIAL")) {
569         result = ssl_var_lookup_ssl_cert_serial(p, xs);
570     }
571     else if (strcEQ(var, "V_START")) {
572         result = ssl_var_lookup_ssl_cert_valid(p, X509_get_notBefore(xs));
573     }
574     else if (strcEQ(var, "V_END")) {
575         result = ssl_var_lookup_ssl_cert_valid(p, X509_get_notAfter(xs));
576     }
577     else if (strcEQ(var, "V_REMAIN")) {
578         result = ssl_var_lookup_ssl_cert_remain(p, X509_get_notAfter(xs));
579         resdup = FALSE;
580     }
581     else if (*var && strcEQ(var+1, "_DN")) {
582         if (*var == 'S')
583             xsname = X509_get_subject_name(xs);
584         else if (*var == 'I')
585             xsname = X509_get_issuer_name(xs);
586         else
587             return NULL;
588         result = ssl_var_lookup_ssl_cert_dn_oneline(p, r, xsname);
589         resdup = FALSE;
590     }
591     else if (strlen(var) > 5 && strcEQn(var+1, "_DN_", 4)) {
592         if (*var == 'S')
593             xsname = X509_get_subject_name(xs);
594         else if (*var == 'I')
595             xsname = X509_get_issuer_name(xs);
596         else
597             return NULL;
598         result = ssl_var_lookup_ssl_cert_dn(p, xsname, var+5);
599         resdup = FALSE;
600     }
601     else if (strlen(var) > 4 && strcEQn(var, "SAN_", 4)) {
602         result = ssl_var_lookup_ssl_cert_san(p, xs, var+4);
603         resdup = FALSE;
604     }
605     else if (strcEQ(var, "A_SIG")) {
606 #if OPENSSL_VERSION_NUMBER < 0x10100000L
607         nid = OBJ_obj2nid((ASN1_OBJECT *)(xs->cert_info->signature->algorithm));
608 #else
609         ASN1_OBJECT *paobj;
610         X509_ALGOR_get0(&paobj, NULL, NULL, X509_get0_tbs_sigalg(xs));
611         nid = OBJ_obj2nid(paobj);
612 #endif
613         result = apr_pstrdup(p,
614                              (nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(nid));
615         resdup = FALSE;
616     }
617     else if (strcEQ(var, "A_KEY")) {
618 #if OPENSSL_VERSION_NUMBER < 0x10100000L
619         nid = OBJ_obj2nid((ASN1_OBJECT *)(xs->cert_info->key->algor->algorithm));
620 #else
621         ASN1_OBJECT *paobj;
622         X509_PUBKEY_get0_param(&paobj, NULL, 0, NULL, X509_get_X509_PUBKEY(xs));
623         nid = OBJ_obj2nid(paobj);
624 #endif
625         result = apr_pstrdup(p,
626                              (nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(nid));
627         resdup = FALSE;
628     }
629     else if (strcEQ(var, "CERT")) {
630         result = ssl_var_lookup_ssl_cert_PEM(p, xs);
631     }
632
633     if (resdup)
634         result = apr_pstrdup(p, result);
635     return result;
636 }
637
638 /* In this table, .extract is non-zero if RDNs using the NID should be
639  * extracted to for the SSL_{CLIENT,SERVER}_{I,S}_DN_* environment
640  * variables. */
641 static const struct {
642     char *name;
643     int   nid;
644     int   extract;
645 } ssl_var_lookup_ssl_cert_dn_rec[] = {
646     { "C",     NID_countryName,            1 },
647     { "ST",    NID_stateOrProvinceName,    1 }, /* officially    (RFC2156) */
648     { "SP",    NID_stateOrProvinceName,    0 }, /* compatibility (SSLeay)  */
649     { "L",     NID_localityName,           1 },
650     { "O",     NID_organizationName,       1 },
651     { "OU",    NID_organizationalUnitName, 1 },
652     { "CN",    NID_commonName,             1 },
653     { "T",     NID_title,                  1 },
654     { "I",     NID_initials,               1 },
655     { "G",     NID_givenName,              1 },
656     { "S",     NID_surname,                1 },
657     { "D",     NID_description,            1 },
658 #ifdef NID_userId
659     { "UID",   NID_userId,                 1 },
660 #endif
661     { "Email", NID_pkcs9_emailAddress,     1 },
662     { NULL,    0,                          0 }
663 };
664
665 static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, char *var)
666 {
667     char *result, *ptr;
668     X509_NAME_ENTRY *xsne;
669     int i, j, n, idx = 0;
670     apr_size_t varlen;
671
672     /* if an _N suffix is used, find the Nth attribute of given name */
673     ptr = strchr(var, '_');
674     if (ptr != NULL && strspn(ptr + 1, "0123456789") == strlen(ptr + 1)) {
675         idx = atoi(ptr + 1);
676         varlen = ptr - var;
677     } else {
678         varlen = strlen(var);
679     }
680
681     result = NULL;
682
683     for (i = 0; ssl_var_lookup_ssl_cert_dn_rec[i].name != NULL; i++) {
684         if (strEQn(var, ssl_var_lookup_ssl_cert_dn_rec[i].name, varlen)
685             && strlen(ssl_var_lookup_ssl_cert_dn_rec[i].name) == varlen) {
686 #if OPENSSL_VERSION_NUMBER < 0x10100000L
687             for (j = 0; j < sk_X509_NAME_ENTRY_num((STACK_OF(X509_NAME_ENTRY) *)
688                                                    xsname->entries);
689                  j++) {
690                 xsne = sk_X509_NAME_ENTRY_value((STACK_OF(X509_NAME_ENTRY) *)
691                                                 xsname->entries, j);
692 #else
693             for (j = 0; j < X509_NAME_entry_count(xsname); j++) {
694                 xsne = X509_NAME_get_entry(xsname, j);
695 #endif
696
697                 n =OBJ_obj2nid((ASN1_OBJECT *)X509_NAME_ENTRY_get_object(xsne));
698
699                 if (n == ssl_var_lookup_ssl_cert_dn_rec[i].nid && idx-- == 0) {
700                     result = modssl_X509_NAME_ENTRY_to_string(p, xsne);
701                     break;
702                 }
703             }
704             break;
705         }
706     }
707     return result;
708 }
709
710 static char *ssl_var_lookup_ssl_cert_san(apr_pool_t *p, X509 *xs, char *var)
711 {
712     int type, numlen;
713     const char *onf = NULL;
714     apr_array_header_t *entries;
715
716     if (strcEQn(var, "Email_", 6)) {
717         type = GEN_EMAIL;
718         var += 6;
719     }
720     else if (strcEQn(var, "DNS_", 4)) {
721         type = GEN_DNS;
722         var += 4;
723     }
724     else if (strcEQn(var, "OTHER_", 6)) {
725         type = GEN_OTHERNAME;
726         var += 6;
727         if (strEQn(var, "msUPN_", 6)) {
728             var += 6;
729             onf = "msUPN";
730         }
731         else if (strEQn(var, "dnsSRV_", 7)) {
732             var += 7;
733             onf = "id-on-dnsSRV";
734         }
735         else
736            return NULL;
737     }
738     else
739         return NULL;
740
741     /* sanity check: number must be between 1 and 4 digits */
742     numlen = strspn(var, "0123456789");
743     if ((numlen < 1) || (numlen > 4) || (numlen != strlen(var)))
744         return NULL;
745
746     if (modssl_X509_getSAN(p, xs, type, onf, atoi(var), &entries))
747         /* return the first entry from this 1-element array */
748         return APR_ARRAY_IDX(entries, 0, char *);
749     else
750         return NULL;
751 }
752
753 static char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_TIME *tm)
754 {
755     char *result;
756     BIO* bio;
757     int n;
758
759     if ((bio = BIO_new(BIO_s_mem())) == NULL)
760         return NULL;
761     ASN1_TIME_print(bio, tm);
762     n = BIO_pending(bio);
763     result = apr_pcalloc(p, n+1);
764     n = BIO_read(bio, result, n);
765     result[n] = NUL;
766     BIO_free(bio);
767     return result;
768 }
769
770 #define DIGIT2NUM(x) (((x)[0] - '0') * 10 + (x)[1] - '0')
771
772 /* Return a string giving the number of days remaining until 'tm', or
773  * "0" if this can't be determined. */
774 static char *ssl_var_lookup_ssl_cert_remain(apr_pool_t *p, ASN1_TIME *tm)
775 {
776     apr_time_t then, now = apr_time_now();
777     apr_time_exp_t exp = {0};
778     long diff;
779     unsigned char *dp;
780
781     /* Fail if the time isn't a valid ASN.1 TIME; RFC3280 mandates
782      * that the seconds digits are present even though ASN.1
783      * doesn't. */
784     if ((tm->type == V_ASN1_UTCTIME && tm->length < 11) ||
785         (tm->type == V_ASN1_GENERALIZEDTIME && tm->length < 13) ||
786         !ASN1_TIME_check(tm)) {
787         return apr_pstrdup(p, "0");
788     }
789
790     if (tm->type == V_ASN1_UTCTIME) {
791         exp.tm_year = DIGIT2NUM(tm->data);
792         if (exp.tm_year <= 50) exp.tm_year += 100;
793         dp = tm->data + 2;
794     } else {
795         exp.tm_year = DIGIT2NUM(tm->data) * 100 + DIGIT2NUM(tm->data + 2) - 1900;
796         dp = tm->data + 4;
797     }
798
799     exp.tm_mon = DIGIT2NUM(dp) - 1;
800     exp.tm_mday = DIGIT2NUM(dp + 2) + 1;
801     exp.tm_hour = DIGIT2NUM(dp + 4);
802     exp.tm_min = DIGIT2NUM(dp + 6);
803     exp.tm_sec = DIGIT2NUM(dp + 8);
804
805     if (apr_time_exp_gmt_get(&then, &exp) != APR_SUCCESS) {
806         return apr_pstrdup(p, "0");
807     }
808
809     diff = (long)((apr_time_sec(then) - apr_time_sec(now)) / (60*60*24));
810
811     return diff > 0 ? apr_ltoa(p, diff) : apr_pstrdup(p, "0");
812 }
813
814 static char *ssl_var_lookup_ssl_cert_serial(apr_pool_t *p, X509 *xs)
815 {
816     char *result;
817     BIO *bio;
818     int n;
819
820     if ((bio = BIO_new(BIO_s_mem())) == NULL)
821         return NULL;
822     i2a_ASN1_INTEGER(bio, X509_get_serialNumber(xs));
823     n = BIO_pending(bio);
824     result = apr_pcalloc(p, n+1);
825     n = BIO_read(bio, result, n);
826     result[n] = NUL;
827     BIO_free(bio);
828     return result;
829 }
830
831 static char *ssl_var_lookup_ssl_cert_chain(apr_pool_t *p, STACK_OF(X509) *sk, char *var)
832 {
833     char *result;
834     X509 *xs;
835     int n;
836
837     result = NULL;
838
839     if (strspn(var, "0123456789") == strlen(var)) {
840         n = atoi(var);
841         if (n < sk_X509_num(sk)) {
842             xs = sk_X509_value(sk, n);
843             result = ssl_var_lookup_ssl_cert_PEM(p, xs);
844         }
845     }
846
847     return result;
848 }
849
850 static char *ssl_var_lookup_ssl_cert_rfc4523_cea(apr_pool_t *p, SSL *ssl)
851 {
852     char *result;
853     X509 *xs;
854
855     ASN1_INTEGER *serialNumber;
856
857     if (!(xs = SSL_get_peer_certificate(ssl))) {
858         return NULL;
859     }
860
861     result = NULL;
862
863     serialNumber = X509_get_serialNumber(xs);
864     if (serialNumber) {
865         X509_NAME *issuer = X509_get_issuer_name(xs);
866         if (issuer) {
867             BIGNUM *bn = ASN1_INTEGER_to_BN(serialNumber, NULL);
868             char *decimal = BN_bn2dec(bn);
869             result = apr_pstrcat(p, "{ serialNumber ", decimal,
870                     ", issuer rdnSequence:\"",
871                     modssl_X509_NAME_to_string(p, issuer, 0), "\" }", NULL);
872             OPENSSL_free(decimal);
873             BN_free(bn);
874         }
875     }
876
877     X509_free(xs);
878     return result;
879 }
880
881 static char *ssl_var_lookup_ssl_cert_PEM(apr_pool_t *p, X509 *xs)
882 {
883     char *result;
884     BIO *bio;
885     int n;
886
887     if ((bio = BIO_new(BIO_s_mem())) == NULL)
888         return NULL;
889     PEM_write_bio_X509(bio, xs);
890     n = BIO_pending(bio);
891     result = apr_pcalloc(p, n+1);
892     n = BIO_read(bio, result, n);
893     result[n] = NUL;
894     BIO_free(bio);
895     return result;
896 }
897
898 static char *ssl_var_lookup_ssl_cert_verify(apr_pool_t *p, SSLConnRec *sslconn)
899 {
900     char *result;
901     long vrc;
902     const char *verr;
903     const char *vinfo;
904     SSL *ssl;
905     X509 *xs;
906
907     result = NULL;
908     ssl   = sslconn->ssl;
909     verr  = sslconn->verify_error;
910     vinfo = sslconn->verify_info;
911     vrc   = SSL_get_verify_result(ssl);
912     xs    = SSL_get_peer_certificate(ssl);
913
914     if (vrc == X509_V_OK && verr == NULL && xs == NULL)
915         /* no client verification done at all */
916         result = "NONE";
917     else if (vrc == X509_V_OK && verr == NULL && vinfo == NULL && xs != NULL)
918         /* client verification done successful */
919         result = "SUCCESS";
920     else if (vrc == X509_V_OK && vinfo != NULL && strEQ(vinfo, "GENEROUS"))
921         /* client verification done in generous way */
922         result = "GENEROUS";
923     else
924         /* client verification failed */
925         result = apr_psprintf(p, "FAILED:%s",
926                               verr ? verr : X509_verify_cert_error_string(vrc));
927
928     if (xs)
929         X509_free(xs);
930     return result;
931 }
932
933 static char *ssl_var_lookup_ssl_cipher(apr_pool_t *p, SSLConnRec *sslconn, char *var)
934 {
935     char *result;
936     BOOL resdup;
937     int usekeysize, algkeysize;
938     SSL *ssl;
939
940     result = NULL;
941     resdup = TRUE;
942
943     ssl = sslconn->ssl;
944     ssl_var_lookup_ssl_cipher_bits(ssl, &usekeysize, &algkeysize);
945
946     if (ssl && strEQ(var, "")) {
947         MODSSL_SSL_CIPHER_CONST SSL_CIPHER *cipher = SSL_get_current_cipher(ssl);
948         result = (cipher != NULL ? (char *)SSL_CIPHER_get_name(cipher) : NULL);
949     }
950     else if (strcEQ(var, "_EXPORT"))
951         result = (usekeysize < 56 ? "true" : "false");
952     else if (strcEQ(var, "_USEKEYSIZE")) {
953         result = apr_itoa(p, usekeysize);
954         resdup = FALSE;
955     }
956     else if (strcEQ(var, "_ALGKEYSIZE")) {
957         result = apr_itoa(p, algkeysize);
958         resdup = FALSE;
959     }
960
961     if (result != NULL && resdup)
962         result = apr_pstrdup(p, result);
963     return result;
964 }
965
966 static void ssl_var_lookup_ssl_cipher_bits(SSL *ssl, int *usekeysize, int *algkeysize)
967 {
968     MODSSL_SSL_CIPHER_CONST SSL_CIPHER *cipher;
969
970     *usekeysize = 0;
971     *algkeysize = 0;
972     if (ssl != NULL)
973         if ((cipher = SSL_get_current_cipher(ssl)) != NULL)
974             *usekeysize = SSL_CIPHER_get_bits(cipher, algkeysize);
975     return;
976 }
977
978 static char *ssl_var_lookup_ssl_version(apr_pool_t *p, char *var)
979 {
980     if (strEQ(var, "INTERFACE")) {
981         return apr_pstrdup(p, var_interface);
982     }
983     else if (strEQ(var, "LIBRARY_INTERFACE")) {
984         return apr_pstrdup(p, var_library_interface);
985     }
986     else if (strEQ(var, "LIBRARY")) {
987         return apr_pstrdup(p, var_library);
988     }
989     return NULL;
990 }
991
992 /* Add each RDN in 'xn' to the table 't' where the NID is present in
993  * 'nids', using key prefix 'pfx'.  */
994 static void extract_dn(apr_table_t *t, apr_hash_t *nids, const char *pfx,
995                        X509_NAME *xn, apr_pool_t *p)
996 {
997 #if OPENSSL_VERSION_NUMBER < 0x10100000L
998     STACK_OF(X509_NAME_ENTRY) *ents = xn->entries;
999 #endif
1000     X509_NAME_ENTRY *xsne;
1001     apr_hash_t *count;
1002     int i, nid;
1003
1004     /* Hash of (int) NID -> (int *) counter to count each time an RDN
1005      * with the given NID has been seen. */
1006     count = apr_hash_make(p);
1007
1008     /* For each RDN... */
1009 #if OPENSSL_VERSION_NUMBER < 0x10100000L
1010     for (i = 0; i < sk_X509_NAME_ENTRY_num(ents); i++) {
1011          const char *tag;
1012
1013          xsne = sk_X509_NAME_ENTRY_value(ents, i);
1014 #else
1015     for (i = 0; i < X509_NAME_entry_count(xn); i++) {
1016          const char *tag;
1017          xsne = X509_NAME_get_entry(xn, i);
1018 #endif
1019
1020          /* Retrieve the nid, and check whether this is one of the nids
1021           * which are to be extracted. */
1022          nid = OBJ_obj2nid((ASN1_OBJECT *)X509_NAME_ENTRY_get_object(xsne));
1023
1024          tag = apr_hash_get(nids, &nid, sizeof nid);
1025          if (tag) {
1026              const char *key;
1027              int *dup;
1028              char *value;
1029
1030              /* Check whether a variable with this nid was already
1031               * been used; if so, use the foo_N=bar syntax. */
1032              dup = apr_hash_get(count, &nid, sizeof nid);
1033              if (dup) {
1034                  key = apr_psprintf(p, "%s%s_%d", pfx, tag, ++(*dup));
1035              }
1036              else {
1037                  /* Otherwise, use the plain foo=bar syntax. */
1038                  dup = apr_pcalloc(p, sizeof *dup);
1039                  apr_hash_set(count, &nid, sizeof nid, dup);
1040                  key = apr_pstrcat(p, pfx, tag, NULL);
1041              }
1042              value = modssl_X509_NAME_ENTRY_to_string(p, xsne);
1043              apr_table_setn(t, key, value);
1044          }
1045     }
1046 }
1047
1048 void modssl_var_extract_dns(apr_table_t *t, SSL *ssl, apr_pool_t *p)
1049 {
1050     apr_hash_t *nids;
1051     unsigned n;
1052     X509 *xs;
1053
1054     /* Build up a hash table of (int *)NID->(char *)short-name for all
1055      * the tags which are to be extracted: */
1056     nids = apr_hash_make(p);
1057     for (n = 0; ssl_var_lookup_ssl_cert_dn_rec[n].name; n++) {
1058         if (ssl_var_lookup_ssl_cert_dn_rec[n].extract) {
1059             apr_hash_set(nids, &ssl_var_lookup_ssl_cert_dn_rec[n].nid,
1060                          sizeof(ssl_var_lookup_ssl_cert_dn_rec[0].nid),
1061                          ssl_var_lookup_ssl_cert_dn_rec[n].name);
1062         }
1063     }
1064
1065     /* Extract the server cert DNS -- note that the refcount does NOT
1066      * increase: */
1067     xs = SSL_get_certificate(ssl);
1068     if (xs) {
1069         extract_dn(t, nids, "SSL_SERVER_S_DN_", X509_get_subject_name(xs), p);
1070         extract_dn(t, nids, "SSL_SERVER_I_DN_", X509_get_issuer_name(xs), p);
1071     }
1072
1073     /* Extract the client cert DNs -- note that the refcount DOES
1074      * increase: */
1075     xs = SSL_get_peer_certificate(ssl);
1076     if (xs) {
1077         extract_dn(t, nids, "SSL_CLIENT_S_DN_", X509_get_subject_name(xs), p);
1078         extract_dn(t, nids, "SSL_CLIENT_I_DN_", X509_get_issuer_name(xs), p);
1079         X509_free(xs);
1080     }
1081 }
1082
1083 static void extract_san_array(apr_table_t *t, const char *pfx,
1084                               apr_array_header_t *entries, apr_pool_t *p)
1085 {
1086     int i;
1087
1088     for (i = 0; i < entries->nelts; i++) {
1089         const char *key = apr_psprintf(p, "%s_%d", pfx, i);
1090         apr_table_setn(t, key, APR_ARRAY_IDX(entries, i, const char *));
1091     }
1092 }
1093
1094 void modssl_var_extract_san_entries(apr_table_t *t, SSL *ssl, apr_pool_t *p)
1095 {
1096     X509 *xs;
1097     apr_array_header_t *entries;
1098
1099     /* subjectAltName entries of the server certificate */
1100     xs = SSL_get_certificate(ssl);
1101     if (xs) {
1102         if (modssl_X509_getSAN(p, xs, GEN_EMAIL, NULL, -1, &entries)) {
1103             extract_san_array(t, "SSL_SERVER_SAN_Email", entries, p);
1104         }
1105         if (modssl_X509_getSAN(p, xs, GEN_DNS, NULL, -1, &entries)) {
1106             extract_san_array(t, "SSL_SERVER_SAN_DNS", entries, p);
1107         }
1108         if (modssl_X509_getSAN(p, xs, GEN_OTHERNAME, "id-on-dnsSRV", -1,
1109                                &entries)) {
1110             extract_san_array(t, "SSL_SERVER_SAN_OTHER_dnsSRV", entries, p);
1111         }
1112         /* no need to free xs (refcount does not increase) */
1113     }
1114
1115     /* subjectAltName entries of the client certificate */
1116     xs = SSL_get_peer_certificate(ssl);
1117     if (xs) {
1118         if (modssl_X509_getSAN(p, xs, GEN_EMAIL, NULL, -1, &entries)) {
1119             extract_san_array(t, "SSL_CLIENT_SAN_Email", entries, p);
1120         }
1121         if (modssl_X509_getSAN(p, xs, GEN_DNS, NULL, -1, &entries)) {
1122             extract_san_array(t, "SSL_CLIENT_SAN_DNS", entries, p);
1123         }
1124         if (modssl_X509_getSAN(p, xs, GEN_OTHERNAME, "msUPN", -1, &entries)) {
1125             extract_san_array(t, "SSL_CLIENT_SAN_OTHER_msUPN", entries, p);
1126         }
1127         X509_free(xs);
1128     }
1129 }
1130
1131 /* For an extension type which OpenSSL does not recognize, attempt to
1132  * parse the extension type as a primitive string.  This will fail for
1133  * any structured extension type per the docs.  Returns non-zero on
1134  * success and writes the string to the given bio. */
1135 static int dump_extn_value(BIO *bio, ASN1_OCTET_STRING *str)
1136 {
1137     const unsigned char *pp = str->data;
1138     ASN1_STRING *ret = ASN1_STRING_new();
1139     int rv = 0;
1140
1141     /* This allows UTF8String, IA5String, VisibleString, or BMPString;
1142      * conversion to UTF-8 is forced. */
1143     if (d2i_DISPLAYTEXT(&ret, &pp, str->length)) {
1144         ASN1_STRING_print_ex(bio, ret, ASN1_STRFLGS_UTF8_CONVERT);
1145         rv = 1;
1146     }
1147
1148     ASN1_STRING_free(ret);
1149     return rv;
1150 }
1151
1152 apr_array_header_t *ssl_ext_list(apr_pool_t *p, conn_rec *c, int peer,
1153                                  const char *extension)
1154 {
1155     SSLConnRec *sslconn = ssl_get_effective_config(c);
1156     SSL *ssl = NULL;
1157     apr_array_header_t *array = NULL;
1158     X509 *xs = NULL;
1159     ASN1_OBJECT *oid = NULL;
1160     int count = 0, j;
1161
1162     if (!sslconn || !sslconn->ssl || !extension) {
1163         return NULL;
1164     }
1165     ssl = sslconn->ssl;
1166
1167     /* We accept the "extension" string to be converted as
1168      * a long name (nsComment), short name (DN) or
1169      * numeric OID (1.2.3.4).
1170      */
1171     oid = OBJ_txt2obj(extension, 0);
1172     if (!oid) {
1173         ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(01970)
1174                       "could not parse OID '%s'", extension);
1175         ERR_clear_error();
1176         return NULL;
1177     }
1178
1179     xs = peer ? SSL_get_peer_certificate(ssl) : SSL_get_certificate(ssl);
1180     if (xs == NULL) {
1181         return NULL;
1182     }
1183
1184     count = X509_get_ext_count(xs);
1185     /* Create an array large enough to accomodate every extension. This is
1186      * likely overkill, but safe.
1187      */
1188     array = apr_array_make(p, count, sizeof(char *));
1189     for (j = 0; j < count; j++) {
1190         X509_EXTENSION *ext = X509_get_ext(xs, j);
1191
1192 #if OPENSSL_VERSION_NUMBER < 0x10100000L
1193         if (OBJ_cmp(ext->object, oid) == 0) {
1194 #else
1195         if (OBJ_cmp(X509_EXTENSION_get_object(ext), oid) == 0) {
1196 #endif
1197             BIO *bio = BIO_new(BIO_s_mem());
1198
1199             /* We want to obtain a string representation of the extensions
1200              * value and add it to the array we're building.
1201              * X509V3_EXT_print() doesn't know about all the possible
1202              * data types, but the value is stored as an ASN1_OCTET_STRING
1203              * allowing us a fallback in case of X509V3_EXT_print
1204              * not knowing how to handle the data.
1205              */
1206             if (X509V3_EXT_print(bio, ext, 0, 0) == 1 ||
1207                 dump_extn_value(bio, X509_EXTENSION_get_data(ext)) == 1) {
1208                 BUF_MEM *buf;
1209                 char **ptr = apr_array_push(array);
1210                 BIO_get_mem_ptr(bio, &buf);
1211                 *ptr = apr_pstrmemdup(p, buf->data, buf->length);
1212             } else {
1213                 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(01971)
1214                               "Found an extension '%s', but failed to "
1215                               "create a string from it", extension);
1216             }
1217             BIO_vfree(bio);
1218         }
1219     }
1220
1221     if (array->nelts == 0)
1222         array = NULL;
1223
1224     if (peer) {
1225         /* only SSL_get_peer_certificate raises the refcount */
1226         X509_free(xs);
1227     }
1228
1229     ASN1_OBJECT_free(oid);
1230     ERR_clear_error();
1231     return array;
1232 }
1233
1234 static char *ssl_var_lookup_ssl_compress_meth(SSL *ssl)
1235 {
1236     char *result = "NULL";
1237 #ifndef OPENSSL_NO_COMP
1238     SSL_SESSION *pSession = SSL_get_session(ssl);
1239
1240     if (pSession) {
1241 #ifdef OPENSSL_NO_SSL_INTERN
1242         switch (SSL_SESSION_get_compress_id(pSession)) {
1243 #else
1244         switch (pSession->compress_meth) {
1245 #endif
1246         case 0:
1247             /* default "NULL" already set */
1248             break;
1249
1250             /* Defined by RFC 3749, deflate is coded by "1" */
1251         case 1:
1252             result = "DEFLATE";
1253             break;
1254
1255             /* IANA assigned compression number for LZS */
1256         case 0x40:
1257             result = "LZS";
1258             break;
1259
1260         default:
1261             result = "UNKNOWN";
1262             break;
1263         }
1264     }
1265 #endif
1266     return result;
1267 }
1268
1269 /*  _________________________________________________________________
1270 **
1271 **  SSL Extension to mod_log_config
1272 **  _________________________________________________________________
1273 */
1274
1275 #include "../../modules/loggers/mod_log_config.h"
1276
1277 static const char *ssl_var_log_handler_c(request_rec *r, char *a);
1278 static const char *ssl_var_log_handler_x(request_rec *r, char *a);
1279
1280 /*
1281  * register us for the mod_log_config function registering phase
1282  * to establish %{...}c and to be able to expand %{...}x variables.
1283  */
1284 void ssl_var_log_config_register(apr_pool_t *p)
1285 {
1286     static APR_OPTIONAL_FN_TYPE(ap_register_log_handler) *log_pfn_register;
1287
1288     log_pfn_register = APR_RETRIEVE_OPTIONAL_FN(ap_register_log_handler);
1289
1290     if (log_pfn_register) {
1291         log_pfn_register(p, "c", ssl_var_log_handler_c, 0);
1292         log_pfn_register(p, "x", ssl_var_log_handler_x, 0);
1293     }
1294     return;
1295 }
1296
1297 /*
1298  * implement the %{..}c log function
1299  * (we are the only function)
1300  */
1301 static const char *ssl_var_log_handler_c(request_rec *r, char *a)
1302 {
1303     SSLConnRec *sslconn = ssl_get_effective_config(r->connection);
1304     char *result;
1305
1306     if (sslconn == NULL || sslconn->ssl == NULL)
1307         return NULL;
1308     result = NULL;
1309     if (strEQ(a, "version"))
1310         result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_PROTOCOL");
1311     else if (strEQ(a, "cipher"))
1312         result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CIPHER");
1313     else if (strEQ(a, "subjectdn") || strEQ(a, "clientcert"))
1314         result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CLIENT_S_DN");
1315     else if (strEQ(a, "issuerdn") || strEQ(a, "cacert"))
1316         result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CLIENT_I_DN");
1317     else if (strEQ(a, "errcode"))
1318         result = "-";
1319     else if (strEQ(a, "errstr"))
1320         result = (char *)sslconn->verify_error;
1321     if (result != NULL && result[0] == NUL)
1322         result = NULL;
1323     return result;
1324 }
1325
1326 /*
1327  * extend the implementation of the %{..}x log function
1328  * (there can be more functions)
1329  */
1330 static const char *ssl_var_log_handler_x(request_rec *r, char *a)
1331 {
1332     char *result;
1333
1334     result = ssl_var_lookup(r->pool, r->server, r->connection, r, a);
1335     if (result != NULL && result[0] == NUL)
1336         result = NULL;
1337     return result;
1338 }
1339
1340