| Index: runtime/bin/secure_socket_ios.cc
 | 
| diff --git a/runtime/bin/secure_socket_macos.cc b/runtime/bin/secure_socket_ios.cc
 | 
| similarity index 63%
 | 
| copy from runtime/bin/secure_socket_macos.cc
 | 
| copy to runtime/bin/secure_socket_ios.cc
 | 
| index 5e6e320f20cca2c007e667170dbe67e70a72dcc0..c52ffb73b5a3db8d529be8d107d686899fc1d367 100644
 | 
| --- a/runtime/bin/secure_socket_macos.cc
 | 
| +++ b/runtime/bin/secure_socket_ios.cc
 | 
| @@ -5,7 +5,7 @@
 | 
|  #if !defined(DART_IO_DISABLED) && !defined(DART_IO_SECURE_SOCKET_DISABLED)
 | 
|  
 | 
|  #include "platform/globals.h"
 | 
| -#if defined(TARGET_OS_MACOS)
 | 
| +#if TARGET_OS_IOS
 | 
|  
 | 
|  #include "bin/secure_socket.h"
 | 
|  #include "bin/secure_socket_macos.h"
 | 
| @@ -62,9 +62,7 @@ static const int kX509NativeFieldIndex = 0;
 | 
|  
 | 
|  static const bool SSL_LOG_STATUS = false;
 | 
|  static const bool SSL_LOG_DATA = false;
 | 
| -static const bool SSL_LOG_CERTS = false;
 | 
|  static const int SSL_ERROR_MESSAGE_BUFFER_SIZE = 1000;
 | 
| -static const intptr_t PEM_BUFSIZE = 1024;
 | 
|  
 | 
|  // SSLCertContext wraps the certificates needed for a SecureTransport
 | 
|  // connection. Fields are protected by the mutex_ field, and may only be set
 | 
