Chromium Code Reviews| Index: runtime/bin/security_context_macos.cc |
| diff --git a/runtime/bin/security_context_macos.cc b/runtime/bin/security_context_macos.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..74178bbd41c4c5222b394c6b8d254be2a32fbaa3 |
| --- /dev/null |
| +++ b/runtime/bin/security_context_macos.cc |
| @@ -0,0 +1,180 @@ |
| +// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| +// for details. All rights reserved. Use of this source code is governed by a |
| +// BSD-style license that can be found in the LICENSE file. |
| + |
| +#if !defined(DART_IO_DISABLED) && !defined(DART_IO_SECURE_SOCKET_DISABLED) |
| + |
| +#include "platform/globals.h" |
| +#if defined(HOST_OS_MACOS) |
| + |
| +#include "bin/security_context.h" |
| + |
| +#include <CoreFoundation/CoreFoundation.h> |
| +#include <Security/SecureTransport.h> |
| +#include <Security/Security.h> |
| + |
| +#include <openssl/ssl.h> |
| +#include <openssl/x509.h> |
| + |
| +#include "bin/secure_socket.h" |
| + |
| +namespace dart { |
| +namespace bin { |
| + |
| +const intptr_t SSLCertContext::kApproximateSize = sizeof(SSLCertContext); |
| + |
| +const char* commandline_root_certs_file = NULL; |
| +const char* commandline_root_certs_cache = NULL; |
| + |
| +SecCertificateRef CreateSecCertificateFromX509(X509* cert) { |
| + if (cert == NULL) { |
| + return NULL; |
| + } |
| + unsigned char* deb_cert = NULL; |
| + int length = i2d_X509(cert, &deb_cert); |
| + if (length < 0) { |
| + return 0; |
| + } |
| + ASSERT(deb_cert != NULL); |
| + CFDataRef cert_buf = |
| + CFDataCreateWithBytesNoCopy(NULL, deb_cert, length, kCFAllocatorNull); |
| + SecCertificateRef auth_cert = SecCertificateCreateWithData(NULL, cert_buf); |
| + if (auth_cert == NULL) { |
| + return NULL; |
| + } |
| + return auth_cert; |
| +} |
| + |
| + |
| +static int CertificateVerificationCallback(X509_STORE_CTX* ctx, void* arg) { |
| + SSLCertContext* context = static_cast<SSLCertContext*>(arg); |
| + |
| + // Convert BoringSSL formatted certificates to SecCertificate certificates. |
| + CFMutableArrayRef cert_chain = NULL; |
| + X509* root_cert = NULL; |
| + if (ctx->untrusted != NULL) { |
| + STACK_OF(X509)* user_provided_certs = ctx->untrusted; |
| + int num_certs = sk_X509_num(user_provided_certs); |
| + int current_cert = 0; |
| + cert_chain = CFArrayCreateMutable(NULL, num_certs, NULL); |
| + X509* ca; |
| + while ((ca = sk_X509_shift(user_provided_certs)) != NULL) { |
| + SecCertificateRef cert = CreateSecCertificateFromX509(ca); |
| + if (cert == NULL) { |
| + CFRelease(cert_chain); |
| + return ctx->verify_cb(0, ctx); |
| + } |
| + CFArrayAppendValue(cert_chain, cert); |
| + ++current_cert; |
| + |
| + if (current_cert == num_certs) { |
| + root_cert = ca; |
| + } |
| + } |
| + } |
| + |
| + // Convert all trusted certificates provided by the user via |
| + // setTrustedCertificatesBytes or the command line into SecCertificates. |
| + CFMutableArrayRef trusted_certs = CFArrayCreateMutable(NULL, 0, NULL); |
| + X509_STORE* store = ctx->ctx; |
| + ASSERT(store != NULL); |
| + |
| + if (store->objs != NULL) { |
| + for (uintptr_t i = 0; i < sk_X509_OBJECT_num(store->objs); ++i) { |
| + X509* ca = sk_X509_OBJECT_value(store->objs, i)->data.x509; |
| + SecCertificateRef cert = CreateSecCertificateFromX509(ca); |
| + if (cert == NULL) { |
| + CFRelease(trusted_certs); |
| + return ctx->verify_cb(0, ctx); |
| + } |
| + CFArrayAppendValue(trusted_certs, cert); |
| + } |
| + } |
| + |
| + // Generate a generic X509 verification policy. |
| + SecPolicyRef policy = SecPolicyCreateBasicX509(); |
| + |
| + // Create the trust object with the certificates provided by the user. |
| + SecTrustRef trust = NULL; |
| + OSStatus status = SecTrustCreateWithCertificates(cert_chain, policy, &trust); |
| + if (status != noErr) { |
| + CFRelease(cert_chain); |
| + CFRelease(policy); |
|
zra
2017/06/02 22:56:24
Maybe a scope class would be useful here so that w
bkonyi
2017/06/05 20:25:52
Done.
|
| + return ctx->verify_cb(0, ctx); |
| + } |
| + |
| + // If the user provided any additional CA certificates, add them to the trust |
| + // object. |
| + if (CFArrayGetCount(trusted_certs) > 0) { |
| + status = SecTrustSetAnchorCertificates(trust, trusted_certs); |
| + if (status != noErr) { |
| + CFRelease(cert_chain); |
| + CFRelease(policy); |
| + CFRelease(trust); |
| + return ctx->verify_cb(0, ctx); |
| + } |
| + } |
| + |
| + // Specify whether or not to use the built-in CA certificates for |
| + // verification. |
| + status = SecTrustSetAnchorCertificatesOnly(trust, !context->trust_builtin()); |
| + if (status != noErr) { |
| + CFRelease(cert_chain); |
| + CFRelease(policy); |
| + CFRelease(trust); |
| + return ctx->verify_cb(0, ctx); |
| + } |
| + |
| + // Perform the certificate verification. |
| + SecTrustResultType trust_result; |
| + status = SecTrustEvaluate(trust, &trust_result); |
| + if (status != noErr) { |
| + CFRelease(cert_chain); |
| + CFRelease(policy); |
| + CFRelease(trust); |
| + return ctx->verify_cb(0, ctx); |
| + } |
| + |
| + CFRelease(cert_chain); |
| + CFRelease(policy); |
| + CFRelease(trust); |
| + |
| + if ((trust_result == kSecTrustResultProceed) || |
| + (trust_result == kSecTrustResultUnspecified)) { |
| + // Successfully verified certificate! |
| + return ctx->verify_cb(1, ctx); |
| + } |
| + |
| + // Set current_cert to the root of the certificate chain. This will be passed |
| + // to the callback provided by the user for additional verification steps. |
| + ctx->current_cert = root_cert; |
| + return ctx->verify_cb(0, ctx); |
| +} |
| + |
| + |
| +void SSLFilter::RegisterCallbacks(SSLCertContext* cert_ctx) { |
| + SSL_CTX* ctx = SSL_get_SSL_CTX(ssl_); |
| + SSL_CTX_set_cert_verify_callback(ctx, CertificateVerificationCallback, |
| + cert_ctx); |
| +} |
| + |
| + |
| +void SSLCertContext::TrustBuiltinRoots() { |
| + // First, try to use locations specified on the command line. |
| + if (commandline_root_certs_file != NULL) { |
| + LoadRootCertFile(commandline_root_certs_file); |
| + return; |
| + } |
| + if (commandline_root_certs_cache != NULL) { |
| + LoadRootCertCache(commandline_root_certs_cache); |
| + return; |
| + } |
| + set_trust_builtin(true); |
| +} |
| + |
| +} // namespace bin |
| +} // namespace dart |
| + |
| +#endif // defined(HOST_OS_MACOS) |
| +#endif // !defined(DART_IO_DISABLED) && |
| + // !defined(DART_IO_SECURE_SOCKET_DISABLED) |