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