diff options
author | tb <> | 2024-10-17 14:34:06 +0000 |
---|---|---|
committer | tb <> | 2024-10-17 14:34:06 +0000 |
commit | a2ef0e2df9a19f862265cd5c206555caba13070f (patch) | |
tree | 25130d18dbeb457738024eeceb2d57abb7cf62e9 /src | |
parent | 978d3a277baeb25c75e71e4d12342c47d1764205 (diff) | |
download | openbsd-a2ef0e2df9a19f862265cd5c206555caba13070f.tar.gz openbsd-a2ef0e2df9a19f862265cd5c206555caba13070f.tar.bz2 openbsd-a2ef0e2df9a19f862265cd5c206555caba13070f.zip |
Split ec_asn1_parameters2group() into digestible pieces
This becomes a simple wrapper function that currently does three checks:
1. ensure the fieldID is for a prime field
2. check that the purported prime is of reasonable size, extract and
set curve coefficients and point conversion form
3. extract and set generator, order, cofactor and seed.
Sanity checks such as the Hasse bound are dealt with in the EC_GROUP API,
so need not be repeated here. They will become redundant once we enforce
that the parameters represent a builtin curve anyway.
ok jsing
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/libcrypto/ec/ec_asn1.c | 240 |
1 files changed, 144 insertions, 96 deletions
diff --git a/src/lib/libcrypto/ec/ec_asn1.c b/src/lib/libcrypto/ec/ec_asn1.c index 02609606ff..289bc3b271 100644 --- a/src/lib/libcrypto/ec/ec_asn1.c +++ b/src/lib/libcrypto/ec/ec_asn1.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ec_asn1.c,v 1.73 2024/10/15 06:35:59 tb Exp $ */ | 1 | /* $OpenBSD: ec_asn1.c,v 1.74 2024/10/17 14:34:06 tb Exp $ */ |
2 | /* | 2 | /* |
3 | * Written by Nils Larsch for the OpenSSL project. | 3 | * Written by Nils Larsch for the OpenSSL project. |
4 | */ | 4 | */ |
@@ -818,99 +818,98 @@ ec_asn1_group2pkparameters(const EC_GROUP *group) | |||
818 | return NULL; | 818 | return NULL; |
819 | } | 819 | } |
820 | 820 | ||
821 | static EC_GROUP * | 821 | static int |
822 | ec_asn1_parameters2group(const ECPARAMETERS *params) | 822 | ec_asn1_is_prime_field(const X9_62_FIELDID *fieldid) |
823 | { | 823 | { |
824 | int ok = 0, tmp; | 824 | int nid; |
825 | EC_GROUP *ret = NULL; | 825 | |
826 | BIGNUM *p = NULL, *a = NULL, *b = NULL, *order = NULL, *cofactor = NULL; | 826 | if (fieldid == NULL) { |
827 | EC_POINT *point = NULL; | ||
828 | int field_bits; | ||
829 | |||
830 | if (!params->fieldID || !params->fieldID->fieldType || | ||
831 | !params->fieldID->p.ptr) { | ||
832 | ECerror(EC_R_ASN1_ERROR); | 827 | ECerror(EC_R_ASN1_ERROR); |
833 | goto err; | 828 | return 0; |
834 | } | 829 | } |
835 | /* now extract the curve parameters a and b */ | 830 | if ((nid = OBJ_obj2nid(fieldid->fieldType)) == NID_undef) { |
836 | if (!params->curve || !params->curve->a || | 831 | ECerror(EC_R_INVALID_FIELD); |
837 | !params->curve->a->data || !params->curve->b || | 832 | return 0; |
838 | !params->curve->b->data) { | ||
839 | ECerror(EC_R_ASN1_ERROR); | ||
840 | goto err; | ||
841 | } | 833 | } |
842 | a = BN_bin2bn(params->curve->a->data, params->curve->a->length, NULL); | 834 | if (nid == NID_X9_62_characteristic_two_field) { |
843 | if (a == NULL) { | 835 | ECerror(EC_R_GF2M_NOT_SUPPORTED); |
844 | ECerror(ERR_R_BN_LIB); | 836 | return 0; |
845 | goto err; | ||
846 | } | 837 | } |
847 | b = BN_bin2bn(params->curve->b->data, params->curve->b->length, NULL); | 838 | if (nid != NID_X9_62_prime_field) { |
848 | if (b == NULL) { | 839 | ECerror(EC_R_UNSUPPORTED_FIELD); |
849 | ECerror(ERR_R_BN_LIB); | 840 | return 0; |
850 | goto err; | ||
851 | } | 841 | } |
852 | /* get the field parameters */ | 842 | |
853 | tmp = OBJ_obj2nid(params->fieldID->fieldType); | 843 | /* We can't check that this is actually a prime due to DoS risk. */ |
854 | if (tmp == NID_X9_62_characteristic_two_field) { | 844 | if (fieldid->p.prime == NULL) { |
855 | ECerror(EC_R_GF2M_NOT_SUPPORTED); | ||
856 | goto err; | ||
857 | } else if (tmp == NID_X9_62_prime_field) { | ||
858 | /* we have a curve over a prime field */ | ||
859 | /* extract the prime number */ | ||
860 | if (!params->fieldID->p.prime) { | ||
861 | ECerror(EC_R_ASN1_ERROR); | ||
862 | goto err; | ||
863 | } | ||
864 | p = ASN1_INTEGER_to_BN(params->fieldID->p.prime, NULL); | ||
865 | if (p == NULL) { | ||
866 | ECerror(ERR_R_ASN1_LIB); | ||
867 | goto err; | ||
868 | } | ||
869 | if (BN_is_negative(p) || BN_is_zero(p)) { | ||
870 | ECerror(EC_R_INVALID_FIELD); | ||
871 | goto err; | ||
872 | } | ||
873 | field_bits = BN_num_bits(p); | ||
874 | if (field_bits > OPENSSL_ECC_MAX_FIELD_BITS) { | ||
875 | ECerror(EC_R_FIELD_TOO_LARGE); | ||
876 | goto err; | ||
877 | } | ||
878 | /* create the EC_GROUP structure */ | ||
879 | ret = EC_GROUP_new_curve_GFp(p, a, b, NULL); | ||
880 | } else { | ||
881 | ECerror(EC_R_INVALID_FIELD); | 845 | ECerror(EC_R_INVALID_FIELD); |
882 | goto err; | 846 | return 0; |
883 | } | 847 | } |
884 | 848 | ||
885 | if (ret == NULL) { | 849 | return 1; |
886 | ECerror(ERR_R_EC_LIB); | 850 | } |
851 | |||
852 | static int | ||
853 | ec_asn1_parameters_curve2group(const X9_62_CURVE *curve, | ||
854 | const ASN1_INTEGER *prime, EC_GROUP **out_group) | ||
855 | { | ||
856 | EC_GROUP *group = NULL; | ||
857 | BIGNUM *p = NULL, *a = NULL, *b = NULL; | ||
858 | int ret = 0; | ||
859 | |||
860 | if (*out_group != NULL) | ||
861 | goto err; | ||
862 | |||
863 | if ((p = ASN1_INTEGER_to_BN(prime, NULL)) == NULL) | ||
864 | goto err; | ||
865 | if ((a = BN_bin2bn(curve->a->data, curve->a->length, NULL)) == NULL) | ||
866 | goto err; | ||
867 | if ((b = BN_bin2bn(curve->b->data, curve->b->length, NULL)) == NULL) | ||
868 | goto err; | ||
869 | |||
870 | /* | ||
871 | * XXX - move these checks to ec_GFp_simple_group_set_curve()? | ||
872 | * What about checking 0 <= a, b < p? | ||
873 | */ | ||
874 | if (BN_is_zero(p) || BN_is_negative(p)) { | ||
875 | ECerror(EC_R_INVALID_FIELD); | ||
887 | goto err; | 876 | goto err; |
888 | } | 877 | } |
889 | /* extract seed (optional) */ | 878 | if (BN_num_bits(p) > OPENSSL_ECC_MAX_FIELD_BITS) { |
890 | if (params->curve->seed != NULL) { | 879 | ECerror(EC_R_FIELD_TOO_LARGE); |
891 | free(ret->seed); | ||
892 | if (!(ret->seed = malloc(params->curve->seed->length))) { | ||
893 | ECerror(ERR_R_MALLOC_FAILURE); | ||
894 | goto err; | ||
895 | } | ||
896 | memcpy(ret->seed, params->curve->seed->data, | ||
897 | params->curve->seed->length); | ||
898 | ret->seed_len = params->curve->seed->length; | ||
899 | } | ||
900 | if (!params->order || !params->base || !params->base->data) { | ||
901 | ECerror(EC_R_ASN1_ERROR); | ||
902 | goto err; | 880 | goto err; |
903 | } | 881 | } |
904 | if ((point = EC_POINT_new(ret)) == NULL) | 882 | |
883 | if ((group = EC_GROUP_new_curve_GFp(p, a, b, NULL)) == NULL) | ||
905 | goto err; | 884 | goto err; |
906 | 885 | ||
907 | /* set the point conversion form */ | 886 | *out_group = group; |
908 | EC_GROUP_set_point_conversion_form(ret, (point_conversion_form_t) | 887 | group = NULL; |
909 | (params->base->data[0] & ~0x01)); | 888 | |
889 | ret = 1; | ||
890 | |||
891 | err: | ||
892 | BN_free(p); | ||
893 | BN_free(a); | ||
894 | BN_free(b); | ||
895 | EC_GROUP_free(group); | ||
896 | |||
897 | return ret; | ||
898 | } | ||
910 | 899 | ||
911 | /* extract the ec point */ | 900 | static int |
912 | if (!EC_POINT_oct2point(ret, point, params->base->data, | 901 | ec_asn1_set_group_parameters(const ECPARAMETERS *params, EC_GROUP *group) |
913 | params->base->length, NULL)) { | 902 | { |
903 | EC_POINT *generator; | ||
904 | BIGNUM *order = NULL, *cofactor = NULL; | ||
905 | const ASN1_BIT_STRING *seed; | ||
906 | point_conversion_form_t form; | ||
907 | int ret = 0; | ||
908 | |||
909 | if ((generator = EC_POINT_new(group)) == NULL) | ||
910 | goto err; | ||
911 | if (!EC_POINT_oct2point(group, generator, | ||
912 | params->base->data, params->base->length, NULL)) { | ||
914 | ECerror(ERR_R_EC_LIB); | 913 | ECerror(ERR_R_EC_LIB); |
915 | goto err; | 914 | goto err; |
916 | } | 915 | } |
@@ -918,14 +917,6 @@ ec_asn1_parameters2group(const ECPARAMETERS *params) | |||
918 | ECerror(ERR_R_ASN1_LIB); | 917 | ECerror(ERR_R_ASN1_LIB); |
919 | goto err; | 918 | goto err; |
920 | } | 919 | } |
921 | if (BN_is_negative(order) || BN_is_zero(order)) { | ||
922 | ECerror(EC_R_INVALID_GROUP_ORDER); | ||
923 | goto err; | ||
924 | } | ||
925 | if (BN_num_bits(order) > field_bits + 1) { /* Hasse bound */ | ||
926 | ECerror(EC_R_INVALID_GROUP_ORDER); | ||
927 | goto err; | ||
928 | } | ||
929 | if (params->cofactor != NULL) { | 920 | if (params->cofactor != NULL) { |
930 | if ((cofactor = ASN1_INTEGER_to_BN(params->cofactor, | 921 | if ((cofactor = ASN1_INTEGER_to_BN(params->cofactor, |
931 | NULL)) == NULL) { | 922 | NULL)) == NULL) { |
@@ -933,27 +924,84 @@ ec_asn1_parameters2group(const ECPARAMETERS *params) | |||
933 | goto err; | 924 | goto err; |
934 | } | 925 | } |
935 | } | 926 | } |
936 | if (!EC_GROUP_set_generator(ret, point, order, cofactor)) { | 927 | |
928 | /* Checks the Hasse bound and sets the cofactor if possible or fails. */ | ||
929 | if (!EC_GROUP_set_generator(group, generator, order, cofactor)) { | ||
937 | ECerror(ERR_R_EC_LIB); | 930 | ECerror(ERR_R_EC_LIB); |
938 | goto err; | 931 | goto err; |
939 | } | 932 | } |
940 | ok = 1; | ||
941 | 933 | ||
942 | err: | 934 | if ((seed = params->curve->seed) != NULL) { |
943 | if (!ok) { | 935 | if (EC_GROUP_set_seed(group, seed->data, seed->length) == 0) { |
944 | EC_GROUP_free(ret); | 936 | ECerror(ERR_R_MALLOC_FAILURE); |
945 | ret = NULL; | 937 | goto err; |
938 | } | ||
946 | } | 939 | } |
947 | BN_free(p); | 940 | |
948 | BN_free(a); | 941 | /* oct2point has ensured that to be compressed, uncompressed, or hybrid. */ |
949 | BN_free(b); | 942 | form = params->base->data[0] & ~1U; |
943 | EC_GROUP_set_point_conversion_form(group, form); | ||
944 | |||
945 | ret = 1; | ||
946 | |||
947 | err: | ||
948 | EC_POINT_free(generator); | ||
950 | BN_free(order); | 949 | BN_free(order); |
951 | BN_free(cofactor); | 950 | BN_free(cofactor); |
952 | EC_POINT_free(point); | ||
953 | 951 | ||
954 | return ret; | 952 | return ret; |
955 | } | 953 | } |
956 | 954 | ||
955 | static int | ||
956 | ec_asn1_parameters_extract_prime_group(const ECPARAMETERS *params, | ||
957 | EC_GROUP **out_group) | ||
958 | { | ||
959 | EC_GROUP *group = NULL; | ||
960 | int ret = 0; | ||
961 | |||
962 | if (*out_group != NULL) | ||
963 | goto err; | ||
964 | |||
965 | if (!ec_asn1_is_prime_field(params->fieldID)) | ||
966 | goto err; | ||
967 | if (!ec_asn1_parameters_curve2group(params->curve, | ||
968 | params->fieldID->p.prime, &group)) | ||
969 | goto err; | ||
970 | if (!ec_asn1_set_group_parameters(params, group)) | ||
971 | goto err; | ||
972 | |||
973 | *out_group = group; | ||
974 | group = NULL; | ||
975 | |||
976 | ret = 1; | ||
977 | |||
978 | err: | ||
979 | EC_GROUP_free(group); | ||
980 | |||
981 | return ret; | ||
982 | } | ||
983 | |||
984 | static EC_GROUP * | ||
985 | ec_asn1_parameters2group(const ECPARAMETERS *params) | ||
986 | { | ||
987 | EC_GROUP *group = NULL; | ||
988 | |||
989 | if (params == NULL) { | ||
990 | ECerror(EC_R_ASN1_ERROR); | ||
991 | goto err; | ||
992 | } | ||
993 | |||
994 | if (!ec_asn1_parameters_extract_prime_group(params, &group)) | ||
995 | goto err; | ||
996 | |||
997 | return group; | ||
998 | |||
999 | err: | ||
1000 | EC_GROUP_free(group); | ||
1001 | |||
1002 | return NULL; | ||
1003 | } | ||
1004 | |||
957 | EC_GROUP * | 1005 | EC_GROUP * |
958 | ec_asn1_pkparameters2group(const ECPKPARAMETERS *params) | 1006 | ec_asn1_pkparameters2group(const ECPKPARAMETERS *params) |
959 | { | 1007 | { |