| @@ -74,98 +72,12 @@ class SSLCertContext {
 | 
|   public:
 | 
|    SSLCertContext() :
 | 
|        mutex_(new Mutex()),
 | 
| -      private_key_(NULL),
 | 
| -      keychain_(NULL),
 | 
| -      cert_chain_(NULL),
 | 
| -      trusted_certs_(NULL),
 | 
| -      cert_authorities_(NULL),
 | 
|        trust_builtin_(false) {}
 | 
|  
 | 
|    ~SSLCertContext() {
 | 
| -    if (private_key_ != NULL) {
 | 
| -      CFRelease(private_key_);
 | 
| -    }
 | 
| -    if (keychain_ != NULL) {
 | 
| -      SecKeychainDelete(keychain_);
 | 
| -      CFRelease(keychain_);
 | 
| -    }
 | 
| -    if (cert_chain_ != NULL) {
 | 
| -      CFRelease(cert_chain_);
 | 
| -    }
 | 
| -    if (trusted_certs_ != NULL) {
 | 
| -      CFRelease(trusted_certs_);
 | 
| -    }
 | 
| -    if (cert_authorities_ != NULL) {
 | 
| -      CFRelease(cert_authorities_);
 | 
| -    }
 | 
|      delete mutex_;
 | 
|    }
 | 
|  
 | 
| -  SecKeyRef private_key() {
 | 
| -    MutexLocker m(mutex_);
 | 
| -    return private_key_;
 | 
| -  }
 | 
| -  bool set_private_key(SecKeyRef private_key) {
 | 
| -    MutexLocker m(mutex_);
 | 
| -    if (private_key_ != NULL) {
 | 
| -      return false;
 | 
| -    }
 | 
| -    private_key_ = private_key;
 | 
| -    return true;
 | 
| -  }
 | 
| -
 | 
| -  SecKeychainRef keychain() {
 | 
| -    MutexLocker m(mutex_);
 | 
| -    return keychain_;
 | 
| -  }
 | 
| -  bool set_keychain(SecKeychainRef keychain) {
 | 
| -    MutexLocker m(mutex_);
 | 
| -    if (keychain_ != NULL) {
 | 
| -      return false;
 | 
| -    }
 | 
| -    keychain_ = keychain;
 | 
| -    return true;
 | 
| -  }
 | 
| -
 | 
| -  CFArrayRef cert_chain() {
 | 
| -    MutexLocker m(mutex_);
 | 
| -    return cert_chain_;
 | 
| -  }
 | 
| -  bool set_cert_chain(CFArrayRef cert_chain) {
 | 
| -    MutexLocker m(mutex_);
 | 
| -    if (cert_chain_ != NULL) {
 | 
| -      return false;
 | 
| -    }
 | 
| -    cert_chain_ = cert_chain;
 | 
| -    return true;
 | 
| -  }
 | 
| -
 | 
| -  CFArrayRef trusted_certs() {
 | 
| -    MutexLocker m(mutex_);
 | 
| -    return trusted_certs_;
 | 
| -  }
 | 
| -  bool set_trusted_certs(CFArrayRef trusted_certs) {
 | 
| -    MutexLocker m(mutex_);
 | 
| -    if (trusted_certs_ != NULL) {
 | 
| -      return false;
 | 
| -    }
 | 
| -    trusted_certs_ = trusted_certs;
 | 
| -    return true;
 | 
| -  }
 | 
| -
 | 
| -  CFArrayRef cert_authorities() {
 | 
| -    MutexLocker m(mutex_);
 | 
| -    return cert_authorities_;
 | 
| -  }
 | 
| -  bool set_cert_authorities(CFArrayRef cert_authorities) {
 | 
| -    MutexLocker m(mutex_);
 | 
| -    if (cert_authorities_ != NULL) {
 | 
| -      return false;
 | 
| -    }
 | 
| -    cert_authorities_ = cert_authorities;
 | 
| -    return true;
 | 
| -  }
 | 
| -
 | 
|    bool trust_builtin() {
 | 
|      MutexLocker m(mutex_);
 | 
|      return trust_builtin_;
 | 
| @@ -179,48 +91,18 @@ class SSLCertContext {
 | 
|    // The context is accessed both by Dart code and the IOService. This mutex
 | 
|    // protects all fields.
 | 
|    Mutex* mutex_;
 | 
| -
 | 
| -  SecKeyRef private_key_;
 | 
| -  SecKeychainRef keychain_;
 | 
| -
 | 
| -  // CFArrays of SecCertificateRef.
 | 
| -  CFArrayRef cert_chain_;
 | 
| -  CFArrayRef trusted_certs_;
 | 
| -  CFArrayRef cert_authorities_;
 | 
| -
 | 
|    bool trust_builtin_;
 | 
|  
 | 
|    DISALLOW_COPY_AND_ASSIGN(SSLCertContext);
 | 
|  };
 | 
|  
 | 
| -
 | 
| -static char* CFStringRefToCString(CFStringRef cfstring) {
 | 
| -  CFIndex len = CFStringGetLength(cfstring);
 | 
| -  CFIndex max_len =
 | 
| -      CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8) + 1;
 | 
| -  char* result = reinterpret_cast<char*>(Dart_ScopeAllocate(max_len));
 | 
| -  ASSERT(result != NULL);
 | 
| -  bool success =
 | 
| -      CFStringGetCString(cfstring, result, max_len, kCFStringEncodingUTF8);
 | 
| -  return success ? result : NULL;
 | 
| -}
 | 
| -
 | 
| -
 | 
|  // Handle an error reported from the SecureTransport library.
 | 
|  static void ThrowIOException(OSStatus status,
 | 
|                               const char* exception_type,
 | 
|                               const char* message) {
 | 
|    TextBuffer status_message(SSL_ERROR_MESSAGE_BUFFER_SIZE);
 | 
| -  CFStringRef error_string = SecCopyErrorMessageString(status, NULL);
 | 
| -  if (error_string == NULL) {
 | 
| -    status_message.Printf("OSStatus = %ld: https://www.osstatus.com",
 | 
| -        static_cast<intptr_t>(status));
 | 
| -  } else {
 | 
| -    char* error = CFStringRefToCString(error_string);
 | 
| -    status_message.Printf("OSStatus = %ld: %s",
 | 
| -        static_cast<intptr_t>(status), error);
 | 
| -    CFRelease(error_string);
 | 
| -  }
 | 
| +  status_message.Printf("OSStatus = %ld: https://www.osstatus.com",
 | 
| +      static_cast<intptr_t>(status));
 | 
|    OSError os_error_struct(status, status_message.buf(), OSError::kBoringSSL);
 | 
|    Dart_Handle os_error = DartUtils::NewDartOSError(&os_error_struct);
 | 
|    Dart_Handle exception =
 | 
| @@ -319,18 +201,6 @@ static Dart_Handle SetSecurityContext(Dart_NativeArguments args,
 | 
|  }
 | 
|  
 | 
|  
 | 
| -static SecCertificateRef GetX509Certificate(Dart_NativeArguments args) {
 | 
| -  SecCertificateRef certificate;
 | 
| -  Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
 | 
| -  ASSERT(Dart_IsInstance(dart_this));
 | 
| -  ThrowIfError(Dart_GetNativeInstanceField(
 | 
| -      dart_this,
 | 
| -      kX509NativeFieldIndex,
 | 
| -      reinterpret_cast<intptr_t*>(&certificate)));
 | 
| -  return certificate;
 | 
| -}
 | 
| -
 | 
| -
 | 
|  static void ReleaseCertificate(void* isolate_data,
 | 
|                                 Dart_WeakPersistentHandle handle,
 | 
|                                 void* context_pointer) {
 | 
| @@ -377,362 +247,6 @@ 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);
 | 
| -};
 | 
| -
 | 
| -
 | 
| -static const char* GetPasswordArgument(Dart_NativeArguments args,
 | 
| -                                       intptr_t index) {
 | 
| -  Dart_Handle password_object =
 | 
| -      ThrowIfError(Dart_GetNativeArgument(args, index));
 | 
| -  const char* password = NULL;
 | 
| -  if (Dart_IsString(password_object)) {
 | 
| -    ThrowIfError(Dart_StringToCString(password_object, &password));
 | 
| -    if (strlen(password) > PEM_BUFSIZE - 1) {
 | 
| -      Dart_ThrowException(DartUtils::NewDartArgumentError(
 | 
| -          "Password length is greater than 1023 bytes."));
 | 
| -    }
 | 
| -  } else if (Dart_IsNull(password_object)) {
 | 
| -    password = "";
 | 
| -  } else {
 | 
| -    Dart_ThrowException(DartUtils::NewDartArgumentError(
 | 
| -        "Password is not a String or null"));
 | 
| -  }
 | 
| -  return password;
 | 
| -}
 | 
| -
 | 
| -
 | 
| -static OSStatus GetKeyAndCerts(CFArrayRef items,
 | 
| -                               CFIndex items_length,
 | 
| -                               CFArrayRef* out_certs,
 | 
| -                               SecKeyRef* out_key) {
 | 
| -  OSStatus status = noErr;
 | 
| -
 | 
| -  // Loop through the items, take only the first private key/identity, ignore
 | 
| -  // any others, populate out_certs.
 | 
| -  CFMutableArrayRef certs =
 | 
| -      CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
 | 
| -  SecKeyRef key = NULL;
 | 
| -
 | 
| -  for (CFIndex i = 0; i < items_length; ++i) {
 | 
| -    CFTypeRef item =
 | 
| -        reinterpret_cast<CFTypeRef>(CFArrayGetValueAtIndex(items, i));
 | 
| -    CFTypeID item_type = CFGetTypeID(item);
 | 
| -    if (item_type == SecCertificateGetTypeID()) {
 | 
| -      if (SSL_LOG_CERTS) {
 | 
| -        Log::Print("\titem %ld: Certificate\n", i);
 | 
| -      }
 | 
| -      CFArrayAppendValue(certs, item);
 | 
| -    } else if ((item_type == SecKeyGetTypeID()) && (key == NULL)) {
 | 
| -      if (SSL_LOG_CERTS) {
 | 
| -        Log::Print("\titem %ld: Key\n", i);
 | 
| -      }
 | 
| -      key = reinterpret_cast<SecKeyRef>(const_cast<void*>(item));
 | 
| -      CFRetain(key);
 | 
| -    } else if ((item_type == SecIdentityGetTypeID()) && (key == NULL)) {
 | 
| -      if (SSL_LOG_CERTS) {
 | 
| -        Log::Print("\titem %ld: Identity\n", i);
 | 
| -      }
 | 
| -      SecIdentityRef identity =
 | 
| -          reinterpret_cast<SecIdentityRef>(const_cast<void*>(item));
 | 
| -      SecCertificateRef cert = NULL;
 | 
| -
 | 
| -      status = SecIdentityCopyPrivateKey(identity, &key);
 | 
| -      if (status != noErr) {
 | 
| -        CFRelease(certs);
 | 
| -        return status;
 | 
| -      }
 | 
| -
 | 
| -      status = SecIdentityCopyCertificate(identity, &cert);
 | 
| -      if (status != noErr) {
 | 
| -        CFRelease(key);
 | 
| -        CFRelease(certs);
 | 
| -        return status;
 | 
| -      }
 | 
| -      CFArrayAppendValue(certs, cert);
 | 
| -      CFRelease(cert);
 | 
| -    }
 | 
| -    // Other item types are ignored.
 | 
| -  }
 | 
| -
 | 
| -  if (out_key == NULL) {
 | 
| -    if (key != NULL) {
 | 
| -      CFRelease(key);
 | 
| -    }
 | 
| -  } else {
 | 
| -    *out_key = key;
 | 
| -  }
 | 
| -
 | 
| -  if (out_certs == NULL) {
 | 
| -    if (certs != NULL) {
 | 
| -      CFRelease(certs);
 | 
| -    }
 | 
| -  } else {
 | 
| -    *out_certs = certs;
 | 
| -  }
 | 
| -  return status;
 | 
| -}
 | 
| -
 | 
| -
 | 
| -static OSStatus TryPEMImport(CFDataRef cfdata,
 | 
| -                             CFStringRef password,
 | 
| -                             CFArrayRef* out_certs,
 | 
| -                             SecKeyRef* out_key) {
 | 
| -  OSStatus status = noErr;
 | 
| -
 | 
| -  SecExternalFormat format = kSecFormatPEMSequence;
 | 
| -  SecExternalItemType sitem_type = kSecItemTypeAggregate;
 | 
| -
 | 
| -  SecItemImportExportKeyParameters params;
 | 
| -  memset(¶ms, 0, sizeof(params));
 | 
| -  params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
 | 
| -  params.flags = kSecKeyNoAccessControl;
 | 
| -  params.passphrase = password;
 | 
| -
 | 
| -  CFArrayRef items = NULL;
 | 
| -  status = SecItemImport(
 | 
| -      cfdata, NULL, &format, &sitem_type, 0, ¶ms, NULL, &items);
 | 
| -
 | 
| -  if (status != noErr) {
 | 
| -    if (SSL_LOG_CERTS) {
 | 
| -      Log::Print("TrySecItemImport failed with: %ld, type = %d, format = %d\n",
 | 
| -          static_cast<intptr_t>(status), sitem_type, format);
 | 
| -    }
 | 
| -    return status;
 | 
| -  }
 | 
| -
 | 
| -  CFIndex items_length = (items == NULL) ? 0 : CFArrayGetCount(items);
 | 
| -  if (SSL_LOG_CERTS) {
 | 
| -    Log::Print(
 | 
| -        "TrySecItemImport succeeded, type = %d, format = %d, count = %ld\n",
 | 
| -        sitem_type, format, items_length);
 | 
| -  }
 | 
| -
 | 
| -  // Empty list indicates a decoding failure of some sort.
 | 
| -  if ((items != NULL) && (items_length == 0)) {
 | 
| -    CFRelease(items);
 | 
| -    return errSSLBadCert;
 | 
| -  }
 | 
| -
 | 
| -  status = GetKeyAndCerts(items, items_length, out_certs, out_key);
 | 
| -  CFRelease(items);
 | 
| -  return status;
 | 
| -}
 | 
| -
 | 
| -
 | 
| -static char* TempKeychainPath() {
 | 
| -  const char* exes = "keychaindir.XXXX";
 | 
| -  const char* fname = "keychain";
 | 
| -  const char* temp_dir = getenv("TMPDIR");
 | 
| -  if (temp_dir == NULL) {
 | 
| -    temp_dir = getenv("TMP");
 | 
| -  }
 | 
| -  if (temp_dir == NULL) {
 | 
| -    temp_dir = "/tmp/";
 | 
| -  }
 | 
| -  ASSERT(temp_dir != NULL);
 | 
| -
 | 
| -  TextBuffer path(PATH_MAX);
 | 
| -  path.Printf("%s/%s", temp_dir, exes);
 | 
| -  char* ret = mkdtemp(path.buf());
 | 
| -  ASSERT(ret != NULL);
 | 
| -  path.Printf("/%s", fname);
 | 
| -
 | 
| -  char* result =
 | 
| -      reinterpret_cast<char*>(Dart_ScopeAllocate(path.length() + 1));
 | 
| -  return strncpy(result, path.buf(), path.length() + 1);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -static OSStatus CreateKeychain(SecKeychainRef* keychain) {
 | 
| -  ASSERT(keychain != NULL);
 | 
| -  OSStatus status = noErr;
 | 
| -  const char* temp_keychain_pwd = "dartdart";
 | 
| -  char* temp_file_path = TempKeychainPath();
 | 
| -  ASSERT(temp_file_path != NULL);
 | 
| -  if (SSL_LOG_CERTS) {
 | 
| -    Log::Print("Temporary keychain at: '%s'\n", temp_file_path);
 | 
| -  }
 | 
| -  status = SecKeychainCreate(temp_file_path,
 | 
| -                             strlen(temp_keychain_pwd) + 1,
 | 
| -                             reinterpret_cast<const void*>(temp_keychain_pwd),
 | 
| -                             FALSE,  // Prompt user? Definitely no.
 | 
| -                             NULL,  // Default access rights.
 | 
| -                             keychain);
 | 
| -  if (status != noErr) {
 | 
| -    return status;
 | 
| -  }
 | 
| -  ASSERT(*keychain != NULL);
 | 
| -  return status;
 | 
| -}
 | 
| -
 | 
| -
 | 
| -static OSStatus TryPKCS12Import(CFDataRef cfdata,
 | 
| -                                CFStringRef password,
 | 
| -                                CFArrayRef* out_certs,
 | 
| -                                SecKeyRef* out_key,
 | 
| -                                SecKeychainRef* out_keychain) {
 | 
| -  OSStatus status = noErr;
 | 
| -
 | 
| -  SecExternalFormat format = kSecFormatPKCS12;
 | 
| -  SecExternalItemType sitem_type = kSecItemTypeAggregate;
 | 
| -
 | 
| -  SecItemImportExportKeyParameters params;
 | 
| -  memset(¶ms, 0, sizeof(params));
 | 
| -  params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
 | 
| -  params.flags = kSecKeyNoAccessControl;
 | 
| -  params.passphrase = password;
 | 
| -
 | 
| -  CFArrayRef items = NULL;
 | 
| -  if (SSL_LOG_CERTS) {
 | 
| -    Log::Print("Trying PKCS12 import with: type = %d, format = %d\n",
 | 
| -        sitem_type, format);
 | 
| -  }
 | 
| -
 | 
| -  // The documentation for SecKeychainItemImport here:
 | 
| -  //
 | 
| -  // https://developer.apple.com/library/mac/documentation/Security/Reference/keychainservices/index.html
 | 
| -  //
 | 
| -  // states that when the SecKeychainRef argument is NULL, the CFArrayRef*
 | 
| -  // argument will be populated by an array containing all keys, identities,
 | 
| -  // and certificates from the data in the CFDataRef argument.
 | 
| -  //
 | 
| -  // Unfortunately, this is not true. The code to populate the CFArrayRef with
 | 
| -  // keys and identities from PKCS12 data has been skipped and/or commented out,
 | 
| -  // here:
 | 
| -  //
 | 
| -  // https://github.com/Apple-FOSS-Mirror/Security/blob/master/libsecurity_keychain/lib/SecImportExportAgg.cpp#L636
 | 
| -  //
 | 
| -  // as "floating" SecKeyRefs from the PKCS12 decoder haven't been implemented.
 | 
| -  // That is, each private key instance coming from the PKCS12 decoder has to be
 | 
| -  // associated with a keychain instance. Thus, as a workaround, we create a
 | 
| -  // temporary keychain here if one is needed, and stash it below in a
 | 
| -  // SecurityContext. This has the drawbacks:
 | 
| -  // 1.) We need to make a temporary directory to hold the keychain file, and
 | 
| -  // 2.) SecKeychainItemImport() probably does blocking IO to create and
 | 
| -  //     manipulate the keychain file.
 | 
| -  // So if the API is updated, this keychain should not be used.
 | 
| -  SecKeychainRef keychain = NULL;
 | 
| -  if (out_key != NULL) {
 | 
| -    ASSERT(out_keychain != NULL);
 | 
| -    status = CreateKeychain(&keychain);
 | 
| -    if (status != noErr) {
 | 
| -      return status;
 | 
| -    }
 | 
| -    *out_keychain = keychain;
 | 
| -  }
 | 
| -
 | 
| -  status = SecItemImport(
 | 
| -      cfdata, NULL, &format, &sitem_type, 0, ¶ms, keychain, &items);
 | 
| -  if (status != noErr) {
 | 
| -    if (SSL_LOG_CERTS) {
 | 
| -      Log::Print("TrySecItemImport failed with: %ld, it = %d, format = %d\n",
 | 
| -          static_cast<intptr_t>(status), sitem_type, format);
 | 
| -    }
 | 
| -    return status;
 | 
| -  }
 | 
| -
 | 
| -  CFIndex items_length = (items == NULL) ? 0 : CFArrayGetCount(items);
 | 
| -  if (SSL_LOG_CERTS) {
 | 
| -    Log::Print("TrySecItemImport succeeded, count = %ld\n", items_length);
 | 
| -  }
 | 
| -
 | 
| -  // Empty list indicates a decoding failure of some sort.
 | 
| -  if ((items != NULL) && (items_length == 0)) {
 | 
| -    CFRelease(items);
 | 
| -    return errSSLBadCert;
 | 
| -  }
 | 
| -
 | 
| -  status = GetKeyAndCerts(items, items_length, out_certs, out_key);
 | 
| -  CFRelease(items);
 | 
| -  return status;
 | 
| -}
 | 
| -
 | 
| -
 | 
| -static OSStatus ExtractSecItems(uint8_t* buffer,
 | 
| -                                intptr_t length,
 | 
| -                                const char* password,
 | 
| -                                CFArrayRef* out_certs,
 | 
| -                                SecKeyRef* out_key,
 | 
| -                                SecKeychainRef* out_keychain) {
 | 
| -  ASSERT(buffer != NULL);
 | 
| -  ASSERT(password != NULL);
 | 
| -  OSStatus status = noErr;
 | 
| -
 | 
| -  CFDataRef cfdata = CFDataCreateWithBytesNoCopy(
 | 
| -      NULL, buffer, length, kCFAllocatorNull);
 | 
| -  CFStringRef cfpassword = CFStringCreateWithCStringNoCopy(
 | 
| -      NULL, password, kCFStringEncodingUTF8, kCFAllocatorNull);
 | 
| -  ASSERT(cfdata != NULL);
 | 
| -  ASSERT(cfpassword != NULL);
 | 
| -
 | 
| -  status = TryPEMImport(cfdata, cfpassword, out_certs, out_key);
 | 
| -  if (status != noErr) {
 | 
| -    status =
 | 
| -        TryPKCS12Import(cfdata, cfpassword, out_certs, out_key, out_keychain);
 | 
| -  }
 | 
| -
 | 
| -  CFRelease(cfdata);
 | 
| -  CFRelease(cfpassword);
 | 
| -  return status;
 | 
| -}
 | 
| -
 | 
| -
 | 
|  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.
 | 
| @@ -843,8 +357,7 @@ void FUNCTION_NAME(SecureSocket_RegisterBadCertificateCallback)(
 | 
|  }
 | 
|  
 | 
|  
 | 
| -void FUNCTION_NAME(SecureSocket_PeerCertificate)
 | 
| -    (Dart_NativeArguments args) {
 | 
| +void FUNCTION_NAME(SecureSocket_PeerCertificate)(Dart_NativeArguments args) {
 | 
|    Dart_SetReturnValue(args, GetFilter(args)->PeerCertificate());
 | 
|  }
 | 
|  
 | 
| @@ -868,62 +381,15 @@ void FUNCTION_NAME(SecurityContext_Allocate)(Dart_NativeArguments args) {
 | 
|  
 | 
|  void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)(
 | 
|      Dart_NativeArguments args) {
 | 
| -  SSLCertContext* context = GetSecurityContext(args);
 | 
| -  const char* password = GetPasswordArgument(args, 2);
 | 
| -
 | 
| -  OSStatus status;
 | 
| -  SecKeyRef key = NULL;
 | 
| -  SecKeychainRef keychain = NULL;
 | 
| -  {
 | 
| -    ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1)));
 | 
| -    status = ExtractSecItems(
 | 
| -        buffer.get(), buffer.length(), password, NULL, &key, &keychain);
 | 
| -  }
 | 
| -
 | 
| -  // Set the context fields. If there's a failure, release the items.
 | 
| -  bool set_failure = false;
 | 
| -  if ((key != NULL) && !context->set_private_key(key)) {
 | 
| -    CFRelease(key);
 | 
| -    SecKeychainDelete(keychain);
 | 
| -    CFRelease(keychain);
 | 
| -    set_failure = true;
 | 
| -  }
 | 
| -  if (!set_failure && (keychain != NULL) && !context->set_keychain(keychain)) {
 | 
| -    SecKeychainDelete(keychain);
 | 
| -    CFRelease(keychain);
 | 
| -  }
 | 
| -
 | 
| -  if (set_failure) {
 | 
| -    Dart_ThrowException(DartUtils::NewDartArgumentError(
 | 
| -        "usePrivateKeyBytes has already been called on the given context."));
 | 
| -  }
 | 
| -  CheckStatus(status, "TlsException", "Failure in usePrivateKeyBytes");
 | 
| +  Dart_ThrowException(DartUtils::NewDartUnsupportedError(
 | 
| +      "SecurityContext.usePrivateKeyBytes is not yet implemented."));
 | 
|  }
 | 
