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

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

Issue 2903743002: Porting SecureSocket to use BoringSSL on OSX (Closed)
Patch Set: Addressed missed comment from last patch set 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
(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 "bin/secure_socket_filter.h"
8
9 #include <openssl/bio.h>
10 #include <openssl/ssl.h>
11 #include <openssl/x509.h>
12
13 #include "bin/lockers.h"
14 #include "bin/log.h"
15 #include "bin/secure_socket_utils.h"
16 #include "bin/security_context.h"
17 #include "platform/text_buffer.h"
18
19
20 // Return the error from the containing function if handle is an error handle.
21 #define RETURN_IF_ERROR(handle) \
22 { \
23 Dart_Handle __handle = handle; \
24 if (Dart_IsError((__handle))) { \
25 return __handle; \
26 } \
27 }
28
29 namespace dart {
30 namespace bin {
31
32 bool SSLFilter::library_initialized_ = false;
33 // To protect library initialization.
34 Mutex* SSLFilter::mutex_ = new Mutex();
35 int SSLFilter::filter_ssl_index;
36
37 const intptr_t SSLFilter::kInternalBIOSize = 10 * KB;
38 const intptr_t SSLFilter::kApproximateSize =
39 sizeof(SSLFilter) + (2 * SSLFilter::kInternalBIOSize);
40
41 static SSLFilter* GetFilter(Dart_NativeArguments args) {
42 SSLFilter* filter;
43 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
44 ASSERT(Dart_IsInstance(dart_this));
45 ThrowIfError(Dart_GetNativeInstanceField(
46 dart_this, SSLFilter::kSSLFilterNativeFieldIndex,
47 reinterpret_cast<intptr_t*>(&filter)));
48 return filter;
49 }
50
51
52 static void DeleteFilter(void* isolate_data,
53 Dart_WeakPersistentHandle handle,
54 void* context_pointer) {
55 SSLFilter* filter = reinterpret_cast<SSLFilter*>(context_pointer);
56 filter->Release();
57 }
58
59
60 static Dart_Handle SetFilter(Dart_NativeArguments args, SSLFilter* filter) {
61 ASSERT(filter != NULL);
62 Dart_Handle dart_this = Dart_GetNativeArgument(args, 0);
63 RETURN_IF_ERROR(dart_this);
64 ASSERT(Dart_IsInstance(dart_this));
65 Dart_Handle err = Dart_SetNativeInstanceField(
66 dart_this, SSLFilter::kSSLFilterNativeFieldIndex,
67 reinterpret_cast<intptr_t>(filter));
68 RETURN_IF_ERROR(err);
69 Dart_NewWeakPersistentHandle(dart_this, reinterpret_cast<void*>(filter),
70 SSLFilter::kApproximateSize, DeleteFilter);
71 return Dart_Null();
72 }
73
74
75 int CertificateCallback(int preverify_ok, X509_STORE_CTX* store_ctx) {
76 if (preverify_ok == 1) {
77 return 1;
78 }
79 Dart_Isolate isolate = Dart_CurrentIsolate();
80 if (isolate == NULL) {
81 FATAL("CertificateCallback called with no current isolate\n");
82 }
83 X509* certificate = X509_STORE_CTX_get_current_cert(store_ctx);
84 int ssl_index = SSL_get_ex_data_X509_STORE_CTX_idx();
85 SSL* ssl =
86 static_cast<SSL*>(X509_STORE_CTX_get_ex_data(store_ctx, ssl_index));
87 SSLFilter* filter = static_cast<SSLFilter*>(
88 SSL_get_ex_data(ssl, SSLFilter::filter_ssl_index));
89 Dart_Handle callback = filter->bad_certificate_callback();
90 if (Dart_IsNull(callback)) {
91 return 0;
92 }
93
94 // Upref since the Dart X509 object may outlive the SecurityContext.
95 if (certificate != NULL) {
96 X509_up_ref(certificate);
97 }
98 Dart_Handle args[1];
99 args[0] = SSLFilter::WrappedX509Certificate(certificate);
100 if (Dart_IsError(args[0])) {
101 filter->callback_error = args[0];
102 return 0;
103 }
104 Dart_Handle result = Dart_InvokeClosure(callback, 1, args);
105 if (!Dart_IsError(result) && !Dart_IsBoolean(result)) {
106 result = Dart_NewUnhandledExceptionError(DartUtils::NewDartIOException(
107 "HandshakeException",
108 "BadCertificateCallback returned a value that was not a boolean",
109 Dart_Null()));
110 }
111 if (Dart_IsError(result)) {
112 filter->callback_error = result;
113 return 0;
114 }
115 return DartUtils::GetBooleanValue(result);
116 }
117
118
119 void FUNCTION_NAME(SecureSocket_Init)(Dart_NativeArguments args) {
120 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
121 SSLFilter* filter = new SSLFilter();
122 Dart_Handle err = SetFilter(args, filter);
123 if (Dart_IsError(err)) {
124 filter->Release();
125 Dart_PropagateError(err);
126 }
127 err = filter->Init(dart_this);
128 if (Dart_IsError(err)) {
129 // The finalizer was set up by SetFilter. It will delete `filter` if there
130 // is an error.
131 filter->Destroy();
132 Dart_PropagateError(err);
133 }
134 }
135
136
137 void FUNCTION_NAME(SecureSocket_Connect)(Dart_NativeArguments args) {
138 Dart_Handle host_name_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
139 Dart_Handle context_object = ThrowIfError(Dart_GetNativeArgument(args, 2));
140 bool is_server = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3));
141 bool request_client_certificate =
142 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 4));
143 bool require_client_certificate =
144 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 5));
145 Dart_Handle protocols_handle = ThrowIfError(Dart_GetNativeArgument(args, 6));
146
147 const char* host_name = NULL;
148 // TODO(whesse): Is truncating a Dart string containing \0 what we want?
149 ThrowIfError(Dart_StringToCString(host_name_object, &host_name));
150
151 SSLCertContext* context = NULL;
152 if (!Dart_IsNull(context_object)) {
153 ThrowIfError(Dart_GetNativeInstanceField(
154 context_object, SSLCertContext::kSecurityContextNativeFieldIndex,
155 reinterpret_cast<intptr_t*>(&context)));
156 }
157
158 // The protocols_handle is guaranteed to be a valid Uint8List.
159 // It will have the correct length encoding of the protocols array.
160 ASSERT(!Dart_IsNull(protocols_handle));
161 GetFilter(args)->Connect(host_name, context, is_server,
162 request_client_certificate,
163 require_client_certificate, protocols_handle);
164 }
165
166
167 void FUNCTION_NAME(SecureSocket_Destroy)(Dart_NativeArguments args) {
168 SSLFilter* filter = GetFilter(args);
169 // There are two paths that can clean up an SSLFilter object. First,
170 // there is this explicit call to Destroy(), called from
171 // _SecureFilter.destroy() in Dart code. After a call to destroy(), the Dart
172 // code maintains the invariant that there will be no futher SSLFilter
173 // requests sent to the IO Service. Therefore, the internals of the SSLFilter
174 // are safe to deallocate, but not the SSLFilter itself, which is already
175 // set up to be cleaned up by the finalizer.
176 //
177 // The second path is through the finalizer, which we have to do in case
178 // some mishap prevents a call to _SecureFilter.destroy().
179 filter->Destroy();
180 }
181
182
183 void FUNCTION_NAME(SecureSocket_Handshake)(Dart_NativeArguments args) {
184 GetFilter(args)->Handshake();
185 }
186
187
188 void FUNCTION_NAME(SecureSocket_GetSelectedProtocol)(
189 Dart_NativeArguments args) {
190 GetFilter(args)->GetSelectedProtocol(args);
191 }
192
193
194 void FUNCTION_NAME(SecureSocket_Renegotiate)(Dart_NativeArguments args) {
195 bool use_session_cache =
196 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 1));
197 bool request_client_certificate =
198 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 2));
199 bool require_client_certificate =
200 DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3));
201 GetFilter(args)->Renegotiate(use_session_cache, request_client_certificate,
202 require_client_certificate);
203 }
204
205
206 void FUNCTION_NAME(SecureSocket_RegisterHandshakeCompleteCallback)(
207 Dart_NativeArguments args) {
208 Dart_Handle handshake_complete =
209 ThrowIfError(Dart_GetNativeArgument(args, 1));
210 if (!Dart_IsClosure(handshake_complete)) {
211 Dart_ThrowException(DartUtils::NewDartArgumentError(
212 "Illegal argument to RegisterHandshakeCompleteCallback"));
213 }
214 GetFilter(args)->RegisterHandshakeCompleteCallback(handshake_complete);
215 }
216
217
218 void FUNCTION_NAME(SecureSocket_RegisterBadCertificateCallback)(
219 Dart_NativeArguments args) {
220 Dart_Handle callback = ThrowIfError(Dart_GetNativeArgument(args, 1));
221 if (!Dart_IsClosure(callback) && !Dart_IsNull(callback)) {
222 Dart_ThrowException(DartUtils::NewDartArgumentError(
223 "Illegal argument to RegisterBadCertificateCallback"));
224 }
225 GetFilter(args)->RegisterBadCertificateCallback(callback);
226 }
227
228
229 void FUNCTION_NAME(SecureSocket_PeerCertificate)(Dart_NativeArguments args) {
230 Dart_Handle cert = ThrowIfError(GetFilter(args)->PeerCertificate());
231 Dart_SetReturnValue(args, cert);
232 }
233
234
235 void FUNCTION_NAME(SecureSocket_FilterPointer)(Dart_NativeArguments args) {
236 SSLFilter* filter = GetFilter(args);
237 // This filter pointer is passed to the IO Service thread. The IO Service
238 // thread must Release() the pointer when it is done with it.
239 filter->Retain();
240 intptr_t filter_pointer = reinterpret_cast<intptr_t>(filter);
241 Dart_SetReturnValue(args, Dart_NewInteger(filter_pointer));
242 }
243
244
245 /**
246 * Pushes data through the SSL filter, reading and writing from circular
247 * buffers shared with Dart.
248 *
249 * The Dart _SecureFilterImpl class contains 4 ExternalByteArrays used to
250 * pass encrypted and plaintext data to and from the C++ SSLFilter object.
251 *
252 * ProcessFilter is called with a CObject array containing the pointer to
253 * the SSLFilter, encoded as an int, and the start and end positions of the
254 * valid data in the four circular buffers. The function only reads from
255 * the valid data area of the input buffers, and only writes to the free
256 * area of the output buffers. The function returns the new start and end
257 * positions in the buffers, but it only updates start for input buffers, and
258 * end for output buffers. Therefore, the Dart thread can simultaneously
259 * write to the free space and end pointer of input buffers, and read from
260 * the data space of output buffers, and modify the start pointer.
261 *
262 * When ProcessFilter returns, the Dart thread is responsible for combining
263 * the updated pointers from Dart and C++, to make the new valid state of
264 * the circular buffer.
265 */
266 CObject* SSLFilter::ProcessFilterRequest(const CObjectArray& request) {
267 CObjectIntptr filter_object(request[0]);
268 SSLFilter* filter = reinterpret_cast<SSLFilter*>(filter_object.Value());
269 RefCntReleaseScope<SSLFilter> rs(filter);
270
271 bool in_handshake = CObjectBool(request[1]).Value();
272 int starts[SSLFilter::kNumBuffers];
273 int ends[SSLFilter::kNumBuffers];
274 for (int i = 0; i < SSLFilter::kNumBuffers; ++i) {
275 starts[i] = CObjectInt32(request[2 * i + 2]).Value();
276 ends[i] = CObjectInt32(request[2 * i + 3]).Value();
277 }
278
279 if (filter->ProcessAllBuffers(starts, ends, in_handshake)) {
280 CObjectArray* result =
281 new CObjectArray(CObject::NewArray(SSLFilter::kNumBuffers * 2));
282 for (int i = 0; i < SSLFilter::kNumBuffers; ++i) {
283 result->SetAt(2 * i, new CObjectInt32(CObject::NewInt32(starts[i])));
284 result->SetAt(2 * i + 1, new CObjectInt32(CObject::NewInt32(ends[i])));
285 }
286 return result;
287 } else {
288 int32_t error_code = static_cast<int32_t>(ERR_peek_error());
289 TextBuffer error_string(SecureSocketUtils::SSL_ERROR_MESSAGE_BUFFER_SIZE);
290 SecureSocketUtils::FetchErrorString(filter->ssl_, &error_string);
291 CObjectArray* result = new CObjectArray(CObject::NewArray(2));
292 result->SetAt(0, new CObjectInt32(CObject::NewInt32(error_code)));
293 result->SetAt(1, new CObjectString(CObject::NewString(error_string.buf())));
294 return result;
295 }
296 }
297
298
299 bool SSLFilter::ProcessAllBuffers(int starts[kNumBuffers],
300 int ends[kNumBuffers],
301 bool in_handshake) {
302 for (int i = 0; i < kNumBuffers; ++i) {
303 if (in_handshake && (i == kReadPlaintext || i == kWritePlaintext)) continue;
304 int start = starts[i];
305 int end = ends[i];
306 int size = IsBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
307 if (start < 0 || end < 0 || start >= size || end >= size) {
308 FATAL("Out-of-bounds internal buffer access in dart:io SecureSocket");
309 }
310 switch (i) {
311 case kReadPlaintext:
312 case kWriteEncrypted:
313 // Write data to the circular buffer's free space. If the buffer
314 // is full, neither if statement is executed and nothing happens.
315 if (start <= end) {
316 // If the free space may be split into two segments,
317 // then the first is [end, size), unless start == 0.
318 // Then, since the last free byte is at position start - 2,
319 // the interval is [end, size - 1).
320 int buffer_end = (start == 0) ? size - 1 : size;
321 int bytes = (i == kReadPlaintext)
322 ? ProcessReadPlaintextBuffer(end, buffer_end)
323 : ProcessWriteEncryptedBuffer(end, buffer_end);
324 if (bytes < 0) return false;
325 end += bytes;
326 ASSERT(end <= size);
327 if (end == size) end = 0;
328 }
329 if (start > end + 1) {
330 int bytes = (i == kReadPlaintext)
331 ? ProcessReadPlaintextBuffer(end, start - 1)
332 : ProcessWriteEncryptedBuffer(end, start - 1);
333 if (bytes < 0) return false;
334 end += bytes;
335 ASSERT(end < start);
336 }
337 ends[i] = end;
338 break;
339 case kReadEncrypted:
340 case kWritePlaintext:
341 // Read/Write data from circular buffer. If the buffer is empty,
342 // neither if statement's condition is true.
343 if (end < start) {
344 // Data may be split into two segments. In this case,
345 // the first is [start, size).
346 int bytes = (i == kReadEncrypted)
347 ? ProcessReadEncryptedBuffer(start, size)
348 : ProcessWritePlaintextBuffer(start, size);
349 if (bytes < 0) return false;
350 start += bytes;
351 ASSERT(start <= size);
352 if (start == size) start = 0;
353 }
354 if (start < end) {
355 int bytes = (i == kReadEncrypted)
356 ? ProcessReadEncryptedBuffer(start, end)
357 : ProcessWritePlaintextBuffer(start, end);
358 if (bytes < 0) return false;
359 start += bytes;
360 ASSERT(start <= end);
361 }
362 starts[i] = start;
363 break;
364 default:
365 UNREACHABLE();
366 }
367 }
368 return true;
369 }
370
371
372 Dart_Handle SSLFilter::Init(Dart_Handle dart_this) {
373 if (!library_initialized_) {
374 InitializeLibrary();
375 }
376 ASSERT(string_start_ == NULL);
377 string_start_ = Dart_NewPersistentHandle(DartUtils::NewString("start"));
378 ASSERT(string_start_ != NULL);
379 ASSERT(string_length_ == NULL);
380 string_length_ = Dart_NewPersistentHandle(DartUtils::NewString("length"));
381 ASSERT(string_length_ != NULL);
382 ASSERT(bad_certificate_callback_ == NULL);
383 bad_certificate_callback_ = Dart_NewPersistentHandle(Dart_Null());
384 ASSERT(bad_certificate_callback_ != NULL);
385 // Caller handles cleanup on an error.
386 return InitializeBuffers(dart_this);
387 }
388
389
390 Dart_Handle SSLFilter::InitializeBuffers(Dart_Handle dart_this) {
391 // Create SSLFilter buffers as ExternalUint8Array objects.
392 Dart_Handle buffers_string = DartUtils::NewString("buffers");
393 RETURN_IF_ERROR(buffers_string);
394 Dart_Handle dart_buffers_object = Dart_GetField(dart_this, buffers_string);
395 RETURN_IF_ERROR(dart_buffers_object);
396 Dart_Handle secure_filter_impl_type = Dart_InstanceGetType(dart_this);
397 RETURN_IF_ERROR(secure_filter_impl_type);
398 Dart_Handle size_string = DartUtils::NewString("SIZE");
399 RETURN_IF_ERROR(size_string);
400 Dart_Handle dart_buffer_size =
401 Dart_GetField(secure_filter_impl_type, size_string);
402 RETURN_IF_ERROR(dart_buffer_size);
403
404 int64_t buffer_size = 0;
405 Dart_Handle err = Dart_IntegerToInt64(dart_buffer_size, &buffer_size);
406 RETURN_IF_ERROR(err);
407
408 Dart_Handle encrypted_size_string = DartUtils::NewString("ENCRYPTED_SIZE");
409 RETURN_IF_ERROR(encrypted_size_string);
410
411 Dart_Handle dart_encrypted_buffer_size =
412 Dart_GetField(secure_filter_impl_type, encrypted_size_string);
413 RETURN_IF_ERROR(dart_encrypted_buffer_size);
414
415 int64_t encrypted_buffer_size = 0;
416 err = Dart_IntegerToInt64(dart_encrypted_buffer_size, &encrypted_buffer_size);
417 RETURN_IF_ERROR(err);
418
419 if (buffer_size <= 0 || buffer_size > 1 * MB) {
420 FATAL("Invalid buffer size in _ExternalBuffer");
421 }
422 if (encrypted_buffer_size <= 0 || encrypted_buffer_size > 1 * MB) {
423 FATAL("Invalid encrypted buffer size in _ExternalBuffer");
424 }
425 buffer_size_ = static_cast<int>(buffer_size);
426 encrypted_buffer_size_ = static_cast<int>(encrypted_buffer_size);
427
428 Dart_Handle data_identifier = DartUtils::NewString("data");
429 RETURN_IF_ERROR(data_identifier);
430
431 for (int i = 0; i < kNumBuffers; i++) {
432 int size = IsBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
433 buffers_[i] = new uint8_t[size];
434 ASSERT(buffers_[i] != NULL);
435 dart_buffer_objects_[i] = NULL;
436 }
437
438 Dart_Handle result = Dart_Null();
439 for (int i = 0; i < kNumBuffers; ++i) {
440 int size = IsBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
441 result = Dart_ListGetAt(dart_buffers_object, i);
442 if (Dart_IsError(result)) {
443 break;
444 }
445
446 dart_buffer_objects_[i] = Dart_NewPersistentHandle(result);
447 ASSERT(dart_buffer_objects_[i] != NULL);
448 Dart_Handle data =
449 Dart_NewExternalTypedData(Dart_TypedData_kUint8, buffers_[i], size);
450 if (Dart_IsError(data)) {
451 result = data;
452 break;
453 }
454 result = Dart_HandleFromPersistent(dart_buffer_objects_[i]);
455 if (Dart_IsError(result)) {
456 break;
457 }
458 result = Dart_SetField(result, data_identifier, data);
459 if (Dart_IsError(result)) {
460 break;
461 }
462 }
463
464 // Caller handles cleanup on an error.
465 return result;
466 }
467
468
469 void SSLFilter::RegisterHandshakeCompleteCallback(Dart_Handle complete) {
470 ASSERT(NULL == handshake_complete_);
471 handshake_complete_ = Dart_NewPersistentHandle(complete);
472
473 ASSERT(handshake_complete_ != NULL);
474 }
475
476
477 void SSLFilter::RegisterBadCertificateCallback(Dart_Handle callback) {
478 ASSERT(bad_certificate_callback_ != NULL);
479 Dart_DeletePersistentHandle(bad_certificate_callback_);
480 bad_certificate_callback_ = Dart_NewPersistentHandle(callback);
481 ASSERT(bad_certificate_callback_ != NULL);
482 }
483
484
485 Dart_Handle SSLFilter::PeerCertificate() {
486 X509* ca = SSL_get_peer_certificate(ssl_);
487 if (ca == NULL) {
488 return Dart_Null();
489 }
490 return SSLFilter::WrappedX509Certificate(ca);
491 }
492
493
494 void SSLFilter::InitializeLibrary() {
495 MutexLocker locker(mutex_);
496 if (!library_initialized_) {
497 SSL_library_init();
498 filter_ssl_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
499 ASSERT(filter_ssl_index >= 0);
500 library_initialized_ = true;
501 }
502 }
503
504
505 void SSLFilter::Connect(const char* hostname,
506 SSLCertContext* context,
507 bool is_server,
508 bool request_client_certificate,
509 bool require_client_certificate,
510 Dart_Handle protocols_handle) {
511 is_server_ = is_server;
512 if (in_handshake_) {
513 FATAL("Connect called twice on the same _SecureFilter.");
514 }
515
516 int status;
517 int error;
518 BIO* ssl_side;
519 status = BIO_new_bio_pair(&ssl_side, kInternalBIOSize, &socket_side_,
520 kInternalBIOSize);
521 SecureSocketUtils::CheckStatusSSL(status, "TlsException", "BIO_new_bio_pair",
522 ssl_);
523
524 ASSERT(context != NULL);
525 ASSERT(context->context() != NULL);
526 ssl_ = SSL_new(context->context());
527 SSL_set_bio(ssl_, ssl_side, ssl_side);
528 SSL_set_mode(ssl_, SSL_MODE_AUTO_RETRY); // TODO(whesse): Is this right?
529 SSL_set_ex_data(ssl_, filter_ssl_index, this);
530 context->RegisterCallbacks(ssl_);
531
532 if (is_server_) {
533 int certificate_mode =
534 request_client_certificate ? SSL_VERIFY_PEER : SSL_VERIFY_NONE;
535 if (require_client_certificate) {
536 certificate_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
537 }
538 SSL_set_verify(ssl_, certificate_mode, NULL);
539 } else {
540 SSLCertContext::SetAlpnProtocolList(protocols_handle, ssl_, NULL, false);
541 status = SSL_set_tlsext_host_name(ssl_, hostname);
542 SecureSocketUtils::CheckStatusSSL(status, "TlsException",
543 "Set SNI host name", ssl_);
544 // Sets the hostname in the certificate-checking object, so it is checked
545 // against the certificate presented by the server.
546 X509_VERIFY_PARAM* certificate_checking_parameters = SSL_get0_param(ssl_);
547 hostname_ = strdup(hostname);
548 X509_VERIFY_PARAM_set_flags(
549 certificate_checking_parameters,
550 X509_V_FLAG_PARTIAL_CHAIN | X509_V_FLAG_TRUSTED_FIRST);
551 X509_VERIFY_PARAM_set_hostflags(certificate_checking_parameters, 0);
552 status = X509_VERIFY_PARAM_set1_host(certificate_checking_parameters,
553 hostname_, strlen(hostname_));
554 SecureSocketUtils::CheckStatusSSL(
555 status, "TlsException", "Set hostname for certificate checking", ssl_);
556 }
557 // Make the connection:
558 if (is_server_) {
559 status = SSL_accept(ssl_);
560 if (SSL_LOG_STATUS) {
561 Log::Print("SSL_accept status: %d\n", status);
562 }
563 if (status != 1) {
564 // TODO(whesse): expect a needs-data error here. Handle other errors.
565 error = SSL_get_error(ssl_, status);
566 if (SSL_LOG_STATUS) {
567 Log::Print("SSL_accept error: %d\n", error);
568 }
569 }
570 } else {
571 status = SSL_connect(ssl_);
572 if (SSL_LOG_STATUS) {
573 Log::Print("SSL_connect status: %d\n", status);
574 }
575 if (status != 1) {
576 // TODO(whesse): expect a needs-data error here. Handle other errors.
577 error = SSL_get_error(ssl_, status);
578 if (SSL_LOG_STATUS) {
579 Log::Print("SSL_connect error: %d\n", error);
580 }
581 }
582 }
583 Handshake();
584 }
585
586
587 void SSLFilter::Handshake() {
588 // Try and push handshake along.
589 int status;
590 status = SSL_do_handshake(ssl_);
591 if (callback_error != NULL) {
592 // The SSL_do_handshake will try performing a handshake and might call
593 // a CertificateCallback. If the certificate validation
594 // failed the 'callback_error" will be set by the certificateCallback
595 // logic and we propagate the error"
596 Dart_PropagateError(callback_error);
597 }
598 if (SSL_want_write(ssl_) || SSL_want_read(ssl_)) {
599 in_handshake_ = true;
600 return;
601 }
602 SecureSocketUtils::CheckStatusSSL(
603 status, "HandshakeException",
604 is_server_ ? "Handshake error in server" : "Handshake error in client",
605 ssl_);
606 // Handshake succeeded.
607 if (in_handshake_) {
608 // TODO(24071): Check return value of SSL_get_verify_result, this
609 // should give us the hostname check.
610 int result = SSL_get_verify_result(ssl_);
611 if (SSL_LOG_STATUS) {
612 Log::Print("Handshake verification status: %d\n", result);
613 X509* peer_certificate = SSL_get_peer_certificate(ssl_);
614 if (peer_certificate == NULL) {
615 Log::Print("No peer certificate received\n");
616 } else {
617 X509_NAME* s_name = X509_get_subject_name(peer_certificate);
618 printf("Peer certificate SN: ");
619 X509_NAME_print_ex_fp(stdout, s_name, 4, 0);
620 printf("\n");
621 }
622 }
623 ThrowIfError(Dart_InvokeClosure(
624 Dart_HandleFromPersistent(handshake_complete_), 0, NULL));
625 in_handshake_ = false;
626 }
627 }
628
629
630 void SSLFilter::GetSelectedProtocol(Dart_NativeArguments args) {
631 const uint8_t* protocol;
632 unsigned length;
633 SSL_get0_alpn_selected(ssl_, &protocol, &length);
634 if (length == 0) {
635 Dart_SetReturnValue(args, Dart_Null());
636 } else {
637 Dart_SetReturnValue(args, Dart_NewStringFromUTF8(protocol, length));
638 }
639 }
640
641
642 void SSLFilter::Renegotiate(bool use_session_cache,
643 bool request_client_certificate,
644 bool require_client_certificate) {
645 // The SSL_REQUIRE_CERTIFICATE option only takes effect if the
646 // SSL_REQUEST_CERTIFICATE option is also set, so set it.
647 request_client_certificate =
648 request_client_certificate || require_client_certificate;
649 // TODO(24070, 24069): Implement setting the client certificate parameters,
650 // and triggering rehandshake.
651 }
652
653
654 static void ReleaseCertificate(void* isolate_data,
655 Dart_WeakPersistentHandle handle,
656 void* context_pointer) {
657 X509* cert = reinterpret_cast<X509*>(context_pointer);
658 X509_free(cert);
659 }
660
661
662 static intptr_t EstimateX509Size(X509* certificate) {
663 intptr_t length = i2d_X509(certificate, NULL);
664 return length > 0 ? length : 0;
665 }
666
667
668 // Returns the handle for a Dart object wrapping the X509 certificate object.
669 // The caller should own a reference to the X509 object whose reference count
670 // won't drop to zero before the ReleaseCertificate finalizer runs.
671 Dart_Handle SSLFilter::WrappedX509Certificate(X509* certificate) {
672 if (certificate == NULL) {
673 return Dart_Null();
674 }
675 Dart_Handle x509_type =
676 DartUtils::GetDartType(DartUtils::kIOLibURL, "X509Certificate");
677 if (Dart_IsError(x509_type)) {
678 X509_free(certificate);
679 return x509_type;
680 }
681 Dart_Handle arguments[] = {NULL};
682 Dart_Handle result =
683 Dart_New(x509_type, DartUtils::NewString("_"), 0, arguments);
684 if (Dart_IsError(result)) {
685 X509_free(certificate);
686 return result;
687 }
688 ASSERT(Dart_IsInstance(result));
689 Dart_Handle status =
690 Dart_SetNativeInstanceField(result, SSLCertContext::kX509NativeFieldIndex,
691 reinterpret_cast<intptr_t>(certificate));
692 if (Dart_IsError(status)) {
693 X509_free(certificate);
694 return status;
695 }
696 const intptr_t approximate_size_of_certificate =
697 sizeof(*certificate) + EstimateX509Size(certificate);
698 ASSERT(approximate_size_of_certificate > 0);
699 Dart_NewWeakPersistentHandle(result, reinterpret_cast<void*>(certificate),
700 approximate_size_of_certificate,
701 ReleaseCertificate);
702 return result;
703 }
704
705
706 void SSLFilter::FreeResources() {
707 if (ssl_ != NULL) {
708 SSL_free(ssl_);
709 ssl_ = NULL;
710 }
711 if (socket_side_ != NULL) {
712 BIO_free(socket_side_);
713 socket_side_ = NULL;
714 }
715 if (hostname_ != NULL) {
716 free(hostname_);
717 hostname_ = NULL;
718 }
719 for (int i = 0; i < kNumBuffers; ++i) {
720 if (buffers_[i] != NULL) {
721 delete[] buffers_[i];
722 buffers_[i] = NULL;
723 }
724 }
725 }
726
727
728 SSLFilter::~SSLFilter() {
729 FreeResources();
730 }
731
732
733 void SSLFilter::Destroy() {
734 for (int i = 0; i < kNumBuffers; ++i) {
735 if (dart_buffer_objects_[i] != NULL) {
736 Dart_DeletePersistentHandle(dart_buffer_objects_[i]);
737 dart_buffer_objects_[i] = NULL;
738 }
739 }
740 if (string_start_ != NULL) {
741 Dart_DeletePersistentHandle(string_start_);
742 string_start_ = NULL;
743 }
744 if (string_length_ != NULL) {
745 Dart_DeletePersistentHandle(string_length_);
746 string_length_ = NULL;
747 }
748 if (handshake_complete_ != NULL) {
749 Dart_DeletePersistentHandle(handshake_complete_);
750 handshake_complete_ = NULL;
751 }
752 if (bad_certificate_callback_ != NULL) {
753 Dart_DeletePersistentHandle(bad_certificate_callback_);
754 bad_certificate_callback_ = NULL;
755 }
756 FreeResources();
757 }
758
759
760 /* Read decrypted data from the filter to the circular buffer */
761 int SSLFilter::ProcessReadPlaintextBuffer(int start, int end) {
762 int length = end - start;
763 int bytes_processed = 0;
764 if (length > 0) {
765 bytes_processed = SSL_read(
766 ssl_, reinterpret_cast<char*>((buffers_[kReadPlaintext] + start)),
767 length);
768 if (bytes_processed < 0) {
769 int error = SSL_get_error(ssl_, bytes_processed);
770 USE(error);
771 bytes_processed = 0;
772 }
773 }
774 return bytes_processed;
775 }
776
777
778 int SSLFilter::ProcessWritePlaintextBuffer(int start, int end) {
779 int length = end - start;
780 int bytes_processed =
781 SSL_write(ssl_, buffers_[kWritePlaintext] + start, length);
782 if (bytes_processed < 0) {
783 if (SSL_LOG_DATA) {
784 Log::Print("SSL_write returned error %d\n", bytes_processed);
785 }
786 return 0;
787 }
788 return bytes_processed;
789 }
790
791
792 /* Read encrypted data from the circular buffer to the filter */
793 int SSLFilter::ProcessReadEncryptedBuffer(int start, int end) {
794 int length = end - start;
795 if (SSL_LOG_DATA)
796 Log::Print("Entering ProcessReadEncryptedBuffer with %d bytes\n", length);
797 int bytes_processed = 0;
798 if (length > 0) {
799 bytes_processed =
800 BIO_write(socket_side_, buffers_[kReadEncrypted] + start, length);
801 if (bytes_processed <= 0) {
802 bool retry = BIO_should_retry(socket_side_);
803 if (!retry) {
804 if (SSL_LOG_DATA)
805 Log::Print("BIO_write failed in ReadEncryptedBuffer\n");
806 }
807 bytes_processed = 0;
808 }
809 }
810 if (SSL_LOG_DATA)
811 Log::Print("Leaving ProcessReadEncryptedBuffer wrote %d bytes\n",
812 bytes_processed);
813 return bytes_processed;
814 }
815
816
817 int SSLFilter::ProcessWriteEncryptedBuffer(int start, int end) {
818 int length = end - start;
819 int bytes_processed = 0;
820 if (length > 0) {
821 bytes_processed =
822 BIO_read(socket_side_, buffers_[kWriteEncrypted] + start, length);
823 if (bytes_processed < 0) {
824 if (SSL_LOG_DATA)
825 Log::Print("WriteEncrypted BIO_read returned error %d\n",
826 bytes_processed);
827 return 0;
828 } else {
829 if (SSL_LOG_DATA)
830 Log::Print("WriteEncrypted BIO_read wrote %d bytes\n",
831 bytes_processed);
832 }
833 }
834 return bytes_processed;
835 }
836
837 } // namespace bin
838 } // namespace dart
839
840 #endif // !defined(DART_IO_DISABLED) &&
841 // !defined(DART_IO_SECURE_SOCKET_DISABLED)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698