Index: openssl-1.1.1d/crypto/ec/ecx_meth.c =================================================================== --- openssl-1.1.1d.orig/crypto/ec/ecx_meth.c +++ openssl-1.1.1d/crypto/ec/ecx_meth.c @@ -842,6 +842,7 @@ static const EVP_PKEY_METHOD ed448_pkey_ #ifdef S390X_EC_ASM # include "s390x_arch.h" +# include "internal/constant_time.h" static void s390x_x25519_mod_p(unsigned char u[32]) { @@ -855,16 +856,16 @@ static void s390x_x25519_mod_p(unsigned u_red[31] = (unsigned char)c; c >>= 8; - for (i = 30; c > 0 && i >= 0; i--) { + for (i = 30; i >= 0; i--) { c += (unsigned int)u_red[i]; u_red[i] = (unsigned char)c; c >>= 8; } - if (u_red[0] & 0x80) { - u_red[0] &= 0x7f; - memcpy(u, u_red, sizeof(u_red)); - } + c = (u_red[0] & 0x80) >> 7; + u_red[0] &= 0x7f; + constant_time_cond_swap_buff(0 - (unsigned char)c, + u, u_red, sizeof(u_red)); } static void s390x_x448_mod_p(unsigned char u[56]) @@ -889,16 +890,14 @@ static void s390x_x448_mod_p(unsigned ch u_red[27] = (unsigned char)c; c >>= 8; - for (i = 26; c > 0 && i >= 0; i--) { + for (i = 26; i >= 0; i--) { c += (unsigned int)u_red[i]; u_red[i] = (unsigned char)c; c >>= 8; } - if (u_red[0] & 0x80) { - u_red[0] &= 0x7f; - memcpy(u, u_red, sizeof(u_red)); - } + constant_time_cond_swap_buff(0 - (unsigned char)c, + u, u_red, sizeof(u_red)); } static int s390x_x25519_mul(unsigned char u_dst[32], @@ -954,7 +953,7 @@ static int s390x_x448_mul(unsigned char memcpy(param.x448.d_src, d_src, 56); s390x_flip_endian64(param.x448.u_src, param.x448.u_src); - s390x_x448_mod_p(param.x448.u_src); + s390x_x448_mod_p(param.x448.u_src + 8); s390x_flip_endian64(param.x448.d_src, param.x448.d_src); param.x448.d_src[63] &= 252; Index: openssl-1.1.1d/include/internal/constant_timeh =================================================================== --- openssl-1.1.1d.orig/include/internal/constant_time.h +++ openssl-1.1.1d/include/internal/constant_time.h @@ -353,6 +353,34 @@ static ossl_inline void constant_time_co } /* + * mask must be 0xFF or 0x00. + * "constant time" is per len. + * + * if (mask) { + * unsigned char tmp[len]; + * + * memcpy(tmp, a, len); + * memcpy(a, b); + * memcpy(b, tmp); + * } + */ +static ossl_inline void constant_time_cond_swap_buff(unsigned char mask, + unsigned char *a, + unsigned char *b, + size_t len) +{ + size_t i; + unsigned char tmp; + + for (i = 0; i < len; i++) { + tmp = a[i] ^ b[i]; + tmp &= mask; + a[i] ^= tmp; + b[i] ^= tmp; + } +} + +/* * table is a two dimensional array of bytes. Each row has rowsize elements. * Copies row number idx into out. rowsize and numrows are not considered * private. Index: openssl-1.1.1d/test/recipes/30-test_evp_data/evppkey.txt =================================================================== --- openssl-1.1.1d.orig/test/recipes/30-test_evp_data/evppkey.txt +++ openssl-1.1.1d/test/recipes/30-test_evp_data/evppkey.txt @@ -814,6 +814,8 @@ PublicKeyRaw=Bob-448-PUBLIC-Raw:X448:3eb PrivPubKeyPair = Bob-448-Raw:Bob-448-PUBLIC-Raw +PublicKeyRaw=Bob-448-PUBLIC-Raw-NonCanonical:X448:ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + Derive=Alice-448 PeerKey=Bob-448-PUBLIC SharedSecret=07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d @@ -830,6 +832,11 @@ Derive=Bob-448-Raw PeerKey=Alice-448-PUBLIC-Raw SharedSecret=07fff4181ac6cc95ec1c16a94a0f74d12da232ce40a77552281d282bb60c0b56fd2464c335543936521c24403085d59a449a5037514a879d +# Self-generated non-canonical +Derive=Alice-448-Raw +PeerKey=Bob-448-PUBLIC-Raw-NonCanonical +SharedSecret=66e2e682b1f8e68c809f1bb3e406bd826921d9c1a5bfbfcbab7ae72feecee63660eabd54934f3382061d17607f581a90bdac917a064959fb + # Illegal sign/verify operations with X448 key Sign=Alice-448