Chromium Code Reviews| Index: runtime/bin/secure_socket.cc |
| diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc |
| index 7f62fcf6adf913c003a6e38ac0a1d95f94aeef7d..81a05c432e9a64c9ac5673cbf87fca6a1a67702f 100644 |
| --- a/runtime/bin/secure_socket.cc |
| +++ b/runtime/bin/secure_socket.cc |
| @@ -376,17 +376,83 @@ void CheckStatus(int status, |
| } |
| +// Where the argument to the constructor is the handle for an object |
| +// implementing List<int>, this class creates a scope in which a memory-backed |
| +// BIO is allocated. Leaving the scope cleans up the BIO and the buffer that |
| +// was used to create it. |
| +class MemBIOScope { |
| + public: |
| + explicit MemBIOScope(Dart_Handle object) { |
| + if (!Dart_IsTypedData(object) && !Dart_IsList(object)) { |
| + Dart_ThrowException(DartUtils::NewDartArgumentError( |
| + "Argument is not a List<int>")); |
| + } |
| + |
| + uint8_t* bytes = NULL; |
| + intptr_t bytes_len = 0; |
| + bool is_typed_data = false; |
| + if (Dart_IsTypedData(object)) { |
| + is_typed_data = true; |
| + Dart_TypedData_Type typ; |
| + ThrowIfError(Dart_TypedDataAcquireData( |
|
Bill Hesse
2016/02/05 21:35:39
Any idea what PropagateError from a constructor or
zra
2016/02/05 23:10:39
Checked with iposva offline. From the point of vie
|
| + object, |
| + &typ, |
| + reinterpret_cast<void**>(&bytes), |
| + &bytes_len)); |
| + } else { |
| + ASSERT(Dart_IsList(object)); |
| + is_typed_data = false; |
|
Bill Hesse
2016/02/05 21:35:39
I wouldn't assign false to is_typed_data twice.
zra
2016/02/05 23:10:39
Done.
|
| + ThrowIfError(Dart_ListLength(object, &bytes_len)); |
| + bytes = new uint8_t[bytes_len]; |
| + Dart_Handle err = |
| + Dart_ListGetAsBytes(object, 0, bytes, bytes_len); |
| + if (Dart_IsError(err)) { |
| + delete[] bytes; |
| + Dart_PropagateError(err); |
| + } |
| + } |
| + |
| + object_ = object; |
| + bytes_ = bytes; |
| + bytes_len_ = bytes_len_; |
| + bio_ = BIO_new_mem_buf(bytes, bytes_len); |
| + ASSERT(bio_ != NULL); |
| + is_typed_data_ = is_typed_data; |
| + } |
| + |
| + ~MemBIOScope() { |
| + ASSERT(bio_ != NULL); |
| + if (is_typed_data_) { |
| + BIO_free(bio_); |
| + ThrowIfError(Dart_TypedDataReleaseData(object_)); |
| + } else { |
| + ASSERT(bytes_ != NULL); |
| + delete[] bytes_; |
| + BIO_free(bio_); |
| + } |
| + } |
| + |
| + BIO* bio() { |
| + ASSERT(bio_ != NULL); |
| + return bio_; |
| + } |
| + |
| + private: |
| + Dart_Handle object_; |
| + uint8_t* bytes_; |
| + intptr_t bytes_len_; |
| + BIO* bio_; |
| + bool is_typed_data_; |
| + |
| + DISALLOW_ALLOCATION(); |
| + DISALLOW_COPY_AND_ASSIGN(MemBIOScope); |
| +}; |
| + |
| + |
| 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.usePrivateKeyBytes " |
| - "is not a List<int>")); |
| - } |
| - |
| Dart_Handle password_object = ThrowIfError(Dart_GetNativeArgument(args, 2)); |
| const char* password = NULL; |
| if (Dart_IsString(password_object)) { |
| @@ -403,39 +469,12 @@ void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)( |
| "SecurityContext.usePrivateKey password is not a String or null")); |
| } |
| - uint8_t* key_bytes = NULL; |
| - intptr_t key_bytes_len = 0; |
| - bool is_typed_data = false; |
| - if (Dart_IsTypedData(key_object)) { |
| - is_typed_data = true; |
| - Dart_TypedData_Type typ; |
| - ThrowIfError(Dart_TypedDataAcquireData( |
| - key_object, |
| - &typ, |
| - reinterpret_cast<void**>(&key_bytes), |
| - &key_bytes_len)); |
| - } else { |
| - ASSERT(Dart_IsList(key_object)); |
| - ThrowIfError(Dart_ListLength(key_object, &key_bytes_len)); |
| - key_bytes = new uint8_t[key_bytes_len]; |
| - Dart_Handle err = |
| - Dart_ListGetAsBytes(key_object, 0, key_bytes, key_bytes_len); |
| - if (Dart_IsError(err)) { |
| - delete[] key_bytes; |
| - Dart_PropagateError(err); |
| - } |
| - } |
| - ASSERT(key_bytes != NULL); |
| - |
| - BIO* bio = BIO_new_mem_buf(key_bytes, key_bytes_len); |
| - EVP_PKEY *key = PEM_read_bio_PrivateKey( |
| - bio, NULL, PasswordCallback, const_cast<char*>(password)); |
| - int status = SSL_CTX_use_PrivateKey(context, key); |
| - BIO_free(bio); |
| - if (is_typed_data) { |
| - ThrowIfError(Dart_TypedDataReleaseData(key_object)); |
| - } else { |
| - delete[] key_bytes; |
| + int status; |
| + { |
| + MemBIOScope bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); |
| + EVP_PKEY *key = PEM_read_bio_PrivateKey( |
| + bio.bio(), NULL, PasswordCallback, const_cast<char*>(password)); |
| + status = SSL_CTX_use_PrivateKey(context, key); |
| } |
| // TODO(24184): Handle different expected errors here - file missing, |
| @@ -445,29 +484,44 @@ void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)( |
| } |
| -void FUNCTION_NAME(SecurityContext_SetTrustedCertificates)( |
| - 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)); |
| +static int SetTrustedCertificatesBytes(SSL_CTX* context, BIO* bio) { |
| + X509_STORE* store = SSL_CTX_get_cert_store(context); |
| + |
| + int status = 0; |
| + X509* cert = NULL; |
| + while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) { |
| + status = X509_STORE_add_cert(store, cert); |
| + if (status == 0) { |
| + X509_free(cert); |
| + return status; |
| + } |
| } |
| - Dart_Handle directory_object = ThrowIfError(Dart_GetNativeArgument(args, 2)); |
| - const char* directory = NULL; |
| - if (Dart_IsString(directory_object)) { |
| - ThrowIfError(Dart_StringToCString(directory_object, &directory)); |
| - } else if (Dart_IsNull(directory_object)) { |
| - directory = NULL; |
| + |
| + 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 { |
| - Dart_ThrowException(DartUtils::NewDartArgumentError( |
| - "Directory argument to SecurityContext.setTrustedCertificates is not " |
| - "a String or null")); |
| + // Some real error happened. |
| + status = 0; |
| } |
| - int status = SSL_CTX_load_verify_locations(context, filename, directory); |
| - CheckStatus( |
| - status, "TlsException", "SSL_CTX_load_verify_locations"); |
| + return status; |
| +} |
| + |
| + |
| +void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)( |
| + Dart_NativeArguments args) { |
| + SSL_CTX* context = GetSecurityContext(args); |
| + int status; |
| + { |
| + MemBIOScope bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); |
| + status = SetTrustedCertificatesBytes(context, bio.bio()); |
| + } |
| + CheckStatus(status, |
| + "TlsException", |
| + "Failure in setTrustedCertificatesBytes"); |
| } |
| @@ -489,17 +543,10 @@ void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)( |
| } |
| -static int UseChainBytes( |
| - SSL_CTX* context, uint8_t* chain_bytes, intptr_t chain_bytes_len) { |
| +static int UseChainBytes(SSL_CTX* context, BIO* bio) { |
| 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; |
| } |
| @@ -510,7 +557,6 @@ static int UseChainBytes( |
| } |
| if (status == 0) { |
| X509_free(x509); |
| - BIO_free(bio); |
| return status; |
| } |
| @@ -525,7 +571,6 @@ static int UseChainBytes( |
| 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 |
| @@ -544,7 +589,6 @@ static int UseChainBytes( |
| } |
| X509_free(x509); |
| - BIO_free(bio); |
| return status; |
| } |
| @@ -552,65 +596,61 @@ static int UseChainBytes( |
| void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)( |
| Dart_NativeArguments args) { |
| SSL_CTX* context = GetSecurityContext(args); |
| + int status; |
| + { |
| + MemBIOScope bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); |
| + status = UseChainBytes(context, bio.bio()); |
| + } |
| + CheckStatus(status, |
| + "TlsException", |
| + "Failure in useCertificateChainBytes"); |
| +} |
| - Dart_Handle chain_object = ThrowIfError(Dart_GetNativeArgument(args, 1)); |
| - if (!Dart_IsTypedData(chain_object) && !Dart_IsList(chain_object)) { |
| - Dart_ThrowException(DartUtils::NewDartArgumentError( |
| - "chainBytes argument to SecurityContext.useCertificateChainBytes " |
| - "is not a List<int>")); |
| + |
| +static STACK_OF(X509_NAME)* GetCertificateNames(BIO* bio) { |
| + STACK_OF(X509_NAME)* result = sk_X509_NAME_new_null(); |
| + if (result == NULL) { |
| + return NULL; |
| } |
| - 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); |
| + while (true) { |
| + X509* x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); |
| + if (x509 == NULL) { |
| + break; |
| } |
| - } |
| - ASSERT(chain_bytes != NULL); |
| - int status = UseChainBytes(context, chain_bytes, chain_bytes_len); |
| + X509_NAME* x509_name = X509_get_subject_name(x509); |
| + if (x509_name == NULL) { |
| + sk_X509_NAME_pop_free(result, X509_NAME_free); |
| + X509_free(x509); |
| + return NULL; |
| + } |
| - if (is_typed_data) { |
| - ThrowIfError(Dart_TypedDataReleaseData(chain_object)); |
| - } else { |
| - delete[] chain_bytes; |
| + // Duplicate the name to put it on the stack. |
| + x509_name = X509_NAME_dup(x509_name); |
| + if (x509_name == NULL) { |
| + sk_X509_NAME_pop_free(result, X509_NAME_free); |
| + X509_free(x509); |
| + return NULL; |
| + } |
| + sk_X509_NAME_push(result, x509_name); |
| + X509_free(x509); |
| } |
| - CheckStatus(status, |
| - "TlsException", |
| - "Failure in useCertificateChainBytes"); |
| + |
| + return result; |
| } |
| -void FUNCTION_NAME(SecurityContext_SetClientAuthorities)( |
| +void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)( |
| 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_ThrowException(DartUtils::NewDartArgumentError( |
| - "file argument in SecurityContext.setClientAuthorities" |
| - " is not a String")); |
| - } |
| STACK_OF(X509_NAME)* certificate_names; |
| - certificate_names = SSL_load_client_CA_file(filename); |
| + |
| + { |
| + MemBIOScope bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); |
| + certificate_names = GetCertificateNames(bio.bio()); |
| + } |
| + |
| if (certificate_names != NULL) { |
| SSL_CTX_set_client_CA_list(context, certificate_names); |
| } else { |