diff options
| author | jsing <> | 2019-09-08 17:00:05 +0000 | 
|---|---|---|
| committer | jsing <> | 2019-09-08 17:00:05 +0000 | 
| commit | 633c0b7b298b56e623ca77728f2044b8179ed6fd (patch) | |
| tree | 26ee5913af92445d851c4a009a9e9875b8ec536c | |
| parent | 428d94e41ffb941e459939409f837aa7a3ab188c (diff) | |
| download | openbsd-633c0b7b298b56e623ca77728f2044b8179ed6fd.tar.gz openbsd-633c0b7b298b56e623ca77728f2044b8179ed6fd.tar.bz2 openbsd-633c0b7b298b56e623ca77728f2044b8179ed6fd.zip | |
Add CMS ECC support.
This brings in EC code from OpenSSL 1.1.1b, with style(9) and whitespace
cleanups. All of this code is currently under OPENSSL_NO_CMS hence is a
no-op.
ok inoguchi@
Diffstat (limited to '')
| -rw-r--r-- | src/lib/libcrypto/ec/ec_ameth.c | 372 | 
1 files changed, 370 insertions, 2 deletions
| diff --git a/src/lib/libcrypto/ec/ec_ameth.c b/src/lib/libcrypto/ec/ec_ameth.c index 04c068200f..a7e80c73d7 100644 --- a/src/lib/libcrypto/ec/ec_ameth.c +++ b/src/lib/libcrypto/ec/ec_ameth.c | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | /* $OpenBSD: ec_ameth.c,v 1.25 2018/08/24 20:22:15 tb Exp $ */ | 1 | /* $OpenBSD: ec_ameth.c,v 1.26 2019/09/08 17:00:05 jsing Exp $ */ | 
| 2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL | 2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL | 
| 3 | * project 2006. | 3 | * project 2006. | 
| 4 | */ | 4 | */ | 
| @@ -65,9 +65,15 @@ | |||
| 65 | #include <openssl/err.h> | 65 | #include <openssl/err.h> | 
| 66 | #include <openssl/x509.h> | 66 | #include <openssl/x509.h> | 
| 67 | 67 | ||
| 68 | |||
| 69 | #include "asn1_locl.h" | 68 | #include "asn1_locl.h" | 
| 70 | 69 | ||
| 70 | #ifndef OPENSSL_NO_CMS | ||
| 71 | #include <openssl/cms.h> | ||
| 72 | |||
| 73 | static int ecdh_cms_decrypt(CMS_RecipientInfo *ri); | ||
| 74 | static int ecdh_cms_encrypt(CMS_RecipientInfo *ri); | ||
| 75 | #endif | ||
| 76 | |||
| 71 | static int | 77 | static int | 
| 72 | eckey_param2type(int *pptype, void **ppval, EC_KEY * ec_key) | 78 | eckey_param2type(int *pptype, void **ppval, EC_KEY * ec_key) | 
| 73 | { | 79 | { | 
| @@ -573,6 +579,36 @@ ec_pkey_ctrl(EVP_PKEY * pkey, int op, long arg1, void *arg2) | |||
| 573 | } | 579 | } | 
| 574 | return 1; | 580 | return 1; | 
| 575 | 581 | ||
| 582 | #ifndef OPENSSL_NO_CMS | ||
| 583 | case ASN1_PKEY_CTRL_CMS_SIGN: | ||
| 584 | if (arg1 == 0) { | ||
| 585 | X509_ALGOR *alg1, *alg2; | ||
| 586 | int snid, hnid; | ||
| 587 | |||
| 588 | CMS_SignerInfo_get0_algs(arg2, NULL, NULL, &alg1, &alg2); | ||
| 589 | if (alg1 == NULL || alg1->algorithm == NULL) | ||
| 590 | return -1; | ||
| 591 | hnid = OBJ_obj2nid(alg1->algorithm); | ||
| 592 | if (hnid == NID_undef) | ||
| 593 | return -1; | ||
| 594 | if (!OBJ_find_sigid_by_algs(&snid, hnid, EVP_PKEY_id(pkey))) | ||
| 595 | return -1; | ||
| 596 | X509_ALGOR_set0(alg2, OBJ_nid2obj(snid), V_ASN1_UNDEF, 0); | ||
| 597 | } | ||
| 598 | return 1; | ||
| 599 | |||
| 600 | case ASN1_PKEY_CTRL_CMS_ENVELOPE: | ||
| 601 | if (arg1 == 0) | ||
| 602 | return ecdh_cms_encrypt(arg2); | ||
| 603 | else if (arg1 == 1) | ||
| 604 | return ecdh_cms_decrypt(arg2); | ||
| 605 | return -2; | ||
| 606 | |||
| 607 | case ASN1_PKEY_CTRL_CMS_RI_TYPE: | ||
| 608 | *(int *)arg2 = CMS_RECIPINFO_AGREE; | ||
| 609 | return 1; | ||
| 610 | #endif | ||
| 611 | |||
| 576 | case ASN1_PKEY_CTRL_DEFAULT_MD_NID: | 612 | case ASN1_PKEY_CTRL_DEFAULT_MD_NID: | 
| 577 | *(int *) arg2 = NID_sha1; | 613 | *(int *) arg2 = NID_sha1; | 
| 578 | return 2; | 614 | return 2; | 
| @@ -584,6 +620,338 @@ ec_pkey_ctrl(EVP_PKEY * pkey, int op, long arg1, void *arg2) | |||
| 584 | 620 | ||
| 585 | } | 621 | } | 
| 586 | 622 | ||
| 623 | #ifndef OPENSSL_NO_CMS | ||
| 624 | |||
| 625 | static int | ||
| 626 | ecdh_cms_set_peerkey(EVP_PKEY_CTX *pctx, X509_ALGOR *alg, | ||
| 627 | ASN1_BIT_STRING *pubkey) | ||
| 628 | { | ||
| 629 | const ASN1_OBJECT *aoid; | ||
| 630 | int atype; | ||
| 631 | const void *aval; | ||
| 632 | int rv = 0; | ||
| 633 | EVP_PKEY *pkpeer = NULL; | ||
| 634 | EC_KEY *ecpeer = NULL; | ||
| 635 | const unsigned char *p; | ||
| 636 | int plen; | ||
| 637 | |||
| 638 | X509_ALGOR_get0(&aoid, &atype, &aval, alg); | ||
| 639 | if (OBJ_obj2nid(aoid) != NID_X9_62_id_ecPublicKey) | ||
| 640 | goto err; | ||
| 641 | |||
| 642 | /* If absent parameters get group from main key */ | ||
| 643 | if (atype == V_ASN1_UNDEF || atype == V_ASN1_NULL) { | ||
| 644 | const EC_GROUP *grp; | ||
| 645 | EVP_PKEY *pk; | ||
| 646 | |||
| 647 | pk = EVP_PKEY_CTX_get0_pkey(pctx); | ||
| 648 | if (!pk) | ||
| 649 | goto err; | ||
| 650 | grp = EC_KEY_get0_group(pk->pkey.ec); | ||
| 651 | ecpeer = EC_KEY_new(); | ||
| 652 | if (ecpeer == NULL) | ||
| 653 | goto err; | ||
| 654 | if (!EC_KEY_set_group(ecpeer, grp)) | ||
| 655 | goto err; | ||
| 656 | } else { | ||
| 657 | ecpeer = eckey_type2param(atype, aval); | ||
| 658 | if (!ecpeer) | ||
| 659 | goto err; | ||
| 660 | } | ||
| 661 | |||
| 662 | /* We have parameters now set public key */ | ||
| 663 | plen = ASN1_STRING_length(pubkey); | ||
| 664 | p = ASN1_STRING_get0_data(pubkey); | ||
| 665 | if (!p || !plen) | ||
| 666 | goto err; | ||
| 667 | if (!o2i_ECPublicKey(&ecpeer, &p, plen)) | ||
| 668 | goto err; | ||
| 669 | pkpeer = EVP_PKEY_new(); | ||
| 670 | if (pkpeer == NULL) | ||
| 671 | goto err; | ||
| 672 | EVP_PKEY_set1_EC_KEY(pkpeer, ecpeer); | ||
| 673 | if (EVP_PKEY_derive_set_peer(pctx, pkpeer) > 0) | ||
| 674 | rv = 1; | ||
| 675 | err: | ||
| 676 | EC_KEY_free(ecpeer); | ||
| 677 | EVP_PKEY_free(pkpeer); | ||
| 678 | return rv; | ||
| 679 | } | ||
| 680 | |||
| 681 | /* Set KDF parameters based on KDF NID */ | ||
| 682 | static int | ||
| 683 | ecdh_cms_set_kdf_param(EVP_PKEY_CTX *pctx, int eckdf_nid) | ||
| 684 | { | ||
| 685 | int kdf_nid, kdfmd_nid, cofactor; | ||
| 686 | const EVP_MD *kdf_md; | ||
| 687 | |||
| 688 | if (eckdf_nid == NID_undef) | ||
| 689 | return 0; | ||
| 690 | |||
| 691 | /* Lookup KDF type, cofactor mode and digest */ | ||
| 692 | if (!OBJ_find_sigid_algs(eckdf_nid, &kdfmd_nid, &kdf_nid)) | ||
| 693 | return 0; | ||
| 694 | |||
| 695 | if (kdf_nid == NID_dh_std_kdf) | ||
| 696 | cofactor = 0; | ||
| 697 | else if (kdf_nid == NID_dh_cofactor_kdf) | ||
| 698 | cofactor = 1; | ||
| 699 | else | ||
| 700 | return 0; | ||
| 701 | |||
| 702 | if (EVP_PKEY_CTX_set_ecdh_cofactor_mode(pctx, cofactor) <= 0) | ||
| 703 | return 0; | ||
| 704 | |||
| 705 | if (EVP_PKEY_CTX_set_ecdh_kdf_type(pctx, EVP_PKEY_ECDH_KDF_X9_63) <= 0) | ||
| 706 | return 0; | ||
| 707 | |||
| 708 | kdf_md = EVP_get_digestbynid(kdfmd_nid); | ||
| 709 | if (!kdf_md) | ||
| 710 | return 0; | ||
| 711 | |||
| 712 | if (EVP_PKEY_CTX_set_ecdh_kdf_md(pctx, kdf_md) <= 0) | ||
| 713 | return 0; | ||
| 714 | |||
| 715 | return 1; | ||
| 716 | } | ||
| 717 | |||
| 718 | static int | ||
| 719 | ecdh_cms_set_shared_info(EVP_PKEY_CTX *pctx, CMS_RecipientInfo *ri) | ||
| 720 | { | ||
| 721 | X509_ALGOR *alg, *kekalg = NULL; | ||
| 722 | ASN1_OCTET_STRING *ukm; | ||
| 723 | const unsigned char *p; | ||
| 724 | unsigned char *der = NULL; | ||
| 725 | int plen, keylen; | ||
| 726 | const EVP_CIPHER *kekcipher; | ||
| 727 | EVP_CIPHER_CTX *kekctx; | ||
| 728 | int rv = 0; | ||
| 729 | |||
| 730 | if (!CMS_RecipientInfo_kari_get0_alg(ri, &alg, &ukm)) | ||
| 731 | return 0; | ||
| 732 | |||
| 733 | if (!ecdh_cms_set_kdf_param(pctx, OBJ_obj2nid(alg->algorithm))) { | ||
| 734 | ECerror(EC_R_KDF_PARAMETER_ERROR); | ||
| 735 | return 0; | ||
| 736 | } | ||
| 737 | |||
| 738 | if (alg->parameter->type != V_ASN1_SEQUENCE) | ||
| 739 | return 0; | ||
| 740 | |||
| 741 | p = alg->parameter->value.sequence->data; | ||
| 742 | plen = alg->parameter->value.sequence->length; | ||
| 743 | kekalg = d2i_X509_ALGOR(NULL, &p, plen); | ||
| 744 | if (!kekalg) | ||
| 745 | goto err; | ||
| 746 | kekctx = CMS_RecipientInfo_kari_get0_ctx(ri); | ||
| 747 | if (!kekctx) | ||
| 748 | goto err; | ||
| 749 | kekcipher = EVP_get_cipherbyobj(kekalg->algorithm); | ||
| 750 | if (!kekcipher || EVP_CIPHER_mode(kekcipher) != EVP_CIPH_WRAP_MODE) | ||
| 751 | goto err; | ||
| 752 | if (!EVP_EncryptInit_ex(kekctx, kekcipher, NULL, NULL, NULL)) | ||
| 753 | goto err; | ||
| 754 | if (EVP_CIPHER_asn1_to_param(kekctx, kekalg->parameter) <= 0) | ||
| 755 | goto err; | ||
| 756 | |||
| 757 | keylen = EVP_CIPHER_CTX_key_length(kekctx); | ||
| 758 | if (EVP_PKEY_CTX_set_ecdh_kdf_outlen(pctx, keylen) <= 0) | ||
| 759 | goto err; | ||
| 760 | |||
| 761 | plen = CMS_SharedInfo_encode(&der, kekalg, ukm, keylen); | ||
| 762 | if (!plen) | ||
| 763 | goto err; | ||
| 764 | |||
| 765 | if (EVP_PKEY_CTX_set0_ecdh_kdf_ukm(pctx, der, plen) <= 0) | ||
| 766 | goto err; | ||
| 767 | der = NULL; | ||
| 768 | |||
| 769 | rv = 1; | ||
| 770 | err: | ||
| 771 | X509_ALGOR_free(kekalg); | ||
| 772 | free(der); | ||
| 773 | return rv; | ||
| 774 | } | ||
| 775 | |||
| 776 | static int | ||
| 777 | ecdh_cms_decrypt(CMS_RecipientInfo *ri) | ||
| 778 | { | ||
| 779 | EVP_PKEY_CTX *pctx; | ||
| 780 | |||
| 781 | pctx = CMS_RecipientInfo_get0_pkey_ctx(ri); | ||
| 782 | if (!pctx) | ||
| 783 | return 0; | ||
| 784 | |||
| 785 | /* See if we need to set peer key */ | ||
| 786 | if (!EVP_PKEY_CTX_get0_peerkey(pctx)) { | ||
| 787 | X509_ALGOR *alg; | ||
| 788 | ASN1_BIT_STRING *pubkey; | ||
| 789 | |||
| 790 | if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &alg, &pubkey, | ||
| 791 | NULL, NULL, NULL)) | ||
| 792 | return 0; | ||
| 793 | if (!alg || !pubkey) | ||
| 794 | return 0; | ||
| 795 | if (!ecdh_cms_set_peerkey(pctx, alg, pubkey)) { | ||
| 796 | ECerror(EC_R_PEER_KEY_ERROR); | ||
| 797 | return 0; | ||
| 798 | } | ||
| 799 | } | ||
| 800 | |||
| 801 | /* Set ECDH derivation parameters and initialise unwrap context */ | ||
| 802 | if (!ecdh_cms_set_shared_info(pctx, ri)) { | ||
| 803 | ECerror(EC_R_SHARED_INFO_ERROR); | ||
| 804 | return 0; | ||
| 805 | } | ||
| 806 | |||
| 807 | return 1; | ||
| 808 | } | ||
| 809 | |||
| 810 | static int | ||
| 811 | ecdh_cms_encrypt(CMS_RecipientInfo *ri) | ||
| 812 | { | ||
| 813 | EVP_PKEY_CTX *pctx; | ||
| 814 | EVP_PKEY *pkey; | ||
| 815 | EVP_CIPHER_CTX *ctx; | ||
| 816 | int keylen; | ||
| 817 | X509_ALGOR *talg, *wrap_alg = NULL; | ||
| 818 | const ASN1_OBJECT *aoid; | ||
| 819 | ASN1_BIT_STRING *pubkey; | ||
| 820 | ASN1_STRING *wrap_str; | ||
| 821 | ASN1_OCTET_STRING *ukm; | ||
| 822 | unsigned char *penc = NULL; | ||
| 823 | int penclen; | ||
| 824 | int ecdh_nid, kdf_type, kdf_nid, wrap_nid; | ||
| 825 | const EVP_MD *kdf_md; | ||
| 826 | int rv = 0; | ||
| 827 | |||
| 828 | pctx = CMS_RecipientInfo_get0_pkey_ctx(ri); | ||
| 829 | if (!pctx) | ||
| 830 | return 0; | ||
| 831 | /* Get ephemeral key */ | ||
| 832 | pkey = EVP_PKEY_CTX_get0_pkey(pctx); | ||
| 833 | if (!CMS_RecipientInfo_kari_get0_orig_id(ri, &talg, &pubkey, | ||
| 834 | NULL, NULL, NULL)) | ||
| 835 | goto err; | ||
| 836 | X509_ALGOR_get0(&aoid, NULL, NULL, talg); | ||
| 837 | |||
| 838 | /* Is everything uninitialised? */ | ||
| 839 | if (aoid == OBJ_nid2obj(NID_undef)) { | ||
| 840 | EC_KEY *eckey = pkey->pkey.ec; | ||
| 841 | unsigned char *p; | ||
| 842 | |||
| 843 | /* Set the key */ | ||
| 844 | penclen = i2o_ECPublicKey(eckey, NULL); | ||
| 845 | if (penclen <= 0) | ||
| 846 | goto err; | ||
| 847 | penc = malloc(penclen); | ||
| 848 | if (penc == NULL) | ||
| 849 | goto err; | ||
| 850 | p = penc; | ||
| 851 | penclen = i2o_ECPublicKey(eckey, &p); | ||
| 852 | if (penclen <= 0) | ||
| 853 | goto err; | ||
| 854 | ASN1_STRING_set0(pubkey, penc, penclen); | ||
| 855 | pubkey->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07); | ||
| 856 | pubkey->flags |= ASN1_STRING_FLAG_BITS_LEFT; | ||
| 857 | penc = NULL; | ||
| 858 | |||
| 859 | X509_ALGOR_set0(talg, OBJ_nid2obj(NID_X9_62_id_ecPublicKey), | ||
| 860 | V_ASN1_UNDEF, NULL); | ||
| 861 | } | ||
| 862 | |||
| 863 | /* See if custom parameters set */ | ||
| 864 | kdf_type = EVP_PKEY_CTX_get_ecdh_kdf_type(pctx); | ||
| 865 | if (kdf_type <= 0) | ||
| 866 | goto err; | ||
| 867 | if (!EVP_PKEY_CTX_get_ecdh_kdf_md(pctx, &kdf_md)) | ||
| 868 | goto err; | ||
| 869 | ecdh_nid = EVP_PKEY_CTX_get_ecdh_cofactor_mode(pctx); | ||
| 870 | if (ecdh_nid < 0) | ||
| 871 | goto err; | ||
| 872 | else if (ecdh_nid == 0) | ||
| 873 | ecdh_nid = NID_dh_std_kdf; | ||
| 874 | else if (ecdh_nid == 1) | ||
| 875 | ecdh_nid = NID_dh_cofactor_kdf; | ||
| 876 | |||
| 877 | if (kdf_type == EVP_PKEY_ECDH_KDF_NONE) { | ||
| 878 | kdf_type = EVP_PKEY_ECDH_KDF_X9_63; | ||
| 879 | if (EVP_PKEY_CTX_set_ecdh_kdf_type(pctx, kdf_type) <= 0) | ||
| 880 | goto err; | ||
| 881 | } else { | ||
| 882 | /* Unknown KDF */ | ||
| 883 | goto err; | ||
| 884 | } | ||
| 885 | if (kdf_md == NULL) { | ||
| 886 | /* Fixme later for better MD */ | ||
| 887 | kdf_md = EVP_sha1(); | ||
| 888 | if (EVP_PKEY_CTX_set_ecdh_kdf_md(pctx, kdf_md) <= 0) | ||
| 889 | goto err; | ||
| 890 | } | ||
| 891 | |||
| 892 | if (!CMS_RecipientInfo_kari_get0_alg(ri, &talg, &ukm)) | ||
| 893 | goto err; | ||
| 894 | |||
| 895 | /* Lookup NID for KDF+cofactor+digest */ | ||
| 896 | if (!OBJ_find_sigid_by_algs(&kdf_nid, EVP_MD_type(kdf_md), ecdh_nid)) | ||
| 897 | goto err; | ||
| 898 | |||
| 899 | /* Get wrap NID */ | ||
| 900 | ctx = CMS_RecipientInfo_kari_get0_ctx(ri); | ||
| 901 | wrap_nid = EVP_CIPHER_CTX_type(ctx); | ||
| 902 | keylen = EVP_CIPHER_CTX_key_length(ctx); | ||
| 903 | |||
| 904 | /* Package wrap algorithm in an AlgorithmIdentifier */ | ||
| 905 | |||
| 906 | wrap_alg = X509_ALGOR_new(); | ||
| 907 | if (wrap_alg == NULL) | ||
| 908 | goto err; | ||
| 909 | wrap_alg->algorithm = OBJ_nid2obj(wrap_nid); | ||
| 910 | wrap_alg->parameter = ASN1_TYPE_new(); | ||
| 911 | if (wrap_alg->parameter == NULL) | ||
| 912 | goto err; | ||
| 913 | if (EVP_CIPHER_param_to_asn1(ctx, wrap_alg->parameter) <= 0) | ||
| 914 | goto err; | ||
| 915 | if (ASN1_TYPE_get(wrap_alg->parameter) == NID_undef) { | ||
| 916 | ASN1_TYPE_free(wrap_alg->parameter); | ||
| 917 | wrap_alg->parameter = NULL; | ||
| 918 | } | ||
| 919 | |||
| 920 | if (EVP_PKEY_CTX_set_ecdh_kdf_outlen(pctx, keylen) <= 0) | ||
| 921 | goto err; | ||
| 922 | |||
| 923 | penclen = CMS_SharedInfo_encode(&penc, wrap_alg, ukm, keylen); | ||
| 924 | if (!penclen) | ||
| 925 | goto err; | ||
| 926 | |||
| 927 | if (EVP_PKEY_CTX_set0_ecdh_kdf_ukm(pctx, penc, penclen) <= 0) | ||
| 928 | goto err; | ||
| 929 | penc = NULL; | ||
| 930 | |||
| 931 | /* | ||
| 932 | * Now need to wrap encoding of wrap AlgorithmIdentifier into parameter | ||
| 933 | * of another AlgorithmIdentifier. | ||
| 934 | */ | ||
| 935 | penclen = i2d_X509_ALGOR(wrap_alg, &penc); | ||
| 936 | if (!penc || !penclen) | ||
| 937 | goto err; | ||
| 938 | wrap_str = ASN1_STRING_new(); | ||
| 939 | if (wrap_str == NULL) | ||
| 940 | goto err; | ||
| 941 | ASN1_STRING_set0(wrap_str, penc, penclen); | ||
| 942 | penc = NULL; | ||
| 943 | X509_ALGOR_set0(talg, OBJ_nid2obj(kdf_nid), V_ASN1_SEQUENCE, wrap_str); | ||
| 944 | |||
| 945 | rv = 1; | ||
| 946 | |||
| 947 | err: | ||
| 948 | free(penc); | ||
| 949 | X509_ALGOR_free(wrap_alg); | ||
| 950 | return rv; | ||
| 951 | } | ||
| 952 | |||
| 953 | #endif | ||
| 954 | |||
| 587 | const EVP_PKEY_ASN1_METHOD eckey_asn1_meth = { | 955 | const EVP_PKEY_ASN1_METHOD eckey_asn1_meth = { | 
| 588 | .pkey_id = EVP_PKEY_EC, | 956 | .pkey_id = EVP_PKEY_EC, | 
| 589 | .pkey_base_id = EVP_PKEY_EC, | 957 | .pkey_base_id = EVP_PKEY_EC, | 
