Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(237)

Side by Side Diff: runtime/bin/secure_socket_macos.cc

Issue 2903743002: Porting SecureSocket to use BoringSSL on OSX (Closed)
Patch Set: Fixed issues on non-Macos platforms Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #if !defined(DART_IO_DISABLED) && !defined(DART_IO_SECURE_SOCKET_DISABLED) 5 #if !defined(DART_IO_DISABLED) && !defined(DART_IO_SECURE_SOCKET_DISABLED)
6 6
7 #include "platform/globals.h" 7 #include "platform/globals.h"
8 #if defined(HOST_OS_MACOS) && !HOST_OS_IOS 8 #if defined(HOST_OS_MACOS) && !HOST_OS_IOS
9 9
10 #include "bin/secure_socket.h" 10 #include "bin/secure_socket.h"
11 #include "bin/secure_socket_macos.h" 11 #include "bin/secure_socket_macos.h"
12 #include "bin/secure_socket_utils.h"
12 13
13 #include <errno.h> 14 #include <errno.h>
14 #include <fcntl.h> 15 #include <fcntl.h>
15 #include <sys/stat.h> 16 #include <sys/stat.h>
16 #include <sys/syslimits.h> 17 #include <sys/syslimits.h>
17 #include <stdio.h> 18 #include <stdio.h>
18 #include <string.h> 19 #include <string.h>
19 20
20 #include <CoreFoundation/CoreFoundation.h> 21 #include <CoreFoundation/CoreFoundation.h>
21 #include <Security/SecureTransport.h> 22 #include <Security/SecureTransport.h>
22 #include <Security/Security.h> 23 #include <Security/Security.h>
23 24
25 #include <openssl/bio.h>
26 #include <openssl/err.h>
27 #include <openssl/pkcs12.h>
28 #include <openssl/safestack.h>
29 #include <openssl/ssl.h>
30 #include <openssl/tls1.h>
31 #include <openssl/x509.h>
32
24 #include "bin/builtin.h" 33 #include "bin/builtin.h"
25 #include "bin/dartutils.h" 34 #include "bin/dartutils.h"
26 #include "bin/lockers.h" 35 #include "bin/lockers.h"
27 #include "bin/log.h" 36 #include "bin/log.h"
28 #include "bin/socket.h" 37 #include "bin/socket.h"
29 #include "bin/thread.h" 38 #include "bin/thread.h"
30 #include "bin/utils.h" 39 #include "bin/utils.h"
31 40
32 #include "platform/text_buffer.h" 41 #include "platform/text_buffer.h"
33 #include "platform/utils.h" 42 #include "platform/utils.h"
34 43
35 #include "include/dart_api.h" 44 #include "include/dart_api.h"
36 45
37 // Return the error from the containing function if handle is an error handle.
38 #define RETURN_IF_ERROR(handle) \
39 { \
40 Dart_Handle __handle = handle; \
41 if (Dart_IsError((__handle))) { \
42 return __handle; \
43 } \
44 }
45
46 // We need to access this private API function to create a SecIdentityRef
47 // without writing a custom keychain to the filesystem. This is the approach
48 // taken in WebKit:
49 // https://webkit.googlesource.com/WebKit/+/master/Source/WebKit2/Shared/cf/Argu mentCodersCF.cpp
50 extern "C" {
51 SecIdentityRef SecIdentityCreate(CFAllocatorRef allocator,
52 SecCertificateRef certificate,
53 SecKeyRef private_key);
54 }
55
56 namespace dart { 46 namespace dart {
57 namespace bin { 47 namespace bin {
58 48
59 static const int kSSLFilterNativeFieldIndex = 0; 49 const intptr_t SSLCertContext::kApproximateSize = sizeof(SSLCertContext);
60 static const int kSecurityContextNativeFieldIndex = 0;
61 static const int kX509NativeFieldIndex = 0;
62 50
63 static const bool SSL_LOG_STATUS = false; 51 static void ReleaseCertificate(void* isolate_data,
64 static const bool SSL_LOG_DATA = false; 52 Dart_WeakPersistentHandle handle,
65 static const bool SSL_LOG_CERTS = false; 53 void* context_pointer) {
66 static const int SSL_ERROR_MESSAGE_BUFFER_SIZE = 1000; 54 SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(context_pointer);
67 static const intptr_t PEM_BUFSIZE = 1024; 55 CFRelease(cert);
56 }
57
68 58
69 static char* CFStringRefToCString(CFStringRef cfstring) { 59 static char* CFStringRefToCString(CFStringRef cfstring) {
70 CFIndex len = CFStringGetLength(cfstring); 60 CFIndex len = CFStringGetLength(cfstring);
71 CFIndex max_len = 61 CFIndex max_len =
72 CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8) + 1; 62 CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8) + 1;
73 char* result = reinterpret_cast<char*>(Dart_ScopeAllocate(max_len)); 63 char* result = reinterpret_cast<char*>(Dart_ScopeAllocate(max_len));
74 ASSERT(result != NULL); 64 ASSERT(result != NULL);
75 bool success = 65 bool success =
76 CFStringGetCString(cfstring, result, max_len, kCFStringEncodingUTF8); 66 CFStringGetCString(cfstring, result, max_len, kCFStringEncodingUTF8);
77 return success ? result : NULL; 67 return success ? result : NULL;
78 } 68 }
79 69
80 70
81 // Handle an error reported from the SecureTransport library.
82 static void ThrowIOException(OSStatus status,
83 const char* exception_type,
84 const char* message) {
85 TextBuffer status_message(SSL_ERROR_MESSAGE_BUFFER_SIZE);
86 CFStringRef error_string = SecCopyErrorMessageString(status, NULL);
87 if (error_string == NULL) {
88 status_message.Printf("OSStatus = %ld: https://www.osstatus.com",
89 static_cast<intptr_t>(status));
90 } else {
91 char* error = CFStringRefToCString(error_string);
92 status_message.Printf("OSStatus = %ld: %s", static_cast<intptr_t>(status),
93 error);
94 CFRelease(error_string);
95 }
96 OSError os_error_struct(status, status_message.buf(), OSError::kBoringSSL);
97 Dart_Handle os_error = DartUtils::NewDartOSError(&os_error_struct);
98 Dart_Handle exception =
99 DartUtils::NewDartIOException(exception_type, message, os_error);
100 ASSERT(!Dart_IsError(exception));
101 Dart_ThrowException(exception);
102 UNREACHABLE();
103 }
104
105
106 static void CheckStatus(OSStatus status,
107 const char* type,
108 const char* message) {
109 if (status == noErr) {
110 return;
111 }
112 ThrowIOException(status, type, message);
113 }
114
115
116 static SSLFilter* GetFilter(Dart_NativeArguments args) {
117 SSLFilter* filter;
118 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
119 ASSERT(Dart_IsInstance(dart_this));
120 ThrowIfError(
121 Dart_GetNativeInstanceField(dart_this, kSSLFilterNativeFieldIndex,
122 reinterpret_cast<intptr_t*>(&filter)));
123 return filter;
124 }
125
126
127 static void DeleteFilter(void* isolate_data,
128 Dart_WeakPersistentHandle handle,
129 void* context_pointer) {
130 SSLFilter* filter = reinterpret_cast<SSLFilter*>(context_pointer);
131 filter->Release();
132 }
133
134
135 static Dart_Handle SetFilter(Dart_NativeArguments args, SSLFilter* filter) {
136 ASSERT(filter != NULL);
137 const int approximate_size_of_filter = 1500;
138 Dart_Handle dart_this = Dart_GetNativeArgument(args, 0);
139 RETURN_IF_ERROR(dart_this);
140 ASSERT(Dart_IsInstance(dart_this));
141 Dart_Handle err =
142 Dart_SetNativeInstanceField(dart_this, kSSLFilterNativeFieldIndex,
143 reinterpret_cast<intptr_t>(filter));
144 RETURN_IF_ERROR(err);
145 Dart_NewWeakPersistentHandle(dart_this, reinterpret_cast<void*>(filter),
146 approximate_size_of_filter, DeleteFilter);
147 return Dart_Null();
148 }
149
150
151 static SSLCertContext* GetSecurityContext(Dart_NativeArguments args) {
152 SSLCertContext* context;
153 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
154 ASSERT(Dart_IsInstance(dart_this));
155 ThrowIfError(
156 Dart_GetNativeInstanceField(dart_this, kSecurityContextNativeFieldIndex,
157 reinterpret_cast<intptr_t*>(&context)));
158 return context;
159 }
160
161
162 static void DeleteCertContext(void* isolate_data,
163 Dart_WeakPersistentHandle handle,
164 void* context_pointer) {
165 SSLCertContext* context = static_cast<SSLCertContext*>(context_pointer);
166 context->Release();
167 }
168
169
170 static Dart_Handle SetSecurityContext(Dart_NativeArguments args,
171 SSLCertContext* context) {
172 const int approximate_size_of_context = 1500;
173 Dart_Handle dart_this = Dart_GetNativeArgument(args, 0);
174 RETURN_IF_ERROR(dart_this);
175 ASSERT(Dart_IsInstance(dart_this));
176 Dart_Handle err =
177 Dart_SetNativeInstanceField(dart_this, kSecurityContextNativeFieldIndex,
178 reinterpret_cast<intptr_t>(context));
179 RETURN_IF_ERROR(err);
180 Dart_NewWeakPersistentHandle(dart_this, context, approximate_size_of_context,
181 DeleteCertContext);
182 return Dart_Null();
183 }
184
185
186 static SecCertificateRef GetX509Certificate(Dart_NativeArguments args) { 71 static SecCertificateRef GetX509Certificate(Dart_NativeArguments args) {
187 SecCertificateRef certificate; 72 SecCertificateRef certificate;
188 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0)); 73 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
189 ASSERT(Dart_IsInstance(dart_this)); 74 ASSERT(Dart_IsInstance(dart_this));
190 ThrowIfError( 75 ThrowIfError(Dart_GetNativeInstanceField(
191 Dart_GetNativeInstanceField(dart_this, kX509NativeFieldIndex, 76 dart_this, SSLCertContext::kX509NativeFieldIndex,
192 reinterpret_cast<intptr_t*>(&certificate))); 77 reinterpret_cast<intptr_t*>(&certificate)));
193 return certificate; 78 return certificate;
194 } 79 }
195 80
196 81
197 static void ReleaseCertificate(void* isolate_data,
198 Dart_WeakPersistentHandle handle,
199 void* context_pointer) {
200 SecCertificateRef cert = reinterpret_cast<SecCertificateRef>(context_pointer);
201 CFRelease(cert);
202 }
203
204
205 static Dart_Handle WrappedX509Certificate(SecCertificateRef certificate) { 82 static Dart_Handle WrappedX509Certificate(SecCertificateRef certificate) {
206 const intptr_t approximate_size_of_certificate = 1500; 83 const intptr_t approximate_size_of_certificate = 1500;
207 if (certificate == NULL) { 84 if (certificate == NULL) {
208 return Dart_Null(); 85 return Dart_Null();
209 } 86 }
210 Dart_Handle x509_type = 87 Dart_Handle x509_type =
211 DartUtils::GetDartType(DartUtils::kIOLibURL, "X509Certificate"); 88 DartUtils::GetDartType(DartUtils::kIOLibURL, "X509Certificate");
212 if (Dart_IsError(x509_type)) { 89 if (Dart_IsError(x509_type)) {
213 return x509_type; 90 return x509_type;
214 } 91 }
215 Dart_Handle arguments[] = {NULL}; 92 Dart_Handle arguments[] = {NULL};
216 93
217 Dart_Handle result = 94 Dart_Handle result =
218 Dart_New(x509_type, DartUtils::NewString("_"), 0, arguments); 95 Dart_New(x509_type, DartUtils::NewString("_"), 0, arguments);
219 if (Dart_IsError(result)) { 96 if (Dart_IsError(result)) {
220 return result; 97 return result;
221 } 98 }
222 ASSERT(Dart_IsInstance(result)); 99 ASSERT(Dart_IsInstance(result));
223 100
224 // CFRetain in case the returned Dart object outlives the SecurityContext. 101 // CFRetain in case the returned Dart object outlives the SecurityContext.
225 // CFRelease is in the Dart object's finalizer 102 // CFRelease is in the Dart object's finalizer
226 CFRetain(certificate); 103 CFRetain(certificate);
227 Dart_NewWeakPersistentHandle(result, reinterpret_cast<void*>(certificate), 104 Dart_NewWeakPersistentHandle(result, reinterpret_cast<void*>(certificate),
228 approximate_size_of_certificate, 105 approximate_size_of_certificate,
229 ReleaseCertificate); 106 ReleaseCertificate);
230 107
231 Dart_Handle status = Dart_SetNativeInstanceField( 108 Dart_Handle status =
232 result, kX509NativeFieldIndex, reinterpret_cast<intptr_t>(certificate)); 109 Dart_SetNativeInstanceField(result, SSLCertContext::kX509NativeFieldIndex,
110 reinterpret_cast<intptr_t>(certificate));
233 if (Dart_IsError(status)) { 111 if (Dart_IsError(status)) {
234 return status; 112 return status;
235 } 113 }
236 return result; 114 return result;
237 } 115 }
238 116
239 117
240 static const char* GetPasswordArgument(Dart_NativeArguments args, 118 static void CheckStatus(int status, const char* type, const char* message) {
241 intptr_t index) { 119 if (status == noErr) {
242 Dart_Handle password_object = 120 return;
243 ThrowIfError(Dart_GetNativeArgument(args, index));
244 const char* password = NULL;
245 if (Dart_IsString(password_object)) {
246 ThrowIfError(Dart_StringToCString(password_object, &password));
247 if (strlen(password) > PEM_BUFSIZE - 1) {
248 Dart_ThrowException(DartUtils::NewDartArgumentError(
249 "Password length is greater than 1023 bytes."));
250 }
251 } else if (Dart_IsNull(password_object)) {
252 password = "";
253 } else {
254 Dart_ThrowException(
255 DartUtils::NewDartArgumentError("Password is not a String or null"));
256 } 121 }
257 return password; 122 SecureSocketUtils::ThrowIOException(status, type, message, NULL);
258 } 123 }
259 124
260 125
261 static OSStatus GetKeyAndCerts(CFArrayRef items, 126 SecCertificateRef CreateSecCertificateFromX509(X509* cert) {
262 CFIndex items_length, 127 unsigned char* deb_cert = NULL;
263 CFArrayRef* out_certs, 128 int length = i2d_X509(cert, &deb_cert);
264 SecKeyRef* out_key) { 129 if (length < 0) {
130 return 0;
131 }
132 ASSERT(deb_cert != NULL);
133 CFDataRef cert_buf =
134 CFDataCreateWithBytesNoCopy(NULL, deb_cert, length, kCFAllocatorNull);
135 SecCertificateRef auth_cert = SecCertificateCreateWithData(NULL, cert_buf);
136 if (auth_cert == NULL) {
137 return NULL;
138 }
139 return auth_cert;
140 }
141
142
143 static int CertificateVerificationCallback(X509_STORE_CTX* ctx, void* arg) {
144 SSLCertContext* context = static_cast<SSLCertContext*>(arg);
145
146 // Convert BoringSSL formatted certificates to SecCertificate certificates.
147 CFMutableArrayRef cert_chain = NULL;
148 X509* root_cert = NULL;
149 if (ctx->untrusted != NULL) {
150 STACK_OF(X509)* user_provided_certs = ctx->untrusted;
151 int num_certs = sk_X509_num(user_provided_certs);
152 int current_cert = 0;
153 cert_chain = CFArrayCreateMutable(NULL, num_certs, NULL);
154 X509* ca;
155 while ((ca = sk_X509_shift(user_provided_certs)) != NULL) {
156 SecCertificateRef cert = CreateSecCertificateFromX509(ca);
157 if (cert == NULL) {
158 CFRelease(cert_chain);
159 return ctx->verify_cb(0, ctx);
160 }
161 CFArrayAppendValue(cert_chain, cert);
162 ++current_cert;
163
164 if (current_cert == num_certs) {
165 root_cert = ca;
166 }
167 }
168 }
169
170 // Generate a generic X509 verification policy.
171 SecPolicyRef policy = SecPolicyCreateBasicX509();
172
173 // Create the trust object with the certificates provided by the user.
174 SecTrustRef trust = NULL;
175 OSStatus status = SecTrustCreateWithCertificates(cert_chain, policy, &trust);
176 if (status != noErr) {
177 CFRelease(cert_chain);
178 CFRelease(policy);
179 return ctx->verify_cb(0, ctx);
180 }
181
182 // If the user provided any additional CA certificates, add them to the trust
183 // object.
184 if (context->trusted_certs() != NULL) {
185 status = SecTrustSetAnchorCertificates(trust, context->trusted_certs());
186 if (status != noErr) {
187 CFRelease(cert_chain);
188 CFRelease(policy);
189 CFRelease(trust);
190 return ctx->verify_cb(0, ctx);
191 }
192 }
193
194 // Specify whether or not to use the built-in CA certificates for
195 // verification.
196 status = SecTrustSetAnchorCertificatesOnly(trust, !context->trust_builtin());
197 if (status != noErr) {
198 CFRelease(cert_chain);
199 CFRelease(policy);
200 CFRelease(trust);
201 return ctx->verify_cb(0, ctx);
202 }
203
204 // Perform the certificate verification.
205 SecTrustResultType trust_result;
206 status = SecTrustEvaluate(trust, &trust_result);
207 if (status != noErr) {
208 CFRelease(cert_chain);
209 CFRelease(policy);
210 CFRelease(trust);
211 return ctx->verify_cb(0, ctx);
212 }
213
214 CFRelease(cert_chain);
215 CFRelease(policy);
216 CFRelease(trust);
217
218 if ((trust_result == kSecTrustResultProceed) ||
219 (trust_result == kSecTrustResultUnspecified)) {
220 // Successfully verified certificate!
221 return ctx->verify_cb(1, ctx);
222 }
223
224 // Set current_cert to the root of the certificate chain. This will be passed
225 // to the callback provided by the user for additional verification steps.
226 ctx->current_cert = root_cert;
227 return ctx->verify_cb(0, ctx);
228 }
229
230
231 int CertificateCallback(int preverify_ok, X509_STORE_CTX* store_ctx) {
232 if (preverify_ok == 1) {
233 return 1;
234 }
235 Dart_Isolate isolate = Dart_CurrentIsolate();
236 if (isolate == NULL) {
237 FATAL("CertificateCallback called with no current isolate\n");
238 }
239 int ssl_index = SSL_get_ex_data_X509_STORE_CTX_idx();
240 SSL* ssl =
241 static_cast<SSL*>(X509_STORE_CTX_get_ex_data(store_ctx, ssl_index));
242 SSLFilter* filter = static_cast<SSLFilter*>(
243 SSL_get_ex_data(ssl, SSLFilter::filter_ssl_index));
244 X509* certificate = X509_STORE_CTX_get_current_cert(store_ctx);
245 Dart_Handle callback = filter->bad_certificate_callback();
246 if (Dart_IsNull(callback)) {
247 return 0;
248 }
249
250 // Upref since the Dart X509 object may outlive the SecurityContext.
251 if (certificate != NULL) {
252 X509_up_ref(certificate);
253 }
254 Dart_Handle args[1];
255 args[0] = WrappedX509Certificate(CreateSecCertificateFromX509(certificate));
256 if (Dart_IsError(args[0])) {
257 filter->callback_error = args[0];
258 return 0;
259 }
260 Dart_Handle result = Dart_InvokeClosure(callback, 1, args);
261 if (!Dart_IsError(result) && !Dart_IsBoolean(result)) {
262 result = Dart_NewUnhandledExceptionError(DartUtils::NewDartIOException(
263 "HandshakeException",
264 "BadCertificateCallback returned a value that was not a boolean",
265 Dart_Null()));
266 }
267 if (Dart_IsError(result)) {
268 filter->callback_error = result;
269 return 0;
270 }
271 return DartUtils::GetBooleanValue(result);
272 }
273
274
275 void SSLFilter::RegisterCallbacks(SSLCertContext* cert_ctx) {
276 SSL_CTX* ctx = SSL_get_SSL_CTX(ssl_);
277 SSL_CTX_set_cert_verify_callback(ctx, CertificateVerificationCallback,
278 cert_ctx);
279 }
280
281
282 Dart_Handle SSLFilter::PeerCertificate() {
283 X509* ca = SSL_get_peer_certificate(ssl_);
284 if (ca == NULL) {
285 return Dart_Null();
286 }
287 SecCertificateRef peer = CreateSecCertificateFromX509(ca);
288 return WrappedX509Certificate(peer);
289 }
290
291
292 static OSStatus GetCerts(CFArrayRef items,
293 CFIndex items_length,
294 CFArrayRef* out_certs) {
265 OSStatus status = noErr; 295 OSStatus status = noErr;
266 296
267 // Loop through the items, take only the first private key/identity, ignore 297 // Loop through the items, take only the first private key/identity, ignore
268 // any others, populate out_certs. 298 // any others, populate out_certs.
269 CFMutableArrayRef certs = 299 CFMutableArrayRef certs =
270 CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 300 CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
271 SecKeyRef key = NULL;
272 301
273 for (CFIndex i = 0; i < items_length; ++i) { 302 for (CFIndex i = 0; i < items_length; ++i) {
274 CFTypeRef item = 303 CFTypeRef item =
275 reinterpret_cast<CFTypeRef>(CFArrayGetValueAtIndex(items, i)); 304 reinterpret_cast<CFTypeRef>(CFArrayGetValueAtIndex(items, i));
276 CFTypeID item_type = CFGetTypeID(item); 305 CFTypeID item_type = CFGetTypeID(item);
277 if (item_type == SecCertificateGetTypeID()) { 306 if (item_type == SecCertificateGetTypeID()) {
278 if (SSL_LOG_CERTS) { 307 if (SSL_LOG_CERTS) {
279 Log::Print("\titem %ld: Certificate\n", i); 308 Log::Print("\titem %ld: Certificate\n", i);
280 } 309 }
281 CFArrayAppendValue(certs, item); 310 CFArrayAppendValue(certs, item);
282 } else if ((item_type == SecKeyGetTypeID()) && (key == NULL)) {
283 if (SSL_LOG_CERTS) {
284 Log::Print("\titem %ld: Key\n", i);
285 }
286 key = reinterpret_cast<SecKeyRef>(const_cast<void*>(item));
287 CFRetain(key);
288 } else if ((item_type == SecIdentityGetTypeID()) && (key == NULL)) {
289 if (SSL_LOG_CERTS) {
290 Log::Print("\titem %ld: Identity\n", i);
291 }
292 SecIdentityRef identity =
293 reinterpret_cast<SecIdentityRef>(const_cast<void*>(item));
294 SecCertificateRef cert = NULL;
295
296 status = SecIdentityCopyPrivateKey(identity, &key);
297 if (status != noErr) {
298 CFRelease(certs);
299 return status;
300 }
301
302 status = SecIdentityCopyCertificate(identity, &cert);
303 if (status != noErr) {
304 CFRelease(key);
305 CFRelease(certs);
306 return status;
307 }
308 CFArrayAppendValue(certs, cert);
309 CFRelease(cert);
310 } 311 }
311 // Other item types are ignored. 312 // Other item types are ignored.
312 } 313 }
313 314
314 if (out_key == NULL) {
315 if (key != NULL) {
316 CFRelease(key);
317 }
318 } else {
319 *out_key = key;
320 }
321
322 if (out_certs == NULL) { 315 if (out_certs == NULL) {
323 if (certs != NULL) { 316 if (certs != NULL) {
324 CFRelease(certs); 317 CFRelease(certs);
325 } 318 }
326 } else { 319 } else {
327 *out_certs = certs; 320 *out_certs = certs;
328 } 321 }
329 return status; 322 return status;
330 } 323 }
331 324
332 325
333 static OSStatus TryPEMImport(CFDataRef cfdata, 326 static OSStatus TryPEMImport(CFDataRef cfdata,
334 CFStringRef password, 327 CFStringRef password,
335 CFArrayRef* out_certs, 328 CFArrayRef* out_certs) {
336 SecKeyRef* out_key) {
337 OSStatus status = noErr; 329 OSStatus status = noErr;
338 330
339 SecExternalFormat format = kSecFormatPEMSequence; 331 SecExternalFormat format = kSecFormatPEMSequence;
340 SecExternalItemType sitem_type = kSecItemTypeAggregate; 332 SecExternalItemType sitem_type = kSecItemTypeAggregate;
341 333
342 SecItemImportExportKeyParameters params; 334 SecItemImportExportKeyParameters params;
343 memset(&params, 0, sizeof(params)); 335 memset(&params, 0, sizeof(params));
344 params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; 336 params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
345 params.flags = kSecKeyNoAccessControl; 337 params.flags = kSecKeyNoAccessControl;
346 params.passphrase = password; 338 params.passphrase = password;
(...skipping 16 matching lines...) Expand all
363 "TrySecItemImport succeeded, type = %d, format = %d, count = %ld\n", 355 "TrySecItemImport succeeded, type = %d, format = %d, count = %ld\n",
364 sitem_type, format, items_length); 356 sitem_type, format, items_length);
365 } 357 }
366 358
367 // Empty list indicates a decoding failure of some sort. 359 // Empty list indicates a decoding failure of some sort.
368 if ((items != NULL) && (items_length == 0)) { 360 if ((items != NULL) && (items_length == 0)) {
369 CFRelease(items); 361 CFRelease(items);
370 return errSSLBadCert; 362 return errSSLBadCert;
371 } 363 }
372 364
373 status = GetKeyAndCerts(items, items_length, out_certs, out_key); 365 status = GetCerts(items, items_length, out_certs);
374 CFRelease(items); 366 CFRelease(items);
375 return status; 367 return status;
376 } 368 }
377 369
378
379 static char* TempKeychainPath() {
380 const char* exes = "keychaindir.XXXX";
381 const char* fname = "keychain";
382 const char* temp_dir = getenv("TMPDIR");
383 if (temp_dir == NULL) {
384 temp_dir = getenv("TMP");
385 }
386 if (temp_dir == NULL) {
387 temp_dir = "/tmp/";
388 }
389 ASSERT(temp_dir != NULL);
390
391 TextBuffer path(PATH_MAX);
392 path.Printf("%s/%s", temp_dir, exes);
393 char* ret = mkdtemp(path.buf());
394 ASSERT(ret != NULL);
395 path.Printf("/%s", fname);
396
397 char* result = reinterpret_cast<char*>(Dart_ScopeAllocate(path.length() + 1));
398 return strncpy(result, path.buf(), path.length() + 1);
399 }
400
401
402 static OSStatus CreateKeychain(SecKeychainRef* keychain) {
403 ASSERT(keychain != NULL);
404 OSStatus status = noErr;
405 const char* temp_keychain_pwd = "dartdart";
406 char* temp_file_path = TempKeychainPath();
407 ASSERT(temp_file_path != NULL);
408 if (SSL_LOG_CERTS) {
409 Log::Print("Temporary keychain at: '%s'\n", temp_file_path);
410 }
411 status = SecKeychainCreate(temp_file_path, strlen(temp_keychain_pwd) + 1,
412 reinterpret_cast<const void*>(temp_keychain_pwd),
413 FALSE, // Prompt user? Definitely no.
414 NULL, // Default access rights.
415 keychain);
416 if (status != noErr) {
417 return status;
418 }
419 ASSERT(*keychain != NULL);
420 return status;
421 }
422
423
424 static OSStatus TryPKCS12Import(CFDataRef cfdata, 370 static OSStatus TryPKCS12Import(CFDataRef cfdata,
425 CFStringRef password, 371 CFStringRef password,
426 CFArrayRef* out_certs, 372 CFArrayRef* out_certs) {
427 SecKeyRef* out_key,
428 SecKeychainRef* out_keychain) {
429 OSStatus status = noErr; 373 OSStatus status = noErr;
430 374
431 SecExternalFormat format = kSecFormatPKCS12; 375 SecExternalFormat format = kSecFormatPKCS12;
432 SecExternalItemType sitem_type = kSecItemTypeAggregate; 376 SecExternalItemType sitem_type = kSecItemTypeAggregate;
433 377
434 SecItemImportExportKeyParameters params; 378 SecItemImportExportKeyParameters params;
435 memset(&params, 0, sizeof(params)); 379 memset(&params, 0, sizeof(params));
436 params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION; 380 params.version = SEC_KEY_IMPORT_EXPORT_PARAMS_VERSION;
437 params.flags = kSecKeyNoAccessControl; 381 params.flags = kSecKeyNoAccessControl;
438 params.passphrase = password; 382 params.passphrase = password;
439 383
440 CFArrayRef items = NULL; 384 CFArrayRef items = NULL;
441 if (SSL_LOG_CERTS) { 385 if (SSL_LOG_CERTS) {
442 Log::Print("Trying PKCS12 import with: type = %d, format = %d\n", 386 Log::Print("Trying PKCS12 import with: type = %d, format = %d\n",
443 sitem_type, format); 387 sitem_type, format);
444 } 388 }
445 389
446 // The documentation for SecKeychainItemImport here: 390 status = SecItemImport(cfdata, NULL, &format, &sitem_type, 0, &params, NULL,
447 // 391 &items);
448 // https://developer.apple.com/library/mac/documentation/Security/Reference/ke ychainservices/index.html
449 //
450 // states that when the SecKeychainRef argument is NULL, the CFArrayRef*
451 // argument will be populated by an array containing all keys, identities,
452 // and certificates from the data in the CFDataRef argument.
453 //
454 // Unfortunately, this is not true. The code to populate the CFArrayRef with
455 // keys and identities from PKCS12 data has been skipped and/or commented out,
456 // here:
457 //
458 // https://github.com/Apple-FOSS-Mirror/Security/blob/master/libsecurity_keych ain/lib/SecImportExportAgg.cpp#L636
459 //
460 // as "floating" SecKeyRefs from the PKCS12 decoder haven't been implemented.
461 // That is, each private key instance coming from the PKCS12 decoder has to be
462 // associated with a keychain instance. Thus, as a workaround, we create a
463 // temporary keychain here if one is needed, and stash it below in a
464 // SecurityContext. This has the drawbacks:
465 // 1.) We need to make a temporary directory to hold the keychain file, and
466 // 2.) SecKeychainItemImport() probably does blocking IO to create and
467 // manipulate the keychain file.
468 // So if the API is updated, this keychain should not be used.
469 SecKeychainRef keychain = NULL;
470 if (out_key != NULL) {
471 ASSERT(out_keychain != NULL);
472 status = CreateKeychain(&keychain);
473 if (status != noErr) {
474 return status;
475 }
476 *out_keychain = keychain;
477 }
478
479 status = SecItemImport(cfdata, NULL, &format, &sitem_type, 0, &params,
480 keychain, &items);
481 if (status != noErr) { 392 if (status != noErr) {
482 if (SSL_LOG_CERTS) { 393 if (SSL_LOG_CERTS) {
483 Log::Print("TrySecItemImport failed with: %ld, it = %d, format = %d\n", 394 Log::Print("TrySecItemImport failed with: %ld, it = %d, format = %d\n",
484 static_cast<intptr_t>(status), sitem_type, format); 395 static_cast<intptr_t>(status), sitem_type, format);
485 } 396 }
486 return status; 397 return status;
487 } 398 }
488 399
489 CFIndex items_length = (items == NULL) ? 0 : CFArrayGetCount(items); 400 CFIndex items_length = (items == NULL) ? 0 : CFArrayGetCount(items);
490 if (SSL_LOG_CERTS) { 401 if (SSL_LOG_CERTS) {
491 Log::Print("TrySecItemImport succeeded, count = %ld\n", items_length); 402 Log::Print("TrySecItemImport succeeded, count = %ld\n", items_length);
492 } 403 }
493 404
494 // Empty list indicates a decoding failure of some sort. 405 // Empty list indicates a decoding failure of some sort.
495 if ((items != NULL) && (items_length == 0)) { 406 if ((items != NULL) && (items_length == 0)) {
496 CFRelease(items); 407 CFRelease(items);
497 return errSSLBadCert; 408 return errSSLBadCert;
498 } 409 }
499 410
500 status = GetKeyAndCerts(items, items_length, out_certs, out_key); 411 status = GetCerts(items, items_length, out_certs);
501 CFRelease(items); 412 CFRelease(items);
502 return status; 413 return status;
503 } 414 }
504 415
505 416
506 static OSStatus ExtractSecItems(uint8_t* buffer, 417 static OSStatus ExtractSecItems(uint8_t* buffer,
507 intptr_t length, 418 intptr_t length,
508 const char* password, 419 const char* password,
509 CFArrayRef* out_certs, 420 CFArrayRef* out_certs) {
510 SecKeyRef* out_key,
511 SecKeychainRef* out_keychain) {
512 ASSERT(buffer != NULL); 421 ASSERT(buffer != NULL);
513 ASSERT(password != NULL); 422 ASSERT(password != NULL);
514 OSStatus status = noErr; 423 OSStatus status = noErr;
515 424
516 CFDataRef cfdata = 425 CFDataRef cfdata =
517 CFDataCreateWithBytesNoCopy(NULL, buffer, length, kCFAllocatorNull); 426 CFDataCreateWithBytesNoCopy(NULL, buffer, length, kCFAllocatorNull);
518 CFStringRef cfpassword = CFStringCreateWithCStringNoCopy( 427 CFStringRef cfpassword = CFStringCreateWithCStringNoCopy(
519 NULL, password, kCFStringEncodingUTF8, kCFAllocatorNull); 428 NULL, password, kCFStringEncodingUTF8, kCFAllocatorNull);
520 ASSERT(cfdata != NULL); 429 ASSERT(cfdata != NULL);
521 ASSERT(cfpassword != NULL); 430 ASSERT(cfpassword != NULL);
522 431
523 status = TryPEMImport(cfdata, cfpassword, out_certs, out_key); 432 status = TryPEMImport(cfdata, cfpassword, out_certs);
524 if (status != noErr) { 433 if (status != noErr) {
525 status = 434 status = TryPKCS12Import(cfdata, cfpassword, out_certs);
526 TryPKCS12Import(cfdata, cfpassword, out_certs, out_key, out_keychain);
527 } 435 }
528
529 CFRelease(cfdata); 436 CFRelease(cfdata);
530 CFRelease(cfpassword); 437 CFRelease(cfpassword);
531 return status; 438 return status;
532 } 439 }
533 440
534 441
535 void FUNCTION_NAME(SecureSocket_Init)(Dart_NativeArguments args) {
536 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
537 SSLFilter* filter = new SSLFilter(); // Deleted in DeleteFilter finalizer.
538 Dart_Handle err = SetFilter(args, filter);
539 if (Dart_IsError(err)) {
540 filter->Release();
541 Dart_PropagateError(err);
542 }
543 err = filter->Init(dart_this);
544 if (Dart_IsError(err)) {
545 // The finalizer was set up by SetFilter. It will delete `filter` if there
546 // is an error.
547 filter->Destroy();
548 Dart_PropagateError(err);
549 }
550 }
551
552
553 void FUNCTION_NAME(SecureSocket_Connect)(Dart_NativeArguments args) {
554 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
555 Dart_Handle host_name_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
556 Dart_Handle context_object = ThrowIfError(Dart_GetNativeArgument(args, 2));
557 bool is_server = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3));
558 bool request_client_certificate =
559 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 4));
560 bool require_client_certificate =
561 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 5));
562
563 const char* host_name = NULL;
564 // TODO(whesse): Is truncating a Dart string containing \0 what we want?
565 ThrowIfError(Dart_StringToCString(host_name_object, &host_name));
566
567 SSLCertContext* context = NULL;
568 if (!Dart_IsNull(context_object)) {
569 ThrowIfError(Dart_GetNativeInstanceField(
570 context_object, kSecurityContextNativeFieldIndex,
571 reinterpret_cast<intptr_t*>(&context)));
572 }
573
574 GetFilter(args)->Connect(dart_this, host_name, context, is_server,
575 request_client_certificate,
576 require_client_certificate);
577 }
578
579
580 void FUNCTION_NAME(SecureSocket_Destroy)(Dart_NativeArguments args) {
581 SSLFilter* filter = GetFilter(args);
582 // The SSLFilter is deleted in the finalizer for the Dart object created by
583 // SetFilter. There is no need to NULL-out the native field for the SSLFilter
584 // here because the SSLFilter won't be deleted until the finalizer for the
585 // Dart object runs while the Dart object is being GCd. This approach avoids a
586 // leak if Destroy isn't called, and avoids a NULL-dereference if Destroy is
587 // called more than once.
588 filter->Destroy();
589 }
590
591
592 void FUNCTION_NAME(SecureSocket_Handshake)(Dart_NativeArguments args) {
593 OSStatus status = GetFilter(args)->CheckHandshake();
594 CheckStatus(status, "HandshakeException", "Handshake error");
595 }
596
597
598 void FUNCTION_NAME(SecureSocket_GetSelectedProtocol)(
599 Dart_NativeArguments args) {
600 Dart_SetReturnValue(args, Dart_Null());
601 }
602
603
604 void FUNCTION_NAME(SecureSocket_Renegotiate)(Dart_NativeArguments args) {
605 bool use_session_cache =
606 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 1));
607 bool request_client_certificate =
608 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 2));
609 bool require_client_certificate =
610 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3));
611 GetFilter(args)->Renegotiate(use_session_cache, request_client_certificate,
612 require_client_certificate);
613 }
614
615
616 void FUNCTION_NAME(SecureSocket_RegisterHandshakeCompleteCallback)(
617 Dart_NativeArguments args) {
618 Dart_Handle handshake_complete =
619 ThrowIfError(Dart_GetNativeArgument(args, 1));
620 if (!Dart_IsClosure(handshake_complete)) {
621 Dart_ThrowException(DartUtils::NewDartArgumentError(
622 "Illegal argument to RegisterHandshakeCompleteCallback"));
623 }
624 GetFilter(args)->RegisterHandshakeCompleteCallback(handshake_complete);
625 }
626
627
628 void FUNCTION_NAME(SecureSocket_RegisterBadCertificateCallback)(
629 Dart_NativeArguments args) {
630 Dart_Handle callback = ThrowIfError(Dart_GetNativeArgument(args, 1));
631 if (!Dart_IsClosure(callback) && !Dart_IsNull(callback)) {
632 Dart_ThrowException(DartUtils::NewDartArgumentError(
633 "Illegal argument to RegisterBadCertificateCallback"));
634 }
635 GetFilter(args)->RegisterBadCertificateCallback(callback);
636 }
637
638
639 void FUNCTION_NAME(SecureSocket_PeerCertificate)(Dart_NativeArguments args) {
640 Dart_SetReturnValue(args, GetFilter(args)->PeerCertificate());
641 }
642
643
644 void FUNCTION_NAME(SecureSocket_FilterPointer)(Dart_NativeArguments args) {
645 SSLFilter* filter = GetFilter(args);
646 // This filter pointer is passed to the IO Service thread. The IO Service
647 // thread must Release() the pointer when it is done with it.
648 filter->Retain();
649 intptr_t filter_pointer = reinterpret_cast<intptr_t>(filter);
650 Dart_SetReturnValue(args, Dart_NewInteger(filter_pointer));
651 }
652
653
654 void FUNCTION_NAME(SecurityContext_Allocate)(Dart_NativeArguments args) {
655 SSLCertContext* cert_context = new SSLCertContext();
656 // cert_context deleted in DeleteCertContext finalizer.
657 Dart_Handle err = SetSecurityContext(args, cert_context);
658 if (Dart_IsError(err)) {
659 cert_context->Release();
660 Dart_PropagateError(err);
661 }
662 }
663
664
665 void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)(
666 Dart_NativeArguments args) {
667 SSLCertContext* context = GetSecurityContext(args);
668 const char* password = GetPasswordArgument(args, 2);
669
670 OSStatus status;
671 SecKeyRef key = NULL;
672 SecKeychainRef keychain = NULL;
673 {
674 ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1)));
675 status = ExtractSecItems(buffer.get(), buffer.length(), password, NULL,
676 &key, &keychain);
677 }
678
679 // Set the context fields. If there's a failure, release the items.
680 bool set_failure = false;
681 if ((key != NULL) && !context->set_private_key(key)) {
682 CFRelease(key);
683 SecKeychainDelete(keychain);
684 CFRelease(keychain);
685 set_failure = true;
686 }
687 if (!set_failure && (keychain != NULL) && !context->set_keychain(keychain)) {
688 SecKeychainDelete(keychain);
689 CFRelease(keychain);
690 }
691
692 if (set_failure) {
693 Dart_ThrowException(DartUtils::NewDartArgumentError(
694 "usePrivateKeyBytes has already been called on the given context."));
695 }
696 CheckStatus(status, "TlsException", "Failure in usePrivateKeyBytes");
697 }
698
699
700 void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)( 442 void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)(
701 Dart_NativeArguments args) { 443 Dart_NativeArguments args) {
702 SSLCertContext* context = GetSecurityContext(args); 444 SSLCertContext* context = SSLCertContext::GetSecurityContext(args);
703 const char* password = GetPasswordArgument(args, 2); 445 const char* password = SSLCertContext::GetPasswordArgument(args, 2);
704 446
705 OSStatus status; 447 OSStatus status;
706 CFArrayRef certs = NULL; 448 CFArrayRef certs = NULL;
707 { 449 {
708 ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1))); 450 ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1)));
709 status = ExtractSecItems(buffer.get(), buffer.length(), password, &certs, 451 status = ExtractSecItems(buffer.get(), buffer.length(), password, &certs);
710 NULL, NULL);
711 } 452 }
712 453
713 // Set the field in the context. If there's a failure, release the certs, 454 // Set the field in the context. If there's a failure, release the certs,
714 // and throw an exception. 455 // and throw an exception.
715 if ((certs != NULL) && !context->set_trusted_certs(certs)) { 456 if ((certs != NULL) && !context->set_trusted_certs(certs)) {
716 CFRelease(certs); 457 CFRelease(certs);
717 Dart_ThrowException(DartUtils::NewDartArgumentError( 458 Dart_ThrowException(DartUtils::NewDartArgumentError(
718 "setTrustedCertificatesBytes has already been called " 459 "setTrustedCertificatesBytes has already been called "
719 "on the given context.")); 460 "on the given context."));
720 } 461 }
721 462
722 CheckStatus(status, "TlsException", "Failure in setTrustedCertificatesBytes"); 463 CheckStatus(status, "TlsException", "Failure in setTrustedCertificatesBytes");
723 } 464 }
724 465
725 466
726 void FUNCTION_NAME(SecurityContext_AlpnSupported)(Dart_NativeArguments args) {
727 Dart_SetReturnValue(args, Dart_NewBoolean(false));
728 }
729
730
731 void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)(
732 Dart_NativeArguments args) {
733 SSLCertContext* context = GetSecurityContext(args);
734 context->set_trust_builtin(true);
735 }
736
737
738 void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)(
739 Dart_NativeArguments args) {
740 SSLCertContext* context = GetSecurityContext(args);
741
742 const char* password = GetPasswordArgument(args, 2);
743 OSStatus status;
744 CFArrayRef certs = NULL;
745 {
746 ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1)));
747 status = ExtractSecItems(buffer.get(), buffer.length(), password, &certs,
748 NULL, NULL);
749 }
750
751 // Set the field in the context. If there's a failure, release the certs,
752 // and throw an exception.
753 if ((certs != NULL) && !context->set_cert_chain(certs)) {
754 CFRelease(certs);
755 Dart_ThrowException(DartUtils::NewDartArgumentError(
756 "useCertificateChainBytes has already been called "
757 "on the given context."));
758 }
759
760 CheckStatus(status, "TlsException", "Failure in useCertificateChainBytes");
761 }
762
763
764 void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)( 467 void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)(
765 Dart_NativeArguments args) { 468 Dart_NativeArguments args) {
766 SSLCertContext* context = GetSecurityContext(args); 469 SSLCertContext* context = SSLCertContext::GetSecurityContext(args);
767 const char* password = GetPasswordArgument(args, 2); 470 const char* password = SSLCertContext::GetPasswordArgument(args, 2);
768 471
769 OSStatus status; 472 OSStatus status;
770 CFArrayRef certs = NULL; 473 CFArrayRef certs = NULL;
771 { 474 {
772 ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1))); 475 ScopedMemBuffer buffer(ThrowIfError(Dart_GetNativeArgument(args, 1)));
773 status = ExtractSecItems(buffer.get(), buffer.length(), password, &certs, 476 status = ExtractSecItems(buffer.get(), buffer.length(), password, &certs);
774 NULL, NULL);
775 } 477 }
776 478
777 // Set the field in the context. If there's a failure, release the certs, 479 // Set the field in the context. If there's a failure, release the certs,
778 // and throw an exception. 480 // and throw an exception.
779 if ((certs != NULL) && !context->set_cert_authorities(certs)) { 481 if ((certs != NULL) && !context->set_cert_authorities(certs)) {
780 CFRelease(certs); 482 CFRelease(certs);
781 Dart_ThrowException(DartUtils::NewDartArgumentError( 483 Dart_ThrowException(DartUtils::NewDartArgumentError(
782 "setClientAuthoritiesBytes has already been called " 484 "setClientAuthoritiesBytes has already been called "
783 "on the given context.")); 485 "on the given context."));
784 } 486 }
785 487
786 CheckStatus(status, "TlsException", "Failure in setClientAuthoritiesBytes"); 488 CheckStatus(status, "TlsException", "Failure in setClientAuthoritiesBytes");
787 } 489 }
788 490
789 491
790 void FUNCTION_NAME(SecurityContext_SetAlpnProtocols)( 492 static int UseChainBytesPKCS12(SSL_CTX* context,
493 BIO* bio,
494 const char* password) {
495 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL));
496 if (p12.get() == NULL) {
497 return 0;
498 }
499
500 EVP_PKEY* key = NULL;
501 X509* cert = NULL;
502 STACK_OF(X509)* ca_certs = NULL;
503 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs);
504 if (status == 0) {
505 return status;
506 }
507
508 ScopedX509 x509(cert);
509 ScopedX509Stack certs(ca_certs);
510 status = SSL_CTX_use_certificate(context, x509.get());
511 if (ERR_peek_error() != 0) {
512 // Key/certificate mismatch doesn't imply status is 0.
513 status = 0;
514 }
515 if (status == 0) {
516 return status;
517 }
518
519 SSL_CTX_clear_chain_certs(context);
520
521 X509* ca;
522 while ((ca = sk_X509_shift(certs.get())) != NULL) {
523 status = SSL_CTX_add0_chain_cert(context, ca);
524 // SSL_CTX_add0_chain_cert does not inc ref count, so don't free unless the
525 // call fails.
526 if (status == 0) {
527 X509_free(ca);
528 return status;
529 }
530 }
531
532 return status;
533 }
534
535
536 static int UseChainBytesPEM(SSL_CTX* context, BIO* bio) {
537 int status = 0;
538 ScopedX509 x509(PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL));
539 if (x509.get() == NULL) {
540 return 0;
541 }
542
543 status = SSL_CTX_use_certificate(context, x509.get());
544 if (ERR_peek_error() != 0) {
545 // Key/certificate mismatch doesn't imply status is 0.
546 status = 0;
547 }
548 if (status == 0) {
549 return status;
550 }
551
552 SSL_CTX_clear_chain_certs(context);
553
554 X509* ca;
555 while ((ca = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) {
556 status = SSL_CTX_add0_chain_cert(context, ca);
557 // SSL_CTX_add0_chain_cert does not inc ref count, so don't free unless the
558 // call fails.
559 if (status == 0) {
560 X509_free(ca);
561 return status;
562 }
563 // Note that we must not free `ca` if it was successfully added to the
564 // chain. We must free the main certificate x509, though since its reference
565 // count is increased by SSL_CTX_use_certificate.
566 }
567
568 return SecureSocketUtils::NoPEMStartLine() ? status : 0;
569 }
570
571
572 static int UseChainBytes(SSL_CTX* context, BIO* bio, const char* password) {
573 int status = UseChainBytesPEM(context, bio);
574 if (status == 0) {
575 if (SecureSocketUtils::NoPEMStartLine()) {
576 ERR_clear_error();
577 BIO_reset(bio);
578 status = UseChainBytesPKCS12(context, bio, password);
579 }
580 } else {
581 // The PEM file was successfully read.
582 ERR_clear_error();
583 }
584 return status;
585 }
586
587
588 void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)(
791 Dart_NativeArguments args) { 589 Dart_NativeArguments args) {
792 Dart_ThrowException(DartUtils::NewDartUnsupportedError( 590 SSLCertContext* context = SSLCertContext::GetSecurityContext(args);
793 "ALPN is not supported on this platform")); 591 const char* password = SSLCertContext::GetPasswordArgument(args, 2);
592 int status;
593 {
594 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
595 status = UseChainBytes(context->context(), bio.bio(), password);
596 }
597 SecureSocketUtils::CheckStatus(status, "TlsException",
598 "Failure in useCertificateChainBytes");
599 }
600
601
602 void FUNCTION_NAME(SecurityContext_AlpnSupported)(Dart_NativeArguments args) {
603 Dart_SetReturnValue(args, Dart_NewBoolean(true));
604 }
605
606
607 void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)(
608 Dart_NativeArguments args) {
609 SSLCertContext* context = SSLCertContext::GetSecurityContext(args);
610 context->set_trust_builtin(true);
794 } 611 }
795 612
796 613
797 static char* GetNameFromCert(SecCertificateRef certificate, 614 static char* GetNameFromCert(SecCertificateRef certificate,
798 CFTypeRef field, 615 CFTypeRef field,
799 CFStringRef name) { 616 CFStringRef name) {
800 char* issuer_name = NULL; 617 char* issuer_name = NULL;
801 618
802 CFTypeRef keys[] = {field}; 619 CFTypeRef keys[] = {field};
803 CFArrayRef key_array = CFArrayCreate(NULL, keys, 1, &kCFTypeArrayCallBacks); 620 CFArrayRef key_array = CFArrayCreate(NULL, keys, 1, &kCFTypeArrayCallBacks);
(...skipping 15 matching lines...) Expand all
819 CFArrayRef val_array = reinterpret_cast<CFArrayRef>(item); 636 CFArrayRef val_array = reinterpret_cast<CFArrayRef>(item);
820 637
821 for (intptr_t i = 0; i < CFArrayGetCount(val_array); i++) { 638 for (intptr_t i = 0; i < CFArrayGetCount(val_array); i++) {
822 item = CFArrayGetValueAtIndex(val_array, i); 639 item = CFArrayGetValueAtIndex(val_array, i);
823 ASSERT(CFGetTypeID(item) == CFDictionaryGetTypeID()); 640 ASSERT(CFGetTypeID(item) == CFDictionaryGetTypeID());
824 CFDictionaryRef val_dict2 = reinterpret_cast<CFDictionaryRef>(item); 641 CFDictionaryRef val_dict2 = reinterpret_cast<CFDictionaryRef>(item);
825 642
826 item = CFDictionaryGetValue(val_dict2, kSecPropertyKeyLabel); 643 item = CFDictionaryGetValue(val_dict2, kSecPropertyKeyLabel);
827 ASSERT(CFGetTypeID(item) == CFStringGetTypeID()); 644 ASSERT(CFGetTypeID(item) == CFStringGetTypeID());
828 CFStringRef label = reinterpret_cast<CFStringRef>(item); 645 CFStringRef label = reinterpret_cast<CFStringRef>(item);
829
830 if (CFStringCompare(label, name, 0) == kCFCompareEqualTo) { 646 if (CFStringCompare(label, name, 0) == kCFCompareEqualTo) {
831 item = CFDictionaryGetValue(val_dict2, kSecPropertyKeyValue); 647 item = CFDictionaryGetValue(val_dict2, kSecPropertyKeyValue);
832 ASSERT(CFGetTypeID(item) == CFStringGetTypeID()); 648 ASSERT(CFGetTypeID(item) == CFStringGetTypeID());
833 CFStringRef value = reinterpret_cast<CFStringRef>(item); 649 CFStringRef value = reinterpret_cast<CFStringRef>(item);
834 issuer_name = CFStringRefToCString(value); 650 issuer_name = CFStringRefToCString(value);
835 break; 651 break;
836 } 652 }
837 } 653 }
838 654
839 CFRelease(cert_dict); 655 CFRelease(cert_dict);
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
911 727
912 void FUNCTION_NAME(X509_EndValidity)(Dart_NativeArguments args) { 728 void FUNCTION_NAME(X509_EndValidity)(Dart_NativeArguments args) {
913 SecCertificateRef certificate = GetX509Certificate(args); 729 SecCertificateRef certificate = GetX509Certificate(args);
914 int64_t seconds_since_epoch = 730 int64_t seconds_since_epoch =
915 GetTimeFromCert(certificate, kSecOIDX509V1ValidityNotAfter); 731 GetTimeFromCert(certificate, kSecOIDX509V1ValidityNotAfter);
916 Dart_SetReturnValue( 732 Dart_SetReturnValue(
917 args, 733 args,
918 Dart_NewInteger(static_cast<int64_t>(seconds_since_epoch) * 1000LL)); 734 Dart_NewInteger(static_cast<int64_t>(seconds_since_epoch) * 1000LL));
919 } 735 }
920 736
921
922 // Pushes data through the SSL filter, reading and writing from circular
923 // buffers shared with Dart. Called from the IOService thread.
924 //
925 // The Dart _SecureFilterImpl class contains 4 ExternalByteArrays used to
926 // pass encrypted and plaintext data to and from the C++ SSLFilter object.
927 //
928 // ProcessFilter is called with a CObject array containing the pointer to
929 // the SSLFilter, encoded as an int, and the start and end positions of the
930 // valid data in the four circular buffers. The function only reads from
931 // the valid data area of the input buffers, and only writes to the free
932 // area of the output buffers. The function returns the new start and end
933 // positions in the buffers, but it only updates start for input buffers, and
934 // end for output buffers. Therefore, the Dart thread can simultaneously
935 // write to the free space and end pointer of input buffers, and read from
936 // the data space of output buffers, and modify the start pointer.
937 //
938 // When ProcessFilter returns, the Dart thread is responsible for combining
939 // the updated pointers from Dart and C++, to make the new valid state of
940 // the circular buffer.
941 CObject* SSLFilter::ProcessFilterRequest(const CObjectArray& request) {
942 CObjectIntptr filter_object(request[0]);
943 SSLFilter* filter = reinterpret_cast<SSLFilter*>(filter_object.Value());
944 RefCntReleaseScope<SSLFilter> rs(filter);
945
946 bool in_handshake = CObjectBool(request[1]).Value();
947 intptr_t starts[SSLFilter::kNumBuffers];
948 intptr_t ends[SSLFilter::kNumBuffers];
949 for (intptr_t i = 0; i < SSLFilter::kNumBuffers; ++i) {
950 starts[i] = CObjectInt32(request[2 * i + 2]).Value();
951 ends[i] = CObjectInt32(request[2 * i + 3]).Value();
952 }
953
954 OSStatus status = filter->ProcessAllBuffers(starts, ends, in_handshake);
955 if (status == noErr) {
956 CObjectArray* result =
957 new CObjectArray(CObject::NewArray(SSLFilter::kNumBuffers * 2));
958 for (intptr_t i = 0; i < SSLFilter::kNumBuffers; ++i) {
959 result->SetAt(2 * i, new CObjectInt32(CObject::NewInt32(starts[i])));
960 result->SetAt(2 * i + 1, new CObjectInt32(CObject::NewInt32(ends[i])));
961 }
962 return result;
963 } else {
964 TextBuffer status_message(SSL_ERROR_MESSAGE_BUFFER_SIZE);
965 CFStringRef error_string = SecCopyErrorMessageString(status, NULL);
966 if (error_string == NULL) {
967 status_message.Printf("OSStatus = %ld: https://www.osstatus.com",
968 static_cast<intptr_t>(status));
969 } else {
970 char* error = CFStringRefToCString(error_string);
971 status_message.Printf("OSStatus = %ld: %s", static_cast<intptr_t>(status),
972 error);
973 CFRelease(error_string);
974 }
975 CObjectArray* result = new CObjectArray(CObject::NewArray(2));
976 result->SetAt(0, new CObjectInt32(CObject::NewInt32(status)));
977 result->SetAt(1,
978 new CObjectString(CObject::NewString(status_message.buf())));
979 return result;
980 }
981 }
982
983
984 // Usually buffer_starts_ and buffer_ends_ are populated by ProcessAllBuffers,
985 // called from ProcessFilterRequest, called from the IOService thread.
986 // However, the first call to SSLHandshake comes from the Dart thread, and so
987 // doesn't go through there. This results in calls to SSLReadCallback and
988 // SSLWriteCallback in which buffer_starts_ and buffer_ends_ haven't been set
989 // up. In that case, since we're coming from Dart anyway, we can access the
990 // fieds directly from the Dart objects.
991 intptr_t SSLFilter::GetBufferStart(intptr_t idx) const {
992 if (buffer_starts_[idx] != NULL) {
993 return *buffer_starts_[idx];
994 }
995 Dart_Handle buffer_handle =
996 ThrowIfError(Dart_HandleFromPersistent(dart_buffer_objects_[idx]));
997 Dart_Handle start_handle =
998 ThrowIfError(Dart_GetField(buffer_handle, DartUtils::NewString("start")));
999 int64_t start = DartUtils::GetIntegerValue(start_handle);
1000 return static_cast<intptr_t>(start);
1001 }
1002
1003
1004 intptr_t SSLFilter::GetBufferEnd(intptr_t idx) const {
1005 if (buffer_ends_[idx] != NULL) {
1006 return *buffer_ends_[idx];
1007 }
1008 Dart_Handle buffer_handle =
1009 ThrowIfError(Dart_HandleFromPersistent(dart_buffer_objects_[idx]));
1010 Dart_Handle end_handle =
1011 ThrowIfError(Dart_GetField(buffer_handle, DartUtils::NewString("end")));
1012 int64_t end = DartUtils::GetIntegerValue(end_handle);
1013 return static_cast<intptr_t>(end);
1014 }
1015
1016
1017 void SSLFilter::SetBufferStart(intptr_t idx, intptr_t value) {
1018 if (buffer_starts_[idx] != NULL) {
1019 *buffer_starts_[idx] = value;
1020 return;
1021 }
1022 Dart_Handle buffer_handle =
1023 ThrowIfError(Dart_HandleFromPersistent(dart_buffer_objects_[idx]));
1024 ThrowIfError(DartUtils::SetIntegerField(buffer_handle, "start",
1025 static_cast<int64_t>(value)));
1026 }
1027
1028
1029 void SSLFilter::SetBufferEnd(intptr_t idx, intptr_t value) {
1030 if (buffer_ends_[idx] != NULL) {
1031 *buffer_ends_[idx] = value;
1032 return;
1033 }
1034 Dart_Handle buffer_handle =
1035 ThrowIfError(Dart_HandleFromPersistent(dart_buffer_objects_[idx]));
1036 ThrowIfError(DartUtils::SetIntegerField(buffer_handle, "end",
1037 static_cast<int64_t>(value)));
1038 }
1039
1040
1041 OSStatus SSLFilter::ProcessAllBuffers(intptr_t starts[kNumBuffers],
1042 intptr_t ends[kNumBuffers],
1043 bool in_handshake) {
1044 for (intptr_t i = 0; i < kNumBuffers; ++i) {
1045 buffer_starts_[i] = &starts[i];
1046 buffer_ends_[i] = &ends[i];
1047 }
1048
1049 if (in_handshake) {
1050 OSStatus status = Handshake();
1051 if (status != noErr) {
1052 return status;
1053 }
1054 } else {
1055 for (intptr_t i = 0; i < kNumBuffers; ++i) {
1056 intptr_t start = starts[i];
1057 intptr_t end = ends[i];
1058 intptr_t size =
1059 isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
1060 if (start < 0 || end < 0 || start >= size || end >= size) {
1061 FATAL("Out-of-bounds internal buffer access in dart:io SecureSocket");
1062 }
1063 switch (i) {
1064 case kReadPlaintext:
1065 // Write data to the circular buffer's free space. If the buffer
1066 // is full, neither if statement is executed and nothing happens.
1067 if (start <= end) {
1068 // If the free space may be split into two segments,
1069 // then the first is [end, size), unless start == 0.
1070 // Then, since the last free byte is at position start - 2,
1071 // the interval is [end, size - 1).
1072 intptr_t buffer_end = (start == 0) ? size - 1 : size;
1073 intptr_t bytes = 0;
1074 OSStatus status =
1075 ProcessReadPlaintextBuffer(end, buffer_end, &bytes);
1076 if ((status != noErr) && (status != errSSLWouldBlock)) {
1077 return status;
1078 }
1079 end += bytes;
1080 ASSERT(end <= size);
1081 if (end == size) {
1082 end = 0;
1083 }
1084 }
1085 if (start > end + 1) {
1086 intptr_t bytes = 0;
1087 OSStatus status =
1088 ProcessReadPlaintextBuffer(end, start - 1, &bytes);
1089 if ((status != noErr) && (status != errSSLWouldBlock)) {
1090 return status;
1091 }
1092 end += bytes;
1093 ASSERT(end < start);
1094 }
1095 ends[i] = end;
1096 break;
1097 case kWritePlaintext:
1098 // Read/Write data from circular buffer. If the buffer is empty,
1099 // neither if statement's condition is true.
1100 if (end < start) {
1101 // Data may be split into two segments. In this case,
1102 // the first is [start, size).
1103 intptr_t bytes = 0;
1104 OSStatus status = ProcessWritePlaintextBuffer(start, size, &bytes);
1105 if ((status != noErr) && (status != errSSLWouldBlock)) {
1106 return status;
1107 }
1108 start += bytes;
1109 ASSERT(start <= size);
1110 if (start == size) {
1111 start = 0;
1112 }
1113 }
1114 if (start < end) {
1115 intptr_t bytes = 0;
1116 OSStatus status = ProcessWritePlaintextBuffer(start, end, &bytes);
1117 if ((status != noErr) && (status != errSSLWouldBlock)) {
1118 return status;
1119 }
1120 start += bytes;
1121 ASSERT(start <= end);
1122 }
1123 starts[i] = start;
1124 break;
1125 case kReadEncrypted:
1126 case kWriteEncrypted:
1127 // These buffers are advanced through SSLReadCallback and
1128 // SSLWriteCallback, which are called from SSLRead, SSLWrite, and
1129 // SSLHandshake.
1130 break;
1131 default:
1132 UNREACHABLE();
1133 }
1134 }
1135 }
1136
1137 for (intptr_t i = 0; i < kNumBuffers; ++i) {
1138 buffer_starts_[i] = NULL;
1139 buffer_ends_[i] = NULL;
1140 }
1141 return noErr;
1142 }
1143
1144
1145 Dart_Handle SSLFilter::Init(Dart_Handle dart_this) {
1146 ASSERT(string_start_ == NULL);
1147 string_start_ = Dart_NewPersistentHandle(DartUtils::NewString("start"));
1148 ASSERT(string_start_ != NULL);
1149 ASSERT(string_length_ == NULL);
1150 string_length_ = Dart_NewPersistentHandle(DartUtils::NewString("length"));
1151 ASSERT(string_length_ != NULL);
1152 ASSERT(bad_certificate_callback_ == NULL);
1153 bad_certificate_callback_ = Dart_NewPersistentHandle(Dart_Null());
1154 ASSERT(bad_certificate_callback_ != NULL);
1155
1156 // Caller handles cleanup on an error.
1157 return InitializeBuffers(dart_this);
1158 }
1159
1160
1161 Dart_Handle SSLFilter::InitializeBuffers(Dart_Handle dart_this) {
1162 // Create SSLFilter buffers as ExternalUint8Array objects.
1163 Dart_Handle buffers_string = DartUtils::NewString("buffers");
1164 RETURN_IF_ERROR(buffers_string);
1165 Dart_Handle dart_buffers_object = Dart_GetField(dart_this, buffers_string);
1166 RETURN_IF_ERROR(dart_buffers_object);
1167 Dart_Handle secure_filter_impl_type = Dart_InstanceGetType(dart_this);
1168 RETURN_IF_ERROR(secure_filter_impl_type);
1169 Dart_Handle size_string = DartUtils::NewString("SIZE");
1170 RETURN_IF_ERROR(size_string);
1171 Dart_Handle dart_buffer_size =
1172 Dart_GetField(secure_filter_impl_type, size_string);
1173 RETURN_IF_ERROR(dart_buffer_size);
1174
1175 int64_t buffer_size = 0;
1176 Dart_Handle err = Dart_IntegerToInt64(dart_buffer_size, &buffer_size);
1177 RETURN_IF_ERROR(err);
1178
1179 Dart_Handle encrypted_size_string = DartUtils::NewString("ENCRYPTED_SIZE");
1180 RETURN_IF_ERROR(encrypted_size_string);
1181
1182 Dart_Handle dart_encrypted_buffer_size =
1183 Dart_GetField(secure_filter_impl_type, encrypted_size_string);
1184 RETURN_IF_ERROR(dart_encrypted_buffer_size);
1185
1186 int64_t encrypted_buffer_size = 0;
1187 err = Dart_IntegerToInt64(dart_encrypted_buffer_size, &encrypted_buffer_size);
1188 RETURN_IF_ERROR(err);
1189
1190 if (buffer_size <= 0 || buffer_size > 1 * MB) {
1191 FATAL("Invalid buffer size in _ExternalBuffer");
1192 }
1193 if (encrypted_buffer_size <= 0 || encrypted_buffer_size > 1 * MB) {
1194 FATAL("Invalid encrypted buffer size in _ExternalBuffer");
1195 }
1196 buffer_size_ = static_cast<intptr_t>(buffer_size);
1197 encrypted_buffer_size_ = static_cast<intptr_t>(encrypted_buffer_size);
1198
1199 Dart_Handle data_identifier = DartUtils::NewString("data");
1200 RETURN_IF_ERROR(data_identifier);
1201
1202 for (int i = 0; i < kNumBuffers; i++) {
1203 int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
1204 buffers_[i] = new uint8_t[size];
1205 ASSERT(buffers_[i] != NULL);
1206 buffer_starts_[i] = NULL;
1207 buffer_ends_[i] = NULL;
1208 dart_buffer_objects_[i] = NULL;
1209 }
1210
1211 Dart_Handle result = Dart_Null();
1212 for (int i = 0; i < kNumBuffers; ++i) {
1213 int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
1214 result = Dart_ListGetAt(dart_buffers_object, i);
1215 if (Dart_IsError(result)) {
1216 break;
1217 }
1218
1219 dart_buffer_objects_[i] = Dart_NewPersistentHandle(result);
1220 ASSERT(dart_buffer_objects_[i] != NULL);
1221 Dart_Handle data =
1222 Dart_NewExternalTypedData(Dart_TypedData_kUint8, buffers_[i], size);
1223 if (Dart_IsError(data)) {
1224 result = data;
1225 break;
1226 }
1227 result = Dart_HandleFromPersistent(dart_buffer_objects_[i]);
1228 if (Dart_IsError(result)) {
1229 break;
1230 }
1231 result = Dart_SetField(result, data_identifier, data);
1232 if (Dart_IsError(result)) {
1233 break;
1234 }
1235 }
1236
1237 // Caller handles cleanup on an error.
1238 return result;
1239 }
1240
1241
1242 void SSLFilter::RegisterHandshakeCompleteCallback(Dart_Handle complete) {
1243 ASSERT(NULL == handshake_complete_);
1244 handshake_complete_ = Dart_NewPersistentHandle(complete);
1245 ASSERT(handshake_complete_ != NULL);
1246 }
1247
1248
1249 void SSLFilter::RegisterBadCertificateCallback(Dart_Handle callback) {
1250 ASSERT(bad_certificate_callback_ != NULL);
1251 Dart_DeletePersistentHandle(bad_certificate_callback_);
1252 bad_certificate_callback_ = Dart_NewPersistentHandle(callback);
1253 ASSERT(bad_certificate_callback_ != NULL);
1254 }
1255
1256
1257 Dart_Handle SSLFilter::PeerCertificate() {
1258 if (peer_certs_ == NULL) {
1259 return Dart_Null();
1260 }
1261
1262 CFTypeRef item = CFArrayGetValueAtIndex(peer_certs_, 0);
1263 ASSERT(CFGetTypeID(item) == SecCertificateGetTypeID());
1264 SecCertificateRef cert =
1265 reinterpret_cast<SecCertificateRef>(const_cast<void*>(item));
1266 if (cert == NULL) {
1267 return Dart_Null();
1268 }
1269
1270 return WrappedX509Certificate(cert);
1271 }
1272
1273
1274 void SSLFilter::Connect(Dart_Handle dart_this,
1275 const char* hostname,
1276 SSLCertContext* context,
1277 bool is_server,
1278 bool request_client_certificate,
1279 bool require_client_certificate) {
1280 if (in_handshake_) {
1281 FATAL("Connect called twice on the same _SecureFilter.");
1282 }
1283
1284 // Create the underlying context
1285 SSLContextRef ssl_context = SSLCreateContext(
1286 NULL, is_server ? kSSLServerSide : kSSLClientSide, kSSLStreamType);
1287
1288 // Configure the context.
1289 OSStatus status;
1290 status = SSLSetPeerDomainName(ssl_context, hostname, strlen(hostname));
1291 CheckStatus(status, "TlsException", "Failed to set peer domain name");
1292
1293 status = SSLSetIOFuncs(ssl_context, SSLFilter::SSLReadCallback,
1294 SSLFilter::SSLWriteCallback);
1295 CheckStatus(status, "TlsException", "Failed to set IO Callbacks");
1296
1297 status =
1298 SSLSetConnection(ssl_context, reinterpret_cast<SSLConnectionRef>(this));
1299 CheckStatus(status, "TlsException", "Failed to set connection object");
1300
1301 // Always evaluate the certs manually so that we can cache the peer
1302 // certificates in the context for calls to peerCertificate.
1303 status = SSLSetSessionOption(ssl_context, kSSLSessionOptionBreakOnServerAuth,
1304 true);
1305 CheckStatus(status, "TlsException", "Failed to set BreakOnServerAuth option");
1306
1307 status = SSLSetProtocolVersionMin(ssl_context, kTLSProtocol1);
1308 CheckStatus(status, "TlsException",
1309 "Failed to set minimum protocol version to kTLSProtocol1");
1310
1311 // If the context has a private key and certificate chain, combine the
1312 // private key and first certificate into a SecIdentityRef, and place that
1313 // and the remaining certs in an array to pass to SSLSetCertificate().
1314 if ((context->private_key() != NULL) && (context->cert_chain() != NULL)) {
1315 CFIndex chain_length = CFArrayGetCount(context->cert_chain());
1316 CFMutableArrayRef certs =
1317 CFArrayCreateMutable(NULL, chain_length, &kCFTypeArrayCallBacks);
1318 CFTypeRef item = CFArrayGetValueAtIndex(context->cert_chain(), 0);
1319 ASSERT(CFGetTypeID(item) == SecCertificateGetTypeID());
1320 SecCertificateRef first_cert =
1321 reinterpret_cast<SecCertificateRef>(const_cast<void*>(item));
1322 SecIdentityRef identity =
1323 SecIdentityCreate(NULL, first_cert, context->private_key());
1324 CFArrayAppendValue(certs, identity);
1325 for (CFIndex i = 0; i < chain_length; i++) {
1326 CFArrayAppendValue(certs,
1327 CFArrayGetValueAtIndex(context->cert_chain(), i));
1328 }
1329 CFRelease(identity);
1330 status = SSLSetCertificate(ssl_context, certs);
1331 CFRelease(certs);
1332 CheckStatus(status, "TlsException", "SSLSetCertificate failed");
1333 }
1334
1335 if (context->cert_authorities() != NULL) {
1336 status = SSLSetCertificateAuthorities(ssl_context,
1337 context->cert_authorities(), true);
1338 CheckStatus(status, "TlsException",
1339 "Failed to set certificate authorities");
1340 }
1341
1342 if (is_server) {
1343 SSLAuthenticate auth =
1344 require_client_certificate
1345 ? kAlwaysAuthenticate
1346 : (request_client_certificate ? kTryAuthenticate
1347 : kNeverAuthenticate);
1348 status = SSLSetClientSideAuthenticate(ssl_context, auth);
1349 CheckStatus(status, "TlsException",
1350 "Failed to set client authentication mode");
1351
1352 // If we're at least trying client authentication, then break handshake
1353 // for client authentication.
1354 if (auth != kNeverAuthenticate) {
1355 status = SSLSetSessionOption(ssl_context,
1356 kSSLSessionOptionBreakOnClientAuth, true);
1357 CheckStatus(status, "TlsException",
1358 "Failed to set client authentication mode");
1359 }
1360 }
1361
1362 // Add the contexts to our wrapper.
1363 cert_context_.set(context);
1364 ssl_context_ = ssl_context;
1365 is_server_ = is_server;
1366
1367 // Kick-off the handshake. Expect the handshake to need more data.
1368 // SSLHandshake calls our SSLReadCallback and SSLWriteCallback.
1369 status = SSLHandshake(ssl_context);
1370 ASSERT(status != noErr);
1371 if (status == errSSLWouldBlock) {
1372 status = noErr;
1373 in_handshake_ = true;
1374 }
1375 CheckStatus(status, "HandshakeException", is_server_
1376 ? "Handshake error in server"
1377 : "Handshake error in client");
1378 }
1379
1380
1381 OSStatus SSLFilter::EvaluatePeerTrust() {
1382 OSStatus status = noErr;
1383
1384 if (SSL_LOG_STATUS) {
1385 Log::Print("Handshake evaluating trust.\n");
1386 }
1387 SecTrustRef peer_trust = NULL;
1388 status = SSLCopyPeerTrust(ssl_context_, &peer_trust);
1389 if (status != noErr) {
1390 if (is_server_ && (status == errSSLBadCert)) {
1391 // A client certificate was requested, but not required, and wasn't sent.
1392 return noErr;
1393 }
1394 if (SSL_LOG_STATUS) {
1395 Log::Print("Handshake error from SSLCopyPeerTrust(): %ld.\n",
1396 static_cast<intptr_t>(status));
1397 }
1398 return status;
1399 }
1400
1401 CFArrayRef trusted_certs = NULL;
1402 if (cert_context_.get()->trusted_certs() != NULL) {
1403 trusted_certs =
1404 CFArrayCreateCopy(NULL, cert_context_.get()->trusted_certs());
1405 } else {
1406 trusted_certs = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
1407 }
1408
1409 status = SecTrustSetAnchorCertificates(peer_trust, trusted_certs);
1410 if (status != noErr) {
1411 if (SSL_LOG_STATUS) {
1412 Log::Print("Handshake error from SecTrustSetAnchorCertificates: %ld\n",
1413 static_cast<intptr_t>(status));
1414 }
1415 CFRelease(trusted_certs);
1416 CFRelease(peer_trust);
1417 return status;
1418 }
1419
1420 if (SSL_LOG_STATUS) {
1421 Log::Print(
1422 "Handshake %s built in root certs\n",
1423 cert_context_.get()->trust_builtin() ? "trusting" : "not trusting");
1424 }
1425
1426 status = SecTrustSetAnchorCertificatesOnly(
1427 peer_trust, !cert_context_.get()->trust_builtin());
1428 if (status != noErr) {
1429 CFRelease(trusted_certs);
1430 CFRelease(peer_trust);
1431 return status;
1432 }
1433
1434 SecTrustResultType trust_result;
1435 status = SecTrustEvaluate(peer_trust, &trust_result);
1436 if (status != noErr) {
1437 CFRelease(trusted_certs);
1438 CFRelease(peer_trust);
1439 return status;
1440 }
1441
1442 // Grab the peer's certificate chain.
1443 CFIndex peer_chain_length = SecTrustGetCertificateCount(peer_trust);
1444 CFMutableArrayRef peer_certs =
1445 CFArrayCreateMutable(NULL, peer_chain_length, &kCFTypeArrayCallBacks);
1446 for (CFIndex i = 0; i < peer_chain_length; ++i) {
1447 CFArrayAppendValue(peer_certs,
1448 SecTrustGetCertificateAtIndex(peer_trust, i));
1449 }
1450 peer_certs_ = peer_certs;
1451
1452 CFRelease(trusted_certs);
1453 CFRelease(peer_trust);
1454
1455 if ((trust_result == kSecTrustResultProceed) ||
1456 (trust_result == kSecTrustResultUnspecified)) {
1457 // Trusted.
1458 return noErr;
1459 } else {
1460 if (SSL_LOG_STATUS) {
1461 Log::Print("Trust eval failed: trust_restul = %d\n", trust_result);
1462 }
1463 bad_cert_ = true;
1464 return errSSLBadCert;
1465 }
1466 }
1467
1468
1469 OSStatus SSLFilter::Handshake() {
1470 ASSERT(cert_context_.get() != NULL);
1471 ASSERT(ssl_context_ != NULL);
1472 // Try and push handshake along.
1473 if (SSL_LOG_STATUS) {
1474 Log::Print("Doing SSLHandshake\n");
1475 }
1476 OSStatus status = SSLHandshake(ssl_context_);
1477 if (SSL_LOG_STATUS) {
1478 Log::Print("SSLHandshake returned %ld\n", static_cast<intptr_t>(status));
1479 }
1480
1481 if ((status == errSSLServerAuthCompleted) ||
1482 (status == errSSLClientAuthCompleted)) {
1483 status = EvaluatePeerTrust();
1484 if (status == errSSLBadCert) {
1485 // Need to invoke the bad certificate callback.
1486 return noErr;
1487 } else if (status != noErr) {
1488 return status;
1489 }
1490 // When trust evaluation succeeds, we can call SSLHandshake again
1491 // immediately.
1492 status = SSLHandshake(ssl_context_);
1493 }
1494
1495 if (status == errSSLWouldBlock) {
1496 in_handshake_ = true;
1497 return noErr;
1498 }
1499
1500 // Handshake succeeded.
1501 if ((in_handshake_) && (status == noErr)) {
1502 if (SSL_LOG_STATUS) {
1503 Log::Print("Finished with the Handshake\n");
1504 }
1505 connected_ = true;
1506 }
1507 return status;
1508 }
1509
1510
1511 // Returns false if Handshake should fail, and true if Handshake should
1512 // proceed.
1513 Dart_Handle SSLFilter::InvokeBadCertCallback(SecCertificateRef peer_cert) {
1514 Dart_Handle callback = bad_certificate_callback_;
1515 if (Dart_IsNull(callback)) {
1516 return callback;
1517 }
1518 Dart_Handle args[1];
1519 args[0] = WrappedX509Certificate(peer_cert);
1520 if (Dart_IsError(args[0])) {
1521 return args[0];
1522 }
1523 Dart_Handle result = Dart_InvokeClosure(callback, 1, args);
1524 if (!Dart_IsError(result) && !Dart_IsBoolean(result)) {
1525 result = Dart_NewUnhandledExceptionError(DartUtils::NewDartIOException(
1526 "HandshakeException",
1527 "BadCertificateCallback returned a value that was not a boolean",
1528 Dart_Null()));
1529 }
1530 return result;
1531 }
1532
1533
1534 OSStatus SSLFilter::CheckHandshake() {
1535 if (bad_cert_ && in_handshake_) {
1536 if (SSL_LOG_STATUS) {
1537 Log::Print("Invoking bad certificate callback\n");
1538 }
1539 ASSERT(peer_certs_ != NULL);
1540 CFIndex peer_certs_len = CFArrayGetCount(peer_certs_);
1541 ASSERT(peer_certs_len > 0);
1542 CFTypeRef item = CFArrayGetValueAtIndex(peer_certs_, peer_certs_len - 1);
1543 ASSERT(item != NULL);
1544 ASSERT(CFGetTypeID(item) == SecCertificateGetTypeID());
1545 SecCertificateRef peer_cert =
1546 reinterpret_cast<SecCertificateRef>(const_cast<void*>(item));
1547 Dart_Handle result = InvokeBadCertCallback(peer_cert);
1548 ThrowIfError(result);
1549 if (Dart_IsNull(result)) {
1550 return errSSLBadCert;
1551 } else {
1552 bool good_cert = DartUtils::GetBooleanValue(result);
1553 bad_cert_ = !good_cert;
1554 return good_cert ? noErr : errSSLBadCert;
1555 }
1556 }
1557
1558 if (connected_ && in_handshake_) {
1559 if (SSL_LOG_STATUS) {
1560 Log::Print("Invoking handshake complete callback\n");
1561 }
1562 ThrowIfError(Dart_InvokeClosure(
1563 Dart_HandleFromPersistent(handshake_complete_), 0, NULL));
1564 in_handshake_ = false;
1565 }
1566 return noErr;
1567 }
1568
1569
1570 void SSLFilter::Renegotiate(bool use_session_cache,
1571 bool request_client_certificate,
1572 bool require_client_certificate) {
1573 // The SSL_REQUIRE_CERTIFICATE option only takes effect if the
1574 // SSL_REQUEST_CERTIFICATE option is also set, so set it.
1575 request_client_certificate =
1576 request_client_certificate || require_client_certificate;
1577 // TODO(24070, 24069): Implement setting the client certificate parameters,
1578 // and triggering rehandshake.
1579 }
1580
1581
1582 SSLFilter::~SSLFilter() {
1583 if (ssl_context_ != NULL) {
1584 CFRelease(ssl_context_);
1585 ssl_context_ = NULL;
1586 }
1587 if (peer_certs_ != NULL) {
1588 CFRelease(peer_certs_);
1589 peer_certs_ = NULL;
1590 }
1591 if (hostname_ != NULL) {
1592 free(hostname_);
1593 hostname_ = NULL;
1594 }
1595 for (int i = 0; i < kNumBuffers; ++i) {
1596 if (buffers_[i] != NULL) {
1597 delete[] buffers_[i];
1598 buffers_[i] = NULL;
1599 }
1600 }
1601 }
1602
1603
1604 void SSLFilter::Destroy() {
1605 if (ssl_context_ != NULL) {
1606 SSLClose(ssl_context_);
1607 }
1608 for (int i = 0; i < kNumBuffers; ++i) {
1609 if (dart_buffer_objects_[i] != NULL) {
1610 Dart_DeletePersistentHandle(dart_buffer_objects_[i]);
1611 dart_buffer_objects_[i] = NULL;
1612 }
1613 }
1614 if (string_start_ != NULL) {
1615 Dart_DeletePersistentHandle(string_start_);
1616 string_start_ = NULL;
1617 }
1618 if (string_length_ != NULL) {
1619 Dart_DeletePersistentHandle(string_length_);
1620 string_length_ = NULL;
1621 }
1622 if (handshake_complete_ != NULL) {
1623 Dart_DeletePersistentHandle(handshake_complete_);
1624 handshake_complete_ = NULL;
1625 }
1626 if (bad_certificate_callback_ != NULL) {
1627 Dart_DeletePersistentHandle(bad_certificate_callback_);
1628 bad_certificate_callback_ = NULL;
1629 }
1630 }
1631
1632
1633 OSStatus SSLFilter::SSLReadCallback(SSLConnectionRef connection,
1634 void* data,
1635 size_t* data_requested) {
1636 // Copy at most `data_requested` bytes from `buffers_[kReadEncrypted]` into
1637 // `data`
1638 ASSERT(connection != NULL);
1639 ASSERT(data != NULL);
1640 ASSERT(data_requested != NULL);
1641
1642 SSLFilter* filter =
1643 const_cast<SSLFilter*>(reinterpret_cast<const SSLFilter*>(connection));
1644 uint8_t* datap = reinterpret_cast<uint8_t*>(data);
1645 uint8_t* buffer = filter->buffers_[kReadEncrypted];
1646 intptr_t start = filter->GetBufferStart(kReadEncrypted);
1647 intptr_t end = filter->GetBufferEnd(kReadEncrypted);
1648 intptr_t size = filter->encrypted_buffer_size_;
1649 intptr_t requested = static_cast<intptr_t>(*data_requested);
1650 intptr_t data_read = 0;
1651
1652 if (end < start) {
1653 // Data may be split into two segments. In this case,
1654 // the first is [start, size).
1655 intptr_t buffer_end = (start == 0) ? size - 1 : size;
1656 intptr_t available = buffer_end - start;
1657 intptr_t bytes = requested < available ? requested : available;
1658 memmove(datap, &buffer[start], bytes);
1659 start += bytes;
1660 datap += bytes;
1661 data_read += bytes;
1662 requested -= bytes;
1663 ASSERT(start <= size);
1664 if (start == size) {
1665 start = 0;
1666 }
1667 }
1668 if ((requested > 0) && (start < end)) {
1669 intptr_t available = end - start;
1670 intptr_t bytes = requested < available ? requested : available;
1671 memmove(datap, &buffer[start], bytes);
1672 start += bytes;
1673 datap += bytes;
1674 data_read += bytes;
1675 requested -= bytes;
1676 ASSERT(start <= end);
1677 }
1678
1679 if (SSL_LOG_DATA) {
1680 Log::Print("SSLReadCallback: requested: %ld, read %ld bytes\n",
1681 *data_requested, data_read);
1682 }
1683
1684 filter->SetBufferStart(kReadEncrypted, start);
1685 bool short_read = data_read < static_cast<intptr_t>(*data_requested);
1686 *data_requested = data_read;
1687 return short_read ? errSSLWouldBlock : noErr;
1688 }
1689
1690
1691 // Read decrypted data from the filter to the circular buffer.
1692 OSStatus SSLFilter::ProcessReadPlaintextBuffer(intptr_t start,
1693 intptr_t end,
1694 intptr_t* bytes_processed) {
1695 ASSERT(bytes_processed != NULL);
1696 intptr_t length = end - start;
1697 OSStatus status = noErr;
1698 size_t bytes = 0;
1699 if (length > 0) {
1700 status =
1701 SSLRead(ssl_context_,
1702 reinterpret_cast<void*>((buffers_[kReadPlaintext] + start)),
1703 length, &bytes);
1704 if (SSL_LOG_STATUS) {
1705 Log::Print("SSLRead: status = %ld\n", static_cast<intptr_t>(status));
1706 }
1707 if ((status != noErr) && (status != errSSLWouldBlock)) {
1708 *bytes_processed = 0;
1709 return status;
1710 }
1711 }
1712 if (SSL_LOG_DATA) {
1713 Log::Print("ProcessReadPlaintextBuffer: requested: %ld, read %ld bytes\n",
1714 length, bytes);
1715 }
1716 *bytes_processed = static_cast<intptr_t>(bytes);
1717 return status;
1718 }
1719
1720
1721 OSStatus SSLFilter::SSLWriteCallback(SSLConnectionRef connection,
1722 const void* data,
1723 size_t* data_provided) {
1724 // Copy at most `data_provided` bytes from data into
1725 // `buffers_[kWriteEncrypted]`.
1726 ASSERT(connection != NULL);
1727 ASSERT(data != NULL);
1728 ASSERT(data_provided != NULL);
1729
1730 SSLFilter* filter =
1731 const_cast<SSLFilter*>(reinterpret_cast<const SSLFilter*>(connection));
1732 const uint8_t* datap = reinterpret_cast<const uint8_t*>(data);
1733 uint8_t* buffer = filter->buffers_[kWriteEncrypted];
1734 intptr_t start = filter->GetBufferStart(kWriteEncrypted);
1735 intptr_t end = filter->GetBufferEnd(kWriteEncrypted);
1736 intptr_t size = filter->encrypted_buffer_size_;
1737 intptr_t provided = static_cast<intptr_t>(*data_provided);
1738 intptr_t data_written = 0;
1739
1740 // is full, neither if statement is executed and nothing happens.
1741 if (start <= end) {
1742 // If the free space may be split into two segments,
1743 // then the first is [end, size), unless start == 0.
1744 // Then, since the last free byte is at position start - 2,
1745 // the interval is [end, size - 1).
1746 intptr_t buffer_end = (start == 0) ? size - 1 : size;
1747 intptr_t available = buffer_end - end;
1748 intptr_t bytes = provided < available ? provided : available;
1749 memmove(&buffer[end], datap, bytes);
1750 end += bytes;
1751 datap += bytes;
1752 data_written += bytes;
1753 provided -= bytes;
1754 ASSERT(end <= size);
1755 if (end == size) {
1756 end = 0;
1757 }
1758 }
1759 if ((provided > 0) && (start > end + 1)) {
1760 intptr_t available = (start - 1) - end;
1761 intptr_t bytes = provided < available ? provided : available;
1762 memmove(&buffer[end], datap, bytes);
1763 end += bytes;
1764 datap += bytes;
1765 data_written += bytes;
1766 provided -= bytes;
1767 ASSERT(end < start);
1768 }
1769
1770 if (SSL_LOG_DATA) {
1771 Log::Print("SSLWriteCallback: provided: %ld, written %ld bytes\n",
1772 *data_provided, data_written);
1773 }
1774
1775 filter->SetBufferEnd(kWriteEncrypted, end);
1776 *data_provided = data_written;
1777 return (data_written == 0) ? errSSLWouldBlock : noErr;
1778 }
1779
1780
1781 OSStatus SSLFilter::ProcessWritePlaintextBuffer(intptr_t start,
1782 intptr_t end,
1783 intptr_t* bytes_processed) {
1784 ASSERT(bytes_processed != NULL);
1785 intptr_t length = end - start;
1786 OSStatus status = noErr;
1787 size_t bytes = 0;
1788 if (length > 0) {
1789 status =
1790 SSLWrite(ssl_context_,
1791 reinterpret_cast<void*>(buffers_[kWritePlaintext] + start),
1792 length, &bytes);
1793 if (SSL_LOG_STATUS) {
1794 Log::Print("SSLWrite: status = %ld\n", static_cast<intptr_t>(status));
1795 }
1796 if ((status != noErr) && (status != errSSLWouldBlock)) {
1797 *bytes_processed = 0;
1798 return status;
1799 }
1800 }
1801 if (SSL_LOG_DATA) {
1802 Log::Print("ProcessWritePlaintextBuffer: requested: %ld, written: %ld\n",
1803 length, bytes);
1804 }
1805 *bytes_processed = static_cast<intptr_t>(bytes);
1806 return status;
1807 }
1808
1809 } // namespace bin 737 } // namespace bin
1810 } // namespace dart 738 } // namespace dart
1811 739
1812 #endif // defined(HOST_OS_MACOS) && !HOST_OS_IOS 740 #endif // defined(HOST_OS_MACOS) && !HOST_OS_IOS
1813 741
1814 #endif // !defined(DART_IO_DISABLED) && 742 #endif // !defined(DART_IO_DISABLED) &&
1815 // !defined(DART_IO_SECURE_SOCKET_DISABLED) 743 // !defined(DART_IO_SECURE_SOCKET_DISABLED)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698