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

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

Issue 1687533002: Adds support for PKCS12 containers to SecurityContext (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: 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 | « CHANGELOG.md ('k') | sdk/lib/io/security_context.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>
11 #include <string.h> 11 #include <string.h>
12 12
13 #include <openssl/bio.h> 13 #include <openssl/bio.h>
14 #include <openssl/err.h> 14 #include <openssl/err.h>
15 #include <openssl/pkcs12.h>
15 #include <openssl/safestack.h> 16 #include <openssl/safestack.h>
16 #include <openssl/ssl.h> 17 #include <openssl/ssl.h>
17 #include <openssl/tls1.h> 18 #include <openssl/tls1.h>
18 #include <openssl/x509.h> 19 #include <openssl/x509.h>
19 20
20 #include "bin/builtin.h" 21 #include "bin/builtin.h"
21 #include "bin/dartutils.h" 22 #include "bin/dartutils.h"
22 #include "bin/lockers.h" 23 #include "bin/lockers.h"
23 #include "bin/log.h" 24 #include "bin/log.h"
24 #include "bin/socket.h" 25 #include "bin/socket.h"
(...skipping 349 matching lines...) Expand 10 before | Expand all | Expand 10 after
374 } 375 }
375 ThrowIOException(status, type, message); 376 ThrowIOException(status, type, message);
376 } 377 }
377 378
378 379
379 // Where the argument to the constructor is the handle for an object 380 // Where the argument to the constructor is the handle for an object
380 // implementing List<int>, this class creates a scope in which a memory-backed 381 // implementing List<int>, this class creates a scope in which a memory-backed
381 // BIO is allocated. Leaving the scope cleans up the BIO and the buffer that 382 // BIO is allocated. Leaving the scope cleans up the BIO and the buffer that
382 // was used to create it. 383 // was used to create it.
383 // 384 //
384 // Do not make Dart_ API calls while in a MemBIOScope. 385 // Do not make Dart_ API calls while in a ScopedMemBIO.
385 // Do not call Dart_PropagateError while in a MemBIOScope. 386 // Do not call Dart_PropagateError while in a ScopedMemBIO.
386 class MemBIOScope { 387 class ScopedMemBIO {
387 public: 388 public:
388 explicit MemBIOScope(Dart_Handle object) { 389 explicit ScopedMemBIO(Dart_Handle object) {
389 if (!Dart_IsTypedData(object) && !Dart_IsList(object)) { 390 if (!Dart_IsTypedData(object) && !Dart_IsList(object)) {
390 Dart_ThrowException(DartUtils::NewDartArgumentError( 391 Dart_ThrowException(DartUtils::NewDartArgumentError(
391 "Argument is not a List<int>")); 392 "Argument is not a List<int>"));
392 } 393 }
393 394
394 uint8_t* bytes = NULL; 395 uint8_t* bytes = NULL;
395 intptr_t bytes_len = 0; 396 intptr_t bytes_len = 0;
396 bool is_typed_data = false; 397 bool is_typed_data = false;
397 if (Dart_IsTypedData(object)) { 398 if (Dart_IsTypedData(object)) {
398 is_typed_data = true; 399 is_typed_data = true;
(...skipping 12 matching lines...) Expand all
411 } 412 }
412 413
413 object_ = object; 414 object_ = object;
414 bytes_ = bytes; 415 bytes_ = bytes;
415 bytes_len_ = bytes_len; 416 bytes_len_ = bytes_len;
416 bio_ = BIO_new_mem_buf(bytes, bytes_len); 417 bio_ = BIO_new_mem_buf(bytes, bytes_len);
417 ASSERT(bio_ != NULL); 418 ASSERT(bio_ != NULL);
418 is_typed_data_ = is_typed_data; 419 is_typed_data_ = is_typed_data;
419 } 420 }
420 421
421 ~MemBIOScope() { 422 ~ScopedMemBIO() {
422 ASSERT(bio_ != NULL); 423 ASSERT(bio_ != NULL);
423 if (is_typed_data_) { 424 if (is_typed_data_) {
424 BIO_free(bio_); 425 BIO_free(bio_);
425 ThrowIfError(Dart_TypedDataReleaseData(object_)); 426 ThrowIfError(Dart_TypedDataReleaseData(object_));
426 } else { 427 } else {
427 BIO_free(bio_); 428 BIO_free(bio_);
428 } 429 }
429 } 430 }
430 431
431 BIO* bio() { 432 BIO* bio() {
432 ASSERT(bio_ != NULL); 433 ASSERT(bio_ != NULL);
433 return bio_; 434 return bio_;
434 } 435 }
435 436
436 private: 437 private:
437 Dart_Handle object_; 438 Dart_Handle object_;
438 uint8_t* bytes_; 439 uint8_t* bytes_;
439 intptr_t bytes_len_; 440 intptr_t bytes_len_;
440 BIO* bio_; 441 BIO* bio_;
441 bool is_typed_data_; 442 bool is_typed_data_;
442 443
443 DISALLOW_ALLOCATION(); 444 DISALLOW_ALLOCATION();
444 DISALLOW_COPY_AND_ASSIGN(MemBIOScope); 445 DISALLOW_COPY_AND_ASSIGN(ScopedMemBIO);
445 }; 446 };
446 447
447 448
449 template<typename T, void (*free_func)(T*)>
450 class ScopedSSLType {
451 public:
452 explicit ScopedSSLType(T* obj) : obj_(obj) {}
453
454 ~ScopedSSLType() {
455 if (obj_ != NULL) {
456 free_func(obj_);
457 }
458 }
459
460 T* get() { return obj_; }
461 const T* get() const { return obj_; }
462
463 T* release() {
464 T* result = obj_;
465 obj_ = NULL;
466 return result;
467 }
468
469 private:
470 T* obj_;
471
472 DISALLOW_ALLOCATION();
473 DISALLOW_COPY_AND_ASSIGN(ScopedSSLType);
474 };
475
476 template<typename T, typename E, void (*func)(E*)>
477 class ScopedSSLStackType {
478 public:
479 explicit ScopedSSLStackType(T* obj) : obj_(obj) {}
480
481 ~ScopedSSLStackType() {
482 if (obj_ != NULL) {
483 sk_pop_free(reinterpret_cast<_STACK*>(obj_),
484 reinterpret_cast<void (*)(void *)>(func));
485 }
486 }
487
488 T* get() { return obj_; }
489 const T* get() const { return obj_; }
490
491 T* release() {
492 T* result = obj_;
493 obj_ = NULL;
494 return result;
495 }
496
497 private:
498 T* obj_;
499
500 DISALLOW_ALLOCATION();
501 DISALLOW_COPY_AND_ASSIGN(ScopedSSLStackType);
502 };
503
504 typedef ScopedSSLType<PKCS12, PKCS12_free> ScopedPKCS12;
505 typedef ScopedSSLType<X509, X509_free> ScopedX509;
506
507 typedef ScopedSSLStackType<STACK_OF(X509), X509, X509_free> ScopedX509Stack;
508 typedef ScopedSSLStackType<STACK_OF(X509_NAME), X509_NAME, X509_NAME_free>
509 ScopedX509NAMEStack;
510
511 static EVP_PKEY* GetPrivateKeyPKCS12(BIO* bio, const char* password) {
512 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL));
513 if (p12.get() == NULL) {
514 return NULL;
515 }
516
517 EVP_PKEY* key = NULL;
518 X509 *cert = NULL;
519 STACK_OF(X509) *ca_certs = NULL;
520 int status = PKCS12_parse(p12.get(), password, &key, &cert, &ca_certs);
521 if (status == 0) {
522 return NULL;
523 }
524
525 // We only care about the private key.
526 ScopedX509 delete_cert(cert);
527 ScopedX509Stack delete_ca_certs(ca_certs);
528 return key;
529 }
530
531
532 static EVP_PKEY* GetPrivateKey(BIO* bio, const char* password) {
533 EVP_PKEY *key = PEM_read_bio_PrivateKey(
534 bio, NULL, PasswordCallback, const_cast<char*>(password));
535 if (key == NULL) {
536 // Reset the bio, and clear the error from trying to read as PEM.
537 ERR_clear_error();
538 BIO_reset(bio);
539
540 // Try to decode as PKCS12
541 key = GetPrivateKeyPKCS12(bio, password);
542 }
543 return key;
544 }
545
546
448 void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)( 547 void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)(
449 Dart_NativeArguments args) { 548 Dart_NativeArguments args) {
450 SSL_CTX* context = GetSecurityContext(args); 549 SSL_CTX* context = GetSecurityContext(args);
451 550
452 Dart_Handle password_object = ThrowIfError(Dart_GetNativeArgument(args, 2)); 551 Dart_Handle password_object = ThrowIfError(Dart_GetNativeArgument(args, 2));
453 const char* password = NULL; 552 const char* password = NULL;
454 if (Dart_IsString(password_object)) { 553 if (Dart_IsString(password_object)) {
455 ThrowIfError(Dart_StringToCString(password_object, &password)); 554 ThrowIfError(Dart_StringToCString(password_object, &password));
456 if (strlen(password) > PEM_BUFSIZE - 1) { 555 if (strlen(password) > PEM_BUFSIZE - 1) {
457 Dart_ThrowException(DartUtils::NewDartArgumentError( 556 Dart_ThrowException(DartUtils::NewDartArgumentError(
458 "SecurityContext.usePrivateKey password length is greater than" 557 "SecurityContext.usePrivateKey password length is greater than"
459 " 1023 (PEM_BUFSIZE)")); 558 " 1023 (PEM_BUFSIZE)"));
460 } 559 }
461 } else if (Dart_IsNull(password_object)) { 560 } else if (Dart_IsNull(password_object)) {
462 password = ""; 561 password = "";
463 } else { 562 } else {
464 Dart_ThrowException(DartUtils::NewDartArgumentError( 563 Dart_ThrowException(DartUtils::NewDartArgumentError(
465 "SecurityContext.usePrivateKey password is not a String or null")); 564 "SecurityContext.usePrivateKey password is not a String or null"));
466 } 565 }
467 566
468 int status; 567 int status;
469 { 568 {
470 MemBIOScope bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); 569 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
471 EVP_PKEY *key = PEM_read_bio_PrivateKey( 570 EVP_PKEY *key = GetPrivateKey(bio.bio(), password);
472 bio.bio(), NULL, PasswordCallback, const_cast<char*>(password));
473 status = SSL_CTX_use_PrivateKey(context, key); 571 status = SSL_CTX_use_PrivateKey(context, key);
474 } 572 }
475 573
476 // TODO(24184): Handle different expected errors here - file missing, 574 // TODO(24184): Handle different expected errors here - file missing,
477 // incorrect password, file not a PEM, and throw exceptions. 575 // incorrect password, file not a PEM, and throw exceptions.
478 // CheckStatus should also throw an exception in uncaught cases. 576 // CheckStatus should also throw an exception in uncaught cases.
479 CheckStatus(status, "TlsException", "Failure in usePrivateKeyBytes"); 577 CheckStatus(status, "TlsException", "Failure in usePrivateKeyBytes");
480 } 578 }
481 579
482 580
483 static int SetTrustedCertificatesBytes(SSL_CTX* context, BIO* bio) { 581 static int SetTrustedCertificatesBytesPKCS12(SSL_CTX* context, BIO* bio) {
582 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL));
583 if (p12.get() == NULL) {
584 return NULL;
585 }
586
587 EVP_PKEY* key = NULL;
588 X509 *cert = NULL;
589 STACK_OF(X509) *ca_certs = NULL;
590 // There should be no private keys in this file, so we hardcode the password
591 // to "".
592 // TODO(zra): Allow passing a password anyway.
593 int status = PKCS12_parse(p12.get(), "", &key, &cert, &ca_certs);
594 if (status == 0) {
595 return status;
596 }
597
598 ScopedX509Stack cert_stack(ca_certs);
599
600 // There should be no private key.
601 if (key != NULL) {
602 X509_free(cert);
603 return 0;
604 }
605
606 X509_STORE* store = SSL_CTX_get_cert_store(context);
607 status = X509_STORE_add_cert(store, cert);
608 if (status == 0) {
609 X509_free(cert);
610 return status;
611 }
612
613 X509* ca;
614 while ((ca = sk_X509_shift(cert_stack.get())) != NULL) {
615 status = X509_STORE_add_cert(store, ca);
616 if (status == 0) {
617 X509_free(ca);
618 return status;
619 }
620 }
621
622 return status;
623 }
624
625
626 static int SetTrustedCertificatesBytesPEM(SSL_CTX* context, BIO* bio) {
484 X509_STORE* store = SSL_CTX_get_cert_store(context); 627 X509_STORE* store = SSL_CTX_get_cert_store(context);
485 628
486 int status = 0; 629 int status = 0;
487 X509* cert = NULL; 630 X509* cert = NULL;
488 while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) { 631 while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) {
489 status = X509_STORE_add_cert(store, cert); 632 status = X509_STORE_add_cert(store, cert);
490 if (status == 0) { 633 if (status == 0) {
491 X509_free(cert); 634 X509_free(cert);
492 return status; 635 return status;
493 } 636 }
494 } 637 }
495 638
496 uint32_t err = ERR_peek_last_error(); 639 uint32_t err = ERR_peek_last_error();
497 if ((ERR_GET_LIB(err) == ERR_LIB_PEM) && 640 if ((ERR_GET_LIB(err) == ERR_LIB_PEM) &&
498 (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) { 641 (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
499 // Reached the end of the buffer. 642 // Reached the end of the buffer.
500 ERR_clear_error(); 643 ERR_clear_error();
501 } else { 644 } else {
502 // Some real error happened. 645 // Some real error happened.
503 status = 0; 646 status = 0;
504 } 647 }
505 648
506 return status; 649 return status;
507 } 650 }
508 651
509 652
653 static int SetTrustedCertificatesBytes(SSL_CTX* context, BIO* bio) {
654 int status = SetTrustedCertificatesBytesPEM(context, bio);
655 if (status == 0) {
656 ERR_clear_error();
657 BIO_reset(bio);
658 status = SetTrustedCertificatesBytesPKCS12(context, bio);
Bill Hesse 2016/02/10 18:08:39 If someone submits a flawed PEM file, they will ne
zra 2016/02/10 22:17:14 Rearranged the logic a bit to avoid this problem.
659 }
660 return status;
661 }
662
663
510 void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)( 664 void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)(
511 Dart_NativeArguments args) { 665 Dart_NativeArguments args) {
512 SSL_CTX* context = GetSecurityContext(args); 666 SSL_CTX* context = GetSecurityContext(args);
513 int status; 667 int status;
514 { 668 {
515 MemBIOScope bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); 669 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
516 status = SetTrustedCertificatesBytes(context, bio.bio()); 670 status = SetTrustedCertificatesBytes(context, bio.bio());
517 } 671 }
518 CheckStatus(status, 672 CheckStatus(status,
519 "TlsException", 673 "TlsException",
520 "Failure in setTrustedCertificatesBytes"); 674 "Failure in setTrustedCertificatesBytes");
521 } 675 }
522 676
523 677
524 void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)( 678 void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)(
525 Dart_NativeArguments args) { 679 Dart_NativeArguments args) {
526 SSL_CTX* context = GetSecurityContext(args); 680 SSL_CTX* context = GetSecurityContext(args);
527 X509_STORE* store = SSL_CTX_get_cert_store(context); 681 X509_STORE* store = SSL_CTX_get_cert_store(context);
528 BIO* roots_bio = 682 BIO* roots_bio =
529 BIO_new_mem_buf(const_cast<unsigned char*>(root_certificates_pem), 683 BIO_new_mem_buf(const_cast<unsigned char*>(root_certificates_pem),
530 root_certificates_pem_length); 684 root_certificates_pem_length);
531 X509* root_cert; 685 X509* root_cert;
532 // PEM_read_bio_X509 reads PEM-encoded certificates from a bio (in our case, 686 // PEM_read_bio_X509 reads PEM-encoded certificates from a bio (in our case,
533 // backed by a memory buffer), and returns X509 objects, one by one. 687 // backed by a memory buffer), and returns X509 objects, one by one.
534 // When the end of the bio is reached, it returns null. 688 // When the end of the bio is reached, it returns null.
535 while ((root_cert = PEM_read_bio_X509(roots_bio, NULL, NULL, NULL))) { 689 while ((root_cert = PEM_read_bio_X509(roots_bio, NULL, NULL, NULL))) {
536 X509_STORE_add_cert(store, root_cert); 690 X509_STORE_add_cert(store, root_cert);
537 } 691 }
538 BIO_free(roots_bio); 692 BIO_free(roots_bio);
539 } 693 }
540 694
541 695
542 static int UseChainBytes(SSL_CTX* context, BIO* bio) { 696 static int UseChainBytesPKCS12(SSL_CTX* context, BIO* bio) {
543 int status = 0; 697 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL));
544 X509* x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); 698 if (p12.get() == NULL) {
545 if (x509 == NULL) { 699 return NULL;
700 }
701
702 EVP_PKEY* key = NULL;
703 X509 *cert = NULL;
704 STACK_OF(X509) *ca_certs = NULL;
705 // There should be no private keys in this file, so we hardcode the password
706 // to "".
707 // TODO(zra): Allow passing a password anyway.
708 int status = PKCS12_parse(p12.get(), "", &key, &cert, &ca_certs);
709 if (status == 0) {
710 return status;
711 }
712
713 ScopedX509 x509(cert);
714 ScopedX509Stack certs(ca_certs);
715
716 // There should be no private key.
717 if (key != NULL) {
546 return 0; 718 return 0;
547 } 719 }
548 720
549 status = SSL_CTX_use_certificate(context, x509); 721 status = SSL_CTX_use_certificate(context, x509.get());
550 if (ERR_peek_error() != 0) { 722 if (ERR_peek_error() != 0) {
551 // Key/certificate mismatch doesn't imply status is 0. 723 // Key/certificate mismatch doesn't imply status is 0.
552 status = 0; 724 status = 0;
553 } 725 }
554 if (status == 0) { 726 if (status == 0) {
555 X509_free(x509);
556 return status; 727 return status;
557 } 728 }
558 729
559 SSL_CTX_clear_chain_certs(context); 730 SSL_CTX_clear_chain_certs(context);
560 731
561 while (true) { 732 X509* ca;
562 X509* ca = PEM_read_bio_X509(bio, NULL, NULL, NULL); 733 while ((ca = sk_X509_shift(certs.get())) != NULL) {
563 if (ca == NULL) {
564 break;
565 }
566 status = SSL_CTX_add0_chain_cert(context, ca); 734 status = SSL_CTX_add0_chain_cert(context, ca);
567 if (status == 0) { 735 if (status == 0) {
568 X509_free(ca); 736 X509_free(ca);
569 X509_free(x509); 737 return status;
738 }
739 }
740
741 return status;
742 }
743
744
745 static int UseChainBytesPEM(SSL_CTX* context, BIO* bio) {
746 int status = 0;
747 ScopedX509 x509(PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL));
748 if (x509.get() == NULL) {
749 return 0;
750 }
751
752 status = SSL_CTX_use_certificate(context, x509.get());
753 if (ERR_peek_error() != 0) {
754 // Key/certificate mismatch doesn't imply status is 0.
Bill Hesse 2016/02/10 18:08:39 Is this implying that we need to add the key to th
zra 2016/02/10 22:17:14 This only fires with a non-null key. This is extra
755 status = 0;
756 }
757 if (status == 0) {
758 return status;
759 }
760
761 SSL_CTX_clear_chain_certs(context);
762
763 X509* ca;
764 while ((ca = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) {
765 status = SSL_CTX_add0_chain_cert(context, ca);
766 if (status == 0) {
767 X509_free(ca);
570 return status; 768 return status;
571 } 769 }
572 // Note that we must not free `ca` if it was successfully added to the 770 // Note that we must not free `ca` if it was successfully added to the
573 // chain. We must free the main certificate x509, though since its reference 771 // chain. We must free the main certificate x509, though since its reference
574 // count is increased by SSL_CTX_use_certificate. 772 // count is increased by SSL_CTX_use_certificate.
575 } 773 }
576 774
577 uint32_t err = ERR_peek_last_error(); 775 uint32_t err = ERR_peek_last_error();
578 if ((ERR_GET_LIB(err) == ERR_LIB_PEM) && 776 if ((ERR_GET_LIB(err) == ERR_LIB_PEM) &&
579 (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) { 777 (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
580 // Reached the end of the buffer. 778 // Reached the end of the buffer.
581 ERR_clear_error(); 779 ERR_clear_error();
582 } else { 780 } else {
583 // Some real error happened. 781 // Some real error happened.
584 status = 0; 782 status = 0;
585 } 783 }
586 784
587 X509_free(x509);
588 return status; 785 return status;
589 } 786 }
590 787
788
789 static int UseChainBytes(SSL_CTX* context, BIO* bio) {
790 int status = UseChainBytesPEM(context, bio);
791 if (status == 0) {
792 ERR_clear_error();
793 BIO_reset(bio);
794 status = UseChainBytesPKCS12(context, bio);
795 }
796 return status;
797 }
798
591 799
592 void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)( 800 void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)(
593 Dart_NativeArguments args) { 801 Dart_NativeArguments args) {
594 SSL_CTX* context = GetSecurityContext(args); 802 SSL_CTX* context = GetSecurityContext(args);
595 int status; 803 int status;
596 { 804 {
597 MemBIOScope bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); 805 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
598 status = UseChainBytes(context, bio.bio()); 806 status = UseChainBytes(context, bio.bio());
599 } 807 }
600 CheckStatus(status, 808 CheckStatus(status,
601 "TlsException", 809 "TlsException",
602 "Failure in useCertificateChainBytes"); 810 "Failure in useCertificateChainBytes");
603 } 811 }
604 812
605 813
606 static STACK_OF(X509_NAME)* GetCertificateNames(BIO* bio) { 814 static STACK_OF(X509_NAME)* GetCertificateNamesPKCS12(BIO* bio) {
607 STACK_OF(X509_NAME)* result = sk_X509_NAME_new_null(); 815 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL));
608 if (result == NULL) { 816 if (p12.get() == NULL) {
817 return NULL;
818 }
819
820 ScopedX509NAMEStack result(sk_X509_NAME_new_null());
821 if (result.get() == NULL) {
822 return NULL;
823 }
824
825 EVP_PKEY* key = NULL;
826 X509 *cert = NULL;
827 STACK_OF(X509) *ca_certs = NULL;
828 // There should be no private keys in this file, so we hardcode the password
829 // to "".
830 // TODO(zra): Allow passing a password anyway.
831 int status = PKCS12_parse(p12.get(), "", &key, &cert, &ca_certs);
832 if (status == 0) {
833 return NULL;
834 }
835
836 ScopedX509 x509(cert);
837 ScopedX509Stack certs(ca_certs);
838
839 // There should be no private key.
840 if (key != NULL) {
841 return NULL;
842 }
843
844 X509_NAME* x509_name = X509_get_subject_name(x509.get());
845 if (x509_name == NULL) {
846 return NULL;
847 }
848
849 x509_name = X509_NAME_dup(x509_name);
850 if (x509_name == NULL) {
851 return NULL;
852 }
853
854 sk_X509_NAME_push(result.get(), x509_name);
855
856 while (true) {
857 ScopedX509 ca(sk_X509_shift(certs.get()));
858 if (ca.get() == NULL) {
859 break;
860 }
861
862 X509_NAME* x509_name = X509_get_subject_name(ca.get());
863 if (x509_name == NULL) {
864 return NULL;
865 }
866
867 x509_name = X509_NAME_dup(x509_name);
868 if (x509_name == NULL) {
869 return NULL;
870 }
871
872 sk_X509_NAME_push(result.get(), x509_name);
873 }
874
875 return result.release();
876 }
877
878
879 static STACK_OF(X509_NAME)* GetCertificateNamesPEM(BIO* bio) {
880 ScopedX509NAMEStack result(sk_X509_NAME_new_null());
881 if (result.get() == NULL) {
609 return NULL; 882 return NULL;
610 } 883 }
611 884
612 while (true) { 885 while (true) {
613 X509* x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); 886 ScopedX509 x509(PEM_read_bio_X509(bio, NULL, NULL, NULL));
614 if (x509 == NULL) { 887 if (x509.get() == NULL) {
Bill Hesse 2016/02/10 18:08:39 Isn't this the result of an error reading the file
zra 2016/02/10 22:17:14 Added error checking as done in the other calls.
615 break; 888 break;
616 } 889 }
617 890
618 X509_NAME* x509_name = X509_get_subject_name(x509); 891 X509_NAME* x509_name = X509_get_subject_name(x509.get());
619 if (x509_name == NULL) { 892 if (x509_name == NULL) {
620 sk_X509_NAME_pop_free(result, X509_NAME_free);
621 X509_free(x509);
622 return NULL; 893 return NULL;
623 } 894 }
624 895
625 // Duplicate the name to put it on the stack. 896 // Duplicate the name to put it on the stack.
626 x509_name = X509_NAME_dup(x509_name); 897 x509_name = X509_NAME_dup(x509_name);
627 if (x509_name == NULL) { 898 if (x509_name == NULL) {
628 sk_X509_NAME_pop_free(result, X509_NAME_free);
629 X509_free(x509);
630 return NULL; 899 return NULL;
631 } 900 }
632 sk_X509_NAME_push(result, x509_name); 901 sk_X509_NAME_push(result.get(), x509_name);
633 X509_free(x509);
634 } 902 }
635 903
904 return result.release();
905 }
906
907
908 static STACK_OF(X509_NAME)* GetCertificateNames(BIO* bio) {
909 STACK_OF(X509_NAME)* result = GetCertificateNamesPEM(bio);
910 if (result == NULL) {
911 ERR_clear_error();
912 BIO_reset(bio);
913 result = GetCertificateNamesPKCS12(bio);
914 }
636 return result; 915 return result;
637 } 916 }
638 917
639 918
640 void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)( 919 void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)(
641 Dart_NativeArguments args) { 920 Dart_NativeArguments args) {
642 SSL_CTX* context = GetSecurityContext(args); 921 SSL_CTX* context = GetSecurityContext(args);
643 STACK_OF(X509_NAME)* certificate_names; 922 STACK_OF(X509_NAME)* certificate_names;
644 923
645 { 924 {
646 MemBIOScope bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); 925 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
647 certificate_names = GetCertificateNames(bio.bio()); 926 certificate_names = GetCertificateNames(bio.bio());
648 } 927 }
649 928
650 if (certificate_names != NULL) { 929 if (certificate_names != NULL) {
651 SSL_CTX_set_client_CA_list(context, certificate_names); 930 SSL_CTX_set_client_CA_list(context, certificate_names);
652 } else { 931 } else {
653 Dart_ThrowException(DartUtils::NewDartArgumentError( 932 Dart_ThrowException(DartUtils::NewDartArgumentError(
654 "Could not load certificate names from file in SetClientAuthorities")); 933 "Could not load certificate names from file in SetClientAuthorities"));
655 } 934 }
656 } 935 }
(...skipping 615 matching lines...) Expand 10 before | Expand all | Expand 10 after
1272 } else { 1551 } else {
1273 if (SSL_LOG_DATA) Log::Print( 1552 if (SSL_LOG_DATA) Log::Print(
1274 "WriteEncrypted BIO_read wrote %d bytes\n", bytes_processed); 1553 "WriteEncrypted BIO_read wrote %d bytes\n", bytes_processed);
1275 } 1554 }
1276 } 1555 }
1277 return bytes_processed; 1556 return bytes_processed;
1278 } 1557 }
1279 1558
1280 } // namespace bin 1559 } // namespace bin
1281 } // namespace dart 1560 } // namespace dart
OLDNEW
« no previous file with comments | « CHANGELOG.md ('k') | sdk/lib/io/security_context.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698