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

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: Address comments 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
536 // If the data doesn't contain the PEM start line, try reading as PKCS12.
537 uint32_t err = ERR_peek_last_error();
538 if ((key == NULL) &&
539 (ERR_GET_LIB(err) == ERR_LIB_PEM) &&
540 (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
541 // Reset the bio, and clear the error from trying to read as PEM.
542 ERR_clear_error();
543 BIO_reset(bio);
544
545 // Try to decode as PKCS12
546 key = GetPrivateKeyPKCS12(bio, password);
547 }
548 return key;
549 }
550
551
448 void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)( 552 void FUNCTION_NAME(SecurityContext_UsePrivateKeyBytes)(
449 Dart_NativeArguments args) { 553 Dart_NativeArguments args) {
450 SSL_CTX* context = GetSecurityContext(args); 554 SSL_CTX* context = GetSecurityContext(args);
451 555
452 Dart_Handle password_object = ThrowIfError(Dart_GetNativeArgument(args, 2)); 556 Dart_Handle password_object = ThrowIfError(Dart_GetNativeArgument(args, 2));
453 const char* password = NULL; 557 const char* password = NULL;
454 if (Dart_IsString(password_object)) { 558 if (Dart_IsString(password_object)) {
455 ThrowIfError(Dart_StringToCString(password_object, &password)); 559 ThrowIfError(Dart_StringToCString(password_object, &password));
456 if (strlen(password) > PEM_BUFSIZE - 1) { 560 if (strlen(password) > PEM_BUFSIZE - 1) {
457 Dart_ThrowException(DartUtils::NewDartArgumentError( 561 Dart_ThrowException(DartUtils::NewDartArgumentError(
458 "SecurityContext.usePrivateKey password length is greater than" 562 "SecurityContext.usePrivateKey password length is greater than"
459 " 1023 (PEM_BUFSIZE)")); 563 " 1023 (PEM_BUFSIZE)"));
460 } 564 }
461 } else if (Dart_IsNull(password_object)) { 565 } else if (Dart_IsNull(password_object)) {
462 password = ""; 566 password = "";
463 } else { 567 } else {
464 Dart_ThrowException(DartUtils::NewDartArgumentError( 568 Dart_ThrowException(DartUtils::NewDartArgumentError(
465 "SecurityContext.usePrivateKey password is not a String or null")); 569 "SecurityContext.usePrivateKey password is not a String or null"));
466 } 570 }
467 571
468 int status; 572 int status;
469 { 573 {
470 MemBIOScope bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); 574 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
471 EVP_PKEY *key = PEM_read_bio_PrivateKey( 575 EVP_PKEY *key = GetPrivateKey(bio.bio(), password);
472 bio.bio(), NULL, PasswordCallback, const_cast<char*>(password));
473 status = SSL_CTX_use_PrivateKey(context, key); 576 status = SSL_CTX_use_PrivateKey(context, key);
474 } 577 }
475 578
476 // TODO(24184): Handle different expected errors here - file missing, 579 // TODO(24184): Handle different expected errors here - file missing,
477 // incorrect password, file not a PEM, and throw exceptions. 580 // incorrect password, file not a PEM, and throw exceptions.
478 // CheckStatus should also throw an exception in uncaught cases. 581 // CheckStatus should also throw an exception in uncaught cases.
479 CheckStatus(status, "TlsException", "Failure in usePrivateKeyBytes"); 582 CheckStatus(status, "TlsException", "Failure in usePrivateKeyBytes");
480 } 583 }
481 584
482 585
483 static int SetTrustedCertificatesBytes(SSL_CTX* context, BIO* bio) { 586 static int SetTrustedCertificatesBytesPKCS12(SSL_CTX* context, BIO* bio) {
587 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL));
588 if (p12.get() == NULL) {
589 return NULL;
590 }
591
592 EVP_PKEY* key = NULL;
593 X509 *cert = NULL;
594 STACK_OF(X509) *ca_certs = NULL;
595 // There should be no private keys in this file, so we hardcode the password
596 // to "".
597 // TODO(zra): Allow passing a password anyway.
598 int status = PKCS12_parse(p12.get(), "", &key, &cert, &ca_certs);
599 if (status == 0) {
600 return status;
601 }
602
603 ScopedX509Stack cert_stack(ca_certs);
604
605 // There should be no private key.
606 if (key != NULL) {
607 X509_free(cert);
608 return 0;
609 }
610
611 X509_STORE* store = SSL_CTX_get_cert_store(context);
612 status = X509_STORE_add_cert(store, cert);
613 if (status == 0) {
614 X509_free(cert);
615 return status;
616 }
617
618 X509* ca;
619 while ((ca = sk_X509_shift(cert_stack.get())) != NULL) {
620 status = X509_STORE_add_cert(store, ca);
621 if (status == 0) {
622 X509_free(ca);
623 return status;
624 }
625 }
626
627 return status;
628 }
629
630
631 static int SetTrustedCertificatesBytesPEM(SSL_CTX* context, BIO* bio) {
484 X509_STORE* store = SSL_CTX_get_cert_store(context); 632 X509_STORE* store = SSL_CTX_get_cert_store(context);
485 633
486 int status = 0; 634 int status = 0;
487 X509* cert = NULL; 635 X509* cert = NULL;
488 while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) { 636 while ((cert = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) {
489 status = X509_STORE_add_cert(store, cert); 637 status = X509_STORE_add_cert(store, cert);
490 if (status == 0) { 638 if (status == 0) {
491 X509_free(cert); 639 X509_free(cert);
492 return status; 640 return status;
493 } 641 }
494 } 642 }
495 643
496 uint32_t err = ERR_peek_last_error(); 644 uint32_t err = ERR_peek_last_error();
497 if ((ERR_GET_LIB(err) == ERR_LIB_PEM) && 645 if ((ERR_GET_LIB(err) != ERR_LIB_PEM) ||
498 (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) { 646 (ERR_GET_REASON(err) != PEM_R_NO_START_LINE)) {
499 // Reached the end of the buffer.
500 ERR_clear_error();
501 } else {
502 // Some real error happened. 647 // Some real error happened.
503 status = 0; 648 status = 0;
504 } 649 }
505 650
506 return status; 651 return status;
507 } 652 }
508 653
509 654
655 static int SetTrustedCertificatesBytes(SSL_CTX* context, BIO* bio) {
656 int status = SetTrustedCertificatesBytesPEM(context, bio);
657 uint32_t err = ERR_peek_last_error();
658 if ((status == 0) &&
659 (ERR_GET_LIB(err) == ERR_LIB_PEM) &&
660 (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
661 ERR_clear_error();
662 BIO_reset(bio);
663 status = SetTrustedCertificatesBytesPKCS12(context, bio);
664 } else if (status != 0) {
665 // The PEM file was successfully parsed.
666 ERR_clear_error();
667 }
668 return status;
669 }
670
671
510 void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)( 672 void FUNCTION_NAME(SecurityContext_SetTrustedCertificatesBytes)(
511 Dart_NativeArguments args) { 673 Dart_NativeArguments args) {
512 SSL_CTX* context = GetSecurityContext(args); 674 SSL_CTX* context = GetSecurityContext(args);
513 int status; 675 int status;
514 { 676 {
515 MemBIOScope bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); 677 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
516 status = SetTrustedCertificatesBytes(context, bio.bio()); 678 status = SetTrustedCertificatesBytes(context, bio.bio());
517 } 679 }
518 CheckStatus(status, 680 CheckStatus(status,
519 "TlsException", 681 "TlsException",
520 "Failure in setTrustedCertificatesBytes"); 682 "Failure in setTrustedCertificatesBytes");
521 } 683 }
522 684
523 685
524 void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)( 686 void FUNCTION_NAME(SecurityContext_TrustBuiltinRoots)(
525 Dart_NativeArguments args) { 687 Dart_NativeArguments args) {
526 SSL_CTX* context = GetSecurityContext(args); 688 SSL_CTX* context = GetSecurityContext(args);
527 X509_STORE* store = SSL_CTX_get_cert_store(context); 689 X509_STORE* store = SSL_CTX_get_cert_store(context);
528 BIO* roots_bio = 690 BIO* roots_bio =
529 BIO_new_mem_buf(const_cast<unsigned char*>(root_certificates_pem), 691 BIO_new_mem_buf(const_cast<unsigned char*>(root_certificates_pem),
530 root_certificates_pem_length); 692 root_certificates_pem_length);
531 X509* root_cert; 693 X509* root_cert;
532 // PEM_read_bio_X509 reads PEM-encoded certificates from a bio (in our case, 694 // 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. 695 // backed by a memory buffer), and returns X509 objects, one by one.
534 // When the end of the bio is reached, it returns null. 696 // When the end of the bio is reached, it returns null.
535 while ((root_cert = PEM_read_bio_X509(roots_bio, NULL, NULL, NULL))) { 697 while ((root_cert = PEM_read_bio_X509(roots_bio, NULL, NULL, NULL))) {
536 X509_STORE_add_cert(store, root_cert); 698 X509_STORE_add_cert(store, root_cert);
537 } 699 }
538 BIO_free(roots_bio); 700 BIO_free(roots_bio);
539 } 701 }
540 702
541 703
542 static int UseChainBytes(SSL_CTX* context, BIO* bio) { 704 static int UseChainBytesPKCS12(SSL_CTX* context, BIO* bio) {
543 int status = 0; 705 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL));
544 X509* x509 = PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL); 706 if (p12.get() == NULL) {
545 if (x509 == NULL) { 707 return NULL;
708 }
709
710 EVP_PKEY* key = NULL;
711 X509 *cert = NULL;
712 STACK_OF(X509) *ca_certs = NULL;
713 // There should be no private keys in this file, so we hardcode the password
714 // to "".
715 // TODO(zra): Allow passing a password anyway.
716 int status = PKCS12_parse(p12.get(), "", &key, &cert, &ca_certs);
717 if (status == 0) {
718 return status;
719 }
720
721 ScopedX509 x509(cert);
722 ScopedX509Stack certs(ca_certs);
723
724 // There should be no private key.
725 if (key != NULL) {
546 return 0; 726 return 0;
547 } 727 }
548 728
549 status = SSL_CTX_use_certificate(context, x509); 729 status = SSL_CTX_use_certificate(context, x509.get());
550 if (ERR_peek_error() != 0) { 730 if (ERR_peek_error() != 0) {
551 // Key/certificate mismatch doesn't imply status is 0. 731 // Key/certificate mismatch doesn't imply status is 0.
552 status = 0; 732 status = 0;
553 } 733 }
554 if (status == 0) { 734 if (status == 0) {
555 X509_free(x509);
556 return status; 735 return status;
557 } 736 }
558 737
559 SSL_CTX_clear_chain_certs(context); 738 SSL_CTX_clear_chain_certs(context);
560 739
561 while (true) { 740 X509* ca;
562 X509* ca = PEM_read_bio_X509(bio, NULL, NULL, NULL); 741 while ((ca = sk_X509_shift(certs.get())) != NULL) {
563 if (ca == NULL) {
564 break;
565 }
566 status = SSL_CTX_add0_chain_cert(context, ca); 742 status = SSL_CTX_add0_chain_cert(context, ca);
567 if (status == 0) { 743 if (status == 0) {
568 X509_free(ca); 744 X509_free(ca);
569 X509_free(x509); 745 return status;
746 }
747 }
748
749 return status;
750 }
751
752
753 static int UseChainBytesPEM(SSL_CTX* context, BIO* bio) {
754 int status = 0;
755 ScopedX509 x509(PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL));
756 if (x509.get() == NULL) {
757 return 0;
758 }
759
760 status = SSL_CTX_use_certificate(context, x509.get());
761 if (ERR_peek_error() != 0) {
762 // Key/certificate mismatch doesn't imply status is 0.
763 status = 0;
764 }
765 if (status == 0) {
766 return status;
767 }
768
769 SSL_CTX_clear_chain_certs(context);
770
771 X509* ca;
772 while ((ca = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) {
773 status = SSL_CTX_add0_chain_cert(context, ca);
774 if (status == 0) {
775 X509_free(ca);
570 return status; 776 return status;
571 } 777 }
572 // Note that we must not free `ca` if it was successfully added to the 778 // 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 779 // chain. We must free the main certificate x509, though since its reference
574 // count is increased by SSL_CTX_use_certificate. 780 // count is increased by SSL_CTX_use_certificate.
575 } 781 }
576 782
577 uint32_t err = ERR_peek_last_error(); 783 uint32_t err = ERR_peek_last_error();
578 if ((ERR_GET_LIB(err) == ERR_LIB_PEM) && 784 if ((ERR_GET_LIB(err) != ERR_LIB_PEM) ||
579 (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) { 785 (ERR_GET_REASON(err) != PEM_R_NO_START_LINE)) {
580 // Reached the end of the buffer.
581 ERR_clear_error();
582 } else {
583 // Some real error happened. 786 // Some real error happened.
584 status = 0; 787 status = 0;
585 } 788 }
586 789
587 X509_free(x509);
588 return status; 790 return status;
589 } 791 }
590 792
793
794 static int UseChainBytes(SSL_CTX* context, BIO* bio) {
795 int status = UseChainBytesPEM(context, bio);
796 uint32_t err = ERR_peek_last_error();
797 if ((status == 0) &&
798 (ERR_GET_LIB(err) == ERR_LIB_PEM) &&
799 (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
800 ERR_clear_error();
801 BIO_reset(bio);
802 status = UseChainBytesPKCS12(context, bio);
803 } else if (status != 0) {
804 // The PEM file was successfully parsed.
805 ERR_clear_error();
806 }
807 return status;
808 }
809
591 810
592 void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)( 811 void FUNCTION_NAME(SecurityContext_UseCertificateChainBytes)(
593 Dart_NativeArguments args) { 812 Dart_NativeArguments args) {
594 SSL_CTX* context = GetSecurityContext(args); 813 SSL_CTX* context = GetSecurityContext(args);
595 int status; 814 int status;
596 { 815 {
597 MemBIOScope bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); 816 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
598 status = UseChainBytes(context, bio.bio()); 817 status = UseChainBytes(context, bio.bio());
599 } 818 }
600 CheckStatus(status, 819 CheckStatus(status,
601 "TlsException", 820 "TlsException",
602 "Failure in useCertificateChainBytes"); 821 "Failure in useCertificateChainBytes");
603 } 822 }
604 823
605 824
606 static STACK_OF(X509_NAME)* GetCertificateNames(BIO* bio) { 825 static STACK_OF(X509_NAME)* GetCertificateNamesPKCS12(BIO* bio) {
607 STACK_OF(X509_NAME)* result = sk_X509_NAME_new_null(); 826 ScopedPKCS12 p12(d2i_PKCS12_bio(bio, NULL));
608 if (result == NULL) { 827 if (p12.get() == NULL) {
828 return NULL;
829 }
830
831 ScopedX509NAMEStack result(sk_X509_NAME_new_null());
832 if (result.get() == NULL) {
833 return NULL;
834 }
835
836 EVP_PKEY* key = NULL;
837 X509 *cert = NULL;
838 STACK_OF(X509) *ca_certs = NULL;
839 // There should be no private keys in this file, so we hardcode the password
840 // to "".
841 // TODO(zra): Allow passing a password anyway.
842 int status = PKCS12_parse(p12.get(), "", &key, &cert, &ca_certs);
843 if (status == 0) {
844 return NULL;
845 }
846
847 ScopedX509 x509(cert);
848 ScopedX509Stack certs(ca_certs);
849
850 // There should be no private key.
851 if (key != NULL) {
852 return NULL;
853 }
854
855 X509_NAME* x509_name = X509_get_subject_name(x509.get());
856 if (x509_name == NULL) {
857 return NULL;
858 }
859
860 x509_name = X509_NAME_dup(x509_name);
861 if (x509_name == NULL) {
862 return NULL;
863 }
864
865 sk_X509_NAME_push(result.get(), x509_name);
866
867 while (true) {
868 ScopedX509 ca(sk_X509_shift(certs.get()));
869 if (ca.get() == NULL) {
870 break;
871 }
872
873 X509_NAME* x509_name = X509_get_subject_name(ca.get());
874 if (x509_name == NULL) {
875 return NULL;
876 }
877
878 x509_name = X509_NAME_dup(x509_name);
879 if (x509_name == NULL) {
880 return NULL;
881 }
882
883 sk_X509_NAME_push(result.get(), x509_name);
884 }
885
886 return result.release();
887 }
888
889
890 static STACK_OF(X509_NAME)* GetCertificateNamesPEM(BIO* bio) {
891 ScopedX509NAMEStack result(sk_X509_NAME_new_null());
892 if (result.get() == NULL) {
609 return NULL; 893 return NULL;
610 } 894 }
611 895
612 while (true) { 896 while (true) {
613 X509* x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); 897 ScopedX509 x509(PEM_read_bio_X509(bio, NULL, NULL, NULL));
614 if (x509 == NULL) { 898 if (x509.get() == NULL) {
615 break; 899 break;
616 } 900 }
617 901
618 X509_NAME* x509_name = X509_get_subject_name(x509); 902 X509_NAME* x509_name = X509_get_subject_name(x509.get());
619 if (x509_name == NULL) { 903 if (x509_name == NULL) {
620 sk_X509_NAME_pop_free(result, X509_NAME_free);
621 X509_free(x509);
622 return NULL; 904 return NULL;
623 } 905 }
624 906
625 // Duplicate the name to put it on the stack. 907 // Duplicate the name to put it on the stack.
626 x509_name = X509_NAME_dup(x509_name); 908 x509_name = X509_NAME_dup(x509_name);
627 if (x509_name == NULL) { 909 if (x509_name == NULL) {
628 sk_X509_NAME_pop_free(result, X509_NAME_free);
629 X509_free(x509);
630 return NULL; 910 return NULL;
631 } 911 }
632 sk_X509_NAME_push(result, x509_name); 912 sk_X509_NAME_push(result.get(), x509_name);
633 X509_free(x509);
634 } 913 }
635 914
915 uint32_t err = ERR_peek_last_error();
916 if ((ERR_GET_LIB(err) != ERR_LIB_PEM) ||
917 (ERR_GET_REASON(err) != PEM_R_NO_START_LINE)) {
918 // Some real error happened.
919 return NULL;
920 }
921
922 return result.release();
923 }
924
925
926 static STACK_OF(X509_NAME)* GetCertificateNames(BIO* bio) {
927 STACK_OF(X509_NAME)* result = GetCertificateNamesPEM(bio);
928 uint32_t err = ERR_peek_last_error();
929 if ((result == NULL) &&
930 (ERR_GET_LIB(err) == ERR_LIB_PEM) &&
931 (ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
932 ERR_clear_error();
933 BIO_reset(bio);
934 result = GetCertificateNamesPKCS12(bio);
935 } else if (result != NULL) {
936 // The PEM file was successfully parsed.
937 ERR_clear_error();
938 }
636 return result; 939 return result;
637 } 940 }
638 941
639 942
640 void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)( 943 void FUNCTION_NAME(SecurityContext_SetClientAuthoritiesBytes)(
641 Dart_NativeArguments args) { 944 Dart_NativeArguments args) {
642 SSL_CTX* context = GetSecurityContext(args); 945 SSL_CTX* context = GetSecurityContext(args);
643 STACK_OF(X509_NAME)* certificate_names; 946 STACK_OF(X509_NAME)* certificate_names;
644 947
645 { 948 {
646 MemBIOScope bio(ThrowIfError(Dart_GetNativeArgument(args, 1))); 949 ScopedMemBIO bio(ThrowIfError(Dart_GetNativeArgument(args, 1)));
647 certificate_names = GetCertificateNames(bio.bio()); 950 certificate_names = GetCertificateNames(bio.bio());
648 } 951 }
649 952
650 if (certificate_names != NULL) { 953 if (certificate_names != NULL) {
651 SSL_CTX_set_client_CA_list(context, certificate_names); 954 SSL_CTX_set_client_CA_list(context, certificate_names);
652 } else { 955 } else {
653 Dart_ThrowException(DartUtils::NewDartArgumentError( 956 Dart_ThrowException(DartUtils::NewDartArgumentError(
654 "Could not load certificate names from file in SetClientAuthorities")); 957 "Could not load certificate names from file in SetClientAuthorities"));
655 } 958 }
656 } 959 }
(...skipping 615 matching lines...) Expand 10 before | Expand all | Expand 10 after
1272 } else { 1575 } else {
1273 if (SSL_LOG_DATA) Log::Print( 1576 if (SSL_LOG_DATA) Log::Print(
1274 "WriteEncrypted BIO_read wrote %d bytes\n", bytes_processed); 1577 "WriteEncrypted BIO_read wrote %d bytes\n", bytes_processed);
1275 } 1578 }
1276 } 1579 }
1277 return bytes_processed; 1580 return bytes_processed;
1278 } 1581 }
1279 1582
1280 } // namespace bin 1583 } // namespace bin
1281 } // namespace dart 1584 } // 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