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