--- ../../../../mod_ssl-2.2.8-1.3.6/pkg.sslmod/ssl_engine_kernel.c	Wed May 19 18:43:02 1999
+++ ./ssl_engine_kernel.c	Mon Jun 14 15:41:00 1999
@@ -108,7 +108,8 @@
                                   time I was too famous.''
                                             -- Unknown                */
 #include "mod_ssl.h"
-  
+#include "mod_ldap.h"
+
 /*  _________________________________________________________________
 **
 **  SSL Engine Kernel
@@ -913,6 +914,7 @@
     }
 #endif /* SSL_EXPERIMENTAL */
 
+
     /*
      * Check SSLRequire boolean expressions
      */
@@ -986,6 +988,11 @@
     "SSL_CLIENT_I_DN_Email",
     "SSL_CLIENT_A_KEY",
     "SSL_CLIENT_A_SIG",
+    /*
+     * Giacob: new env var for certificate and response status
+     */
+    "SSL_OCSP_LDAP_RESP_STATUS",
+    "SSL_OCSP_LDAP_CERT_STATUS",
     "SSL_SERVER_M_VERSION",
     "SSL_SERVER_M_SERIAL",
     "SSL_SERVER_V_START",
@@ -1011,6 +1018,466 @@
     NULL
 };
 
