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

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

Issue 1665433002: Adds SecurityContext.setTrustedCertificatesBytes (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Merge with CL adding setClientAuthoritiesBytes Created 4 years, 10 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/io_natives.cc ('k') | runtime/bin/secure_socket_patch.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "bin/secure_socket.h" 5 #include "bin/secure_socket.h"
6 6
7 #include <errno.h> 7 #include <errno.h>
8 #include <fcntl.h> 8 #include <fcntl.h>
9 #include <sys/stat.h> 9 #include <sys/stat.h>
10 #include <stdio.h> 10 #include <stdio.h>
(...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after
369 int error = ERR_get_error(); 369 int error = ERR_get_error();
370 Log::PrintErr("Failed: %s status %d", message, status); 370 Log::PrintErr("Failed: %s status %d", message, status);
371 char error_string[SSL_ERROR_MESSAGE_BUFFER_SIZE]; 371 char error_string[SSL_ERROR_MESSAGE_BUFFER_SIZE];
372 ERR_error_string_n(error, error_string, SSL_ERROR_MESSAGE_BUFFER_SIZE); 372 ERR_error_string_n(error, error_string, SSL_ERROR_MESSAGE_BUFFER_SIZE);
373 Log::PrintErr("ERROR: %d %s\n", error, error_string); 373 Log::PrintErr("ERROR: %d %s\n", error, error_string);
374 } 374 }
375 ThrowIOException(status, type, message); 375 ThrowIOException(status, type, message);
376 } 376 }
377 377
378 378
379 static bool GetBIOArgument(Dart_Handle object, BIO** bio) {
Bill Hesse 2016/02/05 14:48:17 I would call this FillMemBIO. "Argument" doesn't
zra 2016/02/05 17:18:22 Replaced these functions with MemBIOScope
380 ASSERT(bio != NULL);
381 if (!Dart_IsTypedData(object) && !Dart_IsList(object)) {
382 Dart_ThrowException(DartUtils::NewDartArgumentError(
383 "Argument is not a List<int>"));
384 }
385
386 uint8_t* bytes = NULL;
387 intptr_t bytes_len = 0;
388 bool is_typed_data = false;
389 if (Dart_IsTypedData(object)) {
390 is_typed_data = true;
391 Dart_TypedData_Type typ;
392 ThrowIfError(Dart_TypedDataAcquireData(
393 object,
394 &typ,
395 reinterpret_cast<void**>(&bytes),
396 &bytes_len));
397 } else {
398 ASSERT(Dart_IsList(object));
399 ThrowIfError(Dart_ListLength(object, &bytes_len));
400 bytes = new uint8_t[bytes_len];
401 Dart_Handle err =
402 Dart_ListGetAsBytes(object, 0, bytes, bytes_len);
403 if (Dart_IsError(err)) {
404 delete[] bytes;
405 Dart_PropagateError(err);
406 }
407 }
408
409 *bio = BIO_new_mem_buf(bytes, bytes_len);
410 return is_typed_data;
411 }
412
413
Bill Hesse 2016/02/05 14:48:17 This seems really fragile (the typed data release)
zra 2016/02/05 17:18:22 Acknowledged.
414 static void FreeBIO(Dart_Handle object, BIO* bio, bool is_typed_data) {
415 if (is_typed_data) {
416 BIO_free(bio);
417 ThrowIfError(Dart_TypedDataReleaseData(object));
418 } else {
419 uint8_t* bytes;
420 uintptr_t bytes_len;
421 if (BIO_mem_contents(
422 bio, const_cast<const uint8_t**>(&bytes), &bytes_len) != 0) {
423 ASSERT(bytes != NULL);
424 delete[] bytes;
425 }
426 BIO_free(bio);
427 }
428 }
429
430
379 void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)( 431 void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)(
380 Dart_NativeArguments args) { 432 Dart_NativeArguments args) {
381 SSL_CTX* context = GetSecurityContext(args); 433 SSL_CTX* context = GetSecurityContext(args);
382 434
383 Dart_Handle key_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
384 if (!Dart_IsTypedData(key_object) && !Dart_IsList(key_object)) {
385 Dart_ThrowException(DartUtils::NewDartArgumentError(
386 "keyBytes argument to SecurityContext.usePrivateKeyBytes "
387 "is not a List<int>"));
388 }
389
390 Dart_Handle password_object = ThrowIfError(Dart_GetNativeArgument(args, 2)); 435 Dart_Handle password_object = ThrowIfError(Dart_GetNativeArgument(args, 2));
391 const char* password = NULL; 436 const char* password = NULL;
392 if (Dart_IsString(password_object)) { 437 if (Dart_IsString(password_object)) {
393 ThrowIfError(Dart_StringToCString(password_object, &password)); 438 ThrowIfError(Dart_StringToCString(password_object, &password));
394 if (strlen(password) > PEM_BUFSIZE - 1) { 439 if (strlen(password) > PEM_BUFSIZE - 1) {
395 Dart_ThrowException(DartUtils::NewDartArgumentError( 440 Dart_ThrowException(DartUtils::NewDartArgumentError(
396 "SecurityContext.usePrivateKey password length is greater than" 441 "SecurityContext.usePrivateKey password length is greater than"
397 " 1023 (PEM_BUFSIZE)")); 442 " 1023 (PEM_BUFSIZE)"));
398 } 443 }
399 } else if (Dart_IsNull(password_object)) { 444 } else if (Dart_IsNull(password_object)) {
400 password = ""; 445 password = "";
401 } else { 446 } else {
402 Dart_ThrowException(DartUtils::NewDartArgumentError( 447 Dart_ThrowException(DartUtils::NewDartArgumentError(
403 "SecurityContext.usePrivateKey password is not a String or null")); 448 "SecurityContext.usePrivateKey password is not a String or null"));
404 } 449 }
405 450
406 uint8_t* key_bytes = NULL; 451 BIO* bio = NULL;
407 intptr_t key_bytes_len = 0; 452 Dart_Handle key_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
408 bool is_typed_data = false; 453 bool is_typed_data = GetBIOArgument(key_object, &bio);
409 if (Dart_IsTypedData(key_object)) { 454 ASSERT(bio != NULL);
410 is_typed_data = true;
411 Dart_TypedData_Type typ;
412 ThrowIfError(Dart_TypedDataAcquireData(
413 key_object,
414 &typ,
415 reinterpret_cast<void**>(&key_bytes),
416 &key_bytes_len));
417 } else {
418 ASSERT(Dart_IsList(key_object));
419 ThrowIfError(Dart_ListLength(key_object, &key_bytes_len));
420 key_bytes = new uint8_t[key_bytes_len];
421 Dart_Handle err =
422 Dart_ListGetAsBytes(key_object, 0, key_bytes, key_bytes_len);
423 if (Dart_IsError(err)) {
424 delete[] key_bytes;
425 Dart_PropagateError(err);
426 }
427 }
428 ASSERT(key_bytes != NULL);
429 455
430 BIO* bio = BIO_new_mem_buf(key_bytes, key_bytes_len);
431 EVP_PKEY *key = PEM_read_bio_PrivateKey( 456 EVP_PKEY *key = PEM_read_bio_PrivateKey(
432 bio, NULL, PasswordCallback, const_cast<char*>(password)); 457 bio, NULL, PasswordCallback, const_cast<char*>(password));
433 int status = SSL_CTX_use_PrivateKey(context, key); 458 int status = SSL_CTX_use_PrivateKey(context, key);
434 BIO_free(bio); 459
435 if (is_typed_data) { 460 FreeBIO(key_object, bio, is_typed_data);
436 ThrowIfError(Dart_TypedDataReleaseData(key_object));
437 } else {
438 delete[] key_bytes;
439 }
440 461
441 // TODO(24184): Handle different expected errors here - file missing, 462 // TODO(24184): Handle different expected errors here - file missing,
442 // incorrect password, file not a PEM, and throw exceptions. 463 // incorrect password, file not a PEM, and throw exceptions.
443 // CheckStatus should also throw an exception in uncaught cases. 464 // CheckStatus should also throw an exception in uncaught cases.
444 CheckStatus(status, "TlsException", "Failure in usePrivateKeyBytes"); 465 CheckStatus(status, "TlsException", "Failure in usePrivateKeyBytes");
445 } 466 }
446 467
447 468
448 void FUNCTION_NAME(SecurityContext_SetTrustedCertificates)( 469 static int SetTrustedCertificatesBytes(SSL_CTX* context, BIO* bio) {
449 Dart_NativeArguments args) { 470 X509_STORE* store = SSL_CTX_get_cert_store(context);
450 SSL_CTX* context = GetSecurityContext(args); 471
451 Dart_Handle filename_object = ThrowIfError(Dart_GetNativeArgument(args, 1)); 472 int status = 0;
452 const char* filename = NULL; 473 X509* cert = NULL;
453 if (Dart_IsString(filename_object)) { 474 while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) {
454 ThrowIfError(Dart_StringToCString(filename_object, &filename)); 475 status = X509_STORE_add_cert(store, cert);
455 } 476 if (status == 0) {
456 Dart_Handle directory_object = ThrowIfError(Dart_GetNativeArgument(args, 2)); 477 X509_free(cert);
457 const char* directory = NULL; 478 return status;
458 if (Dart_IsString(directory_object)) { 479 }
459 ThrowIfError(Dart_StringToCString(directory_object, &directory));
460 } else if (Dart_IsNull(directory_object)) {
461 directory = NULL;
462 } else {
463 Dart_ThrowException(DartUtils::NewDartArgumentError(
464 "Directory argument to SecurityContext.setTrustedCertificates is not "
465 "a String or null"));
466 } 480 }
467 481
468 int status = SSL_CTX_load_verify_locations(context, filename, directory); 482 uint32_t err = ERR_peek_last_error();
469 CheckStatus( 483 if ((ERR_GET_LIB(err) == ERR_LIB_PEM) &&
470 status, "TlsException", "SSL_CTX_load_verify_locations"); 484 (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
485 // Reached the end of the buffer.
486 ERR_clear_error();
487 } else {
488 // Some real error happened.
489 status = 0;
490 }
491
492 return status;
471 } 493 }
472 494
473 495
496 void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)(
497 Dart_NativeArguments args) {
498 SSL_CTX* context = GetSecurityContext(args);
499
500 BIO* bio = NULL;
501 Dart_Handle certs_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
502 bool is_typed_data = GetBIOArgument(certs_object, &bio);
503 ASSERT(bio != NULL);
504
505 int status = SetTrustedCertificatesBytes(context, bio);
506
507 FreeBIO(certs_object, bio, is_typed_data);
508 CheckStatus(status,
509 "TlsException",
510 "Failure in setTrustedCertificatesBytes");
511 }
512
513
474 void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)( 514 void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)(
475 Dart_NativeArguments args) { 515 Dart_NativeArguments args) {
476 SSL_CTX* context = GetSecurityContext(args); 516 SSL_CTX* context = GetSecurityContext(args);
477 X509_STORE* store = SSL_CTX_get_cert_store(context); 517 X509_STORE* store = SSL_CTX_get_cert_store(context);
478 BIO* roots_bio = 518 BIO* roots_bio =
479 BIO_new_mem_buf(const_cast<unsigned char*>(root_certificates_pem), 519 BIO_new_mem_buf(const_cast<unsigned char*>(root_certificates_pem),
480 root_certificates_pem_length); 520 root_certificates_pem_length);
481 X509* root_cert; 521 X509* root_cert;
482 // PEM_read_bio_X509 reads PEM-encoded certificates from a bio (in our case, 522 // PEM_read_bio_X509 reads PEM-encoded certificates from a bio (in our case,
483 // backed by a memory buffer), and returns X509 objects, one by one. 523 // backed by a memory buffer), and returns X509 objects, one by one.
484 // When the end of the bio is reached, it returns null. 524 // When the end of the bio is reached, it returns null.
485 while ((root_cert = PEM_read_bio_X509(roots_bio, NULL, NULL, NULL))) { 525 while ((root_cert = PEM_read_bio_X509(roots_bio, NULL, NULL, NULL))) {
486 X509_STORE_add_cert(store, root_cert); 526 X509_STORE_add_cert(store, root_cert);
487 } 527 }
488 BIO_free(roots_bio); 528 BIO_free(roots_bio);
489 } 529 }
490 530
491 531
492 static int UseChainBytes( 532 static int UseChainBytes(SSL_CTX* context, BIO* bio) {
493 SSL_CTX* context, uint8_t* chain_bytes, intptr_t chain_bytes_len) {
494 int status = 0; 533 int status = 0;
495 BIO* bio = BIO_new_mem_buf(chain_bytes, chain_bytes_len); 534 X509* x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
496 if (bio == NULL) { 535 if (x509 == NULL) {
497 return 0; 536 return 0;
498 } 537 }
499 538
500 X509* x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL);
501 if (x509 == NULL) {
502 BIO_free(bio);
503 return 0;
504 }
505
506 status = SSL_CTX_use_certificate(context, x509); 539 status = SSL_CTX_use_certificate(context, x509);
507 if (ERR_peek_error() != 0) { 540 if (ERR_peek_error() != 0) {
508 // Key/certificate mismatch doesn't imply status is 0. 541 // Key/certificate mismatch doesn't imply status is 0.
509 status = 0; 542 status = 0;
510 } 543 }
511 if (status == 0) { 544 if (status == 0) {
512 X509_free(x509); 545 X509_free(x509);
513 BIO_free(bio);
514 return status; 546 return status;
515 } 547 }
516 548
517 SSL_CTX_clear_chain_certs(context); 549 SSL_CTX_clear_chain_certs(context);
518 550
519 while (true) { 551 while (true) {
520 X509* ca = PEM_read_bio_X509(bio, NULL, NULL, NULL); 552 X509* ca = PEM_read_bio_X509(bio, NULL, NULL, NULL);
521 if (ca == NULL) { 553 if (ca == NULL) {
522 break; 554 break;
523 } 555 }
524 status = SSL_CTX_add0_chain_cert(context, ca); 556 status = SSL_CTX_add0_chain_cert(context, ca);
525 if (status == 0) { 557 if (status == 0) {
526 X509_free(ca); 558 X509_free(ca);
527 X509_free(x509); 559 X509_free(x509);
528 BIO_free(bio);
529 return status; 560 return status;
530 } 561 }
531 // Note that we must not free `ca` if it was successfully added to the 562 // Note that we must not free `ca` if it was successfully added to the
532 // chain. We must free the main certificate x509, though since its reference 563 // chain. We must free the main certificate x509, though since its reference
533 // count is increased by SSL_CTX_use_certificate. 564 // count is increased by SSL_CTX_use_certificate.
534 } 565 }
535 566
536 uint32_t err = ERR_peek_last_error(); 567 uint32_t err = ERR_peek_last_error();
537 if ((ERR_GET_LIB(err) == ERR_LIB_PEM) && 568 if ((ERR_GET_LIB(err) == ERR_LIB_PEM) &&
538 (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) { 569 (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
539 // Reached the end of the buffer. 570 // Reached the end of the buffer.
540 ERR_clear_error(); 571 ERR_clear_error();
541 } else { 572 } else {
542 // Some real error happened. 573 // Some real error happened.
543 status = 0; 574 status = 0;
544 } 575 }
545 576
546 X509_free(x509); 577 X509_free(x509);
547 BIO_free(bio);
548 return status; 578 return status;
549 } 579 }
550 580
551 581
552 void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)( 582 void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)(
553 Dart_NativeArguments args) { 583 Dart_NativeArguments args) {
554 SSL_CTX* context = GetSecurityContext(args); 584 SSL_CTX* context = GetSecurityContext(args);
555 585
586 BIO* bio = NULL;
556 Dart_Handle chain_object = ThrowIfError(Dart_GetNativeArgument(args, 1)); 587 Dart_Handle chain_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
557 if (!Dart_IsTypedData(chain_object) && !Dart_IsList(chain_object)) { 588 bool is_typed_data = GetBIOArgument(chain_object, &bio);
558 Dart_ThrowException(DartUtils::NewDartArgumentError( 589 ASSERT(bio != NULL);
559 "chainBytes argument to SecurityContext.useCertificateChainBytes "
560 "is not a List<int>"));
561 }
562 590
563 uint8_t* chain_bytes = NULL; 591 int status = UseChainBytes(context, bio);
564 intptr_t chain_bytes_len = 0;
565 bool is_typed_data = false;
566 if (Dart_IsTypedData(chain_object)) {
567 is_typed_data = true;
568 Dart_TypedData_Type typ;
569 ThrowIfError(Dart_TypedDataAcquireData(
570 chain_object,
571 &typ,
572 reinterpret_cast<void**>(&chain_bytes),
573 &chain_bytes_len));
574 } else {
575 ASSERT(Dart_IsList(chain_object));
576 ThrowIfError(Dart_ListLength(chain_object, &chain_bytes_len));
577 chain_bytes = new uint8_t[chain_bytes_len];
578 Dart_Handle err =
579 Dart_ListGetAsBytes(chain_object, 0, chain_bytes, chain_bytes_len);
580 if (Dart_IsError(err)) {
581 delete[] chain_bytes;
582 Dart_PropagateError(err);
583 }
584 }
585 ASSERT(chain_bytes != NULL);
586 592
587 int status = UseChainBytes(context, chain_bytes, chain_bytes_len); 593 FreeBIO(chain_object, bio, is_typed_data);
588
589 if (is_typed_data) {
590 ThrowIfError(Dart_TypedDataReleaseData(chain_object));
591 } else {
592 delete[] chain_bytes;
593 }
594 CheckStatus(status, 594 CheckStatus(status,
595 "TlsException", 595 "TlsException",
596 "Failure in useCertificateChainBytes"); 596 "Failure in useCertificateChainBytes");
597 } 597 }
598 598
599 599
600 void FUNCTION_NAME(SecurityContext_SetClientAuthorities)( 600 static STACK_OF(X509_NAME)* GetCertificateNames(BIO* bio) {
601 STACK_OF(X509_NAME)* result = sk_X509_NAME_new_null();
602 if (result == NULL) {
603 return NULL;
604 }
605
606 while (true) {
607 X509* x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
608 if (x509 == NULL) {
609 break;
610 }
611
612 X509_NAME* x509_name = X509_get_subject_name(x509);
613 if (x509_name == NULL) {
614 sk_X509_NAME_pop_free(result, X509_NAME_free);
615 X509_free(x509);
616 return NULL;
617 }
618
619 // Duplicate the name to put it on the stack.
620 x509_name = X509_NAME_dup(x509_name);
621 if (x509_name == NULL) {
622 sk_X509_NAME_pop_free(result, X509_NAME_free);
623 X509_free(x509);
624 return NULL;
625 }
626 sk_X509_NAME_push(result, x509_name);
627 X509_free(x509);
628 }
629
630 return result;
631 }
632
633
634 void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)(
601 Dart_NativeArguments args) { 635 Dart_NativeArguments args) {
602 SSL_CTX* context = GetSecurityContext(args); 636 SSL_CTX* context = GetSecurityContext(args);
603 Dart_Handle filename_object = ThrowIfError(Dart_GetNativeArgument(args, 1)); 637
604 const char* filename = NULL; 638 BIO* bio = NULL;
605 if (Dart_IsString(filename_object)) { 639 Dart_Handle certs_object = ThrowIfError(Dart_GetNativeArgument(args, 1));
606 ThrowIfError(Dart_StringToCString(filename_object, &filename)); 640 bool is_typed_data = GetBIOArgument(certs_object, &bio);
607 } else { 641 ASSERT(bio != NULL);
608 Dart_ThrowException(DartUtils::NewDartArgumentError( 642
609 "file argument in SecurityContext.setClientAuthorities" 643 STACK_OF(X509_NAME)* certificate_names = GetCertificateNames(bio);
610 " is not a String")); 644
611 } 645 FreeBIO(certs_object, bio, is_typed_data);
612 STACK_OF(X509_NAME)* certificate_names; 646
613 certificate_names = SSL_load_client_CA_file(filename);
614 if (certificate_names != NULL) { 647 if (certificate_names != NULL) {
615 SSL_CTX_set_client_CA_list(context, certificate_names); 648 SSL_CTX_set_client_CA_list(context, certificate_names);
616 } else { 649 } else {
617 Dart_ThrowException(DartUtils::NewDartArgumentError( 650 Dart_ThrowException(DartUtils::NewDartArgumentError(
618 "Could not load certificate names from file in SetClientAuthorities")); 651 "Could not load certificate names from file in SetClientAuthorities"));
619 } 652 }
620 } 653 }
621 654
622 655
623 void FUNCTION_NAME(SecurityContext_SetAlpnProtocols)( 656 void FUNCTION_NAME(SecurityContext_SetAlpnProtocols)(
(...skipping 612 matching lines...) Expand 10 before | Expand all | Expand 10 after
1236 } else { 1269 } else {
1237 if (SSL_LOG_DATA) Log::Print( 1270 if (SSL_LOG_DATA) Log::Print(
1238 "WriteEncrypted BIO_read wrote %d bytes\n", bytes_processed); 1271 "WriteEncrypted BIO_read wrote %d bytes\n", bytes_processed);
1239 } 1272 }
1240 } 1273 }
1241 return bytes_processed; 1274 return bytes_processed;
1242 } 1275 }
1243 1276
1244 } // namespace bin 1277 } // namespace bin
1245 } // namespace dart 1278 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/bin/io_natives.cc ('k') | runtime/bin/secure_socket_patch.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698