mturk 2005/06/11 00:02:15 Modified: jni/native/src sslutils.c Log: Implement verify callback mostly from mod_ssl. See if the simpler implementation would be OK. Revision Changes Path 1.24 +203 -3 jakarta-tomcat-connectors/jni/native/src/sslutils.c Index: sslutils.c =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/jni/native/src/sslutils.c,v retrieving revision 1.23 retrieving revision 1.24 diff -u -r1.23 -r1.24 --- sslutils.c 8 Jun 2005 07:59:34 -0000 1.23 +++ sslutils.c 11 Jun 2005 07:02:15 -0000 1.24 @@ -25,6 +25,7 @@ #include "apr_portable.h" #include "apr_thread_mutex.h" #include "apr_strings.h" +#include "apr_poll.h" #include "tcn.h" @@ -463,15 +464,214 @@ return n; } +static int SSL_X509_STORE_lookup(X509_STORE *store, int yype, + X509_NAME *name, X509_OBJECT *obj) +{ + X509_STORE_CTX ctx; + int rc; + + X509_STORE_CTX_init(&ctx, store, NULL, NULL); + rc = X509_STORE_get_by_subject(&ctx, yype, name, obj); + X509_STORE_CTX_cleanup(&ctx); + return rc; +} + +int SSL_callback_SSL_verify_CRL(int ok, X509_STORE_CTX *ctx, tcn_ssl_conn_t *con) +{ + 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 (!con->ctx->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)); + rc = SSL_X509_STORE_lookup(con->ctx->crl, + X509_LU_CRL, subject, &obj); + crl = obj.data.crl; + + if ((rc > 0) && crl) { + /* + * Log information about CRL + * (A little bit complicated because of ASN.1 and BIOs...) + */ + /* + * Verify the signature on this CRL + */ + pubkey = X509_get_pubkey(cert); + rc = X509_CRL_verify(crl, pubkey); + /* Only refcounted in OpenSSL */ + if (pubkey) + EVP_PKEY_free(pubkey); + if (rc <= 0) { + /* TODO: Log Invalid signature on CRL */ + X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE); + X509_OBJECT_free_contents(&obj); + return 0; + } + + /* + * Check date of CRL to make sure it's not expired + */ + i = X509_cmp_current_time(X509_CRL_get_nextUpdate(crl)); + + if (i == 0) { + /* TODO: Log 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 0; + } + + if (i < 0) { + /* TODO: Log Found CRL is expired */ + X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_HAS_EXPIRED); + X509_OBJECT_free_contents(&obj); + + return 0; + } + + 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(con->ctx->crl, + X509_LU_CRL, issuer, &obj); + + 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 = revoked->serialNumber; + + if (!ASN1_INTEGER_cmp(sn, X509_get_serialNumber(cert))) { + X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REVOKED); + X509_OBJECT_free_contents(&obj); + + return 0; + } + } + + X509_OBJECT_free_contents(&obj); + } + + return ok; +} + /* * This OpenSSL callback function is called when OpenSSL * does client authentication and verifies the certificate chain. */ int SSL_callback_SSL_verify(int ok, X509_STORE_CTX *ctx) { + /* Get Apache context back through OpenSSL context */ + SSL *ssl = X509_STORE_CTX_get_ex_data(ctx, + SSL_get_ex_data_X509_STORE_CTX_idx()); + tcn_ssl_conn_t *con = (tcn_ssl_conn_t *)SSL_get_app_data(ssl); + /* Get verify ingredients */ + int errnum = X509_STORE_CTX_get_error(ctx); + int errdepth = X509_STORE_CTX_get_error_depth(ctx); + int verify = con->ctx->verify_mode; + int depth = con->ctx->verify_depth; + + if (verify == SSL_CVERIFY_UNSET || + verify == SSL_CVERIFY_NONE) + return 1; + + if (SSL_VERIFY_ERROR_IS_OPTIONAL(errnum) && + (verify == SSL_CVERIFY_OPTIONAL_NO_CA)) + ok = TRUE; + + /* + * Additionally perform CRL-based revocation checks + */ + if (ok) { + if (!(ok = SSL_callback_SSL_verify_CRL(ok, ctx, con))) { + errnum = X509_STORE_CTX_get_error(ctx); + } + } + /* + * If we already know it's not ok, log the real reason + */ + if (!ok) { + /* TODO: Some logging + * Certificate Verification: Error + */ + if (con->cert) { + X509_free(con->cert); + con->cert = NULL; + } + } + if (errdepth > depth) { + /* TODO: Some logging + * Certificate Verification: Certificate Chain too long + */ + ok = 0; + } - /* TODO: Dummy function for now */ - return 1; + return ok; } #else
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]