diff options
Diffstat (limited to 'src/lib/libcrypto/ec/ecp_smpl.c')
| -rw-r--r-- | src/lib/libcrypto/ec/ecp_smpl.c | 379 |
1 files changed, 369 insertions, 10 deletions
diff --git a/src/lib/libcrypto/ec/ecp_smpl.c b/src/lib/libcrypto/ec/ecp_smpl.c index 7cbb321f9a..66a92e2a90 100644 --- a/src/lib/libcrypto/ec/ecp_smpl.c +++ b/src/lib/libcrypto/ec/ecp_smpl.c | |||
| @@ -65,19 +65,11 @@ | |||
| 65 | #include <openssl/err.h> | 65 | #include <openssl/err.h> |
| 66 | #include <openssl/symhacks.h> | 66 | #include <openssl/symhacks.h> |
| 67 | 67 | ||
| 68 | #ifdef OPENSSL_FIPS | ||
| 69 | #include <openssl/fips.h> | ||
| 70 | #endif | ||
| 71 | |||
| 72 | #include "ec_lcl.h" | 68 | #include "ec_lcl.h" |
| 73 | 69 | ||
| 74 | const EC_METHOD *EC_GFp_simple_method(void) | 70 | const EC_METHOD *EC_GFp_simple_method(void) |
| 75 | { | 71 | { |
| 76 | #ifdef OPENSSL_FIPS | ||
| 77 | return fips_ec_gfp_simple_method(); | ||
| 78 | #else | ||
| 79 | static const EC_METHOD ret = { | 72 | static const EC_METHOD ret = { |
| 80 | EC_FLAGS_DEFAULT_OCT, | ||
| 81 | NID_X9_62_prime_field, | 73 | NID_X9_62_prime_field, |
| 82 | ec_GFp_simple_group_init, | 74 | ec_GFp_simple_group_init, |
| 83 | ec_GFp_simple_group_finish, | 75 | ec_GFp_simple_group_finish, |
| @@ -96,7 +88,9 @@ const EC_METHOD *EC_GFp_simple_method(void) | |||
| 96 | ec_GFp_simple_get_Jprojective_coordinates_GFp, | 88 | ec_GFp_simple_get_Jprojective_coordinates_GFp, |
| 97 | ec_GFp_simple_point_set_affine_coordinates, | 89 | ec_GFp_simple_point_set_affine_coordinates, |
| 98 | ec_GFp_simple_point_get_affine_coordinates, | 90 | ec_GFp_simple_point_get_affine_coordinates, |
| 99 | 0,0,0, | 91 | ec_GFp_simple_set_compressed_coordinates, |
| 92 | ec_GFp_simple_point2oct, | ||
| 93 | ec_GFp_simple_oct2point, | ||
| 100 | ec_GFp_simple_add, | 94 | ec_GFp_simple_add, |
| 101 | ec_GFp_simple_dbl, | 95 | ec_GFp_simple_dbl, |
| 102 | ec_GFp_simple_invert, | 96 | ec_GFp_simple_invert, |
| @@ -116,7 +110,6 @@ const EC_METHOD *EC_GFp_simple_method(void) | |||
| 116 | 0 /* field_set_to_one */ }; | 110 | 0 /* field_set_to_one */ }; |
| 117 | 111 | ||
| 118 | return &ret; | 112 | return &ret; |
| 119 | #endif | ||
| 120 | } | 113 | } |
| 121 | 114 | ||
| 122 | 115 | ||
| @@ -640,6 +633,372 @@ int ec_GFp_simple_point_get_affine_coordinates(const EC_GROUP *group, const EC_P | |||
| 640 | return ret; | 633 | return ret; |
| 641 | } | 634 | } |
| 642 | 635 | ||
| 636 | |||
| 637 | int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group, EC_POINT *point, | ||
| 638 | const BIGNUM *x_, int y_bit, BN_CTX *ctx) | ||
| 639 | { | ||
| 640 | BN_CTX *new_ctx = NULL; | ||
| 641 | BIGNUM *tmp1, *tmp2, *x, *y; | ||
| 642 | int ret = 0; | ||
| 643 | |||
| 644 | /* clear error queue*/ | ||
| 645 | ERR_clear_error(); | ||
| 646 | |||
| 647 | if (ctx == NULL) | ||
| 648 | { | ||
| 649 | ctx = new_ctx = BN_CTX_new(); | ||
| 650 | if (ctx == NULL) | ||
| 651 | return 0; | ||
| 652 | } | ||
| 653 | |||
| 654 | y_bit = (y_bit != 0); | ||
| 655 | |||
| 656 | BN_CTX_start(ctx); | ||
| 657 | tmp1 = BN_CTX_get(ctx); | ||
| 658 | tmp2 = BN_CTX_get(ctx); | ||
| 659 | x = BN_CTX_get(ctx); | ||
| 660 | y = BN_CTX_get(ctx); | ||
| 661 | if (y == NULL) goto err; | ||
| 662 | |||
| 663 | /* Recover y. We have a Weierstrass equation | ||
| 664 | * y^2 = x^3 + a*x + b, | ||
| 665 | * so y is one of the square roots of x^3 + a*x + b. | ||
| 666 | */ | ||
| 667 | |||
| 668 | /* tmp1 := x^3 */ | ||
| 669 | if (!BN_nnmod(x, x_, &group->field,ctx)) goto err; | ||
| 670 | if (group->meth->field_decode == 0) | ||
| 671 | { | ||
| 672 | /* field_{sqr,mul} work on standard representation */ | ||
| 673 | if (!group->meth->field_sqr(group, tmp2, x_, ctx)) goto err; | ||
| 674 | if (!group->meth->field_mul(group, tmp1, tmp2, x_, ctx)) goto err; | ||
| 675 | } | ||
| 676 | else | ||
| 677 | { | ||
| 678 | if (!BN_mod_sqr(tmp2, x_, &group->field, ctx)) goto err; | ||
| 679 | if (!BN_mod_mul(tmp1, tmp2, x_, &group->field, ctx)) goto err; | ||
| 680 | } | ||
| 681 | |||
| 682 | /* tmp1 := tmp1 + a*x */ | ||
| 683 | if (group->a_is_minus3) | ||
| 684 | { | ||
| 685 | if (!BN_mod_lshift1_quick(tmp2, x, &group->field)) goto err; | ||
| 686 | if (!BN_mod_add_quick(tmp2, tmp2, x, &group->field)) goto err; | ||
| 687 | if (!BN_mod_sub_quick(tmp1, tmp1, tmp2, &group->field)) goto err; | ||
| 688 | } | ||
| 689 | else | ||
| 690 | { | ||
| 691 | if (group->meth->field_decode) | ||
| 692 | { | ||
| 693 | if (!group->meth->field_decode(group, tmp2, &group->a, ctx)) goto err; | ||
| 694 | if (!BN_mod_mul(tmp2, tmp2, x, &group->field, ctx)) goto err; | ||
| 695 | } | ||
| 696 | else | ||
| 697 | { | ||
| 698 | /* field_mul works on standard representation */ | ||
| 699 | if (!group->meth->field_mul(group, tmp2, &group->a, x, ctx)) goto err; | ||
| 700 | } | ||
| 701 | |||
| 702 | if (!BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) goto err; | ||
| 703 | } | ||
| 704 | |||
| 705 | /* tmp1 := tmp1 + b */ | ||
| 706 | if (group->meth->field_decode) | ||
| 707 | { | ||
| 708 | if (!group->meth->field_decode(group, tmp2, &group->b, ctx)) goto err; | ||
| 709 | if (!BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) goto err; | ||
| 710 | } | ||
| 711 | else | ||
| 712 | { | ||
| 713 | if (!BN_mod_add_quick(tmp1, tmp1, &group->b, &group->field)) goto err; | ||
| 714 | } | ||
| 715 | |||
| 716 | if (!BN_mod_sqrt(y, tmp1, &group->field, ctx)) | ||
| 717 | { | ||
| 718 | unsigned long err = ERR_peek_last_error(); | ||
| 719 | |||
| 720 | if (ERR_GET_LIB(err) == ERR_LIB_BN && ERR_GET_REASON(err) == BN_R_NOT_A_SQUARE) | ||
| 721 | { | ||
| 722 | ERR_clear_error(); | ||
| 723 | ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, EC_R_INVALID_COMPRESSED_POINT); | ||
| 724 | } | ||
| 725 | else | ||
| 726 | ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, ERR_R_BN_LIB); | ||
| 727 | goto err; | ||
| 728 | } | ||
| 729 | |||
| 730 | if (y_bit != BN_is_odd(y)) | ||
| 731 | { | ||
| 732 | if (BN_is_zero(y)) | ||
| 733 | { | ||
| 734 | int kron; | ||
| 735 | |||
| 736 | kron = BN_kronecker(x, &group->field, ctx); | ||
| 737 | if (kron == -2) goto err; | ||
| 738 | |||
| 739 | if (kron == 1) | ||
| 740 | ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, EC_R_INVALID_COMPRESSION_BIT); | ||
| 741 | else | ||
| 742 | /* BN_mod_sqrt() should have cought this error (not a square) */ | ||
| 743 | ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, EC_R_INVALID_COMPRESSED_POINT); | ||
| 744 | goto err; | ||
| 745 | } | ||
| 746 | if (!BN_usub(y, &group->field, y)) goto err; | ||
| 747 | } | ||
| 748 | if (y_bit != BN_is_odd(y)) | ||
| 749 | { | ||
| 750 | ECerr(EC_F_EC_GFP_SIMPLE_SET_COMPRESSED_COORDINATES, ERR_R_INTERNAL_ERROR); | ||
| 751 | goto err; | ||
| 752 | } | ||
| 753 | |||
| 754 | if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) goto err; | ||
| 755 | |||
| 756 | ret = 1; | ||
| 757 | |||
| 758 | err: | ||
| 759 | BN_CTX_end(ctx); | ||
| 760 | if (new_ctx != NULL) | ||
| 761 | BN_CTX_free(new_ctx); | ||
| 762 | return ret; | ||
| 763 | } | ||
| 764 | |||
| 765 | |||
| 766 | size_t ec_GFp_simple_point2oct(const EC_GROUP *group, const EC_POINT *point, point_conversion_form_t form, | ||
| 767 | unsigned char *buf, size_t len, BN_CTX *ctx) | ||
| 768 | { | ||
| 769 | size_t ret; | ||
| 770 | BN_CTX *new_ctx = NULL; | ||
| 771 | int used_ctx = 0; | ||
| 772 | BIGNUM *x, *y; | ||
| 773 | size_t field_len, i, skip; | ||
| 774 | |||
| 775 | if ((form != POINT_CONVERSION_COMPRESSED) | ||
| 776 | && (form != POINT_CONVERSION_UNCOMPRESSED) | ||
| 777 | && (form != POINT_CONVERSION_HYBRID)) | ||
| 778 | { | ||
| 779 | ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, EC_R_INVALID_FORM); | ||
| 780 | goto err; | ||
| 781 | } | ||
| 782 | |||
| 783 | if (EC_POINT_is_at_infinity(group, point)) | ||
| 784 | { | ||
| 785 | /* encodes to a single 0 octet */ | ||
| 786 | if (buf != NULL) | ||
| 787 | { | ||
| 788 | if (len < 1) | ||
| 789 | { | ||
| 790 | ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, EC_R_BUFFER_TOO_SMALL); | ||
| 791 | return 0; | ||
| 792 | } | ||
| 793 | buf[0] = 0; | ||
| 794 | } | ||
| 795 | return 1; | ||
| 796 | } | ||
| 797 | |||
| 798 | |||
| 799 | /* ret := required output buffer length */ | ||
| 800 | field_len = BN_num_bytes(&group->field); | ||
| 801 | ret = (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2*field_len; | ||
| 802 | |||
| 803 | /* if 'buf' is NULL, just return required length */ | ||
| 804 | if (buf != NULL) | ||
| 805 | { | ||
| 806 | if (len < ret) | ||
| 807 | { | ||
| 808 | ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, EC_R_BUFFER_TOO_SMALL); | ||
| 809 | goto err; | ||
| 810 | } | ||
| 811 | |||
| 812 | if (ctx == NULL) | ||
| 813 | { | ||
| 814 | ctx = new_ctx = BN_CTX_new(); | ||
| 815 | if (ctx == NULL) | ||
| 816 | return 0; | ||
| 817 | } | ||
| 818 | |||
| 819 | BN_CTX_start(ctx); | ||
| 820 | used_ctx = 1; | ||
| 821 | x = BN_CTX_get(ctx); | ||
| 822 | y = BN_CTX_get(ctx); | ||
| 823 | if (y == NULL) goto err; | ||
| 824 | |||
| 825 | if (!EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx)) goto err; | ||
| 826 | |||
| 827 | if ((form == POINT_CONVERSION_COMPRESSED || form == POINT_CONVERSION_HYBRID) && BN_is_odd(y)) | ||
| 828 | buf[0] = form + 1; | ||
| 829 | else | ||
| 830 | buf[0] = form; | ||
| 831 | |||
| 832 | i = 1; | ||
| 833 | |||
| 834 | skip = field_len - BN_num_bytes(x); | ||
| 835 | if (skip > field_len) | ||
| 836 | { | ||
| 837 | ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR); | ||
| 838 | goto err; | ||
| 839 | } | ||
| 840 | while (skip > 0) | ||
| 841 | { | ||
| 842 | buf[i++] = 0; | ||
| 843 | skip--; | ||
| 844 | } | ||
| 845 | skip = BN_bn2bin(x, buf + i); | ||
| 846 | i += skip; | ||
| 847 | if (i != 1 + field_len) | ||
| 848 | { | ||
| 849 | ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR); | ||
| 850 | goto err; | ||
| 851 | } | ||
| 852 | |||
| 853 | if (form == POINT_CONVERSION_UNCOMPRESSED || form == POINT_CONVERSION_HYBRID) | ||
| 854 | { | ||
| 855 | skip = field_len - BN_num_bytes(y); | ||
| 856 | if (skip > field_len) | ||
| 857 | { | ||
| 858 | ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR); | ||
| 859 | goto err; | ||
| 860 | } | ||
| 861 | while (skip > 0) | ||
| 862 | { | ||
| 863 | buf[i++] = 0; | ||
| 864 | skip--; | ||
| 865 | } | ||
| 866 | skip = BN_bn2bin(y, buf + i); | ||
| 867 | i += skip; | ||
| 868 | } | ||
| 869 | |||
| 870 | if (i != ret) | ||
| 871 | { | ||
| 872 | ECerr(EC_F_EC_GFP_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR); | ||
| 873 | goto err; | ||
| 874 | } | ||
| 875 | } | ||
| 876 | |||
| 877 | if (used_ctx) | ||
| 878 | BN_CTX_end(ctx); | ||
| 879 | if (new_ctx != NULL) | ||
| 880 | BN_CTX_free(new_ctx); | ||
| 881 | return ret; | ||
| 882 | |||
| 883 | err: | ||
| 884 | if (used_ctx) | ||
| 885 | BN_CTX_end(ctx); | ||
| 886 | if (new_ctx != NULL) | ||
| 887 | BN_CTX_free(new_ctx); | ||
| 888 | return 0; | ||
| 889 | } | ||
| 890 | |||
| 891 | |||
| 892 | int ec_GFp_simple_oct2point(const EC_GROUP *group, EC_POINT *point, | ||
| 893 | const unsigned char *buf, size_t len, BN_CTX *ctx) | ||
| 894 | { | ||
| 895 | point_conversion_form_t form; | ||
| 896 | int y_bit; | ||
| 897 | BN_CTX *new_ctx = NULL; | ||
| 898 | BIGNUM *x, *y; | ||
| 899 | size_t field_len, enc_len; | ||
| 900 | int ret = 0; | ||
| 901 | |||
| 902 | if (len == 0) | ||
| 903 | { | ||
| 904 | ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_BUFFER_TOO_SMALL); | ||
| 905 | return 0; | ||
| 906 | } | ||
| 907 | form = buf[0]; | ||
| 908 | y_bit = form & 1; | ||
| 909 | form = form & ~1U; | ||
| 910 | if ((form != 0) && (form != POINT_CONVERSION_COMPRESSED) | ||
| 911 | && (form != POINT_CONVERSION_UNCOMPRESSED) | ||
| 912 | && (form != POINT_CONVERSION_HYBRID)) | ||
| 913 | { | ||
| 914 | ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING); | ||
| 915 | return 0; | ||
| 916 | } | ||
| 917 | if ((form == 0 || form == POINT_CONVERSION_UNCOMPRESSED) && y_bit) | ||
| 918 | { | ||
| 919 | ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING); | ||
| 920 | return 0; | ||
| 921 | } | ||
| 922 | |||
| 923 | if (form == 0) | ||
| 924 | { | ||
| 925 | if (len != 1) | ||
| 926 | { | ||
| 927 | ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING); | ||
| 928 | return 0; | ||
| 929 | } | ||
| 930 | |||
| 931 | return EC_POINT_set_to_infinity(group, point); | ||
| 932 | } | ||
| 933 | |||
| 934 | field_len = BN_num_bytes(&group->field); | ||
| 935 | enc_len = (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2*field_len; | ||
| 936 | |||
| 937 | if (len != enc_len) | ||
| 938 | { | ||
| 939 | ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING); | ||
| 940 | return 0; | ||
| 941 | } | ||
| 942 | |||
| 943 | if (ctx == NULL) | ||
| 944 | { | ||
| 945 | ctx = new_ctx = BN_CTX_new(); | ||
| 946 | if (ctx == NULL) | ||
| 947 | return 0; | ||
| 948 | } | ||
| 949 | |||
| 950 | BN_CTX_start(ctx); | ||
| 951 | x = BN_CTX_get(ctx); | ||
| 952 | y = BN_CTX_get(ctx); | ||
| 953 | if (y == NULL) goto err; | ||
| 954 | |||
| 955 | if (!BN_bin2bn(buf + 1, field_len, x)) goto err; | ||
| 956 | if (BN_ucmp(x, &group->field) >= 0) | ||
| 957 | { | ||
| 958 | ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING); | ||
| 959 | goto err; | ||
| 960 | } | ||
| 961 | |||
| 962 | if (form == POINT_CONVERSION_COMPRESSED) | ||
| 963 | { | ||
| 964 | if (!EC_POINT_set_compressed_coordinates_GFp(group, point, x, y_bit, ctx)) goto err; | ||
| 965 | } | ||
| 966 | else | ||
| 967 | { | ||
| 968 | if (!BN_bin2bn(buf + 1 + field_len, field_len, y)) goto err; | ||
| 969 | if (BN_ucmp(y, &group->field) >= 0) | ||
| 970 | { | ||
| 971 | ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING); | ||
| 972 | goto err; | ||
| 973 | } | ||
| 974 | if (form == POINT_CONVERSION_HYBRID) | ||
| 975 | { | ||
| 976 | if (y_bit != BN_is_odd(y)) | ||
| 977 | { | ||
| 978 | ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING); | ||
| 979 | goto err; | ||
| 980 | } | ||
| 981 | } | ||
| 982 | |||
| 983 | if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) goto err; | ||
| 984 | } | ||
| 985 | |||
| 986 | if (!EC_POINT_is_on_curve(group, point, ctx)) /* test required by X9.62 */ | ||
| 987 | { | ||
| 988 | ECerr(EC_F_EC_GFP_SIMPLE_OCT2POINT, EC_R_POINT_IS_NOT_ON_CURVE); | ||
| 989 | goto err; | ||
| 990 | } | ||
| 991 | |||
| 992 | ret = 1; | ||
| 993 | |||
| 994 | err: | ||
| 995 | BN_CTX_end(ctx); | ||
| 996 | if (new_ctx != NULL) | ||
| 997 | BN_CTX_free(new_ctx); | ||
| 998 | return ret; | ||
| 999 | } | ||
| 1000 | |||
| 1001 | |||
| 643 | int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx) | 1002 | int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx) |
| 644 | { | 1003 | { |
| 645 | int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); | 1004 | int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); |
