Apache HTTPD
ssl_engine_vars.c
Go to the documentation of this file.
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
43static char *ssl_var_lookup_ssl_cert(apr_pool_t *p, request_rec *r, X509 *xs, char *var);
44static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, const char *var);
45static char *ssl_var_lookup_ssl_cert_san(apr_pool_t *p, X509 *xs, char *var);
54static void ssl_var_lookup_ssl_cipher_bits(SSL *ssl, int *usekeysize, int *algkeysize);
55static char *ssl_var_lookup_ssl_version(apr_pool_t *p, char *var);
56static char *ssl_var_lookup_ssl_compress_meth(SSL *ssl);
57
59{
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
69{
71 return (sslconn && sslconn->ssl)? OK : DECLINED;
72}
73
74static const char var_interface[] = "mod_ssl/" AP_SERVER_BASEREVISION;
76static char *var_library = NULL;
77
79 const void *dummy,
80 const char *arg)
81{
82 return ssl_ext_list(ctx->p, ctx->c, 1, arg);
83}
84
85static const char *expr_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
86{
87 char *var = (char *)data;
89
90 return sslconn ? ssl_var_lookup_ssl(ctx->p, sslconn, ctx->r, var) : NULL;
91}
92
93static const char *expr_func_fn(ap_expr_eval_ctx_t *ctx, const void *data,
94 const char *arg)
95{
96 char *var = (char *)arg;
97
98 return var ? ssl_var_lookup(ctx->p, ctx->s, ctx->c, ctx->r, var) : NULL;
99}
100
102{
103 switch (parms->type) {
104 case AP_EXPR_FUNC_VAR:
105 /* for now, we just handle everything that starts with SSL_, but
106 * register our hook as APR_HOOK_LAST
107 * XXX: This can be optimized
108 */
109 if (strcEQn(parms->name, "SSL_", 4)) {
110 *parms->func = expr_var_fn;
111 *parms->data = parms->name + 4;
112 return OK;
113 }
114 break;
116 /* Function SSL() is implemented by us.
117 */
118 if (strcEQ(parms->name, "SSL")) {
119 *parms->func = expr_func_fn;
120 *parms->data = NULL;
121 return OK;
122 }
123 break;
125 if (strcEQ(parms->name, "PeerExtList")) {
127 *parms->data = "PeerExtList";
128 return OK;
129 }
130 break;
131 }
132 return DECLINED;
133}
134
135
137{
138 char *cp, *cp2;
139
143
144 /* Perform once-per-process library version determination: */
146
147 if ((cp = strchr(var_library, ' ')) != NULL) {
148 *cp = '/';
149 if ((cp2 = strchr(cp, ' ')) != NULL)
150 *cp2 = NUL;
151 }
152
153 if ((cp = strchr(var_library_interface, ' ')) != NULL) {
154 *cp = '/';
155 if ((cp2 = strchr(cp, ' ')) != NULL)
156 *cp2 = NUL;
157 }
158
160}
161
162/* This function must remain safe to use for a non-SSL connection. */
164{
166 const char *result;
167 BOOL resdup;
169
170 result = NULL;
171 resdup = TRUE;
172
173 /*
174 * When no pool is given try to find one
175 */
176 if (p == NULL) {
177 if (r != NULL)
178 p = r->pool;
179 else if (c != NULL)
180 p = c->pool;
181 else
182 p = mc->pPool;
183 }
184
185 /*
186 * Request dependent stuff
187 */
188 if (r != NULL) {
189 switch (var[0]) {
190 case 'H':
191 case 'h':
192 if (strcEQ(var, "HTTP_USER_AGENT"))
193 result = apr_table_get(r->headers_in, "User-Agent");
194 else if (strcEQ(var, "HTTP_REFERER"))
195 result = apr_table_get(r->headers_in, "Referer");
196 else if (strcEQ(var, "HTTP_COOKIE"))
197 result = apr_table_get(r->headers_in, "Cookie");
198 else if (strcEQ(var, "HTTP_FORWARDED"))
199 result = apr_table_get(r->headers_in, "Forwarded");
200 else if (strcEQ(var, "HTTP_HOST"))
201 result = apr_table_get(r->headers_in, "Host");
202 else if (strcEQ(var, "HTTP_PROXY_CONNECTION"))
203 result = apr_table_get(r->headers_in, "Proxy-Connection");
204 else if (strcEQ(var, "HTTP_ACCEPT"))
205 result = apr_table_get(r->headers_in, "Accept");
206 else if (strlen(var) > 5 && strcEQn(var, "HTTP:", 5))
207 /* all other headers from which we are still not know about */
209 break;
210
211 case 'R':
212 case 'r':
213 if (strcEQ(var, "REQUEST_METHOD"))
214 result = r->method;
215 else if (strcEQ(var, "REQUEST_SCHEME"))
217 else if (strcEQ(var, "REQUEST_URI"))
218 result = r->uri;
219 else if (strcEQ(var, "REQUEST_FILENAME"))
220 result = r->filename;
221 else if (strcEQ(var, "REMOTE_ADDR"))
223 else if (strcEQ(var, "REMOTE_HOST"))
225 else if (strcEQ(var, "REMOTE_IDENT"))
227 else if (strcEQ(var, "REMOTE_USER"))
228 result = r->user;
229 break;
230
231 case 'S':
232 case 's':
233 if (strcEQn(var, "SSL", 3)) break; /* shortcut common case */
234
235 if (strcEQ(var, "SERVER_ADMIN"))
237 else if (strcEQ(var, "SERVER_NAME"))
239 else if (strcEQ(var, "SERVER_PORT"))
241 else if (strcEQ(var, "SERVER_PROTOCOL"))
242 result = r->protocol;
243 else if (strcEQ(var, "SCRIPT_FILENAME"))
244 result = r->filename;
245 break;
246
247 default:
248 if (strcEQ(var, "PATH_INFO"))
249 result = r->path_info;
250 else if (strcEQ(var, "QUERY_STRING"))
251 result = r->args;
252 else if (strcEQ(var, "IS_SUBREQ"))
253 result = (r->main != NULL ? "true" : "false");
254 else if (strcEQ(var, "DOCUMENT_ROOT"))
256 else if (strcEQ(var, "AUTH_TYPE"))
258 else if (strcEQ(var, "THE_REQUEST"))
260 else if (strlen(var) > 4 && strcEQn(var, "ENV:", 4)) {
262 if (result == NULL)
264 }
265 break;
266 }
267 }
268
269 /*
270 * Connection stuff
271 */
272 if (result == NULL && c != NULL) {
274 if (strlen(var) > 4 && strcEQn(var, "SSL_", 4)
275 && sslconn && sslconn->ssl)
277 else if (strcEQ(var, "HTTPS")) {
278 if (sslconn && sslconn->ssl)
279 result = "on";
280 else
281 result = "off";
282 }
283 }
284
285 /*
286 * Totally independent stuff
287 */
288 if (result == NULL) {
289 if (strlen(var) > 12 && strcEQn(var, "SSL_VERSION_", 12))
291 else if (strcEQ(var, "SERVER_SOFTWARE"))
293 else if (strcEQ(var, "API_VERSION")) {
295 resdup = FALSE;
296 }
297 else if (strcEQ(var, "TIME_YEAR")) {
299 result = apr_psprintf(p, "%02d%02d",
300 (tm.tm_year / 100) + 19, tm.tm_year % 100);
301 resdup = FALSE;
302 }
303#define MKTIMESTR(format, tmfield) \
304 apr_time_exp_lt(&tm, apr_time_now()); \
305 result = apr_psprintf(p, format, tm.tmfield); \
306 resdup = FALSE;
307 else if (strcEQ(var, "TIME_MON")) {
308 MKTIMESTR("%02d", tm_mon+1)
309 }
310 else if (strcEQ(var, "TIME_DAY")) {
311 MKTIMESTR("%02d", tm_mday)
312 }
313 else if (strcEQ(var, "TIME_HOUR")) {
314 MKTIMESTR("%02d", tm_hour)
315 }
316 else if (strcEQ(var, "TIME_MIN")) {
317 MKTIMESTR("%02d", tm_min)
318 }
319 else if (strcEQ(var, "TIME_SEC")) {
320 MKTIMESTR("%02d", tm_sec)
321 }
322 else if (strcEQ(var, "TIME_WDAY")) {
323 MKTIMESTR("%d", tm_wday)
324 }
325 else if (strcEQ(var, "TIME")) {
328 "%02d%02d%02d%02d%02d%02d%02d", (tm.tm_year / 100) + 19,
329 (tm.tm_year % 100), tm.tm_mon+1, tm.tm_mday,
331 resdup = FALSE;
332 }
333 /* all other env-variables from the parent Apache process */
334 else if (strlen(var) > 4 && strcEQn(var, "ENV:", 4)) {
335 result = getenv(var+4);
336 }
337 }
338
339 if (result != NULL && resdup)
341 if (result == NULL)
342 result = "";
343 return (char *)result;
344}
345
347 request_rec *r, char *var)
348{
349 char *result;
350 X509 *xs;
351 STACK_OF(X509) *sk;
352 SSL *ssl;
353
354 result = NULL;
355
356 ssl = sslconn->ssl;
357 if (strlen(var) > 8 && strcEQn(var, "VERSION_", 8)) {
359 }
360 else if (ssl != NULL && strcEQ(var, "PROTOCOL")) {
361 result = (char *)SSL_get_version(ssl);
362 }
363 else if (ssl != NULL && strcEQ(var, "SESSION_ID")) {
366 if (pSession) {
367 IDCONST unsigned char *id;
368 unsigned int idlen;
369
370#ifdef OPENSSL_NO_SSL_INTERN
371 id = (unsigned char *)SSL_SESSION_get_id(pSession, &idlen);
372#else
373 id = pSession->session_id;
374 idlen = pSession->session_id_length;
375#endif
376
378 buf, sizeof(buf)));
379 }
380 }
381 else if(ssl != NULL && strcEQ(var, "SESSION_RESUMED")) {
382 if (SSL_session_reused(ssl) == 1)
383 result = "Resumed";
384 else
385 result = "Initial";
386 }
387 else if (ssl != NULL && strlen(var) >= 6 && strcEQn(var, "CIPHER", 6)) {
389 }
390 else if (ssl != NULL && strlen(var) > 18 && strcEQn(var, "CLIENT_CERT_CHAIN_", 18)) {
393 }
394 else if (ssl != NULL && strcEQ(var, "CLIENT_CERT_RFC4523_CEA")) {
396 }
397 else if (ssl != NULL && strcEQ(var, "CLIENT_VERIFY")) {
399 }
400 else if (ssl != NULL && strlen(var) > 7 && strcEQn(var, "CLIENT_", 7)) {
401 if ((xs = SSL_get_peer_certificate(ssl)) != NULL) {
403 X509_free(xs);
404 }
405 }
406 else if (ssl != NULL && strlen(var) > 7 && strcEQn(var, "SERVER_", 7)) {
407 if ((xs = SSL_get_certificate(ssl)) != NULL) {
409 /* SSL_get_certificate is different from SSL_get_peer_certificate.
410 * No need to X509_free(xs).
411 */
412 }
413 }
414 else if (ssl != NULL && strcEQ(var, "COMPRESS_METHOD")) {
416 }
417#ifdef HAVE_TLSEXT
418 else if (ssl != NULL && strcEQ(var, "TLS_SNI")) {
421 }
422#endif
423 else if (ssl != NULL && strcEQ(var, "SECURE_RENEG")) {
424 int flag = 0;
425#ifdef SSL_get_secure_renegotiation_support
427#endif
428 result = apr_pstrdup(p, flag ? "true" : "false");
429 }
430#ifdef HAVE_SRP
431 else if (ssl != NULL && strcEQ(var, "SRP_USER")) {
432 if ((result = SSL_get_srp_username(ssl)) != NULL) {
434 }
435 }
436 else if (ssl != NULL && strcEQ(var, "SRP_USERINFO")) {
437 if ((result = SSL_get_srp_userinfo(ssl)) != NULL) {
439 }
440 }
441#endif
442
443 return result;
444}
445
448{
449 char *result = NULL;
450 SSLDirConfigRec *dc;
451 int legacy_format = 0;
452 if (r) {
453 dc = myDirConfig(r);
455 }
456 if (legacy_format) {
457 char *cp = X509_NAME_oneline(xsname, NULL, 0);
458 result = apr_pstrdup(p, cp);
459 OPENSSL_free(cp);
460 }
461 else {
462 BIO* bio;
464
465 if ((bio = BIO_new(BIO_s_mem())) == NULL)
466 return NULL;
468
470 }
471 return result;
472}
473
475 char *var)
476{
477 char *result;
478 BOOL resdup;
480 int nid;
481
482 result = NULL;
483 resdup = TRUE;
484
485 if (strcEQ(var, "M_VERSION")) {
487 resdup = FALSE;
488 }
489 else if (strcEQ(var, "M_SERIAL")) {
491 }
492 else if (strcEQ(var, "V_START")) {
494 }
495 else if (strcEQ(var, "V_END")) {
497 }
498 else if (strcEQ(var, "V_REMAIN")) {
500 resdup = FALSE;
501 }
502 else if (*var && strcEQ(var+1, "_DN")) {
503 if (*var == 'S')
505 else if (*var == 'I')
507 else
508 return NULL;
510 resdup = FALSE;
511 }
512 else if (strlen(var) > 5 && strcEQn(var+1, "_DN_", 4)) {
513 if (*var == 'S')
515 else if (*var == 'I')
517 else
518 return NULL;
520 resdup = FALSE;
521 }
522 else if (strlen(var) > 4 && strcEQn(var, "SAN_", 4)) {
524 resdup = FALSE;
525 }
526 else if (strcEQ(var, "A_SIG")) {
527#if MODSSL_USE_OPENSSL_PRE_1_1_API
528 nid = OBJ_obj2nid((ASN1_OBJECT *)(xs->cert_info->signature->algorithm));
529#else
530 const ASN1_OBJECT *paobj;
533#endif
535 (nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(nid));
536 resdup = FALSE;
537 }
538 else if (strcEQ(var, "A_KEY")) {
539#if OPENSSL_VERSION_NUMBER < 0x10100000L
540 nid = OBJ_obj2nid((ASN1_OBJECT *)(xs->cert_info->key->algor->algorithm));
541#else
545#endif
547 (nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(nid));
548 resdup = FALSE;
549 }
550 else if (strcEQ(var, "CERT")) {
552 }
553
554 if (resdup)
556 return result;
557}
558
559/* In this table, .extract is non-zero if RDNs using the NID should be
560 * extracted to for the SSL_{CLIENT,SERVER}_{I,S}_DN_* environment
561 * variables. */
562static const struct {
563 char *name;
564 int nid;
567 { "C", NID_countryName, 1 },
568 { "ST", NID_stateOrProvinceName, 1 }, /* officially (RFC2156) */
569 { "SP", NID_stateOrProvinceName, 0 }, /* compatibility (SSLeay) */
570 { "L", NID_localityName, 1 },
571 { "O", NID_organizationName, 1 },
572 { "OU", NID_organizationalUnitName, 1 },
573 { "CN", NID_commonName, 1 },
574 { "T", NID_title, 1 },
575 { "I", NID_initials, 1 },
576 { "G", NID_givenName, 1 },
577 { "S", NID_surname, 1 },
578 { "D", NID_description, 1 },
579#ifdef NID_userId
580 { "UID", NID_userId, 1 },
581#endif
582 { "Email", NID_pkcs9_emailAddress, 1 },
583 { NULL, 0, 0 }
585
587 const char *var)
588{
589 const char *ptr;
590 char *result;
592 int i, j, n, idx = 0, raw = 0;
594
595 ptr = ap_strrchr_c(var, '_');
596 if (ptr && ptr > var && strcmp(ptr + 1, "RAW") == 0) {
597 var = apr_pstrmemdup(p, var, ptr - var);
598 raw = 1;
599 }
600
601 /* if an _N suffix is used, find the Nth attribute of given name */
602 ptr = ap_strchr_c(var, '_');
603 if (ptr != NULL && strspn(ptr + 1, "0123456789") == strlen(ptr + 1)) {
604 idx = atoi(ptr + 1);
605 varlen = ptr - var;
606 } else {
607 varlen = strlen(var);
608 }
609
610 result = NULL;
611
612 for (i = 0; ssl_var_lookup_ssl_cert_dn_rec[i].name != NULL; i++) {
615 for (j = 0; j < X509_NAME_entry_count(xsname); j++) {
617
619
620 if (n == ssl_var_lookup_ssl_cert_dn_rec[i].nid && idx-- == 0) {
622 break;
623 }
624 }
625 break;
626 }
627 }
628 return result;
629}
630
632{
633 int type;
635 const char *onf = NULL;
636 apr_array_header_t *entries;
637
638 if (strcEQn(var, "Email_", 6)) {
639 type = GEN_EMAIL;
640 var += 6;
641 }
642 else if (strcEQn(var, "DNS_", 4)) {
643 type = GEN_DNS;
644 var += 4;
645 }
646 else if (strcEQn(var, "OTHER_", 6)) {
648 var += 6;
649 if (strEQn(var, "msUPN_", 6)) {
650 var += 6;
651 onf = "msUPN";
652 }
653 else if (strEQn(var, "dnsSRV_", 7)) {
654 var += 7;
655 onf = "id-on-dnsSRV";
656 }
657 else
658 return NULL;
659 }
660 else
661 return NULL;
662
663 /* sanity check: number must be between 1 and 4 digits */
664 numlen = strspn(var, "0123456789");
665 if ((numlen < 1) || (numlen > 4) || (numlen != strlen(var)))
666 return NULL;
667
668 if (modssl_X509_getSAN(p, xs, type, onf, atoi(var), &entries))
669 /* return the first entry from this 1-element array */
670 return APR_ARRAY_IDX(entries, 0, char *);
671 else
672 return NULL;
673}
674
676{
677 BIO* bio;
678
679 if ((bio = BIO_new(BIO_s_mem())) == NULL)
680 return NULL;
682
683 return modssl_bio_free_read(p, bio);
684}
685
686#define DIGIT2NUM(x) (((x)[0] - '0') * 10 + (x)[1] - '0')
687
688/* Return a string giving the number of days remaining until 'tm', or
689 * "0" if this can't be determined. */
691{
693 apr_time_exp_t exp = {0};
694 long diff;
695 unsigned char *dp;
696
697 /* Fail if the time isn't a valid ASN.1 TIME; RFC3280 mandates
698 * that the seconds digits are present even though ASN.1
699 * doesn't. */
700 if ((tm->type == V_ASN1_UTCTIME && tm->length < 11) ||
701 (tm->type == V_ASN1_GENERALIZEDTIME && tm->length < 13) ||
703 return apr_pstrdup(p, "0");
704 }
705
706 if (tm->type == V_ASN1_UTCTIME) {
707 exp.tm_year = DIGIT2NUM(tm->data);
708 if (exp.tm_year <= 50) exp.tm_year += 100;
709 dp = tm->data + 2;
710 } else {
711 exp.tm_year = DIGIT2NUM(tm->data) * 100 + DIGIT2NUM(tm->data + 2) - 1900;
712 dp = tm->data + 4;
713 }
714
715 exp.tm_mon = DIGIT2NUM(dp) - 1;
716 exp.tm_mday = DIGIT2NUM(dp + 2) + 1;
717 exp.tm_hour = DIGIT2NUM(dp + 4);
718 exp.tm_min = DIGIT2NUM(dp + 6);
719 exp.tm_sec = DIGIT2NUM(dp + 8);
720
721 if (apr_time_exp_gmt_get(&then, &exp) != APR_SUCCESS) {
722 return apr_pstrdup(p, "0");
723 }
724
725 diff = (long)((apr_time_sec(then) - apr_time_sec(now)) / (60*60*24));
726
727 return diff > 0 ? apr_ltoa(p, diff) : apr_pstrdup(p, "0");
728}
729
731{
732 BIO *bio;
733
734 if ((bio = BIO_new(BIO_s_mem())) == NULL)
735 return NULL;
737
738 return modssl_bio_free_read(p, bio);
739}
740
742{
743 char *result;
744 X509 *xs;
745 int n;
746
747 result = NULL;
748
749 if (strspn(var, "0123456789") == strlen(var)) {
750 n = atoi(var);
751 if (n < sk_X509_num(sk)) {
752 xs = sk_X509_value(sk, n);
754 }
755 }
756
757 return result;
758}
759
761{
762 char *result;
763 X509 *xs;
764
766
767 if (!(xs = SSL_get_peer_certificate(ssl))) {
768 return NULL;
769 }
770
771 result = NULL;
772
774 if (serialNumber) {
776 if (issuer) {
778 char *decimal = BN_bn2dec(bn);
779 result = apr_pstrcat(p, "{ serialNumber ", decimal,
780 ", issuer rdnSequence:\"",
783 BN_free(bn);
784 }
785 }
786
787 X509_free(xs);
788 return result;
789}
790
792{
793 BIO *bio;
794
795 if ((bio = BIO_new(BIO_s_mem())) == NULL)
796 return NULL;
798
799 return modssl_bio_free_read(p, bio);
800}
801
803{
804 char *result;
805 long vrc;
806 const char *verr;
807 const char *vinfo;
808 SSL *ssl;
809 X509 *xs;
810
811 result = NULL;
812 ssl = sslconn->ssl;
813 verr = sslconn->verify_error;
814 vinfo = sslconn->verify_info;
817
818 if (vrc == X509_V_OK && verr == NULL && xs == NULL)
819 /* no client verification done at all */
820 result = "NONE";
821 else if (vrc == X509_V_OK && verr == NULL && vinfo == NULL && xs != NULL)
822 /* client verification done successful */
823 result = "SUCCESS";
824 else if (vrc == X509_V_OK && vinfo != NULL && strEQ(vinfo, "GENEROUS"))
825 /* client verification done in generous way */
826 result = "GENEROUS";
827 else
828 /* client verification failed */
829 result = apr_psprintf(p, "FAILED:%s",
831
832 if (xs)
833 X509_free(xs);
834 return result;
835}
836
838{
839 char *result;
840 BOOL resdup;
842 SSL *ssl;
843
844 result = NULL;
845 resdup = TRUE;
846
847 ssl = sslconn->ssl;
849
850 if (ssl && strEQ(var, "")) {
852 result = (cipher != NULL ? (char *)SSL_CIPHER_get_name(cipher) : NULL);
853 }
854 else if (strcEQ(var, "_EXPORT"))
855 result = (usekeysize < 56 ? "true" : "false");
856 else if (strcEQ(var, "_USEKEYSIZE")) {
858 resdup = FALSE;
859 }
860 else if (strcEQ(var, "_ALGKEYSIZE")) {
862 resdup = FALSE;
863 }
864
865 if (result != NULL && resdup)
867 return result;
868}
869
871{
873
874 *usekeysize = 0;
875 *algkeysize = 0;
876 if (ssl != NULL)
877 if ((cipher = SSL_get_current_cipher(ssl)) != NULL)
879 return;
880}
881
883{
884 if (strEQ(var, "INTERFACE")) {
885 return apr_pstrdup(p, var_interface);
886 }
887 else if (strEQ(var, "LIBRARY_INTERFACE")) {
889 }
890 else if (strEQ(var, "LIBRARY")) {
891 return apr_pstrdup(p, var_library);
892 }
893 return NULL;
894}
895
896/* Add each RDN in 'xn' to the table 't' where the NID is present in
897 * 'nids', using key prefix 'pfx'. */
898static void extract_dn(apr_table_t *t, apr_hash_t *nids, const char *pfx,
900{
903 int i, nid;
904
905 /* Hash of (int) NID -> (int *) counter to count each time an RDN
906 * with the given NID has been seen. */
908
909 /* For each RDN... */
910 for (i = 0; i < X509_NAME_entry_count(xn); i++) {
911 const char *tag;
913
914 /* Retrieve the nid, and check whether this is one of the nids
915 * which are to be extracted. */
917
918 tag = apr_hash_get(nids, &nid, sizeof nid);
919 if (tag) {
920 const char *key;
921 int *dup;
922 char *value;
923
924 /* Check whether a variable with this nid was already
925 * been used; if so, use the foo_N=bar syntax. */
926 dup = apr_hash_get(count, &nid, sizeof nid);
927 if (dup) {
928 key = apr_psprintf(p, "%s%s_%d", pfx, tag, ++(*dup));
929 }
930 else {
931 /* Otherwise, use the plain foo=bar syntax. */
932 dup = apr_pcalloc(p, sizeof *dup);
933 apr_hash_set(count, &nid, sizeof nid, dup);
934 key = apr_pstrcat(p, pfx, tag, NULL);
935 }
938 }
939 }
940}
941
943{
945 unsigned n;
946 X509 *xs;
947
948 /* Build up a hash table of (int *)NID->(char *)short-name for all
949 * the tags which are to be extracted: */
951 for (n = 0; ssl_var_lookup_ssl_cert_dn_rec[n].name; n++) {
956 }
957 }
958
959 /* Extract the server cert DNS -- note that the refcount does NOT
960 * increase: */
961 xs = SSL_get_certificate(ssl);
962 if (xs) {
963 extract_dn(t, nids, "SSL_SERVER_S_DN_", X509_get_subject_name(xs), p);
964 extract_dn(t, nids, "SSL_SERVER_I_DN_", X509_get_issuer_name(xs), p);
965 }
966
967 /* Extract the client cert DNs -- note that the refcount DOES
968 * increase: */
970 if (xs) {
971 extract_dn(t, nids, "SSL_CLIENT_S_DN_", X509_get_subject_name(xs), p);
972 extract_dn(t, nids, "SSL_CLIENT_I_DN_", X509_get_issuer_name(xs), p);
973 X509_free(xs);
974 }
975}
976
977static void extract_san_array(apr_table_t *t, const char *pfx,
979{
980 int i;
981
982 for (i = 0; i < entries->nelts; i++) {
983 const char *key = apr_psprintf(p, "%s_%d", pfx, i);
984 apr_table_setn(t, key, APR_ARRAY_IDX(entries, i, const char *));
985 }
986}
987
989{
990 X509 *xs;
991 apr_array_header_t *entries;
992
993 /* subjectAltName entries of the server certificate */
994 xs = SSL_get_certificate(ssl);
995 if (xs) {
996 if (modssl_X509_getSAN(p, xs, GEN_EMAIL, NULL, -1, &entries)) {
997 extract_san_array(t, "SSL_SERVER_SAN_Email", entries, p);
998 }
999 if (modssl_X509_getSAN(p, xs, GEN_DNS, NULL, -1, &entries)) {
1000 extract_san_array(t, "SSL_SERVER_SAN_DNS", entries, p);
1001 }
1002 if (modssl_X509_getSAN(p, xs, GEN_OTHERNAME, "id-on-dnsSRV", -1,
1003 &entries)) {
1004 extract_san_array(t, "SSL_SERVER_SAN_OTHER_dnsSRV", entries, p);
1005 }
1006 /* no need to free xs (refcount does not increase) */
1007 }
1008
1009 /* subjectAltName entries of the client certificate */
1011 if (xs) {
1012 if (modssl_X509_getSAN(p, xs, GEN_EMAIL, NULL, -1, &entries)) {
1013 extract_san_array(t, "SSL_CLIENT_SAN_Email", entries, p);
1014 }
1015 if (modssl_X509_getSAN(p, xs, GEN_DNS, NULL, -1, &entries)) {
1016 extract_san_array(t, "SSL_CLIENT_SAN_DNS", entries, p);
1017 }
1018 if (modssl_X509_getSAN(p, xs, GEN_OTHERNAME, "msUPN", -1, &entries)) {
1019 extract_san_array(t, "SSL_CLIENT_SAN_OTHER_msUPN", entries, p);
1020 }
1021 X509_free(xs);
1022 }
1023}
1024
1025/* For an extension type which OpenSSL does not recognize, attempt to
1026 * parse the extension type as a primitive string. This will fail for
1027 * any structured extension type per the docs. Returns non-zero on
1028 * success and writes the string to the given bio. */
1030{
1031 const unsigned char *pp = str->data;
1033 int rv = 0;
1034
1035 /* This allows UTF8String, IA5String, VisibleString, or BMPString;
1036 * conversion to UTF-8 is forced. */
1037 if (d2i_DISPLAYTEXT(&ret, &pp, str->length)) {
1039 rv = 1;
1040 }
1041
1043 return rv;
1044}
1045
1047 const char *extension)
1048{
1050 SSL *ssl = NULL;
1051 apr_array_header_t *array = NULL;
1052 X509 *xs = NULL;
1053 ASN1_OBJECT *oid = NULL;
1054 int count = 0, j;
1055
1056 if (!sslconn || !sslconn->ssl || !extension) {
1057 return NULL;
1058 }
1059 ssl = sslconn->ssl;
1060
1061 /* We accept the "extension" string to be converted as
1062 * a long name (nsComment), short name (DN) or
1063 * numeric OID (1.2.3.4).
1064 */
1066 if (!oid) {
1068 "could not parse OID '%s'", extension);
1070 return NULL;
1071 }
1072
1074 if (xs == NULL) {
1075 return NULL;
1076 }
1077
1079 /* Create an array large enough to accommodate every extension. This is
1080 * likely overkill, but safe.
1081 */
1082 array = apr_array_make(p, count, sizeof(char *));
1083 for (j = 0; j < count; j++) {
1085
1087 BIO *bio = BIO_new(BIO_s_mem());
1088
1089 /* We want to obtain a string representation of the extensions
1090 * value and add it to the array we're building.
1091 * X509V3_EXT_print() doesn't know about all the possible
1092 * data types, but the value is stored as an ASN1_OCTET_STRING
1093 * allowing us a fallback in case of X509V3_EXT_print
1094 * not knowing how to handle the data.
1095 */
1096 if (X509V3_EXT_print(bio, ext, 0, 0) == 1 ||
1098 BUF_MEM *buf;
1099 char **ptr = apr_array_push(array);
1101 *ptr = apr_pstrmemdup(p, buf->data, buf->length);
1102 } else {
1104 "Found an extension '%s', but failed to "
1105 "create a string from it", extension);
1106 }
1107 BIO_vfree(bio);
1108 }
1109 }
1110
1111 if (array->nelts == 0)
1112 array = NULL;
1113
1114 if (peer) {
1115 /* only SSL_get_peer_certificate raises the refcount */
1116 X509_free(xs);
1117 }
1118
1121 return array;
1122}
1123
1125{
1126 char *result = "NULL";
1127#ifndef OPENSSL_NO_COMP
1129
1130 if (pSession) {
1131#ifdef OPENSSL_NO_SSL_INTERN
1133#else
1134 switch (pSession->compress_meth) {
1135#endif
1136 case 0:
1137 /* default "NULL" already set */
1138 break;
1139
1140 /* Defined by RFC 3749, deflate is coded by "1" */
1141 case 1:
1142 result = "DEFLATE";
1143 break;
1144
1145 /* IANA assigned compression number for LZS */
1146 case 0x40:
1147 result = "LZS";
1148 break;
1149
1150 default:
1151 result = "UNKNOWN";
1152 break;
1153 }
1154 }
1155#endif
1156 return result;
1157}
1158
1159/* _________________________________________________________________
1160**
1161** SSL Extension to mod_log_config
1162** _________________________________________________________________
1163*/
1164
1165#include "../../modules/loggers/mod_log_config.h"
1166
1167static const char *ssl_var_log_handler_c(request_rec *r, char *a);
1168static const char *ssl_var_log_handler_x(request_rec *r, char *a);
1169
1170/*
1171 * register us for the mod_log_config function registering phase
1172 * to establish %{...}c and to be able to expand %{...}x variables.
1173 */
1186
1187/*
1188 * implement the %{..}c log function
1189 * (we are the only function)
1190 */
1191static const char *ssl_var_log_handler_c(request_rec *r, char *a)
1192{
1194 char *result;
1195
1196 if (sslconn == NULL || sslconn->ssl == NULL)
1197 return NULL;
1198 result = NULL;
1199 if (strEQ(a, "version"))
1200 result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_PROTOCOL");
1201 else if (strEQ(a, "cipher"))
1202 result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CIPHER");
1203 else if (strEQ(a, "subjectdn") || strEQ(a, "clientcert"))
1204 result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CLIENT_S_DN");
1205 else if (strEQ(a, "issuerdn") || strEQ(a, "cacert"))
1206 result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CLIENT_I_DN");
1207 else if (strEQ(a, "errcode"))
1208 result = "-";
1209 else if (strEQ(a, "errstr"))
1210 result = (char *)sslconn->verify_error;
1211 if (result != NULL && result[0] == NUL)
1212 result = NULL;
1213 return result;
1214}
1215
1216/*
1217 * extend the implementation of the %{..}x log function
1218 * (there can be more functions)
1219 */
1220static const char *ssl_var_log_handler_x(request_rec *r, char *a)
1221{
1222 char *result;
1223
1225 if (result != NULL && result[0] == NUL)
1226 result = NULL;
1227 return result;
1228}
1229
1230
Expression parser.
#define AP_EXPR_FUNC_LIST
Definition ap_expr.h:260
#define AP_EXPR_FUNC_STRING
Definition ap_expr.h:259
#define AP_EXPR_FUNC_VAR
Definition ap_expr.h:258
int n
Definition ap_regex.h:278
#define AP_SERVER_BASEREVISION
Definition ap_release.h:74
#define TRUE
Definition abts.h:38
#define FALSE
Definition abts.h:35
APR Time Library.
request_rec * r
#define ap_http_scheme(r)
Definition httpd.h:297
#define DECLINED
Definition httpd.h:457
#define OK
Definition httpd.h:456
const char * ap_get_server_banner(void)
Definition core.c:3593
apr_port_t ap_get_server_port(const request_rec *r)
Definition core.c:1199
const char * ap_document_root(request_rec *r)
Definition core.c:829
const char * ap_get_remote_logname(request_rec *r)
Definition core.c:1121
const char * ap_get_server_name_for_url(request_rec *r)
Definition core.c:1187
#define APLOGNO(n)
Definition http_log.h:117
#define ap_log_cerror
Definition http_log.h:498
#define APLOG_MARK
Definition http_log.h:283
#define APLOG_DEBUG
Definition http_log.h:71
const unsigned char * buf
Definition util_md5.h:50
#define MODULE_MAGIC_NUMBER_MAJOR
Definition ap_mmn.h:611
void ap_hook_ssl_conn_is_ssl(ap_HOOK_ssl_conn_is_ssl_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
Definition ssl.c:262
void * dummy
Definition http_vhost.h:62
void const char * arg
Definition http_vhost.h:63
unsigned int count
Definition apr_md5.h:152
apr_brigade_flush void * ctx
apr_bucket apr_bucket_brigade * a
const char apr_ssize_t int flags
Definition apr_encode.h:168
#define APR_HOOK_MIDDLE
Definition apr_hooks.h:303
apr_memcache_t * mc
#define APR_RETRIEVE_OPTIONAL_FN(name)
#define APR_OPTIONAL_FN_TYPE(name)
#define APR_REGISTER_OPTIONAL_FN(name)
void ap_hook_expr_lookup(ap_HOOK_expr_lookup_t *pf, const char *const *aszPre, const char *const *aszSucc, int nOrder)
#define myDirConfig(req)
#define X509_get_notAfter
void ssl_var_log_config_register(apr_pool_t *p)
char * ssl_var_lookup(apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, char *var)
#define IDCONST
#define MODSSL_SSL_CIPHER_CONST
#define myConnConfig(c)
#define myModConfig(srv)
#define X509_get_notBefore
apr_array_header_t * ssl_ext_list(apr_pool_t *p, conn_rec *c, int peer, const char *extension)
#define SSL_OPT_LEGACYDNFORMAT
void modssl_var_extract_dns(apr_table_t *t, SSL *ssl, apr_pool_t *p)
#define BOOL
Definition ssl_private.h:81
#define NUL
void ssl_var_register(apr_pool_t *p)
void modssl_var_extract_san_entries(apr_table_t *t, SSL *ssl, apr_pool_t *p)
#define MODSSL_SESSION_ID_STRING_LEN
#define MODSSL_LIBRARY_DYNTEXT
#define MODSSL_LIBRARY_TEXT
char * modssl_X509_NAME_to_string(apr_pool_t *p, X509_NAME *dn, int maxlen)
char * modssl_bio_free_read(apr_pool_t *p, BIO *bio)
unsigned int modssl_X509_getSAN(apr_pool_t *p, X509 *x509, int type, const char *onf, int idx, apr_array_header_t **entries)
char * modssl_X509_NAME_ENTRY_to_string(apr_pool_t *p, X509_NAME_ENTRY *xsne, int raw)
#define ap_strrchr_c(s, c)
Definition httpd.h:2357
#define ap_strchr_c(s, c)
Definition httpd.h:2353
apr_size_t size
const char * value
Definition apr_env.h:51
#define APR_SUCCESS
Definition apr_errno.h:225
const char * key
const char apr_int32_t flag
void * data
int type
apr_array_header_t ** result
apr_vformatter_buff_t * c
Definition apr_lib.h:175
apr_interval_time_t t
const char apr_uint32_t * id
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
const char * s
Definition apr_strings.h:95
#define APR_ARRAY_IDX(ary, i, type)
Definition apr_tables.h:141
apr_size_t apr_size_t const char apr_time_exp_t * tm
Definition apr_time.h:221
apr_int64_t apr_time_t
Definition apr_time.h:45
#define apr_time_sec(time)
Definition apr_time.h:63
const char * ap_get_useragent_host(request_rec *req, int type, int *str_is_ip)
Definition core.c:1036
#define REMOTE_NAME
Definition http_core.h:106
apr_pool_t * p
Definition md_event.c:32
static void ap_register_log_handler(apr_pool_t *p, char *tag, ap_log_handler_fn_t *handler, int def)
#define strEQn(s1, s2, n)
Definition mod_nw_ssl.c:90
#define strEQ(s1, s2)
Definition mod_nw_ssl.c:88
#define strcEQ(s1, s2)
Definition mod_nw_ssl.c:93
#define strcEQn(s1, s2, n)
Definition mod_nw_ssl.c:95
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
SSL extension module for Apache.
STACK_OF(X509_NAME)
int extract
static void extract_san_array(apr_table_t *t, const char *pfx, apr_array_header_t *entries, apr_pool_t *p)
static char * ssl_var_lookup_ssl(apr_pool_t *p, SSLConnRec *sslconn, request_rec *r, char *var)
static void extract_dn(apr_table_t *t, apr_hash_t *nids, const char *pfx, X509_NAME *xn, apr_pool_t *p)
static char * ssl_var_lookup_ssl_compress_meth(SSL *ssl)
static int ssl_expr_lookup(ap_expr_lookup_parms *parms)
static char * ssl_var_lookup_ssl_cert_verify(apr_pool_t *p, SSLConnRec *sslconn)
static SSLConnRec * ssl_get_effective_config(conn_rec *c)
static const char * expr_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
static char * ssl_var_lookup_ssl_cipher(apr_pool_t *p, SSLConnRec *sslconn, char *var)
static char * ssl_var_lookup_ssl_cert_chain(apr_pool_t *p, STACK_OF(X509) *sk, char *var)
static const char * expr_func_fn(ap_expr_eval_ctx_t *ctx, const void *data, const char *arg)
static apr_array_header_t * expr_peer_ext_list_fn(ap_expr_eval_ctx_t *ctx, const void *dummy, const char *arg)
#define DIGIT2NUM(x)
#define MKTIMESTR(format, tmfield)
static char * ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_TIME *tm)
static char * ssl_var_lookup_ssl_cert(apr_pool_t *p, request_rec *r, X509 *xs, char *var)
static char * ssl_var_lookup_ssl_cert_dn_oneline(apr_pool_t *p, request_rec *r, X509_NAME *xsname)
char * name
int nid
static const char * ssl_var_log_handler_x(request_rec *r, char *a)
static char * ssl_var_lookup_ssl_cert_remain(apr_pool_t *p, ASN1_TIME *tm)
static char * ssl_var_lookup_ssl_version(apr_pool_t *p, char *var)
static char * ssl_var_lookup_ssl_cert_san(apr_pool_t *p, X509 *xs, char *var)
static const char var_interface[]
static char * ssl_var_lookup_ssl_cert_serial(apr_pool_t *p, X509 *xs)
static const struct @40 ssl_var_lookup_ssl_cert_dn_rec[]
static char var_library_interface[]
static int dump_extn_value(BIO *bio, ASN1_OCTET_STRING *str)
static void ssl_var_lookup_ssl_cipher_bits(SSL *ssl, int *usekeysize, int *algkeysize)
static const char * ssl_var_log_handler_c(request_rec *r, char *a)
static char * ssl_var_lookup_ssl_cert_PEM(apr_pool_t *p, X509 *xs)
static char * ssl_var_lookup_ssl_cert_rfc4523_cea(apr_pool_t *p, SSL *ssl)
static char * ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname, const char *var)
static char * var_library
static int ssl_conn_is_ssl(conn_rec *c)
Internal interfaces private to mod_ssl.
char * modssl_SSL_SESSION_id2sz(unsigned char *id, int idlen, char *str, int strsize)
ssl_opt_t nOptions
apr_int32_t tm_sec
Definition apr_time.h:101
apr_int32_t tm_hour
Definition apr_time.h:105
apr_int32_t tm_year
Definition apr_time.h:111
apr_int32_t tm_min
Definition apr_time.h:103
apr_int32_t tm_mday
Definition apr_time.h:107
apr_int32_t tm_mon
Definition apr_time.h:109
Structure to store things which are per connection.
Definition httpd.h:1152
A structure that represents the current request.
Definition httpd.h:845
char * user
Definition httpd.h:1005
char * uri
Definition httpd.h:1016
char * useragent_ip
Definition httpd.h:1101
apr_table_t * notes
Definition httpd.h:985
char * the_request
Definition httpd.h:866
apr_pool_t * pool
Definition httpd.h:847
char * filename
Definition httpd.h:1018
conn_rec * connection
Definition httpd.h:849
apr_table_t * headers_in
Definition httpd.h:976
char * protocol
Definition httpd.h:879
request_rec * main
Definition httpd.h:860
apr_table_t * subprocess_env
Definition httpd.h:983
server_rec * server
Definition httpd.h:851
const char * method
Definition httpd.h:900
char * path_info
Definition httpd.h:1024
char * args
Definition httpd.h:1026
char * ap_auth_type
Definition httpd.h:1007
A structure to store information for each virtual server.
Definition httpd.h:1322
char * server_admin
Definition httpd.h:1363
static apr_time_t now
Definition testtime.c:33
#define var
#define str