static int ocsp_resp_cb(SSL *s, void *arg) { const unsigned char *p; int len; OCSP_RESPONSE *rsp; len = SSL_get_tlsext_status_ocsp_resp(s, &p); BIO_puts(arg, "OCSP response: "); if (!p) { BIO_puts(arg, "no response sent\n"); return 1; } rsp = d2i_OCSP_RESPONSE(NULL, &p, len); if (!rsp) { BIO_puts(arg, "response parse error\n"); BIO_dump_indent(arg, (char *)p, len, 4); return 0; } BIO_puts(arg, "\n======================================\n"); OCSP_RESPONSE_print(arg, rsp, 0); BIO_puts(arg, "======================================\n"); OCSP_RESPONSE_free(rsp); return 1; }
//-------------------------------------------------- // Helper function to read OCSP_RESPONSE from binary input data // ppResp - address of newly allocated OCSP_RESPONSE object // pMBufInData - input data // returns error code or ERR_OK //-------------------------------------------------- int ddocOcspReadOcspResp(OCSP_RESPONSE** ppResp, DigiDocMemBuf* pMBufInData) { int err = ERR_OK; unsigned char* p1; RETURN_IF_NULL_PARAM(ppResp); RETURN_IF_NULL_PARAM(pMBufInData); RETURN_IF_NULL_PARAM(pMBufInData->pMem); ddocDebug(4, "ddocOcspReadOcspResp", "converting: %d bytes to OCSP_RESPONSE", pMBufInData->nLen); p1 = (unsigned char*)pMBufInData->pMem; d2i_OCSP_RESPONSE(ppResp, (const unsigned char**)&p1, pMBufInData->nLen); ddocDebug(4, "ddocOcspReadOcspResp", "OCSP_RESPONSE: %s", (*ppResp ? "OK" : "ERR")); return err; }
int bud_client_staple_json(bud_client_t* client, JSON_Value* json) { JSON_Object* obj; const char* b64_body; size_t b64_body_len; char* body; const unsigned char* pbody; size_t body_len; OCSP_RESPONSE* resp; int status; int r; r = -1; body = NULL; obj = json_value_get_object(json); b64_body = json_object_get_string(obj, "response"); if (b64_body == NULL) goto done; b64_body_len = strlen(b64_body); body_len = bud_base64_decoded_size_fast(b64_body_len); body = malloc(body_len); if (body == NULL) goto done; body_len = bud_base64_decode(body, body_len, b64_body, b64_body_len); pbody = (const unsigned char*) body; resp = d2i_OCSP_RESPONSE(NULL, &pbody, body_len); if (resp == NULL) goto done; /* Not successful response, do not waste bandwidth on it */ status = OCSP_response_status(resp); OCSP_RESPONSE_free(resp); if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) goto done; /* Set stapling! */ client->stapling_ocsp_resp = body; client->stapling_ocsp_resp_len = body_len; body = NULL; r = 0; done: free(body); return r; }
static VALUE ossl_ocspres_initialize(int argc, VALUE *argv, VALUE self) { VALUE arg; unsigned char *p; rb_scan_args(argc, argv, "01", &arg); if(!NIL_P(arg)) { arg = ossl_to_der_if_possible(arg); StringValue(arg); p = RSTRING_PTR(arg); if(!d2i_OCSP_RESPONSE((OCSP_RESPONSE**)&DATA_PTR(self), &p, RSTRING_LEN(arg))) { ossl_raise(eOCSPError, "cannot load DER encoded response"); } } return self; }
static VALUE ossl_ocspres_initialize(VALUE self, SEL sel, int argc, VALUE *argv) { VALUE arg; const unsigned char *p; rb_scan_args(argc, argv, "01", &arg); if(!NIL_P(arg)){ OCSP_RESPONSE *res = DATA_PTR(self), *x; arg = ossl_to_der_if_possible(arg); StringValue(arg); p = (unsigned char *)RSTRING_PTR(arg); x = d2i_OCSP_RESPONSE(&res, &p, RSTRING_LEN(arg)); DATA_PTR(self) = res; if(!x){ ossl_raise(eOCSPError, "cannot load DER encoded response"); } } return self; }
int main(int argc, char *argv[]) { int sd, ocsp_status; const unsigned char *p; long len; OCSP_RESPONSE *rsp = NULL; OCSP_BASICRESP *br = NULL; X509_STORE *st = NULL; STACK_OF(X509) *ch = NULL; char *host, *port; #ifdef _PATH_SSL_CA_FILE char *cafile = _PATH_SSL_CA_FILE; #else char *cafile = "/etc/ssl/cert.pem"; #endif SSL *ssl; SSL_CTX *ctx; SSL_library_init(); SSL_load_error_strings(); ctx = SSL_CTX_new(SSLv23_client_method()); if (!SSL_CTX_load_verify_locations(ctx, cafile, NULL)) { printf("failed to load %s\n", cafile); exit(-1); } if (argc != 3) errx(-1, "need a host and port to connect to"); else { host = argv[1]; port = argv[2]; } sd = tcp_connect(host, port); ssl = SSL_new(ctx); SSL_set_fd(ssl, (int) sd); SSL_set_tlsext_status_type(ssl, TLSEXT_STATUSTYPE_ocsp); if (SSL_connect(ssl) <= 0) { printf("SSL connect error\n"); exit(-1); } if (SSL_get_verify_result(ssl) != X509_V_OK) { printf("Certificate doesn't verify from host %s port %s\n", host, port); exit(-1); } /* ==== VERIFY OCSP RESPONSE ==== */ len = SSL_get_tlsext_status_ocsp_resp(ssl, &p); if (!p) { printf("No OCSP response received for %s port %s\n", host, port); exit(-1); } rsp = d2i_OCSP_RESPONSE(NULL, &p, len); if (!rsp) { puts("Invalid OCSP response"); exit(-1); } ocsp_status = OCSP_response_status(rsp); if (ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { printf("Invalid OCSP response status: %s (%d)", OCSP_response_status_str(ocsp_status), ocsp_status); exit(-1); } br = OCSP_response_get1_basic(rsp); if (!br) { puts("Invalid OCSP response"); exit(-1); } ch = SSL_get_peer_cert_chain(ssl); st = SSL_CTX_get_cert_store(ctx); if (OCSP_basic_verify(br, ch, st, 0) <= 0) { puts("OCSP response verification failed"); exit(-1); } printf("OCSP validated from %s %s\n", host, port); return 0; }
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); }
int OCSP_sendreq_nbio(OCSP_RESPONSE **presp, OCSP_REQ_CTX *rctx) { int i, n; const unsigned char *p; next_io: if (!(rctx->state & OHS_NOREAD)) { n = BIO_read(rctx->io, rctx->iobuf, rctx->iobuflen); if (n <= 0) { if (BIO_should_retry(rctx->io)) return -1; return 0; } /* Write data to memory BIO */ if (BIO_write(rctx->mem, rctx->iobuf, n) != n) return 0; } switch(rctx->state) { case OHS_ASN1_WRITE: n = BIO_get_mem_data(rctx->mem, &p); i = BIO_write(rctx->io, p + (n - rctx->asn1_len), rctx->asn1_len); if (i <= 0) { if (BIO_should_retry(rctx->io)) return -1; rctx->state = OHS_ERROR; return 0; } rctx->asn1_len -= i; if (rctx->asn1_len > 0) goto next_io; rctx->state = OHS_ASN1_FLUSH; (void)BIO_reset(rctx->mem); case OHS_ASN1_FLUSH: i = BIO_flush(rctx->io); if (i > 0) { rctx->state = OHS_FIRSTLINE; goto next_io; } if (BIO_should_retry(rctx->io)) return -1; rctx->state = OHS_ERROR; return 0; case OHS_ERROR: return 0; case OHS_FIRSTLINE: case OHS_HEADERS: /* Attempt to read a line in */ next_line: /* Due to &%^*$" memory BIO behaviour with BIO_gets we * have to check there's a complete line in there before * calling BIO_gets or we'll just get a partial read. */ n = BIO_get_mem_data(rctx->mem, &p); if ((n <= 0) || !TINYCLR_SSL_MEMCHR(p, '\n', n)) { if (n >= rctx->iobuflen) { rctx->state = OHS_ERROR; return 0; } goto next_io; } n = BIO_gets(rctx->mem, (char *)rctx->iobuf, rctx->iobuflen); if (n <= 0) { if (BIO_should_retry(rctx->mem)) goto next_io; rctx->state = OHS_ERROR; return 0; } /* Don't allow excessive lines */ if (n == rctx->iobuflen) { rctx->state = OHS_ERROR; return 0; } /* First line */ if (rctx->state == OHS_FIRSTLINE) { if (parse_http_line1((char *)rctx->iobuf)) { rctx->state = OHS_HEADERS; goto next_line; } else { rctx->state = OHS_ERROR; return 0; } } else { /* Look for blank line: end of headers */ for (p = rctx->iobuf; *p; p++) { if ((*p != '\r') && (*p != '\n')) break; } if (*p) goto next_line; rctx->state = OHS_ASN1_HEADER; } /* Fall thru */ case OHS_ASN1_HEADER: /* Now reading ASN1 header: can read at least 6 bytes which * is more than enough for any valid ASN1 SEQUENCE header */ n = BIO_get_mem_data(rctx->mem, &p); if (n < 6) goto next_io; /* Check it is an ASN1 SEQUENCE */ if (*p++ != (V_ASN1_SEQUENCE|V_ASN1_CONSTRUCTED)) { rctx->state = OHS_ERROR; return 0; } /* Check out length field */ if (*p & 0x80) { n = *p & 0x7F; /* Not NDEF or excessive length */ if (!n || (n > 4)) { rctx->state = OHS_ERROR; return 0; } p++; rctx->asn1_len = 0; for (i = 0; i < n; i++) { rctx->asn1_len <<= 8; rctx->asn1_len |= *p++; } if (rctx->asn1_len > OCSP_MAX_REQUEST_LENGTH) { rctx->state = OHS_ERROR; return 0; } rctx->asn1_len += n + 2; } else rctx->asn1_len = *p + 2; rctx->state = OHS_ASN1_CONTENT; /* Fall thru */ case OHS_ASN1_CONTENT: n = BIO_get_mem_data(rctx->mem, &p); if (n < (int)rctx->asn1_len) goto next_io; *presp = d2i_OCSP_RESPONSE(NULL, &p, rctx->asn1_len); if (*presp) { rctx->state = OHS_DONE; return 1; } rctx->state = OHS_ERROR; return 0; break; case OHS_DONE: return 1; } return 0; }
s2n_cert_validation_code s2n_x509_validator_validate_cert_stapled_ocsp_response(struct s2n_x509_validator *validator, struct s2n_connection *conn, const uint8_t *ocsp_response_raw, uint32_t ocsp_response_length) { if (validator->skip_cert_validation || !validator->check_stapled_ocsp) { return S2N_CERT_OK; } #if !S2N_OCSP_STAPLING_SUPPORTED /* Default to safety */ return S2N_CERT_ERR_UNTRUSTED; #else OCSP_RESPONSE *ocsp_response = NULL; OCSP_BASICRESP *basic_response = NULL; s2n_cert_validation_code ret_val = S2N_CERT_ERR_INVALID; if (!ocsp_response_raw) { return ret_val; } ocsp_response = d2i_OCSP_RESPONSE(NULL, &ocsp_response_raw, ocsp_response_length); if (!ocsp_response) { goto clean_up; } int ocsp_status = OCSP_response_status(ocsp_response); if (ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { goto clean_up; } basic_response = OCSP_response_get1_basic(ocsp_response); if (!basic_response) { goto clean_up; } int i; int certs_in_chain = sk_X509_num(validator->cert_chain); int certs_in_ocsp = sk_X509_num(OCSP_GET_CERTS(basic_response)); if (certs_in_chain >= 2 && certs_in_ocsp >= 1) { X509 *responder = sk_X509_value(OCSP_GET_CERTS(basic_response), certs_in_ocsp - 1); /*check to see if one of the certs in the chain is an issuer of the cert in the ocsp response.*/ /*if so it needs to be added to the OCSP verification chain.*/ for (i = 0; i < certs_in_chain; i++) { X509 *issuer = sk_X509_value(validator->cert_chain, i); int issuer_value = X509_check_issued(issuer, responder); if (issuer_value == X509_V_OK) { if (!OCSP_basic_add1_cert(basic_response, issuer)) { goto clean_up; } } } } int ocsp_verify_err = OCSP_basic_verify(basic_response, validator->cert_chain, validator->trust_store->trust_store, 0); /* do the crypto checks on the response.*/ if (!ocsp_verify_err) { ret_val = S2N_CERT_ERR_EXPIRED; goto clean_up; } /* for each response check the timestamps and the status. */ for (i = 0; i < OCSP_resp_count(basic_response); i++) { int status_reason; ASN1_GENERALIZEDTIME *revtime, *thisupd, *nextupd; OCSP_SINGLERESP *single_response = OCSP_resp_get0(basic_response, i); if (!single_response) { goto clean_up; } ocsp_status = OCSP_single_get0_status(single_response, &status_reason, &revtime, &thisupd, &nextupd); uint64_t this_update = 0; int thisupd_err = s2n_asn1_time_to_nano_since_epoch_ticks((const char *) thisupd->data, (uint32_t) thisupd->length, &this_update); uint64_t next_update = 0; int nextupd_err = s2n_asn1_time_to_nano_since_epoch_ticks((const char *) nextupd->data, (uint32_t) nextupd->length, &next_update); uint64_t current_time = 0; int current_time_err = conn->config->wall_clock(conn->config->sys_clock_ctx, ¤t_time); if (thisupd_err || nextupd_err || current_time_err) { ret_val = S2N_CERT_ERR_UNTRUSTED; goto clean_up; } if (current_time < this_update || current_time > next_update) { ret_val = S2N_CERT_ERR_EXPIRED; goto clean_up; } switch (ocsp_status) { case V_OCSP_CERTSTATUS_GOOD: break; case V_OCSP_CERTSTATUS_REVOKED: ret_val = S2N_CERT_ERR_REVOKED; goto clean_up; case V_OCSP_CERTSTATUS_UNKNOWN: goto clean_up; default: goto clean_up; } } ret_val = S2N_CERT_OK; clean_up: if (basic_response) { OCSP_BASICRESP_free(basic_response); } if (ocsp_response) { OCSP_RESPONSE_free(ocsp_response); } return ret_val; #endif /* S2N_OCSP_STAPLING_SUPPORTED */ }
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); }