Botan 3.10.0
Crypto and TLS for C&
tls_signature_scheme.cpp
Go to the documentation of this file.
1/*
2* (C) 2022,2023 Jack Lloyd
3* (C) 2022 René Meusel, Hannes Rantzsch - neXenio GmbH
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#include <botan/tls_signature_scheme.h>
9
10#include <botan/ec_group.h>
11#include <botan/pss_params.h>
12#include <botan/tls_version.h>
13#include <botan/internal/stl_util.h>
14
15namespace Botan::TLS {
16
17const std::vector<Signature_Scheme>& Signature_Scheme::all_available_schemes() {
18 /*
19 * This is ordered in some approximate order of preference
20 */
21 static const std::vector<Signature_Scheme> all_schemes = {
22
23 // EdDSA 25519 is currently not supported as a signature scheme for certificates
24 // certificate authentication.
25 // See: https://github.com/randombit/botan/pull/2958#discussion_r851294715
26 //
27 // #if defined(BOTAN_HAS_ED25519)
28 // EDDSA_25519,
29 // #endif
30
34
38
42 };
43
44 return all_schemes;
45}
46
48
50
52
56
57bool Signature_Scheme::is_set() const noexcept {
58 return m_code != NONE;
59}
60
61std::string Signature_Scheme::to_string() const noexcept {
62 switch(m_code) {
63 case RSA_PKCS1_SHA1:
64 return "RSA_PKCS1_SHA1";
66 return "RSA_PKCS1_SHA256";
68 return "RSA_PKCS1_SHA384";
70 return "RSA_PKCS1_SHA512";
71
72 case ECDSA_SHA1:
73 return "ECDSA_SHA1";
74 case ECDSA_SHA256:
75 return "ECDSA_SHA256";
76 case ECDSA_SHA384:
77 return "ECDSA_SHA384";
78 case ECDSA_SHA512:
79 return "ECDSA_SHA512";
80
81 case RSA_PSS_SHA256:
82 return "RSA_PSS_SHA256";
83 case RSA_PSS_SHA384:
84 return "RSA_PSS_SHA384";
85 case RSA_PSS_SHA512:
86 return "RSA_PSS_SHA512";
87
88 case EDDSA_25519:
89 return "EDDSA_25519";
90 case EDDSA_448:
91 return "EDDSA_448";
92
93 default:
94 return "Unknown signature scheme: " + std::to_string(m_code);
95 }
96}
97
98std::string Signature_Scheme::hash_function_name() const noexcept {
99 switch(m_code) {
100 case RSA_PKCS1_SHA1:
101 case ECDSA_SHA1:
102 return "SHA-1";
103
104 case ECDSA_SHA256:
105 case RSA_PKCS1_SHA256:
106 case RSA_PSS_SHA256:
107 return "SHA-256";
108
109 case ECDSA_SHA384:
110 case RSA_PKCS1_SHA384:
111 case RSA_PSS_SHA384:
112 return "SHA-384";
113
114 case ECDSA_SHA512:
115 case RSA_PKCS1_SHA512:
116 case RSA_PSS_SHA512:
117 return "SHA-512";
118
119 case EDDSA_25519:
120 case EDDSA_448:
121 return "Pure";
122
123 default:
124 return "Unknown hash function";
125 }
126}
127
128std::string Signature_Scheme::padding_string() const noexcept {
129 switch(m_code) {
130 case RSA_PKCS1_SHA1:
131 return "PKCS1v15(SHA-1)";
132 case RSA_PKCS1_SHA256:
133 return "PKCS1v15(SHA-256)";
134 case RSA_PKCS1_SHA384:
135 return "PKCS1v15(SHA-384)";
136 case RSA_PKCS1_SHA512:
137 return "PKCS1v15(SHA-512)";
138
139 case ECDSA_SHA1:
140 return "SHA-1";
141 case ECDSA_SHA256:
142 return "SHA-256";
143 case ECDSA_SHA384:
144 return "SHA-384";
145 case ECDSA_SHA512:
146 return "SHA-512";
147
148 case RSA_PSS_SHA256:
149 return "PSS(SHA-256,MGF1,32)";
150 case RSA_PSS_SHA384:
151 return "PSS(SHA-384,MGF1,48)";
152 case RSA_PSS_SHA512:
153 return "PSS(SHA-512,MGF1,64)";
154
155 case EDDSA_25519:
156 case EDDSA_448:
157 return "Pure";
158
159 default:
160 return "Unknown padding";
161 }
162}
163
164std::string Signature_Scheme::algorithm_name() const noexcept {
165 switch(m_code) {
166 case RSA_PKCS1_SHA1:
167 case RSA_PKCS1_SHA256:
168 case RSA_PKCS1_SHA384:
169 case RSA_PKCS1_SHA512:
170 case RSA_PSS_SHA256:
171 case RSA_PSS_SHA384:
172 case RSA_PSS_SHA512:
173 return "RSA";
174
175 case ECDSA_SHA1:
176 case ECDSA_SHA256:
177 case ECDSA_SHA384:
178 case ECDSA_SHA512:
179 return "ECDSA";
180
181 case EDDSA_25519:
182 return "Ed25519";
183
184 case EDDSA_448:
185 return "Ed448";
186
187 default:
188 return "Unknown algorithm";
189 }
190}
191
193 switch(m_code) {
194 // case ECDSA_SHA1: not defined
195 case ECDSA_SHA256:
196 return {"ECDSA", EC_Group::from_name("secp256r1").DER_encode()};
197 case ECDSA_SHA384:
198 return {"ECDSA", EC_Group::from_name("secp384r1").DER_encode()};
199 case ECDSA_SHA512:
200 return {"ECDSA", EC_Group::from_name("secp521r1").DER_encode()};
201
202 case EDDSA_25519:
203 return {"Ed25519", AlgorithmIdentifier::USE_EMPTY_PARAM};
204 case EDDSA_448:
205 return {"Ed448", AlgorithmIdentifier::USE_EMPTY_PARAM};
206
207 case RSA_PKCS1_SHA1:
208 case RSA_PKCS1_SHA256:
209 case RSA_PKCS1_SHA384:
210 case RSA_PKCS1_SHA512:
211 case RSA_PSS_SHA256:
212 case RSA_PSS_SHA384:
213 case RSA_PSS_SHA512:
215
216 default:
217 return AlgorithmIdentifier();
218 }
219}
220
222 switch(m_code) {
223 case RSA_PKCS1_SHA1:
225 case RSA_PKCS1_SHA256:
227 case RSA_PKCS1_SHA384:
229 case RSA_PKCS1_SHA512:
231
232 case ECDSA_SHA1:
234 case ECDSA_SHA256:
236 case ECDSA_SHA384:
238 case ECDSA_SHA512:
240
241 case RSA_PSS_SHA256:
242 return AlgorithmIdentifier(OID::from_string("RSA/PSS"), PSS_Params("SHA-256", 32).serialize());
243 case RSA_PSS_SHA384:
244 return AlgorithmIdentifier(OID::from_string("RSA/PSS"), PSS_Params("SHA-384", 48).serialize());
245 case RSA_PSS_SHA512:
246 return AlgorithmIdentifier(OID::from_string("RSA/PSS"), PSS_Params("SHA-512", 64).serialize());
247
248 default:
249 // Note that Ed25519 and Ed448 end up here
250 return AlgorithmIdentifier();
251 }
252}
253
254std::optional<Signature_Format> Signature_Scheme::format() const noexcept {
255 switch(m_code) {
256 case RSA_PKCS1_SHA1:
257 case RSA_PKCS1_SHA256:
258 case RSA_PKCS1_SHA384:
259 case RSA_PKCS1_SHA512:
260 case RSA_PSS_SHA256:
261 case RSA_PSS_SHA384:
262 case RSA_PSS_SHA512:
264
265 case ECDSA_SHA1:
266 case ECDSA_SHA256:
267 case ECDSA_SHA384:
268 case ECDSA_SHA512:
269 case EDDSA_25519:
270 case EDDSA_448:
272
273 default:
274 return std::nullopt;
275 }
276}
277
278bool Signature_Scheme::is_compatible_with(const Protocol_Version& protocol_version) const noexcept {
279 // RFC 8446 4.4.3:
280 // The SHA-1 algorithm MUST NOT be used in any signatures of
281 // CertificateVerify messages.
282 //
283 // Note that Botan enforces that for TLS 1.2 as well.
284 if(hash_function_name() == "SHA-1") {
285 return false;
286 }
287
288 // RFC 8446 4.4.3:
289 // RSA signatures MUST use an RSASSA-PSS algorithm, regardless of whether
290 // RSASSA-PKCS1-v1_5 algorithms appear in "signature_algorithms".
291 //
292 // Note that this is enforced for TLS 1.3 and above only.
293 if(!protocol_version.is_pre_tls_13() && (m_code == RSA_PKCS1_SHA1 || m_code == RSA_PKCS1_SHA256 ||
294 m_code == RSA_PKCS1_SHA384 || m_code == RSA_PKCS1_SHA512)) {
295 return false;
296 }
297
298 return true;
299}
300
301bool Signature_Scheme::is_suitable_for(const Private_Key& private_key) const noexcept {
302 if(algorithm_name() != private_key.algo_name()) {
303 return false;
304 }
305
306 // The ECDSA private key length must match the utilized hash output length.
307 const auto keylen = private_key.key_length();
308 if(keylen <= 250) {
309 return false;
310 }
311
312 if(m_code == ECDSA_SHA256 && !(keylen >= 250 && keylen <= 350)) {
313 return false;
314 }
315
316 if(m_code == ECDSA_SHA384 && !(keylen >= 350 && keylen <= 450)) {
317 return false;
318 }
319
320 if(m_code == ECDSA_SHA512 && !(keylen >= 450 && keylen <= 550)) {
321 return false;
322 }
323
324 return true;
325}
326
327std::vector<AlgorithmIdentifier> to_algorithm_identifiers(const std::vector<Signature_Scheme>& schemes) {
328 std::vector<AlgorithmIdentifier> result;
329 std::transform(schemes.begin(), schemes.end(), std::back_inserter(result), [](const auto& scheme) {
330 return scheme.algorithm_identifier();
331 });
332 return result;
333}
334
335} // namespace Botan::TLS
static EC_Group from_name(std::string_view name)
Definition ec_group.cpp:384
std::vector< uint8_t > DER_encode(EC_Group_Encoding form) const
Definition ec_group.cpp:640
static OID from_string(std::string_view str)
Definition asn1_oid.cpp:86
std::string hash_function_name() const noexcept
bool is_compatible_with(const Protocol_Version &protocol_version) const noexcept
AlgorithmIdentifier key_algorithm_identifier() const noexcept
Signature_Scheme::Code wire_code() const noexcept
AlgorithmIdentifier algorithm_identifier() const noexcept
std::optional< Signature_Format > format() const noexcept
bool is_suitable_for(const Private_Key &private_key) const noexcept
std::string to_string() const noexcept
static const std::vector< Signature_Scheme > & all_available_schemes()
std::string padding_string() const noexcept
std::string algorithm_name() const noexcept
std::vector< AlgorithmIdentifier > to_algorithm_identifiers(const std::vector< Signature_Scheme > &schemes)
bool value_exists(const std::vector< T > &vec, const V &val)
Definition stl_util.h:51