Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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) {
91 DartUtils::PostString(port, line);
92 }
93}
94
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
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
907
911
915
919
923
927
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:141
static Dart_Handle NewDartIOException(const char *exception_name, const char *message, Dart_Handle os_error)
Definition dartutils.cc:762
static bool PostString(Dart_Port port_id, const char *value)
Definition dartutils.cc:695
static Dart_Handle NewString(const char *str)
Definition dartutils.h:214
static Dart_Handle NewDartArgumentError(const char *message)
Definition dartutils.cc:750
static Dart_Handle NewInternalError(const char *message)
Definition dartutils.cc:786
static Dart_Handle GetDartType(const char *library_url, const char *class_name)
Definition dartutils.cc:700
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)
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:1530
int64_t Dart_Port
Definition dart_api.h:1524
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:3010
Dart_TypedData_Type
Definition dart_api.h:2603
@ Dart_TypedData_kUint8
Definition dart_api.h:2606
#define RETURN_IF_ERROR(handle)
Definition dartutils.cc:24
#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)
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)