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; } #ifdef SSL_CTRL_SELECT_CURRENT_CERT /* OpenSSL 1.0.2+ */ SSL_CTX_select_current_cert(staple->ssl_ctx, ctx->cert); #endif #ifdef SSL_CTRL_GET_EXTRA_CHAIN_CERTS /* OpenSSL 1.0.1+ */ 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); }
/** * NOTE: From node.js * * Read a file that contains our certificate in "PEM" format, * possibly followed by a sequence of CA certificates that should be * sent to the peer in the Certificate message. * * Taken from OpenSSL - editted for style. */ int bud_context_use_certificate_chain(bud_context_t* ctx, BIO *in) { int ret; X509* x; X509* ca; int r; unsigned long err; bud_context_pkey_type_t type; bud_context_pem_t* pem; ERR_clear_error(); ret = 0; x = PEM_read_bio_X509_AUX(in, NULL, NULL, NULL); pem = NULL; if (x == NULL) { SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_PEM_LIB); goto end; } ret = SSL_CTX_use_certificate(ctx->ctx, x); SSL_CTX_select_current_cert(ctx->ctx, x); type = bud_config_pkey_type(x->cert_info->key->pkey); pem = &ctx->pem[type]; pem->cert = x; pem->issuer = NULL; if (ERR_peek_error() != 0) { /* Key/certificate mismatch doesn't imply ret==0 ... */ ret = 0; } if (ret) { while ((ca = PEM_read_bio_X509(in, NULL, NULL, NULL))) { /* * Extra cert - add it to store to make OpenSSL pick and send proper * certs automatically */ r = SSL_CTX_add1_chain_cert(ctx->ctx, ca); if (!r) { X509_free(ca); ret = 0; goto end; } /** * Note that we must not free r if it was successfully * added to the chain (while we must free the main * certificate, since its reference count is increased * by SSL_CTX_use_certificate). */ /* Find issuer */ if (pem->issuer != NULL || X509_check_issued(ca, x) != X509_V_OK) continue; pem->issuer = ca; } /* When the while loop ends, it's usually just EOF. */ err = ERR_peek_last_error(); if (ERR_GET_LIB(err) == ERR_LIB_PEM && ERR_GET_REASON(err) == PEM_R_NO_START_LINE) { ERR_clear_error(); } else { /* some real error */ ret = 0; } } end: if (ret) { /* Try getting issuer from cert store */ if (pem->issuer == NULL) { X509_STORE* store; X509_STORE_CTX store_ctx; store = SSL_CTX_get_cert_store(ctx->ctx); ret = X509_STORE_CTX_init(&store_ctx, store, NULL, NULL); if (!ret) goto fatal; ret = X509_STORE_CTX_get1_issuer(&pem->issuer, &store_ctx, pem->cert); X509_STORE_CTX_cleanup(&store_ctx); ret = ret < 0 ? 0 : 1; /* NOTE: get_cert_store doesn't increment reference count */ } else { /* Increment issuer reference count */ CRYPTO_add(&pem->issuer->references, 1, CRYPTO_LOCK_X509); } if (pem->issuer != NULL) { /* Get ocsp_id */ pem->ocsp_id = OCSP_cert_to_id(NULL, pem->cert, pem->issuer); if (pem->ocsp_id == NULL) goto fatal; } } fatal: if (!ret && pem != NULL && pem->issuer != NULL) { X509_free(pem->issuer); pem->issuer = NULL; } if (!(pem != NULL && pem->cert == x) && x != NULL) X509_free(x); return ret; }
static ngx_int_t ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_ssl_stapling_t *staple) { int i, n, rc; X509 *cert, *issuer; X509_STORE *store; X509_STORE_CTX *store_ctx; STACK_OF(X509) *chain; cert = staple->cert; #ifdef SSL_CTRL_SELECT_CURRENT_CERT /* OpenSSL 1.0.2+ */ SSL_CTX_select_current_cert(ssl->ctx, cert); #endif #ifdef SSL_CTRL_GET_EXTRA_CHAIN_CERTS /* OpenSSL 1.0.1+ */ SSL_CTX_get_extra_chain_certs(ssl->ctx, &chain); #else chain = ssl->ctx->extra_certs; #endif n = sk_X509_num(chain); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ssl->log, 0, "SSL get issuer: %d extra certs", n); for (i = 0; i < n; i++) { issuer = sk_X509_value(chain, i); if (X509_check_issued(issuer, cert) == X509_V_OK) { #if OPENSSL_VERSION_NUMBER >= 0x10100001L X509_up_ref(issuer); #else CRYPTO_add(&issuer->references, 1, CRYPTO_LOCK_X509); #endif ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ssl->log, 0, "SSL get issuer: found %p in extra certs", issuer); staple->issuer = issuer; return NGX_OK; } } store = SSL_CTX_get_cert_store(ssl->ctx); if (store == NULL) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "SSL_CTX_get_cert_store() failed"); return NGX_ERROR; } store_ctx = X509_STORE_CTX_new(); if (store_ctx == NULL) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "X509_STORE_CTX_new() failed"); return NGX_ERROR; } if (X509_STORE_CTX_init(store_ctx, store, NULL, NULL) == 0) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "X509_STORE_CTX_init() failed"); X509_STORE_CTX_free(store_ctx); return NGX_ERROR; } rc = X509_STORE_CTX_get1_issuer(&issuer, store_ctx, cert); if (rc == -1) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "X509_STORE_CTX_get1_issuer() failed"); X509_STORE_CTX_free(store_ctx); return NGX_ERROR; } if (rc == 0) { ngx_log_error(NGX_LOG_WARN, ssl->log, 0, "\"ssl_stapling\" ignored, issuer certificate not found"); X509_STORE_CTX_free(store_ctx); return NGX_DECLINED; } X509_STORE_CTX_free(store_ctx); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ssl->log, 0, "SSL get issuer: found %p in cert store", issuer); staple->issuer = issuer; return NGX_OK; }