/src/botan/src/lib/tls/msg_cert_verify.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Certificate Verify Message |
3 | | * (C) 2004,2006,2011,2012 Jack Lloyd |
4 | | * 2017 Harry Reimann, Rohde & Schwarz Cybersecurity |
5 | | * 2021 Elektrobit Automotive GmbH |
6 | | * 2022 René Meusel, Hannes Rantzsch - neXenio GmbH |
7 | | * |
8 | | * Botan is released under the Simplified BSD License (see license.txt) |
9 | | */ |
10 | | |
11 | | #include <botan/tls_messages.h> |
12 | | |
13 | | #include <botan/credentials_manager.h> |
14 | | #include <botan/pk_keys.h> |
15 | | #include <botan/tls_algos.h> |
16 | | #include <botan/tls_extensions.h> |
17 | | #include <botan/internal/stl_util.h> |
18 | | #include <botan/internal/tls_handshake_io.h> |
19 | | #include <botan/internal/tls_handshake_state.h> |
20 | | #include <botan/internal/tls_reader.h> |
21 | | |
22 | | namespace Botan::TLS { |
23 | | |
24 | | /* |
25 | | * Create a new Certificate Verify message for TLS 1.2 |
26 | | */ |
27 | | Certificate_Verify_12::Certificate_Verify_12(Handshake_IO& io, |
28 | | Handshake_State& state, |
29 | | const Policy& policy, |
30 | | RandomNumberGenerator& rng, |
31 | 0 | const Private_Key* priv_key) { |
32 | 0 | BOTAN_ASSERT_NONNULL(priv_key); |
33 | |
|
34 | 0 | std::pair<std::string, Signature_Format> format = state.choose_sig_format(*priv_key, m_scheme, true, policy); |
35 | |
|
36 | 0 | m_signature = |
37 | 0 | state.callbacks().tls_sign_message(*priv_key, rng, format.first, format.second, state.hash().get_contents()); |
38 | |
|
39 | 0 | state.hash().update(io.send(*this)); |
40 | 0 | } |
41 | | |
42 | | /* |
43 | | * Deserialize a Certificate Verify message |
44 | | */ |
45 | 1.71k | Certificate_Verify::Certificate_Verify(const std::vector<uint8_t>& buf) { |
46 | 1.71k | TLS_Data_Reader reader("CertificateVerify", buf); |
47 | | |
48 | 1.71k | m_scheme = Signature_Scheme(reader.get_uint16_t()); |
49 | 1.71k | m_signature = reader.get_range<uint8_t>(2, 0, 65535); |
50 | 1.71k | reader.assert_done(); |
51 | | |
52 | 1.71k | if(!m_scheme.is_set()) { |
53 | 1 | throw Decoding_Error("Counterparty did not send hash/sig IDS"); |
54 | 1 | } |
55 | 1.71k | } |
56 | | |
57 | | /* |
58 | | * Serialize a Certificate Verify message |
59 | | */ |
60 | 0 | std::vector<uint8_t> Certificate_Verify::serialize() const { |
61 | 0 | BOTAN_ASSERT_NOMSG(m_scheme.is_set()); |
62 | 0 | std::vector<uint8_t> buf; |
63 | 0 | buf.reserve(2 + 2 + m_signature.size()); // work around GCC warning |
64 | |
|
65 | 0 | const auto code = m_scheme.wire_code(); |
66 | 0 | buf.push_back(get_byte<0>(code)); |
67 | 0 | buf.push_back(get_byte<1>(code)); |
68 | |
|
69 | 0 | if(m_signature.size() > 0xFFFF) { |
70 | 0 | throw Encoding_Error("Certificate_Verify signature too long to encode"); |
71 | 0 | } |
72 | | |
73 | 0 | const uint16_t sig_len = static_cast<uint16_t>(m_signature.size()); |
74 | 0 | buf.push_back(get_byte<0>(sig_len)); |
75 | 0 | buf.push_back(get_byte<1>(sig_len)); |
76 | 0 | buf += m_signature; |
77 | |
|
78 | 0 | return buf; |
79 | 0 | } |
80 | | |
81 | | bool Certificate_Verify_12::verify(const X509_Certificate& cert, |
82 | | const Handshake_State& state, |
83 | 0 | const Policy& policy) const { |
84 | 0 | auto key = cert.subject_public_key(); |
85 | |
|
86 | 0 | policy.check_peer_key_acceptable(*key); |
87 | |
|
88 | 0 | std::pair<std::string, Signature_Format> format = |
89 | 0 | state.parse_sig_format(*key, m_scheme, state.client_hello()->signature_schemes(), true, policy); |
90 | |
|
91 | 0 | const bool signature_valid = |
92 | 0 | state.callbacks().tls_verify_message(*key, format.first, format.second, state.hash().get_contents(), m_signature); |
93 | |
|
94 | 0 | #if defined(BOTAN_UNSAFE_FUZZER_MODE) |
95 | 0 | BOTAN_UNUSED(signature_valid); |
96 | 0 | return true; |
97 | |
|
98 | | #else |
99 | | return signature_valid; |
100 | | |
101 | | #endif |
102 | 0 | } |
103 | | |
104 | | #if defined(BOTAN_HAS_TLS_13) |
105 | | |
106 | | namespace { |
107 | | |
108 | 0 | std::vector<uint8_t> message(Connection_Side side, const Transcript_Hash& hash) { |
109 | 0 | std::vector<uint8_t> msg(64, 0x20); |
110 | 0 | msg.reserve(64 + 33 + 1 + hash.size()); |
111 | |
|
112 | 0 | const std::string context_string = (side == TLS::Connection_Side::Server) ? "TLS 1.3, server CertificateVerify" |
113 | 0 | : "TLS 1.3, client CertificateVerify"; |
114 | |
|
115 | 0 | msg.insert(msg.end(), context_string.cbegin(), context_string.cend()); |
116 | 0 | msg.push_back(0x00); |
117 | |
|
118 | 0 | msg.insert(msg.end(), hash.cbegin(), hash.cend()); |
119 | 0 | return msg; |
120 | 0 | } |
121 | | |
122 | | Signature_Scheme choose_signature_scheme(const Private_Key& key, |
123 | | const std::vector<Signature_Scheme>& allowed_schemes, |
124 | 0 | const std::vector<Signature_Scheme>& peer_allowed_schemes) { |
125 | 0 | for(Signature_Scheme scheme : allowed_schemes) { |
126 | 0 | if(scheme.is_available() && scheme.is_suitable_for(key) && value_exists(peer_allowed_schemes, scheme)) { |
127 | 0 | return scheme; |
128 | 0 | } |
129 | 0 | } |
130 | | |
131 | 0 | throw TLS_Exception(Alert::HandshakeFailure, "Failed to agree on a signature algorithm"); |
132 | 0 | } |
133 | | |
134 | | } // namespace |
135 | | |
136 | | /* |
137 | | * Create a new Certificate Verify message for TLS 1.3 |
138 | | */ |
139 | | Certificate_Verify_13::Certificate_Verify_13(const Certificate_13& certificate_msg, |
140 | | const std::vector<Signature_Scheme>& peer_allowed_schemes, |
141 | | std::string_view hostname, |
142 | | const Transcript_Hash& hash, |
143 | | Connection_Side whoami, |
144 | | Credentials_Manager& creds_mgr, |
145 | | const Policy& policy, |
146 | | Callbacks& callbacks, |
147 | | RandomNumberGenerator& rng) : |
148 | 0 | m_side(whoami) { |
149 | 0 | BOTAN_ASSERT_NOMSG(!certificate_msg.empty()); |
150 | |
|
151 | 0 | const auto op_type = (m_side == Connection_Side::Client) ? "tls-client" : "tls-server"; |
152 | 0 | const auto context = std::string(hostname); |
153 | |
|
154 | 0 | const auto private_key = (certificate_msg.has_certificate_chain()) |
155 | 0 | ? creds_mgr.private_key_for(certificate_msg.leaf(), op_type, context) |
156 | 0 | : creds_mgr.private_key_for(*certificate_msg.public_key(), op_type, context); |
157 | 0 | if(!private_key) { |
158 | 0 | throw TLS_Exception(Alert::InternalError, "Application did not provide a private key for its credential"); |
159 | 0 | } |
160 | | |
161 | 0 | m_scheme = choose_signature_scheme(*private_key, policy.allowed_signature_schemes(), peer_allowed_schemes); |
162 | 0 | BOTAN_ASSERT_NOMSG(m_scheme.is_available()); |
163 | 0 | BOTAN_ASSERT_NOMSG(m_scheme.is_compatible_with(Protocol_Version::TLS_V13)); |
164 | |
|
165 | 0 | m_signature = callbacks.tls_sign_message( |
166 | 0 | *private_key, rng, m_scheme.padding_string(), m_scheme.format().value(), message(m_side, hash)); |
167 | 0 | } |
168 | | |
169 | | Certificate_Verify_13::Certificate_Verify_13(const std::vector<uint8_t>& buf, const Connection_Side side) : |
170 | 1.71k | Certificate_Verify(buf), m_side(side) { |
171 | 1.71k | if(!m_scheme.is_available()) { |
172 | 24 | throw TLS_Exception(Alert::HandshakeFailure, "Peer sent unknown signature scheme"); |
173 | 24 | } |
174 | | |
175 | 1.68k | if(!m_scheme.is_compatible_with(Protocol_Version::TLS_V13)) { |
176 | 4 | throw TLS_Exception(Alert::IllegalParameter, "Peer sent signature algorithm that is not suitable for TLS 1.3"); |
177 | 4 | } |
178 | 1.68k | } |
179 | | |
180 | | /* |
181 | | * Verify a Certificate Verify message |
182 | | */ |
183 | | bool Certificate_Verify_13::verify(const Public_Key& public_key, |
184 | | Callbacks& callbacks, |
185 | 0 | const Transcript_Hash& transcript_hash) const { |
186 | 0 | BOTAN_ASSERT_NOMSG(m_scheme.is_available()); |
187 | | |
188 | | // RFC 8446 4.2.3 |
189 | | // The keys found in certificates MUST [...] be of appropriate type for |
190 | | // the signature algorithms they are used with. |
191 | 0 | if(m_scheme.key_algorithm_identifier() != public_key.algorithm_identifier()) { |
192 | 0 | throw TLS_Exception(Alert::IllegalParameter, "Signature algorithm does not match certificate's public key"); |
193 | 0 | } |
194 | | |
195 | 0 | const bool signature_valid = callbacks.tls_verify_message( |
196 | 0 | public_key, m_scheme.padding_string(), m_scheme.format().value(), message(m_side, transcript_hash), m_signature); |
197 | |
|
198 | 0 | #if defined(BOTAN_UNSAFE_FUZZER_MODE) |
199 | 0 | BOTAN_UNUSED(signature_valid); |
200 | 0 | return true; |
201 | | #else |
202 | | return signature_valid; |
203 | | #endif |
204 | 0 | } |
205 | | |
206 | | #endif // BOTAN_HAS_TLS_13 |
207 | | |
208 | | } // namespace Botan::TLS |