// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #ifndef RUNTIME_BIN_SECURE_SOCKET_UTILS_H_ #define RUNTIME_BIN_SECURE_SOCKET_UTILS_H_ #include #include #include #include #include #include "platform/globals.h" #include "bin/dartutils.h" #include "platform/text_buffer.h" namespace dart { namespace bin { const bool SSL_LOG_STATUS = false; const bool SSL_LOG_DATA = false; const bool SSL_LOG_CERTS = false; class SecureSocketUtils : public AllStatic { public: static constexpr int SSL_ERROR_MESSAGE_BUFFER_SIZE = 1000; static void ThrowIOException(int status, const char* exception_type, const char* message, const SSL* ssl); static void CheckStatusSSL(int status, const char* type, const char* message, const SSL* ssl); static void CheckStatus(int status, const char* type, const char* message); static bool IsCurrentTimeInsideCertValidDateRange(X509* root_cert); static bool NoPEMStartLine() { uint32_t last_error = ERR_peek_last_error(); return (ERR_GET_LIB(last_error) == ERR_LIB_PEM) && (ERR_GET_REASON(last_error) == PEM_R_NO_START_LINE); } static uint32_t FetchErrorString(const SSL* ssl, TextBuffer* text_buffer); }; // Where the argument to the constructor is the handle for an object // implementing List, this class creates a scope in which a memory-backed // BIO is allocated. Leaving the scope cleans up the BIO and the buffer that // was used to create it. // // Do not make Dart_ API calls while in a ScopedMemBIO. // Do not call Dart_PropagateError while in a ScopedMemBIO. class ScopedMemBIO { public: explicit ScopedMemBIO(Dart_Handle object) { if (!Dart_IsTypedData(object) && !Dart_IsList(object)) { Dart_ThrowException( DartUtils::NewDartArgumentError("Argument is not a List")); } uint8_t* bytes = nullptr; intptr_t bytes_len = 0; bool is_typed_data = false; if (Dart_IsTypedData(object)) { is_typed_data = true; Dart_TypedData_Type typ; ThrowIfError(Dart_TypedDataAcquireData( object, &typ, reinterpret_cast(&bytes), &bytes_len)); } else { ASSERT(Dart_IsList(object)); ThrowIfError(Dart_ListLength(object, &bytes_len)); bytes = Dart_ScopeAllocate(bytes_len); ASSERT(bytes != nullptr); ThrowIfError(Dart_ListGetAsBytes(object, 0, bytes, bytes_len)); } object_ = object; bytes_ = bytes; bytes_len_ = bytes_len; bio_ = BIO_new_mem_buf(bytes, bytes_len); ASSERT(bio_ != nullptr); is_typed_data_ = is_typed_data; } ~ScopedMemBIO() { ASSERT(bio_ != nullptr); if (is_typed_data_) { BIO_free(bio_); ThrowIfError(Dart_TypedDataReleaseData(object_)); } else { BIO_free(bio_); } } BIO* bio() { ASSERT(bio_ != nullptr); return bio_; } uint8_t* data() { return bytes_; } intptr_t length() { return bytes_len_; } private: Dart_Handle object_; uint8_t* bytes_; intptr_t bytes_len_; BIO* bio_; bool is_typed_data_; DISALLOW_ALLOCATION(); DISALLOW_COPY_AND_ASSIGN(ScopedMemBIO); }; template class ScopedSSLType { public: explicit ScopedSSLType(T* obj) : obj_(obj) {} ~ScopedSSLType() { if (obj_ != nullptr) { free_func(obj_); } } T* get() { return obj_; } const T* get() const { return obj_; } T* release() { T* result = obj_; obj_ = nullptr; return result; } private: T* obj_; DISALLOW_ALLOCATION(); DISALLOW_COPY_AND_ASSIGN(ScopedSSLType); }; template class ScopedSSLStackType { public: explicit ScopedSSLStackType(T* obj) : obj_(obj) {} ~ScopedSSLStackType() { if (obj_ != nullptr) { OPENSSL_sk_pop_free_ex(reinterpret_cast(obj_), call_free_func, free_func); } } T* get() { return obj_; } const T* get() const { return obj_; } T* release() { T* result = obj_; obj_ = nullptr; return result; } private: static void free_func(void* element) { func(reinterpret_cast(element)); } static void call_free_func(void (*free_func)(void*), void* element) { free_func(element); } T* obj_; DISALLOW_ALLOCATION(); DISALLOW_COPY_AND_ASSIGN(ScopedSSLStackType); }; typedef ScopedSSLType ScopedPKCS12; typedef ScopedSSLType ScopedX509; typedef ScopedSSLStackType ScopedX509Stack; } // namespace bin } // namespace dart #endif // RUNTIME_BIN_SECURE_SOCKET_UTILS_H_