From 90ffd9c7d81263231c9fcfe9e500503eed854de5 Mon Sep 17 00:00:00 2001 From: Andrew McNab Date: Thu, 26 Jun 2008 14:28:28 +0000 Subject: [PATCH] Sync --- org.gridsite.core/src/mod_gridsite.c | 228 +++++++++++++++++++++++++++++++- org.gridsite.core/src/mod_ssl-private.h | 9 ++ 2 files changed, 233 insertions(+), 4 deletions(-) diff --git a/org.gridsite.core/src/mod_gridsite.c b/org.gridsite.core/src/mod_gridsite.c index b6d28d8..6a04c54 100644 --- a/org.gridsite.core/src/mod_gridsite.c +++ b/org.gridsite.core/src/mod_gridsite.c @@ -132,6 +132,12 @@ char *ocspmodes = NULL; struct sitecast_group sitecastgroups[GRST_SITECAST_GROUPS+1]; struct sitecast_alias sitecastaliases[GRST_SITECAST_ALIASES]; +#if AP_MODULE_MAGIC_AT_LEAST(20051115,0) +/* SSL_app_data2_idx is private in Apache 2.2 mod_ssl but can be + determined at init time, and then recorded here */ +int GRST_SSL_app_data2_idx = -1; +#endif + typedef struct { int auth; @@ -3418,6 +3424,210 @@ int GRST_verify_cert_wrapper(X509_STORE_CTX *ctx, void *p) return X509_verify_cert(ctx); } +#if AP_MODULE_MAGIC_AT_LEAST(20051115,0) +/* + Include this here until libgridsite functions can be used +*/ +int GRST_ssl_callback_SSLVerify_CRL(int ok, X509_STORE_CTX *ctx, conn_rec *c) +{ + server_rec *s = c->base_server; + SSLSrvConfigRec *sc = (SSLSrvConfigRec *) ap_get_module_config(s->module_config, &ssl_module); + SSLConnRec *sslconn = (SSLConnRec *) ap_get_module_config(c->conn_config, &ssl_module); + modssl_ctx_t *mctx = sslconn->is_proxy ? sc->proxy : sc->server; + X509_OBJECT obj; + X509_NAME *subject, *issuer; + X509 *cert; + X509_CRL *crl; + EVP_PKEY *pubkey; + int i, n, rc; + + /* + * Unless a revocation store for CRLs was created we + * cannot do any CRL-based verification, of course. + */ + if (!mctx->crl) { + return ok; + } + + /* + * Determine certificate ingredients in advance + */ + cert = X509_STORE_CTX_get_current_cert(ctx); + subject = X509_get_subject_name(cert); + issuer = X509_get_issuer_name(cert); + + /* + * OpenSSL provides the general mechanism to deal with CRLs but does not + * use them automatically when verifying certificates, so we do it + * explicitly here. We will check the CRL for the currently checked + * certificate, if there is such a CRL in the store. + * + * We come through this procedure for each certificate in the certificate + * chain, starting with the root-CA's certificate. At each step we've to + * both verify the signature on the CRL (to make sure it's a valid CRL) + * and it's revocation list (to make sure the current certificate isn't + * revoked). But because to check the signature on the CRL we need the + * public key of the issuing CA certificate (which was already processed + * one round before), we've a little problem. But we can both solve it and + * at the same time optimize the processing by using the following + * verification scheme (idea and code snippets borrowed from the GLOBUS + * project): + * + * 1. We'll check the signature of a CRL in each step when we find a CRL + * through the _subject_ name of the current certificate. This CRL + * itself will be needed the first time in the next round, of course. + * But we do the signature processing one round before this where the + * public key of the CA is available. + * + * 2. We'll check the revocation list of a CRL in each step when + * we find a CRL through the _issuer_ name of the current certificate. + * This CRLs signature was then already verified one round before. + * + * This verification scheme allows a CA to revoke its own certificate as + * well, of course. + */ + + /* + * Try to retrieve a CRL corresponding to the _subject_ of + * the current certificate in order to verify it's integrity. + */ + memset((char *)&obj, 0, sizeof(obj)); + { + X509_STORE_CTX pStoreCtx; + X509_STORE_CTX_init(&pStoreCtx, mctx->crl, NULL, NULL); + rc = X509_STORE_get_by_subject(&pStoreCtx, X509_LU_CRL, subject, &obj); + X509_STORE_CTX_cleanup(&pStoreCtx); + } + + crl = obj.data.crl; + + if ((rc > 0) && crl) { + /* + * Log information about CRL + * (A little bit complicated because of ASN.1 and BIOs...) + */ + if (s->loglevel >= APLOG_DEBUG) { + char buff[512]; /* should be plenty */ + BIO *bio = BIO_new(BIO_s_mem()); + + BIO_printf(bio, "CA CRL: Issuer: "); + X509_NAME_print(bio, issuer, 0); + + BIO_printf(bio, ", lastUpdate: "); + ASN1_UTCTIME_print(bio, X509_CRL_get_lastUpdate(crl)); + + BIO_printf(bio, ", nextUpdate: "); + ASN1_UTCTIME_print(bio, X509_CRL_get_nextUpdate(crl)); + + n = BIO_read(bio, buff, sizeof(buff) - 1); + buff[n] = '\0'; + + BIO_free(bio); + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "%s", buff); + } + + /* + * Verify the signature on this CRL + */ + pubkey = X509_get_pubkey(cert); + rc = X509_CRL_verify(crl, pubkey); +#ifdef OPENSSL_VERSION_NUMBER + /* Only refcounted in OpenSSL */ + if (pubkey) + EVP_PKEY_free(pubkey); +#endif + if (rc <= 0) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "Invalid signature on CRL"); + + X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE); + X509_OBJECT_free_contents(&obj); + return FALSE; + } + + /* + * Check date of CRL to make sure it's not expired + */ + i = X509_cmp_current_time(X509_CRL_get_nextUpdate(crl)); + + if (i == 0) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "Found CRL has invalid nextUpdate field"); + + X509_STORE_CTX_set_error(ctx, + X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD); + X509_OBJECT_free_contents(&obj); + + return FALSE; + } + + if (i < 0) { + ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, + "Found CRL is expired - " + "revoking all certificates until you get updated CRL"); + + X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_HAS_EXPIRED); + X509_OBJECT_free_contents(&obj); + + return FALSE; + } + + X509_OBJECT_free_contents(&obj); + } + + /* + * Try to retrieve a CRL corresponding to the _issuer_ of + * the current certificate in order to check for revocation. + */ + memset((char *)&obj, 0, sizeof(obj)); + { + X509_STORE_CTX pStoreCtx; + X509_STORE_CTX_init(&pStoreCtx, mctx->crl, NULL, NULL); + rc = X509_STORE_get_by_subject(&pStoreCtx, X509_LU_CRL, issuer, &obj); + X509_STORE_CTX_cleanup(&pStoreCtx); + } + + crl = obj.data.crl; + if ((rc > 0) && crl) { + /* + * Check if the current certificate is revoked by this CRL + */ + n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl)); + + for (i = 0; i < n; i++) { + X509_REVOKED *revoked = + sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i); + +// ASN1_INTEGER *sn = X509_REVOKED_get_serialNumber(revoked); + ASN1_INTEGER *sn = revoked->serialNumber; + + if (!ASN1_INTEGER_cmp(sn, X509_get_serialNumber(cert))) { + if (s->loglevel >= APLOG_DEBUG) { + char *cp = X509_NAME_oneline(issuer, NULL, 0); + long serial = ASN1_INTEGER_get(sn); + + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "Certificate with serial %ld (0x%lX) " + "revoked per CRL from issuer %s", + serial, serial, cp); + OPENSSL_free(cp); + } + + X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REVOKED); + X509_OBJECT_free_contents(&obj); + + return FALSE; + } + } + + X509_OBJECT_free_contents(&obj); + } + + return ok; +} +#endif + int GRST_callback_SSLVerify_wrapper(int ok, X509_STORE_CTX *ctx) { SSL *ssl = (SSL *) X509_STORE_CTX_get_app_data(ctx); @@ -3430,7 +3640,7 @@ int GRST_callback_SSLVerify_wrapper(int ok, X509_STORE_CTX *ctx) int returned_ok; int first_non_ca; #if AP_MODULE_MAGIC_AT_LEAST(20051115,0) - request_rec *r = (request_rec *)SSL_get_app_data2(ssl); + request_rec *r = (request_rec *) SSL_get_ex_data(ssl, GRST_SSL_app_data2_idx); SSLSrvConfigRec *sc = (SSLSrvConfigRec *) ap_get_module_config(s->module_config, &ssl_module); SSLDirConfigRec *dc = r ? (SSLDirConfigRec *) ap_get_module_config(r->per_dir_config, &ssl_module) : NULL; modssl_ctx_t *mctx = sslconn->is_proxy ? sc->proxy : sc->server; @@ -3456,9 +3666,9 @@ int GRST_callback_SSLVerify_wrapper(int ok, X509_STORE_CTX *ctx) sname ? sname : "-unknown-", iname ? iname : "-unknown-"); - if (sname) modssl_free(sname); + if (sname) OPENSSL_free(sname); - if (iname) modssl_free(iname); + if (iname) OPENSSL_free(iname); } /* @@ -3500,7 +3710,7 @@ int GRST_callback_SSLVerify_wrapper(int ok, X509_STORE_CTX *ctx) */ if (ok) { - if (!(ok = ssl_callback_SSLVerify_CRL(ok, ctx, conn))) + if (!(ok = GRST_ssl_callback_SSLVerify_CRL(ok, ctx, conn))) { errnum = X509_STORE_CTX_get_error(ctx); } @@ -4017,6 +4227,16 @@ static int mod_gridsite_server_post_config(apr_pool_t *pPool, ap_add_version_component(pPool, apr_psprintf(pPool, "mod_gridsite/%s", VERSION)); +#if AP_MODULE_MAGIC_AT_LEAST(20051115,0) + /* establish value of SSL_app_data2_idx and record it */ + GRST_SSL_app_data2_idx = SSL_get_ex_new_index(0, + "Dummy Application Data for mod_gridsite", + NULL, NULL, NULL) - 1; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, main_server, + "mod_gridsite: GRST_SSL_app_data2_idx=%d", + GRST_SSL_app_data2_idx); +#endif + for (this_server = main_server; this_server != NULL; this_server = this_server->next) diff --git a/org.gridsite.core/src/mod_ssl-private.h b/org.gridsite.core/src/mod_ssl-private.h index 4a7bd52..f4d3582 100644 --- a/org.gridsite.core/src/mod_ssl-private.h +++ b/org.gridsite.core/src/mod_ssl-private.h @@ -93,6 +93,14 @@ typedef enum { SSL_CVERIFY_REQUIRE = 2, SSL_CVERIFY_OPTIONAL_NO_CA = 3 } ssl_verify_t; + +#define ssl_verify_error_is_optional(errnum) \ + ((errnum == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) \ + || (errnum == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) \ + || (errnum == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) \ + || (errnum == X509_V_ERR_CERT_UNTRUSTED) \ + || (errnum == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE)) + #endif typedef struct { @@ -172,4 +180,5 @@ typedef struct { } SSLDirConfigRec; #endif + extern module AP_MODULE_DECLARE_DATA ssl_module; -- 1.8.2.3