1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * _ __ ___ ___ __| | ___ ___| | mod_ssl
19 * | '_ ` _ \ / _ \ / _` | / __/ __| | Apache Interface to OpenSSL
20 * | | | | | | (_) | (_| | \__ \__ \ |
21 * |_| |_| |_|\___/ \__,_|___|___/___/_|
24 * Variable Lookup Facility
26 /* ``Those of you who think they
27 know everything are very annoying
28 to those of us who do.''
30 #include "ssl_private.h"
36 /* _________________________________________________________________
39 ** _________________________________________________________________
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);
58 static SSLConnRec *ssl_get_effective_config(conn_rec *c)
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);
68 static int ssl_is_https(conn_rec *c)
70 SSLConnRec *sslconn = ssl_get_effective_config(c);
71 return sslconn && sslconn->ssl;
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).
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:"
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)
86 SSLConnRec *sslconn = ssl_get_effective_config(c);
89 const unsigned char *data;
90 unsigned char cb[TLS_CB_MAX], *retbuf;
94 if (!sslconn || !sslconn->ssl) {
97 if (strcEQ(type, "SERVER_TLS_UNIQUE")) {
98 l = SSL_get_peer_finished(sslconn->ssl, cb, TLS_CB_MAX);
100 else if (strcEQ(type, "CLIENT_TLS_UNIQUE")) {
101 l = SSL_get_finished(sslconn->ssl, cb, TLS_CB_MAX);
103 else if (strcEQ(type, "SERVER_TLS_SERVER_END_POINT")) {
104 x = SSL_get_certificate(sslconn->ssl);
106 else if (strcEQ(type, "CLIENT_TLS_SERVER_END_POINT")) {
107 x = SSL_get_peer_certificate(sslconn->ssl);
110 preflen = sizeof(TLS_UNIQUE_PREFIX) -1;
111 prefix = TLS_UNIQUE_PREFIX;
114 else if (x != NULL) {
117 #if OPENSSL_VERSION_NUMBER < 0x10100000L
118 md = EVP_get_digestbynid(OBJ_obj2nid(x->sig_alg->algorithm));
120 md = EVP_get_digestbynid(X509_get_signature_nid(x));
122 /* Override digest as specified by RFC 5929 section 4.1. */
123 if (md == NULL || md == EVP_md5() || md == EVP_sha1()) {
126 if (!X509_digest(x, md, cb, &l)) {
130 preflen = sizeof(TLS_SERVER_END_POINT_PREFIX) - 1;
131 prefix = TLS_SERVER_END_POINT_PREFIX;
138 retbuf = apr_palloc(p, preflen + l);
139 memcpy(retbuf, prefix, preflen);
140 memcpy(&retbuf[preflen], data, l);
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;
151 static apr_array_header_t *expr_peer_ext_list_fn(ap_expr_eval_ctx_t *ctx,
155 return ssl_ext_list(ctx->p, ctx->c, 1, arg);
158 static const char *expr_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
160 char *var = (char *)data;
161 SSLConnRec *sslconn = ssl_get_effective_config(ctx->c);
163 return sslconn ? ssl_var_lookup_ssl(ctx->p, sslconn, ctx->r, var) : NULL;
166 static const char *expr_func_fn(ap_expr_eval_ctx_t *ctx, const void *data,
169 char *var = (char *)arg;
171 return var ? ssl_var_lookup(ctx->p, ctx->s, ctx->c, ctx->r, var) : NULL;
174 static int ssl_expr_lookup(ap_expr_lookup_parms *parms)
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
182 if (strcEQn(parms->name, "SSL_", 4)) {
183 *parms->func = expr_var_fn;
184 *parms->data = parms->name + 4;
188 case AP_EXPR_FUNC_STRING:
189 /* Function SSL() is implemented by us.
191 if (strcEQ(parms->name, "SSL")) {
192 *parms->func = expr_func_fn;
197 case AP_EXPR_FUNC_LIST:
198 if (strcEQ(parms->name, "PeerExtList")) {
199 *parms->func = expr_peer_ext_list_fn;
200 *parms->data = "PeerExtList";
209 void ssl_var_register(apr_pool_t *p)
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);
218 /* Perform once-per-process library version determination: */
219 var_library = apr_pstrdup(p, MODSSL_LIBRARY_DYNTEXT);
221 if ((cp = strchr(var_library, ' ')) != NULL) {
223 if ((cp2 = strchr(cp, ' ')) != NULL)
227 if ((cp = strchr(var_library_interface, ' ')) != NULL) {
229 if ((cp2 = strchr(cp, ' ')) != NULL)
233 ap_hook_expr_lookup(ssl_expr_lookup, NULL, NULL, APR_HOOK_MIDDLE);
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)
239 SSLModConfigRec *mc = myModConfig(s);
248 * When no pool is given try to find one
260 * Request dependent stuff
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);
287 if (strcEQ(var, "REQUEST_METHOD"))
289 else if (strcEQ(var, "REQUEST_SCHEME"))
290 result = ap_http_scheme(r);
291 else if (strcEQ(var, "REQUEST_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"))
307 if (strcEQn(var, "SSL", 3)) break; /* shortcut common case */
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;
322 if (strcEQ(var, "PATH_INFO"))
323 result = r->path_info;
324 else if (strcEQ(var, "QUERY_STRING"))
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);
337 result = apr_table_get(r->subprocess_env, var+4);
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)
360 * Totally independent stuff
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);
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);
377 #define MKTIMESTR(format, tmfield) \
378 apr_time_exp_lt(&tm, apr_time_now()); \
379 result = apr_psprintf(p, format, tm.tmfield); \
381 else if (strcEQ(var, "TIME_MON")) {
382 MKTIMESTR("%02d", tm_mon+1)
384 else if (strcEQ(var, "TIME_DAY")) {
385 MKTIMESTR("%02d", tm_mday)
387 else if (strcEQ(var, "TIME_HOUR")) {
388 MKTIMESTR("%02d", tm_hour)
390 else if (strcEQ(var, "TIME_MIN")) {
391 MKTIMESTR("%02d", tm_min)
393 else if (strcEQ(var, "TIME_SEC")) {
394 MKTIMESTR("%02d", tm_sec)
396 else if (strcEQ(var, "TIME_WDAY")) {
397 MKTIMESTR("%d", tm_wday)
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);
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);
413 if (result != NULL && resdup)
414 result = apr_pstrdup(p, result);
417 return (char *)result;
420 static char *ssl_var_lookup_ssl(apr_pool_t *p, SSLConnRec *sslconn,
421 request_rec *r, char *var)
431 if (strlen(var) > 8 && strcEQn(var, "VERSION_", 8)) {
432 result = ssl_var_lookup_ssl_version(p, var+8);
434 else if (ssl != NULL && strcEQ(var, "PROTOCOL")) {
435 result = (char *)SSL_get_version(ssl);
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);
444 #ifdef OPENSSL_NO_SSL_INTERN
445 id = (unsigned char *)SSL_SESSION_get_id(pSession, &idlen);
447 id = pSession->session_id;
448 idlen = pSession->session_id_length;
451 result = apr_pstrdup(p, modssl_SSL_SESSION_id2sz(id, idlen,
455 else if(ssl != NULL && strcEQ(var, "SESSION_RESUMED")) {
456 if (SSL_session_reused(ssl) == 1)
461 else if (ssl != NULL && strlen(var) >= 6 && strcEQn(var, "CIPHER", 6)) {
462 result = ssl_var_lookup_ssl_cipher(p, sslconn, var+6);
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);
468 else if (ssl != NULL && strcEQ(var, "CLIENT_CERT_RFC4523_CEA")) {
469 result = ssl_var_lookup_ssl_cert_rfc4523_cea(p, ssl);
471 else if (ssl != NULL && strcEQ(var, "CLIENT_VERIFY")) {
472 result = ssl_var_lookup_ssl_cert_verify(p, sslconn);
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);
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).
488 else if (ssl != NULL && strcEQ(var, "COMPRESS_METHOD")) {
489 result = ssl_var_lookup_ssl_compress_meth(ssl);
492 else if (ssl != NULL && strcEQ(var, "TLS_SNI")) {
493 result = apr_pstrdup(p, SSL_get_servername(ssl,
494 TLSEXT_NAMETYPE_host_name));
497 else if (ssl != NULL && strcEQ(var, "SECURE_RENEG")) {
499 #ifdef SSL_get_secure_renegotiation_support
500 flag = SSL_get_secure_renegotiation_support(ssl);
502 result = apr_pstrdup(p, flag ? "true" : "false");
505 else if (ssl != NULL && strcEQ(var, "SRP_USER")) {
506 if ((result = SSL_get_srp_username(ssl)) != NULL) {
507 result = apr_pstrdup(p, result);
510 else if (ssl != NULL && strcEQ(var, "SRP_USERINFO")) {
511 if ((result = SSL_get_srp_userinfo(ssl)) != NULL) {
512 result = apr_pstrdup(p, result);
520 static char *ssl_var_lookup_ssl_cert_dn_oneline(apr_pool_t *p, request_rec *r,
525 int legacy_format = 0;
528 legacy_format = dc->nOptions & SSL_OPT_LEGACYDNFORMAT;
531 char *cp = X509_NAME_oneline(xsname, NULL, 0);
532 result = apr_pstrdup(p, cp);
538 unsigned long flags = XN_FLAG_RFC2253 & ~ASN1_STRFLGS_ESC_MSB;
539 if ((bio = BIO_new(BIO_s_mem())) == NULL)
541 X509_NAME_print_ex(bio, xsname, 0, flags);
542 n = BIO_pending(bio);
544 result = apr_palloc(p, n+1);
545 n = BIO_read(bio, result, n);
553 static char *ssl_var_lookup_ssl_cert(apr_pool_t *p, request_rec *r, X509 *xs,
564 if (strcEQ(var, "M_VERSION")) {
565 result = apr_psprintf(p, "%lu", X509_get_version(xs)+1);
568 else if (strcEQ(var, "M_SERIAL")) {
569 result = ssl_var_lookup_ssl_cert_serial(p, xs);
571 else if (strcEQ(var, "V_START")) {
572 result = ssl_var_lookup_ssl_cert_valid(p, X509_get_notBefore(xs));
574 else if (strcEQ(var, "V_END")) {
575 result = ssl_var_lookup_ssl_cert_valid(p, X509_get_notAfter(xs));
577 else if (strcEQ(var, "V_REMAIN")) {
578 result = ssl_var_lookup_ssl_cert_remain(p, X509_get_notAfter(xs));
581 else if (*var && strcEQ(var+1, "_DN")) {
583 xsname = X509_get_subject_name(xs);
584 else if (*var == 'I')
585 xsname = X509_get_issuer_name(xs);
588 result = ssl_var_lookup_ssl_cert_dn_oneline(p, r, xsname);
591 else if (strlen(var) > 5 && strcEQn(var+1, "_DN_", 4)) {
593 xsname = X509_get_subject_name(xs);
594 else if (*var == 'I')
595 xsname = X509_get_issuer_name(xs);
598 result = ssl_var_lookup_ssl_cert_dn(p, xsname, var+5);
601 else if (strlen(var) > 4 && strcEQn(var, "SAN_", 4)) {
602 result = ssl_var_lookup_ssl_cert_san(p, xs, var+4);
605 else if (strcEQ(var, "A_SIG")) {
606 #if OPENSSL_VERSION_NUMBER < 0x10100000L
607 nid = OBJ_obj2nid((ASN1_OBJECT *)(xs->cert_info->signature->algorithm));
610 X509_ALGOR_get0(&paobj, NULL, NULL, X509_get0_tbs_sigalg(xs));
611 nid = OBJ_obj2nid(paobj);
613 result = apr_pstrdup(p,
614 (nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(nid));
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));
622 X509_PUBKEY_get0_param(&paobj, NULL, 0, NULL, X509_get_X509_PUBKEY(xs));
623 nid = OBJ_obj2nid(paobj);
625 result = apr_pstrdup(p,
626 (nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(nid));
629 else if (strcEQ(var, "CERT")) {
630 result = ssl_var_lookup_ssl_cert_PEM(p, xs);
634 result = apr_pstrdup(p, result);
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
641 static const struct {
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 },
659 { "UID", NID_userId, 1 },
661 { "Email", NID_pkcs9_emailAddress, 1 },
665 static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, char *var)
668 X509_NAME_ENTRY *xsne;
669 int i, j, n, idx = 0;
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)) {
678 varlen = strlen(var);
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) *)
690 xsne = sk_X509_NAME_ENTRY_value((STACK_OF(X509_NAME_ENTRY) *)
693 for (j = 0; j < X509_NAME_entry_count(xsname); j++) {
694 xsne = X509_NAME_get_entry(xsname, j);
697 n =OBJ_obj2nid((ASN1_OBJECT *)X509_NAME_ENTRY_get_object(xsne));
699 if (n == ssl_var_lookup_ssl_cert_dn_rec[i].nid && idx-- == 0) {
700 result = modssl_X509_NAME_ENTRY_to_string(p, xsne);
710 static char *ssl_var_lookup_ssl_cert_san(apr_pool_t *p, X509 *xs, char *var)
713 const char *onf = NULL;
714 apr_array_header_t *entries;
716 if (strcEQn(var, "Email_", 6)) {
720 else if (strcEQn(var, "DNS_", 4)) {
724 else if (strcEQn(var, "OTHER_", 6)) {
725 type = GEN_OTHERNAME;
727 if (strEQn(var, "msUPN_", 6)) {
731 else if (strEQn(var, "dnsSRV_", 7)) {
733 onf = "id-on-dnsSRV";
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)))
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 *);
753 static char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_TIME *tm)
759 if ((bio = BIO_new(BIO_s_mem())) == 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);
770 #define DIGIT2NUM(x) (((x)[0] - '0') * 10 + (x)[1] - '0')
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)
776 apr_time_t then, now = apr_time_now();
777 apr_time_exp_t exp = {0};
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
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");
790 if (tm->type == V_ASN1_UTCTIME) {
791 exp.tm_year = DIGIT2NUM(tm->data);
792 if (exp.tm_year <= 50) exp.tm_year += 100;
795 exp.tm_year = DIGIT2NUM(tm->data) * 100 + DIGIT2NUM(tm->data + 2) - 1900;
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);
805 if (apr_time_exp_gmt_get(&then, &exp) != APR_SUCCESS) {
806 return apr_pstrdup(p, "0");
809 diff = (long)((apr_time_sec(then) - apr_time_sec(now)) / (60*60*24));
811 return diff > 0 ? apr_ltoa(p, diff) : apr_pstrdup(p, "0");
814 static char *ssl_var_lookup_ssl_cert_serial(apr_pool_t *p, X509 *xs)
820 if ((bio = BIO_new(BIO_s_mem())) == 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);
831 static char *ssl_var_lookup_ssl_cert_chain(apr_pool_t *p, STACK_OF(X509) *sk, char *var)
839 if (strspn(var, "0123456789") == strlen(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);
850 static char *ssl_var_lookup_ssl_cert_rfc4523_cea(apr_pool_t *p, SSL *ssl)
855 ASN1_INTEGER *serialNumber;
857 if (!(xs = SSL_get_peer_certificate(ssl))) {
863 serialNumber = X509_get_serialNumber(xs);
865 X509_NAME *issuer = X509_get_issuer_name(xs);
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);
881 static char *ssl_var_lookup_ssl_cert_PEM(apr_pool_t *p, X509 *xs)
887 if ((bio = BIO_new(BIO_s_mem())) == 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);
898 static char *ssl_var_lookup_ssl_cert_verify(apr_pool_t *p, SSLConnRec *sslconn)
909 verr = sslconn->verify_error;
910 vinfo = sslconn->verify_info;
911 vrc = SSL_get_verify_result(ssl);
912 xs = SSL_get_peer_certificate(ssl);
914 if (vrc == X509_V_OK && verr == NULL && xs == NULL)
915 /* no client verification done at all */
917 else if (vrc == X509_V_OK && verr == NULL && vinfo == NULL && xs != NULL)
918 /* client verification done successful */
920 else if (vrc == X509_V_OK && vinfo != NULL && strEQ(vinfo, "GENEROUS"))
921 /* client verification done in generous way */
924 /* client verification failed */
925 result = apr_psprintf(p, "FAILED:%s",
926 verr ? verr : X509_verify_cert_error_string(vrc));
933 static char *ssl_var_lookup_ssl_cipher(apr_pool_t *p, SSLConnRec *sslconn, char *var)
937 int usekeysize, algkeysize;
944 ssl_var_lookup_ssl_cipher_bits(ssl, &usekeysize, &algkeysize);
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);
950 else if (strcEQ(var, "_EXPORT"))
951 result = (usekeysize < 56 ? "true" : "false");
952 else if (strcEQ(var, "_USEKEYSIZE")) {
953 result = apr_itoa(p, usekeysize);
956 else if (strcEQ(var, "_ALGKEYSIZE")) {
957 result = apr_itoa(p, algkeysize);
961 if (result != NULL && resdup)
962 result = apr_pstrdup(p, result);
966 static void ssl_var_lookup_ssl_cipher_bits(SSL *ssl, int *usekeysize, int *algkeysize)
968 MODSSL_SSL_CIPHER_CONST SSL_CIPHER *cipher;
973 if ((cipher = SSL_get_current_cipher(ssl)) != NULL)
974 *usekeysize = SSL_CIPHER_get_bits(cipher, algkeysize);
978 static char *ssl_var_lookup_ssl_version(apr_pool_t *p, char *var)
980 if (strEQ(var, "INTERFACE")) {
981 return apr_pstrdup(p, var_interface);
983 else if (strEQ(var, "LIBRARY_INTERFACE")) {
984 return apr_pstrdup(p, var_library_interface);
986 else if (strEQ(var, "LIBRARY")) {
987 return apr_pstrdup(p, var_library);
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)
997 #if OPENSSL_VERSION_NUMBER < 0x10100000L
998 STACK_OF(X509_NAME_ENTRY) *ents = xn->entries;
1000 X509_NAME_ENTRY *xsne;
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);
1008 /* For each RDN... */
1009 #if OPENSSL_VERSION_NUMBER < 0x10100000L
1010 for (i = 0; i < sk_X509_NAME_ENTRY_num(ents); i++) {
1013 xsne = sk_X509_NAME_ENTRY_value(ents, i);
1015 for (i = 0; i < X509_NAME_entry_count(xn); i++) {
1017 xsne = X509_NAME_get_entry(xn, i);
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));
1024 tag = apr_hash_get(nids, &nid, sizeof nid);
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);
1034 key = apr_psprintf(p, "%s%s_%d", pfx, tag, ++(*dup));
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);
1042 value = modssl_X509_NAME_ENTRY_to_string(p, xsne);
1043 apr_table_setn(t, key, value);
1048 void modssl_var_extract_dns(apr_table_t *t, SSL *ssl, apr_pool_t *p)
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);
1065 /* Extract the server cert DNS -- note that the refcount does NOT
1067 xs = SSL_get_certificate(ssl);
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);
1073 /* Extract the client cert DNs -- note that the refcount DOES
1075 xs = SSL_get_peer_certificate(ssl);
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);
1083 static void extract_san_array(apr_table_t *t, const char *pfx,
1084 apr_array_header_t *entries, apr_pool_t *p)
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 *));
1094 void modssl_var_extract_san_entries(apr_table_t *t, SSL *ssl, apr_pool_t *p)
1097 apr_array_header_t *entries;
1099 /* subjectAltName entries of the server certificate */
1100 xs = SSL_get_certificate(ssl);
1102 if (modssl_X509_getSAN(p, xs, GEN_EMAIL, NULL, -1, &entries)) {
1103 extract_san_array(t, "SSL_SERVER_SAN_Email", entries, p);
1105 if (modssl_X509_getSAN(p, xs, GEN_DNS, NULL, -1, &entries)) {
1106 extract_san_array(t, "SSL_SERVER_SAN_DNS", entries, p);
1108 if (modssl_X509_getSAN(p, xs, GEN_OTHERNAME, "id-on-dnsSRV", -1,
1110 extract_san_array(t, "SSL_SERVER_SAN_OTHER_dnsSRV", entries, p);
1112 /* no need to free xs (refcount does not increase) */
1115 /* subjectAltName entries of the client certificate */
1116 xs = SSL_get_peer_certificate(ssl);
1118 if (modssl_X509_getSAN(p, xs, GEN_EMAIL, NULL, -1, &entries)) {
1119 extract_san_array(t, "SSL_CLIENT_SAN_Email", entries, p);
1121 if (modssl_X509_getSAN(p, xs, GEN_DNS, NULL, -1, &entries)) {
1122 extract_san_array(t, "SSL_CLIENT_SAN_DNS", entries, p);
1124 if (modssl_X509_getSAN(p, xs, GEN_OTHERNAME, "msUPN", -1, &entries)) {
1125 extract_san_array(t, "SSL_CLIENT_SAN_OTHER_msUPN", entries, p);
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)
1137 const unsigned char *pp = str->data;
1138 ASN1_STRING *ret = ASN1_STRING_new();
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);
1148 ASN1_STRING_free(ret);
1152 apr_array_header_t *ssl_ext_list(apr_pool_t *p, conn_rec *c, int peer,
1153 const char *extension)
1155 SSLConnRec *sslconn = ssl_get_effective_config(c);
1157 apr_array_header_t *array = NULL;
1159 ASN1_OBJECT *oid = NULL;
1162 if (!sslconn || !sslconn->ssl || !extension) {
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).
1171 oid = OBJ_txt2obj(extension, 0);
1173 ap_log_cerror(APLOG_MARK, APLOG_DEBUG, 0, c, APLOGNO(01970)
1174 "could not parse OID '%s'", extension);
1179 xs = peer ? SSL_get_peer_certificate(ssl) : SSL_get_certificate(ssl);
1184 count = X509_get_ext_count(xs);
1185 /* Create an array large enough to accomodate every extension. This is
1186 * likely overkill, but safe.
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);
1192 #if OPENSSL_VERSION_NUMBER < 0x10100000L
1193 if (OBJ_cmp(ext->object, oid) == 0) {
1195 if (OBJ_cmp(X509_EXTENSION_get_object(ext), oid) == 0) {
1197 BIO *bio = BIO_new(BIO_s_mem());
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.
1206 if (X509V3_EXT_print(bio, ext, 0, 0) == 1 ||
1207 dump_extn_value(bio, X509_EXTENSION_get_data(ext)) == 1) {
1209 char **ptr = apr_array_push(array);
1210 BIO_get_mem_ptr(bio, &buf);
1211 *ptr = apr_pstrmemdup(p, buf->data, buf->length);
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);
1221 if (array->nelts == 0)
1225 /* only SSL_get_peer_certificate raises the refcount */
1229 ASN1_OBJECT_free(oid);
1234 static char *ssl_var_lookup_ssl_compress_meth(SSL *ssl)
1236 char *result = "NULL";
1237 #ifndef OPENSSL_NO_COMP
1238 SSL_SESSION *pSession = SSL_get_session(ssl);
1241 #ifdef OPENSSL_NO_SSL_INTERN
1242 switch (SSL_SESSION_get_compress_id(pSession)) {
1244 switch (pSession->compress_meth) {
1247 /* default "NULL" already set */
1250 /* Defined by RFC 3749, deflate is coded by "1" */
1255 /* IANA assigned compression number for LZS */
1269 /* _________________________________________________________________
1271 ** SSL Extension to mod_log_config
1272 ** _________________________________________________________________
1275 #include "../../modules/loggers/mod_log_config.h"
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);
1281 * register us for the mod_log_config function registering phase
1282 * to establish %{...}c and to be able to expand %{...}x variables.
1284 void ssl_var_log_config_register(apr_pool_t *p)
1286 static APR_OPTIONAL_FN_TYPE(ap_register_log_handler) *log_pfn_register;
1288 log_pfn_register = APR_RETRIEVE_OPTIONAL_FN(ap_register_log_handler);
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);
1298 * implement the %{..}c log function
1299 * (we are the only function)
1301 static const char *ssl_var_log_handler_c(request_rec *r, char *a)
1303 SSLConnRec *sslconn = ssl_get_effective_config(r->connection);
1306 if (sslconn == NULL || sslconn->ssl == 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"))
1319 else if (strEQ(a, "errstr"))
1320 result = (char *)sslconn->verify_error;
1321 if (result != NULL && result[0] == NUL)
1327 * extend the implementation of the %{..}x log function
1328 * (there can be more functions)
1330 static const char *ssl_var_log_handler_x(request_rec *r, char *a)
1334 result = ssl_var_lookup(r->pool, r->server, r->connection, r, a);
1335 if (result != NULL && result[0] == NUL)