Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(838)

Side by Side Diff: runtime/bin/security_context.cc

Issue 2903743002: Porting SecureSocket to use BoringSSL on OSX (Closed)
Patch Set: Addressed nits, confirmed change works on Windows Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/bin/security_context.h ('k') | runtime/bin/security_context_android.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 #if !defined(DART_IO_DISABLED) && !defined(DART_IO_SECURE_SOCKET_DISABLED)
6
7 #include "bin/security_context.h"
8
9 #include <openssl/bio.h>
10 #include <openssl/err.h>
11 #include <openssl/pkcs12.h>
12 #include <openssl/ssl.h>
13 #include <openssl/x509.h>
14
15 #include "platform/globals.h"
16
17 #include "bin/directory.h"
18 #include "bin/file.h"
19 #include "bin/log.h"
20 #include "bin/secure_socket_filter.h"
21 #include "bin/secure_socket_utils.h"
22
23 // Return the error from the containing function if handle is an error handle.
24 #define RETURN_IF_ERROR(handle) \
25 { \
26 Dart_Handle __handle = handle; \
27 if (Dart_IsError((__handle))) { \
28 return __handle; \
29 } \
30 }
31
32 namespace dart {
33 namespace bin {
34
35 int SSLCertContext::CertificateCallback(int preverify_ok,
36 X509_STORE_CTX* store_ctx) {
37 if (preverify_ok == 1) {
38 return 1;
39 }
40 Dart_Isolate isolate = Dart_CurrentIsolate();
41 if (isolate == NULL) {
42 FATAL("CertificateCallback called with no current isolate\n");
43 }
44 X509* certificate = X509_STORE_CTX_get_current_cert(store_ctx);
45 int ssl_index = SSL_get_ex_data_X509_STORE_CTX_idx();
46 SSL* ssl =
47 static_cast<SSL*>(X509_STORE_CTX_get_ex_data(store_ctx, ssl_index));
48 SSLFilter* filter = static_cast<SSLFilter*>(
49 SSL_get_ex_data(ssl, SSLFilter::filter_ssl_index));
50 Dart_Handle callback = filter->bad_certificate_callback();
51 if (Dart_IsNull(callback)) {
52 return 0;
53 }
54
55 // Upref since the Dart X509 object may outlive the SecurityContext.
56 if (certificate != NULL) {
57 X509_up_ref(certificate);
58 }
59 Dart_Handle args[1];
60 args[0] = X509Helper::WrappedX509Certificate(certificate);
61 if (Dart_IsError(args[0])) {
62 filter->callback_error = args[0];
63 return 0;
64 }
65 Dart_Handle result = Dart_InvokeClosure(callback, 1, args);
66 if (!Dart_IsError(result) && !Dart_IsBoolean(result)) {
67 result = Dart_NewUnhandledExceptionError(DartUtils::NewDartIOException(
68 "HandshakeException",
69 "BadCertificateCallback returned a value that was not a boolean",
70 Dart_Null()));
71 }
72 if (Dart_IsError(result)) {
73 filter->callback_error = result;
74 return 0;
75 }
76 return DartUtils::GetBooleanValue(result);
77 }
78
79
80 SSLCertContext* SSLCertContext::GetSecurityContext(Dart_NativeArguments args) {
81 SSLCertContext* context;
82 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
83 ASSERT(Dart_IsInstance(dart_this));
84 ThrowIfError(Dart_GetNativeInstanceField(
85 dart_this, SSLCertContext::kSecurityContextNativeFieldIndex,
86 reinterpret_cast<intptr_t*>(&context)));
87 return context;
88 }
89
90
91 static void DeleteSecurityContext(void* isolate_data,
92 Dart_WeakPersistentHandle handle,
93 void* context_pointer) {
94 SSLCertContext* context = static_cast<SSLCertContext*>(context_pointer);
95 context->Release();
96 }
97
98
99 static Dart_Handle SetSecurityContext(Dart_NativeArguments args,
100 SSLCertContext* context) {
101 Dart_Handle dart_this = Dart_GetNativeArgument(args, 0);
102 RETURN_IF_ERROR(dart_this);
103 ASSERT(Dart_IsInstance(dart_this));
104 Dart_Handle err = Dart_SetNativeInstanceField(
105 dart_this, SSLCertContext::kSecurityContextNativeFieldIndex,
106 reinterpret_cast<intptr_t>(context));
107 RETURN_IF_ERROR(err);
108 Dart_NewWeakPersistentHandle(dart_this, context,
109 SSLCertContext::kApproximateSize,
110 DeleteSecurityContext);
111 return Dart_Null();
112 }
113
114
115 static void ReleaseCertificate(void* isolate_data,
116 Dart_WeakPersistentHandle handle,
117 void* context_pointer) {
118 X509* cert = reinterpret_cast<X509*>(context_pointer);
119 X509_free(cert);
120 }
121
122
123 static intptr_t EstimateX509Size(X509* certificate) {
124 intptr_t length = i2d_X509(certificate, NULL);
125 return length > 0 ? length : 0;
126 }
127
128
129 // Returns the handle for a Dart object wrapping the X509 certificate object.
130 // The caller should own a reference to the X509 object whose reference count
131 // won't drop to zero before the ReleaseCertificate finalizer runs.
132 Dart_Handle X509Helper::WrappedX509Certificate(X509* certificate) {
133 if (certificate == NULL) {
134 return Dart_Null();
135 }
136 Dart_Handle x509_type =
137 DartUtils::GetDartType(DartUtils::kIOLibURL, "X509Certificate");
138 if (Dart_IsError(x509_type)) {
139 X509_free(certificate);
140 return x509_type;
141 }
142 Dart_Handle arguments[] = {NULL};
143 Dart_Handle result =
144 Dart_New(x509_type, DartUtils::NewString("_"), 0, arguments);
145 if (Dart_IsError(result)) {
146 X509_free(certificate);
147 return result;
148 }
149 ASSERT(Dart_IsInstance(result));
150 Dart_Handle status =
151 Dart_SetNativeInstanceField(result, SSLCertContext::kX509NativeFieldIndex,
152 reinterpret_cast<intptr_t>(certificate));
153 if (Dart_IsError(status)) {
154 X509_free(certificate);
155 return status;
156 }
157 const intptr_t approximate_size_of_certificate =
158 sizeof(*certificate) + EstimateX509Size(certificate);
159 ASSERT(approximate_size_of_certificate > 0);
160 Dart_NewWeakPersistentHandle(result, reinterpret_cast<void*>(certificate),
161 approximate_size_of_certificate,
162 ReleaseCertificate);
163 return result;
164 }
165
166
167 static int SetTrustedCertificatesBytesPKCS12(SSL_CTX* context,
168 BIO* bio,
169 const char* password) {
170 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL));
171 if (p12.get() == NULL) {
172 return 0;
173 }
174
175 EVP_PKEY* key = NULL;
176 X509* cert = NULL;
177 STACK_OF(X509)* ca_certs = NULL;
178 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs);
179 if (status == 0) {
180 return status;
181 }
182
183 ScopedX509Stack cert_stack(ca_certs);
184 X509_STORE* store = SSL_CTX_get_cert_store(context);
185 status = X509_STORE_add_cert(store, cert);
186 // X509_STORE_add_cert increments the reference count of cert on success.
187 X509_free(cert);
188 if (status == 0) {
189 return status;
190 }
191
192 X509* ca;
193 while ((ca = sk_X509_shift(cert_stack.get())) != NULL) {
194 status = X509_STORE_add_cert(store, ca);
195 // X509_STORE_add_cert increments the reference count of cert on success.
196 X509_free(ca);
197 if (status == 0) {
198 return status;
199 }
200 }
201
202 return status;
203 }
204
205
206 static int SetTrustedCertificatesBytesPEM(SSL_CTX* context, BIO* bio) {
207 X509_STORE* store = SSL_CTX_get_cert_store(context);
208
209 int status = 0;
210 X509* cert = NULL;
211 while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) {
212 status = X509_STORE_add_cert(store, cert);
213 // X509_STORE_add_cert increments the reference count of cert on success.
214 X509_free(cert);
215 if (status == 0) {
216 return status;
217 }
218 }
219
220 // If no PEM start line is found, it means that we read to the end of the
221 // file, or that the file isn't PEM. In the first case, status will be
222 // non-zero indicating success. In the second case, status will be 0,
223 // indicating that we should try to read as PKCS12. If there is some other
224 // error, we return it up to the caller.
225 return SecureSocketUtils::NoPEMStartLine() ? status : 0;
226 }
227
228
229 void SSLCertContext::SetTrustedCertificatesBytes(Dart_Handle cert_bytes,
230 const char* password) {
231 ScopedMemBIO bio(cert_bytes);
232 int status = SetTrustedCertificatesBytesPEM(context(), bio.bio());
233 if (status == 0) {
234 if (SecureSocketUtils::NoPEMStartLine()) {
235 ERR_clear_error();
236 BIO_reset(bio.bio());
237 status =
238 SetTrustedCertificatesBytesPKCS12(context(), bio.bio(), password);
239 }
240 } else {
241 // The PEM file was successfully parsed.
242 ERR_clear_error();
243 }
244
245 SecureSocketUtils::CheckStatus(status, "TlsException",
246 "Failure trusting builtin roots");
247 }
248
249
250 static int SetClientAuthoritiesPKCS12(SSL_CTX* context,
251 BIO* bio,
252 const char* password) {
253 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL));
254 if (p12.get() == NULL) {
255 return 0;
256 }
257
258 EVP_PKEY* key = NULL;
259 X509* cert = NULL;
260 STACK_OF(X509)* ca_certs = NULL;
261 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs);
262 if (status == 0) {
263 return status;
264 }
265
266 ScopedX509Stack cert_stack(ca_certs);
267 status = SSL_CTX_add_client_CA(context, cert);
268 // SSL_CTX_add_client_CA increments the reference count of cert on success.
269 X509_free(cert);
270 if (status == 0) {
271 return status;
272 }
273
274 X509* ca;
275 while ((ca = sk_X509_shift(cert_stack.get())) != NULL) {
276 status = SSL_CTX_add_client_CA(context, ca);
277 // SSL_CTX_add_client_CA increments the reference count of ca on success.
278 X509_free(ca); // The name has been extracted.
279 if (status == 0) {
280 return status;
281 }
282 }
283
284 return status;
285 }
286
287
288 static int SetClientAuthoritiesPEM(SSL_CTX* context, BIO* bio) {
289 int status = 0;
290 X509* cert = NULL;
291 while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) {
292 status = SSL_CTX_add_client_CA(context, cert);
293 X509_free(cert); // The name has been extracted.
294 if (status == 0) {
295 return status;
296 }
297 }
298 return SecureSocketUtils::NoPEMStartLine() ? status : 0;
299 }
300
301
302 static int SetClientAuthorities(SSL_CTX* context,
303 BIO* bio,
304 const char* password) {
305 int status = SetClientAuthoritiesPEM(context, bio);
306 if (status == 0) {
307 if (SecureSocketUtils::NoPEMStartLine()) {
308 ERR_clear_error();
309 BIO_reset(bio);
310 status = SetClientAuthoritiesPKCS12(context, bio, password);
311 }
312 } else {
313 // The PEM file was successfully parsed.
314 ERR_clear_error();
315 }
316 return status;
317 }
318
319
320 void SSLCertContext::SetClientAuthoritiesBytes(
321 Dart_Handle client_authorities_bytes,
322 const char* password) {
323 int status;
324 {
325 ScopedMemBIO bio(client_authorities_bytes);
326 status = SetClientAuthorities(context(), bio.bio(), password);
327 }
328
329 SecureSocketUtils::CheckStatus(status, "TlsException",
330 "Failure in setClientAuthoritiesBytes");
331 }
332
333 void SSLCertContext::LoadRootCertFile(const char* file) {
334 if (SSL_LOG_STATUS) {
335 Log::Print("Looking for trusted roots in %s\n", file);
336 }
337 if (!File::Exists(file)) {
338 SecureSocketUtils::ThrowIOException(-1, "TlsException",
339 "Failed to find root cert file", NULL);
340 }
341 int status = SSL_CTX_load_verify_locations(context(), file, NULL);
342 SecureSocketUtils::CheckStatus(status, "TlsException",
343 "Failure trusting builtin roots");
344 if (SSL_LOG_STATUS) {
345 Log::Print("Trusting roots from: %s\n", file);
346 }
347 }
348
349
350 void SSLCertContext::AddCompiledInCerts() {
351 if (root_certificates_pem == NULL) {
352 if (SSL_LOG_STATUS) {
353 Log::Print("Missing compiled-in roots\n");
354 }
355 return;
356 }
357 X509_STORE* store = SSL_CTX_get_cert_store(context());
358 BIO* roots_bio =
359 BIO_new_mem_buf(const_cast<unsigned char*>(root_certificates_pem),
360 root_certificates_pem_length);
361 X509* root_cert;
362 // PEM_read_bio_X509 reads PEM-encoded certificates from a bio (in our case,
363 // backed by a memory buffer), and returns X509 objects, one by one.
364 // When the end of the bio is reached, it returns null.
365 while ((root_cert = PEM_read_bio_X509(roots_bio, NULL, NULL, NULL)) != NULL) {
366 int status = X509_STORE_add_cert(store, root_cert);
367 // X509_STORE_add_cert increments the reference count of cert on success.
368 X509_free(root_cert);
369 if (status == 0) {
370 break;
371 }
372 }
373 BIO_free(roots_bio);
374 // If there is an error here, it must be the error indicating that we are done
375 // reading PEM certificates.
376 ASSERT((ERR_peek_error() == 0) || SecureSocketUtils::NoPEMStartLine());
377 ERR_clear_error();
378 }
379
380
381 void SSLCertContext::LoadRootCertCache(const char* cache) {
382 if (SSL_LOG_STATUS) {
383 Log::Print("Looking for trusted roots in %s\n", cache);
384 }
385 if (Directory::Exists(cache) != Directory::EXISTS) {
386 SecureSocketUtils::ThrowIOException(-1, "TlsException",
387 "Failed to find root cert cache", NULL);
388 }
389 int status = SSL_CTX_load_verify_locations(context(), NULL, cache);
390 SecureSocketUtils::CheckStatus(status, "TlsException",
391 "Failure trusting builtin roots");
392 if (SSL_LOG_STATUS) {
393 Log::Print("Trusting roots from: %s\n", cache);
394 }
395 }
396
397
398 int PasswordCallback(char* buf, int size, int rwflag, void* userdata) {
399 char* password = static_cast<char*>(userdata);
400 ASSERT(size == PEM_BUFSIZE);
401 strncpy(buf, password, size);
402 return strlen(password);
403 }
404
405
406 static EVP_PKEY* GetPrivateKeyPKCS12(BIO* bio, const char* password) {
407 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL));
408 if (p12.get() == NULL) {
409 return NULL;
410 }
411
412 EVP_PKEY* key = NULL;
413 X509* cert = NULL;
414 STACK_OF(X509)* ca_certs = NULL;
415 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs);
416 if (status == 0) {
417 return NULL;
418 }
419
420 // We only care about the private key.
421 ScopedX509 delete_cert(cert);
422 ScopedX509Stack delete_ca_certs(ca_certs);
423 return key;
424 }
425
426
427 static EVP_PKEY* GetPrivateKey(BIO* bio, const char* password) {
428 EVP_PKEY* key = PEM_read_bio_PrivateKey(bio, NULL, PasswordCallback,
429 const_cast<char*>(password));
430 if (key == NULL) {
431 // We try reading data as PKCS12 only if reading as PEM was unsuccessful and
432 // if there is no indication that the data is malformed PEM. We assume the
433 // data is malformed PEM if it contains the start line, i.e. a line
434 // with ----- BEGIN.
435 if (SecureSocketUtils::NoPEMStartLine()) {
436 // Reset the bio, and clear the error from trying to read as PEM.
437 ERR_clear_error();
438 BIO_reset(bio);
439
440 // Try to decode as PKCS12.
441 key = GetPrivateKeyPKCS12(bio, password);
442 }
443 }
444 return key;
445 }
446
447
448 const char* SSLCertContext::GetPasswordArgument(Dart_NativeArguments args,
449 intptr_t index) {
450 Dart_Handle password_object =
451 ThrowIfError(Dart_GetNativeArgument(args, index));
452 const char* password = NULL;
453 if (Dart_IsString(password_object)) {
454 ThrowIfError(Dart_StringToCString(password_object, &password));
455 if (strlen(password) > PEM_BUFSIZE - 1) {
456 Dart_ThrowException(DartUtils::NewDartArgumentError(
457 "Password length is greater than 1023 (PEM_BUFSIZE)"));
458 }
459 } else if (Dart_IsNull(password_object)) {
460 password = "";
461 } else {
462 Dart_ThrowException(
463 DartUtils::NewDartArgumentError("Password is not a String or null"));
464 }
465 return password;
466 }
467
468
469 int AlpnCallback(SSL* ssl,
470 const uint8_t** out,
471 uint8_t* outlen,
472 const uint8_t* in,
473 unsigned int inlen,
474 void* arg) {
475 // 'in' and 'arg' are sequences of (length, data) strings with 1-byte lengths.
476 // 'arg' is 0-terminated. Finds the first string in 'arg' that is in 'in'.
477 uint8_t* server_list = static_cast<uint8_t*>(arg);
478 while (*server_list != 0) {
479 uint8_t protocol_length = *server_list++;
480 const uint8_t* client_list = in;
481 while (client_list < in + inlen) {
482 uint8_t client_protocol_length = *client_list++;
483 if (client_protocol_length == protocol_length) {
484 if (0 == memcmp(server_list, client_list, protocol_length)) {
485 *out = client_list;
486 *outlen = client_protocol_length;
487 return SSL_TLSEXT_ERR_OK; // Success
488 }
489 }
490 client_list += client_protocol_length;
491 }
492 server_list += protocol_length;
493 }
494 // TODO(23580): Make failure send a fatal alert instead of ignoring ALPN.
495 return SSL_TLSEXT_ERR_NOACK;
496 }
497
498
499 // Sets the protocol list for ALPN on a SSL object or a context.
500 void SSLCertContext::SetAlpnProtocolList(Dart_Handle protocols_handle,
501 SSL* ssl,
502 SSLCertContext* context,
503 bool is_server) {
504 // Enable ALPN (application layer protocol negotiation) if the caller provides
505 // a valid list of supported protocols.
506 Dart_TypedData_Type protocols_type;
507 uint8_t* protocol_string = NULL;
508 uint8_t* protocol_string_copy = NULL;
509 intptr_t protocol_string_len = 0;
510 int status;
511
512 Dart_Handle result = Dart_TypedDataAcquireData(
513 protocols_handle, &protocols_type,
514 reinterpret_cast<void**>(&protocol_string), &protocol_string_len);
515 if (Dart_IsError(result)) {
516 Dart_PropagateError(result);
517 }
518
519 if (protocols_type != Dart_TypedData_kUint8) {
520 Dart_TypedDataReleaseData(protocols_handle);
521 Dart_PropagateError(Dart_NewApiError(
522 "Unexpected type for protocols (expected valid Uint8List)."));
523 }
524
525 if (protocol_string_len > 0) {
526 if (is_server) {
527 // ALPN on server connections must be set on an SSL_CTX object,
528 // not on the SSL object of the individual connection.
529 ASSERT(context != NULL);
530 ASSERT(ssl == NULL);
531 // Because it must be passed as a single void*, terminate
532 // the list of (length, data) strings with a length 0 string.
533 protocol_string_copy =
534 static_cast<uint8_t*>(malloc(protocol_string_len + 1));
535 memmove(protocol_string_copy, protocol_string, protocol_string_len);
536 protocol_string_copy[protocol_string_len] = '\0';
537 SSL_CTX_set_alpn_select_cb(context->context(), AlpnCallback,
538 protocol_string_copy);
539 context->set_alpn_protocol_string(protocol_string_copy);
540 } else {
541 // The function makes a local copy of protocol_string, which it owns.
542 if (ssl != NULL) {
543 ASSERT(context == NULL);
544 status = SSL_set_alpn_protos(ssl, protocol_string, protocol_string_len);
545 } else {
546 ASSERT(context != NULL);
547 ASSERT(ssl == NULL);
548 status = SSL_CTX_set_alpn_protos(context->context(), protocol_string,
549 protocol_string_len);
550 }
551 ASSERT(status == 0); // The function returns a non-standard status.
552 }
553 }
554 Dart_TypedDataReleaseData(protocols_handle);
555 }
556
557
558 static int UseChainBytesPKCS12(SSL_CTX* context,
559 BIO* bio,
560 const char* password) {
561 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL));
562 if (p12.get() == NULL) {
563 return 0;
564 }
565
566 EVP_PKEY* key = NULL;
567 X509* cert = NULL;
568 STACK_OF(X509)* ca_certs = NULL;
569 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs);
570 if (status == 0) {
571 return status;
572 }
573
574 ScopedX509 x509(cert);
575 ScopedX509Stack certs(ca_certs);
576 status = SSL_CTX_use_certificate(context, x509.get());
577 if (ERR_peek_error() != 0) {
578 // Key/certificate mismatch doesn't imply status is 0.
579 status = 0;
580 }
581 if (status == 0) {
582 return status;
583 }
584
585 SSL_CTX_clear_chain_certs(context);
586
587 X509* ca;
588 while ((ca = sk_X509_shift(certs.get())) != NULL) {
589 status = SSL_CTX_add0_chain_cert(context, ca);
590 // SSL_CTX_add0_chain_cert does not inc ref count, so don't free unless the
591 // call fails.
592 if (status == 0) {
593 X509_free(ca);
594 return status;
595 }
596 }
597
598 return status;
599 }
600
601
602 static int UseChainBytesPEM(SSL_CTX* context, BIO* bio) {
603 int status = 0;
604 ScopedX509 x509(PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL));
605 if (x509.get() == NULL) {
606 return 0;
607 }
608
609 status = SSL_CTX_use_certificate(context, x509.get());
610 if (ERR_peek_error() != 0) {
611 // Key/certificate mismatch doesn't imply status is 0.
612 status = 0;
613 }
614 if (status == 0) {
615 return status;
616 }
617
618 SSL_CTX_clear_chain_certs(context);
619
620 X509* ca;
621 while ((ca = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) {
622 status = SSL_CTX_add0_chain_cert(context, ca);
623 // SSL_CTX_add0_chain_cert does not inc ref count, so don't free unless the
624 // call fails.
625 if (status == 0) {
626 X509_free(ca);
627 return status;
628 }
629 // Note that we must not free `ca` if it was successfully added to the
630 // chain. We must free the main certificate x509, though since its reference
631 // count is increased by SSL_CTX_use_certificate.
632 }
633
634 return SecureSocketUtils::NoPEMStartLine() ? status : 0;
635 }
636
637
638 static int UseChainBytes(SSL_CTX* context, BIO* bio, const char* password) {
639 int status = UseChainBytesPEM(context, bio);
640 if (status == 0) {
641 if (SecureSocketUtils::NoPEMStartLine()) {
642 ERR_clear_error();
643 BIO_reset(bio);
644 status = UseChainBytesPKCS12(context, bio, password);
645 }
646 } else {
647 // The PEM file was successfully read.
648 ERR_clear_error();
649 }
650 return status;
651 }
652
653
654 int SSLCertContext::UseCertificateChainBytes(Dart_Handle cert_chain_bytes,
655 const char* password) {
656 ScopedMemBIO bio(cert_chain_bytes);
657 return UseChainBytes(context(), bio.bio(), password);
658 }
659
660
661 static X509* GetX509Certificate(Dart_NativeArguments args) {
662 X509* certificate = NULL;
663 Dart_Handle dart_this = ThrowIfError(Dart_GetNativeArgument(args, 0));
664 ASSERT(Dart_IsInstance(dart_this));
665 ThrowIfError(Dart_GetNativeInstanceField(
666 dart_this, SSLCertContext::kX509NativeFieldIndex,
667 reinterpret_cast<intptr_t*>(&certificate)));
668 return certificate;
669 }
670
671
672 Dart_Handle X509Helper::GetSubject(Dart_NativeArguments args) {
673 X509* certificate = GetX509Certificate(args);
674 X509_NAME* subject = X509_get_subject_name(certificate);
675 char* subject_string = X509_NAME_oneline(subject, NULL, 0);
676 if (subject_string == NULL) {
677 Dart_ThrowException(DartUtils::NewDartArgumentError(
678 "X509.subject failed to find subject's common name."));
679 }
680 Dart_Handle subject_handle = Dart_NewStringFromCString(subject_string);
681 OPENSSL_free(subject_string);
682 return subject_handle;
683 }
684
685
686 Dart_Handle X509Helper::GetIssuer(Dart_NativeArguments args) {
687 fprintf(stdout, "Getting issuer!\n");
688 X509* certificate = GetX509Certificate(args);
689 X509_NAME* issuer = X509_get_issuer_name(certificate);
690 char* issuer_string = X509_NAME_oneline(issuer, NULL, 0);
691 if (issuer_string == NULL) {
692 Dart_ThrowException(DartUtils::NewDartArgumentError(
693 "X509.issuer failed to find issuer's common name."));
694 }
695 Dart_Handle issuer_handle = Dart_NewStringFromCString(issuer_string);
696 OPENSSL_free(issuer_string);
697 return issuer_handle;
698 }
699
700
701 static Dart_Handle ASN1TimeToMilliseconds(ASN1_TIME* aTime) {
702 ASN1_UTCTIME* epoch_start = M_ASN1_UTCTIME_new();
703 ASN1_UTCTIME_set_string(epoch_start, "700101000000Z");
704 int days;
705 int seconds;
706 int result = ASN1_TIME_diff(&days, &seconds, epoch_start, aTime);
707 M_ASN1_UTCTIME_free(epoch_start);
708 if (result != 1) {
709 // TODO(whesse): Propagate an error to Dart.
710 Log::PrintErr("ASN1Time error %d\n", result);
711 }
712 return Dart_NewInteger((86400LL * days + seconds) * 1000LL);
713 }
714
715
716 Dart_Handle X509Helper::GetStartValidity(Dart_NativeArguments args) {
717 X509* certificate = GetX509Certificate(args);
718 ASN1_TIME* not_before = X509_get_notBefore(certificate);
719 return ASN1TimeToMilliseconds(not_before);
720 }
721
722
723 Dart_Handle X509Helper::GetEndValidity(Dart_NativeArguments args) {
724 X509* certificate = GetX509Certificate(args);
725 ASN1_TIME* not_after = X509_get_notAfter(certificate);
726 return ASN1TimeToMilliseconds(not_after);
727 }
728
729 void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)(
730 Dart_NativeArguments args) {
731 SSLCertContext* context = SSLCertContext::GetSecurityContext(args);
732 const char* password = SSLCertContext::GetPasswordArgument(args, 2);
733
734 int status;
735 {
736 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
737 EVP_PKEY* key = GetPrivateKey(bio.bio(), password);
738 status = SSL_CTX_use_PrivateKey(context->context(), key);
739 // SSL_CTX_use_PrivateKey increments the reference count of key on success,
740 // so we have to call EVP_PKEY_free on both success and failure.
741 EVP_PKEY_free(key);
742 }
743
744 // TODO(24184): Handle different expected errors here - file missing,
745 // incorrect password, file not a PEM, and throw exceptions.
746 // SecureSocketUtils::CheckStatus should also throw an exception in uncaught
747 // cases.
748 SecureSocketUtils::CheckStatus(status, "TlsException",
749 "Failure in usePrivateKeyBytes");
750 }
751
752
753 void FUNCTION_NAME(SecurityContext_Allocate)(Dart_NativeArguments args) {
754 SSLFilter::InitializeLibrary();
755 SSL_CTX* ctx = SSL_CTX_new(TLS_method());
756 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, SSLCertContext::CertificateCallback);
757 SSL_CTX_set_min_proto_version(ctx, TLS1_VERSION);
758 SSL_CTX_set_cipher_list(ctx, "HIGH:MEDIUM");
759 SSLCertContext* context = new SSLCertContext(ctx);
760 Dart_Handle err = SetSecurityContext(args, context);
761 if (Dart_IsError(err)) {
762 delete context;
763 Dart_PropagateError(err);
764 }
765 }
766
767
768 void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)(
769 Dart_NativeArguments args) {
770 SSLCertContext* context = SSLCertContext::GetSecurityContext(args);
771 Dart_Handle cert_bytes = ThrowIfError(Dart_GetNativeArgument(args, 1));
772 const char* password = SSLCertContext::GetPasswordArgument(args, 2);
773
774 ASSERT(context != NULL);
775 ASSERT(password != NULL);
776 context->SetTrustedCertificatesBytes(cert_bytes, password);
777 }
778
779
780 void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)(
781 Dart_NativeArguments args) {
782 SSLCertContext* context = SSLCertContext::GetSecurityContext(args);
783 Dart_Handle client_authorities_bytes =
784 ThrowIfError(Dart_GetNativeArgument(args, 1));
785 const char* password = SSLCertContext::GetPasswordArgument(args, 2);
786
787 ASSERT(context != NULL);
788 ASSERT(password != NULL);
789
790 context->SetClientAuthoritiesBytes(client_authorities_bytes, password);
791 }
792
793
794 void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)(
795 Dart_NativeArguments args) {
796 SSLCertContext* context = SSLCertContext::GetSecurityContext(args);
797 Dart_Handle cert_chain_bytes = ThrowIfError(Dart_GetNativeArgument(args, 1));
798 const char* password = SSLCertContext::GetPasswordArgument(args, 2);
799
800 ASSERT(context != NULL);
801 ASSERT(password != NULL);
802
803 int status = context->UseCertificateChainBytes(cert_chain_bytes, password);
804
805 SecureSocketUtils::CheckStatus(status, "TlsException",
806 "Failure in useCertificateChainBytes");
807 }
808
809
810 void FUNCTION_NAME(SecurityContext_AlpnSupported)(Dart_NativeArguments args) {
811 Dart_SetReturnValue(args, Dart_NewBoolean(true));
812 }
813
814
815 void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)(
816 Dart_NativeArguments args) {
817 SSLCertContext* context = SSLCertContext::GetSecurityContext(args);
818
819 ASSERT(context != NULL);
820
821 context->TrustBuiltinRoots();
822 }
823
824
825 void FUNCTION_NAME(X509_Subject)(Dart_NativeArguments args) {
826 Dart_SetReturnValue(args, X509Helper::GetSubject(args));
827 }
828
829
830 void FUNCTION_NAME(X509_Issuer)(Dart_NativeArguments args) {
831 Dart_SetReturnValue(args, X509Helper::GetIssuer(args));
832 }
833
834
835 void FUNCTION_NAME(X509_StartValidity)(Dart_NativeArguments args) {
836 Dart_SetReturnValue(args, X509Helper::GetStartValidity(args));
837 }
838
839
840 void FUNCTION_NAME(X509_EndValidity)(Dart_NativeArguments args) {
841 Dart_SetReturnValue(args, X509Helper::GetEndValidity(args));
842 }
843
844
845 void FUNCTION_NAME(SecurityContext_SetAlpnProtocols)(
846 Dart_NativeArguments args) {
847 SSLCertContext* context = SSLCertContext::GetSecurityContext(args);
848 Dart_Handle protocols_handle = ThrowIfError(Dart_GetNativeArgument(args, 1));
849 Dart_Handle is_server_handle = ThrowIfError(Dart_GetNativeArgument(args, 2));
850 if (Dart_IsBoolean(is_server_handle)) {
851 bool is_server = DartUtils::GetBooleanValue(is_server_handle);
852 SSLCertContext::SetAlpnProtocolList(protocols_handle, NULL, context,
853 is_server);
854 } else {
855 Dart_ThrowException(DartUtils::NewDartArgumentError(
856 "Non-boolean is_server argument passed to SetAlpnProtocols"));
857 }
858 }
859
860 } // namespace bin
861 } // namespace dart
862
863 #endif // !defined(DART_IO_DISABLED) &&
864 // !defined(DART_IO_SECURE_SOCKET_DISABLED)
OLDNEW
« no previous file with comments | « runtime/bin/security_context.h ('k') | runtime/bin/security_context_android.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698