int SslOcspStapling::getCertId(X509 *pCert) { int i, n; X509 *pXissuer; X509_STORE *pXstore; STACK_OF(X509) *pXchain; X509_STORE_CTX *pXstore_ctx; pXchain = m_pCtx->extra_certs; n = sk_X509_num(pXchain); for (i = 0; i < n; i++) { pXissuer = sk_X509_value(pXchain, i); if (X509_check_issued(pXissuer, pCert) == X509_V_OK) { CRYPTO_add(&pXissuer->references, 1, CRYPTO_LOCK_X509); m_pCertId = OCSP_cert_to_id(NULL, pCert, pXissuer); X509_free(pXissuer); return 0; } } pXstore = SSL_CTX_get_cert_store(m_pCtx); if (pXstore == NULL) { setLastErrMsg("SSL_CTX_get_cert_store failed!\n"); return LS_FAIL; } pXstore_ctx = X509_STORE_CTX_new(); if (pXstore_ctx == NULL) { setLastErrMsg("X509_STORE_CTX_new failed!\n"); return LS_FAIL; } if (X509_STORE_CTX_init(pXstore_ctx, pXstore, NULL, NULL) == 0) { setLastErrMsg("X509_STORE_CTX_init failed!\n"); return LS_FAIL; } n = X509_STORE_CTX_get1_issuer(&pXissuer, pXstore_ctx, pCert); X509_STORE_CTX_free(pXstore_ctx); if ((n == -1) || (n == 0)) { setLastErrMsg("X509_STORE_CTX_get1_issuer failed!\n"); return LS_FAIL; } m_pCertId = OCSP_cert_to_id(NULL, pCert, pXissuer); X509_free(pXissuer); return 0; }
/* * Before trusting a certificate, you must make sure that the * certificate is 'valid'. There are several steps that your * application can take in determining if a certificate is * valid. Commonly used steps are: * * 1.Verifying the certificate's signature, and verifying that * the certificate has been issued by a trusted Certificate * Authority. * * 2.Verifying that the certificate is valid for the present date * (i.e. it is being presented within its validity dates). * * 3.Verifying that the certificate has not been revoked by its * issuing Certificate Authority, by checking with respect to a * Certificate Revocation List (CRL). * * 4.Verifying that the credentials presented by the certificate * fulfill additional requirements specific to the application, * such as with respect to access control lists or with respect * to OCSP (Online Certificate Status Processing). * * NOTE: This callback will be called multiple times based on the * depth of the root certificate chain */ static int cbtls_verify(int ok, X509_STORE_CTX *ctx) { char subject[1024]; /* Used for the subject name */ char issuer[1024]; /* Used for the issuer name */ char common_name[1024]; char cn_str[1024]; char buf[64]; EAP_HANDLER *handler = NULL; X509 *client_cert; X509 *issuer_cert; SSL *ssl; int err, depth, lookup; EAP_TLS_CONF *conf; int my_ok = ok; REQUEST *request; ASN1_INTEGER *sn = NULL; ASN1_TIME *asn_time = NULL; #ifdef HAVE_OPENSSL_OCSP_H X509_STORE *ocsp_store = NULL; #endif client_cert = X509_STORE_CTX_get_current_cert(ctx); err = X509_STORE_CTX_get_error(ctx); depth = X509_STORE_CTX_get_error_depth(ctx); lookup = depth; /* * Log client/issuing cert. If there's an error, log * issuing cert. */ if ((lookup > 1) && !my_ok) lookup = 1; /* * Retrieve the pointer to the SSL of the connection currently treated * and the application specific data stored into the SSL object. */ ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); handler = (EAP_HANDLER *)SSL_get_ex_data(ssl, 0); request = handler->request; conf = (EAP_TLS_CONF *)SSL_get_ex_data(ssl, 1); #ifdef HAVE_OPENSSL_OCSP_H ocsp_store = (X509_STORE *)SSL_get_ex_data(ssl, 2); #endif /* * Get the Serial Number */ buf[0] = '\0'; sn = X509_get_serialNumber(client_cert); /* * For this next bit, we create the attributes *only* if * we're at the client or issuing certificate. */ if ((lookup <= 1) && sn && (sn->length < (sizeof(buf) / 2))) { char *p = buf; int i; for (i = 0; i < sn->length; i++) { sprintf(p, "%02x", (unsigned int)sn->data[i]); p += 2; } pairadd(&handler->certs, pairmake(cert_attr_names[EAPTLS_SERIAL][lookup], buf, T_OP_SET)); } /* * Get the Expiration Date */ buf[0] = '\0'; asn_time = X509_get_notAfter(client_cert); if ((lookup <= 1) && asn_time && (asn_time->length < MAX_STRING_LEN)) { memcpy(buf, (char*) asn_time->data, asn_time->length); buf[asn_time->length] = '\0'; pairadd(&handler->certs, pairmake(cert_attr_names[EAPTLS_EXPIRATION][lookup], buf, T_OP_SET)); } /* * Get the Subject & Issuer */ subject[0] = issuer[0] = '\0'; X509_NAME_oneline(X509_get_subject_name(client_cert), subject, sizeof(subject)); subject[sizeof(subject) - 1] = '\0'; if ((lookup <= 1) && subject[0] && (strlen(subject) < MAX_STRING_LEN)) { pairadd(&handler->certs, pairmake(cert_attr_names[EAPTLS_SUBJECT][lookup], subject, T_OP_SET)); } X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), issuer, sizeof(issuer)); issuer[sizeof(issuer) - 1] = '\0'; if ((lookup <= 1) && issuer[0] && (strlen(issuer) < MAX_STRING_LEN)) { pairadd(&handler->certs, pairmake(cert_attr_names[EAPTLS_ISSUER][lookup], issuer, T_OP_SET)); } /* * Get the Common Name */ X509_NAME_get_text_by_NID(X509_get_subject_name(client_cert), NID_commonName, common_name, sizeof(common_name)); common_name[sizeof(common_name) - 1] = '\0'; if ((lookup <= 1) && common_name[0] && (strlen(common_name) < MAX_STRING_LEN)) { pairadd(&handler->certs, pairmake(cert_attr_names[EAPTLS_CN][lookup], common_name, T_OP_SET)); } /* * If the CRL has expired, that might still be OK. */ if (!my_ok && (conf->allow_expired_crl) && (err == X509_V_ERR_CRL_HAS_EXPIRED)) { my_ok = 1; X509_STORE_CTX_set_error( ctx, 0 ); } if (!my_ok) { const char *p = X509_verify_cert_error_string(err); radlog(L_ERR,"--> verify error:num=%d:%s\n",err, p); radius_pairmake(request, &request->packet->vps, "Module-Failure-Message", p, T_OP_SET); return my_ok; } switch (ctx->error) { case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: radlog(L_ERR, "issuer= %s\n", issuer); break; case X509_V_ERR_CERT_NOT_YET_VALID: case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: radlog(L_ERR, "notBefore="); #if 0 ASN1_TIME_print(bio_err, X509_get_notBefore(ctx->current_cert)); #endif break; case X509_V_ERR_CERT_HAS_EXPIRED: case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: radlog(L_ERR, "notAfter="); #if 0 ASN1_TIME_print(bio_err, X509_get_notAfter(ctx->current_cert)); #endif break; } /* * If we're at the actual client cert, apply additional * checks. */ if (depth == 0) { /* * If the conf tells us to, check cert issuer * against the specified value and fail * verification if they don't match. */ if (conf->check_cert_issuer && (strcmp(issuer, conf->check_cert_issuer) != 0)) { radlog(L_AUTH, "rlm_eap_tls: Certificate issuer (%s) does not match specified value (%s)!", issuer, conf->check_cert_issuer); my_ok = 0; } /* * If the conf tells us to, check the CN in the * cert against xlat'ed value, but only if the * previous checks passed. */ if (my_ok && conf->check_cert_cn) { if (!radius_xlat(cn_str, sizeof(cn_str), conf->check_cert_cn, handler->request, NULL)) { radlog(L_ERR, "rlm_eap_tls (%s): xlat failed.", conf->check_cert_cn); /* if this fails, fail the verification */ my_ok = 0; } else { RDEBUG2("checking certificate CN (%s) with xlat'ed value (%s)", common_name, cn_str); if (strcmp(cn_str, common_name) != 0) { radlog(L_AUTH, "rlm_eap_tls: Certificate CN (%s) does not match specified value (%s)!", common_name, cn_str); my_ok = 0; } } } /* check_cert_cn */ #ifdef HAVE_OPENSSL_OCSP_H if (my_ok && conf->ocsp_enable){ RDEBUG2("--> Starting OCSP Request"); if(X509_STORE_CTX_get1_issuer(&issuer_cert, ctx, client_cert)!=1) { radlog(L_ERR, "Error: Couldn't get issuer_cert for %s", common_name); } my_ok = ocsp_check(ocsp_store, issuer_cert, client_cert, conf); } #endif while (conf->verify_client_cert_cmd) { char filename[256]; int fd; FILE *fp; snprintf(filename, sizeof(filename), "%s/%s.client.XXXXXXXX", conf->verify_tmp_dir, progname); fd = mkstemp(filename); if (fd < 0) { RDEBUG("Failed creating file in %s: %s", conf->verify_tmp_dir, strerror(errno)); break; } fp = fdopen(fd, "w"); if (!fp) { RDEBUG("Failed opening file %s: %s", filename, strerror(errno)); break; } if (!PEM_write_X509(fp, client_cert)) { fclose(fp); RDEBUG("Failed writing certificate to file"); goto do_unlink; } fclose(fp); if (!radius_pairmake(request, &request->packet->vps, "TLS-Client-Cert-Filename", filename, T_OP_SET)) { RDEBUG("Failed creating TLS-Client-Cert-Filename"); goto do_unlink; } RDEBUG("Verifying client certificate: %s", conf->verify_client_cert_cmd); if (radius_exec_program(conf->verify_client_cert_cmd, request, 1, NULL, 0, request->packet->vps, NULL, 1) != 0) { radlog(L_AUTH, "rlm_eap_tls: Certificate CN (%s) fails external verification!", common_name); my_ok = 0; } else { RDEBUG("Client certificate CN %s passed external validation", common_name); } do_unlink: unlink(filename); break; } } /* depth == 0 */ if (debug_flag > 0) { RDEBUG2("chain-depth=%d, ", depth); RDEBUG2("error=%d", err); RDEBUG2("--> User-Name = %s", handler->identity); RDEBUG2("--> BUF-Name = %s", common_name); RDEBUG2("--> subject = %s", subject); RDEBUG2("--> issuer = %s", issuer); RDEBUG2("--> verify return:%d", my_ok); } return my_ok; }
static ngx_int_t ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl) { int i, n, rc; X509 *cert, *issuer; X509_STORE *store; X509_STORE_CTX *store_ctx; STACK_OF(X509) *chain; ngx_ssl_stapling_t *staple; staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index); cert = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_certificate_index); #if OPENSSL_VERSION_NUMBER >= 0x10001000L 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->cert = cert; 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->cert = cert; staple->issuer = issuer; return NGX_OK; }
/** * 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; X509_STORE* store; X509_STORE_CTX store_ctx; int r; unsigned long err; ERR_clear_error(); ret = 0; x = PEM_read_bio_X509_AUX(in, NULL, NULL, 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); ctx->cert = x; ctx->issuer = NULL; if (ERR_peek_error() != 0) { /* Key/certificate mismatch doesn't imply ret==0 ... */ ret = 0; } if (ret) { /** * If we could set up our certificate, now proceed to * the CA certificates. */ if (ctx->ctx->extra_certs != NULL) { sk_X509_pop_free(ctx->ctx->extra_certs, X509_free); ctx->ctx->extra_certs = NULL; } while ((ca = PEM_read_bio_X509(in, NULL, NULL, NULL))) { r = SSL_CTX_add_extra_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 (ctx->issuer != NULL || X509_check_issued(ca, x) != X509_V_OK) continue; ctx->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 (ctx->issuer == NULL) { 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(&ctx->issuer, &store_ctx, ctx->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(&ctx->issuer->references, 1, CRYPTO_LOCK_X509); } if (ctx->issuer != NULL) { /* Get ocsp_id */ ctx->ocsp_id = OCSP_cert_to_id(NULL, ctx->cert, ctx->issuer); if (ctx->ocsp_id == NULL) { ctx->issuer = NULL; goto fatal; } } } else { if (ctx->issuer != NULL) X509_free(ctx->issuer); } fatal: if (ctx->cert != x && x != NULL) X509_free(x); return ret; }
/** * 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 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; }