int SslOcspStapling::certVerify(OCSP_RESPONSE *pResponse, OCSP_BASICRESP *pBasicResp, X509_STORE *pXstore) { int n, iResult = -1; STACK_OF(X509) *pXchain; ASN1_GENERALIZEDTIME *pThisupdate, *pNextupdate; struct stat st; pXchain = m_pCtx->extra_certs; if (OCSP_basic_verify(pBasicResp, pXchain, pXstore, OCSP_NOVERIFY) == 1) { if ((m_pCertId != NULL) && (OCSP_resp_find_status(pBasicResp, m_pCertId, &n, NULL, NULL, &pThisupdate, &pNextupdate) == 1) && (n == V_OCSP_CERTSTATUS_GOOD) && (OCSP_check_validity(pThisupdate, pNextupdate, 300, -1) == 1)) { iResult = 0; updateRespData(pResponse); unlink(m_sRespfile.c_str()); rename(m_sRespfileTmp.c_str(), m_sRespfile.c_str()); if (::stat(m_sRespfile.c_str(), &st) == 0) m_RespTime = st.st_mtime; } } if (iResult) { setLastErrMsg("%s", SSLError().what()); ERR_clear_error(); if (m_pHttpFetch) m_pHttpFetch->writeLog(s_ErrMsg.c_str()); } return iResult; }
static void ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx) { #if OPENSSL_VERSION_NUMBER >= 0x0090707fL const #endif u_char *p; int n; size_t len; time_t now, valid; ngx_str_t response; X509_STORE *store; STACK_OF(X509) *chain; OCSP_CERTID *id; OCSP_RESPONSE *ocsp; OCSP_BASICRESP *basic; ngx_ssl_stapling_t *staple; ASN1_GENERALIZEDTIME *thisupdate, *nextupdate; staple = ctx->data; now = ngx_time(); ocsp = NULL; basic = NULL; id = NULL; if (ctx->code != 200) { goto error; } /* check the response */ len = ctx->response->last - ctx->response->pos; p = ctx->response->pos; ocsp = d2i_OCSP_RESPONSE(NULL, &p, len); if (ocsp == NULL) { ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, "d2i_OCSP_RESPONSE() failed"); goto error; } n = OCSP_response_status(ocsp); if (n != OCSP_RESPONSE_STATUS_SUCCESSFUL) { ngx_log_error(NGX_LOG_ERR, ctx->log, 0, "OCSP response not successful (%d: %s)", n, OCSP_response_status_str(n)); goto error; } basic = OCSP_response_get1_basic(ocsp); if (basic == NULL) { ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, "OCSP_response_get1_basic() failed"); goto error; } store = SSL_CTX_get_cert_store(staple->ssl_ctx); if (store == NULL) { ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0, "SSL_CTX_get_cert_store() failed"); goto error; } #if OPENSSL_VERSION_NUMBER >= 0x10001000L SSL_CTX_get_extra_chain_certs(staple->ssl_ctx, &chain); #else chain = staple->ssl_ctx->extra_certs; #endif if (OCSP_basic_verify(basic, chain, store, staple->verify ? OCSP_TRUSTOTHER : OCSP_NOVERIFY) != 1) { ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, "OCSP_basic_verify() failed"); goto error; } id = OCSP_cert_to_id(NULL, ctx->cert, ctx->issuer); if (id == NULL) { ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0, "OCSP_cert_to_id() failed"); goto error; } if (OCSP_resp_find_status(basic, id, &n, NULL, NULL, &thisupdate, &nextupdate) != 1) { ngx_log_error(NGX_LOG_ERR, ctx->log, 0, "certificate status not found in the OCSP response"); goto error; } if (n != V_OCSP_CERTSTATUS_GOOD) { ngx_log_error(NGX_LOG_ERR, ctx->log, 0, "certificate status \"%s\" in the OCSP response", OCSP_cert_status_str(n)); goto error; } if (OCSP_check_validity(thisupdate, nextupdate, 300, -1) != 1) { ngx_ssl_error(NGX_LOG_ERR, ctx->log, 0, "OCSP_check_validity() failed"); goto error; } if (nextupdate) { valid = ngx_ssl_stapling_time(nextupdate); if (valid == (time_t) NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, ctx->log, 0, "invalid nextUpdate time in certificate status"); goto error; } } else { valid = NGX_MAX_TIME_T_VALUE; } OCSP_CERTID_free(id); OCSP_BASICRESP_free(basic); OCSP_RESPONSE_free(ocsp); id = NULL; basic = NULL; ocsp = NULL; /* copy the response to memory not in ctx->pool */ response.len = len; response.data = ngx_alloc(response.len, ctx->log); if (response.data == NULL) { goto error; } ngx_memcpy(response.data, ctx->response->pos, response.len); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0, "ssl ocsp response, %s, %uz", OCSP_cert_status_str(n), response.len); if (staple->staple.data) { ngx_free(staple->staple.data); } staple->staple = response; staple->valid = valid; /* * refresh before the response expires, * but not earlier than in 5 minutes, and at least in an hour */ staple->loading = 0; staple->refresh = ngx_max(ngx_min(valid - 300, now + 3600), now + 300); ngx_ssl_ocsp_done(ctx); return; error: staple->loading = 0; staple->refresh = now + 300; if (id) { OCSP_CERTID_free(id); } if (basic) { OCSP_BASICRESP_free(basic); } if (ocsp) { OCSP_RESPONSE_free(ocsp); } ngx_ssl_ocsp_done(ctx); }
GTlsCertificateFlags g_tls_database_openssl_verify_ocsp_response (GTlsDatabaseOpenssl *self, GTlsCertificate *chain, OCSP_RESPONSE *resp) { GTlsCertificateFlags errors = 0; #if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \ !defined(OPENSSL_NO_OCSP) GTlsDatabaseOpensslPrivate *priv; STACK_OF(X509) *chain_openssl = NULL; OCSP_BASICRESP *basic_resp = NULL; int ocsp_status = 0; int i; ocsp_status = OCSP_response_status (resp); if (ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { errors = G_TLS_CERTIFICATE_GENERIC_ERROR; goto end; } basic_resp = OCSP_response_get1_basic (resp); if (basic_resp == NULL) { errors = G_TLS_CERTIFICATE_GENERIC_ERROR; goto end; } chain_openssl = convert_certificate_chain_to_openssl (G_TLS_CERTIFICATE_OPENSSL (chain)); priv = g_tls_database_openssl_get_instance_private (self); if ((chain_openssl == NULL) || (priv->store == NULL)) { errors = G_TLS_CERTIFICATE_GENERIC_ERROR; goto end; } if (OCSP_basic_verify (basic_resp, chain_openssl, priv->store, 0) <= 0) { errors = G_TLS_CERTIFICATE_GENERIC_ERROR; goto end; } for (i = 0; i < OCSP_resp_count (basic_resp); i++) { OCSP_SINGLERESP *single_resp = OCSP_resp_get0 (basic_resp, i); ASN1_GENERALIZEDTIME *revocation_time = NULL; ASN1_GENERALIZEDTIME *this_update_time = NULL; ASN1_GENERALIZEDTIME *next_update_time = NULL; int crl_reason = 0; int cert_status = 0; if (single_resp == NULL) continue; cert_status = OCSP_single_get0_status (single_resp, &crl_reason, &revocation_time, &this_update_time, &next_update_time); if (!OCSP_check_validity (this_update_time, next_update_time, 300L, -1L)) { errors = G_TLS_CERTIFICATE_GENERIC_ERROR; goto end; } switch (cert_status) { case V_OCSP_CERTSTATUS_GOOD: break; case V_OCSP_CERTSTATUS_REVOKED: errors = G_TLS_CERTIFICATE_REVOKED; goto end; case V_OCSP_CERTSTATUS_UNKNOWN: errors = G_TLS_CERTIFICATE_GENERIC_ERROR; goto end; } } end: if (basic_resp != NULL) OCSP_BASICRESP_free (basic_resp); if (resp != NULL) OCSP_RESPONSE_free (resp); #endif return errors; }
int myproxy_ocsp_verify(X509 *cert, X509 *issuer) { BIO *bio = 0; int rc, reason, ssl, status; char *host = 0, *path = 0, *port = 0, *certdir = 0; char *aiaocspurl = 0, *chosenurl = 0; SSL_CTX *ctx = 0; X509_LOOKUP *lookup = NULL; X509_STORE *store = 0; OCSP_CERTID *id; OCSP_REQUEST *req = 0; OCSP_RESPONSE *resp = 0; OCSP_BASICRESP *basic = 0; myproxy_ocspresult_t result; ASN1_GENERALIZEDTIME *producedAt, *thisUpdate, *nextUpdate; globus_result_t res; if (!policy && !responder_url) { result = MYPROXY_OCSPRESULT_ERROR_NOTCONFIGURED; goto end; } result = MYPROXY_OCSPRESULT_ERROR_UNKNOWN; if (policy && strstr(policy, "aia")) { aiaocspurl = myproxy_get_aia_ocsp_uri(cert); } if (!responder_url && !aiaocspurl) { result = MYPROXY_OCSPRESULT_ERROR_NOTCONFIGURED; goto end; } chosenurl = aiaocspurl ? aiaocspurl : responder_url; if (!OCSP_parse_url(chosenurl, &host, &port, &path, &ssl)) { result = MYPROXY_OCSPRESULT_ERROR_BADOCSPADDRESS; goto end; } myproxy_log("querying OCSP responder at %s", chosenurl); if (!(req = OCSP_REQUEST_new())) { result = MYPROXY_OCSPRESULT_ERROR_OUTOFMEMORY; goto end; } id = OCSP_cert_to_id(0, cert, issuer); if (!id || !OCSP_request_add0_id(req, id)) goto end; if (usenonce) OCSP_request_add1_nonce(req, 0, -1); /* sign the request */ if (sign_cert && sign_key && !OCSP_request_sign(req, sign_cert, sign_key, EVP_sha1(), 0, 0)) { result = MYPROXY_OCSPRESULT_ERROR_SIGNFAILURE; goto end; } /* setup GSI context */ store=X509_STORE_new(); lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir()); if (lookup == NULL) { result = MYPROXY_OCSPRESULT_ERROR_OUTOFMEMORY; goto end; } res = GLOBUS_GSI_SYSCONFIG_GET_CERT_DIR(&certdir); if (res != GLOBUS_SUCCESS) { verror_put_string("failed to find GSI CA cert directory"); globus_error_to_verror(res); goto end; } X509_LOOKUP_add_dir(lookup, certdir, X509_FILETYPE_PEM); ctx = SSL_CTX_new(SSLv23_client_method()); if (ctx == NULL) { result = MYPROXY_OCSPRESULT_ERROR_OUTOFMEMORY; goto end; } SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2); SSL_CTX_set_cert_store(ctx, store); SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL); /* establish a connection to the OCSP responder */ if (!(bio = my_connect(host, atoi(port), ssl, &ctx))) { result = MYPROXY_OCSPRESULT_ERROR_CONNECTFAILURE; goto end; } /* send the request and get a response */ resp = OCSP_sendreq_bio(bio, path, req); if ((rc = OCSP_response_status(resp)) != OCSP_RESPONSE_STATUS_SUCCESSFUL) { switch (rc) { case OCSP_RESPONSE_STATUS_MALFORMEDREQUEST: result = MYPROXY_OCSPRESULT_ERROR_MALFORMEDREQUEST; break; case OCSP_RESPONSE_STATUS_INTERNALERROR: result = MYPROXY_OCSPRESULT_ERROR_INTERNALERROR; break; case OCSP_RESPONSE_STATUS_TRYLATER: result = MYPROXY_OCSPRESULT_ERROR_TRYLATER; break; case OCSP_RESPONSE_STATUS_SIGREQUIRED: result = MYPROXY_OCSPRESULT_ERROR_SIGREQUIRED; break; case OCSP_RESPONSE_STATUS_UNAUTHORIZED: result = MYPROXY_OCSPRESULT_ERROR_UNAUTHORIZED; break; } goto end; } /* verify the response */ result = MYPROXY_OCSPRESULT_ERROR_INVALIDRESPONSE; if (!(basic = OCSP_response_get1_basic(resp))) goto end; if (usenonce && OCSP_check_nonce(req, basic) <= 0) goto end; if (!responder_cert || (rc = OCSP_basic_verify(basic, responder_cert, store, OCSP_TRUSTOTHER)) <= 0) if ((rc = OCSP_basic_verify(basic, NULL, store, 0)) <= 0) goto end; if (!OCSP_resp_find_status(basic, id, &status, &reason, &producedAt, &thisUpdate, &nextUpdate)) goto end; if (!OCSP_check_validity(thisUpdate, nextUpdate, skew, maxage)) goto end; /* All done. Set the return code based on the status from the response. */ if (status == V_OCSP_CERTSTATUS_REVOKED) { result = MYPROXY_OCSPRESULT_CERTIFICATE_REVOKED; myproxy_log("OCSP status revoked!"); } else { result = MYPROXY_OCSPRESULT_CERTIFICATE_VALID; myproxy_log("OCSP status valid"); } end: if (result < 0 && result != MYPROXY_OCSPRESULT_ERROR_NOTCONFIGURED) { ssl_error_to_verror(); myproxy_log("OCSP check failed"); myproxy_log_verror(); } if (bio) BIO_free_all(bio); if (host) OPENSSL_free(host); if (port) OPENSSL_free(port); if (path) OPENSSL_free(path); if (req) OCSP_REQUEST_free(req); if (resp) OCSP_RESPONSE_free(resp); if (basic) OCSP_BASICRESP_free(basic); if (ctx) SSL_CTX_free(ctx); /* this does X509_STORE_free(store) */ if (certdir) free(certdir); if (aiaocspurl) free(aiaocspurl); return result; }
/* Verify the OCSP status of given certificate. Returns * V_OCSP_CERTSTATUS_* result code. */ static int verify_ocsp_status(X509 *cert, X509_STORE_CTX *ctx, conn_rec *c, SSLSrvConfigRec *sc, server_rec *s, apr_pool_t *pool) { int rc = V_OCSP_CERTSTATUS_GOOD; OCSP_RESPONSE *response = NULL; OCSP_BASICRESP *basicResponse = NULL; OCSP_REQUEST *request = NULL; OCSP_CERTID *certID = NULL; apr_uri_t *ruri; ruri = determine_responder_uri(sc, cert, c, pool); if (!ruri) { return V_OCSP_CERTSTATUS_UNKNOWN; } request = create_request(ctx, cert, &certID, s, pool, sc); if (request) { apr_interval_time_t to = sc->server->ocsp_responder_timeout == UNSET ? apr_time_from_sec(DEFAULT_OCSP_TIMEOUT) : sc->server->ocsp_responder_timeout; response = modssl_dispatch_ocsp_request(ruri, to, request, c, pool); } if (!request || !response) { rc = V_OCSP_CERTSTATUS_UNKNOWN; } if (rc == V_OCSP_CERTSTATUS_GOOD) { int r = OCSP_response_status(response); if (r != OCSP_RESPONSE_STATUS_SUCCESSFUL) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01922) "OCSP response not successful: %d", rc); rc = V_OCSP_CERTSTATUS_UNKNOWN; } } if (rc == V_OCSP_CERTSTATUS_GOOD) { basicResponse = OCSP_response_get1_basic(response); if (!basicResponse) { ap_log_cerror(APLOG_MARK, APLOG_ERR, 0, c, APLOGNO(01923) "could not retrieve OCSP basic response"); ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s); rc = V_OCSP_CERTSTATUS_UNKNOWN; } } if (rc == V_OCSP_CERTSTATUS_GOOD && sc->server->ocsp_use_request_nonce != FALSE && OCSP_check_nonce(request, basicResponse) != 1) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01924) "Bad OCSP responder answer (bad nonce)"); rc = V_OCSP_CERTSTATUS_UNKNOWN; } if (rc == V_OCSP_CERTSTATUS_GOOD) { /* TODO: allow flags configuration. */ if (OCSP_basic_verify(basicResponse, NULL, ctx->ctx, 0) != 1) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01925) "failed to verify the OCSP response"); ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s); rc = V_OCSP_CERTSTATUS_UNKNOWN; } } if (rc == V_OCSP_CERTSTATUS_GOOD) { int reason = -1, status; ASN1_GENERALIZEDTIME *thisup = NULL, *nextup = NULL; rc = OCSP_resp_find_status(basicResponse, certID, &status, &reason, NULL, &thisup, &nextup); if (rc != 1) { ssl_log_cxerror(SSLLOG_MARK, APLOG_ERR, 0, c, cert, APLOGNO(02272) "failed to retrieve OCSP response status"); ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s); rc = V_OCSP_CERTSTATUS_UNKNOWN; } else { rc = status; } /* Check whether the response is inside the defined validity * period; otherwise fail. */ if (rc != V_OCSP_CERTSTATUS_UNKNOWN) { long resptime_skew = sc->server->ocsp_resptime_skew == UNSET ? DEFAULT_OCSP_MAX_SKEW : sc->server->ocsp_resptime_skew; /* oscp_resp_maxage can be passed verbatim - UNSET (-1) means * that responses can be of any age as long as nextup is in the * future. */ int vrc = OCSP_check_validity(thisup, nextup, resptime_skew, sc->server->ocsp_resp_maxage); if (vrc != 1) { ssl_log_cxerror(SSLLOG_MARK, APLOG_ERR, 0, c, cert, APLOGNO(02273) "OCSP response outside validity period"); ssl_log_ssl_error(SSLLOG_MARK, APLOG_ERR, s); rc = V_OCSP_CERTSTATUS_UNKNOWN; } } { int level = (status == V_OCSP_CERTSTATUS_GOOD) ? APLOG_INFO : APLOG_ERR; const char *result = status == V_OCSP_CERTSTATUS_GOOD ? "good" : (status == V_OCSP_CERTSTATUS_REVOKED ? "revoked" : "unknown"); ssl_log_cxerror(SSLLOG_MARK, level, 0, c, cert, "OCSP validation completed, " "certificate status: %s (%d, %d)", result, status, reason); } } if (request) OCSP_REQUEST_free(request); if (response) OCSP_RESPONSE_free(response); if (basicResponse) OCSP_BASICRESP_free(basicResponse); /* certID is freed when the request is freed */ return rc; }
static int ocsp_check(CLI *c, X509_STORE_CTX *callback_ctx) { int error, retval=0; SOCKADDR_UNION addr; X509 *cert; X509 *issuer=NULL; OCSP_CERTID *certID; BIO *bio=NULL; OCSP_REQUEST *request=NULL; OCSP_RESPONSE *response=NULL; OCSP_BASICRESP *basicResponse=NULL; ASN1_GENERALIZEDTIME *revoked_at=NULL, *this_update=NULL, *next_update=NULL; int status, reason; /* connect specified OCSP server (responder) */ c->fd=s_socket(c->opt->ocsp_addr.addr[0].sa.sa_family, SOCK_STREAM, 0, 0, "OCSP: socket (auth_user)"); if(c->fd<0) return 0; /* reject connection */ memcpy(&addr, &c->opt->ocsp_addr.addr[0], sizeof addr); if(connect_blocking(c, &addr, addr_len(addr))) goto cleanup; s_log(LOG_DEBUG, "OCSP: server connected"); /* get current certificate ID */ cert=X509_STORE_CTX_get_current_cert(callback_ctx); /* get current cert */ if(X509_STORE_CTX_get1_issuer(&issuer, callback_ctx, cert)!=1) { sslerror("OCSP: X509_STORE_CTX_get1_issuer"); goto cleanup; } certID=OCSP_cert_to_id(0, cert, issuer); if(!certID) { sslerror("OCSP: OCSP_cert_to_id"); goto cleanup; } /* build request */ request=OCSP_REQUEST_new(); if(!request) { sslerror("OCSP: OCSP_REQUEST_new"); goto cleanup; } if(!OCSP_request_add0_id(request, certID)) { sslerror("OCSP: OCSP_request_add0_id"); goto cleanup; } OCSP_request_add1_nonce(request, 0, -1); /* send the request and get a response */ /* FIXME: this code won't work with ucontext threading */ /* (blocking sockets are used) */ bio=BIO_new_fd(c->fd, BIO_NOCLOSE); response=OCSP_sendreq_bio(bio, c->opt->ocsp_path, request); if(!response) { sslerror("OCSP: OCSP_sendreq_bio"); goto cleanup; } error=OCSP_response_status(response); if(error!=OCSP_RESPONSE_STATUS_SUCCESSFUL) { s_log(LOG_WARNING, "OCSP: Responder error: %d: %s", error, OCSP_response_status_str(error)); goto cleanup; } s_log(LOG_DEBUG, "OCSP: Response received"); /* verify the response */ basicResponse=OCSP_response_get1_basic(response); if(!basicResponse) { sslerror("OCSP: OCSP_response_get1_basic"); goto cleanup; } if(OCSP_check_nonce(request, basicResponse)<=0) { sslerror("OCSP: OCSP_check_nonce"); goto cleanup; } if(OCSP_basic_verify(basicResponse, NULL, c->opt->revocation_store, c->opt->ocsp_flags)<=0) { sslerror("OCSP: OCSP_basic_verify"); goto cleanup; } if(!OCSP_resp_find_status(basicResponse, certID, &status, &reason, &revoked_at, &this_update, &next_update)) { sslerror("OCSP: OCSP_resp_find_status"); goto cleanup; } s_log(LOG_NOTICE, "OCSP: Status: %d: %s", status, OCSP_cert_status_str(status)); log_time(LOG_INFO, "OCSP: This update", this_update); log_time(LOG_INFO, "OCSP: Next update", next_update); /* check if the response is valid for at least one minute */ if(!OCSP_check_validity(this_update, next_update, 60, -1)) { sslerror("OCSP: OCSP_check_validity"); goto cleanup; } if(status==V_OCSP_CERTSTATUS_REVOKED) { if(reason==-1) s_log(LOG_WARNING, "OCSP: Certificate revoked"); else s_log(LOG_WARNING, "OCSP: Certificate revoked: %d: %s", reason, OCSP_crl_reason_str(reason)); log_time(LOG_NOTICE, "OCSP: Revoked at", revoked_at); goto cleanup; } retval=1; /* accept connection */ cleanup: if(bio) BIO_free_all(bio); if(issuer) X509_free(issuer); if(request) OCSP_REQUEST_free(request); if(response) OCSP_RESPONSE_free(response); if(basicResponse) OCSP_BASICRESP_free(basicResponse); closesocket(c->fd); c->fd=-1; /* avoid double close on cleanup */ return retval; }
static int ocsp_check(CLI *c, X509_STORE_CTX *callback_ctx) { int error, retval=0; X509 *cert; X509 *issuer=NULL; OCSP_CERTID *certID; OCSP_REQUEST *request=NULL; OCSP_RESPONSE *response=NULL; OCSP_BASICRESP *basicResponse=NULL; ASN1_GENERALIZEDTIME *revoked_at=NULL, *this_update=NULL, *next_update=NULL; int status, reason; /* get current certificate ID */ cert=X509_STORE_CTX_get_current_cert(callback_ctx); /* get current cert */ if(X509_STORE_CTX_get1_issuer(&issuer, callback_ctx, cert)!=1) { sslerror("OCSP: X509_STORE_CTX_get1_issuer"); goto cleanup; } certID=OCSP_cert_to_id(0, cert, issuer); if(!certID) { sslerror("OCSP: OCSP_cert_to_id"); goto cleanup; } /* build request */ request=OCSP_REQUEST_new(); if(!request) { sslerror("OCSP: OCSP_REQUEST_new"); goto cleanup; } if(!OCSP_request_add0_id(request, certID)) { sslerror("OCSP: OCSP_request_add0_id"); goto cleanup; } OCSP_request_add1_nonce(request, 0, -1); /* send the request and get a response */ response=ocsp_get_response(c, request); if(!response) goto cleanup; error=OCSP_response_status(response); if(error!=OCSP_RESPONSE_STATUS_SUCCESSFUL) { s_log(LOG_WARNING, "OCSP: Responder error: %d: %s", error, OCSP_response_status_str(error)); goto cleanup; } s_log(LOG_DEBUG, "OCSP: Response received"); /* verify the response */ basicResponse=OCSP_response_get1_basic(response); if(!basicResponse) { sslerror("OCSP: OCSP_response_get1_basic"); goto cleanup; } if(OCSP_check_nonce(request, basicResponse)<=0) { sslerror("OCSP: OCSP_check_nonce"); goto cleanup; } if(OCSP_basic_verify(basicResponse, NULL, c->opt->revocation_store, c->opt->ocsp_flags)<=0) { sslerror("OCSP: OCSP_basic_verify"); goto cleanup; } if(!OCSP_resp_find_status(basicResponse, certID, &status, &reason, &revoked_at, &this_update, &next_update)) { sslerror("OCSP: OCSP_resp_find_status"); goto cleanup; } s_log(LOG_NOTICE, "OCSP: Status: %d: %s", status, OCSP_cert_status_str(status)); log_time(LOG_INFO, "OCSP: This update", this_update); log_time(LOG_INFO, "OCSP: Next update", next_update); /* check if the response is valid for at least one minute */ if(!OCSP_check_validity(this_update, next_update, 60, -1)) { sslerror("OCSP: OCSP_check_validity"); goto cleanup; } if(status==V_OCSP_CERTSTATUS_REVOKED) { if(reason==-1) s_log(LOG_WARNING, "OCSP: Certificate revoked"); else s_log(LOG_WARNING, "OCSP: Certificate revoked: %d: %s", reason, OCSP_crl_reason_str(reason)); log_time(LOG_NOTICE, "OCSP: Revoked at", revoked_at); goto cleanup; } retval=1; /* accept connection */ cleanup: if(issuer) X509_free(issuer); if(request) OCSP_REQUEST_free(request); if(response) OCSP_RESPONSE_free(response); if(basicResponse) OCSP_BASICRESP_free(basicResponse); return retval; }
/* returns one of: * V_OCSP_CERTSTATUS_GOOD * V_OCSP_CERTSTATUS_REVOKED * V_OCSP_CERTSTATUS_UNKNOWN */ NOEXPORT int ocsp_request(CLI *c, X509_STORE_CTX *callback_ctx, OCSP_CERTID *cert_id, char *url) { int status=V_OCSP_CERTSTATUS_UNKNOWN; int reason; int ctx_err=X509_V_ERR_APPLICATION_VERIFICATION; OCSP_REQUEST *request=NULL; OCSP_RESPONSE *response=NULL; OCSP_BASICRESP *basic_response=NULL; ASN1_GENERALIZEDTIME *revoked_at=NULL, *this_update=NULL, *next_update=NULL; /* build request */ request=OCSP_REQUEST_new(); if(!request) { sslerror("OCSP: OCSP_REQUEST_new"); goto cleanup; } if(!OCSP_request_add0_id(request, cert_id)) { sslerror("OCSP: OCSP_request_add0_id"); goto cleanup; } OCSP_request_add1_nonce(request, NULL, -1); /* send the request and get a response */ response=ocsp_get_response(c, request, url); if(!response) goto cleanup; status=OCSP_response_status(response); if(status!=OCSP_RESPONSE_STATUS_SUCCESSFUL) { s_log(LOG_WARNING, "OCSP: Responder error: %d: %s", status, OCSP_response_status_str(status)); goto cleanup; } s_log(LOG_DEBUG, "OCSP: Response received"); /* verify the response */ basic_response=OCSP_response_get1_basic(response); if(!basic_response) { sslerror("OCSP: OCSP_response_get1_basic"); goto cleanup; } if(OCSP_check_nonce(request, basic_response)<=0) { s_log(LOG_WARNING, "OCSP: Invalid nonce"); goto cleanup; } if(OCSP_basic_verify(basic_response, NULL, c->opt->revocation_store, c->opt->ocsp_flags)<=0) { sslerror("OCSP: OCSP_basic_verify"); goto cleanup; } if(!OCSP_resp_find_status(basic_response, cert_id, &status, &reason, &revoked_at, &this_update, &next_update)) { sslerror("OCSP: OCSP_resp_find_status"); goto cleanup; } s_log(LOG_NOTICE, "OCSP: Status: %s", OCSP_cert_status_str(status)); log_time(LOG_INFO, "OCSP: This update", this_update); log_time(LOG_INFO, "OCSP: Next update", next_update); /* check if the response is valid for at least one minute */ if(!OCSP_check_validity(this_update, next_update, 60, -1)) { sslerror("OCSP: OCSP_check_validity"); status=V_OCSP_CERTSTATUS_UNKNOWN; goto cleanup; } switch(status) { case V_OCSP_CERTSTATUS_GOOD: break; case V_OCSP_CERTSTATUS_REVOKED: if(reason==-1) s_log(LOG_WARNING, "OCSP: Certificate revoked"); else s_log(LOG_WARNING, "OCSP: Certificate revoked: %d: %s", reason, OCSP_crl_reason_str(reason)); log_time(LOG_NOTICE, "OCSP: Revoked at", revoked_at); ctx_err=X509_V_ERR_CERT_REVOKED; break; case V_OCSP_CERTSTATUS_UNKNOWN: s_log(LOG_WARNING, "OCSP: Unknown verification status"); } cleanup: if(request) OCSP_REQUEST_free(request); if(response) OCSP_RESPONSE_free(response); if(basic_response) OCSP_BASICRESP_free(basic_response); if(status!=V_OCSP_CERTSTATUS_GOOD) X509_STORE_CTX_set_error(callback_ctx, ctx_err); return status; }
void OCSPResponseVerifier_impl::ProcessL() { if (!m_request || !m_response_der || m_response_length == 0 || !m_certificate_chain || !m_ca_storage) LEAVE(OpStatus::ERR_OUT_OF_RANGE); // Default value. Will be checked in the end of the function. OP_STATUS status = OpStatus::ERR; // Default verify status. m_verify_status = CryptoCertificateChain::VERIFY_STATUS_UNKNOWN; OCSP_RESPONSE* ocsp_response = 0; OCSP_BASICRESP* ocsp_basicresp = 0; do { const OCSPRequest_impl* request_impl = static_cast <const OCSPRequest_impl*> (m_request); const CryptoCertificateChain_impl* chain_impl = static_cast <const CryptoCertificateChain_impl*> (m_certificate_chain); const CryptoCertificateStorage_impl* storage_impl = static_cast <const CryptoCertificateStorage_impl*> (m_ca_storage); if (!request_impl || !chain_impl || !storage_impl) { status = OpStatus::ERR_OUT_OF_RANGE; break; } OCSP_REQUEST* ocsp_request = request_impl->GetOCSP_REQUEST(); STACK_OF(X509)* x509_chain = chain_impl->GetStackOfX509(); X509_STORE* x509_store = storage_impl->GetX509Store(); OP_ASSERT(ocsp_request && x509_chain && x509_store); // Both ocsp_request, x509_chain and x509_store are owned // by their container objects. // Temporary variable, according to the documentation. const unsigned char* response_tmp = m_response_der; ocsp_response = d2i_OCSP_RESPONSE(0, &response_tmp, m_response_length); OPENSSL_VERIFY_OR_BREAK2(ocsp_response, status); // Check that the OCSP responder was able to respond correctly. int ocsp_response_status = OCSP_response_status(ocsp_response); OPENSSL_BREAK2_IF(ocsp_response_status != OCSP_RESPONSE_STATUS_SUCCESSFUL, status); ocsp_basicresp = OCSP_response_get1_basic(ocsp_response); OPENSSL_VERIFY_OR_BREAK2(ocsp_basicresp, status); // Verify that the response is correctly signed. int response_valid_status = OCSP_basic_verify(ocsp_basicresp, x509_chain, x509_store, /* flags = */ 0); OPENSSL_BREAK2_IF(response_valid_status != 1, status); OP_ASSERT(ocsp_request->tbsRequest && ocsp_request->tbsRequest->requestList); OCSP_ONEREQ* ocsp_onereq = sk_OCSP_ONEREQ_value(ocsp_request->tbsRequest->requestList, 0); OPENSSL_VERIFY_OR_BREAK(ocsp_onereq); // ocsp_request owns ocsp_onereq. OCSP_CERTID* ocsp_certid = ocsp_onereq->reqCert; OPENSSL_VERIFY_OR_BREAK(ocsp_certid); // ocsp_request owns ocsp_certid. int revocation_code = -1, response_code = -1; ASN1_GENERALIZEDTIME* thisupd = 0; ASN1_GENERALIZEDTIME* nextupd = 0; int err = OCSP_resp_find_status( ocsp_basicresp, ocsp_certid, &response_code, &revocation_code, 0, &thisupd, &nextupd); OPENSSL_BREAK2_IF(err != 1 || response_code < 0, status); // Allow some difference in client and server clocks. const long int CLOCK_SHARPNESS = 3600; // Default age limit for responses without nextUpdate field. const long int DEFAULT_MAXAGE = 100 * 24 * 3600; err = OCSP_check_validity(thisupd, nextupd, CLOCK_SHARPNESS, DEFAULT_MAXAGE); OPENSSL_BREAK2_IF(err != 1, status); switch (response_code) { case V_OCSP_CERTSTATUS_GOOD: m_verify_status = CryptoCertificateChain::OK_CHECKED_WITH_OCSP; status = OpStatus::OK; break; case V_OCSP_CERTSTATUS_REVOKED: m_verify_status = CryptoCertificateChain::CERTIFICATE_REVOKED; status = OpStatus::OK; break; default: OP_ASSERT(!"Unexpected OCSP response code!"); // fall-through case V_OCSP_CERTSTATUS_UNKNOWN: OP_ASSERT(m_verify_status == CryptoCertificateChain::VERIFY_STATUS_UNKNOWN); break; } } while(0); if(ocsp_basicresp) OCSP_BASICRESP_free(ocsp_basicresp); if(ocsp_response) OCSP_RESPONSE_free(ocsp_response); // There shouldn't be any errors. OP_ASSERT(ERR_peek_error() == 0); LEAVE_IF_ERROR(status); }