|  
 | 
|  
 | 
|  void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)(
 | 
|      Dart_NativeArguments args) {
 | 
| -  SSLCertContext* context = GetSecurityContext(args);
 | 
| -  const char* password = GetPasswordArgument(args, 2);
 | 
| -
 | 
| -  OSStatus status;
 | 
| -  CFArrayRef certs = NULL;
 | 
| -  {
 | 
| -    ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1)));
 | 
| -    status = ExtractSecItems(
 | 
| -        buffer.get(), buffer.length(), password, &certs, NULL, NULL);
 | 
| -  }
 | 
| -
 | 
| -  // Set the field in the context. If there's a failure, release the certs,
 | 
| -  // and throw an exception.
 | 
| -  if ((certs != NULL) && !context->set_trusted_certs(certs)) {
 | 
| -    CFRelease(certs);
 | 
| -    Dart_ThrowException(DartUtils::NewDartArgumentError(
 | 
| -        "setTrustedCertificatesBytes has already been called "
 | 
| -        "on the given context."));
 | 
| -  }
 | 
| -
 | 
| -  CheckStatus(status, "TlsException", "Failure in setTrustedCertificatesBytes");
 | 
| +  Dart_ThrowException(DartUtils::NewDartUnsupportedError(
 | 
| +      "SecurityContext.setTrustedCertificatesBytes is not yet implemented."));
 | 
