diff -Naur stunnel-4.21.orig/doc/stunnel.pod stunnel-4.21/doc/stunnel.pod --- stunnel-4.21.orig/doc/stunnel.pod 2007-11-23 16:42:49.000000000 -0500 +++ stunnel-4.21/doc/stunnel.pod 2007-11-26 12:54:32.000000000 -0500 @@ -405,6 +405,10 @@ currently supported flags: NOCERTS, NOINTERN NOSIGS, NOCHAIN, NOVERIFY, NOEXPLICIT, NOCASIGN, NODELEGATED, NOCHECKS, TRUSTOTHER, RESPID_KEY, NOTIME +=item B =yes | no + +turn on OCSP verification. The OCSP responder URL is taken from the Authority Information Access (AIA) from the certificate. + =item B = SSL_options OpenSSL library options diff -Naur stunnel-4.21.orig/src/options.c stunnel-4.21/src/options.c --- stunnel-4.21.orig/src/options.c 2007-11-23 16:42:52.000000000 -0500 +++ stunnel-4.21/src/options.c 2007-11-23 17:14:31.000000000 -0500 @@ -870,6 +870,28 @@ s_log(LOG_RAW, "%-15s = OCSP server flags", "OCSPflag"); break; } + + /* OCSP AIA */ + switch (cmd) { + case CMD_INIT: + section->option.aia=0; + break; + case CMD_EXEC: + if(strcasecmp(opt, "OCSPaia")) + break; + if(!strcasecmp(arg, "yes")) + section->option.aia=1; + else if(!strcasecmp(arg, "no")) + section->option.aia=0; + else + return "Argument should be either 'yes' or 'no'"; + return NULL; /* OK */ + case CMD_DEFAULT: + break; + case CMD_HELP: + s_log(LOG_RAW, "%-15s = yes|no to have the certificate's use URI contained in the X509 AIA ", "OCSPaia"); + break; + } #endif /* OpenSSL-0.9.7 */ /* options */ diff -Naur stunnel-4.21.orig/src/prototypes.h stunnel-4.21/src/prototypes.h --- stunnel-4.21.orig/src/prototypes.h 2007-11-23 16:42:52.000000000 -0500 +++ stunnel-4.21/src/prototypes.h 2007-11-23 17:09:12.000000000 -0500 @@ -218,6 +218,7 @@ #endif #if SSLEAY_VERSION_NUMBER >= 0x00907000L unsigned int ocsp:1; + unsigned int aia:1; #endif } option; } LOCAL_OPTIONS; diff -Naur stunnel-4.21.orig/src/verify.c stunnel-4.21/src/verify.c --- stunnel-4.21.orig/src/verify.c 2007-11-23 16:42:52.000000000 -0500 +++ stunnel-4.21/src/verify.c 2007-11-26 13:16:04.000000000 -0500 @@ -49,6 +49,8 @@ static int cert_check(CLI *c, X509_STORE_CTX *, char *, int); static int crl_check(CLI *c, X509_STORE_CTX *, char *); static int ocsp_check(CLI *c, X509_STORE_CTX *, char *); +static int ocsp_check_one_responder(CLI *, X509_STORE_CTX *, char *, SOCKADDR_LIST *, const char *); +static int ocsp_check_aia(CLI *, X509_STORE_CTX *, char *); /* utility functions */ static void log_time(const int, const char *, ASN1_TIME *); @@ -171,6 +173,8 @@ #if SSLEAY_VERSION_NUMBER >= 0x00907000L if(c->opt->option.ocsp && !ocsp_check(c, callback_ctx, subject_name)) return 0; /* reject connection */ + else if (c->opt->option.aia && !ocsp_check_aia(c, callback_ctx, subject_name)) + return 0; /* reject connection */ #endif /* OpenSSL-0.9.7 */ /* errnum=X509_STORE_CTX_get_error(ctx); */ @@ -322,7 +326,79 @@ #if SSLEAY_VERSION_NUMBER >= 0x00907000L static int ocsp_check(CLI *c, X509_STORE_CTX *callback_ctx, char *subject_name) { - int error, retval=0; + + return (ocsp_check_one_responder(c, callback_ctx, subject_name, &c->opt->ocsp_addr, c->opt->ocsp_path) > 0); +} + +static int ocsp_check_aia(CLI *c, X509_STORE_CTX *callback_ctx, + char *subject_name) { + X509 *cert = X509_STORE_CTX_get_current_cert(callback_ctx); + AUTHORITY_INFO_ACCESS *aia; + int k, rc=-1; + + if ((aia = (AUTHORITY_INFO_ACCESS *) X509_get_ext_d2i(cert, NID_info_access, NULL, NULL)) == NULL) { + s_log(LOG_WARNING, "failed to find AIA extension"); + return 1; + } + + for (k=0;kmethod) != NID_ad_OCSP) + continue; + + /* make sure we have the URI */ + gn = ad->location; + if (gn->type != GEN_URI) + continue; + asn1Uri = gn->d.uniformResourceIdentifier; + s_log(LOG_DEBUG, "Got URI %s", asn1Uri->data); + + if (! OCSP_parse_url(asn1Uri->data, & hostPtr, & portPtr, & pathPtr, & ssl)) { + s_log(LOG_ERR, "OCSP_parse_url fails for \"%s\"", asn1Uri); + continue; + } + + if (ssl) { + s_log(LOG_WARNING, "SSL not supported for OCSP"); + continue; + } + + memset(&addr_list, 0, sizeof(SOCKADDR_LIST)); + hostport2addrlist(&addr_list, hostPtr, portPtr); + + rc = ocsp_check_one_responder(c, callback_ctx, subject_name, &addr_list, pathPtr); + + OPENSSL_free(hostPtr); + OPENSSL_free(portPtr); + OPENSSL_free(pathPtr); + + if (rc>=0) + break; + } + + AUTHORITY_INFO_ACCESS_free(aia); + + return (rc>0); +} + + +/* + * Check the status of a certificate from one responder, returns + * 1 if cert is OK. + * 0 if revoked + * -1 if unknown or error + */ +static int ocsp_check_one_responder(CLI *c, X509_STORE_CTX *callback_ctx, + char *subject_name, SOCKADDR_LIST *this_addr, const char *path) { + int error, retval=-1; SOCKADDR_UNION addr; X509 *cert; X509 *issuer=NULL; @@ -340,13 +416,13 @@ /* connect specified OCSP server (responder) */ if((c->fd= - socket(c->opt->ocsp_addr.addr[0].sa.sa_family, SOCK_STREAM, 0))<0) { + socket(this_addr->addr[0].sa.sa_family, SOCK_STREAM, 0))<0) { sockerror("socket (auth_user)"); - return 0; /* reject connection */ + return retval; /* reject connection */ } if(alloc_fd(c->fd)) goto cleanup; - memcpy(&addr, &c->opt->ocsp_addr.addr[0], sizeof(SOCKADDR_UNION)); + memcpy(&addr, &this_addr->addr[0], sizeof(SOCKADDR_UNION)); if(connect(c->fd, &addr.sa, addr_len(addr))) { error=get_last_socket_error(); if(error!=EINPROGRESS && error!=EWOULDBLOCK) { @@ -387,7 +463,7 @@ /* (blocking sockets are used) */ bio=BIO_new_fd(c->fd, BIO_NOCLOSE); setnonblock(c->fd, 0); - response=OCSP_sendreq_bio(bio, c->opt->ocsp_path, request); + response=OCSP_sendreq_bio(bio, path, request); setnonblock(c->fd, 1); if(!response) { sslerror("OCSP_sendreq_bio"); @@ -436,13 +512,19 @@ else s_log(LOG_WARNING, "OCSP: certificate revoked: %d: %s", reason, OCSP_crl_reason_str(reason)); + retval=0; log_time(LOG_NOTICE, "OCSP: revoked at", revoked_at); - goto cleanup; + } + else if(status==V_OCSP_CERTSTATUS_GOOD) { + /* success */ + retval=1; + s_log(LOG_NOTICE, "OCSP: verification passed"); + } + else { + /* most likely an unknown, so we try the next one */ + s_log(LOG_WARNING, "OCSP: unknown response"); } - /* success */ - s_log(LOG_NOTICE, "OCSP: verification passed"); - retval=1; /* accept connection */ cleanup: if(bio) BIO_free_all(bio);