Chromium Code Reviews| 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 SecCertificateRef CreateSecCertificateFromX509(X509* cert) { | |
|
zra
2017/06/06 19:16:27
static
bkonyi
2017/06/06 19:51:39
Done.
| |
| 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 |