/src/boringssl/ssl/ssl_credential.cc
Line | Count | Source |
1 | | // Copyright 2024 The BoringSSL Authors |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #include <openssl/ssl.h> |
16 | | |
17 | | #include <assert.h> |
18 | | |
19 | | #include <openssl/hkdf.h> |
20 | | #include <openssl/span.h> |
21 | | |
22 | | #include "../crypto/internal.h" |
23 | | #include "../crypto/spake2plus/internal.h" |
24 | | #include "internal.h" |
25 | | |
26 | | |
27 | | BSSL_NAMESPACE_BEGIN |
28 | | |
29 | | // new_leafless_chain returns a fresh stack of buffers set to {nullptr}. |
30 | 686 | static UniquePtr<STACK_OF(CRYPTO_BUFFER)> new_leafless_chain() { |
31 | 686 | UniquePtr<STACK_OF(CRYPTO_BUFFER)> chain(sk_CRYPTO_BUFFER_new_null()); |
32 | 686 | if (!chain || !sk_CRYPTO_BUFFER_push(chain.get(), nullptr)) { |
33 | 0 | return nullptr; |
34 | 0 | } |
35 | | |
36 | 686 | return chain; |
37 | 686 | } |
38 | | |
39 | | bool ssl_get_full_credential_list(SSL_HANDSHAKE *hs, |
40 | 23.9k | Array<SSL_CREDENTIAL *> *out) { |
41 | 23.9k | CERT *cert = hs->config->cert.get(); |
42 | | // Finish filling in the legacy credential if needed. |
43 | 23.9k | if (!cert->x509_method->ssl_auto_chain_if_needed(hs)) { |
44 | 0 | return false; |
45 | 0 | } |
46 | | |
47 | 23.9k | size_t num_creds = cert->credentials.size(); |
48 | 23.9k | bool include_legacy = cert->legacy_credential->IsComplete(); |
49 | 23.9k | if (include_legacy) { |
50 | 23.9k | num_creds++; |
51 | 23.9k | } |
52 | | |
53 | 23.9k | if (!out->InitForOverwrite(num_creds)) { |
54 | 0 | return false; |
55 | 0 | } |
56 | | |
57 | 23.9k | for (size_t i = 0; i < cert->credentials.size(); i++) { |
58 | 0 | (*out)[i] = cert->credentials[i].get(); |
59 | 0 | } |
60 | 23.9k | if (include_legacy) { |
61 | 23.9k | (*out)[num_creds - 1] = cert->legacy_credential.get(); |
62 | 23.9k | } |
63 | 23.9k | return true; |
64 | 23.9k | } |
65 | | |
66 | | bool ssl_credential_matches_requested_issuers(SSL_HANDSHAKE *hs, |
67 | 23.4k | const SSL_CREDENTIAL *cred) { |
68 | 23.4k | if (!cred->must_match_issuer) { |
69 | | // This credential does not need to match a requested issuer, so |
70 | | // it is good to use without a match. |
71 | 23.4k | return true; |
72 | 23.4k | } |
73 | | |
74 | | // If we have names sent by the CA extension, and this |
75 | | // credential matches it, it is good. |
76 | 0 | if (hs->ca_names != nullptr) { |
77 | 0 | for (const CRYPTO_BUFFER *ca_name : hs->ca_names.get()) { |
78 | 0 | if (cred->ChainContainsIssuer( |
79 | 0 | Span(CRYPTO_BUFFER_data(ca_name), CRYPTO_BUFFER_len(ca_name)))) { |
80 | 0 | return true; |
81 | 0 | } |
82 | 0 | } |
83 | 0 | } |
84 | | // If the credential has a trust anchor ID and it matches one sent by the |
85 | | // peer, it is good. |
86 | 0 | if (!cred->trust_anchor_id.empty() && hs->peer_requested_trust_anchors) { |
87 | 0 | CBS cbs = CBS(*hs->peer_requested_trust_anchors), candidate; |
88 | 0 | while (CBS_len(&cbs) > 0) { |
89 | 0 | if (!CBS_get_u8_length_prefixed(&cbs, &candidate) || |
90 | 0 | CBS_len(&candidate) == 0) { |
91 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); |
92 | 0 | return false; |
93 | 0 | } |
94 | 0 | if (candidate == Span(cred->trust_anchor_id)) { |
95 | 0 | hs->matched_peer_trust_anchor = true; |
96 | 0 | return true; |
97 | 0 | } |
98 | 0 | } |
99 | 0 | } |
100 | | |
101 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_NO_MATCHING_ISSUER); |
102 | 0 | return false; |
103 | 0 | } |
104 | | |
105 | | BSSL_NAMESPACE_END |
106 | | |
107 | | using namespace bssl; |
108 | | |
109 | | static ExDataClass g_ex_data_class; |
110 | | |
111 | | ssl_credential_st::ssl_credential_st(SSLCredentialType type_arg) |
112 | 235k | : RefCounted(CheckSubClass()), type(type_arg) { |
113 | 235k | CRYPTO_new_ex_data(&ex_data); |
114 | 235k | } |
115 | | |
116 | 234k | ssl_credential_st::~ssl_credential_st() { |
117 | 234k | CRYPTO_free_ex_data(&g_ex_data_class, &ex_data); |
118 | 234k | } |
119 | | |
120 | 115k | static CRYPTO_BUFFER *buffer_up_ref(const CRYPTO_BUFFER *buffer) { |
121 | 115k | CRYPTO_BUFFER_up_ref(const_cast<CRYPTO_BUFFER *>(buffer)); |
122 | 115k | return const_cast<CRYPTO_BUFFER *>(buffer); |
123 | 115k | } |
124 | | |
125 | 115k | UniquePtr<SSL_CREDENTIAL> ssl_credential_st::Dup() const { |
126 | 115k | assert(type == SSLCredentialType::kX509); |
127 | 115k | UniquePtr<SSL_CREDENTIAL> ret = MakeUnique<SSL_CREDENTIAL>(type); |
128 | 115k | if (ret == nullptr) { |
129 | 0 | return nullptr; |
130 | 0 | } |
131 | | |
132 | 115k | ret->pubkey = UpRef(pubkey); |
133 | 115k | ret->privkey = UpRef(privkey); |
134 | 115k | ret->key_method = key_method; |
135 | 115k | if (!ret->sigalgs.CopyFrom(sigalgs)) { |
136 | 0 | return nullptr; |
137 | 0 | } |
138 | | |
139 | 115k | if (chain) { |
140 | 110k | ret->chain.reset(sk_CRYPTO_BUFFER_deep_copy(chain.get(), buffer_up_ref, |
141 | 110k | CRYPTO_BUFFER_free)); |
142 | 110k | if (!ret->chain) { |
143 | 0 | return nullptr; |
144 | 0 | } |
145 | 110k | } |
146 | | |
147 | 115k | ret->dc = UpRef(dc); |
148 | 115k | ret->signed_cert_timestamp_list = UpRef(signed_cert_timestamp_list); |
149 | 115k | ret->ocsp_response = UpRef(ocsp_response); |
150 | 115k | ret->dc_algorithm = dc_algorithm; |
151 | 115k | return ret; |
152 | 115k | } |
153 | | |
154 | 0 | void ssl_credential_st::ClearCertAndKey() { |
155 | 0 | pubkey = nullptr; |
156 | 0 | privkey = nullptr; |
157 | 0 | key_method = nullptr; |
158 | 0 | chain = nullptr; |
159 | 0 | } |
160 | | |
161 | 72.3k | bool ssl_credential_st::UsesX509() const { |
162 | 72.3k | switch (type) { |
163 | 72.3k | case SSLCredentialType::kX509: |
164 | 72.3k | case SSLCredentialType::kDelegated: |
165 | 72.3k | return true; |
166 | 0 | case SSLCredentialType::kSPAKE2PlusV1Client: |
167 | 0 | case SSLCredentialType::kSPAKE2PlusV1Server: |
168 | 0 | case SSLCredentialType::kPreSharedKey: |
169 | 0 | return false; |
170 | 72.3k | } |
171 | 0 | abort(); |
172 | 72.3k | } |
173 | | |
174 | 105k | bool ssl_credential_st::UsesPrivateKey() const { |
175 | 105k | switch (type) { |
176 | 105k | case SSLCredentialType::kX509: |
177 | 105k | case SSLCredentialType::kDelegated: |
178 | 105k | return true; |
179 | 0 | case SSLCredentialType::kSPAKE2PlusV1Client: |
180 | 0 | case SSLCredentialType::kSPAKE2PlusV1Server: |
181 | 0 | case SSLCredentialType::kPreSharedKey: |
182 | 0 | return false; |
183 | 105k | } |
184 | 0 | abort(); |
185 | 105k | } |
186 | | |
187 | 23.9k | bool ssl_credential_st::IsComplete() const { |
188 | | // APIs like |SSL_use_certificate| and |SSL_set1_chain| configure the leaf and |
189 | | // other certificates separately. It is possible for |chain| have a null leaf. |
190 | 23.9k | if (UsesX509() && (sk_CRYPTO_BUFFER_num(chain.get()) == 0 || |
191 | 23.9k | sk_CRYPTO_BUFFER_value(chain.get(), 0) == nullptr)) { |
192 | 0 | return false; |
193 | 0 | } |
194 | | // We must have successfully extracted a public key from the certificate, |
195 | | // delegated credential, etc. |
196 | 23.9k | if (UsesPrivateKey() && pubkey == nullptr) { |
197 | 0 | return false; |
198 | 0 | } |
199 | 23.9k | if (UsesPrivateKey() && privkey == nullptr && key_method == nullptr) { |
200 | 0 | return false; |
201 | 0 | } |
202 | 23.9k | if (type == SSLCredentialType::kDelegated && dc == nullptr) { |
203 | 0 | return false; |
204 | 0 | } |
205 | 23.9k | return true; |
206 | 23.9k | } |
207 | | |
208 | | bool ssl_credential_st::SetLeafCert(UniquePtr<CRYPTO_BUFFER> leaf, |
209 | 12.1k | bool discard_key_on_mismatch) { |
210 | 12.1k | if (!UsesX509()) { |
211 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); |
212 | 0 | return false; |
213 | 0 | } |
214 | | |
215 | 12.1k | const bool private_key_matches_leaf = type != SSLCredentialType::kDelegated; |
216 | | |
217 | 12.1k | CBS cbs; |
218 | 12.1k | CRYPTO_BUFFER_init_CBS(leaf.get(), &cbs); |
219 | 12.1k | UniquePtr<EVP_PKEY> new_pubkey = ssl_cert_parse_pubkey(&cbs); |
220 | 12.1k | if (new_pubkey == nullptr) { |
221 | 0 | return false; |
222 | 0 | } |
223 | | |
224 | 12.1k | if (!ssl_is_key_type_supported(EVP_PKEY_id(new_pubkey.get()))) { |
225 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE); |
226 | 0 | return false; |
227 | 0 | } |
228 | | |
229 | | // An ECC certificate may be usable for ECDH or ECDSA. We only support ECDSA |
230 | | // certificates, so sanity-check the key usage extension. |
231 | 12.1k | if (EVP_PKEY_id(new_pubkey.get()) == EVP_PKEY_EC && |
232 | 0 | !ssl_cert_check_key_usage(&cbs, key_usage_digital_signature)) { |
233 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_CERTIFICATE_TYPE); |
234 | 0 | return false; |
235 | 0 | } |
236 | | |
237 | 12.1k | if (private_key_matches_leaf && privkey != nullptr && |
238 | 7.77k | !ssl_compare_public_and_private_key(new_pubkey.get(), privkey.get())) { |
239 | 0 | if (!discard_key_on_mismatch) { |
240 | 0 | return false; |
241 | 0 | } |
242 | 0 | ERR_clear_error(); |
243 | 0 | privkey = nullptr; |
244 | 0 | } |
245 | | |
246 | 12.1k | if (chain == nullptr) { |
247 | 231 | chain = new_leafless_chain(); |
248 | 231 | if (chain == nullptr) { |
249 | 0 | return false; |
250 | 0 | } |
251 | 231 | } |
252 | | |
253 | 12.1k | CRYPTO_BUFFER_free(sk_CRYPTO_BUFFER_value(chain.get(), 0)); |
254 | 12.1k | sk_CRYPTO_BUFFER_set(chain.get(), 0, leaf.release()); |
255 | 12.1k | if (private_key_matches_leaf) { |
256 | 12.1k | pubkey = std::move(new_pubkey); |
257 | 12.1k | } |
258 | 12.1k | return true; |
259 | 12.1k | } |
260 | | |
261 | 68.0k | void ssl_credential_st::ClearIntermediateCerts() { |
262 | 68.0k | if (chain == nullptr) { |
263 | 2.48k | return; |
264 | 2.48k | } |
265 | | |
266 | 82.2k | while (sk_CRYPTO_BUFFER_num(chain.get()) > 1) { |
267 | 16.6k | CRYPTO_BUFFER_free(sk_CRYPTO_BUFFER_pop(chain.get())); |
268 | 16.6k | } |
269 | 65.6k | } |
270 | | |
271 | 0 | bool ssl_credential_st::ChainContainsIssuer(Span<const uint8_t> dn) const { |
272 | 0 | if (UsesX509()) { |
273 | | // TODO(bbe) This is used for matching a chain by CA name for the CA |
274 | | // extension. If we require a chain to be present, we could remove any |
275 | | // remaining parts of the chain after the found issuer, on the assumption |
276 | | // that the peer sending the CA extension has the issuer in their trust |
277 | | // store and does not need us to waste bytes on the wire. |
278 | 0 | CBS dn_cbs; |
279 | 0 | CBS_init(&dn_cbs, dn.data(), dn.size()); |
280 | 0 | for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(chain.get()); i++) { |
281 | 0 | const CRYPTO_BUFFER *cert = sk_CRYPTO_BUFFER_value(chain.get(), i); |
282 | 0 | CBS cert_cbs; |
283 | 0 | CRYPTO_BUFFER_init_CBS(cert, &cert_cbs); |
284 | 0 | if (ssl_cert_matches_issuer(&cert_cbs, &dn_cbs)) { |
285 | 0 | return true; |
286 | 0 | } |
287 | 0 | } |
288 | 0 | } |
289 | 0 | return false; |
290 | 0 | } |
291 | | |
292 | 0 | bool ssl_credential_st::HasPAKEAttempts() const { |
293 | 0 | return pake_limit.load() != 0; |
294 | 0 | } |
295 | | |
296 | 0 | bool ssl_credential_st::ClaimPAKEAttempt() const { |
297 | 0 | uint32_t current = pake_limit.load(std::memory_order_relaxed); |
298 | 0 | for (;;) { |
299 | 0 | if (current == 0) { |
300 | 0 | return false; |
301 | 0 | } |
302 | 0 | if (pake_limit.compare_exchange_weak(current, current - 1)) { |
303 | 0 | break; |
304 | 0 | } |
305 | 0 | } |
306 | | |
307 | 0 | return true; |
308 | 0 | } |
309 | | |
310 | 0 | void ssl_credential_st::RestorePAKEAttempt() const { |
311 | | // This should not overflow because it will only be paired with |
312 | | // ClaimPAKEAttempt. |
313 | 0 | pake_limit.fetch_add(1); |
314 | 0 | } |
315 | | |
316 | 21.3k | bool ssl_credential_st::AppendIntermediateCert(UniquePtr<CRYPTO_BUFFER> cert) { |
317 | 21.3k | if (!UsesX509()) { |
318 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); |
319 | 0 | return false; |
320 | 0 | } |
321 | | |
322 | 21.3k | if (chain == nullptr) { |
323 | 455 | chain = new_leafless_chain(); |
324 | 455 | if (chain == nullptr) { |
325 | 0 | return false; |
326 | 0 | } |
327 | 455 | } |
328 | | |
329 | 21.3k | return PushToStack(chain.get(), std::move(cert)); |
330 | 21.3k | } |
331 | | |
332 | 0 | SSL_CREDENTIAL *SSL_CREDENTIAL_new_x509() { |
333 | 0 | return New<SSL_CREDENTIAL>(SSLCredentialType::kX509); |
334 | 0 | } |
335 | | |
336 | | SSL_CREDENTIAL *SSL_CREDENTIAL_new_pre_shared_key( |
337 | | const uint8_t *key, size_t key_len, const uint8_t *id, size_t id_len, |
338 | 0 | const EVP_MD *md, const uint8_t *context, size_t context_len) { |
339 | 0 | if (id_len == 0) { |
340 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_IDENTITY_NOT_FOUND); |
341 | 0 | return nullptr; |
342 | 0 | } |
343 | | |
344 | 0 | auto cred = MakeUnique<SSL_CREDENTIAL>(SSLCredentialType::kPreSharedKey); |
345 | 0 | size_t epskx_len; |
346 | 0 | if (cred == nullptr || |
347 | | // Precompute epskx, to avoid recomputing it on every use of the |
348 | | // credential. |
349 | 0 | !cred->epskx.InitForOverwrite(EVP_MD_size(md)) || |
350 | 0 | !HKDF_extract(cred->epskx.data(), &epskx_len, md, key, key_len, |
351 | 0 | /*salt=*/nullptr, /*salt_len=*/0) || |
352 | 0 | !cred->epsk_id.CopyFrom(Span(id, id_len)) || |
353 | 0 | !cred->epsk_context.CopyFrom(Span(context, context_len))) { |
354 | 0 | return nullptr; |
355 | 0 | } |
356 | 0 | BSSL_CHECK(epskx_len == cred->epskx.size()); |
357 | 0 | cred->epsk_md = md; |
358 | 0 | return cred.release(); |
359 | 0 | } |
360 | | |
361 | 0 | SSL_CREDENTIAL *SSL_CREDENTIAL_new_delegated() { |
362 | 0 | return New<SSL_CREDENTIAL>(SSLCredentialType::kDelegated); |
363 | 0 | } |
364 | | |
365 | 23.4k | void SSL_CREDENTIAL_up_ref(SSL_CREDENTIAL *cred) { cred->UpRefInternal(); } |
366 | | |
367 | 258k | void SSL_CREDENTIAL_free(SSL_CREDENTIAL *cred) { |
368 | 258k | if (cred != nullptr) { |
369 | 258k | cred->DecRefInternal(); |
370 | 258k | } |
371 | 258k | } |
372 | | |
373 | 0 | int SSL_CREDENTIAL_is_complete(const SSL_CREDENTIAL *cred) { |
374 | 0 | return cred->IsComplete(); |
375 | 0 | } |
376 | | |
377 | 9.02k | int SSL_CREDENTIAL_set1_private_key(SSL_CREDENTIAL *cred, EVP_PKEY *key) { |
378 | 9.02k | if (!cred->UsesPrivateKey()) { |
379 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); |
380 | 0 | return 0; |
381 | 0 | } |
382 | | |
383 | | // If the public half has been configured, check |key| matches. |pubkey| will |
384 | | // have been extracted from the certificate, delegated credential, etc. |
385 | 9.02k | if (cred->pubkey != nullptr && |
386 | 5.83k | !ssl_compare_public_and_private_key(cred->pubkey.get(), key)) { |
387 | 0 | return false; |
388 | 0 | } |
389 | | |
390 | 9.02k | cred->privkey = UpRef(key); |
391 | 9.02k | cred->key_method = nullptr; |
392 | 9.02k | return 1; |
393 | 9.02k | } |
394 | | |
395 | | int SSL_CREDENTIAL_set_private_key_method( |
396 | 0 | SSL_CREDENTIAL *cred, const SSL_PRIVATE_KEY_METHOD *key_method) { |
397 | 0 | if (!cred->UsesPrivateKey()) { |
398 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); |
399 | 0 | return 0; |
400 | 0 | } |
401 | | |
402 | 0 | cred->privkey = nullptr; |
403 | 0 | cred->key_method = key_method; |
404 | 0 | return 1; |
405 | 0 | } |
406 | | |
407 | | int SSL_CREDENTIAL_set1_cert_chain(SSL_CREDENTIAL *cred, |
408 | | CRYPTO_BUFFER *const *certs, |
409 | 0 | size_t num_certs) { |
410 | 0 | if (!cred->UsesX509() || num_certs == 0) { |
411 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); |
412 | 0 | return 0; |
413 | 0 | } |
414 | | |
415 | 0 | if (!cred->SetLeafCert(UpRef(certs[0]), /*discard_key_on_mismatch=*/false)) { |
416 | 0 | return 0; |
417 | 0 | } |
418 | | |
419 | 0 | cred->ClearIntermediateCerts(); |
420 | 0 | for (size_t i = 1; i < num_certs; i++) { |
421 | 0 | if (!cred->AppendIntermediateCert(UpRef(certs[i]))) { |
422 | 0 | return 0; |
423 | 0 | } |
424 | 0 | } |
425 | | |
426 | 0 | return 1; |
427 | 0 | } |
428 | | |
429 | | int SSL_CREDENTIAL_set1_delegated_credential(SSL_CREDENTIAL *cred, |
430 | 0 | CRYPTO_BUFFER *dc) { |
431 | 0 | if (cred->type != SSLCredentialType::kDelegated) { |
432 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); |
433 | 0 | return 0; |
434 | 0 | } |
435 | | |
436 | | // Parse the delegated credential to check for validity, and extract a few |
437 | | // fields from it. See RFC 9345, section 4. |
438 | 0 | CBS cbs, spki, sig; |
439 | 0 | uint32_t valid_time; |
440 | 0 | uint16_t dc_cert_verify_algorithm, algorithm; |
441 | 0 | CRYPTO_BUFFER_init_CBS(dc, &cbs); |
442 | 0 | if (!CBS_get_u32(&cbs, &valid_time) || |
443 | 0 | !CBS_get_u16(&cbs, &dc_cert_verify_algorithm) || |
444 | 0 | !CBS_get_u24_length_prefixed(&cbs, &spki) || |
445 | 0 | !CBS_get_u16(&cbs, &algorithm) || |
446 | 0 | !CBS_get_u16_length_prefixed(&cbs, &sig) || // |
447 | 0 | CBS_len(&sig) == 0 || // |
448 | 0 | CBS_len(&cbs) != 0) { |
449 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); |
450 | 0 | return 0; |
451 | 0 | } |
452 | | |
453 | | // RFC 9345 forbids algorithms that use the rsaEncryption OID. As the |
454 | | // RSASSA-PSS OID is unusably complicated, this effectively means we will not |
455 | | // support RSA delegated credentials. |
456 | 0 | if (SSL_get_signature_algorithm_key_type(dc_cert_verify_algorithm) == |
457 | 0 | EVP_PKEY_RSA) { |
458 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SIGNATURE_ALGORITHM); |
459 | 0 | return 0; |
460 | 0 | } |
461 | | |
462 | 0 | UniquePtr<EVP_PKEY> pubkey = ssl_parse_peer_subject_public_key_info(spki); |
463 | 0 | if (pubkey == nullptr) { |
464 | 0 | return 0; |
465 | 0 | } |
466 | | |
467 | 0 | if (!cred->sigalgs.CopyFrom(Span(&dc_cert_verify_algorithm, 1))) { |
468 | 0 | return 0; |
469 | 0 | } |
470 | | |
471 | 0 | if (cred->privkey != nullptr && |
472 | 0 | !ssl_compare_public_and_private_key(pubkey.get(), cred->privkey.get())) { |
473 | 0 | return 0; |
474 | 0 | } |
475 | | |
476 | 0 | cred->dc = UpRef(dc); |
477 | 0 | cred->pubkey = std::move(pubkey); |
478 | 0 | cred->dc_algorithm = algorithm; |
479 | 0 | return 1; |
480 | 0 | } |
481 | | |
482 | | int SSL_CREDENTIAL_set1_ocsp_response(SSL_CREDENTIAL *cred, |
483 | 7.94k | CRYPTO_BUFFER *ocsp) { |
484 | 7.94k | if (!cred->UsesX509()) { |
485 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); |
486 | 0 | return 0; |
487 | 0 | } |
488 | | |
489 | 7.94k | cred->ocsp_response = UpRef(ocsp); |
490 | 7.94k | return 1; |
491 | 7.94k | } |
492 | | |
493 | | int SSL_CREDENTIAL_set1_signed_cert_timestamp_list(SSL_CREDENTIAL *cred, |
494 | 3.52k | CRYPTO_BUFFER *sct_list) { |
495 | 3.52k | if (!cred->UsesX509()) { |
496 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); |
497 | 0 | return 0; |
498 | 0 | } |
499 | | |
500 | 3.52k | CBS cbs; |
501 | 3.52k | CRYPTO_BUFFER_init_CBS(sct_list, &cbs); |
502 | 3.52k | if (!ssl_is_sct_list_valid(&cbs)) { |
503 | 2.94k | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SCT_LIST); |
504 | 2.94k | return 0; |
505 | 2.94k | } |
506 | | |
507 | 574 | cred->signed_cert_timestamp_list = UpRef(sct_list); |
508 | 574 | return 1; |
509 | 3.52k | } |
510 | | |
511 | | int SSL_spake2plusv1_register(uint8_t out_w0[32], uint8_t out_w1[32], |
512 | | uint8_t out_registration_record[65], |
513 | | const uint8_t *password, size_t password_len, |
514 | | const uint8_t *client_identity, |
515 | | size_t client_identity_len, |
516 | | const uint8_t *server_identity, |
517 | 0 | size_t server_identity_len) { |
518 | 0 | return spake2plus::Register( |
519 | 0 | Span(out_w0, 32), Span(out_w1, 32), Span(out_registration_record, 65), |
520 | 0 | Span(password, password_len), Span(client_identity, client_identity_len), |
521 | 0 | Span(server_identity, server_identity_len)); |
522 | 0 | } |
523 | | |
524 | | static UniquePtr<SSL_CREDENTIAL> ssl_credential_new_spake2plusv1( |
525 | | SSLCredentialType type, Span<const uint8_t> context, |
526 | | Span<const uint8_t> client_identity, Span<const uint8_t> server_identity, |
527 | 0 | uint32_t limit) { |
528 | 0 | assert(type == SSLCredentialType::kSPAKE2PlusV1Client || |
529 | 0 | type == SSLCredentialType::kSPAKE2PlusV1Server); |
530 | 0 | auto cred = MakeUnique<SSL_CREDENTIAL>(type); |
531 | 0 | if (cred == nullptr) { |
532 | 0 | return nullptr; |
533 | 0 | } |
534 | | |
535 | 0 | if (!cred->pake_context.CopyFrom(context) || |
536 | 0 | !cred->client_identity.CopyFrom(client_identity) || |
537 | 0 | !cred->server_identity.CopyFrom(server_identity)) { |
538 | 0 | return nullptr; |
539 | 0 | } |
540 | | |
541 | 0 | cred->pake_limit.store(limit); |
542 | 0 | return cred; |
543 | 0 | } |
544 | | |
545 | | SSL_CREDENTIAL *SSL_CREDENTIAL_new_spake2plusv1_client( |
546 | | const uint8_t *context, size_t context_len, const uint8_t *client_identity, |
547 | | size_t client_identity_len, const uint8_t *server_identity, |
548 | | size_t server_identity_len, uint32_t error_limit, const uint8_t *w0, |
549 | 0 | size_t w0_len, const uint8_t *w1, size_t w1_len) { |
550 | 0 | if (w0_len != spake2plus::kVerifierSize || |
551 | 0 | w1_len != spake2plus::kVerifierSize || |
552 | 0 | (context == nullptr && context_len != 0)) { |
553 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SPAKE2PLUSV1_VALUE); |
554 | 0 | return nullptr; |
555 | 0 | } |
556 | | |
557 | 0 | UniquePtr<SSL_CREDENTIAL> cred = ssl_credential_new_spake2plusv1( |
558 | 0 | SSLCredentialType::kSPAKE2PlusV1Client, Span(context, context_len), |
559 | 0 | Span(client_identity, client_identity_len), |
560 | 0 | Span(server_identity, server_identity_len), error_limit); |
561 | 0 | if (!cred) { |
562 | 0 | return nullptr; |
563 | 0 | } |
564 | | |
565 | 0 | if (!cred->password_verifier_w0.CopyFrom(Span(w0, w0_len)) || |
566 | 0 | !cred->password_verifier_w1.CopyFrom(Span(w1, w1_len))) { |
567 | 0 | return nullptr; |
568 | 0 | } |
569 | | |
570 | 0 | return cred.release(); |
571 | 0 | } |
572 | | |
573 | | SSL_CREDENTIAL *SSL_CREDENTIAL_new_spake2plusv1_server( |
574 | | const uint8_t *context, size_t context_len, const uint8_t *client_identity, |
575 | | size_t client_identity_len, const uint8_t *server_identity, |
576 | | size_t server_identity_len, uint32_t rate_limit, const uint8_t *w0, |
577 | | size_t w0_len, const uint8_t *registration_record, |
578 | 0 | size_t registration_record_len) { |
579 | 0 | if (w0_len != spake2plus::kVerifierSize || |
580 | 0 | registration_record_len != spake2plus::kRegistrationRecordSize || |
581 | 0 | (context == nullptr && context_len != 0)) { |
582 | 0 | return nullptr; |
583 | 0 | } |
584 | | |
585 | 0 | UniquePtr<SSL_CREDENTIAL> cred = ssl_credential_new_spake2plusv1( |
586 | 0 | SSLCredentialType::kSPAKE2PlusV1Server, Span(context, context_len), |
587 | 0 | Span(client_identity, client_identity_len), |
588 | 0 | Span(server_identity, server_identity_len), rate_limit); |
589 | 0 | if (!cred) { |
590 | 0 | return nullptr; |
591 | 0 | } |
592 | | |
593 | 0 | if (!cred->password_verifier_w0.CopyFrom(Span(w0, w0_len)) || |
594 | 0 | !cred->registration_record.CopyFrom( |
595 | 0 | Span(registration_record, registration_record_len))) { |
596 | 0 | return nullptr; |
597 | 0 | } |
598 | | |
599 | 0 | return cred.release(); |
600 | 0 | } |
601 | | |
602 | 0 | int SSL_CTX_add1_credential(SSL_CTX *ctx, SSL_CREDENTIAL *cred) { |
603 | 0 | if (!cred->IsComplete()) { |
604 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); |
605 | 0 | return 0; |
606 | 0 | } |
607 | 0 | return ctx->cert->credentials.Push(UpRef(cred)); |
608 | 0 | } |
609 | | |
610 | 0 | int SSL_add1_credential(SSL *ssl, SSL_CREDENTIAL *cred) { |
611 | 0 | if (ssl->config == nullptr) { |
612 | 0 | return 0; |
613 | 0 | } |
614 | | |
615 | 0 | if (!cred->IsComplete()) { |
616 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); |
617 | 0 | return 0; |
618 | 0 | } |
619 | 0 | return ssl->config->cert->credentials.Push(UpRef(cred)); |
620 | 0 | } |
621 | | |
622 | 0 | const SSL_CREDENTIAL *SSL_get0_selected_credential(const SSL *ssl) { |
623 | 0 | if (ssl->s3->hs == nullptr) { |
624 | 0 | return nullptr; |
625 | 0 | } |
626 | 0 | return ssl->s3->hs->credential.get(); |
627 | 0 | } |
628 | | |
629 | | int SSL_CREDENTIAL_get_ex_new_index(long argl, void *argp, |
630 | | CRYPTO_EX_unused *unused, |
631 | | CRYPTO_EX_dup *dup_unused, |
632 | 0 | CRYPTO_EX_free *free_func) { |
633 | 0 | return CRYPTO_get_ex_new_index_ex(&g_ex_data_class, argl, argp, free_func); |
634 | 0 | } |
635 | | |
636 | 0 | int SSL_CREDENTIAL_set_ex_data(SSL_CREDENTIAL *cred, int idx, void *arg) { |
637 | 0 | return CRYPTO_set_ex_data(&cred->ex_data, idx, arg); |
638 | 0 | } |
639 | | |
640 | 0 | void *SSL_CREDENTIAL_get_ex_data(const SSL_CREDENTIAL *cred, int idx) { |
641 | 0 | return CRYPTO_get_ex_data(&cred->ex_data, idx); |
642 | 0 | } |
643 | | |
644 | 0 | void SSL_CREDENTIAL_set_must_match_issuer(SSL_CREDENTIAL *cred, int match) { |
645 | 0 | cred->must_match_issuer = !!match; |
646 | 0 | } |
647 | | |
648 | | int SSL_CREDENTIAL_set1_trust_anchor_id(SSL_CREDENTIAL *cred, const uint8_t *id, |
649 | 0 | size_t id_len) { |
650 | | // For now, this is only valid for X.509. |
651 | 0 | if (!cred->UsesX509()) { |
652 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); |
653 | 0 | return 0; |
654 | 0 | } |
655 | | |
656 | 0 | if (!cred->trust_anchor_id.CopyFrom(Span(id, id_len))) { |
657 | 0 | OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); |
658 | 0 | return 0; |
659 | 0 | } |
660 | | |
661 | 0 | return 1; |
662 | 0 | } |
663 | | |
664 | | int SSL_CREDENTIAL_set1_certificate_properties( |
665 | 0 | SSL_CREDENTIAL *cred, CRYPTO_BUFFER *cert_property_list) { |
666 | 0 | std::optional<CBS> trust_anchor; |
667 | 0 | CBS cbs, cpl; |
668 | 0 | CRYPTO_BUFFER_init_CBS(cert_property_list, &cbs); |
669 | |
|
670 | 0 | if (!CBS_get_u16_length_prefixed(&cbs, &cpl)) { |
671 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_CERTIFICATE_PROPERTY_LIST); |
672 | 0 | return 0; |
673 | 0 | } |
674 | 0 | while (CBS_len(&cpl) != 0) { |
675 | 0 | uint16_t cp_type; |
676 | 0 | CBS cp_data; |
677 | 0 | if (!CBS_get_u16(&cpl, &cp_type) || |
678 | 0 | !CBS_get_u16_length_prefixed(&cpl, &cp_data)) { |
679 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_CERTIFICATE_PROPERTY_LIST); |
680 | 0 | return 0; |
681 | 0 | } |
682 | 0 | switch (cp_type) { |
683 | 0 | case 0: // trust anchor identifier. |
684 | 0 | if (trust_anchor.has_value()) { |
685 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_CERTIFICATE_PROPERTY_LIST); |
686 | 0 | return 0; |
687 | 0 | } |
688 | 0 | trust_anchor = cp_data; |
689 | 0 | break; |
690 | 0 | default: |
691 | 0 | break; |
692 | 0 | } |
693 | 0 | } |
694 | 0 | if (CBS_len(&cbs) != 0) { |
695 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_CERTIFICATE_PROPERTY_LIST); |
696 | 0 | return 0; |
697 | 0 | } |
698 | | // Certificate property list has parsed correctly. |
699 | | |
700 | | // We do not currently retain |cert_property_list|, but if we define another |
701 | | // property with larger fields (e.g. stapled SCTs), it may make sense for |
702 | | // those fields to retain |cert_property_list| and alias into it. |
703 | 0 | if (trust_anchor.has_value()) { |
704 | 0 | if (!CBS_len(&trust_anchor.value())) { |
705 | 0 | OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_TRUST_ANCHOR_LIST); |
706 | 0 | return 0; |
707 | 0 | } |
708 | 0 | if (!SSL_CREDENTIAL_set1_trust_anchor_id(cred, |
709 | 0 | CBS_data(&trust_anchor.value()), |
710 | 0 | CBS_len(&trust_anchor.value()))) { |
711 | 0 | return 0; |
712 | 0 | } |
713 | 0 | } |
714 | 0 | return 1; |
715 | 0 | } |