Index: runtime/bin/secure_socket_ios.cc |
diff --git a/runtime/bin/secure_socket_ios.cc b/runtime/bin/secure_socket_ios.cc |
index c52ffb73b5a3db8d529be8d107d686899fc1d367..8fae462c5d83c80bfc027339a665088bf1e7fdc6 100644 |
--- a/runtime/bin/secure_socket_ios.cc |
+++ b/runtime/bin/secure_socket_ios.cc |
@@ -43,16 +43,6 @@ |
} \ |
} |
-// We need to access this private API function to create a SecIdentityRef |
-// without writing a custom keychain to the filesystem. This is the approach |
-// taken in WebKit: |
-// https://webkit.googlesource.com/WebKit/+/master/Source/WebKit2/Shared/cf/ArgumentCodersCF.cpp |
-extern "C" { |
-SecIdentityRef SecIdentityCreate(CFAllocatorRef allocator, |
- SecCertificateRef certificate, |
- SecKeyRef private_key); |
-} |
- |
namespace dart { |
namespace bin { |
@@ -72,10 +62,28 @@ class SSLCertContext { |
public: |
SSLCertContext() : |
mutex_(new Mutex()), |
+ trusted_certs_(NULL), |
trust_builtin_(false) {} |
~SSLCertContext() { |
delete mutex_; |
+ if (trusted_certs_ != NULL) { |
+ CFRelease(trusted_certs_); |
+ } |
+ } |
+ |
+ CFMutableArrayRef trusted_certs() { |
+ MutexLocker m(mutex_); |
+ return trusted_certs_; |
+ } |
+ void add_trusted_cert(SecCertificateRef trusted_cert) { |
+ // Takes ownership of trusted_cert. |
+ MutexLocker m(mutex_); |
+ if (trusted_certs_ == NULL) { |
+ trusted_certs_ = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); |
+ } |
+ CFArrayAppendValue(trusted_certs_, trusted_cert); |
+ CFRelease(trusted_cert); // trusted_cert is retained by the array. |
} |
bool trust_builtin() { |
@@ -91,6 +99,7 @@ class SSLCertContext { |
// The context is accessed both by Dart code and the IOService. This mutex |
// protects all fields. |
Mutex* mutex_; |
+ CFMutableArrayRef trusted_certs_; |
bool trust_builtin_; |
DISALLOW_COPY_AND_ASSIGN(SSLCertContext); |
@@ -247,6 +256,65 @@ static Dart_Handle WrappedX509Certificate(SecCertificateRef certificate) { |
} |
+// Where the argument to the constructor is the handle for an object |
+// implementing List<int>, this class creates a scope in which the memory |
+// backing the list can be accessed. |
+// |
+// Do not make Dart_ API calls while in a ScopedMemBuffer. |
+// Do not call Dart_PropagateError while in a ScopedMemBuffer. |
+class ScopedMemBuffer { |
+ public: |
+ explicit ScopedMemBuffer(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( |
+ object, |
+ &typ, |
+ reinterpret_cast<void**>(&bytes), |
+ &bytes_len)); |
+ } else { |
+ ASSERT(Dart_IsList(object)); |
+ ThrowIfError(Dart_ListLength(object, &bytes_len)); |
+ bytes = Dart_ScopeAllocate(bytes_len); |
+ ASSERT(bytes != NULL); |
+ ThrowIfError(Dart_ListGetAsBytes(object, 0, bytes, bytes_len)); |
+ } |
+ |
+ object_ = object; |
+ bytes_ = bytes; |
+ bytes_len_ = bytes_len; |
+ is_typed_data_ = is_typed_data; |
+ } |
+ |
+ ~ScopedMemBuffer() { |
+ if (is_typed_data_) { |
+ ThrowIfError(Dart_TypedDataReleaseData(object_)); |
+ } |
+ } |
+ |
+ uint8_t* get() const { return bytes_; } |
+ intptr_t length() const { return bytes_len_; } |
+ |
+ private: |
+ Dart_Handle object_; |
+ uint8_t* bytes_; |
+ intptr_t bytes_len_; |
+ bool is_typed_data_; |
+ |
+ DISALLOW_ALLOCATION(); |
+ DISALLOW_COPY_AND_ASSIGN(ScopedMemBuffer); |
+}; |
+ |
+ |
void FUNCTION_NAME(SecureSocket_Init)(Dart_NativeArguments args) { |
Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); |
SSLFilter* filter = new SSLFilter(); // Deleted in DeleteFilter finalizer. |
@@ -388,8 +456,25 @@ void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)( |
void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)( |
Dart_NativeArguments args) { |
- Dart_ThrowException(DartUtils::NewDartUnsupportedError( |
- "SecurityContext.setTrustedCertificatesBytes is not yet implemented.")); |
+ SSLCertContext* context = GetSecurityContext(args); |
+ |
+ OSStatus status = noErr; |
+ SecCertificateRef cert = NULL; |
+ { |
+ ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1))); |
+ CFDataRef cfdata = CFDataCreateWithBytesNoCopy( |
+ NULL, buffer.get(), buffer.length(), kCFAllocatorNull); |
+ cert = SecCertificateCreateWithData(NULL, cfdata); |
+ CFRelease(cfdata); |
+ } |
+ |
+ // Add the certs to the context. |
+ if (cert != NULL) { |
+ context->add_trusted_cert(cert); |
+ } else { |
+ status = errSSLBadCert; |
+ } |
+ CheckStatus(status, "TlsException", "Failure in setTrustedCertificatesBytes"); |
} |
@@ -898,8 +983,12 @@ OSStatus SSLFilter::EvaluatePeerTrust() { |
return status; |
} |
- CFArrayRef trusted_certs = |
- CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks); |
+ CFArrayRef trusted_certs = NULL; |
+ if (cert_context_->trusted_certs() != NULL) { |
+ trusted_certs = CFArrayCreateCopy(NULL, cert_context_->trusted_certs()); |
+ } else { |
+ trusted_certs = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks); |
+ } |
status = SecTrustSetAnchorCertificates(peer_trust, trusted_certs); |
if (status != noErr) { |