diff --git a/BUILD.gn b/BUILD.gn index 830956510a11086a9a7ffaa23f97e1699faf9ba4..8c02acb151d24af4c72d3076e21d41d8aefe27d0 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -306,6 +306,7 @@ ohos_source_set("crypto_source") { "crypto/bn/bn_srp.c", "crypto/bn/bn_word.c", "crypto/bn/bn_x931p.c", + "crypto/bn/rsa_sup_mul.c", "crypto/buffer/buf_err.c", "crypto/buffer/buffer.c", "crypto/cmac/cm_ameth.c", diff --git a/CHANGES b/CHANGES index 3ef3fa28cfa82ad7625c8b5d51ae5baae10c5a08..ff82b6957d9a28b8459b850b52faea85e3508f9c 100644 --- a/CHANGES +++ b/CHANGES @@ -7,6 +7,124 @@ https://github.com/openssl/openssl/commits/ and pick the appropriate release branch. + Changes between 1.1.1s and 1.1.1t [xx XXX xxxx] + + *) Fixed a type confusion vulnerability relating to X.400 address processing + inside an X.509 GeneralName. X.400 addresses were parsed as an ASN1_STRING + but subsequently interpreted by GENERAL_NAME_cmp as an ASN1_TYPE. This + vulnerability may allow an attacker who can provide a certificate chain and + CRL (neither of which need have a valid signature) to pass arbitrary + pointers to a memcmp call, creating a possible read primitive, subject to + some constraints. Refer to the advisory for more information. Thanks to + David Benjamin for discovering this issue. (CVE-2023-0286) + + This issue has been fixed by changing the public header file definition of + GENERAL_NAME so that x400Address reflects the implementation. It was not + possible for any existing application to successfully use the existing + definition; however, if any application references the x400Address field + (e.g. in dead code), note that the type of this field has changed. There is + no ABI change. + + [Hugo Landau] + + Changes between 1.1.1r and 1.1.1s [1 Nov 2022] + + *) Fixed a regression introduced in 1.1.1r version not refreshing the + certificate data to be signed before signing the certificate. + + [Gibeom Gwon] + + Changes between 1.1.1q and 1.1.1r [11 Oct 2022] + + *) Fixed the linux-mips64 Configure target which was missing the + SIXTY_FOUR_BIT bn_ops flag. This was causing heap corruption on that + platform. + [Adam Joseph] + + *) Fixed a strict aliasing problem in bn_nist. Clang-14 optimisation was + causing incorrect results in some cases as a result. + [Paul Dale] + + *) Fixed SSL_pending() and SSL_has_pending() with DTLS which were failing to + report correct results in some cases + [Matt Caswell] + + *) Fixed a regression introduced in 1.1.1o for re-signing certificates with + different key sizes + [Todd Short] + + *) Added the loongarch64 target + [Shi Pujin] + + *) Fixed a DRBG seed propagation thread safety issue + [Bernd Edlinger] + + *) Fixed a memory leak in tls13_generate_secret + [Bernd Edlinger] + + *) Fixed reported performance degradation on aarch64. Restored the + implementation prior to commit 2621751 ("aes/asm/aesv8-armx.pl: avoid + 32-bit lane assignment in CTR mode") for 64bit targets only, since it is + reportedly 2-17% slower and the silicon errata only affects 32bit targets. + The new algorithm is still used for 32 bit targets. + [Bernd Edlinger] + + *) Added a missing header for memcmp that caused compilation failure on some + platforms + [Gregor Jasny] + + Changes between 1.1.1p and 1.1.1q [5 Jul 2022] + + *) AES OCB mode for 32-bit x86 platforms using the AES-NI assembly optimised + implementation would not encrypt the entirety of the data under some + circumstances. This could reveal sixteen bytes of data that was + preexisting in the memory that wasn't written. In the special case of + "in place" encryption, sixteen bytes of the plaintext would be revealed. + + Since OpenSSL does not support OCB based cipher suites for TLS and DTLS, + they are both unaffected. + (CVE-2022-2097) + [Alex Chernyakhovsky, David Benjamin, Alejandro Sedeño] + + Changes between 1.1.1o and 1.1.1p [21 Jun 2022] + + *) In addition to the c_rehash shell command injection identified in + CVE-2022-1292, further bugs where the c_rehash script does not + properly sanitise shell metacharacters to prevent command injection have been + fixed. + + When the CVE-2022-1292 was fixed it was not discovered that there + are other places in the script where the file names of certificates + being hashed were possibly passed to a command executed through the shell. + + This script is distributed by some operating systems in a manner where + it is automatically executed. On such operating systems, an attacker + could execute arbitrary commands with the privileges of the script. + + Use of the c_rehash script is considered obsolete and should be replaced + by the OpenSSL rehash command line tool. + (CVE-2022-2068) + [Daniel Fiala, Tomáš Mráz] + + *) When OpenSSL TLS client is connecting without any supported elliptic + curves and TLS-1.3 protocol is disabled the connection will no longer fail + if a ciphersuite that does not use a key exchange based on elliptic + curves can be negotiated. + [Tomáš Mráz] + + Changes between 1.1.1n and 1.1.1o [3 May 2022] + + *) Fixed a bug in the c_rehash script which was not properly sanitising shell + metacharacters to prevent command injection. This script is distributed + by some operating systems in a manner where it is automatically executed. + On such operating systems, an attacker could execute arbitrary commands + with the privileges of the script. + + Use of the c_rehash script is considered obsolete and should be replaced + by the OpenSSL rehash command line tool. + (CVE-2022-1292) + [Tomáš Mráz] + Changes between 1.1.1m and 1.1.1n [15 Mar 2022] *) Fixed a bug in the BN_mod_sqrt() function that can cause it to loop forever diff --git a/crypto/asn1/bio_ndef.c b/crypto/asn1/bio_ndef.c index 760e4846a474499866f21a7bb7ce47aac9451e52..f8d4b1b9aa6703759667420c910b58b1ce2ef0de 100644 --- a/crypto/asn1/bio_ndef.c +++ b/crypto/asn1/bio_ndef.c @@ -49,12 +49,19 @@ static int ndef_suffix(BIO *b, unsigned char **pbuf, int *plen, void *parg); static int ndef_suffix_free(BIO *b, unsigned char **pbuf, int *plen, void *parg); +/* + * On success, the returned BIO owns the input BIO as part of its BIO chain. + * On failure, NULL is returned and the input BIO is owned by the caller. + * + * Unfortunately cannot constify this due to CMS_stream() and PKCS7_stream() + */ BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it) { NDEF_SUPPORT *ndef_aux = NULL; BIO *asn_bio = NULL; const ASN1_AUX *aux = it->funcs; ASN1_STREAM_ARG sarg; + BIO *pop_bio = NULL; if (!aux || !aux->asn1_cb) { ASN1err(ASN1_F_BIO_NEW_NDEF, ASN1_R_STREAMING_NOT_SUPPORTED); @@ -69,21 +76,39 @@ BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it) out = BIO_push(asn_bio, out); if (out == NULL) goto err; + pop_bio = asn_bio; - BIO_asn1_set_prefix(asn_bio, ndef_prefix, ndef_prefix_free); - BIO_asn1_set_suffix(asn_bio, ndef_suffix, ndef_suffix_free); + if (BIO_asn1_set_prefix(asn_bio, ndef_prefix, ndef_prefix_free) <= 0 + || BIO_asn1_set_suffix(asn_bio, ndef_suffix, ndef_suffix_free) <= 0 + || BIO_ctrl(asn_bio, BIO_C_SET_EX_ARG, 0, ndef_aux) <= 0) + goto err; /* - * Now let callback prepends any digest, cipher etc BIOs ASN1 structure - * needs. + * Now let the callback prepend any digest, cipher, etc., that the BIO's + * ASN1 structure needs. */ sarg.out = out; sarg.ndef_bio = NULL; sarg.boundary = NULL; - if (aux->asn1_cb(ASN1_OP_STREAM_PRE, &val, it, &sarg) <= 0) + /* + * The asn1_cb(), must not have mutated asn_bio on error, leaving it in the + * middle of some partially built, but not returned BIO chain. + */ + if (aux->asn1_cb(ASN1_OP_STREAM_PRE, &val, it, &sarg) <= 0) { + /* + * ndef_aux is now owned by asn_bio so we must not free it in the err + * clean up block + */ + ndef_aux = NULL; goto err; + } + + /* + * We must not fail now because the callback has prepended additional + * BIOs to the chain + */ ndef_aux->val = val; ndef_aux->it = it; @@ -91,11 +116,11 @@ BIO *BIO_new_NDEF(BIO *out, ASN1_VALUE *val, const ASN1_ITEM *it) ndef_aux->boundary = sarg.boundary; ndef_aux->out = out; - BIO_ctrl(asn_bio, BIO_C_SET_EX_ARG, 0, ndef_aux); - return sarg.ndef_bio; err: + /* BIO_pop() is NULL safe */ + (void)BIO_pop(pop_bio); BIO_free(asn_bio); OPENSSL_free(ndef_aux); return NULL; diff --git a/crypto/bn/bn_blind.c b/crypto/bn/bn_blind.c index 76fc7ebcffc0b78fed134ddf2f0688b8a904e0d6..6e9d2393211964d7a57f0d83f3042474677966a4 100644 --- a/crypto/bn/bn_blind.c +++ b/crypto/bn/bn_blind.c @@ -13,20 +13,6 @@ #define BN_BLINDING_COUNTER 32 -struct bn_blinding_st { - BIGNUM *A; - BIGNUM *Ai; - BIGNUM *e; - BIGNUM *mod; /* just a reference */ - CRYPTO_THREAD_ID tid; - int counter; - unsigned long flags; - BN_MONT_CTX *m_ctx; - int (*bn_mod_exp) (BIGNUM *r, const BIGNUM *a, const BIGNUM *p, - const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx); - CRYPTO_RWLOCK *lock; -}; - BN_BLINDING *BN_BLINDING_new(const BIGNUM *A, const BIGNUM *Ai, BIGNUM *mod) { BN_BLINDING *ret = NULL; diff --git a/crypto/bn/bn_err.c b/crypto/bn/bn_err.c index dd87c152cf375816c06498b56a4f9d8e53192295..3dd8d9a5682be3e271e89e84b815755780380f3d 100644 --- a/crypto/bn/bn_err.c +++ b/crypto/bn/bn_err.c @@ -73,6 +73,8 @@ static const ERR_STRING_DATA BN_str_functs[] = { {ERR_PACK(ERR_LIB_BN, BN_F_BN_SET_WORDS, 0), "bn_set_words"}, {ERR_PACK(ERR_LIB_BN, BN_F_BN_STACK_PUSH, 0), "BN_STACK_push"}, {ERR_PACK(ERR_LIB_BN, BN_F_BN_USUB, 0), "BN_usub"}, + {ERR_PACK(ERR_LIB_BN, BN_F_OSSL_BN_RSA_DO_UNBLIND, 0), + "ossl_bn_rsa_do_unblind"}, {0, NULL} }; diff --git a/crypto/bn/bn_local.h b/crypto/bn/bn_local.h index 8ad69ccd3639edd7331cc183f700540a14f0c145..096513533b704cccae74b48943a8a8ccef8ab90b 100644 --- a/crypto/bn/bn_local.h +++ b/crypto/bn/bn_local.h @@ -263,6 +263,20 @@ struct bn_gencb_st { } cb; }; +struct bn_blinding_st { + BIGNUM *A; + BIGNUM *Ai; + BIGNUM *e; + BIGNUM *mod; /* just a reference */ + CRYPTO_THREAD_ID tid; + int counter; + unsigned long flags; + BN_MONT_CTX *m_ctx; + int (*bn_mod_exp) (BIGNUM *r, const BIGNUM *a, const BIGNUM *p, + const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *m_ctx); + CRYPTO_RWLOCK *lock; +}; + /*- * BN_window_bits_for_exponent_size -- macro for sliding window mod_exp functions * diff --git a/crypto/bn/build.info b/crypto/bn/build.info index b9ed5322fa689bb9a812f0aead8e53d068f42629..c9fe2fdada69e7efe6834ef862445961ea6e7e07 100644 --- a/crypto/bn/build.info +++ b/crypto/bn/build.info @@ -5,7 +5,8 @@ SOURCE[../../libcrypto]=\ bn_kron.c bn_sqrt.c bn_gcd.c bn_prime.c bn_err.c bn_sqr.c \ {- $target{bn_asm_src} -} \ bn_recp.c bn_mont.c bn_mpi.c bn_exp2.c bn_gf2m.c bn_nist.c \ - bn_depr.c bn_const.c bn_x931p.c bn_intern.c bn_dh.c bn_srp.c + bn_depr.c bn_const.c bn_x931p.c bn_intern.c bn_dh.c bn_srp.c \ + rsa_sup_mul.c INCLUDE[bn_exp.o]=.. diff --git a/crypto/bn/rsa_sup_mul.c b/crypto/bn/rsa_sup_mul.c new file mode 100644 index 0000000000000000000000000000000000000000..acafefd5febf70e1996016b190a6c02dd7e327e1 --- /dev/null +++ b/crypto/bn/rsa_sup_mul.c @@ -0,0 +1,614 @@ +#include +#include +#include +#include +#include +#include +#include +#include "internal/numbers.h" +#include "internal/constant_time.h" +#include "bn_local.h" + +# if BN_BYTES == 8 +typedef uint64_t limb_t; +# if defined(__SIZEOF_INT128__) && __SIZEOF_INT128__ == 16 +/* nonstandard; implemented by gcc on 64-bit platforms */ +typedef __uint128_t limb2_t; +# define HAVE_LIMB2_T +# endif +# define LIMB_BIT_SIZE 64 +# define LIMB_BYTE_SIZE 8 +# elif BN_BYTES == 4 +typedef uint32_t limb_t; +typedef uint64_t limb2_t; +# define LIMB_BIT_SIZE 32 +# define LIMB_BYTE_SIZE 4 +# define HAVE_LIMB2_T +# else +# error "Not supported" +# endif + +/* + * For multiplication we're using schoolbook multiplication, + * so if we have two numbers, each with 6 "digits" (words) + * the multiplication is calculated as follows: + * A B C D E F + * x I J K L M N + * -------------- + * N*F + * N*E + * N*D + * N*C + * N*B + * N*A + * M*F + * M*E + * M*D + * M*C + * M*B + * M*A + * L*F + * L*E + * L*D + * L*C + * L*B + * L*A + * K*F + * K*E + * K*D + * K*C + * K*B + * K*A + * J*F + * J*E + * J*D + * J*C + * J*B + * J*A + * I*F + * I*E + * I*D + * I*C + * I*B + * + I*A + * ========================== + * N*B N*D N*F + * + N*A N*C N*E + * + M*B M*D M*F + * + M*A M*C M*E + * + L*B L*D L*F + * + L*A L*C L*E + * + K*B K*D K*F + * + K*A K*C K*E + * + J*B J*D J*F + * + J*A J*C J*E + * + I*B I*D I*F + * + I*A I*C I*E + * + * 1+1 1+3 1+5 + * 1+0 1+2 1+4 + * 0+1 0+3 0+5 + * 0+0 0+2 0+4 + * + * 0 1 2 3 4 5 6 + * which requires n^2 multiplications and 2n full length additions + * as we can keep every other result of limb multiplication in two separate + * limbs + */ + +#if defined HAVE_LIMB2_T +static ossl_inline void _mul_limb(limb_t *hi, limb_t *lo, limb_t a, limb_t b) +{ + limb2_t t; + /* + * this is idiomatic code to tell compiler to use the native mul + * those three lines will actually compile to single instruction + */ + + t = (limb2_t)a * b; + *hi = t >> LIMB_BIT_SIZE; + *lo = (limb_t)t; +} +#elif (BN_BYTES == 8) && (defined _MSC_VER) +/* https://learn.microsoft.com/en-us/cpp/intrinsics/umul128?view=msvc-170 */ +#pragma intrinsic(_umul128) +static ossl_inline void _mul_limb(limb_t *hi, limb_t *lo, limb_t a, limb_t b) +{ + *lo = _umul128(a, b, hi); +} +#else +/* + * if the compiler doesn't have either a 128bit data type nor a "return + * high 64 bits of multiplication" + */ +static ossl_inline void _mul_limb(limb_t *hi, limb_t *lo, limb_t a, limb_t b) +{ + limb_t a_low = (limb_t)(uint32_t)a; + limb_t a_hi = a >> 32; + limb_t b_low = (limb_t)(uint32_t)b; + limb_t b_hi = b >> 32; + + limb_t p0 = a_low * b_low; + limb_t p1 = a_low * b_hi; + limb_t p2 = a_hi * b_low; + limb_t p3 = a_hi * b_hi; + + uint32_t cy = (uint32_t)(((p0 >> 32) + (uint32_t)p1 + (uint32_t)p2) >> 32); + + *lo = p0 + (p1 << 32) + (p2 << 32); + *hi = p3 + (p1 >> 32) + (p2 >> 32) + cy; +} +#endif + +/* add two limbs with carry in, return carry out */ +static ossl_inline limb_t _add_limb(limb_t *ret, limb_t a, limb_t b, limb_t carry) +{ + limb_t carry1, carry2, t; + /* + * `c = a + b; if (c < a)` is idiomatic code that makes compilers + * use add with carry on assembly level + */ + + *ret = a + carry; + if (*ret < a) + carry1 = 1; + else + carry1 = 0; + + t = *ret; + *ret = t + b; + if (*ret < t) + carry2 = 1; + else + carry2 = 0; + + return carry1 + carry2; +} + +/* + * add two numbers of the same size, return overflow + * + * add a to b, place result in ret; all arrays need to be n limbs long + * return overflow from addition (0 or 1) + */ +static ossl_inline limb_t add(limb_t *ret, limb_t *a, limb_t *b, size_t n) +{ + limb_t c = 0; + ossl_ssize_t i; + + for(i = n - 1; i > -1; i--) + c = _add_limb(&ret[i], a[i], b[i], c); + + return c; +} + +/* + * return number of limbs necessary for temporary values + * when multiplying numbers n limbs large + */ +static ossl_inline size_t mul_limb_numb(size_t n) +{ + return 2 * n * 2; +} + +/* + * multiply two numbers of the same size + * + * multiply a by b, place result in ret; a and b need to be n limbs long + * ret needs to be 2*n limbs long, tmp needs to be mul_limb_numb(n) limbs + * long + */ +static void limb_mul(limb_t *ret, limb_t *a, limb_t *b, size_t n, limb_t *tmp) +{ + limb_t *r_odd, *r_even; + size_t i, j, k; + + r_odd = tmp; + r_even = &tmp[2 * n]; + + memset(ret, 0, 2 * n * sizeof(limb_t)); + + for (i = 0; i < n; i++) { + for (k = 0; k < i + n + 1; k++) { + r_even[k] = 0; + r_odd[k] = 0; + } + for (j = 0; j < n; j++) { + /* + * place results from even and odd limbs in separate arrays so that + * we don't have to calculate overflow every time we get individual + * limb multiplication result + */ + if (j % 2 == 0) + _mul_limb(&r_even[i + j], &r_even[i + j + 1], a[i], b[j]); + else + _mul_limb(&r_odd[i + j], &r_odd[i + j + 1], a[i], b[j]); + } + /* + * skip the least significant limbs when adding multiples of + * more significant limbs (they're zero anyway) + */ + add(ret, ret, r_even, n + i + 1); + add(ret, ret, r_odd, n + i + 1); + } +} + +/* modifies the value in place by performing a right shift by one bit */ +static ossl_inline void rshift1(limb_t *val, size_t n) +{ + limb_t shift_in = 0, shift_out = 0; + size_t i; + + for (i = 0; i < n; i++) { + shift_out = val[i] & 1; + val[i] = shift_in << (LIMB_BIT_SIZE - 1) | (val[i] >> 1); + shift_in = shift_out; + } +} + +/* extend the LSB of flag to all bits of limb */ +static ossl_inline limb_t mk_mask(limb_t flag) +{ + flag |= flag << 1; + flag |= flag << 2; + flag |= flag << 4; + flag |= flag << 8; + flag |= flag << 16; +#if (LIMB_BYTE_SIZE == 8) + flag |= flag << 32; +#endif + return flag; +} + +/* + * copy from either a or b to ret based on flag + * when flag == 0, then copies from b + * when flag == 1, then copies from a + */ +static ossl_inline void cselect(limb_t flag, limb_t *ret, limb_t *a, limb_t *b, size_t n) +{ + /* + * would be more efficient with non volatile mask, but then gcc + * generates code with jumps + */ + volatile limb_t mask; + size_t i; + + mask = mk_mask(flag); + for (i = 0; i < n; i++) { +#if (LIMB_BYTE_SIZE == 8) + ret[i] = constant_time_select_64(mask, a[i], b[i]); +#else + ret[i] = constant_time_select_32(mask, a[i], b[i]); +#endif + } +} + +static limb_t _sub_limb(limb_t *ret, limb_t a, limb_t b, limb_t borrow) +{ + limb_t borrow1, borrow2, t; + /* + * while it doesn't look constant-time, this is idiomatic code + * to tell compilers to use the carry bit from subtraction + */ + + *ret = a - borrow; + if (*ret > a) + borrow1 = 1; + else + borrow1 = 0; + + t = *ret; + *ret = t - b; + if (*ret > t) + borrow2 = 1; + else + borrow2 = 0; + + return borrow1 + borrow2; +} + +/* + * place the result of a - b into ret, return the borrow bit. + * All arrays need to be n limbs long + */ +static limb_t sub(limb_t *ret, limb_t *a, limb_t *b, size_t n) +{ + limb_t borrow = 0; + ossl_ssize_t i; + + for (i = n - 1; i > -1; i--) + borrow = _sub_limb(&ret[i], a[i], b[i], borrow); + + return borrow; +} + +/* return the number of limbs necessary to allocate for the mod() tmp operand */ +static ossl_inline size_t mod_limb_numb(size_t anum, size_t modnum) +{ + return (anum + modnum) * 3; +} + +/* + * calculate a % mod, place the result in ret + * size of a is defined by anum, size of ret and mod is modnum, + * size of tmp is returned by mod_limb_numb() + */ +static void mod(limb_t *ret, limb_t *a, size_t anum, limb_t *mod, + size_t modnum, limb_t *tmp) +{ + limb_t *atmp, *modtmp, *rettmp; + limb_t res; + size_t i; + + memset(tmp, 0, mod_limb_numb(anum, modnum) * LIMB_BYTE_SIZE); + + atmp = tmp; + modtmp = &tmp[anum + modnum]; + rettmp = &tmp[(anum + modnum) * 2]; + + for (i = modnum; i 0; i--, rp--) { + v = _mul_add_limb(rp, mod, modnum, rp[modnum - 1] * ni0, tmp2); + v = v + carry + rp[-1]; + carry |= (v != rp[-1]); + carry &= (v <= rp[-1]); + rp[-1] = v; + } + + /* perform the final reduction by mod... */ + carry -= sub(ret, rp, mod, modnum); + + /* ...conditionally */ + cselect(carry, ret, rp, ret, modnum); +} + +/* allocated buffer should be freed afterwards */ +static void BN_to_limb(const BIGNUM *bn, limb_t *buf, size_t limbs) +{ + int i; + int real_limbs = (BN_num_bytes(bn) + LIMB_BYTE_SIZE - 1) / LIMB_BYTE_SIZE; + limb_t *ptr = buf + (limbs - real_limbs); + + for (i = 0; i < real_limbs; i++) + ptr[i] = bn->d[real_limbs - i - 1]; +} + +#if LIMB_BYTE_SIZE == 8 +static ossl_inline uint64_t be64(uint64_t host) +{ + const union { + long one; + char little; + } is_endian = { 1 }; + + if (is_endian.little) { + uint64_t big = 0; + + big |= (host & 0xff00000000000000) >> 56; + big |= (host & 0x00ff000000000000) >> 40; + big |= (host & 0x0000ff0000000000) >> 24; + big |= (host & 0x000000ff00000000) >> 8; + big |= (host & 0x00000000ff000000) << 8; + big |= (host & 0x0000000000ff0000) << 24; + big |= (host & 0x000000000000ff00) << 40; + big |= (host & 0x00000000000000ff) << 56; + return big; + } else { + return host; + } +} + +#else +/* Not all platforms have htobe32(). */ +static ossl_inline uint32_t be32(uint32_t host) +{ + const union { + long one; + char little; + } is_endian = { 1 }; + + if (is_endian.little) { + uint32_t big = 0; + + big |= (host & 0xff000000) >> 24; + big |= (host & 0x00ff0000) >> 8; + big |= (host & 0x0000ff00) << 8; + big |= (host & 0x000000ff) << 24; + return big; + } else { + return host; + } +} +#endif + +/* + * We assume that intermediate, possible_arg2, blinding, and ctx are used + * similar to BN_BLINDING_invert_ex() arguments. + * to_mod is RSA modulus. + * buf and num is the serialization buffer and its length. + * + * Here we use classic/Montgomery multiplication and modulo. After the calculation finished + * we serialize the new structure instead of BIGNUMs taking endianness into account. + */ +int ossl_bn_rsa_do_unblind(const BIGNUM *intermediate, + const BN_BLINDING *blinding, + const BIGNUM *possible_arg2, + const BIGNUM *to_mod, BN_CTX *ctx, + unsigned char *buf, int num) +{ + limb_t *l_im = NULL, *l_mul = NULL, *l_mod = NULL; + limb_t *l_ret = NULL, *l_tmp = NULL, l_buf; + size_t l_im_count = 0, l_mul_count = 0, l_size = 0, l_mod_count = 0; + size_t l_tmp_count = 0; + int ret = 0; + size_t i; + unsigned char *tmp; + const BIGNUM *arg1 = intermediate; + const BIGNUM *arg2 = (possible_arg2 == NULL) ? blinding->Ai : possible_arg2; + + l_im_count = (BN_num_bytes(arg1) + LIMB_BYTE_SIZE - 1) / LIMB_BYTE_SIZE; + l_mul_count = (BN_num_bytes(arg2) + LIMB_BYTE_SIZE - 1) / LIMB_BYTE_SIZE; + l_mod_count = (BN_num_bytes(to_mod) + LIMB_BYTE_SIZE - 1) / LIMB_BYTE_SIZE; + + l_size = l_im_count > l_mul_count ? l_im_count : l_mul_count; + l_im = OPENSSL_zalloc(l_size * LIMB_BYTE_SIZE); + l_mul = OPENSSL_zalloc(l_size * LIMB_BYTE_SIZE); + l_mod = OPENSSL_zalloc(l_mod_count * LIMB_BYTE_SIZE); + + if ((l_im == NULL) || (l_mul == NULL) || (l_mod == NULL)) + goto err; + + BN_to_limb(arg1, l_im, l_size); + BN_to_limb(arg2, l_mul, l_size); + BN_to_limb(to_mod, l_mod, l_mod_count); + + l_ret = OPENSSL_malloc(2 * l_size * LIMB_BYTE_SIZE); + + if (blinding->m_ctx != NULL) { + l_tmp_count = mul_limb_numb(l_size) > mod_montgomery_limb_numb(l_mod_count) ? + mul_limb_numb(l_size) : mod_montgomery_limb_numb(l_mod_count); + l_tmp = OPENSSL_malloc(l_tmp_count * LIMB_BYTE_SIZE); + } else { + l_tmp_count = mul_limb_numb(l_size) > mod_limb_numb(2 * l_size, l_mod_count) ? + mul_limb_numb(l_size) : mod_limb_numb(2 * l_size, l_mod_count); + l_tmp = OPENSSL_malloc(l_tmp_count * LIMB_BYTE_SIZE); + } + + if ((l_ret == NULL) || (l_tmp == NULL)) + goto err; + + if (blinding->m_ctx != NULL) { + limb_mul(l_ret, l_im, l_mul, l_size, l_tmp); + mod_montgomery(l_ret, l_ret, 2 * l_size, l_mod, l_mod_count, + blinding->m_ctx->n0[0], l_tmp); + } else { + limb_mul(l_ret, l_im, l_mul, l_size, l_tmp); + mod(l_ret, l_ret, 2 * l_size, l_mod, l_mod_count, l_tmp); + } + + /* modulus size in bytes can be equal to num but after limbs conversion it becomes bigger */ + if (num < BN_num_bytes(to_mod)) { + BNerr(BN_F_OSSL_BN_RSA_DO_UNBLIND, ERR_R_PASSED_INVALID_ARGUMENT); + goto err; + } + + memset(buf, 0, num); + tmp = buf + num - BN_num_bytes(to_mod); + for (i = 0; i < l_mod_count; i++) { +#if LIMB_BYTE_SIZE == 8 + l_buf = be64(l_ret[i]); +#else + l_buf = be32(l_ret[i]); +#endif + if (i == 0) { + int delta = LIMB_BYTE_SIZE - ((l_mod_count * LIMB_BYTE_SIZE) - num); + + memcpy(tmp, ((char *)&l_buf) + LIMB_BYTE_SIZE - delta, delta); + tmp += delta; + } else { + memcpy(tmp, &l_buf, LIMB_BYTE_SIZE); + tmp += LIMB_BYTE_SIZE; + } + } + ret = num; + + err: + OPENSSL_free(l_im); + OPENSSL_free(l_mul); + OPENSSL_free(l_mod); + OPENSSL_free(l_tmp); + OPENSSL_free(l_ret); + + return ret; +} diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 902e97b84355109b8b4e255d36ab363d54d2b63a..e0f0ab7c76f8a644a55087135fc4ee0109840bec 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -1,4 +1,4 @@ -# Copyright 1999-2021 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 1999-2023 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the OpenSSL license (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy @@ -232,6 +232,7 @@ BN_F_BN_RSHIFT:146:BN_rshift BN_F_BN_SET_WORDS:144:bn_set_words BN_F_BN_STACK_PUSH:148:BN_STACK_push BN_F_BN_USUB:115:BN_usub +BN_F_OSSL_BN_RSA_DO_UNBLIND:151:ossl_bn_rsa_do_unblind BUF_F_BUF_MEM_GROW:100:BUF_MEM_grow BUF_F_BUF_MEM_GROW_CLEAN:105:BUF_MEM_grow_clean BUF_F_BUF_MEM_NEW:101:BUF_MEM_new diff --git a/crypto/pem/pem_lib.c b/crypto/pem/pem_lib.c index 2de093595d0d2e45962a78adf23ece83ee188f1d..173045be21eacf25b9dc60e7c72ddb7f16401d92 100644 --- a/crypto/pem/pem_lib.c +++ b/crypto/pem/pem_lib.c @@ -957,7 +957,9 @@ int PEM_read_bio_ex(BIO *bp, char **name_out, char **header, *data = pem_malloc(len, flags); if (*header == NULL || *data == NULL) { pem_free(*header, flags, 0); + *header = NULL; pem_free(*data, flags, 0); + *data = NULL; goto end; } BIO_read(headerB, *header, headerlen); diff --git a/crypto/rsa/rsa_ossl.c b/crypto/rsa/rsa_ossl.c index b52a66f6a6280321a28fd2cc8ca18a195910611c..6c3c0cf78d300014941140027b81b5e09c94a084 100644 --- a/crypto/rsa/rsa_ossl.c +++ b/crypto/rsa/rsa_ossl.c @@ -465,11 +465,20 @@ static int rsa_ossl_private_decrypt(int flen, const unsigned char *from, BN_free(d); } - if (blinding) - if (!rsa_blinding_invert(blinding, ret, unblind, ctx)) + if (blinding) { + /* + * ossl_bn_rsa_do_unblind() combines blinding inversion and + * 0-padded BN BE serialization + */ + j = ossl_bn_rsa_do_unblind(ret, blinding, unblind, rsa->n, ctx, + buf, num); + if (j == 0) goto err; - - j = BN_bn2binpad(ret, buf, num); + } else { + j = BN_bn2binpad(ret, buf, num); + if (j < 0) + goto err; + } switch (padding) { case RSA_PKCS1_PADDING: diff --git a/crypto/x509v3/v3_genn.c b/crypto/x509v3/v3_genn.c index 87a5eff47cd99a61d7a5e00ad1c5a1c35626dba5..e54ddc55c957aa3ca9fce64d3eafaf4dc931b84e 100644 --- a/crypto/x509v3/v3_genn.c +++ b/crypto/x509v3/v3_genn.c @@ -98,7 +98,7 @@ int GENERAL_NAME_cmp(GENERAL_NAME *a, GENERAL_NAME *b) return -1; switch (a->type) { case GEN_X400: - result = ASN1_TYPE_cmp(a->d.x400Address, b->d.x400Address); + result = ASN1_STRING_cmp(a->d.x400Address, b->d.x400Address); break; case GEN_EDIPARTY: diff --git a/include/crypto/bn.h b/include/crypto/bn.h index 60afda1dadee0c56eecae294e44d683675eb0872..b5f36fb25aa22c4a9003e83758ff0b6a4ff9faac 100644 --- a/include/crypto/bn.h +++ b/include/crypto/bn.h @@ -86,5 +86,10 @@ int bn_lshift_fixed_top(BIGNUM *r, const BIGNUM *a, int n); int bn_rshift_fixed_top(BIGNUM *r, const BIGNUM *a, int n); int bn_div_fixed_top(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx); +int ossl_bn_rsa_do_unblind(const BIGNUM *intermediate, + const BN_BLINDING *blinding, + const BIGNUM *possible_arg2, + const BIGNUM *to_mod, BN_CTX *ctx, + unsigned char *buf, int num); #endif diff --git a/include/openssl/bnerr.h b/include/openssl/bnerr.h index 9f3c7cfaab674255e79a45296d3e2cd0c8d7328c..a0752cea52d7acb333b769fc673bd7ff4f72a0c5 100644 --- a/include/openssl/bnerr.h +++ b/include/openssl/bnerr.h @@ -72,6 +72,7 @@ int ERR_load_BN_strings(void); # define BN_F_BN_SET_WORDS 144 # define BN_F_BN_STACK_PUSH 148 # define BN_F_BN_USUB 115 +# define BN_F_OSSL_BN_RSA_DO_UNBLIND 151 /* * BN reason codes. diff --git a/include/openssl/x509v3.h b/include/openssl/x509v3.h index 90fa3592ce58f7bdf6e1757519a6ec223f380e76..e61c0f29d4b4de249e04eda183699bf37e946eb3 100644 --- a/include/openssl/x509v3.h +++ b/include/openssl/x509v3.h @@ -136,7 +136,7 @@ typedef struct GENERAL_NAME_st { OTHERNAME *otherName; /* otherName */ ASN1_IA5STRING *rfc822Name; ASN1_IA5STRING *dNSName; - ASN1_TYPE *x400Address; + ASN1_STRING *x400Address; X509_NAME *directoryName; EDIPARTYNAME *ediPartyName; ASN1_IA5STRING *uniformResourceIdentifier; diff --git a/test/pemtest.c b/test/pemtest.c index 3203d976be7683626f8a1f96dc8bcf2d1d27ac8f..edeb0a12059ee9fb92820a722655447d3766d5b3 100644 --- a/test/pemtest.c +++ b/test/pemtest.c @@ -83,9 +83,39 @@ static int test_invalid(void) return 1; } +static int test_empty_payload(void) +{ + BIO *b; + static char *emptypay = + "-----BEGIN CERTIFICATE-----\n" + "-\n" /* Base64 EOF character */ + "-----END CERTIFICATE-----"; + char *name = NULL, *header = NULL; + unsigned char *data = NULL; + long len; + int ret = 0; + + b = BIO_new_mem_buf(emptypay, strlen(emptypay)); + if (!TEST_ptr(b)) + return 0; + + /* Expected to fail because the payload is empty */ + if (!TEST_false(PEM_read_bio_ex(b, &name, &header, &data, &len, 0))) + goto err; + + ret = 1; + err: + OPENSSL_free(name); + OPENSSL_free(header); + OPENSSL_free(data); + BIO_free(b); + return ret; +} + int setup_tests(void) { ADD_ALL_TESTS(test_b64, OSSL_NELEM(b64_pem_data)); ADD_TEST(test_invalid); + ADD_TEST(test_empty_payload); return 1; } diff --git a/test/v3nametest.c b/test/v3nametest.c index d1852190b84eb948de8b5665762021b23b2c7766..37819da8fd78361785f01421fb44066208a532cb 100644 --- a/test/v3nametest.c +++ b/test/v3nametest.c @@ -646,6 +646,14 @@ static struct gennamedata { 0xb7, 0x09, 0x02, 0x02 }, 15 + }, { + /* + * Regression test for CVE-2023-0286. + */ + { + 0xa3, 0x00 + }, + 2 } };