diff options
author | jsing <> | 2019-09-08 17:00:05 +0000 |
---|---|---|
committer | jsing <> | 2019-09-08 17:00:05 +0000 |
commit | 79f43db0e9e6910673a15e03e802c3cc28083b8a (patch) | |
tree | 26ee5913af92445d851c4a009a9e9875b8ec536c /src | |
parent | 11474dfb0e4a1fb55d042fbfb4e2c68602f61508 (diff) | |
download | openbsd-79f43db0e9e6910673a15e03e802c3cc28083b8a.tar.gz openbsd-79f43db0e9e6910673a15e03e802c3cc28083b8a.tar.bz2 openbsd-79f43db0e9e6910673a15e03e802c3cc28083b8a.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 'src')
-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, |