One Level Up
Top Level
src/event/ngx_event_openssl_stapling.c - nginx-1.7.10
Data types defined
Functions defined
Source code
- #include <ngx_config.h>
- #include <ngx_core.h>
- #include <ngx_event.h>
- #include <ngx_event_connect.h>
- #if (!defined OPENSSL_NO_OCSP && defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB)
- typedef struct {
- ngx_str_t staple;
- ngx_msec_t timeout;
- ngx_resolver_t *resolver;
- ngx_msec_t resolver_timeout;
- ngx_addr_t *addrs;
- ngx_str_t host;
- ngx_str_t uri;
- in_port_t port;
- SSL_CTX *ssl_ctx;
- X509 *cert;
- X509 *issuer;
- time_t valid;
- unsigned verify:1;
- unsigned loading:1;
- } ngx_ssl_stapling_t;
- typedef struct ngx_ssl_ocsp_ctx_s ngx_ssl_ocsp_ctx_t;
- struct ngx_ssl_ocsp_ctx_s {
- X509 *cert;
- X509 *issuer;
- ngx_uint_t naddrs;
- ngx_addr_t *addrs;
- ngx_str_t host;
- ngx_str_t uri;
- in_port_t port;
- ngx_resolver_t *resolver;
- ngx_msec_t resolver_timeout;
- ngx_msec_t timeout;
- void (*handler)(ngx_ssl_ocsp_ctx_t *r);
- void *data;
- ngx_buf_t *request;
- ngx_buf_t *response;
- ngx_peer_connection_t peer;
- ngx_int_t (*process)(ngx_ssl_ocsp_ctx_t *r);
- ngx_uint_t state;
- ngx_uint_t code;
- ngx_uint_t count;
- ngx_uint_t done;
- u_char *header_name_start;
- u_char *header_name_end;
- u_char *header_start;
- u_char *header_end;
- ngx_pool_t *pool;
- ngx_log_t *log;
- };
- static ngx_int_t ngx_ssl_stapling_file(ngx_conf_t *cf, ngx_ssl_t *ssl,
- ngx_str_t *file);
- static ngx_int_t ngx_ssl_stapling_issuer(ngx_conf_t *cf, ngx_ssl_t *ssl);
- static ngx_int_t ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl,
- ngx_str_t *responder);
- static int ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn,
- void *data);
- static void ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple);
- static void ngx_ssl_stapling_ocsp_handler(ngx_ssl_ocsp_ctx_t *ctx);
- static void ngx_ssl_stapling_cleanup(void *data);
- static ngx_ssl_ocsp_ctx_t *ngx_ssl_ocsp_start(void);
- static void ngx_ssl_ocsp_done(ngx_ssl_ocsp_ctx_t *ctx);
- static void ngx_ssl_ocsp_request(ngx_ssl_ocsp_ctx_t *ctx);
- static void ngx_ssl_ocsp_resolve_handler(ngx_resolver_ctx_t *resolve);
- static void ngx_ssl_ocsp_connect(ngx_ssl_ocsp_ctx_t *ctx);
- static void ngx_ssl_ocsp_write_handler(ngx_event_t *wev);
- static void ngx_ssl_ocsp_read_handler(ngx_event_t *rev);
- static void ngx_ssl_ocsp_dummy_handler(ngx_event_t *ev);
- static ngx_int_t ngx_ssl_ocsp_create_request(ngx_ssl_ocsp_ctx_t *ctx);
- static ngx_int_t ngx_ssl_ocsp_process_status_line(ngx_ssl_ocsp_ctx_t *ctx);
- static ngx_int_t ngx_ssl_ocsp_parse_status_line(ngx_ssl_ocsp_ctx_t *ctx);
- static ngx_int_t ngx_ssl_ocsp_process_headers(ngx_ssl_ocsp_ctx_t *ctx);
- static ngx_int_t ngx_ssl_ocsp_parse_header_line(ngx_ssl_ocsp_ctx_t *ctx);
- static ngx_int_t ngx_ssl_ocsp_process_body(ngx_ssl_ocsp_ctx_t *ctx);
- static u_char *ngx_ssl_ocsp_log_error(ngx_log_t *log, u_char *buf, size_t len);
- ngx_int_t
- ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file,
- ngx_str_t *responder, ngx_uint_t verify)
- {
- ngx_int_t rc;
- ngx_pool_cleanup_t *cln;
- ngx_ssl_stapling_t *staple;
- staple = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_stapling_t));
- if (staple == NULL) {
- return NGX_ERROR;
- }
- cln = ngx_pool_cleanup_add(cf->pool, 0);
- if (cln == NULL) {
- return NGX_ERROR;
- }
- cln->handler = ngx_ssl_stapling_cleanup;
- cln->data = staple;
- if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_stapling_index, staple)
- == 0)
- {
- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
- "SSL_CTX_set_ex_data() failed");
- return NGX_ERROR;
- }
- staple->ssl_ctx = ssl->ctx;
- staple->timeout = 60000;
- staple->verify = verify;
- if (file->len) {
-
- if (ngx_ssl_stapling_file(cf, ssl, file) != NGX_OK) {
- return NGX_ERROR;
- }
- goto done;
- }
- rc = ngx_ssl_stapling_issuer(cf, ssl);
- if (rc == NGX_DECLINED) {
- return NGX_OK;
- }
- if (rc != NGX_OK) {
- return NGX_ERROR;
- }
- rc = ngx_ssl_stapling_responder(cf, ssl, responder);
- if (rc == NGX_DECLINED) {
- return NGX_OK;
- }
- if (rc != NGX_OK) {
- return NGX_ERROR;
- }
- done:
- SSL_CTX_set_tlsext_status_cb(ssl->ctx, ngx_ssl_certificate_status_callback);
- SSL_CTX_set_tlsext_status_arg(ssl->ctx, staple);
- return NGX_OK;
- }
- static ngx_int_t
- ngx_ssl_stapling_file(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file)
- {
- BIO *bio;
- int len;
- u_char *p, *buf;
- OCSP_RESPONSE *response;
- ngx_ssl_stapling_t *staple;
- staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index);
- if (ngx_conf_full_name(cf->cycle, file, 1) != NGX_OK) {
- return NGX_ERROR;
- }
- bio = BIO_new_file((char *) file->data, "r");
- if (bio == NULL) {
- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
- "BIO_new_file(\"%s\") failed", file->data);
- return NGX_ERROR;
- }
- response = d2i_OCSP_RESPONSE_bio(bio, NULL);
- if (response == NULL) {
- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
- "d2i_OCSP_RESPONSE_bio(\"%s\") failed", file->data);
- BIO_free(bio);
- return NGX_ERROR;
- }
- len = i2d_OCSP_RESPONSE(response, NULL);
- if (len <= 0) {
- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
- "i2d_OCSP_RESPONSE(\"%s\") failed", file->data);
- goto failed;
- }
- buf = ngx_alloc(len, ssl->log);
- if (buf == NULL) {
- goto failed;
- }
- p = buf;
- len = i2d_OCSP_RESPONSE(response, &p);
- if (len <= 0) {
- ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
- "i2d_OCSP_RESPONSE(\"%s\") failed", file->data);
- ngx_free(buf);
- goto failed;
- }
- OCSP_RESPONSE_free(response);
- BIO_free(bio);
- staple->staple.data = buf;
- staple->staple.len = len;
- return NGX_OK;
- failed:
- OCSP_RESPONSE_free(response);
- BIO_free(bio);
- return NGX_ERROR;
- }
- 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) {
- CRYPTO_add(&issuer->references, 1, CRYPTO_LOCK_X509);
- 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");
- 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;
- }
- static ngx_int_t
- ngx_ssl_stapling_responder(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *responder)
- {
- ngx_url_t u;
- char *s;
- ngx_ssl_stapling_t *staple;
- STACK_OF(OPENSSL_STRING) *aia;
- staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index);
- if (responder->len == 0) {
-
- aia = X509_get1_ocsp(staple->cert);
- if (aia == NULL) {
- ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
- "\"ssl_stapling\" ignored, "
- "no OCSP responder URL in the certificate");
- return NGX_DECLINED;
- }
- #if OPENSSL_VERSION_NUMBER >= 0x10000000L
- s = sk_OPENSSL_STRING_value(aia, 0);
- #else
- s = sk_value(aia, 0);
- #endif
- if (s == NULL) {
- ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
- "\"ssl_stapling\" ignored, "
- "no OCSP responder URL in the certificate");
- X509_email_free(aia);
- return NGX_DECLINED;
- }
- responder->len = ngx_strlen(s);
- responder->data = ngx_palloc(cf->pool, responder->len);
- if (responder->data == NULL) {
- X509_email_free(aia);
- return NGX_ERROR;
- }
- ngx_memcpy(responder->data, s, responder->len);
- X509_email_free(aia);
- }
- ngx_memzero(&u, sizeof(ngx_url_t));
- u.url = *responder;
- u.default_port = 80;
- u.uri_part = 1;
- if (u.url.len > 7
- && ngx_strncasecmp(u.url.data, (u_char *) "http://", 7) == 0)
- {
- u.url.len -= 7;
- u.url.data += 7;
- } else {
- ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
- "\"ssl_stapling\" ignored, "
- "invalid URL prefix in OCSP responder \"%V\"", &u.url);
- return NGX_DECLINED;
- }
- if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
- if (u.err) {
- ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
- "\"ssl_stapling\" ignored, "
- "%s in OCSP responder \"%V\"", u.err, &u.url);
- return NGX_DECLINED;
- }
- return NGX_ERROR;
- }
- staple->addrs = u.addrs;
- staple->host = u.host;
- staple->uri = u.uri;
- staple->port = u.port;
- if (staple->uri.len == 0) {
- ngx_str_set(&staple->uri, "/");
- }
- return NGX_OK;
- }
- ngx_int_t
- ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
- ngx_resolver_t *resolver, ngx_msec_t resolver_timeout)
- {
- ngx_ssl_stapling_t *staple;
- staple = SSL_CTX_get_ex_data(ssl->ctx, ngx_ssl_stapling_index);
- staple->resolver = resolver;
- staple->resolver_timeout = resolver_timeout;
- return NGX_OK;
- }
- static int
- ngx_ssl_certificate_status_callback(ngx_ssl_conn_t *ssl_conn, void *data)
- {
- int rc;
- u_char *p;
- ngx_connection_t *c;
- ngx_ssl_stapling_t *staple;
- c = ngx_ssl_get_connection(ssl_conn);
- ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0,
- "SSL certificate status callback");
- staple = data;
- rc = SSL_TLSEXT_ERR_NOACK;
- if (staple->staple.len) {
-
- p = OPENSSL_malloc(staple->staple.len);
- if (p == NULL) {
- ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "OPENSSL_malloc() failed");
- return SSL_TLSEXT_ERR_NOACK;
- }
- ngx_memcpy(p, staple->staple.data, staple->staple.len);
- SSL_set_tlsext_status_ocsp_resp(ssl_conn, p, staple->staple.len);
- rc = SSL_TLSEXT_ERR_OK;
- }
- ngx_ssl_stapling_update(staple);
- return rc;
- }
- static void
- ngx_ssl_stapling_update(ngx_ssl_stapling_t *staple)
- {
- ngx_ssl_ocsp_ctx_t *ctx;
- if (staple->host.len == 0
- || staple->loading || staple->valid >= ngx_time())
- {
- return;
- }
- staple->loading = 1;
- ctx = ngx_ssl_ocsp_start();
- if (ctx == NULL) {
- return;
- }
- ctx->cert = staple->cert;
- ctx->issuer = staple->issuer;
- ctx->addrs = staple->addrs;
- ctx->host = staple->host;
- ctx->uri = staple->uri;
- ctx->port = staple->port;
- ctx->timeout = staple->timeout;
- ctx->resolver = staple->resolver;
- ctx->resolver_timeout = staple->resolver_timeout;
- ctx->handler = ngx_ssl_stapling_ocsp_handler;
- ctx->data = staple;
- ngx_ssl_ocsp_request(ctx);
- return;
- }
- 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;
- 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;
- ocsp = NULL;
- basic = NULL;
- id = NULL;
- if (ctx->code != 200) {
- goto error;
- }
-
- 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;
- }
- OCSP_CERTID_free(id);
- OCSP_BASICRESP_free(basic);
- OCSP_RESPONSE_free(ocsp);
-
- response.len = len;
- response.data = ngx_alloc(response.len, ctx->log);
- if (response.data == NULL) {
- goto done;
- }
- 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;
- done:
- staple->loading = 0;
- staple->valid = ngx_time() + 3600;
- ngx_ssl_ocsp_done(ctx);
- return;
- error:
- staple->loading = 0;
- staple->valid = ngx_time() + 300;
- if (id) {
- OCSP_CERTID_free(id);
- }
- if (basic) {
- OCSP_BASICRESP_free(basic);
- }
- if (ocsp) {
- OCSP_RESPONSE_free(ocsp);
- }
- ngx_ssl_ocsp_done(ctx);
- }
- static void
- ngx_ssl_stapling_cleanup(void *data)
- {
- ngx_ssl_stapling_t *staple = data;
- if (staple->issuer) {
- X509_free(staple->issuer);
- }
- if (staple->staple.data) {
- ngx_free(staple->staple.data);
- }
- }
- static ngx_ssl_ocsp_ctx_t *
- ngx_ssl_ocsp_start(void)
- {
- ngx_log_t *log;
- ngx_pool_t *pool;
- ngx_ssl_ocsp_ctx_t *ctx;
- pool = ngx_create_pool(2048, ngx_cycle->log);
- if (pool == NULL) {
- return NULL;
- }
- ctx = ngx_pcalloc(pool, sizeof(ngx_ssl_ocsp_ctx_t));
- if (ctx == NULL) {
- ngx_destroy_pool(pool);
- return NULL;
- }
- log = ngx_palloc(pool, sizeof(ngx_log_t));
- if (log == NULL) {
- ngx_destroy_pool(pool);
- return NULL;
- }
- ctx->pool = pool;
- *log = *ctx->pool->log;
- ctx->pool->log = log;
- ctx->log = log;
- log->handler = ngx_ssl_ocsp_log_error;
- log->data = ctx;
- log->action = "requesting certificate status";
- return ctx;
- }
- static void
- ngx_ssl_ocsp_done(ngx_ssl_ocsp_ctx_t *ctx)
- {
- ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
- "ssl ocsp done");
- if (ctx->peer.connection) {
- ngx_close_connection(ctx->peer.connection);
- }
- ngx_destroy_pool(ctx->pool);
- }
- static void
- ngx_ssl_ocsp_error(ngx_ssl_ocsp_ctx_t *ctx)
- {
- ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
- "ssl ocsp error");
- ctx->code = 0;
- ctx->handler(ctx);
- }
- static void
- ngx_ssl_ocsp_request(ngx_ssl_ocsp_ctx_t *ctx)
- {
- ngx_resolver_ctx_t *resolve, temp;
- ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
- "ssl ocsp request");
- if (ngx_ssl_ocsp_create_request(ctx) != NGX_OK) {
- ngx_ssl_ocsp_error(ctx);
- return;
- }
- if (ctx->resolver) {
-
- temp.name = ctx->host;
- resolve = ngx_resolve_start(ctx->resolver, &temp);
- if (resolve == NULL) {
- ngx_ssl_ocsp_error(ctx);
- return;
- }
- if (resolve == NGX_NO_RESOLVER) {
- ngx_log_error(NGX_LOG_WARN, ctx->log, 0,
- "no resolver defined to resolve %V", &ctx->host);
- goto connect;
- }
- resolve->name = ctx->host;
- resolve->handler = ngx_ssl_ocsp_resolve_handler;
- resolve->data = ctx;
- resolve->timeout = ctx->resolver_timeout;
- if (ngx_resolve_name(resolve) != NGX_OK) {
- ngx_ssl_ocsp_error(ctx);
- return;
- }
- return;
- }
- connect:
- ngx_ssl_ocsp_connect(ctx);
- }
- static void
- ngx_ssl_ocsp_resolve_handler(ngx_resolver_ctx_t *resolve)
- {
- ngx_ssl_ocsp_ctx_t *ctx = resolve->data;
- u_char *p;
- size_t len;
- in_port_t port;
- socklen_t socklen;
- ngx_uint_t i;
- struct sockaddr *sockaddr;
- ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
- "ssl ocsp resolve handler");
- if (resolve->state) {
- ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
- "%V could not be resolved (%i: %s)",
- &resolve->name, resolve->state,
- ngx_resolver_strerror(resolve->state));
- goto failed;
- }
- #if (NGX_DEBUG)
- {
- u_char text[NGX_SOCKADDR_STRLEN];
- ngx_str_t addr;
- addr.data = text;
- for (i = 0; i < resolve->naddrs; i++) {
- addr.len = ngx_sock_ntop(resolve->addrs[i].sockaddr,
- resolve->addrs[i].socklen,
- text, NGX_SOCKADDR_STRLEN, 0);
- ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
- "name was resolved to %V", &addr);
- }
- }
- #endif
- ctx->naddrs = resolve->naddrs;
- ctx->addrs = ngx_pcalloc(ctx->pool, ctx->naddrs * sizeof(ngx_addr_t));
- if (ctx->addrs == NULL) {
- goto failed;
- }
- port = htons(ctx->port);
- for (i = 0; i < resolve->naddrs; i++) {
- socklen = resolve->addrs[i].socklen;
- sockaddr = ngx_palloc(ctx->pool, socklen);
- if (sockaddr == NULL) {
- goto failed;
- }
- ngx_memcpy(sockaddr, resolve->addrs[i].sockaddr, socklen);
- switch (sockaddr->sa_family) {
- #if (NGX_HAVE_INET6)
- case AF_INET6:
- ((struct sockaddr_in6 *) sockaddr)->sin6_port = port;
- break;
- #endif
- default:
- ((struct sockaddr_in *) sockaddr)->sin_port = port;
- }
- ctx->addrs[i].sockaddr = sockaddr;
- ctx->addrs[i].socklen = socklen;
- p = ngx_pnalloc(ctx->pool, NGX_SOCKADDR_STRLEN);
- if (p == NULL) {
- goto failed;
- }
- len = ngx_sock_ntop(sockaddr, socklen, p, NGX_SOCKADDR_STRLEN, 1);
- ctx->addrs[i].name.len = len;
- ctx->addrs[i].name.data = p;
- }
- ngx_resolve_name_done(resolve);
- ngx_ssl_ocsp_connect(ctx);
- return;
- failed:
- ngx_resolve_name_done(resolve);
- ngx_ssl_ocsp_error(ctx);
- }
- static void
- ngx_ssl_ocsp_connect(ngx_ssl_ocsp_ctx_t *ctx)
- {
- ngx_int_t rc;
- ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
- "ssl ocsp connect");
- TODO
- ctx->peer.sockaddr = ctx->addrs[0].sockaddr;
- ctx->peer.socklen = ctx->addrs[0].socklen;
- ctx->peer.name = &ctx->addrs[0].name;
- ctx->peer.get = ngx_event_get_peer;
- ctx->peer.log = ctx->log;
- ctx->peer.log_error = NGX_ERROR_ERR;
- rc = ngx_event_connect_peer(&ctx->peer);
- ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
- "ssl ocsp connect peer done");
- if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {
- ngx_ssl_ocsp_error(ctx);
- return;
- }
- ctx->peer.connection->data = ctx;
- ctx->peer.connection->pool = ctx->pool;
- ctx->peer.connection->read->handler = ngx_ssl_ocsp_read_handler;
- ctx->peer.connection->write->handler = ngx_ssl_ocsp_write_handler;
- ctx->process = ngx_ssl_ocsp_process_status_line;
- ngx_add_timer(ctx->peer.connection->read, ctx->timeout);
- ngx_add_timer(ctx->peer.connection->write, ctx->timeout);
- if (rc == NGX_OK) {
- ngx_ssl_ocsp_write_handler(ctx->peer.connection->write);
- return;
- }
- }
- static void
- ngx_ssl_ocsp_write_handler(ngx_event_t *wev)
- {
- ssize_t n, size;
- ngx_connection_t *c;
- ngx_ssl_ocsp_ctx_t *ctx;
- c = wev->data;
- ctx = c->data;
- ngx_log_debug0(NGX_LOG_DEBUG_EVENT, wev->log, 0,
- "ssl ocsp write handler");
- if (wev->timedout) {
- ngx_log_error(NGX_LOG_ERR, wev->log, NGX_ETIMEDOUT,
- "OCSP responder timed out");
- ngx_ssl_ocsp_error(ctx);
- return;
- }
- size = ctx->request->last - ctx->request->pos;
- n = ngx_send(c, ctx->request->pos, size);
- if (n == NGX_ERROR) {
- ngx_ssl_ocsp_error(ctx);
- return;
- }
- if (n > 0) {
- ctx->request->pos += n;
- if (n == size) {
- wev->handler = ngx_ssl_ocsp_dummy_handler;
- if (wev->timer_set) {
- ngx_del_timer(wev);
- }
- if (ngx_handle_write_event(wev, 0) != NGX_OK) {
- ngx_ssl_ocsp_error(ctx);
- }
- return;
- }
- }
- if (!wev->timer_set) {
- ngx_add_timer(wev, ctx->timeout);
- }
- }
- static void
- ngx_ssl_ocsp_read_handler(ngx_event_t *rev)
- {
- ssize_t n, size;
- ngx_int_t rc;
- ngx_ssl_ocsp_ctx_t *ctx;
- ngx_connection_t *c;
- c = rev->data;
- ctx = c->data;
- ngx_log_debug0(NGX_LOG_DEBUG_EVENT, rev->log, 0,
- "ssl ocsp read handler");
- if (rev->timedout) {
- ngx_log_error(NGX_LOG_ERR, rev->log, NGX_ETIMEDOUT,
- "OCSP responder timed out");
- ngx_ssl_ocsp_error(ctx);
- return;
- }
- if (ctx->response == NULL) {
- ctx->response = ngx_create_temp_buf(ctx->pool, 16384);
- if (ctx->response == NULL) {
- ngx_ssl_ocsp_error(ctx);
- return;
- }
- }
- for ( ;; ) {
- size = ctx->response->end - ctx->response->last;
- n = ngx_recv(c, ctx->response->last, size);
- if (n > 0) {
- ctx->response->last += n;
- rc = ctx->process(ctx);
- if (rc == NGX_ERROR) {
- ngx_ssl_ocsp_error(ctx);
- return;
- }
- continue;
- }
- if (n == NGX_AGAIN) {
- if (ngx_handle_read_event(rev, 0) != NGX_OK) {
- ngx_ssl_ocsp_error(ctx);
- }
- return;
- }
- break;
- }
- ctx->done = 1;
- rc = ctx->process(ctx);
- if (rc == NGX_DONE) {
-
- return;
- }
- ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
- "OCSP responder prematurely closed connection");
- ngx_ssl_ocsp_error(ctx);
- }
- static void
- ngx_ssl_ocsp_dummy_handler(ngx_event_t *ev)
- {
- ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0,
- "ssl ocsp dummy handler");
- }
- static ngx_int_t
- ngx_ssl_ocsp_create_request(ngx_ssl_ocsp_ctx_t *ctx)
- {
- int len;
- u_char *p;
- uintptr_t escape;
- ngx_str_t binary, base64;
- ngx_buf_t *b;
- OCSP_CERTID *id;
- OCSP_REQUEST *ocsp;
- ocsp = OCSP_REQUEST_new();
- if (ocsp == NULL) {
- ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
- "OCSP_REQUEST_new() failed");
- return NGX_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 failed;
- }
- if (OCSP_request_add0_id(ocsp, id) == NULL) {
- ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
- "OCSP_request_add0_id() failed");
- goto failed;
- }
- len = i2d_OCSP_REQUEST(ocsp, NULL);
- if (len <= 0) {
- ngx_ssl_error(NGX_LOG_CRIT, ctx->log, 0,
- "i2d_OCSP_REQUEST() failed");
- goto failed;
- }
- binary.len = len;
- binary.data = ngx_palloc(ctx->pool, len);
- if (binary.data == NULL) {
- goto failed;
- }
- p = binary.data;
- len = i2d_OCSP_REQUEST(ocsp, &p);
- if (len <= 0) {
- ngx_ssl_error(NGX_LOG_EMERG, ctx->log, 0,
- "i2d_OCSP_REQUEST() failed");
- goto failed;
- }
- base64.len = ngx_base64_encoded_length(binary.len);
- base64.data = ngx_palloc(ctx->pool, base64.len);
- if (base64.data == NULL) {
- goto failed;
- }
- ngx_encode_base64(&base64, &binary);
- escape = ngx_escape_uri(NULL, base64.data, base64.len,
- NGX_ESCAPE_URI_COMPONENT);
- ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
- "ssl ocsp request length %z, escape %d",
- base64.len, escape);
- len = sizeof("GET ") - 1 + ctx->uri.len + sizeof("/") - 1
- + base64.len + 2 * escape + sizeof(" HTTP/1.0" CRLF) - 1
- + sizeof("Host: ") - 1 + ctx->host.len + sizeof(CRLF) - 1
- + sizeof(CRLF) - 1;
- b = ngx_create_temp_buf(ctx->pool, len);
- if (b == NULL) {
- goto failed;
- }
- p = b->last;
- p = ngx_cpymem(p, "GET ", sizeof("GET ") - 1);
- p = ngx_cpymem(p, ctx->uri.data, ctx->uri.len);
- if (ctx->uri.data[ctx->uri.len - 1] != '/') {
- *p++ = '/';
- }
- if (escape == 0) {
- p = ngx_cpymem(p, base64.data, base64.len);
- } else {
- p = (u_char *) ngx_escape_uri(p, base64.data, base64.len,
- NGX_ESCAPE_URI_COMPONENT);
- }
- p = ngx_cpymem(p, " HTTP/1.0" CRLF, sizeof(" HTTP/1.0" CRLF) - 1);
- p = ngx_cpymem(p, "Host: ", sizeof("Host: ") - 1);
- p = ngx_cpymem(p, ctx->host.data, ctx->host.len);
- *p++ = CR; *p++ = LF;
-
- *p++ = CR; *p++ = LF;
- b->last = p;
- ctx->request = b;
- OCSP_REQUEST_free(ocsp);
- return NGX_OK;
- failed:
- OCSP_REQUEST_free(ocsp);
- return NGX_ERROR;
- }
- static ngx_int_t
- ngx_ssl_ocsp_process_status_line(ngx_ssl_ocsp_ctx_t *ctx)
- {
- ngx_int_t rc;
- rc = ngx_ssl_ocsp_parse_status_line(ctx);
- if (rc == NGX_OK) {
- #if 0
- #endif
- ctx->process = ngx_ssl_ocsp_process_headers;
- return ctx->process(ctx);
- }
- if (rc == NGX_AGAIN) {
- return NGX_AGAIN;
- }
-
- ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
- "OCSP responder sent invalid response");
- return NGX_ERROR;
- }
- static ngx_int_t
- ngx_ssl_ocsp_parse_status_line(ngx_ssl_ocsp_ctx_t *ctx)
- {
- u_char ch;
- u_char *p;
- ngx_buf_t *b;
- enum {
- sw_start = 0,
- sw_H,
- sw_HT,
- sw_HTT,
- sw_HTTP,
- sw_first_major_digit,
- sw_major_digit,
- sw_first_minor_digit,
- sw_minor_digit,
- sw_status,
- sw_space_after_status,
- sw_status_text,
- sw_almost_done
- } state;
- ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
- "ssl ocsp process status line");
- state = ctx->state;
- b = ctx->response;
- for (p = b->pos; p < b->last; p++) {
- ch = *p;
- switch (state) {
-
- case sw_start:
- switch (ch) {
- case 'H':
- state = sw_H;
- break;
- default:
- return NGX_ERROR;
- }
- break;
- case sw_H:
- switch (ch) {
- case 'T':
- state = sw_HT;
- break;
- default:
- return NGX_ERROR;
- }
- break;
- case sw_HT:
- switch (ch) {
- case 'T':
- state = sw_HTT;
- break;
- default:
- return NGX_ERROR;
- }
- break;
- case sw_HTT:
- switch (ch) {
- case 'P':
- state = sw_HTTP;
- break;
- default:
- return NGX_ERROR;
- }
- break;
- case sw_HTTP:
- switch (ch) {
- case '/':
- state = sw_first_major_digit;
- break;
- default:
- return NGX_ERROR;
- }
- break;
-
- case sw_first_major_digit:
- if (ch < '1' || ch > '9') {
- return NGX_ERROR;
- }
- state = sw_major_digit;
- break;
-
- case sw_major_digit:
- if (ch == '.') {
- state = sw_first_minor_digit;
- break;
- }
- if (ch < '0' || ch > '9') {
- return NGX_ERROR;
- }
- break;
-
- case sw_first_minor_digit:
- if (ch < '0' || ch > '9') {
- return NGX_ERROR;
- }
- state = sw_minor_digit;
- break;
-
- case sw_minor_digit:
- if (ch == ' ') {
- state = sw_status;
- break;
- }
- if (ch < '0' || ch > '9') {
- return NGX_ERROR;
- }
- break;
-
- case sw_status:
- if (ch == ' ') {
- break;
- }
- if (ch < '0' || ch > '9') {
- return NGX_ERROR;
- }
- ctx->code = ctx->code * 10 + ch - '0';
- if (++ctx->count == 3) {
- state = sw_space_after_status;
- }
- break;
-
- case sw_space_after_status:
- switch (ch) {
- case ' ':
- state = sw_status_text;
- break;
- case '.':
- state = sw_status_text;
- break;
- case CR:
- state = sw_almost_done;
- break;
- case LF:
- goto done;
- default:
- return NGX_ERROR;
- }
- break;
-
- case sw_status_text:
- switch (ch) {
- case CR:
- state = sw_almost_done;
- break;
- case LF:
- goto done;
- }
- break;
-
- case sw_almost_done:
- switch (ch) {
- case LF:
- goto done;
- default:
- return NGX_ERROR;
- }
- }
- }
- b->pos = p;
- ctx->state = state;
- return NGX_AGAIN;
- done:
- b->pos = p + 1;
- ctx->state = sw_start;
- return NGX_OK;
- }
- static ngx_int_t
- ngx_ssl_ocsp_process_headers(ngx_ssl_ocsp_ctx_t *ctx)
- {
- size_t len;
- ngx_int_t rc;
- ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
- "ssl ocsp process headers");
- for ( ;; ) {
- rc = ngx_ssl_ocsp_parse_header_line(ctx);
- if (rc == NGX_OK) {
- ngx_log_debug4(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
- "ssl ocsp header \"%*s: %*s\"",
- ctx->header_name_end - ctx->header_name_start,
- ctx->header_name_start,
- ctx->header_end - ctx->header_start,
- ctx->header_start);
- len = ctx->header_name_end - ctx->header_name_start;
- if (len == sizeof("Content-Type") - 1
- && ngx_strncasecmp(ctx->header_name_start,
- (u_char *) "Content-Type",
- sizeof("Content-Type") - 1)
- == 0)
- {
- len = ctx->header_end - ctx->header_start;
- if (len != sizeof("application/ocsp-response") - 1
- || ngx_strncasecmp(ctx->header_start,
- (u_char *) "application/ocsp-response",
- sizeof("application/ocsp-response") - 1)
- != 0)
- {
- ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
- "OCSP responder sent invalid "
- "\"Content-Type\" header: \"%*s\"",
- ctx->header_end - ctx->header_start,
- ctx->header_start);
- return NGX_ERROR;
- }
- continue;
- }
- TODO
- continue;
- }
- if (rc == NGX_DONE) {
- break;
- }
- if (rc == NGX_AGAIN) {
- return NGX_AGAIN;
- }
-
- ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
- "OCSP responder sent invalid response");
- return NGX_ERROR;
- }
- ctx->process = ngx_ssl_ocsp_process_body;
- return ctx->process(ctx);
- }
- static ngx_int_t
- ngx_ssl_ocsp_parse_header_line(ngx_ssl_ocsp_ctx_t *ctx)
- {
- u_char c, ch, *p;
- enum {
- sw_start = 0,
- sw_name,
- sw_space_before_value,
- sw_value,
- sw_space_after_value,
- sw_almost_done,
- sw_header_almost_done
- } state;
- state = ctx->state;
- for (p = ctx->response->pos; p < ctx->response->last; p++) {
- ch = *p;
- #if 0
- #endif
- switch (state) {
-
- case sw_start:
- switch (ch) {
- case CR:
- ctx->header_end = p;
- state = sw_header_almost_done;
- break;
- case LF:
- ctx->header_end = p;
- goto header_done;
- default:
- state = sw_name;
- ctx->header_name_start = p;
- c = (u_char) (ch | 0x20);
- if (c >= 'a' && c <= 'z') {
- break;
- }
- if (ch >= '0' && ch <= '9') {
- break;
- }
- return NGX_ERROR;
- }
- break;
-
- case sw_name:
- c = (u_char) (ch | 0x20);
- if (c >= 'a' && c <= 'z') {
- break;
- }
- if (ch == ':') {
- ctx->header_name_end = p;
- state = sw_space_before_value;
- break;
- }
- if (ch == '-') {
- break;
- }
- if (ch >= '0' && ch <= '9') {
- break;
- }
- if (ch == CR) {
- ctx->header_name_end = p;
- ctx->header_start = p;
- ctx->header_end = p;
- state = sw_almost_done;
- break;
- }
- if (ch == LF) {
- ctx->header_name_end = p;
- ctx->header_start = p;
- ctx->header_end = p;
- goto done;
- }
- return NGX_ERROR;
-
- case sw_space_before_value:
- switch (ch) {
- case ' ':
- break;
- case CR:
- ctx->header_start = p;
- ctx->header_end = p;
- state = sw_almost_done;
- break;
- case LF:
- ctx->header_start = p;
- ctx->header_end = p;
- goto done;
- default:
- ctx->header_start = p;
- state = sw_value;
- break;
- }
- break;
-
- case sw_value:
- switch (ch) {
- case ' ':
- ctx->header_end = p;
- state = sw_space_after_value;
- break;
- case CR:
- ctx->header_end = p;
- state = sw_almost_done;
- break;
- case LF:
- ctx->header_end = p;
- goto done;
- }
- break;
-
- case sw_space_after_value:
- switch (ch) {
- case ' ':
- break;
- case CR:
- state = sw_almost_done;
- break;
- case LF:
- goto done;
- default:
- state = sw_value;
- break;
- }
- break;
-
- case sw_almost_done:
- switch (ch) {
- case LF:
- goto done;
- default:
- return NGX_ERROR;
- }
-
- case sw_header_almost_done:
- switch (ch) {
- case LF:
- goto header_done;
- default:
- return NGX_ERROR;
- }
- }
- }
- ctx->response->pos = p;
- ctx->state = state;
- return NGX_AGAIN;
- done:
- ctx->response->pos = p + 1;
- ctx->state = sw_start;
- return NGX_OK;
- header_done:
- ctx->response->pos = p + 1;
- ctx->state = sw_start;
- return NGX_DONE;
- }
- static ngx_int_t
- ngx_ssl_ocsp_process_body(ngx_ssl_ocsp_ctx_t *ctx)
- {
- ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
- "ssl ocsp process body");
- if (ctx->done) {
- ctx->handler(ctx);
- return NGX_DONE;
- }
- return NGX_AGAIN;
- }
- static u_char *
- ngx_ssl_ocsp_log_error(ngx_log_t *log, u_char *buf, size_t len)
- {
- u_char *p;
- ngx_ssl_ocsp_ctx_t *ctx;
- p = buf;
- if (log->action) {
- p = ngx_snprintf(buf, len, " while %s", log->action);
- len -= p - buf;
- }
- ctx = log->data;
- if (ctx) {
- p = ngx_snprintf(p, len, ", responder: %V", &ctx->host);
- }
- return p;
- }
- #else
- ngx_int_t
- ngx_ssl_stapling(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file,
- ngx_str_t *responder, ngx_uint_t verify)
- {
- ngx_log_error(NGX_LOG_WARN, ssl->log, 0,
- "\"ssl_stapling\" ignored, not supported");
- return NGX_OK;
- }
- ngx_int_t
- ngx_ssl_stapling_resolver(ngx_conf_t *cf, ngx_ssl_t *ssl,
- ngx_resolver_t *resolver, ngx_msec_t resolver_timeout)
- {
- return NGX_OK;
- }
- #endif
One Level Up
Top Level