|  }
 | 
|  
 | 
|  
 | 
| @@ -941,53 +407,15 @@ void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)(
 | 
|  
 | 
|  void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)(
 | 
|      Dart_NativeArguments args) {
 | 
| -  SSLCertContext* context = GetSecurityContext(args);
 | 
| -
 | 
| -  const char* password = GetPasswordArgument(args, 2);
 | 
| -  OSStatus status;
 | 
| -  CFArrayRef certs = NULL;
 | 
| -  {
 | 
| -    ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1)));
 | 
| -    status = ExtractSecItems(
 | 
| -        buffer.get(), buffer.length(), password, &certs, NULL, NULL);
 | 
| -  }
 | 
| -
 | 
| -  // Set the field in the context. If there's a failure, release the certs,
 | 
| -  // and throw an exception.
 | 
| -  if ((certs != NULL) && !context->set_cert_chain(certs)) {
 | 
| -    CFRelease(certs);
 | 
| -    Dart_ThrowException(DartUtils::NewDartArgumentError(
 | 
| -        "useCertificateChainBytes has already been called "
 | 
| -        "on the given context."));
 | 
| -  }
 | 
| -
 | 
| -  CheckStatus(status, "TlsException", "Failure in useCertificateChainBytes");
 | 
| +  Dart_ThrowException(DartUtils::NewDartUnsupportedError(
 | 
| +      "SecurityContext.useCertificateChainBytes is not yet implemented."));
 | 
