📄 ssl_engine_kernel.c
字号:
*/int ssl_callback_SSLVerify(int ok, X509_STORE_CTX *ctx){ SSL *ssl; conn_rec *conn; server_rec *s; request_rec *r; SSLSrvConfigRec *sc; SSLDirConfigRec *dc; ap_ctx *actx; X509 *xs; int errnum; int errdepth; char *cp; char *cp2; int depth; int verify; /* * Get Apache context back through OpenSSL context */ ssl = (SSL *)X509_STORE_CTX_get_app_data(ctx); conn = (conn_rec *)SSL_get_app_data(ssl); actx = (ap_ctx *)SSL_get_app_data2(ssl); r = (request_rec *)ap_ctx_get(actx, "ssl::request_rec"); s = conn->server; sc = mySrvConfig(s); dc = (r != NULL ? myDirConfig(r) : NULL); /* * Get verify ingredients */ xs = X509_STORE_CTX_get_current_cert(ctx); errnum = X509_STORE_CTX_get_error(ctx); errdepth = X509_STORE_CTX_get_error_depth(ctx); /* * Log verification information */ cp = X509_NAME_oneline(X509_get_subject_name(xs), NULL, 0); cp2 = X509_NAME_oneline(X509_get_issuer_name(xs), NULL, 0); ssl_log(s, SSL_LOG_TRACE, "Certificate Verification: depth: %d, subject: %s, issuer: %s", errdepth, cp != NULL ? cp : "-unknown-", cp2 != NULL ? cp2 : "-unknown"); if (cp) free(cp); if (cp2) free(cp2); /* * Check for optionally acceptable non-verifiable issuer situation */ if (dc != NULL && dc->nVerifyClient != SSL_CVERIFY_UNSET) verify = dc->nVerifyClient; else verify = sc->nVerifyClient; if ( ( 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_UNABLE_TO_VERIFY_LEAF_SIGNATURE ) && verify == SSL_CVERIFY_OPTIONAL_NO_CA ) { ssl_log(s, SSL_LOG_TRACE, "Certificate Verification: Verifiable Issuer is configured as " "optional, therefore we're accepting the certificate"); ap_ctx_set(conn->client->ctx, "ssl::verify::info", "GENEROUS"); ok = TRUE; } /* * Additionally perform CRL-based revocation checks */ if (ok) { ok = ssl_callback_SSLVerify_CRL(ok, ctx, s); if (!ok) errnum = X509_STORE_CTX_get_error(ctx); } /* * If we already know it's not ok, log the real reason */ if (!ok) { ssl_log(s, SSL_LOG_ERROR, "Certificate Verification: Error (%d): %s", errnum, X509_verify_cert_error_string(errnum)); ap_ctx_set(conn->client->ctx, "ssl::client::dn", NULL); ap_ctx_set(conn->client->ctx, "ssl::verify::error", (void *)X509_verify_cert_error_string(errnum)); } /* * Finally check the depth of the certificate verification */ if (dc != NULL && dc->nVerifyDepth != UNSET) depth = dc->nVerifyDepth; else depth = sc->nVerifyDepth; if (errdepth > depth) { ssl_log(s, SSL_LOG_ERROR, "Certificate Verification: Certificate Chain too long " "(chain has %d certificates, but maximum allowed are only %d)", errdepth, depth); ap_ctx_set(conn->client->ctx, "ssl::verify::error", (void *)X509_verify_cert_error_string(X509_V_ERR_CERT_CHAIN_TOO_LONG)); ok = FALSE; } /* * And finally signal OpenSSL the (perhaps changed) state */ return (ok);}int ssl_callback_SSLVerify_CRL( int ok, X509_STORE_CTX *ctx, server_rec *s){ SSLSrvConfigRec *sc; X509_OBJECT obj; X509_NAME *subject; X509_NAME *issuer; X509 *xs; X509_CRL *crl; X509_REVOKED *revoked; long serial; BIO *bio; int i, n, rc; char *cp; char *cp2; /* * Unless a revocation store for CRLs was created we * cannot do any CRL-based verification, of course. */ sc = mySrvConfig(s); if (sc->pRevocationStore == NULL) return ok; /* * Determine certificate ingredients in advance */ xs = X509_STORE_CTX_get_current_cert(ctx); subject = X509_get_subject_name(xs); issuer = X509_get_issuer_name(xs); /* * 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)); rc = SSL_X509_STORE_lookup(sc->pRevocationStore, X509_LU_CRL, subject, &obj); crl = obj.data.crl; if (rc > 0 && crl != NULL) { /* * Log information about CRL * (A little bit complicated because of ASN.1 and BIOs...) */ if (ssl_log_applies(s, SSL_LOG_TRACE)) { bio = BIO_new(BIO_s_mem()); 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_pending(bio); cp = malloc(n+1); n = BIO_read(bio, cp, n); cp[n] = NUL; BIO_free(bio); cp2 = X509_NAME_oneline(subject, NULL, 0); ssl_log(s, SSL_LOG_TRACE, "CA CRL: Issuer: %s, %s", cp2, cp); free(cp2); free(cp); } /* * Verify the signature on this CRL */ if (X509_CRL_verify(crl, X509_get_pubkey(xs)) <= 0) { ssl_log(s, SSL_LOG_WARN, "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) { ssl_log(s, SSL_LOG_WARN, "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) { ssl_log(s, SSL_LOG_WARN, "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)); rc = SSL_X509_STORE_lookup(sc->pRevocationStore, X509_LU_CRL, issuer, &obj); crl = obj.data.crl; if (rc > 0 && crl != NULL) { /* * Check if the current certificate is revoked by this CRL */#if SSL_LIBRARY_VERSION < 0x00904000 n = sk_num(X509_CRL_get_REVOKED(crl));#else n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));#endif for (i = 0; i < n; i++) {#if SSL_LIBRARY_VERSION < 0x00904000 revoked = (X509_REVOKED *)sk_value(X509_CRL_get_REVOKED(crl), i);#else revoked = sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);#endif if (ASN1_INTEGER_cmp(revoked->serialNumber, X509_get_serialNumber(xs)) == 0) { serial = ASN1_INTEGER_get(revoked->serialNumber); cp = X509_NAME_oneline(issuer, NULL, 0); ssl_log(s, SSL_LOG_INFO, "Certificate with serial %ld (0x%lX) " "revoked per CRL from issuer %s", serial, serial, cp); 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;}/* * This callback function is executed by OpenSSL whenever a new SSL_SESSION is * added to the internal OpenSSL session cache. We use this hook to spread the * SSL_SESSION also to the inter-process disk-cache to make share it with our * other Apache pre-forked server processes. */int ssl_callback_NewSessionCacheEntry(SSL *ssl, SSL_SESSION *pNew){ conn_rec *conn; server_rec *s; SSLSrvConfigRec *sc; long t; BOOL rc; /* * Get Apache context back through OpenSSL context */ conn = (conn_rec *)SSL_get_app_data(ssl); s = conn->server; sc = mySrvConfig(s); /* * Set the timeout also for the internal OpenSSL cache, because this way * our inter-process cache is consulted only when it's really necessary. */ t = sc->nSessionCacheTimeout; SSL_set_timeout(pNew, t); /* * Store the SSL_SESSION in the inter-process cache with the * same expire time, so it expires automatically there, too. */ t = (SSL_get_time(pNew) + sc->nSessionCacheTimeout); rc = ssl_scache_store(s, pNew, t); /* * Log this cache operation */ ssl_log(s, SSL_LOG_TRACE, "Inter-Process Session Cache: " "request=SET status=%s id=%s timeout=%ds (session caching)", rc == TRUE ? "OK" : "BAD", ssl_scache_id2sz(pNew->session_id, pNew->session_id_length), t-time(NULL)); /* * return 0 which means to OpenSSL that the pNew is still * valid and was not freed by us with SSL_SESSION_free(). */ return 0;}/* * This callback function is executed by OpenSSL whenever a * SSL_SESSION is looked up in the internal OpenSSL cache and it * was not found. We use this to lookup the SSL_SESSION in the * inter-process disk-cache where it was perhaps stored by one * of our other Apache pre-forked server processes. */SSL_SESSION *ssl_callback_GetSessionCacheEntry( SSL *ssl, unsigned char *id, int idlen, int *pCopy){ conn_rec *conn; server_rec *s; SSL_SESSION *pSession; /* * Get Apache context back through OpenSSL context */ conn = (conn_rec *)SSL_get_app_data(ssl); s = conn->server;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -