Botan 3.12.0
Crypto and TLS for C&
tls_extensions_cert_status_req.cpp
Go to the documentation of this file.
1/*
2* TLS Extension Certificate_Status_Request
3* (C) 2011,2012,2015,2016,2022 Jack Lloyd
4* 2016 Juraj Somorovsky
5* 2021 Elektrobit Automotive GmbH
6* 2022 Hannes Rantzsch, René Meusel, neXenio GmbH
7*
8* Botan is released under the Simplified BSD License (see license.txt)
9*/
10
11#include <botan/tls_extensions.h>
12
13#include <botan/tls_exceptn.h>
14#include <botan/tls_messages.h>
15#include <botan/internal/tls_reader.h>
16
17namespace Botan::TLS {
18
19namespace {
20class RFC6066_Empty_Certificate_Status_Request {
21 public:
22 RFC6066_Empty_Certificate_Status_Request() = default;
23
24 explicit RFC6066_Empty_Certificate_Status_Request(uint16_t extension_size) {
25 if(extension_size != 0) {
26 throw Decoding_Error("Received an unexpectedly non-empty Certificate_Status_Request");
27 }
28 }
29
30 std::vector<uint8_t> serialize() const { return {}; }
31};
32
33class RFC6066_Certificate_Status_Request {
34 public:
35 RFC6066_Certificate_Status_Request(std::vector<uint8_t> names, std::vector<std::vector<uint8_t>> keys) :
36 ocsp_names(std::move(names)), ocsp_keys(std::move(keys)) {}
37
38 RFC6066_Certificate_Status_Request(TLS_Data_Reader& reader, uint16_t extension_size) {
39 if(extension_size == 0) {
40 throw Decoding_Error("Received an unexpectedly empty Certificate_Status_Request");
41 }
42
43 const uint8_t type = reader.get_byte();
44 if(type == 1 /* ocsp */) {
45 // RFC 6066 Section 8: OCSP CertificateStatusRequest is
46 // ResponderID responder_id_list<0..2^16-1>;
47 // Extensions request_extensions;
48 //
49 // for a total wire size of 1 (status_type) + 2 (resp_id_list len)
50 // + len_resp_id_list + 2 (request_ext len) + len_requ_ext.
51 if(extension_size < 5) {
52 throw Decoding_Error("Truncated OCSP CertificateStatusRequest");
53 }
54 const size_t len_resp_id_list = reader.get_uint16_t();
55 if(len_resp_id_list > static_cast<size_t>(extension_size) - 5) {
56 throw Decoding_Error("Inconsistent length in OCSP CertificateStatusRequest");
57 }
58 ocsp_names = reader.get_fixed<uint8_t>(len_resp_id_list);
59 const size_t len_requ_ext = reader.get_uint16_t();
60 if(len_resp_id_list + len_requ_ext + 5 != extension_size) {
61 throw Decoding_Error("Inconsistent length in OCSP CertificateStatusRequest");
62 }
63 extension_bytes = reader.get_fixed<uint8_t>(len_requ_ext);
64 } else {
65 // RFC 6066 does not specify anything but 'ocsp' and we
66 // don't support anything else either.
67 reader.discard_next(extension_size - 1);
68 }
69 }
70
71 std::vector<uint8_t> serialize() const {
72 // Serialization is hard-coded as we don't support advanced features
73 // of this extension anyway.
74 return {
75 1, // status_type = ocsp
76 0,
77 0, // empty responder_id_list
78 0,
79 0, // no extensions
80 };
81 }
82
83 std::vector<uint8_t> ocsp_names; // NOLINT(*-non-private-member-variable*)
84 std::vector<std::vector<uint8_t>> ocsp_keys; // NOLINT(*-non-private-member-variable*)
85 std::vector<uint8_t> extension_bytes; // NOLINT(*-non-private-member-variable*)
86};
87
88} // namespace
89
90class Certificate_Status_Request_Internal {
91 private:
92 using Contents =
93 std::variant<RFC6066_Empty_Certificate_Status_Request, RFC6066_Certificate_Status_Request, Certificate_Status>;
94
95 public:
96 explicit Certificate_Status_Request_Internal(Contents c) : content(std::move(c)) {}
97
98 Contents content; // NOLINT(*-non-private-member-variable*)
99};
100
102 uint16_t extension_size,
103 Handshake_Type message_type,
104 Connection_Side from) {
105 // This parser needs to take TLS 1.2 and TLS 1.3 into account. The
106 // extension's content and structure is dependent on the context it
107 // was sent in (i.e. the enclosing handshake message). Below is a list
108 // of handshake messages this can appear in.
109 //
110 // TLS 1.2
111 // * Client Hello
112 // * Server Hello
113 //
114 // TLS 1.3
115 // * Client Hello
116 // * Certificate Request
117 // * Certificate (Entry)
118
119 // RFC 6066 8.
120 // In order to indicate their desire to receive certificate status
121 // information, clients MAY include an extension of type "status_request"
122 // in the (extended) client hello.
123 if(message_type == Handshake_Type::ClientHello) {
124 m_impl = std::make_unique<Certificate_Status_Request_Internal>(
125 RFC6066_Certificate_Status_Request(reader, extension_size));
126 }
127
128 // RFC 6066 8.
129 // If a server returns a "CertificateStatus" message, then the server MUST
130 // have included an extension of type "status_request" with empty
131 // "extension_data" in the extended server hello.
132 //
133 // RFC 8446 4.4.2.1
134 // A server MAY request that a client present an OCSP response with its
135 // certificate by sending an empty "status_request" extension in its
136 // CertificateRequest message.
137 else if(message_type == Handshake_Type::ServerHello || message_type == Handshake_Type::CertificateRequest) {
138 m_impl = std::make_unique<Certificate_Status_Request_Internal>(
139 RFC6066_Empty_Certificate_Status_Request(extension_size));
140 }
141
142 // RFC 8446 4.4.2.1
143 // In TLS 1.3, the server's OCSP information is carried in an extension
144 // in the CertificateEntry [in a Certificate handshake message] [...].
145 // Specifically, the body of the "status_request" extension from the
146 // server MUST be a CertificateStatus structure as defined in [RFC6066]
147 // [...].
148 //
149 // RFC 8446 4.4.2.1
150 // If the client opts to send an OCSP response, the body of its
151 // "status_request" extension MUST be a CertificateStatus structure as
152 // defined in [RFC6066].
153 else if(message_type == Handshake_Type::Certificate) {
154 m_impl = std::make_unique<Certificate_Status_Request_Internal>(
155 Certificate_Status(reader.get_fixed<uint8_t>(extension_size), from));
156 }
157
158 // all other contexts are not allowed for this extension
159 else {
160 throw TLS_Exception(Alert::UnsupportedExtension,
161 "Server sent a Certificate_Status_Request extension in an unsupported context");
162 }
163}
164
166 m_impl(std::make_unique<Certificate_Status_Request_Internal>(RFC6066_Empty_Certificate_Status_Request())) {}
167
168Certificate_Status_Request::Certificate_Status_Request(std::vector<uint8_t> ocsp_responder_ids,
169 std::vector<std::vector<uint8_t>> ocsp_key_ids) :
170 m_impl(std::make_unique<Certificate_Status_Request_Internal>(
171 RFC6066_Certificate_Status_Request(std::move(ocsp_responder_ids), std::move(ocsp_key_ids)))) {}
172
174 m_impl(std::make_unique<Certificate_Status_Request_Internal>(Certificate_Status(std::move(response)))) {}
175
177
178const std::vector<uint8_t>& Certificate_Status_Request::get_ocsp_response() const {
179 BOTAN_ASSERT_NONNULL(m_impl);
180 BOTAN_STATE_CHECK(std::holds_alternative<Certificate_Status>(m_impl->content));
181 return std::get<Certificate_Status>(m_impl->content).response();
182}
183
184std::vector<uint8_t> Certificate_Status_Request::serialize(Connection_Side /*side*/) const {
185 BOTAN_ASSERT_NONNULL(m_impl);
186 return std::visit([](const auto& c) { return c.serialize(); }, m_impl->content);
187}
188
189} // namespace Botan::TLS
#define BOTAN_STATE_CHECK(expr)
Definition assert.h:49
#define BOTAN_ASSERT_NONNULL(ptr)
Definition assert.h:114
const std::vector< uint8_t > & get_ocsp_response() const
std::vector< uint8_t > serialize(Connection_Side whoami) const override
std::vector< T > get_fixed(size_t size)
Definition tls_reader.h:129