|  }
 | 
|  
 | 
|  
 | 
|  void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)(
 | 
|      Dart_NativeArguments args) {
 | 
| -  SSLCertContext* context = GetSecurityContext(args);
 | 
| -  const char* password = GetPasswordArgument(args, 2);
 | 
| -
 | 
| -  OSStatus status;
 | 
| -  CFArrayRef certs = NULL;
 | 
| -  {
 | 
| -    ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1)));
 | 
| -    status = ExtractSecItems(
 | 
| -        buffer.get(), buffer.length(), password, &certs, NULL, NULL);
 | 
| -  }
 | 
| -
 | 
| -  // Set the field in the context. If there's a failure, release the certs,
 | 
| -  // and throw an exception.
 | 
| -  if ((certs != NULL) && !context->set_cert_authorities(certs)) {
 | 
| -    CFRelease(certs);
 | 
| -    Dart_ThrowException(DartUtils::NewDartArgumentError(
 | 
| -        "setClientAuthoritiesBytes has already been called "
 | 
| -        "on the given context."));
 | 
| -  }
 | 
| -
 | 
| -  CheckStatus(status, "TlsException", "Failure in setClientAuthoritiesBytes");
 | 
| +  Dart_ThrowException(DartUtils::NewDartUnsupportedError(
 | 
| +      "SecurityContext.setClientAuthoritiesBytes is not yet implemented."));
 | 
