OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #if !defined(DART_IO_DISABLED) && !defined(DART_IO_SECURE_SOCKET_DISABLED) | 5 #if !defined(DART_IO_DISABLED) && !defined(DART_IO_SECURE_SOCKET_DISABLED) |
6 | 6 |
7 #include "platform/globals.h" | 7 #include "platform/globals.h" |
8 #if defined(TARGET_OS_ANDROID) || \ | 8 #if defined(TARGET_OS_ANDROID) || \ |
9 defined(TARGET_OS_LINUX) || \ | 9 defined(TARGET_OS_LINUX) || \ |
10 defined(TARGET_OS_WINDOWS) | 10 defined(TARGET_OS_WINDOWS) |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
87 } | 87 } |
88 } | 88 } |
89 | 89 |
90 | 90 |
91 /* Handle an error reported from the BoringSSL library. */ | 91 /* Handle an error reported from the BoringSSL library. */ |
92 static void ThrowIOException(int status, | 92 static void ThrowIOException(int status, |
93 const char* exception_type, | 93 const char* exception_type, |
94 const char* message) { | 94 const char* message) { |
95 char error_string[SSL_ERROR_MESSAGE_BUFFER_SIZE]; | 95 char error_string[SSL_ERROR_MESSAGE_BUFFER_SIZE]; |
96 FetchErrorString(error_string, SSL_ERROR_MESSAGE_BUFFER_SIZE); | 96 FetchErrorString(error_string, SSL_ERROR_MESSAGE_BUFFER_SIZE); |
97 OSError os_error_struct(status, error_string, OSError::kBoringSSL); | 97 Dart_Handle exception; |
98 Dart_Handle os_error = DartUtils::NewDartOSError(&os_error_struct); | 98 { |
99 Dart_Handle exception = | 99 OSError os_error_struct(status, error_string, OSError::kBoringSSL); |
100 DartUtils::NewDartIOException(exception_type, message, os_error); | 100 Dart_Handle os_error = DartUtils::NewDartOSError(&os_error_struct); |
101 ASSERT(!Dart_IsError(exception)); | 101 exception = |
| 102 DartUtils::NewDartIOException(exception_type, message, os_error); |
| 103 ASSERT(!Dart_IsError(exception)); |
| 104 } |
102 Dart_ThrowException(exception); | 105 Dart_ThrowException(exception); |
103 UNREACHABLE(); | 106 UNREACHABLE(); |
104 } | 107 } |
105 | 108 |
106 | 109 |
107 static SSLFilter* GetFilter(Dart_NativeArguments args) { | 110 static SSLFilter* GetFilter(Dart_NativeArguments args) { |
108 SSLFilter* filter; | 111 SSLFilter* filter; |
109 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); | 112 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); |
110 ASSERT(Dart_IsInstance(dart_this)); | 113 ASSERT(Dart_IsInstance(dart_this)); |
111 ThrowIfError(Dart_GetNativeInstanceField( | 114 ThrowIfError(Dart_GetNativeInstanceField( |
(...skipping 24 matching lines...) Expand all Loading... |
136 reinterpret_cast<intptr_t>(filter)); | 139 reinterpret_cast<intptr_t>(filter)); |
137 RETURN_IF_ERROR(err); | 140 RETURN_IF_ERROR(err); |
138 Dart_NewWeakPersistentHandle(dart_this, | 141 Dart_NewWeakPersistentHandle(dart_this, |
139 reinterpret_cast<void*>(filter), | 142 reinterpret_cast<void*>(filter), |
140 sizeof(*filter), | 143 sizeof(*filter), |
141 DeleteFilter); | 144 DeleteFilter); |
142 return Dart_Null(); | 145 return Dart_Null(); |
143 } | 146 } |
144 | 147 |
145 | 148 |
146 static SSL_CTX* GetSecurityContext(Dart_NativeArguments args) { | 149 static SSLContext* GetSecurityContext(Dart_NativeArguments args) { |
147 SSL_CTX* context; | 150 SSLContext* context; |
148 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); | 151 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); |
149 ASSERT(Dart_IsInstance(dart_this)); | 152 ASSERT(Dart_IsInstance(dart_this)); |
150 ThrowIfError(Dart_GetNativeInstanceField( | 153 ThrowIfError(Dart_GetNativeInstanceField( |
151 dart_this, | 154 dart_this, |
152 kSecurityContextNativeFieldIndex, | 155 kSecurityContextNativeFieldIndex, |
153 reinterpret_cast<intptr_t*>(&context))); | 156 reinterpret_cast<intptr_t*>(&context))); |
154 return context; | 157 return context; |
155 } | 158 } |
156 | 159 |
157 | 160 |
158 static void FreeSecurityContext( | 161 static void DeleteSecurityContext( |
159 void* isolate_data, | 162 void* isolate_data, |
160 Dart_WeakPersistentHandle handle, | 163 Dart_WeakPersistentHandle handle, |
161 void* context_pointer) { | 164 void* context_pointer) { |
162 SSL_CTX* context = static_cast<SSL_CTX*>(context_pointer); | 165 SSLContext* context = static_cast<SSLContext*>(context_pointer); |
163 SSL_CTX_free(context); | 166 delete context; |
164 } | 167 } |
165 | 168 |
166 | 169 |
167 static Dart_Handle SetSecurityContext(Dart_NativeArguments args, | 170 static Dart_Handle SetSecurityContext(Dart_NativeArguments args, |
168 SSL_CTX* context) { | 171 SSLContext* context) { |
169 const int approximate_size_of_context = 1500; | 172 const int approximate_size_of_context = 1500; |
170 Dart_Handle dart_this = Dart_GetNativeArgument(args, 0); | 173 Dart_Handle dart_this = Dart_GetNativeArgument(args, 0); |
171 RETURN_IF_ERROR(dart_this); | 174 RETURN_IF_ERROR(dart_this); |
172 ASSERT(Dart_IsInstance(dart_this)); | 175 ASSERT(Dart_IsInstance(dart_this)); |
173 Dart_Handle err = Dart_SetNativeInstanceField( | 176 Dart_Handle err = Dart_SetNativeInstanceField( |
174 dart_this, | 177 dart_this, |
175 kSecurityContextNativeFieldIndex, | 178 kSecurityContextNativeFieldIndex, |
176 reinterpret_cast<intptr_t>(context)); | 179 reinterpret_cast<intptr_t>(context)); |
177 RETURN_IF_ERROR(err); | 180 RETURN_IF_ERROR(err); |
178 Dart_NewWeakPersistentHandle(dart_this, | 181 Dart_NewWeakPersistentHandle(dart_this, |
179 context, | 182 context, |
180 approximate_size_of_context, | 183 approximate_size_of_context, |
181 FreeSecurityContext); | 184 DeleteSecurityContext); |
182 return Dart_Null(); | 185 return Dart_Null(); |
183 } | 186 } |
184 | 187 |
185 | 188 |
186 static X509* GetX509Certificate(Dart_NativeArguments args) { | 189 static X509* GetX509Certificate(Dart_NativeArguments args) { |
187 X509* certificate; | 190 X509* certificate; |
188 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); | 191 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); |
189 ASSERT(Dart_IsInstance(dart_this)); | 192 ASSERT(Dart_IsInstance(dart_this)); |
190 ThrowIfError(Dart_GetNativeInstanceField( | 193 ThrowIfError(Dart_GetNativeInstanceField( |
191 dart_this, | 194 dart_this, |
192 kX509NativeFieldIndex, | 195 kX509NativeFieldIndex, |
193 reinterpret_cast<intptr_t*>(&certificate))); | 196 reinterpret_cast<intptr_t*>(&certificate))); |
194 return certificate; | 197 return certificate; |
195 } | 198 } |
196 | 199 |
197 | 200 |
198 // Forward declaration. | 201 // Forward declaration. |
199 static void SetAlpnProtocolList(Dart_Handle protocols_handle, | 202 static void SetAlpnProtocolList(Dart_Handle protocols_handle, |
200 SSL* ssl, | 203 SSL* ssl, |
201 SSL_CTX* context, | 204 SSLContext* context, |
202 bool is_server); | 205 bool is_server); |
203 | 206 |
204 | 207 |
205 void FUNCTION_NAME(SecureSocket_Init)(Dart_NativeArguments args) { | 208 void FUNCTION_NAME(SecureSocket_Init)(Dart_NativeArguments args) { |
206 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); | 209 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); |
207 SSLFilter* filter = new SSLFilter(); | 210 SSLFilter* filter = new SSLFilter(); |
208 Dart_Handle err = SetFilter(args, filter); | 211 Dart_Handle err = SetFilter(args, filter); |
209 if (Dart_IsError(err)) { | 212 if (Dart_IsError(err)) { |
210 filter->Release(); | 213 filter->Release(); |
211 Dart_PropagateError(err); | 214 Dart_PropagateError(err); |
(...skipping 16 matching lines...) Expand all Loading... |
228 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 4)); | 231 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 4)); |
229 bool require_client_certificate = | 232 bool require_client_certificate = |
230 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 5)); | 233 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 5)); |
231 Dart_Handle protocols_handle = | 234 Dart_Handle protocols_handle = |
232 ThrowIfError(Dart_GetNativeArgument(args, 6)); | 235 ThrowIfError(Dart_GetNativeArgument(args, 6)); |
233 | 236 |
234 const char* host_name = NULL; | 237 const char* host_name = NULL; |
235 // TODO(whesse): Is truncating a Dart string containing \0 what we want? | 238 // TODO(whesse): Is truncating a Dart string containing \0 what we want? |
236 ThrowIfError(Dart_StringToCString(host_name_object, &host_name)); | 239 ThrowIfError(Dart_StringToCString(host_name_object, &host_name)); |
237 | 240 |
238 SSL_CTX* context = NULL; | 241 SSLContext* context = NULL; |
239 if (!Dart_IsNull(context_object)) { | 242 if (!Dart_IsNull(context_object)) { |
240 ThrowIfError(Dart_GetNativeInstanceField( | 243 ThrowIfError(Dart_GetNativeInstanceField( |
241 context_object, | 244 context_object, |
242 kSecurityContextNativeFieldIndex, | 245 kSecurityContextNativeFieldIndex, |
243 reinterpret_cast<intptr_t*>(&context))); | 246 reinterpret_cast<intptr_t*>(&context))); |
244 } | 247 } |
245 | 248 |
246 // The protocols_handle is guaranteed to be a valid Uint8List. | 249 // The protocols_handle is guaranteed to be a valid Uint8List. |
247 // It will have the correct length encoding of the protocols array. | 250 // It will have the correct length encoding of the protocols array. |
248 ASSERT(!Dart_IsNull(protocols_handle)); | 251 ASSERT(!Dart_IsNull(protocols_handle)); |
249 | 252 |
250 GetFilter(args)->Connect(host_name, | 253 GetFilter(args)->Connect(host_name, |
251 context, | 254 context->context(), |
252 is_server, | 255 is_server, |
253 request_client_certificate, | 256 request_client_certificate, |
254 require_client_certificate, | 257 require_client_certificate, |
255 protocols_handle); | 258 protocols_handle); |
256 } | 259 } |
257 | 260 |
258 | 261 |
259 void FUNCTION_NAME(SecureSocket_Destroy)(Dart_NativeArguments args) { | 262 void FUNCTION_NAME(SecureSocket_Destroy)(Dart_NativeArguments args) { |
260 SSLFilter* filter = GetFilter(args); | 263 SSLFilter* filter = GetFilter(args); |
261 // The SSLFilter is deleted in the finalizer for the Dart object created by | 264 // The SSLFilter is deleted in the finalizer for the Dart object created by |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
419 if (Dart_IsError(result)) { | 422 if (Dart_IsError(result)) { |
420 filter->callback_error = result; | 423 filter->callback_error = result; |
421 return 0; | 424 return 0; |
422 } | 425 } |
423 return DartUtils::GetBooleanValue(result); | 426 return DartUtils::GetBooleanValue(result); |
424 } | 427 } |
425 | 428 |
426 | 429 |
427 void FUNCTION_NAME(SecurityContext_Allocate)(Dart_NativeArguments args) { | 430 void FUNCTION_NAME(SecurityContext_Allocate)(Dart_NativeArguments args) { |
428 SSLFilter::InitializeLibrary(); | 431 SSLFilter::InitializeLibrary(); |
429 SSL_CTX* context = SSL_CTX_new(TLS_method()); | 432 SSL_CTX* ctx = SSL_CTX_new(TLS_method()); |
430 SSL_CTX_set_verify(context, SSL_VERIFY_PEER, CertificateCallback); | 433 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, CertificateCallback); |
431 SSL_CTX_set_min_version(context, TLS1_VERSION); | 434 SSL_CTX_set_min_version(ctx, TLS1_VERSION); |
432 SSL_CTX_set_cipher_list(context, "HIGH:MEDIUM"); | 435 SSL_CTX_set_cipher_list(ctx, "HIGH:MEDIUM"); |
433 SSL_CTX_set_cipher_list_tls11(context, "HIGH:MEDIUM"); | 436 SSL_CTX_set_cipher_list_tls11(ctx, "HIGH:MEDIUM"); |
| 437 SSLContext* context = new SSLContext(ctx); |
434 Dart_Handle err = SetSecurityContext(args, context); | 438 Dart_Handle err = SetSecurityContext(args, context); |
435 if (Dart_IsError(err)) { | 439 if (Dart_IsError(err)) { |
436 SSL_CTX_free(context); | 440 delete context; |
437 Dart_PropagateError(err); | 441 Dart_PropagateError(err); |
438 } | 442 } |
439 } | 443 } |
440 | 444 |
441 | 445 |
442 int PasswordCallback(char* buf, int size, int rwflag, void* userdata) { | 446 int PasswordCallback(char* buf, int size, int rwflag, void* userdata) { |
443 char* password = static_cast<char*>(userdata); | 447 char* password = static_cast<char*>(userdata); |
444 ASSERT(size == PEM_BUFSIZE); | 448 ASSERT(size == PEM_BUFSIZE); |
445 strncpy(buf, password, size); | 449 strncpy(buf, password, size); |
446 return strlen(password); | 450 return strlen(password); |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
656 } else { | 660 } else { |
657 Dart_ThrowException(DartUtils::NewDartArgumentError( | 661 Dart_ThrowException(DartUtils::NewDartArgumentError( |
658 "Password is not a String or null")); | 662 "Password is not a String or null")); |
659 } | 663 } |
660 return password; | 664 return password; |
661 } | 665 } |
662 | 666 |
663 | 667 |
664 void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)( | 668 void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)( |
665 Dart_NativeArguments args) { | 669 Dart_NativeArguments args) { |
666 SSL_CTX* context = GetSecurityContext(args); | 670 SSLContext* context = GetSecurityContext(args); |
667 const char* password = GetPasswordArgument(args, 2); | 671 const char* password = GetPasswordArgument(args, 2); |
668 | 672 |
669 int status; | 673 int status; |
670 { | 674 { |
671 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); | 675 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); |
672 EVP_PKEY *key = GetPrivateKey(bio.bio(), password); | 676 EVP_PKEY *key = GetPrivateKey(bio.bio(), password); |
673 status = SSL_CTX_use_PrivateKey(context, key); | 677 status = SSL_CTX_use_PrivateKey(context->context(), key); |
| 678 // SSL_CTX_use_PrivateKey increments the reference count of key on success, |
| 679 // so we have to call EVP_PKEY_free on both success and failure. |
| 680 EVP_PKEY_free(key); |
674 } | 681 } |
675 | 682 |
676 // TODO(24184): Handle different expected errors here - file missing, | 683 // TODO(24184): Handle different expected errors here - file missing, |
677 // incorrect password, file not a PEM, and throw exceptions. | 684 // incorrect password, file not a PEM, and throw exceptions. |
678 // CheckStatus should also throw an exception in uncaught cases. | 685 // CheckStatus should also throw an exception in uncaught cases. |
679 CheckStatus(status, "TlsException", "Failure in usePrivateKeyBytes"); | 686 CheckStatus(status, "TlsException", "Failure in usePrivateKeyBytes"); |
680 } | 687 } |
681 | 688 |
682 | 689 |
683 static int SetTrustedCertificatesBytesPKCS12(SSL_CTX* context, | 690 static int SetTrustedCertificatesBytesPKCS12(SSL_CTX* context, |
684 BIO* bio, | 691 BIO* bio, |
685 const char* password) { | 692 const char* password) { |
686 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); | 693 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); |
687 if (p12.get() == NULL) { | 694 if (p12.get() == NULL) { |
688 return 0; | 695 return 0; |
689 } | 696 } |
690 | 697 |
691 EVP_PKEY* key = NULL; | 698 EVP_PKEY* key = NULL; |
692 X509 *cert = NULL; | 699 X509 *cert = NULL; |
693 STACK_OF(X509) *ca_certs = NULL; | 700 STACK_OF(X509) *ca_certs = NULL; |
694 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs); | 701 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs); |
695 if (status == 0) { | 702 if (status == 0) { |
696 return status; | 703 return status; |
697 } | 704 } |
698 | 705 |
699 ScopedX509Stack cert_stack(ca_certs); | 706 ScopedX509Stack cert_stack(ca_certs); |
700 X509_STORE* store = SSL_CTX_get_cert_store(context); | 707 X509_STORE* store = SSL_CTX_get_cert_store(context); |
701 status = X509_STORE_add_cert(store, cert); | 708 status = X509_STORE_add_cert(store, cert); |
| 709 // X509_STORE_add_cert increments the reference count of cert on success. |
| 710 X509_free(cert); |
702 if (status == 0) { | 711 if (status == 0) { |
703 X509_free(cert); | |
704 return status; | 712 return status; |
705 } | 713 } |
706 | 714 |
707 X509* ca; | 715 X509* ca; |
708 while ((ca = sk_X509_shift(cert_stack.get())) != NULL) { | 716 while ((ca = sk_X509_shift(cert_stack.get())) != NULL) { |
709 status = X509_STORE_add_cert(store, ca); | 717 status = X509_STORE_add_cert(store, ca); |
| 718 // X509_STORE_add_cert increments the reference count of cert on success. |
| 719 X509_free(ca); |
710 if (status == 0) { | 720 if (status == 0) { |
711 X509_free(ca); | |
712 return status; | 721 return status; |
713 } | 722 } |
714 } | 723 } |
715 | 724 |
716 return status; | 725 return status; |
717 } | 726 } |
718 | 727 |
719 | 728 |
720 static int SetTrustedCertificatesBytesPEM(SSL_CTX* context, BIO* bio) { | 729 static int SetTrustedCertificatesBytesPEM(SSL_CTX* context, BIO* bio) { |
721 X509_STORE* store = SSL_CTX_get_cert_store(context); | 730 X509_STORE* store = SSL_CTX_get_cert_store(context); |
722 | 731 |
723 int status = 0; | 732 int status = 0; |
724 X509* cert = NULL; | 733 X509* cert = NULL; |
725 while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) { | 734 while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) { |
726 status = X509_STORE_add_cert(store, cert); | 735 status = X509_STORE_add_cert(store, cert); |
| 736 // X509_STORE_add_cert increments the reference count of cert on success. |
| 737 X509_free(cert); |
727 if (status == 0) { | 738 if (status == 0) { |
728 X509_free(cert); | |
729 return status; | 739 return status; |
730 } | 740 } |
731 } | 741 } |
732 | 742 |
733 // If no PEM start line is found, it means that we read to the end of the | 743 // If no PEM start line is found, it means that we read to the end of the |
734 // file, or that the file isn't PEM. In the first case, status will be | 744 // file, or that the file isn't PEM. In the first case, status will be |
735 // non-zero indicating success. In the second case, status will be 0, | 745 // non-zero indicating success. In the second case, status will be 0, |
736 // indicating that we should try to read as PKCS12. If there is some other | 746 // indicating that we should try to read as PKCS12. If there is some other |
737 // error, we return it up to the caller. | 747 // error, we return it up to the caller. |
738 return NoPEMStartLine() ? status : 0; | 748 return NoPEMStartLine() ? status : 0; |
(...skipping 13 matching lines...) Expand all Loading... |
752 } else { | 762 } else { |
753 // The PEM file was successfully parsed. | 763 // The PEM file was successfully parsed. |
754 ERR_clear_error(); | 764 ERR_clear_error(); |
755 } | 765 } |
756 return status; | 766 return status; |
757 } | 767 } |
758 | 768 |
759 | 769 |
760 void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)( | 770 void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)( |
761 Dart_NativeArguments args) { | 771 Dart_NativeArguments args) { |
762 SSL_CTX* context = GetSecurityContext(args); | 772 SSLContext* context = GetSecurityContext(args); |
763 const char* password = GetPasswordArgument(args, 2); | 773 const char* password = GetPasswordArgument(args, 2); |
764 int status; | 774 int status; |
765 { | 775 { |
766 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); | 776 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); |
767 status = SetTrustedCertificatesBytes(context, bio.bio(), password); | 777 status = SetTrustedCertificatesBytes( |
| 778 context->context(), bio.bio(), password); |
768 } | 779 } |
769 CheckStatus(status, | 780 CheckStatus(status, |
770 "TlsException", | 781 "TlsException", |
771 "Failure in setTrustedCertificatesBytes"); | 782 "Failure in setTrustedCertificatesBytes"); |
772 } | 783 } |
773 | 784 |
774 | 785 |
775 void FUNCTION_NAME(SecurityContext_AlpnSupported)(Dart_NativeArguments args) { | 786 void FUNCTION_NAME(SecurityContext_AlpnSupported)(Dart_NativeArguments args) { |
776 Dart_SetReturnValue(args, Dart_NewBoolean(true)); | 787 Dart_SetReturnValue(args, Dart_NewBoolean(true)); |
777 } | 788 } |
778 | 789 |
779 | 790 |
780 void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)( | 791 void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)( |
781 Dart_NativeArguments args) { | 792 Dart_NativeArguments args) { |
782 SSL_CTX* context = GetSecurityContext(args); | 793 SSLContext* context = GetSecurityContext(args); |
783 #if defined(TARGET_OS_ANDROID) | 794 #if defined(TARGET_OS_ANDROID) |
784 // On Android, we don't compile in the trusted root certificates. Insead, | 795 // On Android, we don't compile in the trusted root certificates. Insead, |
785 // we use the directory of trusted certificates already present on the device. | 796 // we use the directory of trusted certificates already present on the device. |
786 // This saves ~240KB from the size of the binary. This has the drawback that | 797 // This saves ~240KB from the size of the binary. This has the drawback that |
787 // SSL_do_handshake will synchronously hit the filesystem looking for root | 798 // SSL_do_handshake will synchronously hit the filesystem looking for root |
788 // certs during its trust evaluation. We call SSL_do_handshake directly from | 799 // certs during its trust evaluation. We call SSL_do_handshake directly from |
789 // the Dart thread so that Dart code can be invoked from the "bad certificate" | 800 // the Dart thread so that Dart code can be invoked from the "bad certificate" |
790 // callback called by SSL_do_handshake. | 801 // callback called by SSL_do_handshake. |
791 const char* android_cacerts = "/system/etc/security/cacerts"; | 802 const char* android_cacerts = "/system/etc/security/cacerts"; |
792 int status = SSL_CTX_load_verify_locations(context, NULL, android_cacerts); | 803 int status = SSL_CTX_load_verify_locations( |
| 804 context->context(), NULL, android_cacerts); |
793 CheckStatus(status, "TlsException", "Failure trusting builtint roots"); | 805 CheckStatus(status, "TlsException", "Failure trusting builtint roots"); |
794 #else | 806 #else |
795 X509_STORE* store = SSL_CTX_get_cert_store(context); | 807 X509_STORE* store = SSL_CTX_get_cert_store(context->context()); |
796 BIO* roots_bio = | 808 BIO* roots_bio = |
797 BIO_new_mem_buf(const_cast<unsigned char*>(root_certificates_pem), | 809 BIO_new_mem_buf(const_cast<unsigned char*>(root_certificates_pem), |
798 root_certificates_pem_length); | 810 root_certificates_pem_length); |
799 X509* root_cert; | 811 X509* root_cert; |
800 // PEM_read_bio_X509 reads PEM-encoded certificates from a bio (in our case, | 812 // PEM_read_bio_X509 reads PEM-encoded certificates from a bio (in our case, |
801 // backed by a memory buffer), and returns X509 objects, one by one. | 813 // backed by a memory buffer), and returns X509 objects, one by one. |
802 // When the end of the bio is reached, it returns null. | 814 // When the end of the bio is reached, it returns null. |
803 while ((root_cert = PEM_read_bio_X509(roots_bio, NULL, NULL, NULL)) != NULL) { | 815 while ((root_cert = PEM_read_bio_X509(roots_bio, NULL, NULL, NULL)) != NULL) { |
804 X509_STORE_add_cert(store, root_cert); | 816 int status = X509_STORE_add_cert(store, root_cert); |
| 817 // X509_STORE_add_cert increments the reference count of cert on success. |
| 818 X509_free(root_cert); |
| 819 if (status == 0) { |
| 820 break; |
| 821 } |
805 } | 822 } |
806 BIO_free(roots_bio); | 823 BIO_free(roots_bio); |
807 // If there is an error here, it must be the error indicating that we are done | 824 // If there is an error here, it must be the error indicating that we are done |
808 // reading PEM certificates. | 825 // reading PEM certificates. |
809 ASSERT((ERR_peek_error() == 0) || NoPEMStartLine()); | 826 ASSERT((ERR_peek_error() == 0) || NoPEMStartLine()); |
810 ERR_clear_error(); | 827 ERR_clear_error(); |
811 #endif // defined(TARGET_OS_ANDROID) | 828 #endif // defined(TARGET_OS_ANDROID) |
812 } | 829 } |
813 | 830 |
814 | 831 |
(...skipping 22 matching lines...) Expand all Loading... |
837 } | 854 } |
838 if (status == 0) { | 855 if (status == 0) { |
839 return status; | 856 return status; |
840 } | 857 } |
841 | 858 |
842 SSL_CTX_clear_chain_certs(context); | 859 SSL_CTX_clear_chain_certs(context); |
843 | 860 |
844 X509* ca; | 861 X509* ca; |
845 while ((ca = sk_X509_shift(certs.get())) != NULL) { | 862 while ((ca = sk_X509_shift(certs.get())) != NULL) { |
846 status = SSL_CTX_add0_chain_cert(context, ca); | 863 status = SSL_CTX_add0_chain_cert(context, ca); |
| 864 // SSL_CTX_add0_chain_cert does not inc ref count, so don't free unless the |
| 865 // call fails. |
847 if (status == 0) { | 866 if (status == 0) { |
848 X509_free(ca); | 867 X509_free(ca); |
849 return status; | 868 return status; |
850 } | 869 } |
851 } | 870 } |
852 | 871 |
853 return status; | 872 return status; |
854 } | 873 } |
855 | 874 |
856 | 875 |
(...skipping 11 matching lines...) Expand all Loading... |
868 } | 887 } |
869 if (status == 0) { | 888 if (status == 0) { |
870 return status; | 889 return status; |
871 } | 890 } |
872 | 891 |
873 SSL_CTX_clear_chain_certs(context); | 892 SSL_CTX_clear_chain_certs(context); |
874 | 893 |
875 X509* ca; | 894 X509* ca; |
876 while ((ca = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) { | 895 while ((ca = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) { |
877 status = SSL_CTX_add0_chain_cert(context, ca); | 896 status = SSL_CTX_add0_chain_cert(context, ca); |
| 897 // SSL_CTX_add0_chain_cert does not inc ref count, so don't free unless the |
| 898 // call fails. |
878 if (status == 0) { | 899 if (status == 0) { |
879 X509_free(ca); | 900 X509_free(ca); |
880 return status; | 901 return status; |
881 } | 902 } |
882 // Note that we must not free `ca` if it was successfully added to the | 903 // Note that we must not free `ca` if it was successfully added to the |
883 // chain. We must free the main certificate x509, though since its reference | 904 // chain. We must free the main certificate x509, though since its reference |
884 // count is increased by SSL_CTX_use_certificate. | 905 // count is increased by SSL_CTX_use_certificate. |
885 } | 906 } |
886 | 907 |
887 return NoPEMStartLine() ? status : 0; | 908 return NoPEMStartLine() ? status : 0; |
(...skipping 11 matching lines...) Expand all Loading... |
899 } else { | 920 } else { |
900 // The PEM file was successfully read. | 921 // The PEM file was successfully read. |
901 ERR_clear_error(); | 922 ERR_clear_error(); |
902 } | 923 } |
903 return status; | 924 return status; |
904 } | 925 } |
905 | 926 |
906 | 927 |
907 void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)( | 928 void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)( |
908 Dart_NativeArguments args) { | 929 Dart_NativeArguments args) { |
909 SSL_CTX* context = GetSecurityContext(args); | 930 SSLContext* context = GetSecurityContext(args); |
910 const char* password = GetPasswordArgument(args, 2); | 931 const char* password = GetPasswordArgument(args, 2); |
911 int status; | 932 int status; |
912 { | 933 { |
913 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); | 934 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); |
914 status = UseChainBytes(context, bio.bio(), password); | 935 status = UseChainBytes(context->context(), bio.bio(), password); |
915 } | 936 } |
916 CheckStatus(status, | 937 CheckStatus(status, |
917 "TlsException", | 938 "TlsException", |
918 "Failure in useCertificateChainBytes"); | 939 "Failure in useCertificateChainBytes"); |
919 } | 940 } |
920 | 941 |
921 | 942 |
922 static int SetClientAuthoritiesPKCS12(SSL_CTX* context, | 943 static int SetClientAuthoritiesPKCS12(SSL_CTX* context, |
923 BIO* bio, | 944 BIO* bio, |
924 const char* password) { | 945 const char* password) { |
925 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); | 946 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL)); |
926 if (p12.get() == NULL) { | 947 if (p12.get() == NULL) { |
927 return 0; | 948 return 0; |
928 } | 949 } |
929 | 950 |
930 EVP_PKEY* key = NULL; | 951 EVP_PKEY* key = NULL; |
931 X509 *cert = NULL; | 952 X509 *cert = NULL; |
932 STACK_OF(X509) *ca_certs = NULL; | 953 STACK_OF(X509) *ca_certs = NULL; |
933 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs); | 954 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs); |
934 if (status == 0) { | 955 if (status == 0) { |
935 return status; | 956 return status; |
936 } | 957 } |
937 | 958 |
938 ScopedX509Stack cert_stack(ca_certs); | 959 ScopedX509Stack cert_stack(ca_certs); |
939 status = SSL_CTX_add_client_CA(context, cert); | 960 status = SSL_CTX_add_client_CA(context, cert); |
| 961 // SSL_CTX_add_client_CA increments the reference count of cert on success. |
| 962 X509_free(cert); |
940 if (status == 0) { | 963 if (status == 0) { |
941 X509_free(cert); | |
942 return status; | 964 return status; |
943 } | 965 } |
944 | 966 |
945 X509* ca; | 967 X509* ca; |
946 while ((ca = sk_X509_shift(cert_stack.get())) != NULL) { | 968 while ((ca = sk_X509_shift(cert_stack.get())) != NULL) { |
947 status = SSL_CTX_add_client_CA(context, ca); | 969 status = SSL_CTX_add_client_CA(context, ca); |
| 970 // SSL_CTX_add_client_CA increments the reference count of ca on success. |
948 X509_free(ca); // The name has been extracted. | 971 X509_free(ca); // The name has been extracted. |
949 if (status == 0) { | 972 if (status == 0) { |
950 return status; | 973 return status; |
951 } | 974 } |
952 } | 975 } |
953 | 976 |
954 return status; | 977 return status; |
955 } | 978 } |
956 | 979 |
957 | 980 |
(...skipping 24 matching lines...) Expand all Loading... |
982 } else { | 1005 } else { |
983 // The PEM file was successfully parsed. | 1006 // The PEM file was successfully parsed. |
984 ERR_clear_error(); | 1007 ERR_clear_error(); |
985 } | 1008 } |
986 return status; | 1009 return status; |
987 } | 1010 } |
988 | 1011 |
989 | 1012 |
990 void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)( | 1013 void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)( |
991 Dart_NativeArguments args) { | 1014 Dart_NativeArguments args) { |
992 SSL_CTX* context = GetSecurityContext(args); | 1015 SSLContext* context = GetSecurityContext(args); |
993 const char* password = GetPasswordArgument(args, 2); | 1016 const char* password = GetPasswordArgument(args, 2); |
994 | 1017 |
995 int status; | 1018 int status; |
996 { | 1019 { |
997 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); | 1020 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); |
998 status = SetClientAuthorities(context, bio.bio(), password); | 1021 status = SetClientAuthorities(context->context(), bio.bio(), password); |
999 } | 1022 } |
1000 | 1023 |
1001 CheckStatus(status, | 1024 CheckStatus(status, |
1002 "TlsException", | 1025 "TlsException", |
1003 "Failure in setClientAuthoritiesBytes"); | 1026 "Failure in setClientAuthoritiesBytes"); |
1004 } | 1027 } |
1005 | 1028 |
1006 | 1029 |
1007 void FUNCTION_NAME(SecurityContext_SetAlpnProtocols)( | 1030 void FUNCTION_NAME(SecurityContext_SetAlpnProtocols)( |
1008 Dart_NativeArguments args) { | 1031 Dart_NativeArguments args) { |
1009 SSL_CTX* context = GetSecurityContext(args); | 1032 SSLContext* context = GetSecurityContext(args); |
1010 Dart_Handle protocols_handle = | 1033 Dart_Handle protocols_handle = |
1011 ThrowIfError(Dart_GetNativeArgument(args, 1)); | 1034 ThrowIfError(Dart_GetNativeArgument(args, 1)); |
1012 Dart_Handle is_server_handle = | 1035 Dart_Handle is_server_handle = |
1013 ThrowIfError(Dart_GetNativeArgument(args, 2)); | 1036 ThrowIfError(Dart_GetNativeArgument(args, 2)); |
1014 if (Dart_IsBoolean(is_server_handle)) { | 1037 if (Dart_IsBoolean(is_server_handle)) { |
1015 bool is_server = DartUtils::GetBooleanValue(is_server_handle); | 1038 bool is_server = DartUtils::GetBooleanValue(is_server_handle); |
1016 SetAlpnProtocolList(protocols_handle, NULL, context, is_server); | 1039 SetAlpnProtocolList(protocols_handle, NULL, context, is_server); |
1017 } else { | 1040 } else { |
1018 Dart_ThrowException(DartUtils::NewDartArgumentError( | 1041 Dart_ThrowException(DartUtils::NewDartArgumentError( |
1019 "Non-boolean is_server argument passed to SetAlpnProtocols")); | 1042 "Non-boolean is_server argument passed to SetAlpnProtocols")); |
(...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1356 server_list += protocol_length; | 1379 server_list += protocol_length; |
1357 } | 1380 } |
1358 // TODO(23580): Make failure send a fatal alert instead of ignoring ALPN. | 1381 // TODO(23580): Make failure send a fatal alert instead of ignoring ALPN. |
1359 return SSL_TLSEXT_ERR_NOACK; | 1382 return SSL_TLSEXT_ERR_NOACK; |
1360 } | 1383 } |
1361 | 1384 |
1362 | 1385 |
1363 // Sets the protocol list for ALPN on a SSL object or a context. | 1386 // Sets the protocol list for ALPN on a SSL object or a context. |
1364 static void SetAlpnProtocolList(Dart_Handle protocols_handle, | 1387 static void SetAlpnProtocolList(Dart_Handle protocols_handle, |
1365 SSL* ssl, | 1388 SSL* ssl, |
1366 SSL_CTX* context, | 1389 SSLContext* context, |
1367 bool is_server) { | 1390 bool is_server) { |
1368 // Enable ALPN (application layer protocol negotiation) if the caller provides | 1391 // Enable ALPN (application layer protocol negotiation) if the caller provides |
1369 // a valid list of supported protocols. | 1392 // a valid list of supported protocols. |
1370 Dart_TypedData_Type protocols_type; | 1393 Dart_TypedData_Type protocols_type; |
1371 uint8_t* protocol_string = NULL; | 1394 uint8_t* protocol_string = NULL; |
1372 uint8_t* protocol_string_copy = NULL; | 1395 uint8_t* protocol_string_copy = NULL; |
1373 intptr_t protocol_string_len = 0; | 1396 intptr_t protocol_string_len = 0; |
1374 int status; | 1397 int status; |
1375 | 1398 |
1376 Dart_Handle result = Dart_TypedDataAcquireData( | 1399 Dart_Handle result = Dart_TypedDataAcquireData( |
(...skipping 16 matching lines...) Expand all Loading... |
1393 // ALPN on server connections must be set on an SSL_CTX object, | 1416 // ALPN on server connections must be set on an SSL_CTX object, |
1394 // not on the SSL object of the individual connection. | 1417 // not on the SSL object of the individual connection. |
1395 ASSERT(context != NULL); | 1418 ASSERT(context != NULL); |
1396 ASSERT(ssl == NULL); | 1419 ASSERT(ssl == NULL); |
1397 // Because it must be passed as a single void*, terminate | 1420 // Because it must be passed as a single void*, terminate |
1398 // the list of (length, data) strings with a length 0 string. | 1421 // the list of (length, data) strings with a length 0 string. |
1399 protocol_string_copy = | 1422 protocol_string_copy = |
1400 static_cast<uint8_t*>(malloc(protocol_string_len + 1)); | 1423 static_cast<uint8_t*>(malloc(protocol_string_len + 1)); |
1401 memmove(protocol_string_copy, protocol_string, protocol_string_len); | 1424 memmove(protocol_string_copy, protocol_string, protocol_string_len); |
1402 protocol_string_copy[protocol_string_len] = '\0'; | 1425 protocol_string_copy[protocol_string_len] = '\0'; |
1403 SSL_CTX_set_alpn_select_cb(context, AlpnCallback, protocol_string_copy); | 1426 SSL_CTX_set_alpn_select_cb( |
1404 // TODO(whesse): If this function is called again, free the previous | 1427 context->context(), AlpnCallback, protocol_string_copy); |
1405 // protocol_string_copy. It may be better to keep this as a native | 1428 context->set_alpn_protocol_string(protocol_string_copy); |
1406 // field on the Dart object, since fetching it from the structure is | |
1407 // not in the public api. | |
1408 // Also free protocol_string_copy when the context is destroyed, | |
1409 // in FreeSecurityContext() | |
1410 } else { | 1429 } else { |
1411 // The function makes a local copy of protocol_string, which it owns. | 1430 // The function makes a local copy of protocol_string, which it owns. |
1412 if (ssl != NULL) { | 1431 if (ssl != NULL) { |
1413 ASSERT(context == NULL); | 1432 ASSERT(context == NULL); |
1414 status = SSL_set_alpn_protos(ssl, protocol_string, protocol_string_len); | 1433 status = SSL_set_alpn_protos(ssl, protocol_string, protocol_string_len); |
1415 } else { | 1434 } else { |
1416 ASSERT(context != NULL); | 1435 ASSERT(context != NULL); |
1417 ASSERT(ssl == NULL); | 1436 ASSERT(ssl == NULL); |
1418 status = SSL_CTX_set_alpn_protos( | 1437 status = SSL_CTX_set_alpn_protos( |
1419 context, protocol_string, protocol_string_len); | 1438 context->context(), protocol_string, protocol_string_len); |
1420 } | 1439 } |
1421 ASSERT(status == 0); // The function returns a non-standard status. | 1440 ASSERT(status == 0); // The function returns a non-standard status. |
1422 } | 1441 } |
1423 } | 1442 } |
1424 Dart_TypedDataReleaseData(protocols_handle); | 1443 Dart_TypedDataReleaseData(protocols_handle); |
1425 } | 1444 } |
1426 | 1445 |
1427 | 1446 |
1428 void SSLFilter::Connect(const char* hostname, | 1447 void SSLFilter::Connect(const char* hostname, |
1429 SSL_CTX* context, | 1448 SSL_CTX* context, |
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1688 return bytes_processed; | 1707 return bytes_processed; |
1689 } | 1708 } |
1690 | 1709 |
1691 } // namespace bin | 1710 } // namespace bin |
1692 } // namespace dart | 1711 } // namespace dart |
1693 | 1712 |
1694 #endif // defined(TARGET_OS_LINUX) | 1713 #endif // defined(TARGET_OS_LINUX) |
1695 | 1714 |
1696 #endif // !defined(DART_IO_DISABLED) && | 1715 #endif // !defined(DART_IO_DISABLED) && |
1697 // !defined(DART_IO_SECURE_SOCKET_DISABLED) | 1716 // !defined(DART_IO_SECURE_SOCKET_DISABLED) |
OLD | NEW |