| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2017 the Dart project authors. Please see the AUTHORS file |
| 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. |
| 4 |
| 5 #if !defined(DART_IO_DISABLED) && !defined(DART_IO_SECURE_SOCKET_DISABLED) |
| 6 |
| 7 #include "platform/globals.h" |
| 8 #if defined(HOST_OS_MACOS) |
| 9 |
| 10 #include "bin/security_context.h" |
| 11 |
| 12 #include <CoreFoundation/CoreFoundation.h> |
| 13 #include <Security/SecureTransport.h> |
| 14 #include <Security/Security.h> |
| 15 |
| 16 #include <openssl/ssl.h> |
| 17 #include <openssl/x509.h> |
| 18 |
| 19 #include "bin/secure_socket_filter.h" |
| 20 |
| 21 namespace dart { |
| 22 namespace bin { |
| 23 |
| 24 const intptr_t SSLCertContext::kApproximateSize = sizeof(SSLCertContext); |
| 25 |
| 26 const char* commandline_root_certs_file = NULL; |
| 27 const char* commandline_root_certs_cache = NULL; |
| 28 |
| 29 template <typename T> |
| 30 class ScopedCFType { |
| 31 public: |
| 32 explicit ScopedCFType(T obj) : obj_(obj) {} |
| 33 |
| 34 ~ScopedCFType() { CFRelease(obj_); } |
| 35 |
| 36 T get() { return obj_; } |
| 37 T* ptr() { return &obj_; } |
| 38 const T get() const { return obj_; } |
| 39 |
| 40 void set(T obj) { obj_ = obj; } |
| 41 |
| 42 private: |
| 43 T obj_; |
| 44 |
| 45 DISALLOW_ALLOCATION(); |
| 46 DISALLOW_COPY_AND_ASSIGN(ScopedCFType); |
| 47 }; |
| 48 |
| 49 typedef ScopedCFType<CFMutableArrayRef> ScopedCFMutableArrayRef; |
| 50 typedef ScopedCFType<CFDataRef> ScopedCFDataRef; |
| 51 typedef ScopedCFType<SecPolicyRef> ScopedSecPolicyRef; |
| 52 typedef ScopedCFType<SecCertificateRef> ScopedSecCertificateRef; |
| 53 typedef ScopedCFType<SecTrustRef> ScopedSecTrustRef; |
| 54 |
| 55 static SecCertificateRef CreateSecCertificateFromX509(X509* cert) { |
| 56 if (cert == NULL) { |
| 57 return NULL; |
| 58 } |
| 59 unsigned char* deb_cert = NULL; |
| 60 int length = i2d_X509(cert, &deb_cert); |
| 61 if (length < 0) { |
| 62 return 0; |
| 63 } |
| 64 ASSERT(deb_cert != NULL); |
| 65 ScopedCFDataRef cert_buf( |
| 66 CFDataCreateWithBytesNoCopy(NULL, deb_cert, length, kCFAllocatorNull)); |
| 67 SecCertificateRef auth_cert = |
| 68 SecCertificateCreateWithData(NULL, cert_buf.get()); |
| 69 if (auth_cert == NULL) { |
| 70 return NULL; |
| 71 } |
| 72 return auth_cert; |
| 73 } |
| 74 |
| 75 |
| 76 static int CertificateVerificationCallback(X509_STORE_CTX* ctx, void* arg) { |
| 77 SSLCertContext* context = static_cast<SSLCertContext*>(arg); |
| 78 |
| 79 // Convert BoringSSL formatted certificates to SecCertificate certificates. |
| 80 ScopedCFMutableArrayRef cert_chain(NULL); |
| 81 X509* root_cert = NULL; |
| 82 if (ctx->untrusted != NULL) { |
| 83 STACK_OF(X509)* user_provided_certs = ctx->untrusted; |
| 84 int num_certs = sk_X509_num(user_provided_certs); |
| 85 int current_cert = 0; |
| 86 cert_chain.set(CFArrayCreateMutable(NULL, num_certs, NULL)); |
| 87 X509* ca; |
| 88 while ((ca = sk_X509_shift(user_provided_certs)) != NULL) { |
| 89 SecCertificateRef cert = CreateSecCertificateFromX509(ca); |
| 90 if (cert == NULL) { |
| 91 return ctx->verify_cb(0, ctx); |
| 92 } |
| 93 CFArrayAppendValue(cert_chain.get(), cert); |
| 94 ++current_cert; |
| 95 |
| 96 if (current_cert == num_certs) { |
| 97 root_cert = ca; |
| 98 } |
| 99 } |
| 100 } |
| 101 |
| 102 // Convert all trusted certificates provided by the user via |
| 103 // setTrustedCertificatesBytes or the command line into SecCertificates. |
| 104 ScopedCFMutableArrayRef trusted_certs(CFArrayCreateMutable(NULL, 0, NULL)); |
| 105 X509_STORE* store = ctx->ctx; |
| 106 ASSERT(store != NULL); |
| 107 |
| 108 if (store->objs != NULL) { |
| 109 for (uintptr_t i = 0; i < sk_X509_OBJECT_num(store->objs); ++i) { |
| 110 X509* ca = sk_X509_OBJECT_value(store->objs, i)->data.x509; |
| 111 SecCertificateRef cert = CreateSecCertificateFromX509(ca); |
| 112 if (cert == NULL) { |
| 113 return ctx->verify_cb(0, ctx); |
| 114 } |
| 115 CFArrayAppendValue(trusted_certs.get(), cert); |
| 116 } |
| 117 } |
| 118 |
| 119 // Generate a generic X509 verification policy. |
| 120 ScopedSecPolicyRef policy(SecPolicyCreateBasicX509()); |
| 121 |
| 122 // Create the trust object with the certificates provided by the user. |
| 123 ScopedSecTrustRef trust(NULL); |
| 124 OSStatus status = SecTrustCreateWithCertificates(cert_chain.get(), |
| 125 policy.get(), trust.ptr()); |
| 126 if (status != noErr) { |
| 127 return ctx->verify_cb(0, ctx); |
| 128 } |
| 129 |
| 130 // If the user provided any additional CA certificates, add them to the trust |
| 131 // object. |
| 132 if (CFArrayGetCount(trusted_certs.get()) > 0) { |
| 133 status = SecTrustSetAnchorCertificates(trust.get(), trusted_certs.get()); |
| 134 if (status != noErr) { |
| 135 return ctx->verify_cb(0, ctx); |
| 136 } |
| 137 } |
| 138 |
| 139 // Specify whether or not to use the built-in CA certificates for |
| 140 // verification. |
| 141 status = |
| 142 SecTrustSetAnchorCertificatesOnly(trust.get(), !context->trust_builtin()); |
| 143 if (status != noErr) { |
| 144 return ctx->verify_cb(0, ctx); |
| 145 } |
| 146 |
| 147 // Perform the certificate verification. |
| 148 SecTrustResultType trust_result; |
| 149 status = SecTrustEvaluate(trust.get(), &trust_result); |
| 150 if (status != noErr) { |
| 151 return ctx->verify_cb(0, ctx); |
| 152 } |
| 153 |
| 154 if ((trust_result == kSecTrustResultProceed) || |
| 155 (trust_result == kSecTrustResultUnspecified)) { |
| 156 // Successfully verified certificate! |
| 157 return ctx->verify_cb(1, ctx); |
| 158 } |
| 159 |
| 160 // Set current_cert to the root of the certificate chain. This will be passed |
| 161 // to the callback provided by the user for additional verification steps. |
| 162 ctx->current_cert = root_cert; |
| 163 return ctx->verify_cb(0, ctx); |
| 164 } |
| 165 |
| 166 |
| 167 void SSLCertContext::RegisterCallbacks(SSL* ssl) { |
| 168 SSL_CTX* ctx = SSL_get_SSL_CTX(ssl); |
| 169 SSL_CTX_set_cert_verify_callback(ctx, CertificateVerificationCallback, this); |
| 170 } |
| 171 |
| 172 |
| 173 void SSLCertContext::TrustBuiltinRoots() { |
| 174 // First, try to use locations specified on the command line. |
| 175 if (commandline_root_certs_file != NULL) { |
| 176 LoadRootCertFile(commandline_root_certs_file); |
| 177 return; |
| 178 } |
| 179 if (commandline_root_certs_cache != NULL) { |
| 180 LoadRootCertCache(commandline_root_certs_cache); |
| 181 return; |
| 182 } |
| 183 set_trust_builtin(true); |
| 184 } |
| 185 |
| 186 } // namespace bin |
| 187 } // namespace dart |
| 188 |
| 189 #endif // defined(HOST_OS_MACOS) |
| 190 #endif // !defined(DART_IO_DISABLED) && |
| 191 // !defined(DART_IO_SECURE_SOCKET_DISABLED) |
| OLD | NEW |