NULL
};
+/* Lookup SSL variable @arg varname and set in the table @arg env.
+ * Returns the value if the value is non-NULL and not the empty
+ * string; otherwise returns NULL. */
+static const char *extract_to_env(request_rec *r, apr_table_t *env,
+ const char *varname)
+{
+ const char *val = ssl_var_lookup(r->pool, r->server, r->connection,
+ r, varname);
+ apr_table_setn(env, varname, val);
+ return val && *val ? val : NULL;
+}
+
int ssl_hook_Fixup(request_rec *r)
{
SSLDirConfigRec *dc = myDirConfig(r);
#ifdef HAVE_TLSEXT
const char *servername;
#endif
- STACK_OF(X509) *peer_certs;
SSLConnRec *sslconn;
SSL *ssl;
int i;
* On-demand bloat up the SSI/CGI environment with certificate data
*/
if (dc->nOptions & SSL_OPT_EXPORTCERTDATA) {
- val = ssl_var_lookup(r->pool, r->server, r->connection,
- r, "SSL_SERVER_CERT");
+ extract_to_env(r, env, "SSL_SERVER_CERT");
+ extract_to_env(r, env, "SSL_CLIENT_CERT");
- apr_table_setn(env, "SSL_SERVER_CERT", val);
-
- val = ssl_var_lookup(r->pool, r->server, r->connection,
- r, "SSL_CLIENT_CERT");
+ i = 0;
+ do {
+ var = apr_psprintf(r->pool, "SSL_CLIENT_CERT_CHAIN_%d", i++);
+ } while (extract_to_env(r, env, var));
+ }
- apr_table_setn(env, "SSL_CLIENT_CERT", val);
+ if (dc->nOptions & SSL_OPT_EXPORTCB64DATA) {
+ extract_to_env(r, env, "SSL_SERVER_B64CERT");
+ extract_to_env(r, env, "SSL_CLIENT_B64CERT");
- if ((peer_certs = (STACK_OF(X509) *)SSL_get_peer_cert_chain(ssl))) {
- for (i = 0; i < sk_X509_num(peer_certs); i++) {
- var = apr_psprintf(r->pool, "SSL_CLIENT_CERT_CHAIN_%d", i);
- val = ssl_var_lookup(r->pool, r->server, r->connection,
- r, var);
- if (val) {
- apr_table_setn(env, var, val);
- }
- }
- }
+ i = 0;
+ do {
+ var = apr_psprintf(r->pool, "SSL_CLIENT_B64CERT_CHAIN_%d", i++);
+ } while (extract_to_env(r, env, var));
}
-
#ifdef SSL_get_secure_renegotiation_support
apr_table_setn(r->notes, "ssl-secure-reneg",
SSL_get_secure_renegotiation_support(ssl) ? "1" : "0");
static const char *ssl_var_lookup_ssl_cert_valid(apr_pool_t *p, ASN1_TIME *tm);
static const char *ssl_var_lookup_ssl_cert_remain(apr_pool_t *p, ASN1_TIME *tm);
static const char *ssl_var_lookup_ssl_cert_serial(apr_pool_t *p, X509 *xs);
-static const char *ssl_var_lookup_ssl_cert_chain(apr_pool_t *p, STACK_OF(X509) *sk, const char *var);
+static const char *ssl_var_lookup_ssl_cert_chain(apr_pool_t *p, STACK_OF(X509) *sk, const char *var, int pem);
static const char *ssl_var_lookup_ssl_cert_rfc4523_cea(apr_pool_t *p, SSL *ssl);
-static const char *ssl_var_lookup_ssl_cert_PEM(apr_pool_t *p, X509 *xs);
static const char *ssl_var_lookup_ssl_cert_verify(apr_pool_t *p, const SSLConnRec *sslconn);
static const char *ssl_var_lookup_ssl_cipher(apr_pool_t *p, const SSLConnRec *sslconn, const char *var);
static void ssl_var_lookup_ssl_cipher_bits(SSL *ssl, int *usekeysize, int *algkeysize);
return sslconn && sslconn->ssl;
}
+/* Returns certificate data, either PEM encoded if 'pem' is non-zero,
+ * else plain base64-encoded DER. */
+static const char *ssl_var_lookup_ssl_cert_data(apr_pool_t *p, X509 *xs,
+ int pem)
+{
+ BIO *bio;
+
+ if ((bio = BIO_new(BIO_s_mem())) == NULL)
+ return NULL;
+
+ if (pem) {
+ PEM_write_bio_X509(bio, xs);
+ }
+ else {
+ BIO *b64 = BIO_new(BIO_f_base64());
+ if (b64 == NULL) {
+ BIO_free(bio);
+ return NULL;
+ }
+ BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
+ b64 = BIO_push(b64, bio);
+ i2d_X509_bio(b64, xs);
+ BIO_flush(b64); /* ensures trailing bytes are padded */
+ BIO_pop(b64);
+ BIO_free(b64);
+ }
+
+ return modssl_bio_free_read(p, bio);
+}
+
/* SSLv3 uses 36 bytes for Finishd messages, TLS1.0 12 bytes,
* So tls-unique is max 36 bytes, however with tls-server-end-point,
* the CB data is the certificate signature, so we use the maximum
}
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);
+ result = ssl_var_lookup_ssl_cert_chain(p, sk, var+18, 1);
+ }
+ else if (ssl != NULL && strlen(var) > 21 && strcEQn(var, "CLIENT_B64CERT_CHAIN_", 21)) {
+ sk = SSL_get_peer_cert_chain(ssl);
+ result = ssl_var_lookup_ssl_cert_chain(p, sk, var+21, 0);
}
else if (ssl != NULL && strcEQ(var, "CLIENT_CERT_RFC4523_CEA")) {
result = ssl_var_lookup_ssl_cert_rfc4523_cea(p, ssl);
result = (nid == NID_undef) ? "UNKNOWN" : OBJ_nid2ln(nid);
}
else if (strcEQ(var, "CERT")) {
- result = ssl_var_lookup_ssl_cert_PEM(p, xs);
+ result = ssl_var_lookup_ssl_cert_data(p, xs, 1);
+ }
+ else if (strcEQ(var, "B64CERT")) {
+ result = ssl_var_lookup_ssl_cert_data(p, xs, 0);
}
return result;
return modssl_bio_free_read(p, bio);
}
-static const char *ssl_var_lookup_ssl_cert_chain(apr_pool_t *p, STACK_OF(X509) *sk, const char *var)
+static const char *ssl_var_lookup_ssl_cert_chain(apr_pool_t *p, STACK_OF(X509) *sk,
+ const char *var, int pem)
{
const char *result;
X509 *xs;
n = atoi(var);
if (n < sk_X509_num(sk)) {
xs = sk_X509_value(sk, n);
- result = ssl_var_lookup_ssl_cert_PEM(p, xs);
+ result = ssl_var_lookup_ssl_cert_data(p, xs, pem);
}
}
return result;
}
-static const char *ssl_var_lookup_ssl_cert_PEM(apr_pool_t *p, X509 *xs)
-{
- BIO *bio;
-
- if ((bio = BIO_new(BIO_s_mem())) == NULL)
- return NULL;
- PEM_write_bio_X509(bio, xs);
-
- return modssl_bio_free_read(p, bio);
-}
-
static const char *ssl_var_lookup_ssl_cert_verify(apr_pool_t *p,
const SSLConnRec *sslconn)
{