+/*
+ * Giacob: ldap cert status check
+ */
+void ldap_check_hook(request_rec *r, X509 *xs,  SSLSrvConfigRec *sc, conn_rec *conn) 
+{
+    RESPONSE_FILE *response = NULL;
+    STRTBL *table; 
+    char ou[20];
+    X509_NAME *xn;
+    LDAP_FILE *ldap;
+    pool *buf_pool;
+    
+    buf_pool=ap_make_sub_pool(r->pool);
+ 
+    xn = X509_get_subject_name(xs);
+    X509_NAME_get_text_by_NID(xn, NID_organizationalUnitName, ou, 20);
+    
+    ldap = (LDAP_FILE *)ap_palloc(buf_pool, (sizeof(LDAP_FILE)));
+    if (ldap == NULL) {
+        ssl_log(r->server, SSL_LOG_ERROR, "Allocation memory error");
+        response->rsp_status = OCSP_RESPONSE_STATUS_INTERNALERROR;
+        response->cert_file->status = V_OCSP_CERTSTATUS_UNKNOWN;
+        table = &respStatus[response->rsp_status];
+        ap_ctx_set(conn->client->ctx, "ssl::ocsp::resp::status", table->m);
+        table = &certStatus[response->cert_file->status];
+        ap_ctx_set(conn->client->ctx, "ssl::ocsp::cert::status", table->m);
+        return;  
+    }
+    else {
+        ldap->servers = sc->ldapServers;
+        ldap->base_dn = sc->ldapBaseDn; 
+        ldap->user = sc->ldapUser;
+        ldap->pwd = sc->ldapPwd;
+    }
+     
+    if (!strcmp(ou, "Developer")) {
+        response = ocsp_responder_hook (r, xs, ldap);
+        if (response != NULL) {
+            table = &respStatus[response->rsp_status];
+            ap_ctx_set(conn->client->ctx, "ssl::ocsp::resp::status", table->m);
+            table = &certStatus[response->cert_file->status];
+            ap_ctx_set(conn->client->ctx, "ssl::ocsp::cert::status", table->m);
+        }
+    }
+    free(ldap);
+return;
+}
+
+/*
+ * Giacob: retrieve cert status from ldap 
+ */  
+RESPONSE_FILE *ocsp_ldap_hook(request_rec *r, X509 *xs, LDAP_FILE *ldap, char *mail, char *time)
+{ 
+    RESPONSE_FILE *response; 
+    LDAP *ld;
+    LDAPMessage *res;
+    LDAPMessage *e;
+    char filtpattern[1024];
+    char *certificate;
+    char *attrs[] = {"mail", "dn", "usercertificate;binary", NULL};
+    unsigned char *cert;
+    unsigned char *buf;
+    int len;
+    int done;
+    int rc;
+    pool *buf_pool;
+    
+    buf_pool=ap_make_sub_pool(r->pool);
+
+    /* Default response: certificate status REVOKED */
+    response->rsp_status = OCSP_RESPONSE_STATUS_SUCCESSFULL;
+    response->cert_file->status = V_OCSP_CERTSTATUS_REVOKED;
+    response->cert_file->reason = OCSP_REVOKED_STATUS_KEYCOMPROMISE;
+    response->cert_file->time = time;
+
+    /* Convert certificate from X509* to DER, put it in a string certificate */
+    len = i2d_X509(xs, NULL);
+    cert = (unsigned char *)ap_palloc(buf_pool, len);
+    if (cert == NULL) {
+        ssl_log(r->server, SSL_LOG_ERROR, "Allocation memory error");
+        response->rsp_status = OCSP_RESPONSE_STATUS_INTERNALERROR;
+        response->cert_file->status = V_OCSP_CERTSTATUS_UNKNOWN;
+        return response;
+    }
+    else {
+        buf = cert;
+        if (!(i2d_X509(xs, &buf))) { 
+            ssl_log(r->server, SSL_LOG_ERROR, "Can't convert X509 certificate in DER format");
+            response->rsp_status = OCSP_RESPONSE_STATUS_INTERNALERROR;
+            response->cert_file->status = V_OCSP_CERTSTATUS_UNKNOWN;
+            return response;
+        }
+        certificate = (char *)cert;
+    } 
+
+   ssl_log(r->server, SSL_LOG_INFO, "Certificate to verify lenght in bytes: %d", len);
+   
+   if ((ld = ldap_init(ldap->servers, 0)) == NULL ) {
+       ssl_log(r->server, SSL_LOG_ERROR, "Can't initialize ldap support");
+       response->rsp_status = OCSP_RESPONSE_STATUS_INTERNALERROR;
+       response->cert_file->status = V_OCSP_CERTSTATUS_UNKNOWN;
+       return response;
+   }
+   ld -> ld_options = LDAP_OPT_REFERRALS;
+   ld -> ld_sizelimit = 0;
+   ld -> ld_timelimit = 0;
+   ld -> ld_deref = LDAP_DEREF_ALWAYS;
+   
+   if ((rc = ldap_bind_s (ld, NULL, NULL, LDAP_AUTH_SIMPLE)) != LDAP_SUCCESS) {
+       ssl_log(r->server, SSL_LOG_ERROR, "Can't bind to LDAP server: %s",ldap_err2string (rc));
+       response->rsp_status = OCSP_RESPONSE_STATUS_TRYLATER;
+       response->cert_file->status = V_OCSP_CERTSTATUS_UNKNOWN;
+       return response;
+   } 
+   else ssl_log(r->server, SSL_LOG_TRACE, "Binded to LDAP server");
+   
+   /* Build filter for ldap search by e-mail */
+   ldap_build_filter(filtpattern, 1024, "(%a=%v)", NULL, NULL, "mail", mail, NULL);
+   
+   if (ldap_search(ld, ldap->base_dn, LDAP_SCOPE_SUBTREE, filtpattern, attrs, 0) == -1) {
+       ssl_log(r->server, SSL_LOG_ERROR, "User %s NOT found in LDAP\n", mail);
+       response->rsp_status = OCSP_RESPONSE_STATUS_UNAUTHORIZED;
+       response->cert_file->status = V_OCSP_CERTSTATUS_UNKNOWN;
+       return response;
+   } 
+   else ssl_log(r->server, SSL_LOG_TRACE, "User %s found in LDAP", mail);
+   
+   done = 0;
+   
+   /* Retrieve results of ldap search: must be just one entry */
+   while ((rc = ldap_result(ld, LDAP_RES_ANY, 0, NULL, &res)) == LDAP_RES_SEARCH_ENTRY) {
+       e = ldap_first_entry(ld, res);
+       get_entry_hook(r, ld, e, &response, cert, len);
+       ldap_msgfree(res);
+       done = 1;
+   }
+   
+   if (!done) {
+       ssl_log(r->server, SSL_LOG_ERROR, "Ldap search result not retrieved: %s.\n", ldap_err2string (rc));
+       response->rsp_status = OCSP_RESPONSE_STATUS_UNAUTHORIZED;
+       response->cert_file->status = V_OCSP_CERTSTATUS_UNKNOWN;
+       return response;
+   }
+   
+   ldap_msgfree(res);
+   ldap_unbind(ld);
+   free(cert);
+   
+return response;
+}  
+
+/*
+ * Giacob: process data retrieved from ldap
+ */
+void get_entry_hook(request_rec *r, LDAP *ld, LDAPMessage *entry, RESPONSE_FILE **response, char *cert, int len)
+{
+    char *attribute;
+    char *value;
+    char *cert_ldap;
+    char *ldapc;
+    char *clientc;
+    int cert_len;
+    BerElement *ber;
+    struct berval **bvals;
+    int k;
+   
+    /* Retrieve attributes of the entry found by ldap search */
+    for (attribute = ldap_first_attribute(ld, entry, &ber); attribute != NULL; attribute = ldap_next_attribute(ld, entry, ber)) {
+        if ((bvals = ldap_get_values_len(ld, entry, attribute)) != NULL) {
+            /* Get each attribute value of current entry */
+            for (k = 0; bvals[k] != NULL; k++) {
+                value = bvals[k]->bv_val;
+                if (!strcmp(attribute, "usercertificate;binary")) {
+                    cert_ldap = value;
+                    cert_len = bvals[k]->bv_len;
+                    ssl_log(r->server, SSL_LOG_INFO, "Certificate found in LDAP long %d bytes.\n", cert_len);
+                       
+                    /* cert_ldap, cert_len = current certificate from LDAP in DER, certificate lenght in byte */
+                    /* cert, len  = certificate to verify, certificate lenght in byte */
+                    if (cert_len == len) {
+                        /* Verify certificate found in LDAP */
+                        clientc = cert;
+                        ldapc = cert_ldap;
+                            
+                        while (ldapc < cert_ldap + cert_len && *ldapc++ == *clientc++); /* NULL INSTRUCTION */
+   
+                        if (ldapc == cert_ldap + cert_len) { 
+                            /* Certificate found ! */
+                            (*response)->rsp_status = OCSP_RESPONSE_STATUS_SUCCESSFULL;
+                            (*response)->cert_file->status = V_OCSP_CERTSTATUS_GOOD;
+                        }
+                    }
+                }
+                /* Nothing on other attributes retrieved: mail, cn */
+                else;
+            }
+        }
+        /* Frees array of berval returned from search */
+        ber_bvecfree(bvals);
+    }
+
+return;
+}
+
+/*
+ * Giacob: creating ocsp request on certificate
+ */
+OCSP_REQUEST *ocsp_request_hook(request_rec *r, X509 *xs, OCSP_CERTID *certid)
+{
+    OCSP_REQUEST *req = NULL;
+    X509_NAME *xn = NULL;
+    BIO *bio = NULL;
+    STACK *extns = NULL;
+    pool *buf_pool;
+    FILE *fp_ocsp;
+  
+    buf_pool=ap_make_sub_pool(r->pool);
+   
+    xn = X509_get_subject_name(xs);
+
+    if (!(req = OCSP_request_new(xn, extns))) { 
+        ssl_log(r->server, SSL_LOG_ERROR, "Can't create OCSP request");
+        return NULL;
+    } 
+    else ssl_log(r->server, SSL_LOG_TRACE, "OCSP request created");
+
+    if (OCSP_request_add(req, certid, NULL) == 0) {
+        ssl_log(r->server, SSL_LOG_ERROR, "Can't put data in OCSP Request");
+        if (req) OCSP_REQUEST_free(req);
+        return NULL; 
+    }
+    else ssl_log(r->server, SSL_LOG_TRACE, "OCSP Request filled with data");
+
+    if ((fp_ocsp = ap_pfopen(buf_pool, OCSP_FILE_PATH, WRITE_ONLY)) == NULL)
+        ssl_log(r->server, SSL_LOG_ERROR, "Can't open OCSP file to log OCSP Request");
+    else {
+        if ((bio = BIO_new(BIO_s_file())) == NULL)
+            ssl_log(r->server, SSL_LOG_ERROR, "Can't create new bio_file to log OCSP Request");
+        else {
+            BIO_set_fp(bio, fp_ocsp, BIO_NOCLOSE);
+            if (!(OCSP_REQUEST_print(bio, req))) 
+                ssl_log(r->server, SSL_LOG_ERROR, "Can't log OCSP Request");
+            ap_pfclose(buf_pool, fp_ocsp);
+        }
+    }
+
+return req;
+}
+
+/*
+ * Giacob: creating ocsp response on certificate
+ */    
+OCSP_RESPONSE *ocsp_response_hook(request_rec *r, int id, int rsp_status, X509 *xs, OCSP_CERTID *certid, 
+                                  OCSP_CERTSTATUS *ocsp_status, char *this, char *next)
+{   
+    OCSP_BASICRESP *brsp = NULL;
+    OCSP_RESPONSE *rsp = NULL;
+    X509_NAME *xn;
+    X509 *xs_srvr;
+    EVP_PKEY *key;
+    STACK *sk;
+    BIO *bio;
+    FILE *fp_srvr;
+    FILE *fp_ocsp;
+    pool *buf_pool;
+    
+    xn = X509_get_subject_name(xs);
+    buf_pool=ap_make_sub_pool(r->pool);
+
+    if ((fp_srvr = ap_pfopen(buf_pool, SERVER_CERT_PATH, READ_ONLY)) == NULL) {
+        ssl_log(r->server, SSL_LOG_ERROR, "Can't open server certificate file");  
+        if (brsp) OCSP_BASICRESP_free(brsp);
+        return NULL;
+    }
+
+    xs_srvr = PEM_read_X509(fp_srvr, NULL, NULL);
+    ap_pfclose(buf_pool, fp_srvr);
+    if (!xs_srvr) {
+        ssl_log(r->server, SSL_LOG_ERROR, "Can't read server certificate file");
+        if (brsp) OCSP_BASICRESP_free(brsp);
+        return NULL;
+    }
+
+    if (!(brsp = OCSP_basic_response_new(id, xs_srvr, NULL))) {
+        ssl_log(r->server, SSL_LOG_ERROR, "Cant't create OCSP basic response");
+        return NULL;
+    }
+    else ssl_log(r->server, SSL_LOG_TRACE, "OCSP basic response created");
+
+    if (!(OCSP_basic_response_add(brsp, certid, ocsp_status, this, next, NULL))) {
+        ssl_log(r->server, SSL_LOG_ERROR, "Can't put data in OCSP basic response");
+        if (brsp) OCSP_BASICRESP_free(brsp);
+        return NULL;
+    }
+    else ssl_log(r->server, SSL_LOG_TRACE, "OCSP basic response filled with data");
+ 
+    if (!(sk = sk_new(NULL))) {
+        ssl_log(r->server, SSL_LOG_ERROR, "Can't initialize stack");
+        if (brsp) OCSP_BASICRESP_free(brsp);
+        return NULL;
+    }
+
+    if (!sk_push(sk, (char *)xs_srvr)) {
+        ssl_log(r->server, SSL_LOG_ERROR, "Can't put server certificate in stack");
+        if (brsp) OCSP_BASICRESP_free(brsp);
+        return NULL;
+    }
+
+    if ((fp_srvr = ap_pfopen(buf_pool, SERVER_KEY_PATH, READ_ONLY)) == NULL) {
+        ssl_log(r->server, SSL_LOG_ERROR, "Can't open server key file");   
+        if (brsp) OCSP_BASICRESP_free(brsp);
+        return NULL;
+    }
+
+    key = PEM_read_PrivateKey(fp_srvr, NULL, NULL);
+    ap_pfclose(buf_pool, fp_srvr);
+    if (!key) {
+        ssl_log(r->server, SSL_LOG_ERROR, "Can't read server key file");
+        if (brsp) OCSP_BASICRESP_free(brsp);
+        return NULL;
+    }
+
+    if (!(OCSP_basic_response_sign(brsp, key, EVP_sha1(), sk))) {
+        ssl_log(r->server, SSL_LOG_ERROR, "Can't sign OCSP basic response");
+        if (brsp) OCSP_BASICRESP_free(brsp);
+        return NULL;
+    }
+    else ssl_log(r->server, SSL_LOG_TRACE, "OCSP basic response signed with server certificate");
+
+    if (!(rsp = OCSP_response_new(rsp_status, NID_id_pkix_ocsp_basic, i2d_OCSP_BASICRESP, (char *)brsp))) {
+        ssl_log(r->server, SSL_LOG_ERROR, "Can't create OCSP response");
+        if (brsp) OCSP_BASICRESP_free(brsp);
+        return NULL;
+    }
+    else ssl_log(r->server, SSL_LOG_TRACE, "OCSP response created");
+
+    if (!(OCSP_response_verify(rsp, X509_get_pubkey(xs_srvr)))) {
+        ssl_log(r->server, SSL_LOG_ERROR, "Can't verify OCSP response");  
+        if (brsp) OCSP_BASICRESP_free(brsp);
+        return NULL;
+    } 
+    else ssl_log(r->server, SSL_LOG_TRACE, "OCSP response verified");
+    
+    if ((fp_ocsp = ap_pfopen(buf_pool, OCSP_FILE_PATH, APPEND)) == NULL)
+        ssl_log(r->server, SSL_LOG_ERROR, "Can't open OCSP file to log OCSP Response");  
+    else {
+        if ((bio = BIO_new(BIO_s_file())) == NULL)
+            ssl_log(r->server, SSL_LOG_ERROR, "Can't create new bio_file to log OCSP Response");
+        else {
+            BIO_set_fp(bio, fp_ocsp, BIO_NOCLOSE);
+            if (!(OCSP_RESPONSE_print(bio, rsp)))  
+                ssl_log(r->server, SSL_LOG_ERROR, "Can't log OCSP Response");  
+            ap_pfclose(buf_pool, fp_ocsp);     
+        }
+    } 
+
+    if (brsp) OCSP_BASICRESP_free(brsp);
+
+return rsp;
+} 
+
+/*
+ * Giacob: OCSP responder
+ */
+RESPONSE_FILE *ocsp_responder_hook(request_rec *r, X509 *xs, LDAP_FILE *ldap)  
+{
+    OCSP_CERTID *new_cid;
+    OCSP_REQUEST *new_req;
+    OCSP_RESPONSE *new_rsp;
+    OCSP_CERTSTATUS *cert_status;
+    X509 *xs_ca;
+    X509_NAME *xn;
+    RESPONSE_FILE *new_response;
+    STRTBL *table;
+    time_t tc;
+    struct tm *tm;
+    int rspid = V_OCSP_RESPID_NAME;
+    char ou[20];
+    char name[30];
+    char mail[30];
+    char *now;
+    char *this;
+    char *next;
+    FILE *fp_ca;
+    pool *buf_pool;
+
+    buf_pool=ap_make_sub_pool(r->pool);
+ 
+    xn = X509_get_subject_name(xs);
+    X509_NAME_get_text_by_NID(xn, NID_organizationalUnitName, ou, 20);
+
+    if ((fp_ca = ap_pfopen(buf_pool, CA_CERT_PATH, READ_ONLY)) == NULL) {
+        ssl_log(r->server, SSL_LOG_ERROR, "Can't open CA certificate file");   
+        return NULL;
+    }
+
+    xs_ca = PEM_read_X509(fp_ca, NULL, NULL);
+    ap_pfclose(buf_pool, fp_ca);
+    if (!xs_ca) {
+        ssl_log(r->server, SSL_LOG_ERROR, "Can't read CA certificate file");
+        return NULL;
+    }
+
+    tc = time(NULL);
+    tm = localtime(&tc);
+    /* now = local time */
+    now = ap_psprintf(buf_pool, "%02d%02d%02d%02d%02d%02d%02dZ", (tm->tm_year / 100) + 19, (tm->tm_year % 100), tm->tm_mon + 1, 
+                      tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+    /* this = this update of certificate status time */
+    this = ap_psprintf(buf_pool, "%02d%02d%02d%02d%02d%02d%02dZ", (tm->tm_year / 100) + 19, (tm->tm_year % 100), tm->tm_mon + 1, 
+                       tm->tm_mday, tm->tm_hour - 2, tm->tm_min, tm->tm_sec);
+    /* next = next avaiable update of certificate status time */
+    next = ap_psprintf(buf_pool, "%02d%02d%02d%02d%02d%02d%02dZ", (tm->tm_year / 100) + 19, (tm->tm_year % 100), tm->tm_mon + 2, 
+                       tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+    ssl_log(r->server, SSL_LOG_INFO, "OCSP response Time: %s, This: %s, Next: %s", now, this, next);
+
+    if (!(new_cid = OCSP_cert_id_new(EVP_md5(), X509_get_issuer_name(xs),
+                                     xs_ca->cert_info->key->public_key, X509_get_serialNumber(xs)))) {
+        ssl_log(r->server, SSL_LOG_ERROR, "Can't create certificate id");
+        return NULL;
+    }
+    else ssl_log(r->server, SSL_LOG_TRACE, "New certificate id created");
+
+    if (!(new_req = ocsp_request_hook (r, xs, new_cid))) return NULL;
+
+    X509_NAME_get_text_by_NID(xn, NID_commonName, name, 30);
+    X509_NAME_get_text_by_NID(xn, NID_pkcs9_emailAddress, mail, 30);
+
+    if (!(new_response = ocsp_ldap_hook(r, xs, ldap, mail, now))) {
+        ssl_log(r->server, SSL_LOG_ERROR, "Can't get status from LDAP directory");
+        return NULL;
+    }
+    else ssl_log(r->server, SSL_LOG_TRACE, "Ldap get status done");
+
+    new_response->cert_file->name = name;
+    new_response->cert_file->time = now;
+    new_response->cert_file->this = this;
+    new_response->cert_file->next = next;
+ 
+    if (!(cert_status = OCSP_cert_status_new(new_response->cert_file->status, new_response->cert_file->reason, now))) {
+        ssl_log(r->server, SSL_LOG_ERROR, "Can't create new certificate status");
+        return NULL;
+    }
+    else {
+        table = &certStatus[new_response->cert_file->status];
+        ssl_log(r->server, SSL_LOG_TRACE, "New certificate status created: %s", table->m);
+    }
+
+    if (!(new_rsp = ocsp_response_hook(r, rspid, new_response->rsp_status, xs, new_cid, cert_status, this, next))) return NULL;
+    else {
+        table = &respStatus[new_response->rsp_status];
+        ssl_log(r->server, SSL_LOG_INFO, "Response status: %s", table->m);
+    }
+
+    if (cert_status) OCSP_CERTSTATUS_free(cert_status);
+    
+return new_response;
+}
+
 
 int ssl_hook_Fixup(request_rec *r)
 {
@@ -1029,6 +1496,7 @@
     if (ap_ctx_get(r->connection->client->ctx, "ssl") == NULL)
         return DECLINED;
 
+
     /*
      * Annotate the SSI/CGI environment with standard SSL information
      */
@@ -1040,6 +1508,7 @@
             ap_table_set(e, var, val);
     }
 
+
     /*
      * On-demand bloat up the SSI/CGI environment with certificate data
      */
@@ -1163,6 +1632,7 @@
     s    = conn->server;
     sc   = mySrvConfig(s);
     dc   = (r != NULL ? myDirConfig(r) : NULL);
+    
 
     /*
      * Get verify ingredients
@@ -1224,8 +1694,13 @@
                 errdepth, depth);
         ap_ctx_set(conn->client->ctx, "ssl::verify::error",
                    X509_verify_cert_error_string(X509_V_ERR_CERT_CHAIN_TOO_LONG));
-        ok = FALSE;
+       ok = FALSE;
     }
+
+    /*
+     * Giacob: cert status check with ldap
+     */
+    if (sc->nLdapVerifyClient == LDAP_CHECK_ENABLED) ldap_check_hook(r, xs, sc, conn);
 
     /*
      * And finally signal OpenSSL the (perhaps changed) state
