Index: runtime/bin/secure_socket.cc |
diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc |
index f8dd77625991447ba16912c08f065a612915cb49..7f62fcf6adf913c003a6e38ac0a1d95f94aeef7d 100644 |
--- a/runtime/bin/secure_socket.cc |
+++ b/runtime/bin/secure_socket.cc |
@@ -376,14 +376,14 @@ void CheckStatus(int status, |
} |
-void FUNCTION_NAME(SecurityContext_UsePrivateKeyAsBytes)( |
+void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)( |
Dart_NativeArguments args) { |
SSL_CTX* context = GetSecurityContext(args); |
Dart_Handle key_object = ThrowIfError(Dart_GetNativeArgument(args, 1)); |
if (!Dart_IsTypedData(key_object) && !Dart_IsList(key_object)) { |
Dart_ThrowException(DartUtils::NewDartArgumentError( |
- "keyBytes argument to SecurityContext.usePrivateKey " |
+ "keyBytes argument to SecurityContext.usePrivateKeyBytes " |
"is not a List<int>")); |
} |
@@ -441,7 +441,7 @@ void FUNCTION_NAME(SecurityContext_UsePrivateKeyAsBytes)( |
// TODO(24184): Handle different expected errors here - file missing, |
// incorrect password, file not a PEM, and throw exceptions. |
// CheckStatus should also throw an exception in uncaught cases. |
- CheckStatus(status, "TlsException", "Failure in usePrivateKey"); |
+ CheckStatus(status, "TlsException", "Failure in usePrivateKeyBytes"); |
} |
@@ -489,22 +489,111 @@ void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)( |
} |
-void FUNCTION_NAME(SecurityContext_UseCertificateChain)( |
+static int UseChainBytes( |
+ SSL_CTX* context, uint8_t* chain_bytes, intptr_t chain_bytes_len) { |
+ int status = 0; |
+ BIO* bio = BIO_new_mem_buf(chain_bytes, chain_bytes_len); |
+ if (bio == NULL) { |
+ return 0; |
+ } |
+ |
+ X509* x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); |
+ if (x509 == NULL) { |
+ BIO_free(bio); |
+ return 0; |
+ } |
+ |
+ status = SSL_CTX_use_certificate(context, x509); |
+ if (ERR_peek_error() != 0) { |
+ // Key/certificate mismatch doesn't imply status is 0. |
+ status = 0; |
+ } |
+ if (status == 0) { |
+ X509_free(x509); |
+ BIO_free(bio); |
+ return status; |
+ } |
+ |
+ SSL_CTX_clear_chain_certs(context); |
+ |
+ while (true) { |
+ X509* ca = PEM_read_bio_X509(bio, NULL, NULL, NULL); |
+ if (ca == NULL) { |
+ break; |
+ } |
+ status = SSL_CTX_add0_chain_cert(context, ca); |
+ if (status == 0) { |
+ X509_free(ca); |
+ X509_free(x509); |
+ BIO_free(bio); |
+ return status; |
+ } |
+ // Note that we must not free `ca` if it was successfully added to the |
+ // chain. We must free the main certificate x509, though since its reference |
+ // count is increased by SSL_CTX_use_certificate. |
+ } |
+ |
+ uint32_t err = ERR_peek_last_error(); |
+ if ((ERR_GET_LIB(err) == ERR_LIB_PEM) && |
+ (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) { |
+ // Reached the end of the buffer. |
+ ERR_clear_error(); |
+ } else { |
+ // Some real error happened. |
+ status = 0; |
+ } |
+ |
+ X509_free(x509); |
+ BIO_free(bio); |
+ return status; |
+} |
+ |
+ |
+void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)( |
Dart_NativeArguments args) { |
SSL_CTX* context = GetSecurityContext(args); |
- Dart_Handle filename_object = ThrowIfError(Dart_GetNativeArgument(args, 1)); |
- const char* filename = NULL; |
- if (Dart_IsString(filename_object)) { |
- ThrowIfError(Dart_StringToCString(filename_object, &filename)); |
- } else { |
+ |
+ Dart_Handle chain_object = ThrowIfError(Dart_GetNativeArgument(args, 1)); |
+ if (!Dart_IsTypedData(chain_object) && !Dart_IsList(chain_object)) { |
Dart_ThrowException(DartUtils::NewDartArgumentError( |
- "file argument in SecurityContext.useCertificateChain" |
- " is not a String")); |
+ "chainBytes argument to SecurityContext.useCertificateChainBytes " |
+ "is not a List<int>")); |
+ } |
+ |
+ uint8_t* chain_bytes = NULL; |
+ intptr_t chain_bytes_len = 0; |
+ bool is_typed_data = false; |
+ if (Dart_IsTypedData(chain_object)) { |
+ is_typed_data = true; |
+ Dart_TypedData_Type typ; |
+ ThrowIfError(Dart_TypedDataAcquireData( |
+ chain_object, |
+ &typ, |
+ reinterpret_cast<void**>(&chain_bytes), |
+ &chain_bytes_len)); |
+ } else { |
+ ASSERT(Dart_IsList(chain_object)); |
+ ThrowIfError(Dart_ListLength(chain_object, &chain_bytes_len)); |
+ chain_bytes = new uint8_t[chain_bytes_len]; |
+ Dart_Handle err = |
+ Dart_ListGetAsBytes(chain_object, 0, chain_bytes, chain_bytes_len); |
+ if (Dart_IsError(err)) { |
+ delete[] chain_bytes; |
+ Dart_PropagateError(err); |
+ } |
+ } |
+ ASSERT(chain_bytes != NULL); |
+ |
+ int status = UseChainBytes(context, chain_bytes, chain_bytes_len); |
+ |
+ if (is_typed_data) { |
+ ThrowIfError(Dart_TypedDataReleaseData(chain_object)); |
+ } else { |
+ delete[] chain_bytes; |
} |
- int status = SSL_CTX_use_certificate_chain_file(context, filename); |
CheckStatus(status, |
"TlsException", |
- "Failure in useCertificateChain"); |
+ "Failure in useCertificateChainBytes"); |
} |