static int ssl_expr_lookup(ap_expr_lookup_parms *parms) { switch (parms->type) { case AP_EXPR_FUNC_VAR: /* for now, we just handle everything that starts with SSL_, but * register our hook as APR_HOOK_LAST * XXX: This can be optimized */ if (strcEQn(parms->name, "SSL_", 4)) { *parms->func = expr_var_fn; *parms->data = parms->name + 4; return OK; } break; case AP_EXPR_FUNC_STRING: /* Function SSL() is implemented by us. */ if (strcEQ(parms->name, "SSL")) { *parms->func = expr_func_fn; *parms->data = NULL; return OK; } break; case AP_EXPR_FUNC_LIST: if (strcEQ(parms->name, "PeerExtList")) { *parms->func = expr_peer_ext_list_fn; *parms->data = "PeerExtList"; return OK; } break; } return DECLINED; }
static char *ssl_var_lookup_ssl_cert_san(apr_pool_t *p, X509 *xs, char *var) { int type, numlen; const char *onf = NULL; apr_array_header_t *entries; if (strcEQn(var, "Email_", 6)) { type = GEN_EMAIL; var += 6; } else if (strcEQn(var, "DNS_", 4)) { type = GEN_DNS; var += 4; } else if (strcEQn(var, "OTHER_", 6)) { type = GEN_OTHERNAME; var += 6; if (strEQn(var, "msUPN_", 6)) { var += 6; onf = "msUPN"; } else if (strEQn(var, "dnsSRV_", 7)) { var += 7; onf = "id-on-dnsSRV"; } else return NULL; } else return NULL; /* sanity check: number must be between 1 and 4 digits */ numlen = strspn(var, "0123456789"); if ((numlen < 1) || (numlen > 4) || (numlen != strlen(var))) return NULL; if (modssl_X509_getSAN(p, xs, type, onf, atoi(var), &entries)) /* return the first entry from this 1-element array */ return APR_ARRAY_IDX(entries, 0, char *); else return NULL;
const char *ssl_cmd_SSLSessionCache(cmd_parms *cmd, void *dcfg, const char *arg) { SSLModConfigRec *mc = myModConfig(cmd->server); const char *err, *colon; char *cp, *cp2; int arglen = strlen(arg); if ((err = ap_check_cmd_context(cmd, GLOBAL_ONLY))) { return err; } if (ssl_config_global_isfixed(mc)) { return NULL; } if (strcEQ(arg, "none")) { mc->nSessionCacheMode = SSL_SCMODE_NONE; mc->szSessionCacheDataFile = NULL; } else if (strcEQ(arg, "nonenotnull")) { mc->nSessionCacheMode = SSL_SCMODE_NONE_NOT_NULL; mc->szSessionCacheDataFile = NULL; } else if ((arglen > 4) && strcEQn(arg, "dbm:", 4)) { mc->nSessionCacheMode = SSL_SCMODE_DBM; mc->szSessionCacheDataFile = ap_server_root_relative(mc->pPool, arg+4); if (!mc->szSessionCacheDataFile) { return apr_psprintf(cmd->pool, "SSLSessionCache: Invalid cache file path %s", arg+4); } } else if (((arglen > 4) && strcEQn(arg, "shm:", 4)) || ((arglen > 6) && strcEQn(arg, "shmht:", 6)) || ((arglen > 6) && strcEQn(arg, "shmcb:", 6))) { #if !APR_HAS_SHARED_MEMORY return MODSSL_NO_SHARED_MEMORY_ERROR; #endif mc->nSessionCacheMode = SSL_SCMODE_SHMCB; colon = ap_strchr_c(arg, ':'); mc->szSessionCacheDataFile = ap_server_root_relative(mc->pPool, colon+1); if (!mc->szSessionCacheDataFile) { return apr_psprintf(cmd->pool, "SSLSessionCache: Invalid cache file path %s", colon+1); } mc->tSessionCacheDataTable = NULL; mc->nSessionCacheDataSize = 1024*512; /* 512KB */ if ((cp = strchr(mc->szSessionCacheDataFile, '('))) { *cp++ = NUL; if (!(cp2 = strchr(cp, ')'))) { return "SSLSessionCache: Invalid argument: " "no closing parenthesis"; } *cp2 = NUL; mc->nSessionCacheDataSize = atoi(cp); if (mc->nSessionCacheDataSize < 8192) { return "SSLSessionCache: Invalid argument: " "size has to be >= 8192 bytes"; } if (mc->nSessionCacheDataSize >= APR_SHM_MAXSIZE) { return apr_psprintf(cmd->pool, "SSLSessionCache: Invalid argument: " "size has to be < %d bytes on this " "platform", APR_SHM_MAXSIZE); } } } else if ((arglen > 3) && strcEQn(arg, "dc:", 3)) { #ifdef HAVE_DISTCACHE mc->nSessionCacheMode = SSL_SCMODE_DC; mc->szSessionCacheDataFile = apr_pstrdup(mc->pPool, arg+3); if (!mc->szSessionCacheDataFile) { return apr_pstrcat(cmd->pool, "SSLSessionCache: Invalid cache file path: ", arg+3, NULL); } #else return "SSLSessionCache: distcache support disabled"; #endif } else { return "SSLSessionCache: Invalid argument"; } return NULL; }
static char *ssl_var_lookup_ssl_cert(apr_pool_t *p, request_rec *r, X509 *xs, char *var) { char *result; BOOL resdup; X509_NAME *xsname; int nid; result = NULL; resdup = TRUE; if (strcEQ(var, "M_VERSION")) { result = apr_psprintf(p, "%lu", X509_get_version(xs)+1); resdup = FALSE; } else if (strcEQ(var, "M_SERIAL")) { result = ssl_var_lookup_ssl_cert_serial(p, xs); } else if (strcEQ(var, "V_START")) { result = ssl_var_lookup_ssl_cert_valid(p, X509_get_notBefore(xs)); } else if (strcEQ(var, "V_END")) { result = ssl_var_lookup_ssl_cert_valid(p, X509_get_notAfter(xs)); } else if (strcEQ(var, "V_REMAIN")) { result = ssl_var_lookup_ssl_cert_remain(p, X509_get_notAfter(xs)); resdup = FALSE; } else if (*var && strcEQ(var+1, "_DN")) { if (*var == 'S') xsname = X509_get_subject_name(xs); else if (*var == 'I') xsname = X509_get_issuer_name(xs); else return NULL; result = ssl_var_lookup_ssl_cert_dn_oneline(p, r, xsname); resdup = FALSE; } else if (strlen(var) > 5 && strcEQn(var+1, "_DN_", 4)) { if (*var == 'S') xsname = X509_get_subject_name(xs); else if (*var == 'I') xsname = X509_get_issuer_name(xs); else return NULL; result = ssl_var_lookup_ssl_cert_dn(p, xsname, var+5); resdup = FALSE; } else if (strlen(var) > 4 && strcEQn(var, "SAN_", 4)) { result = ssl_var_lookup_ssl_cert_san(p, xs, var+4); resdup = FALSE; } else if (strcEQ(var, "A_SIG")) { #if MODSSL_USE_OPENSSL_PRE_1_1_API nid = OBJ_obj2nid((ASN1_OBJECT *)(xs->cert_info->signature->algorithm)); #else const ASN1_OBJECT *paobj; X509_ALGOR_get0(&paobj, NULL, NULL, X509_get0_tbs_sigalg(xs)); nid = OBJ_obj2nid(paobj); #endif result = apr_pstrdup(p, (nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(nid)); resdup = FALSE; } else if (strcEQ(var, "A_KEY")) { #if OPENSSL_VERSION_NUMBER < 0x10100000L nid = OBJ_obj2nid((ASN1_OBJECT *)(xs->cert_info->key->algor->algorithm)); #else ASN1_OBJECT *paobj; X509_PUBKEY_get0_param(&paobj, NULL, 0, NULL, X509_get_X509_PUBKEY(xs)); nid = OBJ_obj2nid(paobj); #endif result = apr_pstrdup(p, (nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(nid)); resdup = FALSE; } else if (strcEQ(var, "CERT")) { result = ssl_var_lookup_ssl_cert_PEM(p, xs); } if (resdup) result = apr_pstrdup(p, result); return result; }
static char *ssl_var_lookup_ssl(apr_pool_t *p, SSLConnRec *sslconn, request_rec *r, char *var) { char *result; X509 *xs; STACK_OF(X509) *sk; SSL *ssl; result = NULL; ssl = sslconn->ssl; if (strlen(var) > 8 && strcEQn(var, "VERSION_", 8)) { result = ssl_var_lookup_ssl_version(p, var+8); } else if (ssl != NULL && strcEQ(var, "PROTOCOL")) { result = (char *)SSL_get_version(ssl); } else if (ssl != NULL && strcEQ(var, "SESSION_ID")) { char buf[MODSSL_SESSION_ID_STRING_LEN]; SSL_SESSION *pSession = SSL_get_session(ssl); if (pSession) { IDCONST unsigned char *id; unsigned int idlen; #ifdef OPENSSL_NO_SSL_INTERN id = (unsigned char *)SSL_SESSION_get_id(pSession, &idlen); #else id = pSession->session_id; idlen = pSession->session_id_length; #endif result = apr_pstrdup(p, modssl_SSL_SESSION_id2sz(id, idlen, buf, sizeof(buf))); } } else if(ssl != NULL && strcEQ(var, "SESSION_RESUMED")) { if (SSL_session_reused(ssl) == 1) result = "Resumed"; else result = "Initial"; } else if (ssl != NULL && strlen(var) >= 6 && strcEQn(var, "CIPHER", 6)) { result = ssl_var_lookup_ssl_cipher(p, sslconn, var+6); } else if (ssl != NULL && strlen(var) > 18 && strcEQn(var, "CLIENT_CERT_CHAIN_", 18)) { sk = SSL_get_peer_cert_chain(ssl); result = ssl_var_lookup_ssl_cert_chain(p, sk, var+18); } else if (ssl != NULL && strcEQ(var, "CLIENT_CERT_RFC4523_CEA")) { result = ssl_var_lookup_ssl_cert_rfc4523_cea(p, ssl); } else if (ssl != NULL && strcEQ(var, "CLIENT_VERIFY")) { result = ssl_var_lookup_ssl_cert_verify(p, sslconn); } else if (ssl != NULL && strlen(var) > 7 && strcEQn(var, "CLIENT_", 7)) { if ((xs = SSL_get_peer_certificate(ssl)) != NULL) { result = ssl_var_lookup_ssl_cert(p, r, xs, var+7); X509_free(xs); } } else if (ssl != NULL && strlen(var) > 7 && strcEQn(var, "SERVER_", 7)) { if ((xs = SSL_get_certificate(ssl)) != NULL) { result = ssl_var_lookup_ssl_cert(p, r, xs, var+7); /* SSL_get_certificate is different from SSL_get_peer_certificate. * No need to X509_free(xs). */ } } else if (ssl != NULL && strcEQ(var, "COMPRESS_METHOD")) { result = ssl_var_lookup_ssl_compress_meth(ssl); } #ifdef HAVE_TLSEXT else if (ssl != NULL && strcEQ(var, "TLS_SNI")) { result = apr_pstrdup(p, SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name)); } #endif else if (ssl != NULL && strcEQ(var, "SECURE_RENEG")) { int flag = 0; #ifdef SSL_get_secure_renegotiation_support flag = SSL_get_secure_renegotiation_support(ssl); #endif result = apr_pstrdup(p, flag ? "true" : "false"); } #ifdef HAVE_SRP else if (ssl != NULL && strcEQ(var, "SRP_USER")) { if ((result = SSL_get_srp_username(ssl)) != NULL) { result = apr_pstrdup(p, result); } } else if (ssl != NULL && strcEQ(var, "SRP_USERINFO")) { if ((result = SSL_get_srp_userinfo(ssl)) != NULL) { result = apr_pstrdup(p, result); } } #endif return result; }
/* This function must remain safe to use for a non-SSL connection. */ char *ssl_var_lookup(apr_pool_t *p, server_rec *s, conn_rec *c, request_rec *r, char *var) { SSLModConfigRec *mc = myModConfig(s); const char *result; BOOL resdup; apr_time_exp_t tm; result = NULL; resdup = TRUE; /* * When no pool is given try to find one */ if (p == NULL) { if (r != NULL) p = r->pool; else if (c != NULL) p = c->pool; else p = mc->pPool; } /* * Request dependent stuff */ if (r != NULL) { switch (var[0]) { case 'H': case 'h': if (strcEQ(var, "HTTP_USER_AGENT")) result = apr_table_get(r->headers_in, "User-Agent"); else if (strcEQ(var, "HTTP_REFERER")) result = apr_table_get(r->headers_in, "Referer"); else if (strcEQ(var, "HTTP_COOKIE")) result = apr_table_get(r->headers_in, "Cookie"); else if (strcEQ(var, "HTTP_FORWARDED")) result = apr_table_get(r->headers_in, "Forwarded"); else if (strcEQ(var, "HTTP_HOST")) result = apr_table_get(r->headers_in, "Host"); else if (strcEQ(var, "HTTP_PROXY_CONNECTION")) result = apr_table_get(r->headers_in, "Proxy-Connection"); else if (strcEQ(var, "HTTP_ACCEPT")) result = apr_table_get(r->headers_in, "Accept"); else if (strlen(var) > 5 && strcEQn(var, "HTTP:", 5)) /* all other headers from which we are still not know about */ result = apr_table_get(r->headers_in, var+5); break; case 'R': case 'r': if (strcEQ(var, "REQUEST_METHOD")) result = r->method; else if (strcEQ(var, "REQUEST_SCHEME")) result = ap_http_scheme(r); else if (strcEQ(var, "REQUEST_URI")) result = r->uri; else if (strcEQ(var, "REQUEST_FILENAME")) result = r->filename; else if (strcEQ(var, "REMOTE_ADDR")) result = r->useragent_ip; else if (strcEQ(var, "REMOTE_HOST")) result = ap_get_useragent_host(r, REMOTE_NAME, NULL); else if (strcEQ(var, "REMOTE_IDENT")) result = ap_get_remote_logname(r); else if (strcEQ(var, "REMOTE_USER")) result = r->user; break; case 'S': case 's': if (strcEQn(var, "SSL", 3)) break; /* shortcut common case */ if (strcEQ(var, "SERVER_ADMIN")) result = r->server->server_admin; else if (strcEQ(var, "SERVER_NAME")) result = ap_get_server_name_for_url(r); else if (strcEQ(var, "SERVER_PORT")) result = apr_psprintf(p, "%u", ap_get_server_port(r)); else if (strcEQ(var, "SERVER_PROTOCOL")) result = r->protocol; else if (strcEQ(var, "SCRIPT_FILENAME")) result = r->filename; break; default: if (strcEQ(var, "PATH_INFO")) result = r->path_info; else if (strcEQ(var, "QUERY_STRING")) result = r->args; else if (strcEQ(var, "IS_SUBREQ")) result = (r->main != NULL ? "true" : "false"); else if (strcEQ(var, "DOCUMENT_ROOT")) result = ap_document_root(r); else if (strcEQ(var, "AUTH_TYPE")) result = r->ap_auth_type; else if (strcEQ(var, "THE_REQUEST")) result = r->the_request; else if (strlen(var) > 4 && strcEQn(var, "ENV:", 4)) { result = apr_table_get(r->notes, var+4); if (result == NULL) result = apr_table_get(r->subprocess_env, var+4); } break; } } /* * Connection stuff */ if (result == NULL && c != NULL) { SSLConnRec *sslconn = ssl_get_effective_config(c); if (strlen(var) > 4 && strcEQn(var, "SSL_", 4) && sslconn && sslconn->ssl) result = ssl_var_lookup_ssl(p, sslconn, r, var+4); else if (strcEQ(var, "HTTPS")) { if (sslconn && sslconn->ssl) result = "on"; else result = "off"; } } /* * Totally independent stuff */ if (result == NULL) { if (strlen(var) > 12 && strcEQn(var, "SSL_VERSION_", 12)) result = ssl_var_lookup_ssl_version(p, var+12); else if (strcEQ(var, "SERVER_SOFTWARE")) result = ap_get_server_banner(); else if (strcEQ(var, "API_VERSION")) { result = apr_itoa(p, MODULE_MAGIC_NUMBER_MAJOR); resdup = FALSE; } else if (strcEQ(var, "TIME_YEAR")) { apr_time_exp_lt(&tm, apr_time_now()); result = apr_psprintf(p, "%02d%02d", (tm.tm_year / 100) + 19, tm.tm_year % 100); resdup = FALSE; } #define MKTIMESTR(format, tmfield) \ apr_time_exp_lt(&tm, apr_time_now()); \ result = apr_psprintf(p, format, tm.tmfield); \ resdup = FALSE; else if (strcEQ(var, "TIME_MON")) { MKTIMESTR("%02d", tm_mon+1) } else if (strcEQ(var, "TIME_DAY")) { MKTIMESTR("%02d", tm_mday) } else if (strcEQ(var, "TIME_HOUR")) { MKTIMESTR("%02d", tm_hour) } else if (strcEQ(var, "TIME_MIN")) { MKTIMESTR("%02d", tm_min) } else if (strcEQ(var, "TIME_SEC")) { MKTIMESTR("%02d", tm_sec) } else if (strcEQ(var, "TIME_WDAY")) { MKTIMESTR("%d", tm_wday) } else if (strcEQ(var, "TIME")) { apr_time_exp_lt(&tm, apr_time_now()); result = apr_psprintf(p, "%02d%02d%02d%02d%02d%02d%02d", (tm.tm_year / 100) + 19, (tm.tm_year % 100), tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); resdup = FALSE; } /* all other env-variables from the parent Apache process */ else if (strlen(var) > 4 && strcEQn(var, "ENV:", 4)) { result = getenv(var+4); } } if (result != NULL && resdup) result = apr_pstrdup(p, result); if (result == NULL) result = ""; return (char *)result; }