| // 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 <openssl/bio.h> | |
| #include <openssl/err.h> | |
| #include <openssl/pkcs12.h> | |
| #include <openssl/ssl.h> | |
| #include <openssl/x509.h> | |
| #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<int>, 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<int>")); | |
| } | |
| 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<void**>(&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 <typename T, void (*free_func)(T*)> | |
| 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 <typename T, typename E, void (*func)(E*)> | |
| class ScopedSSLStackType { | |
| public: | |
| explicit ScopedSSLStackType(T* obj) : obj_(obj) {} | |
| ~ScopedSSLStackType() { | |
| if (obj_ != nullptr) { | |
| sk_pop_free(reinterpret_cast<_STACK*>(obj_), | |
| reinterpret_cast<void (*)(void*)>(func)); | |
| } | |
| } | |
| 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(ScopedSSLStackType); | |
| }; | |
| typedef ScopedSSLType<PKCS12, PKCS12_free> ScopedPKCS12; | |
| typedef ScopedSSLType<X509, X509_free> ScopedX509; | |
| typedef ScopedSSLStackType<STACK_OF(X509), X509, X509_free> ScopedX509Stack; | |
| } // namespace bin | |
| } // namespace dart | |
| #endif // RUNTIME_BIN_SECURE_SOCKET_UTILS_H_ |