|  }
 | 
|  
 | 
|  
 | 
| @@ -998,128 +426,27 @@ void FUNCTION_NAME(SecurityContext_SetAlpnProtocols)(
 | 
|  }
 | 
|  
 | 
|  
 | 
| -static char* GetNameFromCert(SecCertificateRef certificate,
 | 
| -                             CFTypeRef field,
 | 
| -                             CFStringRef name) {
 | 
| -  char* issuer_name = NULL;
 | 
| -
 | 
| -  CFTypeRef keys[] = { field };
 | 
| -  CFArrayRef key_array = CFArrayCreate(NULL, keys, 1, &kCFTypeArrayCallBacks);
 | 
| -  CFErrorRef error = NULL;
 | 
| -  CFDictionaryRef cert_dict =
 | 
| -      SecCertificateCopyValues(certificate, key_array, &error);
 | 
| -  if (cert_dict == NULL) {
 | 
| -    CFRelease(key_array);
 | 
| -    Dart_ThrowException(DartUtils::NewDartArgumentError(
 | 
| -        "X509.issuer failed to copy issuer field out of certificate"));
 | 
| -  }
 | 
| -
 | 
| -  CFTypeRef item = CFDictionaryGetValue(cert_dict, keys[0]);
 | 
| -  ASSERT(CFGetTypeID(item) == CFDictionaryGetTypeID());
 | 
| -  CFDictionaryRef val_dict = reinterpret_cast<CFDictionaryRef>(item);
 | 
| -
 | 
| -  item = CFDictionaryGetValue(val_dict, kSecPropertyKeyValue);
 | 
| -  ASSERT(CFGetTypeID(item) == CFArrayGetTypeID());
 | 
| -  CFArrayRef val_array = reinterpret_cast<CFArrayRef>(item);
 | 
| -
 | 
| -  for (intptr_t i = 0; i < CFArrayGetCount(val_array); i++) {
 | 
| -    item = CFArrayGetValueAtIndex(val_array, i);
 | 
| -    ASSERT(CFGetTypeID(item) == CFDictionaryGetTypeID());
 | 
| -    CFDictionaryRef val_dict2 = reinterpret_cast<CFDictionaryRef>(item);
 | 
| -
 | 
| -    item = CFDictionaryGetValue(val_dict2, kSecPropertyKeyLabel);
 | 
| -    ASSERT(CFGetTypeID(item) == CFStringGetTypeID());
 | 
| -    CFStringRef label = reinterpret_cast<CFStringRef>(item);
 | 
| -
 | 
| -    if (CFStringCompare(label, name, 0) == kCFCompareEqualTo) {
 | 
| -      item = CFDictionaryGetValue(val_dict2, kSecPropertyKeyValue);
 | 
| -      ASSERT(CFGetTypeID(item) == CFStringGetTypeID());
 | 
| -      CFStringRef value = reinterpret_cast<CFStringRef>(item);
 | 
| -      issuer_name = CFStringRefToCString(value);
 | 
| -      break;
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  CFRelease(cert_dict);
 | 
| -  CFRelease(key_array);
 | 
| -  return issuer_name;
 | 
| -}
 | 
| -
 | 
| -
 | 
|  void FUNCTION_NAME(X509_Subject)(Dart_NativeArguments args) {
 | 
| -  SecCertificateRef certificate = GetX509Certificate(args);
 | 
| -  char* subject_name = GetNameFromCert(
 | 
| -      certificate,
 | 
| -      kSecOIDX509V1SubjectName,
 | 
| -      reinterpret_cast<CFStringRef>(kSecOIDCommonName));
 | 
| -  if (subject_name == NULL) {
 | 
| -    Dart_ThrowException(DartUtils::NewDartArgumentError(
 | 
| -        "X509.subject failed to find issuer's common name."));
 | 
| -  } else {
 | 
| -    Dart_SetReturnValue(args, Dart_NewStringFromCString(subject_name));
 | 
| -  }
 | 
| +  Dart_ThrowException(DartUtils::NewDartUnsupportedError(
 | 
| +      "X509Certificate.subject is not yet implemented."));
 | 
|  }
 | 
|  
 | 
|  
 | 
|  void FUNCTION_NAME(X509_Issuer)(Dart_NativeArguments args) {
 | 
| -  SecCertificateRef certificate = GetX509Certificate(args);
 | 
| -  char* issuer_name = GetNameFromCert(
 | 
| -      certificate,
 | 
| -      kSecOIDX509V1IssuerName,
 | 
| -      reinterpret_cast<CFStringRef>(kSecOIDCommonName));
 | 
| -  if (issuer_name == NULL) {
 | 
| -    Dart_ThrowException(DartUtils::NewDartArgumentError(
 | 
| -        "X509.issuer failed to find issuer's common name."));
 | 
| -  } else {
 | 
| -    Dart_SetReturnValue(args, Dart_NewStringFromCString(issuer_name));
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -
 | 
| -// Returns the number of seconds since the epoch from 'field'.
 | 
| -static int64_t GetTimeFromCert(SecCertificateRef certificate, CFTypeRef field) {
 | 
| -  CFTypeRef keys[] = { field };
 | 
| -  CFArrayRef key_array = CFArrayCreate(NULL, keys, 1, &kCFTypeArrayCallBacks);
 | 
| -  CFErrorRef error = NULL;
 | 
| -  CFDictionaryRef cert_dict =
 | 
| -      SecCertificateCopyValues(certificate, key_array, &error);
 | 
| -  if (cert_dict == NULL) {
 | 
| -    CFRelease(key_array);
 | 
| -    Dart_ThrowException(DartUtils::NewDartArgumentError(
 | 
| -        "X509.startValidity: failed to copy issuer field out of certificate"));
 | 
| -  }
 | 
| -
 | 
| -  CFTypeRef item = CFDictionaryGetValue(cert_dict, keys[0]);
 | 
| -  ASSERT(CFGetTypeID(item) == CFDictionaryGetTypeID());
 | 
| -  CFDictionaryRef val_dict = reinterpret_cast<CFDictionaryRef>(item);
 | 
| -
 | 
| -  item = CFDictionaryGetValue(val_dict, kSecPropertyKeyValue);
 | 
| -  ASSERT(CFGetTypeID(item) == CFNumberGetTypeID());
 | 
| -  CFNumberRef date_number = reinterpret_cast<CFNumberRef>(item);
 | 
| -
 | 
| -  CFAbsoluteTime date_abs_time;
 | 
| -  CFNumberGetValue(date_number, kCFNumberDoubleType, &date_abs_time);
 | 
| -  CFAbsoluteTime seconds_since_epoch =
 | 
| -      date_abs_time + kCFAbsoluteTimeIntervalSince1970;
 | 
| -  return static_cast<int64_t>(seconds_since_epoch) * 1000LL;
 | 
| +  Dart_ThrowException(DartUtils::NewDartUnsupportedError(
 | 
| +      "X509Certificate.issuer is not supported on this platform."));
 | 
|  }
 | 
|  
 | 
|  
 | 
|  void FUNCTION_NAME(X509_StartValidity)(Dart_NativeArguments args) {
 | 
| -  SecCertificateRef certificate = GetX509Certificate(args);
 | 
| -  int64_t seconds_since_epoch = GetTimeFromCert(certificate,
 | 
| -                                                kSecOIDX509V1ValidityNotBefore);
 | 
| -  Dart_SetReturnValue(args,
 | 
| -      Dart_NewInteger(static_cast<int64_t>(seconds_since_epoch) * 1000LL));
 | 
| +  Dart_ThrowException(DartUtils::NewDartUnsupportedError(
 | 
| +      "X509Certificate.startValidity is not supported on this platform."));
 | 
|  }
 | 
|  
 | 
|  
 | 
|  void FUNCTION_NAME(X509_EndValidity)(Dart_NativeArguments args) {
 | 
| -  SecCertificateRef certificate = GetX509Certificate(args);
 | 
| -  int64_t seconds_since_epoch = GetTimeFromCert(certificate,
 | 
| -                                                kSecOIDX509V1ValidityNotAfter);
 | 
| -  Dart_SetReturnValue(args,
 | 
| -      Dart_NewInteger(static_cast<int64_t>(seconds_since_epoch) * 1000LL));
 | 
| +    Dart_ThrowException(DartUtils::NewDartUnsupportedError(
 | 
| +      "X509Certificate.endValidity is not supported on this platform."));
 | 
|  }
 | 
|  
 | 
|  
 | 
| @@ -1164,16 +491,8 @@ CObject* SSLFilter::ProcessFilterRequest(const CObjectArray& request) {
 | 
|      return result;
 | 
|    } else {
 | 
|      TextBuffer status_message(SSL_ERROR_MESSAGE_BUFFER_SIZE);
 | 
| -    CFStringRef error_string = SecCopyErrorMessageString(status, NULL);
 | 
| -    if (error_string == NULL) {
 | 
| -      status_message.Printf("OSStatus = %ld: https://www.osstatus.com",
 | 
| -          static_cast<intptr_t>(status));
 | 
| -    } else {
 | 
| -      char* error = CFStringRefToCString(error_string);
 | 
| -      status_message.Printf("OSStatus = %ld: %s",
 | 
| -          static_cast<intptr_t>(status), error);
 | 
| -      CFRelease(error_string);
 | 
| -    }
 | 
| +    status_message.Printf("OSStatus = %ld: https://www.osstatus.com",
 | 
| +        static_cast<intptr_t>(status));
 | 
|      CObjectArray* result = new CObjectArray(CObject::NewArray(2));
 | 
|      result->SetAt(0, new CObjectInt32(CObject::NewInt32(status)));
 | 
|      result->SetAt(1, new CObjectString(CObject::NewString(
 | 
| @@ -1519,38 +838,6 @@ void SSLFilter::Connect(Dart_Handle dart_this,
 | 
|        "TlsException",
 | 
|        "Failed to set minimum protocol version to kTLSProtocol1");
 | 
|  
 | 
| -  // If the context has a private key and certificate chain, combine the
 | 
| -  // private key and first certificate into a SecIdentityRef, and place that
 | 
| -  // and the remaining certs in an array to pass to SSLSetCertificate().
 | 
| -  if ((context->private_key() != NULL) && (context->cert_chain() != NULL)) {
 | 
| -    CFIndex chain_length = CFArrayGetCount(context->cert_chain());
 | 
| -    CFMutableArrayRef certs =
 | 
| -        CFArrayCreateMutable(NULL, chain_length, &kCFTypeArrayCallBacks);
 | 
| -    CFTypeRef item = CFArrayGetValueAtIndex(context->cert_chain(), 0);
 | 
| -    ASSERT(CFGetTypeID(item) == SecCertificateGetTypeID());
 | 
| -    SecCertificateRef first_cert =
 | 
| -        reinterpret_cast<SecCertificateRef>(const_cast<void*>(item));
 | 
| -    SecIdentityRef identity =
 | 
| -        SecIdentityCreate(NULL, first_cert, context->private_key());
 | 
| -    CFArrayAppendValue(certs, identity);
 | 
| -    for (CFIndex i = 0; i < chain_length; i++) {
 | 
| -      CFArrayAppendValue(certs,
 | 
| -                         CFArrayGetValueAtIndex(context->cert_chain(), i));
 | 
| -    }
 | 
| -    CFRelease(identity);
 | 
| -    status = SSLSetCertificate(ssl_context, certs);
 | 
| -    CFRelease(certs);
 | 
| -    CheckStatus(status, "TlsException", "SSLSetCertificate failed");
 | 
| -  }
 | 
| -
 | 
| -  if (context->cert_authorities() != NULL) {
 | 
| -    status = SSLSetCertificateAuthorities(
 | 
| -        ssl_context, context->cert_authorities(), true);
 | 
| -    CheckStatus(status,
 | 
| -        "TlsException",
 | 
| -        "Failed to set certificate authorities");
 | 
| -  }
 | 
| -
 | 
|    if (is_server) {
 | 
|      SSLAuthenticate auth =
 | 
|          require_client_certificate
 | 
| @@ -1611,12 +898,8 @@ OSStatus SSLFilter::EvaluatePeerTrust() {
 | 
|      return status;
 | 
|    }
 | 
|  
 | 
| -  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);
 | 
| -  }
 | 
| +  CFArrayRef trusted_certs =
 | 
| +      CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
 | 
|  
 | 
|    status = SecTrustSetAnchorCertificates(peer_trust, trusted_certs);
 | 
|    if (status != noErr) {
 | 
| @@ -2022,7 +1305,6 @@ OSStatus SSLFilter::ProcessWritePlaintextBuffer(intptr_t start,
 | 
|  }  // namespace bin
 | 
|  }  // namespace dart
 | 
|  
 | 
| -#endif  // defined(TARGET_OS_MACOS)
 | 
| +#endif  // TARGET_OS_IOS
 | 
|  
 | 
| -#endif  // !defined(DART_IO_DISABLED) &&
 | 
| -        // !defined(DART_IO_SECURE_SOCKET_DISABLED)
 | 
| +#endif  // !defined(DART_IO_SECURE_SOCKET_DISABLED)
 | 
| 
 |