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#ifndef RUNTIME_BIN_SECURE_SOCKET_UTILS_H_
6#define RUNTIME_BIN_SECURE_SOCKET_UTILS_H_
7
8#include <openssl/bio.h>
9#include <openssl/err.h>
10#include <openssl/pkcs12.h>
11#include <openssl/ssl.h>
12#include <openssl/x509.h>
13
14#include "platform/globals.h"
15
16#include "bin/dartutils.h"
17#include "platform/text_buffer.h"
18
19namespace dart {
20namespace bin {
21
22const bool SSL_LOG_STATUS = false;
23const bool SSL_LOG_DATA = false;
24const bool SSL_LOG_CERTS = false;
25
26class SecureSocketUtils : public AllStatic {
27 public:
28 static const int SSL_ERROR_MESSAGE_BUFFER_SIZE = 1000;
29
30 static void ThrowIOException(int status,
31 const char* exception_type,
32 const char* message,
33 const SSL* ssl);
34
35 static void CheckStatusSSL(int status,
36 const char* type,
37 const char* message,
38 const SSL* ssl);
39
40 static void CheckStatus(int status, const char* type, const char* message);
41
42 static bool NoPEMStartLine() {
43 uint32_t last_error = ERR_peek_last_error();
44 return (ERR_GET_LIB(last_error) == ERR_LIB_PEM) &&
45 (ERR_GET_REASON(last_error) == PEM_R_NO_START_LINE);
46 }
47
48 static void FetchErrorString(const SSL* ssl, TextBuffer* text_buffer);
49};
50
51// Where the argument to the constructor is the handle for an object
52// implementing List<int>, this class creates a scope in which a memory-backed
53// BIO is allocated. Leaving the scope cleans up the BIO and the buffer that
54// was used to create it.
55//
56// Do not make Dart_ API calls while in a ScopedMemBIO.
57// Do not call Dart_PropagateError while in a ScopedMemBIO.
58class ScopedMemBIO {
59 public:
60 explicit ScopedMemBIO(Dart_Handle object) {
61 if (!Dart_IsTypedData(object) && !Dart_IsList(object)) {
62 Dart_ThrowException(
63 DartUtils::NewDartArgumentError("Argument is not a List<int>"));
64 }
65
66 uint8_t* bytes = NULL;
67 intptr_t bytes_len = 0;
68 bool is_typed_data = false;
69 if (Dart_IsTypedData(object)) {
70 is_typed_data = true;
71 Dart_TypedData_Type typ;
72 ThrowIfError(Dart_TypedDataAcquireData(
73 object, &typ, reinterpret_cast<void**>(&bytes), &bytes_len));
74 } else {
75 ASSERT(Dart_IsList(object));
76 ThrowIfError(Dart_ListLength(object, &bytes_len));
77 bytes = Dart_ScopeAllocate(bytes_len);
78 ASSERT(bytes != NULL);
79 ThrowIfError(Dart_ListGetAsBytes(object, 0, bytes, bytes_len));
80 }
81
82 object_ = object;
83 bytes_ = bytes;
84 bytes_len_ = bytes_len;
85 bio_ = BIO_new_mem_buf(bytes, bytes_len);
86 ASSERT(bio_ != NULL);
87 is_typed_data_ = is_typed_data;
88 }
89
90 ~ScopedMemBIO() {
91 ASSERT(bio_ != NULL);
92 if (is_typed_data_) {
93 BIO_free(bio_);
94 ThrowIfError(Dart_TypedDataReleaseData(object_));
95 } else {
96 BIO_free(bio_);
97 }
98 }
99
100 BIO* bio() {
101 ASSERT(bio_ != NULL);
102 return bio_;
103 }
104
105 uint8_t* data() { return bytes_; }
106 intptr_t length() { return bytes_len_; }
107
108 private:
109 Dart_Handle object_;
110 uint8_t* bytes_;
111 intptr_t bytes_len_;
112 BIO* bio_;
113 bool is_typed_data_;
114
115 DISALLOW_ALLOCATION();
116 DISALLOW_COPY_AND_ASSIGN(ScopedMemBIO);
117};
118
119template <typename T, void (*free_func)(T*)>
120class ScopedSSLType {
121 public:
122 explicit ScopedSSLType(T* obj) : obj_(obj) {}
123
124 ~ScopedSSLType() {
125 if (obj_ != NULL) {
126 free_func(obj_);
127 }
128 }
129
130 T* get() { return obj_; }
131 const T* get() const { return obj_; }
132
133 T* release() {
134 T* result = obj_;
135 obj_ = NULL;
136 return result;
137 }
138
139 private:
140 T* obj_;
141
142 DISALLOW_ALLOCATION();
143 DISALLOW_COPY_AND_ASSIGN(ScopedSSLType);
144};
145
146template <typename T, typename E, void (*func)(E*)>
147class ScopedSSLStackType {
148 public:
149 explicit ScopedSSLStackType(T* obj) : obj_(obj) {}
150
151 ~ScopedSSLStackType() {
152 if (obj_ != NULL) {
153 sk_pop_free(reinterpret_cast<_STACK*>(obj_),
154 reinterpret_cast<void (*)(void*)>(func));
155 }
156 }
157
158 T* get() { return obj_; }
159 const T* get() const { return obj_; }
160
161 T* release() {
162 T* result = obj_;
163 obj_ = NULL;
164 return result;
165 }
166
167 private:
168 T* obj_;
169
170 DISALLOW_ALLOCATION();
171 DISALLOW_COPY_AND_ASSIGN(ScopedSSLStackType);
172};
173
174typedef ScopedSSLType<PKCS12, PKCS12_free> ScopedPKCS12;
175typedef ScopedSSLType<X509, X509_free> ScopedX509;
176typedef ScopedSSLStackType<STACK_OF(X509), X509, X509_free> ScopedX509Stack;
177
178} // namespace bin
179} // namespace dart
180
181#endif // RUNTIME_BIN_SECURE_SOCKET_UTILS_H_
182