Flutter Engine
The Flutter Engine
security_context.cc
Go to the documentation of this file.
1// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#if !defined(DART_IO_SECURE_SOCKET_DISABLED)
6
8
9#include <openssl/bio.h>
10#include <openssl/err.h>
11#include <openssl/pkcs12.h>
12#include <openssl/ssl.h>
13#include <openssl/x509.h>
14
15#include "platform/globals.h"
16
17#include "bin/directory.h"
18#include "bin/file.h"
21#include "platform/syslog.h"
22
23// Return the error from the containing function if handle is an error handle.
24#define RETURN_IF_ERROR(handle) \
25 { \
26 Dart_Handle __handle = handle; \
27 if (Dart_IsError((__handle))) { \
28 return __handle; \
29 } \
30 }
31
32namespace dart {
33namespace bin {
34
35const char* SSLCertContext::root_certs_file_ = nullptr;
36const char* SSLCertContext::root_certs_cache_ = nullptr;
37bool SSLCertContext::long_ssl_cert_evaluation_ = false;
38bool SSLCertContext::bypass_trusting_system_roots_ = false;
39
41 X509_STORE_CTX* store_ctx) {
42 if (preverify_ok == 1) {
43 return 1;
44 }
46 if (isolate == nullptr) {
47 FATAL("CertificateCallback called with no current isolate\n");
48 }
49 X509* certificate = X509_STORE_CTX_get_current_cert(store_ctx);
50 int ssl_index = SSL_get_ex_data_X509_STORE_CTX_idx();
51 SSL* ssl =
52 static_cast<SSL*>(X509_STORE_CTX_get_ex_data(store_ctx, ssl_index));
53 SSLFilter* filter = static_cast<SSLFilter*>(
54 SSL_get_ex_data(ssl, SSLFilter::filter_ssl_index));
56 if (Dart_IsNull(callback)) {
57 return 0;
58 }
59
60 // Upref since the Dart X509 object may outlive the SecurityContext.
61 if (certificate != nullptr) {
62 X509_up_ref(certificate);
63 }
66 if (Dart_IsError(args[0])) {
67 filter->callback_error = args[0];
68 return 0;
69 }
73 "HandshakeException",
74 "BadCertificateCallback returned a value that was not a boolean",
75 Dart_Null()));
76 }
77 // See SSLFilter::Handshake for the semantics of filter->callback_error.
78 if (Dart_IsError(result) && filter->callback_error == nullptr) {
79 filter->callback_error = result;
80 return 0;
81 }
82 return static_cast<int>(DartUtils::GetBooleanValue(result));
83}
84
85void SSLCertContext::KeyLogCallback(const SSL* ssl, const char* line) {
86 SSLFilter* filter = static_cast<SSLFilter*>(
87 SSL_get_ex_data(ssl, SSLFilter::filter_ssl_index));
88
89 Dart_Port port = filter->key_log_port();
90 if (port != ILLEGAL_PORT) {
92 }
93}
94
98 ASSERT(Dart_IsInstance(dart_this));
101 reinterpret_cast<intptr_t*>(&context)));
102 if (context == nullptr) {
104 DartUtils::NewInternalError("No native peer")));
105 }
106 return context;
107}
108
109static void DeleteSecurityContext(void* isolate_data, void* context_pointer) {
110 SSLCertContext* context = static_cast<SSLCertContext*>(context_pointer);
111 context->Release();
112}
113
115 SSLCertContext* context) {
117 RETURN_IF_ERROR(dart_this);
118 ASSERT(Dart_IsInstance(dart_this));
121 reinterpret_cast<intptr_t>(context));
122 RETURN_IF_ERROR(err);
123 Dart_NewFinalizableHandle(dart_this, context,
126 return Dart_Null();
127}
128
129static void ReleaseCertificate(void* isolate_data, void* context_pointer) {
130 X509* cert = reinterpret_cast<X509*>(context_pointer);
131 X509_free(cert);
132}
133
134static intptr_t EstimateX509Size(X509* certificate) {
135 intptr_t length = i2d_X509(certificate, nullptr);
136 length = length > 0 ? length : 0;
137 // An X509 is a tree of structures, which are either opaque or will be opaque
138 // in the future. Estimate the overhead to 512 bytes by rounding up
139 // sizeof(X509) + sizeof(X509_CINF).
140 return length + 512;
141}
142
143// Returns the handle for a Dart object wrapping the X509 certificate object.
144// The caller should own a reference to the X509 object whose reference count
145// won't drop to zero before the ReleaseCertificate finalizer runs.
147 if (certificate == nullptr) {
148 return Dart_Null();
149 }
150 Dart_Handle x509_type =
152 if (Dart_IsError(x509_type)) {
153 X509_free(certificate);
154 return x509_type;
155 }
156 Dart_Handle arguments[] = {nullptr};
158 Dart_New(x509_type, DartUtils::NewString("_"), 0, arguments);
159 if (Dart_IsError(result)) {
160 X509_free(certificate);
161 return result;
162 }
164 Dart_Handle status =
166 reinterpret_cast<intptr_t>(certificate));
167 if (Dart_IsError(status)) {
168 X509_free(certificate);
169 return status;
170 }
171 const intptr_t approximate_size_of_certificate =
172 EstimateX509Size(certificate);
173 ASSERT(approximate_size_of_certificate > 0);
174 Dart_NewFinalizableHandle(result, reinterpret_cast<void*>(certificate),
175 approximate_size_of_certificate,
177 return result;
178}
179
180static int SetTrustedCertificatesBytesPKCS12(SSL_CTX* context,
181 ScopedMemBIO* bio,
182 const char* password) {
183 CBS cbs;
184 CBS_init(&cbs, bio->data(), bio->length());
185
186 EVP_PKEY* key = nullptr;
187 ScopedX509Stack cert_stack(sk_X509_new_null());
188 int status = PKCS12_get_key_and_certs(&key, cert_stack.get(), &cbs, password);
189 if (status == 0) {
190 return status;
191 }
192
193 X509_STORE* store = SSL_CTX_get_cert_store(context);
194 X509* ca;
195 while ((ca = sk_X509_shift(cert_stack.get())) != nullptr) {
196 status = X509_STORE_add_cert(store, ca);
197 // X509_STORE_add_cert increments the reference count of cert on success.
198 X509_free(ca);
199 if (status == 0) {
200 return status;
201 }
202 }
203
204 return status;
205}
206
207static int SetTrustedCertificatesBytesPEM(SSL_CTX* context, BIO* bio) {
208 X509_STORE* store = SSL_CTX_get_cert_store(context);
209
210 int status = 0;
211 X509* cert = nullptr;
212 while ((cert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr)) !=
213 nullptr) {
214 status = X509_STORE_add_cert(store, cert);
215 // X509_STORE_add_cert increments the reference count of cert on success.
216 X509_free(cert);
217 if (status == 0) {
218 return status;
219 }
220 }
221
222 // If no PEM start line is found, it means that we read to the end of the
223 // file, or that the file isn't PEM. In the first case, status will be
224 // non-zero indicating success. In the second case, status will be 0,
225 // indicating that we should try to read as PKCS12. If there is some other
226 // error, we return it up to the caller.
227 return SecureSocketUtils::NoPEMStartLine() ? status : 0;
228}
229
231 const char* password) {
232 int status = 0;
233 {
234 ScopedMemBIO bio(cert_bytes);
235 status = SetTrustedCertificatesBytesPEM(context(), bio.bio());
236 if (status == 0) {
238 ERR_clear_error();
239 BIO_reset(bio.bio());
240 status = SetTrustedCertificatesBytesPKCS12(context(), &bio, password);
241 }
242 } else {
243 // The PEM file was successfully parsed.
244 ERR_clear_error();
245 }
246 }
247 SecureSocketUtils::CheckStatus(status, "TlsException",
248 "Failure trusting builtin roots");
249}
250
251static int SetClientAuthoritiesPKCS12(SSL_CTX* context,
252 ScopedMemBIO* bio,
253 const char* password) {
254 CBS cbs;
255 CBS_init(&cbs, bio->data(), bio->length());
256
257 EVP_PKEY* key = nullptr;
258 ScopedX509Stack cert_stack(sk_X509_new_null());
259 int status = PKCS12_get_key_and_certs(&key, cert_stack.get(), &cbs, password);
260 if (status == 0) {
261 return status;
262 }
263
264 X509* ca;
265 while ((ca = sk_X509_shift(cert_stack.get())) != nullptr) {
266 status = SSL_CTX_add_client_CA(context, ca);
267 // SSL_CTX_add_client_CA increments the reference count of ca on success.
268 X509_free(ca); // The name has been extracted.
269 if (status == 0) {
270 return status;
271 }
272 }
273
274 return status;
275}
276
277static int SetClientAuthoritiesPEM(SSL_CTX* context, BIO* bio) {
278 int status = 0;
279 X509* cert = nullptr;
280 while ((cert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr)) !=
281 nullptr) {
282 status = SSL_CTX_add_client_CA(context, cert);
283 X509_free(cert); // The name has been extracted.
284 if (status == 0) {
285 return status;
286 }
287 }
288 return SecureSocketUtils::NoPEMStartLine() ? status : 0;
289}
290
291static int SetClientAuthorities(SSL_CTX* context,
292 ScopedMemBIO* bio,
293 const char* password) {
294 int status = SetClientAuthoritiesPEM(context, bio->bio());
295 if (status == 0) {
297 ERR_clear_error();
298 BIO_reset(bio->bio());
299 status = SetClientAuthoritiesPKCS12(context, bio, password);
300 }
301 } else {
302 // The PEM file was successfully parsed.
303 ERR_clear_error();
304 }
305 return status;
306}
307
309 Dart_Handle client_authorities_bytes,
310 const char* password) {
311 int status;
312 {
313 ScopedMemBIO bio(client_authorities_bytes);
314 status = SetClientAuthorities(context(), &bio, password);
315 }
316
317 SecureSocketUtils::CheckStatus(status, "TlsException",
318 "Failure in setClientAuthoritiesBytes");
319}
320
321void SSLCertContext::LoadRootCertFile(const char* file) {
322 if (SSL_LOG_STATUS) {
323 Syslog::Print("Looking for trusted roots in %s\n", file);
324 }
325 if (!File::Exists(nullptr, file)) {
327 -1, "TlsException", "Failed to find root cert file", nullptr);
328 }
329 int status = SSL_CTX_load_verify_locations(context(), file, nullptr);
330 SecureSocketUtils::CheckStatus(status, "TlsException",
331 "Failure trusting builtin roots");
332 if (SSL_LOG_STATUS) {
333 Syslog::Print("Trusting roots from: %s\n", file);
334 }
335}
336
337void SSLCertContext::AddCompiledInCerts() {
338 if (root_certificates_pem == nullptr) {
339 if (SSL_LOG_STATUS) {
340 Syslog::Print("Missing compiled-in roots\n");
341 }
342 return;
343 }
344 X509_STORE* store = SSL_CTX_get_cert_store(context());
345 BIO* roots_bio =
346 BIO_new_mem_buf(const_cast<unsigned char*>(root_certificates_pem),
348 X509* root_cert;
349 // PEM_read_bio_X509 reads PEM-encoded certificates from a bio (in our case,
350 // backed by a memory buffer), and returns X509 objects, one by one.
351 // When the end of the bio is reached, it returns null.
352 while ((root_cert = PEM_read_bio_X509(roots_bio, nullptr, nullptr,
353 nullptr)) != nullptr) {
354 int status = X509_STORE_add_cert(store, root_cert);
355 // X509_STORE_add_cert increments the reference count of cert on success.
356 X509_free(root_cert);
357 if (status == 0) {
358 break;
359 }
360 }
361 BIO_free(roots_bio);
362 // If there is an error here, it must be the error indicating that we are done
363 // reading PEM certificates.
364 ASSERT((ERR_peek_error() == 0) || SecureSocketUtils::NoPEMStartLine());
365 ERR_clear_error();
366}
367
368void SSLCertContext::LoadRootCertCache(const char* cache) {
369 if (SSL_LOG_STATUS) {
370 Syslog::Print("Looking for trusted roots in %s\n", cache);
371 }
372 if (Directory::Exists(nullptr, cache) != Directory::EXISTS) {
374 -1, "TlsException", "Failed to find root cert cache", nullptr);
375 }
376 int status = SSL_CTX_load_verify_locations(context(), nullptr, cache);
377 SecureSocketUtils::CheckStatus(status, "TlsException",
378 "Failure trusting builtin roots");
379 if (SSL_LOG_STATUS) {
380 Syslog::Print("Trusting roots from: %s\n", cache);
381 }
382}
383
384int PasswordCallback(char* buf, int size, int rwflag, void* userdata) {
385 char* password = static_cast<char*>(userdata);
386 ASSERT(size == PEM_BUFSIZE);
387 strncpy(buf, password, size);
388 return strlen(password);
389}
390
391static EVP_PKEY* GetPrivateKeyPKCS12(BIO* bio, const char* password) {
392 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, nullptr));
393 if (p12.get() == nullptr) {
394 return nullptr;
395 }
396
397 EVP_PKEY* key = nullptr;
398 X509* cert = nullptr;
399 STACK_OF(X509)* ca_certs = nullptr;
400 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs);
401 if (status == 0) {
402 return nullptr;
403 }
404
405 // We only care about the private key.
406 ScopedX509 delete_cert(cert);
407 ScopedX509Stack delete_ca_certs(ca_certs);
408 return key;
409}
410
411static EVP_PKEY* GetPrivateKey(BIO* bio, const char* password) {
412 EVP_PKEY* key = PEM_read_bio_PrivateKey(bio, nullptr, PasswordCallback,
413 const_cast<char*>(password));
414 if (key == nullptr) {
415 // We try reading data as PKCS12 only if reading as PEM was unsuccessful and
416 // if there is no indication that the data is malformed PEM. We assume the
417 // data is malformed PEM if it contains the start line, i.e. a line
418 // with ----- BEGIN.
420 // Reset the bio, and clear the error from trying to read as PEM.
421 ERR_clear_error();
422 BIO_reset(bio);
423
424 // Try to decode as PKCS12.
425 key = GetPrivateKeyPKCS12(bio, password);
426 }
427 }
428 return key;
429}
430
432 intptr_t index) {
433 Dart_Handle password_object =
435 const char* password = nullptr;
436 if (Dart_IsString(password_object)) {
437 ThrowIfError(Dart_StringToCString(password_object, &password));
438 if (strlen(password) > PEM_BUFSIZE - 1) {
440 "Password length is greater than 1023 (PEM_BUFSIZE)"));
441 }
442 } else if (Dart_IsNull(password_object)) {
443 password = "";
444 } else {
446 DartUtils::NewDartArgumentError("Password is not a String or null"));
447 }
448 return password;
449}
450
451int AlpnCallback(SSL* ssl,
452 const uint8_t** out,
453 uint8_t* outlen,
454 const uint8_t* in,
455 unsigned int inlen,
456 void* arg) {
457 // 'in' and 'arg' are sequences of (length, data) strings with 1-byte lengths.
458 // 'arg' is 0-terminated. Finds the first string in 'arg' that is in 'in'.
459 uint8_t* server_list = static_cast<uint8_t*>(arg);
460 while (*server_list != 0) {
461 uint8_t protocol_length = *server_list++;
462 const uint8_t* client_list = in;
463 while (client_list < in + inlen) {
464 uint8_t client_protocol_length = *client_list++;
465 if (client_protocol_length == protocol_length) {
466 if (0 == memcmp(server_list, client_list, protocol_length)) {
467 *out = client_list;
468 *outlen = client_protocol_length;
469 return SSL_TLSEXT_ERR_OK; // Success
470 }
471 }
472 client_list += client_protocol_length;
473 }
474 server_list += protocol_length;
475 }
476 // TODO(23580): Make failure send a fatal alert instead of ignoring ALPN.
477 return SSL_TLSEXT_ERR_NOACK;
478}
479
480// Sets the protocol list for ALPN on a SSL object or a context.
482 SSL* ssl,
483 SSLCertContext* context,
484 bool is_server) {
485 // Enable ALPN (application layer protocol negotiation) if the caller provides
486 // a valid list of supported protocols.
487 Dart_TypedData_Type protocols_type;
488 uint8_t* protocol_string = nullptr;
489 uint8_t* protocol_string_copy = nullptr;
490 intptr_t protocol_string_len = 0;
491 int status;
492
494 protocols_handle, &protocols_type,
495 reinterpret_cast<void**>(&protocol_string), &protocol_string_len);
496 if (Dart_IsError(result)) {
498 }
499
500 if (protocols_type != Dart_TypedData_kUint8) {
501 Dart_TypedDataReleaseData(protocols_handle);
503 "Unexpected type for protocols (expected valid Uint8List)."));
504 }
505
506 if (protocol_string_len > 0) {
507 if (is_server) {
508 // ALPN on server connections must be set on an SSL_CTX object,
509 // not on the SSL object of the individual connection.
510 ASSERT(context != nullptr);
511 ASSERT(ssl == nullptr);
512 // Because it must be passed as a single void*, terminate
513 // the list of (length, data) strings with a length 0 string.
514 protocol_string_copy =
515 static_cast<uint8_t*>(malloc(protocol_string_len + 1));
516 memmove(protocol_string_copy, protocol_string, protocol_string_len);
517 protocol_string_copy[protocol_string_len] = '\0';
518 SSL_CTX_set_alpn_select_cb(context->context(), AlpnCallback,
519 protocol_string_copy);
520 context->set_alpn_protocol_string(protocol_string_copy);
521 } else {
522 // The function makes a local copy of protocol_string, which it owns.
523 if (ssl != nullptr) {
524 ASSERT(context == nullptr);
525 status = SSL_set_alpn_protos(ssl, protocol_string, protocol_string_len);
526 } else {
527 ASSERT(context != nullptr);
528 ASSERT(ssl == nullptr);
529 status = SSL_CTX_set_alpn_protos(context->context(), protocol_string,
530 protocol_string_len);
531 }
532 ASSERT(status == 0); // The function returns a non-standard status.
533 }
534 }
535 Dart_TypedDataReleaseData(protocols_handle);
536}
537
538static int UseChainBytesPKCS12(SSL_CTX* context,
539 ScopedMemBIO* bio,
540 const char* password) {
541 CBS cbs;
542 CBS_init(&cbs, bio->data(), bio->length());
543
544 EVP_PKEY* key = nullptr;
545 ScopedX509Stack certs(sk_X509_new_null());
546 int status = PKCS12_get_key_and_certs(&key, certs.get(), &cbs, password);
547 if (status == 0) {
548 return status;
549 }
550
551 X509* ca = sk_X509_shift(certs.get());
552 status = SSL_CTX_use_certificate(context, ca);
553 if (ERR_peek_error() != 0) {
554 // Key/certificate mismatch doesn't imply status is 0.
555 status = 0;
556 }
557 X509_free(ca);
558 if (status == 0) {
559 return status;
560 }
561
562 SSL_CTX_clear_chain_certs(context);
563
564 while ((ca = sk_X509_shift(certs.get())) != nullptr) {
565 status = SSL_CTX_add0_chain_cert(context, ca);
566 // SSL_CTX_add0_chain_cert does not inc ref count, so don't free unless the
567 // call fails.
568 if (status == 0) {
569 X509_free(ca);
570 return status;
571 }
572 }
573
574 return status;
575}
576
577static int UseChainBytesPEM(SSL_CTX* context, BIO* bio) {
578 int status = 0;
579 ScopedX509 x509(PEM_read_bio_X509_AUX(bio, nullptr, nullptr, nullptr));
580 if (x509.get() == nullptr) {
581 return 0;
582 }
583
584 status = SSL_CTX_use_certificate(context, x509.get());
585 if (ERR_peek_error() != 0) {
586 // Key/certificate mismatch doesn't imply status is 0.
587 status = 0;
588 }
589 if (status == 0) {
590 return status;
591 }
592
593 SSL_CTX_clear_chain_certs(context);
594
595 X509* ca;
596 while ((ca = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr)) != nullptr) {
597 status = SSL_CTX_add0_chain_cert(context, ca);
598 // SSL_CTX_add0_chain_cert does not inc ref count, so don't free unless the
599 // call fails.
600 if (status == 0) {
601 X509_free(ca);
602 return status;
603 }
604 // Note that we must not free `ca` if it was successfully added to the
605 // chain. We must free the main certificate x509, though since its reference
606 // count is increased by SSL_CTX_use_certificate.
607 }
608
609 return SecureSocketUtils::NoPEMStartLine() ? status : 0;
610}
611
612static int UseChainBytes(SSL_CTX* context,
613 ScopedMemBIO* bio,
614 const char* password) {
615 int status = UseChainBytesPEM(context, bio->bio());
616 if (status == 0) {
618 ERR_clear_error();
619 BIO_reset(bio->bio());
620 status = UseChainBytesPKCS12(context, bio, password);
621 }
622 } else {
623 // The PEM file was successfully read.
624 ERR_clear_error();
625 }
626 return status;
627}
628
630 const char* password) {
631 ScopedMemBIO bio(cert_chain_bytes);
632 return UseChainBytes(context(), &bio, password);
633}
634
636 X509* certificate = nullptr;
638 ASSERT(Dart_IsInstance(dart_this));
641 reinterpret_cast<intptr_t*>(&certificate)));
642 if (certificate == nullptr) {
644 DartUtils::NewInternalError("No native peer")));
645 }
646 return certificate;
647}
648
650 X509* certificate = GetX509Certificate(args);
651 // When the second argument is nullptr, i2d_X509() returns the length of the
652 // DER encoded cert in bytes.
653 intptr_t length = i2d_X509(certificate, nullptr);
655 if (Dart_IsError(cert_handle)) {
656 Dart_PropagateError(cert_handle);
657 }
659 void* dart_cert_bytes = nullptr;
660 Dart_Handle status =
661 Dart_TypedDataAcquireData(cert_handle, &typ, &dart_cert_bytes, &length);
662 if (Dart_IsError(status)) {
663 Dart_PropagateError(status);
664 }
665
666 // When the second argument points to a non-nullptr buffer address,
667 // i2d_X509 fills that buffer with the DER encoded cert data and increments
668 // the buffer pointer.
669 unsigned char* tmp = static_cast<unsigned char*>(dart_cert_bytes);
670 const intptr_t written_length = i2d_X509(certificate, &tmp);
671 ASSERT(written_length <= length);
672 if (written_length < 0) {
673 Dart_TypedDataReleaseData(cert_handle);
675 -1, "TlsException", "Failed to get certificate bytes", nullptr);
676 // SecureSocketUtils::ThrowIOException() does not return.
677 }
678
679 status = Dart_TypedDataReleaseData(cert_handle);
680 if (Dart_IsError(status)) {
681 Dart_PropagateError(status);
682 }
683 return cert_handle;
684}
685
687 X509* certificate = GetX509Certificate(args);
688 BIO* cert_bio = BIO_new(BIO_s_mem());
689 intptr_t status = PEM_write_bio_X509(cert_bio, certificate);
690 if (status == 0) {
691 BIO_free(cert_bio);
693 -1, "TlsException", "Failed to write certificate to PEM", nullptr);
694 // SecureSocketUtils::ThrowIOException() does not return.
695 }
696
697 BUF_MEM* mem = nullptr;
698 BIO_get_mem_ptr(cert_bio, &mem);
700 reinterpret_cast<const uint8_t*>(mem->data), mem->length);
701 BIO_free(cert_bio);
702 if (Dart_IsError(pem_string)) {
703 Dart_PropagateError(pem_string);
704 }
705
706 return pem_string;
707}
708
710 unsigned char sha1_bytes[EVP_MAX_MD_SIZE];
711 X509* certificate = GetX509Certificate(args);
712 const EVP_MD* hash_type = EVP_sha1();
713
714 unsigned int sha1_size;
715 intptr_t status = X509_digest(certificate, hash_type, sha1_bytes, &sha1_size);
716 if (status == 0) {
718 -1, "TlsException", "Failed to compute certificate's sha1", nullptr);
719 // SecureSocketUtils::ThrowIOException() does not return.
720 }
721
722 Dart_Handle sha1_handle = Dart_NewTypedData(Dart_TypedData_kUint8, sha1_size);
723 if (Dart_IsError(sha1_handle)) {
724 Dart_PropagateError(sha1_handle);
725 }
726
728 void* dart_sha1_bytes;
729 intptr_t length;
731 Dart_TypedDataAcquireData(sha1_handle, &typ, &dart_sha1_bytes, &length);
732 if (Dart_IsError(result)) {
734 }
735
736 memmove(dart_sha1_bytes, sha1_bytes, length);
737
738 result = Dart_TypedDataReleaseData(sha1_handle);
739 if (Dart_IsError(result)) {
741 }
742 return sha1_handle;
743}
744
746 X509* certificate = GetX509Certificate(args);
747 X509_NAME* subject = X509_get_subject_name(certificate);
748 char* subject_string = X509_NAME_oneline(subject, nullptr, 0);
749 if (subject_string == nullptr) {
751 "X509.subject failed to find subject's common name."));
752 }
753 Dart_Handle subject_handle = Dart_NewStringFromCString(subject_string);
754 OPENSSL_free(subject_string);
755 return subject_handle;
756}
757
759 X509* certificate = GetX509Certificate(args);
760 X509_NAME* issuer = X509_get_issuer_name(certificate);
761 char* issuer_string = X509_NAME_oneline(issuer, nullptr, 0);
762 if (issuer_string == nullptr) {
764 "X509.issuer failed to find issuer's common name."));
765 }
766 Dart_Handle issuer_handle = Dart_NewStringFromCString(issuer_string);
767 OPENSSL_free(issuer_string);
768 return issuer_handle;
769}
770
771static Dart_Handle ASN1TimeToMilliseconds(ASN1_TIME* aTime) {
772 ASN1_UTCTIME* epoch_start = ASN1_UTCTIME_new();
773 ASN1_UTCTIME_set_string(epoch_start, "700101000000Z");
774 int days;
775 int seconds;
776 int result = ASN1_TIME_diff(&days, &seconds, epoch_start, aTime);
777 ASN1_UTCTIME_free(epoch_start);
778 if (result != 1) {
779 // TODO(whesse): Propagate an error to Dart.
780 Syslog::PrintErr("ASN1Time error %d\n", result);
781 }
782 return Dart_NewInteger((86400LL * days + seconds) * 1000LL);
783}
784
786 X509* certificate = GetX509Certificate(args);
787 ASN1_TIME* not_before = X509_get_notBefore(certificate);
788 return ASN1TimeToMilliseconds(not_before);
789}
790
792 X509* certificate = GetX509Certificate(args);
793 ASN1_TIME* not_after = X509_get_notAfter(certificate);
794 return ASN1TimeToMilliseconds(not_after);
795}
796
800 const char* password = SSLCertContext::GetPasswordArgument(args, 2);
801
802 int status;
803 EVP_PKEY* key;
804 {
806 key = GetPrivateKey(bio.bio(), password);
807 }
808 if (key == nullptr) {
810 "Expected private key, but none was found"));
811 }
812 status = SSL_CTX_use_PrivateKey(context->context(), key);
813 // SSL_CTX_use_PrivateKey increments the reference count of key on success,
814 // so we have to call EVP_PKEY_free on both success and failure.
815 EVP_PKEY_free(key);
816
817 // TODO(24184): Handle different expected errors here - file missing,
818 // incorrect password, file not a PEM, and throw exceptions.
819 // SecureSocketUtils::CheckStatus should also throw an exception in uncaught
820 // cases.
821 SecureSocketUtils::CheckStatus(status, "TlsException",
822 "Failure in usePrivateKeyBytes");
823}
824
827 SSL_CTX* ctx = SSL_CTX_new(TLS_method());
828 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, SSLCertContext::CertificateCallback);
829 SSL_CTX_set_keylog_callback(ctx, SSLCertContext::KeyLogCallback);
830 SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
831 SSL_CTX_set_cipher_list(ctx, "HIGH:MEDIUM");
832 SSLCertContext* context = new SSLCertContext(ctx);
833 Dart_Handle err = SetSecurityContext(args, context);
834 if (Dart_IsError(err)) {
835 delete context;
837 }
838}
839
844 const char* password = SSLCertContext::GetPasswordArgument(args, 2);
845
846 ASSERT(context != nullptr);
847 ASSERT(password != nullptr);
848 context->SetTrustedCertificatesBytes(cert_bytes, password);
849}
850
854 Dart_Handle client_authorities_bytes =
856 const char* password = SSLCertContext::GetPasswordArgument(args, 2);
857
858 ASSERT(context != nullptr);
859 ASSERT(password != nullptr);
860
861 context->SetClientAuthoritiesBytes(client_authorities_bytes, password);
862}
863
867 Dart_Handle cert_chain_bytes = ThrowIfError(Dart_GetNativeArgument(args, 1));
868 const char* password = SSLCertContext::GetPasswordArgument(args, 2);
869
870 ASSERT(context != nullptr);
871 ASSERT(password != nullptr);
872
873 int status = context->UseCertificateChainBytes(cert_chain_bytes, password);
874
875 SecureSocketUtils::CheckStatus(status, "TlsException",
876 "Failure in useCertificateChainBytes");
877}
878
882
883 ASSERT(context != nullptr);
884
885 context->TrustBuiltinRoots();
886}
887
891 Dart_Handle allow_tls_handle = ThrowIfError(Dart_GetNativeArgument(args, 1));
892
893 ASSERT(context != nullptr);
894 ASSERT(allow_tls_handle != nullptr);
895
896 if (!Dart_IsBoolean(allow_tls_handle)) {
898 "Non-boolean argument passed to SetAllowTlsRenegotiation"));
899 }
900 bool allow = DartUtils::GetBooleanValue(allow_tls_handle);
901 context->set_allow_tls_renegotiation(allow);
902}
903
906}
907
910}
911
914}
915
918}
919
922}
923
926}
927
930}
931
935 Dart_Handle protocols_handle = ThrowIfError(Dart_GetNativeArgument(args, 1));
936 Dart_Handle is_server_handle = ThrowIfError(Dart_GetNativeArgument(args, 2));
937 if (Dart_IsBoolean(is_server_handle)) {
938 bool is_server = DartUtils::GetBooleanValue(is_server_handle);
939 SSLCertContext::SetAlpnProtocolList(protocols_handle, nullptr, context,
940 is_server);
941 } else {
943 "Non-boolean is_server argument passed to SetAlpnProtocols"));
944 }
945}
946
947} // namespace bin
948} // namespace dart
949
950#endif // !defined(DART_IO_SECURE_SOCKET_DISABLED)
SI void store(P *ptr, const T &val)
#define FUNCTION_NAME(name)
Definition: builtin.h:19
static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static void Print(const char *format,...) PRINTF_ATTRIBUTE(1
static constexpr const char * kIOLibURL
Definition: dartutils.h:297
static bool GetBooleanValue(Dart_Handle bool_obj)
Definition: dartutils.cc:137
static Dart_Handle NewDartIOException(const char *exception_name, const char *message, Dart_Handle os_error)
Definition: dartutils.cc:758
static bool PostString(Dart_Port port_id, const char *value)
Definition: dartutils.cc:691
static Dart_Handle NewString(const char *str)
Definition: dartutils.h:214
static Dart_Handle NewDartArgumentError(const char *message)
Definition: dartutils.cc:746
static Dart_Handle NewInternalError(const char *message)
Definition: dartutils.cc:781
static Dart_Handle GetDartType(const char *library_url, const char *class_name)
Definition: dartutils.cc:696
static ExistsResult Exists(Namespace *namespc, const char *path)
static bool Exists(Namespace *namespc, const char *path)
static void KeyLogCallback(const SSL *ssl, const char *line)
static SSLCertContext * GetSecurityContext(Dart_NativeArguments args)
SSL_CTX * context() const
static constexpr int kX509NativeFieldIndex
void SetClientAuthoritiesBytes(Dart_Handle client_authorities_bytes, const char *password)
static int CertificateCallback(int preverify_ok, X509_STORE_CTX *store_ctx)
static const char * GetPasswordArgument(Dart_NativeArguments args, intptr_t index)
static const intptr_t kApproximateSize
void set_allow_tls_renegotiation(bool allow)
int UseCertificateChainBytes(Dart_Handle cert_chain_bytes, const char *password)
static void SetAlpnProtocolList(Dart_Handle protocols_handle, SSL *ssl, SSLCertContext *context, bool is_server)
void SetTrustedCertificatesBytes(Dart_Handle cert_bytes, const char *password)
static constexpr int kSecurityContextNativeFieldIndex
Dart_Handle bad_certificate_callback()
static void ThrowIOException(int status, const char *exception_type, const char *message, const SSL *ssl)
static void CheckStatus(int status, const char *type, const char *message)
static Dart_Handle GetSha1(Dart_NativeArguments args)
static Dart_Handle GetDer(Dart_NativeArguments args)
static Dart_Handle GetStartValidity(Dart_NativeArguments args)
static Dart_Handle WrappedX509Certificate(X509 *certificate)
static Dart_Handle GetIssuer(Dart_NativeArguments args)
static Dart_Handle GetPem(Dart_NativeArguments args)
static Dart_Handle GetEndValidity(Dart_NativeArguments args)
static Dart_Handle GetSubject(Dart_NativeArguments args)
#define ILLEGAL_PORT
Definition: dart_api.h:1535
int64_t Dart_Port
Definition: dart_api.h:1525
struct _Dart_Handle * Dart_Handle
Definition: dart_api.h:258
struct _Dart_Isolate * Dart_Isolate
Definition: dart_api.h:88
struct _Dart_NativeArguments * Dart_NativeArguments
Definition: dart_api.h:3019
Dart_TypedData_Type
Definition: dart_api.h:2612
@ Dart_TypedData_kUint8
Definition: dart_api.h:2615
#define ASSERT(E)
#define FATAL(error)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
GAsyncResult * result
size_t length
static int UseChainBytesPEM(SSL_CTX *context, BIO *bio)
static intptr_t EstimateX509Size(X509 *certificate)
void FUNCTION_NAME() SecurityContext_SetTrustedCertificatesBytes(Dart_NativeArguments args)
const bool SSL_LOG_STATUS
static Dart_Handle ThrowIfError(Dart_Handle handle)
Definition: dartutils.h:31
void FUNCTION_NAME() X509_Issuer(Dart_NativeArguments args)
void FUNCTION_NAME() SecurityContext_TrustBuiltinRoots(Dart_NativeArguments args)
static int SetTrustedCertificatesBytesPEM(SSL_CTX *context, BIO *bio)
static int UseChainBytes(SSL_CTX *context, ScopedMemBIO *bio, const char *password)
void FUNCTION_NAME() X509_EndValidity(Dart_NativeArguments args)
void FUNCTION_NAME() SecurityContext_UseCertificateChainBytes(Dart_NativeArguments args)
static EVP_PKEY * GetPrivateKeyPKCS12(BIO *bio, const char *password)
int PasswordCallback(char *buf, int size, int rwflag, void *userdata)
void FUNCTION_NAME() SecurityContext_Allocate(Dart_NativeArguments args)
static Dart_Handle ASN1TimeToMilliseconds(ASN1_TIME *aTime)
static Dart_Handle SetSecurityContext(Dart_NativeArguments args, SSLCertContext *context)
static void ReleaseCertificate(void *isolate_data, void *context_pointer)
static int SetClientAuthorities(SSL_CTX *context, ScopedMemBIO *bio, const char *password)
void FUNCTION_NAME() SecurityContext_UsePrivateKeyBytes(Dart_NativeArguments args)
void FUNCTION_NAME() X509_Der(Dart_NativeArguments args)
const unsigned char * root_certificates_pem
static void DeleteSecurityContext(void *isolate_data, void *context_pointer)
static X509 * GetX509Certificate(Dart_NativeArguments args)
void FUNCTION_NAME() X509_Subject(Dart_NativeArguments args)
void FUNCTION_NAME() SecurityContext_SetAlpnProtocols(Dart_NativeArguments args)
unsigned int root_certificates_pem_length
static EVP_PKEY * GetPrivateKey(BIO *bio, const char *password)
static int SetClientAuthoritiesPEM(SSL_CTX *context, BIO *bio)
void FUNCTION_NAME() X509_Pem(Dart_NativeArguments args)
static int UseChainBytesPKCS12(SSL_CTX *context, ScopedMemBIO *bio, const char *password)
void FUNCTION_NAME() SecurityContext_SetAllowTlsRenegotiation(Dart_NativeArguments args)
void FUNCTION_NAME() X509_StartValidity(Dart_NativeArguments args)
static int SetClientAuthoritiesPKCS12(SSL_CTX *context, ScopedMemBIO *bio, const char *password)
void FUNCTION_NAME() SecurityContext_SetClientAuthoritiesBytes(Dart_NativeArguments args)
static int SetTrustedCertificatesBytesPKCS12(SSL_CTX *context, ScopedMemBIO *bio, const char *password)
int AlpnCallback(SSL *ssl, const uint8_t **out, uint8_t *outlen, const uint8_t *in, unsigned int inlen, void *arg)
void FUNCTION_NAME() X509_Sha1(Dart_NativeArguments args)
Definition: dart_vm.cc:33
DART_EXPORT bool Dart_IsInstance(Dart_Handle object)
DART_EXPORT bool Dart_IsBoolean(Dart_Handle object)
DART_EXPORT Dart_Handle Dart_GetNativeInstanceField(Dart_Handle obj, int index, intptr_t *value)
void * malloc(size_t size)
Definition: allocation.cc:19
DART_EXPORT Dart_Handle Dart_NewUnhandledExceptionError(Dart_Handle exception)
DART_EXPORT Dart_Handle Dart_NewInteger(int64_t value)
DART_EXPORT Dart_Handle Dart_NewStringFromUTF8(const uint8_t *utf8_array, intptr_t length)
DART_EXPORT void Dart_PropagateError(Dart_Handle handle)
DART_EXPORT Dart_FinalizableHandle Dart_NewFinalizableHandle(Dart_Handle object, void *peer, intptr_t external_allocation_size, Dart_HandleFinalizer callback)
DART_EXPORT Dart_Handle Dart_NewTypedData(Dart_TypedData_Type type, intptr_t length)
DART_EXPORT void Dart_SetReturnValue(Dart_NativeArguments args, Dart_Handle retval)
DART_EXPORT Dart_Handle Dart_TypedDataAcquireData(Dart_Handle object, Dart_TypedData_Type *type, void **data, intptr_t *len)
DART_EXPORT Dart_Isolate Dart_CurrentIsolate()
DART_EXPORT bool Dart_IsError(Dart_Handle handle)
DART_EXPORT Dart_Handle Dart_SetNativeInstanceField(Dart_Handle obj, int index, intptr_t value)
DART_EXPORT Dart_Handle Dart_GetNativeArgument(Dart_NativeArguments args, int index)
DART_EXPORT Dart_Handle Dart_InvokeClosure(Dart_Handle closure, int number_of_arguments, Dart_Handle *arguments)
DART_EXPORT Dart_Handle Dart_TypedDataReleaseData(Dart_Handle object)
DART_EXPORT Dart_Handle Dart_NewApiError(const char *error)
DART_EXPORT Dart_Handle Dart_ThrowException(Dart_Handle exception)
DART_EXPORT bool Dart_IsNull(Dart_Handle object)
DART_EXPORT Dart_Handle Dart_Null()
DART_EXPORT bool Dart_IsString(Dart_Handle object)
DART_EXPORT Dart_Handle Dart_New(Dart_Handle type, Dart_Handle constructor_name, int number_of_arguments, Dart_Handle *arguments)
DART_EXPORT Dart_Handle Dart_StringToCString(Dart_Handle object, const char **cstr)
DART_EXPORT Dart_Handle Dart_NewStringFromCString(const char *str)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service port
Definition: switches.h:87
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets Path to the Flutter assets directory enable service port Allow the VM service to fallback to automatic port selection if binding to a specified port fails trace Trace early application lifecycle Automatically switches to an endless trace buffer trace skia Filters out all Skia trace event categories except those that are specified in this comma separated list dump skp on shader Automatically dump the skp that triggers new shader compilations This is useful for writing custom ShaderWarmUp to reduce jank By this is not enabled to reduce the overhead purge persistent cache
Definition: switches.h:191
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
#define RETURN_IF_ERROR(handle)