Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |