Index: runtime/bin/secure_socket.cc |
diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc |
index 482f9a640cbb4e333041f481bc062c6346851e36..e4fab51ee2973a3e4e1f7e0e6c772c515bcc2253 100644 |
--- a/runtime/bin/secure_socket.cc |
+++ b/runtime/bin/secure_socket.cc |
@@ -41,6 +41,13 @@ dart::Mutex SSLFilter::mutex_; // To protect library initialization. |
// be null if only secure client sockets are used. |
const char* SSLFilter::password_ = NULL; |
+// Forward declaration. |
+static void ProcessFilter(Dart_Port dest_port_id, |
+ Dart_Port reply_port_id, |
+ Dart_CObject* message); |
+ |
+NativeService SSLFilter::filter_service_("FilterService", ProcessFilter, 16); |
+ |
static const int kSSLFilterNativeFieldIndex = 0; |
static SSLFilter* GetFilter(Dart_NativeArguments args) { |
@@ -177,22 +184,6 @@ void FUNCTION_NAME(SecureSocket_RegisterBadCertificateCallback)( |
} |
-void FUNCTION_NAME(SecureSocket_ProcessBuffer)(Dart_NativeArguments args) { |
- Dart_EnterScope(); |
- Dart_Handle buffer_id_object = ThrowIfError(Dart_GetNativeArgument(args, 1)); |
- int64_t buffer_id = DartUtils::GetIntegerValue(buffer_id_object); |
- if (buffer_id < 0 || buffer_id >= SSLFilter::kNumBuffers) { |
- Dart_ThrowException(DartUtils::NewDartArgumentError( |
- "Illegal argument to ProcessBuffer")); |
- } |
- |
- intptr_t bytes_read = |
- GetFilter(args)->ProcessBuffer(static_cast<int>(buffer_id)); |
- Dart_SetReturnValue(args, Dart_NewInteger(bytes_read)); |
- Dart_ExitScope(); |
-} |
- |
- |
void FUNCTION_NAME(SecureSocket_InitializeLibrary) |
(Dart_NativeArguments args) { |
Dart_EnterScope(); |
@@ -247,6 +238,131 @@ void FUNCTION_NAME(SecureSocket_PeerCertificate) |
} |
+void FUNCTION_NAME(SecureSocket_FilterPointer)(Dart_NativeArguments args) { |
+ Dart_EnterScope(); |
+ intptr_t filter_pointer = reinterpret_cast<intptr_t>(GetFilter(args)); |
+ Dart_SetReturnValue(args, Dart_NewInteger(filter_pointer)); |
+ Dart_ExitScope(); |
+} |
+ |
+ |
+/** |
+ * Pushes data through the SSL filter, reading and writing from circular |
+ * buffers shared with Dart. |
+ * |
+ * The Dart _SecureFilterImpl class contains 4 ExternalByteArrays used to |
+ * pass encrypted and plaintext data to and from the C++ SSLFilter object. |
+ * |
+ * ProcessFilter is called with a CObject array containing the pointer to |
+ * the SSLFilter, encoded as an int, and the start and end positions of the |
+ * valid data in the four circular buffers. The function only reads from |
+ * the valid data area of the input buffers, and only writes to the free |
+ * area of the output buffers. The function returns the new start and end |
+ * positions in the buffers, but it only updates start for input buffers, and |
+ * end for output buffers. Therefore, the Dart thread can simultaneously |
+ * write to the free space and end pointer of input buffers, and read from |
+ * the data space of output buffers, and modify the start pointer. |
+ * |
+ * When ProcessFilter returns, the Dart thread is responsible for combining |
+ * the updated pointers from Dart and C++, to make the new valid state of |
+ * the circular buffer. |
+ */ |
+static void ProcessFilter(Dart_Port dest_port_id, |
+ Dart_Port reply_port_id, |
+ Dart_CObject* message) { |
+ CObjectArray args(message); |
+ CObjectIntptr filter_object(args[0]); |
+ SSLFilter* filter = reinterpret_cast<SSLFilter*>(filter_object.Value()); |
+ bool in_handshake = CObjectBool(args[1]).Value(); |
+ int starts[SSLFilter::kNumBuffers]; |
+ int ends[SSLFilter::kNumBuffers]; |
+ for (int i = 0; i < SSLFilter::kNumBuffers; ++i) { |
+ starts[i] = CObjectInt32(args[2 * i + 2]).Value(); |
+ ends[i] = CObjectInt32(args[2 * i + 3]).Value(); |
+ } |
+ |
+ filter->ProcessAllBuffers(starts, ends, in_handshake); |
+ |
+ for (int i = 0; i < SSLFilter::kNumBuffers; ++i) { |
+ args[2 * i + 2]->AsApiCObject()->value.as_int32 = starts[i]; |
+ args[2 * i + 3]->AsApiCObject()->value.as_int32 = ends[i]; |
+ } |
+ Dart_PostCObject(reply_port_id, args.AsApiCObject()); |
+} |
+ |
+ |
+void SSLFilter::ProcessAllBuffers(int starts[kNumBuffers], |
+ int ends[kNumBuffers], |
+ bool in_handshake) { |
+ for (int i = 0; i < kNumBuffers; ++i) { |
+ if (in_handshake && (i == kReadPlaintext || i == kWritePlaintext)) continue; |
+ int start = starts[i]; |
+ int end = ends[i]; |
+ int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_; |
+ switch (i) { |
+ case kReadPlaintext: |
+ case kWriteEncrypted: |
+ // Write data to the circular buffer's free space. If the buffer |
+ // is full, neither if statement is executed and nothing happens. |
+ if (start <= end) { |
+ // If the free space may be split into two segments, |
+ // then the first is [end, size), unless start == 0. |
+ // Then, since the last free byte is at position start - 2, |
+ // the interval is [end, size - 1). |
+ int buffer_end = (start == 0) ? size - 1 : size; |
+ int bytes = (i == kReadPlaintext) ? |
+ ProcessReadPlaintextBuffer(end, buffer_end) : |
+ ProcessWriteEncryptedBuffer(end, buffer_end); |
+ end += bytes; |
+ ASSERT(end <= size); |
+ if (end == size) end = 0; |
+ } |
+ if (start > end + 1) { |
+ int bytes = (i == kReadPlaintext) ? |
+ ProcessReadPlaintextBuffer(end, start - 1) : |
+ ProcessWriteEncryptedBuffer(end, start - 1); |
+ end += bytes; |
+ ASSERT(end < start); |
+ } |
+ ends[i] = end; |
+ break; |
+ case kReadEncrypted: |
+ // Read data from circular buffer. |
+ if (end < start) { |
+ // Data may be split into two segments. In this case, |
+ // the first is [start, size). |
+ int bytes = ProcessReadEncryptedBuffer(start, size); |
+ start += bytes; |
+ ASSERT(start <= size); |
+ if (start == size) start = 0; |
+ } |
+ if (start < end) { |
+ int bytes = ProcessReadEncryptedBuffer(start, end); |
+ start += bytes; |
+ ASSERT(start <= end); |
+ } |
+ starts[i] = start; |
+ break; |
+ case kWritePlaintext: |
+ if (end < start) { |
+ // Data is split into two segments, [start, size) and [0, end). |
+ int bytes = ProcessWritePlaintextBuffer(start, size, 0, end); |
+ start += bytes; |
+ if (start >= size) start -= size; |
+ } else { |
+ int bytes = ProcessWritePlaintextBuffer(start, end, 0, 0); |
+ start += bytes; |
+ ASSERT(start <= end); |
+ } |
+ starts[i] = start; |
+ break; |
+ default: |
+ UNREACHABLE(); |
+ } |
+ } |
+} |
+ |
+ |
static Dart_Handle X509FromCertificate(CERTCertificate* certificate) { |
PRTime start_validity; |
PRTime end_validity; |
@@ -307,15 +423,13 @@ void SSLFilter::InitializeBuffers(Dart_Handle dart_this) { |
// Create SSLFilter buffers as ExternalUint8Array objects. |
Dart_Handle dart_buffers_object = ThrowIfError( |
Dart_GetField(dart_this, DartUtils::NewString("buffers"))); |
- Dart_Handle dart_buffer_object = |
- Dart_ListGetAt(dart_buffers_object, kReadPlaintext); |
- Dart_Handle external_buffer_class = |
- Dart_InstanceGetClass(dart_buffer_object); |
+ Dart_Handle secure_filter_impl_class = |
+ Dart_InstanceGetClass(dart_this); |
Dart_Handle dart_buffer_size = ThrowIfError( |
- Dart_GetField(external_buffer_class, DartUtils::NewString("SIZE"))); |
+ Dart_GetField(secure_filter_impl_class, DartUtils::NewString("SIZE"))); |
int64_t buffer_size = DartUtils::GetIntegerValue(dart_buffer_size); |
Dart_Handle dart_encrypted_buffer_size = ThrowIfError( |
- Dart_GetField(external_buffer_class, |
+ Dart_GetField(secure_filter_impl_class, |
DartUtils::NewString("ENCRYPTED_SIZE"))); |
int64_t encrypted_buffer_size = |
DartUtils::GetIntegerValue(dart_encrypted_buffer_size); |
@@ -333,7 +447,7 @@ void SSLFilter::InitializeBuffers(Dart_Handle dart_this) { |
Dart_Handle data_identifier = DartUtils::NewString("data"); |
for (int i = 0; i < kNumBuffers; ++i) { |
- int size = isEncrypted(i) ? encrypted_buffer_size_ : buffer_size_; |
+ int size = isBufferEncrypted(i) ? encrypted_buffer_size_ : buffer_size_; |
dart_buffer_objects_[i] = |
Dart_NewPersistentHandle(Dart_ListGetAt(dart_buffers_object, i)); |
ASSERT(dart_buffer_objects_[i] != NULL); |
@@ -494,6 +608,11 @@ void SSLFilter::Connect(const char* host_name, |
ThrowPRException("Failed SSL_ImportFD call"); |
} |
+ SSLVersionRange vrange; |
+ vrange.min = SSL_LIBRARY_VERSION_3_0; |
+ vrange.max = SSL_LIBRARY_VERSION_TLS_1_1; |
+ SSL_VersionRangeSet(filter_, &vrange); |
+ |
SECStatus status; |
if (is_server) { |
PK11_SetPasswordFunc(PasswordCallback); |
@@ -648,106 +767,112 @@ void SSLFilter::Destroy() { |
} |
-intptr_t SSLFilter::ProcessBuffer(int buffer_index) { |
- int size = isEncrypted(buffer_index) ? encrypted_buffer_size_ : buffer_size_; |
- Dart_Handle buffer_object = |
- Dart_HandleFromPersistent(dart_buffer_objects_[buffer_index]); |
- Dart_Handle start_object = ThrowIfError( |
- Dart_GetField(buffer_object, Dart_HandleFromPersistent(string_start_))); |
- Dart_Handle length_object = ThrowIfError( |
- Dart_GetField(buffer_object, Dart_HandleFromPersistent(string_length_))); |
- int64_t unsafe_start = DartUtils::GetIntegerValue(start_object); |
- int64_t unsafe_length = DartUtils::GetIntegerValue(length_object); |
- ASSERT(unsafe_start >= 0); |
- ASSERT(unsafe_start < size); |
- ASSERT(unsafe_length >= 0); |
- ASSERT(unsafe_length <= size); |
- int start = static_cast<int>(unsafe_start); |
- int length = static_cast<int>(unsafe_length); |
- uint8_t* buffer = buffers_[buffer_index]; |
- |
+intptr_t SSLFilter::ProcessReadPlaintextBuffer(int start, int end) { |
+ int length = end - start; |
int bytes_processed = 0; |
- switch (buffer_index) { |
- case kReadPlaintext: { |
- int bytes_free = size - start - length; |
- bytes_processed = PR_Read(filter_, |
- buffer + start + length, |
- bytes_free); |
- if (bytes_processed < 0) { |
- ASSERT(bytes_processed == -1); |
- // TODO(whesse): Handle unexpected errors here. |
- PRErrorCode pr_error = PR_GetError(); |
- if (PR_WOULD_BLOCK_ERROR != pr_error) { |
- ThrowPRException("Error reading plaintext from SSLFilter"); |
- } |
- bytes_processed = 0; |
+ if (length > 0) { |
+ bytes_processed = PR_Read(filter_, |
+ buffers_[kReadPlaintext] + start, |
+ length); |
+ if (bytes_processed < 0) { |
+ ASSERT(bytes_processed == -1); |
+ PRErrorCode pr_error = PR_GetError(); |
+ if (PR_WOULD_BLOCK_ERROR != pr_error) { |
+ // TODO(11383): Handle unexpected errors here. |
+ FATAL("Error reading plaintext from SSLFilter"); |
} |
- break; |
+ bytes_processed = 0; |
} |
+ } |
+ return bytes_processed; |
+} |
- case kWriteEncrypted: { |
- const uint8_t* buf1; |
- const uint8_t* buf2; |
- unsigned int len1; |
- unsigned int len2; |
- int bytes_free = size - start - length; |
- memio_Private* secret = memio_GetSecret(filter_); |
- memio_GetWriteParams(secret, &buf1, &len1, &buf2, &len2); |
- int bytes_to_send = |
- dart::Utils::Minimum(len1, static_cast<unsigned>(bytes_free)); |
- if (bytes_to_send > 0) { |
- memmove(buffer + start + length, buf1, bytes_to_send); |
- bytes_processed = bytes_to_send; |
- } |
- bytes_to_send = dart::Utils::Minimum(len2, |
- static_cast<unsigned>(bytes_free - bytes_processed)); |
- if (bytes_to_send > 0) { |
- memmove(buffer + start + length + bytes_processed, buf2, |
- bytes_to_send); |
- bytes_processed += bytes_to_send; |
- } |
- if (bytes_processed > 0) { |
- memio_PutWriteResult(secret, bytes_processed); |
- } |
- break; |
- } |
- case kReadEncrypted: { |
- if (length > 0) { |
- bytes_processed = length; |
- memio_Private* secret = memio_GetSecret(filter_); |
- uint8_t* filter_buf; |
- int free_bytes = memio_GetReadParams(secret, &filter_buf); |
- if (free_bytes < bytes_processed) bytes_processed = free_bytes; |
- memmove(filter_buf, |
- buffer + start, |
- bytes_processed); |
- memio_PutReadResult(secret, bytes_processed); |
- } |
- break; |
+intptr_t SSLFilter::ProcessWritePlaintextBuffer(int start1, int end1, |
+ int start2, int end2) { |
+ PRIOVec ranges[2]; |
+ uint8_t* buffer = buffers_[kWritePlaintext]; |
+ ranges[0].iov_base = reinterpret_cast<char*>(buffer + start1); |
+ ranges[0].iov_len = end1 - start1; |
+ ranges[1].iov_base = reinterpret_cast<char*>(buffer + start2); |
+ ranges[1].iov_len = end2 - start2; |
+ int bytes_processed = PR_Writev(filter_, ranges, 2, PR_INTERVAL_NO_TIMEOUT); |
+ if (bytes_processed < 0) { |
+ ASSERT(bytes_processed == -1); |
+ PRErrorCode pr_error = PR_GetError(); |
+ if (PR_WOULD_BLOCK_ERROR != pr_error) { |
+ // TODO(11383): Handle unexpected errors here. |
+ FATAL("Error reading plaintext from SSLFilter"); |
} |
+ bytes_processed = 0; |
+ } |
+ return bytes_processed; |
+} |
- case kWritePlaintext: { |
- if (length > 0) { |
- bytes_processed = PR_Write(filter_, |
- buffer + start, |
- length); |
- } |
- if (bytes_processed < 0) { |
- ASSERT(bytes_processed == -1); |
- // TODO(whesse): Handle unexpected errors here. |
- PRErrorCode pr_error = PR_GetError(); |
- if (PR_WOULD_BLOCK_ERROR != pr_error) { |
- ThrowPRException("Error reading plaintext from SSLFilter"); |
- } |
- bytes_processed = 0; |
- } |
- break; |
+intptr_t SSLFilter::ProcessReadEncryptedBuffer(int start, int end) { |
+ int length = end - start; |
+ int bytes_processed = 0; |
+ if (length > 0) { |
+ memio_Private* secret = memio_GetSecret(filter_); |
+ uint8_t* filter_buf; |
+ int free_bytes = memio_GetReadParams(secret, &filter_buf); |
+ bytes_processed = dart::Utils::Minimum(length, free_bytes); |
+ memmove(filter_buf, buffers_[kReadEncrypted] + start, bytes_processed); |
+ memio_PutReadResult(secret, bytes_processed); |
+ } |
+ return bytes_processed; |
+} |
+ |
+ |
+intptr_t SSLFilter::ProcessWriteEncryptedBuffer(int start, int end) { |
+ int length = end - start; |
+ int bytes_processed = 0; |
+ if (length > 0) { |
+ uint8_t* buffer = buffers_[kWriteEncrypted]; |
+ const uint8_t* buf1; |
+ const uint8_t* buf2; |
+ unsigned int len1; |
+ unsigned int len2; |
+ memio_Private* secret = memio_GetSecret(filter_); |
+ memio_GetWriteParams(secret, &buf1, &len1, &buf2, &len2); |
+ int bytes_to_send = |
+ dart::Utils::Minimum(len1, static_cast<unsigned>(length)); |
+ if (bytes_to_send > 0) { |
+ memmove(buffer + start, buf1, bytes_to_send); |
+ bytes_processed = bytes_to_send; |
+ } |
+ bytes_to_send = dart::Utils::Minimum(len2, |
+ static_cast<unsigned>(length - bytes_processed)); |
+ if (bytes_to_send > 0) { |
+ memmove(buffer + start + bytes_processed, buf2, bytes_to_send); |
+ bytes_processed += bytes_to_send; |
+ } |
+ if (bytes_processed > 0) { |
+ memio_PutWriteResult(secret, bytes_processed); |
} |
} |
return bytes_processed; |
} |
+ |
+Dart_Port SSLFilter::GetServicePort() { |
+ return filter_service_.GetServicePort(); |
+} |
+ |
+ |
+void FUNCTION_NAME(SecureSocket_NewServicePort)(Dart_NativeArguments args) { |
+ Dart_EnterScope(); |
+ Dart_SetReturnValue(args, Dart_Null()); |
+ Dart_Port service_port = SSLFilter::GetServicePort(); |
+ if (service_port != ILLEGAL_PORT) { |
+ // Return a send port for the service port. |
+ Dart_Handle send_port = Dart_NewSendPort(service_port); |
+ Dart_SetReturnValue(args, send_port); |
+ } |
+ Dart_ExitScope(); |
+} |
+ |
+ |
} // namespace bin |
} // namespace dart |