bud_error_t bud_client_ocsp_stapling(bud_client_t* client) { bud_config_t* config; bud_context_t* context; bud_error_t err; const char* id; size_t id_size; config = client->config; if (client->sni_ctx.ctx != NULL) { /* Async SNI success */ context = &client->sni_ctx; } else if (client->hello.servername_len != 0) { /* Matching context */ context = bud_config_select_context(config, client->hello.servername, client->hello.servername_len); } else { /* Default context */ context = &config->contexts[0]; } /* Cache context to prevent second search in OpenSSL's callback */ if (!SSL_set_ex_data(client->ssl, kBudSSLSNIIndex, context)) { err = bud_error(kBudErrStaplingSetData); goto fatal; } id = bud_context_get_ocsp_id(context, &id_size); /* Certificate has no OCSP id */ if (id == NULL) return bud_ok(); /* Request backend for cached respose first */ client->stapling_cache_req = bud_http_get(config->stapling.pool, config->stapling.query_fmt, id, id_size, bud_client_stapling_cache_req_cb, &err); client->stapling_cache_req->data = client; if (!bud_is_ok(err)) goto fatal; client->hello_parse = kBudProgressRunning; return bud_ok(); fatal: return err; }
bud_client_error_t bud_client_on_hello(bud_client_t* client) { bud_config_t* config; bud_error_t err; config = client->config; /* Perform SNI lookup */ if (config->sni.enabled && client->hello.servername_len != 0) { client->sni_req = bud_http_get(config->sni.pool, config->sni.url, client->hello.servername, client->hello.servername_len, bud_client_sni_cb, &err); if (!bud_is_ok(err)) { NOTICE(&client->frontend, "failed to request SNI: \"%s\"", bud_error_to_str(err)); goto fatal; } client->sni_req->data = client; client->async_hello = kBudProgressRunning; /* Perform OCSP stapling request */ } else if (config->stapling.enabled && client->hello.ocsp_request != 0) { err = bud_client_ocsp_stapling(client); if (!bud_is_ok(err)) goto fatal; } if (client->async_hello != kBudProgressNone) return bud_client_ok(&client->frontend); client->async_hello = kBudProgressDone; return bud_client_cycle(client); fatal: client->async_hello = kBudProgressDone; return bud_client_error(err, &client->frontend); }
bud_client_error_t bud_client_parse_hello(bud_client_t* client) { bud_config_t* config; bud_error_t err; char* data; size_t size; /* Already running, ignore */ if (client->hello_parse != kBudProgressNone) return bud_client_ok(&client->frontend); if (ringbuffer_is_empty(&client->frontend.input)) return bud_client_ok(&client->frontend); config = client->config; data = ringbuffer_read_next(&client->frontend.input, &size); err = bud_parse_client_hello(data, (size_t) size, &client->hello); /* Parser need more data, wait for it */ if (err.code == kBudErrParserNeedMore) return bud_client_ok(&client->frontend); if (!bud_is_ok(err)) { NOTICE(&client->frontend, "failed to parse hello: \"%s\"", bud_error_to_str(err)); goto fatal; } /* Parse success, perform SNI lookup */ if (config->sni.enabled && client->hello.servername_len != 0) { client->sni_req = bud_http_get(config->sni.pool, config->sni.url, client->hello.servername, client->hello.servername_len, bud_client_sni_cb, &err); client->sni_req->data = client; if (!bud_is_ok(err)) { NOTICE(&client->frontend, "failed to request SNI: \"%s\"", bud_error_to_str(err)); goto fatal; } client->hello_parse = kBudProgressRunning; /* Perform OCSP stapling request */ } else if (config->stapling.enabled && client->hello.ocsp_request != 0) { err = bud_client_ocsp_stapling(client); if (!bud_is_ok(err)) goto fatal; } if (client->hello_parse != kBudProgressNone) return bud_client_ok(&client->frontend); client->hello_parse = kBudProgressDone; return bud_client_cycle(client); fatal: client->hello_parse = kBudProgressDone; return bud_client_error(err, &client->frontend); }