blob: ddbd2b675ae4c4b8dc766628d775354fade9e26d [file] [log] [blame]
// 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 const 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 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 void 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 = NULL;
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 != NULL);
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_ != NULL);
is_typed_data_ = is_typed_data;
}
~ScopedMemBIO() {
ASSERT(bio_ != NULL);
if (is_typed_data_) {
BIO_free(bio_);
ThrowIfError(Dart_TypedDataReleaseData(object_));
} else {
BIO_free(bio_);
}
}
BIO* bio() {
ASSERT(bio_ != NULL);
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_ != NULL) {
free_func(obj_);
}
}
T* get() { return obj_; }
const T* get() const { return obj_; }
T* release() {
T* result = obj_;
obj_ = NULL;
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_ != NULL) {
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_ = NULL;
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_