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]