return ret;
}
+struct ocsp_req_ctx_st {
+ gnutls_pcert_st *pcert;
+ unsigned cert_index;
+ gnutls_session_t session;
+ gnutls_certificate_credentials_t cred;
+};
+
+static
+int append_status_request(void *_ctx, gnutls_buffer_st *buf)
+{
+ struct ocsp_req_ctx_st *ctx = _ctx;
+ gnutls_session_t session = ctx->session;
+ int ret;
+ gnutls_datum_t resp;
+
+ assert(session->internals.selected_ocsp_func != NULL || ctx->cred->glob_ocsp_func != NULL);
+
+ /* The global ocsp callback function can only be used to return
+ * a single certificate request */
+ if (!session->internals.selected_ocsp_func && ctx->cert_index != 0)
+ return 0;
+
+ if (session->internals.selected_ocsp_length > 0) {
+ if (ctx->cert_index < session->internals.selected_ocsp_length) {
+ resp.data = session->internals.selected_ocsp[ctx->cert_index].data;
+ resp.size = session->internals.selected_ocsp[ctx->cert_index].size;
+ ret = 0;
+ } else {
+ return 0;
+ }
+ } else if (session->internals.selected_ocsp_func) {
+ if (ctx->cert_index == 0)
+ ret = session->internals.selected_ocsp_func(session, session->internals.selected_ocsp_func_ptr, &resp);
+ else {
+ return 0;
+ }
+ } else
+ return 0;
+
+ if (ret == GNUTLS_E_NO_CERTIFICATE_STATUS || resp.data == 0) {
+ return 0;
+ } else if (ret < 0) {
+ return gnutls_assert_val(ret);
+ }
+
+ ret = _gnutls_buffer_append_data(buf, "\x01", 1);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = _gnutls_buffer_append_data_prefix(buf, 24, resp.data, resp.size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = 0;
+ cleanup:
+ gnutls_free(resp.data);
+ return ret;
+}
+
int _gnutls13_send_certificate(gnutls_session_t session, unsigned again)
{
int ret;
int apr_cert_list_length;
mbuffer_st *bufel = NULL;
gnutls_buffer_st buf;
- unsigned pos_mark;
+ unsigned pos_mark, ext_pos_mark;
unsigned i;
+ struct ocsp_req_ctx_st ctx;
+ gnutls_certificate_credentials_t cred;
+
if (again == 0) {
+ cred = (gnutls_certificate_credentials_t)
+ _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
+ if (cred == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
+ }
+
ret = _gnutls_get_selected_cert(session, &apr_cert_list,
&apr_cert_list_length, &apr_pkey);
if (ret < 0)
goto cleanup;
}
- /* no extensions for now */
- ret = _gnutls_buffer_append_prefix(&buf, 16, 0);
- if (ret < 0) {
- gnutls_assert();
- goto cleanup;
+#ifdef ENABLE_OCSP
+ if ((session->internals.selected_ocsp_func != NULL ||
+ cred->glob_ocsp_func != NULL) &&
+ _gnutls_hello_ext_is_present(session, GNUTLS_EXTENSION_STATUS_REQUEST)) {
+ /* append status response if available */
+ ret = _gnutls_extv_append_init(&buf);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ ext_pos_mark = ret;
+
+ ctx.pcert = &apr_cert_list[i];
+ ctx.cert_index = i;
+ ctx.session = session;
+ ctx.cred = cred;
+ ret = _gnutls_extv_append(&buf, STATUS_REQUEST_TLS_ID,
+ &ctx, append_status_request);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = _gnutls_extv_append_final(&buf, ext_pos_mark);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ } else
+#endif
+ {
+ ret = _gnutls_buffer_append_prefix(&buf, 16, 0);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
}
}