--- crypto/openssl/apps/dgst.c.orig +++ crypto/openssl/apps/dgst.c @@ -704,12 +704,11 @@ { int res, ret = EXIT_FAILURE; size_t len = 0; - int buflen = 0; - int maxlen = 16 * 1024 * 1024; + size_t buflen = 0; + size_t maxlen = 16 * 1024 * 1024; uint8_t *buf = NULL, *sig = NULL; - buflen = bio_to_mem(&buf, maxlen, in); - if (buflen <= 0) { + if (!bio_to_mem(&buf, &buflen, maxlen, in)) { BIO_printf(bio_err, "Read error in %s\n", file); return ret; } --- crypto/openssl/apps/include/apps.h.orig +++ crypto/openssl/apps/include/apps.h @@ -253,7 +253,7 @@ X509_NAME *parse_name(const char *str, int chtype, int multirdn, const char *desc); void policies_print(X509_STORE_CTX *ctx); -int bio_to_mem(unsigned char **out, int maxlen, BIO *in); +int bio_to_mem(unsigned char **out, size_t *outlen, size_t maxlen, BIO *in); int pkey_ctrl_string(EVP_PKEY_CTX *ctx, const char *value); int x509_ctrl_string(X509 *x, const char *value); int x509_req_ctrl_string(X509_REQ *x, const char *value); --- crypto/openssl/apps/lib/apps.c.orig +++ crypto/openssl/apps/lib/apps.c @@ -49,6 +49,7 @@ #include "apps.h" #include "internal/sockets.h" /* for openssl_fdset() */ +#include "internal/numbers.h" /* for LONG_MAX */ #include "internal/e_os.h" #ifdef _WIN32 @@ -2010,45 +2011,45 @@ } /* - * Read whole contents of a BIO into an allocated memory buffer and return - * it. + * Read whole contents of a BIO into an allocated memory buffer. + * The return value is one on success, zero on error. + * If `maxlen` is non-zero, at most `maxlen` bytes are returned, or else, if + * the input is longer than `maxlen`, an error is returned. + * If `maxlen` is zero, the limit is effectively `SIZE_MAX`. */ - -int bio_to_mem(unsigned char **out, int maxlen, BIO *in) +int bio_to_mem(unsigned char **out, size_t *outlen, size_t maxlen, BIO *in) { + unsigned char tbuf[4096]; BIO *mem; - int len, ret; - unsigned char tbuf[1024]; + BUF_MEM *bufm; + size_t sz = 0; + int len; mem = BIO_new(BIO_s_mem()); if (mem == NULL) - return -1; + return 0; for (;;) { - if ((maxlen != -1) && maxlen < 1024) - len = maxlen; - else - len = 1024; - len = BIO_read(in, tbuf, len); - if (len < 0) { - BIO_free(mem); - return -1; - } - if (len == 0) + if ((len = BIO_read(in, tbuf, 4096)) == 0) break; - if (BIO_write(mem, tbuf, len) != len) { + if (len < 0 + || BIO_write(mem, tbuf, len) != len + || sz > SIZE_MAX - len + || ((sz += len) > maxlen && maxlen != 0)) { BIO_free(mem); - return -1; + return 0; } - if (maxlen != -1) - maxlen -= len; - - if (maxlen == 0) - break; } - ret = BIO_get_mem_data(mem, (char **)out); - BIO_set_flags(mem, BIO_FLAGS_MEM_RDONLY); + + /* So BIO_free orphans BUF_MEM */ + (void)BIO_set_close(mem, BIO_NOCLOSE); + BIO_get_mem_ptr(mem, &bufm); BIO_free(mem); - return ret; + *out = (unsigned char *)bufm->data; + *outlen = bufm->length; + /* Tell BUF_MEM to orphan data */ + bufm->data = NULL; + BUF_MEM_free(bufm); + return 1; } int pkey_ctrl_string(EVP_PKEY_CTX *ctx, const char *value) --- crypto/openssl/apps/pkeyutl.c.orig +++ crypto/openssl/apps/pkeyutl.c @@ -40,7 +40,7 @@ static int do_raw_keyop(int pkey_op, EVP_MD_CTX *mctx, EVP_PKEY *pkey, BIO *in, - int filesize, unsigned char *sig, int siglen, + int filesize, unsigned char *sig, size_t siglen, unsigned char **out, size_t *poutlen); static int only_nomd(EVP_PKEY *pkey) @@ -133,7 +133,7 @@ char hexdump = 0, asn1parse = 0, rev = 0, *prog; unsigned char *buf_in = NULL, *buf_out = NULL, *sig = NULL, *secret = NULL; OPTION_CHOICE o; - int buf_inlen = 0, siglen = -1; + size_t buf_inlen = 0, siglen = 0; int keyform = FORMAT_UNDEF, peerform = FORMAT_UNDEF; int keysize = -1, pkey_op = EVP_PKEY_OP_SIGN, key_type = KEY_PRIVKEY; int engine_impl = 0; @@ -486,31 +486,31 @@ if (sigfile != NULL) { BIO *sigbio = BIO_new_file(sigfile, "rb"); + size_t maxsiglen = 16 * 1024 * 1024; if (sigbio == NULL) { BIO_printf(bio_err, "Can't open signature file %s\n", sigfile); goto end; } - siglen = bio_to_mem(&sig, keysize * 10, sigbio); - BIO_free(sigbio); - if (siglen < 0) { + if (!bio_to_mem(&sig, &siglen, maxsiglen, sigbio)) { + BIO_free(sigbio); BIO_printf(bio_err, "Error reading signature data\n"); goto end; } + BIO_free(sigbio); } /* Raw input data is handled elsewhere */ if (in != NULL && !rawin) { /* Read the input data */ - buf_inlen = bio_to_mem(&buf_in, -1, in); - if (buf_inlen < 0) { + if (!bio_to_mem(&buf_in, &buf_inlen, 0, in)) { BIO_printf(bio_err, "Error reading input Data\n"); goto end; } if (rev) { size_t i; unsigned char ctmp; - size_t l = (size_t)buf_inlen; + size_t l = buf_inlen; for (i = 0; i < l / 2; i++) { ctmp = buf_in[i]; @@ -525,7 +525,8 @@ && (pkey_op == EVP_PKEY_OP_SIGN || pkey_op == EVP_PKEY_OP_VERIFY)) { if (buf_inlen > EVP_MAX_MD_SIZE) { BIO_printf(bio_err, - "Error: The non-raw input data length %d is too long - max supported hashed size is %d\n", + "Error: The non-raw input data length %zd is too long - " + "max supported hashed size is %d\n", buf_inlen, EVP_MAX_MD_SIZE); goto end; } @@ -536,8 +537,7 @@ rv = do_raw_keyop(pkey_op, mctx, pkey, in, filesize, sig, siglen, NULL, 0); } else { - rv = EVP_PKEY_verify(ctx, sig, (size_t)siglen, - buf_in, (size_t)buf_inlen); + rv = EVP_PKEY_verify(ctx, sig, siglen, buf_in, buf_inlen); } if (rv == 1) { BIO_puts(out, "Signature Verified Successfully\n"); @@ -556,8 +556,8 @@ buf_outlen = kdflen; rv = 1; } else { - rv = do_keyop(ctx, pkey_op, NULL, (size_t *)&buf_outlen, - buf_in, (size_t)buf_inlen, NULL, (size_t *)&secretlen); + rv = do_keyop(ctx, pkey_op, NULL, &buf_outlen, + buf_in, buf_inlen, NULL, &secretlen); } if (rv > 0 && (secretlen > 0 || (pkey_op != EVP_PKEY_OP_ENCAPSULATE @@ -568,8 +568,8 @@ if (secretlen > 0) secret = app_malloc(secretlen, "secret output"); rv = do_keyop(ctx, pkey_op, - buf_out, (size_t *)&buf_outlen, - buf_in, (size_t)buf_inlen, secret, (size_t *)&secretlen); + buf_out, &buf_outlen, + buf_in, buf_inlen, secret, &secretlen); } } if (rv <= 0) { @@ -838,7 +838,7 @@ static int do_raw_keyop(int pkey_op, EVP_MD_CTX *mctx, EVP_PKEY *pkey, BIO *in, - int filesize, unsigned char *sig, int siglen, + int filesize, unsigned char *sig, size_t siglen, unsigned char **out, size_t *poutlen) { int rv = 0; @@ -861,7 +861,7 @@ BIO_printf(bio_err, "Error reading raw input data\n"); goto end; } - rv = EVP_DigestVerify(mctx, sig, (size_t)siglen, mbuf, buf_len); + rv = EVP_DigestVerify(mctx, sig, siglen, mbuf, buf_len); break; case EVP_PKEY_OP_SIGN: buf_len = BIO_read(in, mbuf, filesize); @@ -895,7 +895,7 @@ goto end; } } - rv = EVP_DigestVerifyFinal(mctx, sig, (size_t)siglen); + rv = EVP_DigestVerifyFinal(mctx, sig, siglen); break; case EVP_PKEY_OP_SIGN: for (;;) { --- crypto/openssl/apps/s_client.c.orig +++ crypto/openssl/apps/s_client.c @@ -2834,8 +2834,9 @@ goto end; } atyp = ASN1_generate_nconf(genstr, cnf); - if (atyp == NULL) { + if (atyp == NULL || atyp->type != V_ASN1_SEQUENCE) { NCONF_free(cnf); + ASN1_TYPE_free(atyp); BIO_printf(bio_err, "ASN1_generate_nconf failed\n"); goto end; } --- crypto/openssl/crypto/asn1/a_strex.c.orig +++ crypto/openssl/crypto/asn1/a_strex.c @@ -204,8 +204,10 @@ orflags = CHARTYPE_LAST_ESC_2253; if (type & BUF_TYPE_CONVUTF8) { unsigned char utfbuf[6]; - int utflen; - utflen = UTF8_putc(utfbuf, sizeof(utfbuf), c); + int utflen = UTF8_putc(utfbuf, sizeof(utfbuf), c); + + if (utflen < 0) + return -1; /* error happened with UTF8 */ for (i = 0; i < utflen; i++) { /* * We don't need to worry about setting orflags correctly --- crypto/openssl/crypto/asn1/evp_asn1.c.orig +++ crypto/openssl/crypto/asn1/evp_asn1.c @@ -60,6 +60,12 @@ oct->flags = 0; } +/* + * This function copies 'anum' to 'num' and the data of 'oct' to 'data'. + * If the length of 'data' > 'max_len', copies only the first 'max_len' + * bytes, but returns the full length of 'oct'; this allows distinguishing + * whether all the data was copied. + */ static int asn1_type_get_int_oct(ASN1_OCTET_STRING *oct, int32_t anum, long *num, unsigned char *data, int max_len) { @@ -106,6 +112,13 @@ return 0; } +/* + * This function decodes an int-octet sequence and copies the integer to 'num' + * and the data of octet to 'data'. + * If the length of 'data' > 'max_len', copies only the first 'max_len' + * bytes, but returns the full length of 'oct'; this allows distinguishing + * whether all the data was copied. + */ int ASN1_TYPE_get_int_octetstring(const ASN1_TYPE *a, long *num, unsigned char *data, int max_len) { @@ -162,6 +175,13 @@ return 0; } +/* + * This function decodes an octet-int sequence and copies the data of octet + * to 'data' and the integer to 'num'. + * If the length of 'data' > 'max_len', copies only the first 'max_len' + * bytes, but returns the full length of 'oct'; this allows distinguishing + * whether all the data was copied. + */ int ossl_asn1_type_get_octetstring_int(const ASN1_TYPE *a, long *num, unsigned char *data, int max_len) { --- crypto/openssl/crypto/bio/bf_lbuf.c.orig +++ crypto/openssl/crypto/bio/bf_lbuf.c @@ -186,14 +186,34 @@ while (foundnl && inl > 0); /* * We've written as much as we can. The rest of the input buffer, if - * any, is text that doesn't and with a NL and therefore needs to be - * saved for the next trip. + * any, is text that doesn't end with a NL and therefore we need to try + * free up some space in our obuf so we can make forward progress. */ - if (inl > 0) { - memcpy(&(ctx->obuf[ctx->obuf_len]), in, inl); - ctx->obuf_len += inl; - num += inl; + while (inl > 0) { + size_t avail = (size_t)ctx->obuf_size - (size_t)ctx->obuf_len; + size_t to_copy; + + if (avail == 0) { + /* Flush buffered data to make room */ + i = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); + if (i <= 0) { + BIO_copy_next_retry(b); + return num > 0 ? num : i; + } + if (i < ctx->obuf_len) + memmove(ctx->obuf, ctx->obuf + i, ctx->obuf_len - i); + ctx->obuf_len -= i; + continue; + } + + to_copy = inl > (int)avail ? avail : (size_t)inl; + memcpy(&(ctx->obuf[ctx->obuf_len]), in, to_copy); + ctx->obuf_len += (int)to_copy; + in += to_copy; + inl -= (int)to_copy; + num += (int)to_copy; } + return num; } --- crypto/openssl/crypto/evp/evp_lib.c.orig +++ crypto/openssl/crypto/evp/evp_lib.c @@ -228,10 +228,9 @@ if (type == NULL || asn1_params == NULL) return 0; - i = ossl_asn1_type_get_octetstring_int(type, &tl, NULL, EVP_MAX_IV_LENGTH); - if (i <= 0) + i = ossl_asn1_type_get_octetstring_int(type, &tl, iv, EVP_MAX_IV_LENGTH); + if (i <= 0 || i > EVP_MAX_IV_LENGTH) return -1; - ossl_asn1_type_get_octetstring_int(type, &tl, iv, i); memcpy(asn1_params->iv, iv, i); asn1_params->iv_len = i; --- crypto/openssl/crypto/modes/ocb128.c.orig +++ crypto/openssl/crypto/modes/ocb128.c @@ -338,7 +338,7 @@ if (num_blocks && all_num_blocks == (size_t)all_num_blocks && ctx->stream != NULL) { - size_t max_idx = 0, top = (size_t)all_num_blocks; + size_t max_idx = 0, top = (size_t)all_num_blocks, processed_bytes = 0; /* * See how many L_{i} entries we need to process data at hand @@ -352,6 +352,9 @@ ctx->stream(in, out, num_blocks, ctx->keyenc, (size_t)ctx->sess.blocks_processed + 1, ctx->sess.offset.c, (const unsigned char (*)[16])ctx->l, ctx->sess.checksum.c); + processed_bytes = num_blocks * 16; + in += processed_bytes; + out += processed_bytes; } else { /* Loop through all full blocks to be encrypted */ for (i = ctx->sess.blocks_processed + 1; i <= all_num_blocks; i++) { @@ -430,7 +433,7 @@ if (num_blocks && all_num_blocks == (size_t)all_num_blocks && ctx->stream != NULL) { - size_t max_idx = 0, top = (size_t)all_num_blocks; + size_t max_idx = 0, top = (size_t)all_num_blocks, processed_bytes = 0; /* * See how many L_{i} entries we need to process data at hand @@ -444,6 +447,9 @@ ctx->stream(in, out, num_blocks, ctx->keydec, (size_t)ctx->sess.blocks_processed + 1, ctx->sess.offset.c, (const unsigned char (*)[16])ctx->l, ctx->sess.checksum.c); + processed_bytes = num_blocks * 16; + in += processed_bytes; + out += processed_bytes; } else { OCB_BLOCK tmp; --- crypto/openssl/crypto/pkcs12/p12_decr.c.orig +++ crypto/openssl/crypto/pkcs12/p12_decr.c @@ -143,6 +143,11 @@ void *ret; int outlen = 0; + if (oct == NULL) { + ERR_raise(ERR_LIB_PKCS12, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + if (!PKCS12_pbe_crypt_ex(algor, pass, passlen, oct->data, oct->length, &out, &outlen, 0, libctx, propq)) return NULL; --- crypto/openssl/crypto/pkcs12/p12_kiss.c.orig +++ crypto/openssl/crypto/pkcs12/p12_kiss.c @@ -197,11 +197,17 @@ ASN1_BMPSTRING *fname = NULL; ASN1_OCTET_STRING *lkid = NULL; - if ((attrib = PKCS12_SAFEBAG_get0_attr(bag, NID_friendlyName))) + if ((attrib = PKCS12_SAFEBAG_get0_attr(bag, NID_friendlyName))) { + if (attrib->type != V_ASN1_BMPSTRING) + return 0; fname = attrib->value.bmpstring; + } - if ((attrib = PKCS12_SAFEBAG_get0_attr(bag, NID_localKeyID))) + if ((attrib = PKCS12_SAFEBAG_get0_attr(bag, NID_localKeyID))) { + if (attrib->type != V_ASN1_OCTET_STRING) + return 0; lkid = attrib->value.octet_string; + } switch (PKCS12_SAFEBAG_get_nid(bag)) { case NID_keyBag: --- crypto/openssl/crypto/pkcs12/p12_mutl.c.orig +++ crypto/openssl/crypto/pkcs12/p12_mutl.c @@ -122,8 +122,6 @@ ERR_raise(ERR_LIB_PKCS12, ERR_R_UNSUPPORTED); goto err; } - keylen = ASN1_INTEGER_get(pbkdf2_param->keylength); - pbkdf2_salt = pbkdf2_param->salt->value.octet_string; if (pbkdf2_param->prf == NULL) { kdf_hmac_nid = NID_hmacWithSHA1; @@ -138,6 +136,22 @@ goto err; } + /* Validate salt is an OCTET STRING choice */ + if (pbkdf2_param->salt == NULL + || pbkdf2_param->salt->type != V_ASN1_OCTET_STRING) { + ERR_raise(ERR_LIB_PKCS12, PKCS12_R_PARSE_ERROR); + goto err; + } + pbkdf2_salt = pbkdf2_param->salt->value.octet_string; + + /* RFC 9579 specifies missing key length as invalid */ + if (pbkdf2_param->keylength != NULL) + keylen = ASN1_INTEGER_get(pbkdf2_param->keylength); + if (keylen <= 0 || keylen > EVP_MAX_MD_SIZE) { + ERR_raise(ERR_LIB_PKCS12, PKCS12_R_PARSE_ERROR); + goto err; + } + if (PKCS5_PBKDF2_HMAC(pass, passlen, pbkdf2_salt->data, pbkdf2_salt->length, ASN1_INTEGER_get(pbkdf2_param->iter), kdf_md, keylen, key) <= 0) { ERR_raise(ERR_LIB_PKCS12, ERR_R_INTERNAL_ERROR); --- crypto/openssl/crypto/pkcs12/p12_utl.c.orig +++ crypto/openssl/crypto/pkcs12/p12_utl.c @@ -206,6 +206,11 @@ /* re-run the loop emitting UTF-8 string */ for (asclen = 0, i = 0; i < unilen; ) { j = bmp_to_utf8(asctmp+asclen, uni+i, unilen-i); + /* when UTF8_putc fails */ + if (j < 0) { + OPENSSL_free(asctmp); + return NULL; + } if (j == 4) i += 4; else i += 2; asclen += j; --- crypto/openssl/crypto/pkcs7/pk7_doit.c.orig +++ crypto/openssl/crypto/pkcs7/pk7_doit.c @@ -1231,6 +1231,8 @@ ASN1_TYPE *astype; if ((astype = get_attribute(sk, NID_pkcs9_messageDigest)) == NULL) return NULL; + if (astype->type != V_ASN1_OCTET_STRING) + return NULL; return astype->value.octet_string; } --- crypto/openssl/crypto/ts/ts_rsp_verify.c.orig +++ crypto/openssl/crypto/ts/ts_rsp_verify.c @@ -211,7 +211,7 @@ const unsigned char *p; attr = PKCS7_get_signed_attribute(si, NID_id_smime_aa_signingCertificate); - if (attr == NULL) + if (attr == NULL || attr->type != V_ASN1_SEQUENCE) return NULL; p = attr->value.sequence->data; return d2i_ESS_SIGNING_CERT(NULL, &p, attr->value.sequence->length); @@ -224,7 +224,7 @@ const unsigned char *p; attr = PKCS7_get_signed_attribute(si, NID_id_smime_aa_signingCertificateV2); - if (attr == NULL) + if (attr == NULL || attr->type != V_ASN1_SEQUENCE) return NULL; p = attr->value.sequence->data; return d2i_ESS_SIGNING_CERT_V2(NULL, &p, attr->value.sequence->length); --- crypto/openssl/ssl/quic/quic_impl.c.orig +++ crypto/openssl/ssl/quic/quic_impl.c @@ -5065,6 +5065,8 @@ { const SSL_CIPHER *ciph = ssl3_get_cipher_by_char(p); + if (ciph == NULL) + return NULL; if ((ciph->algorithm2 & SSL_QUIC) == 0) return NULL; --- crypto/openssl/ssl/statem/statem_lib.c.orig +++ crypto/openssl/ssl/statem/statem_lib.c @@ -2912,6 +2912,12 @@ goto err; } + /* Prevent excessive pre-decompression allocation */ + if (expected_length > sc->max_cert_list) { + SSLfatal(sc, SSL_AD_ILLEGAL_PARAMETER, SSL_R_EXCESSIVE_MESSAGE_SIZE); + goto err; + } + if (PACKET_remaining(pkt) != comp_length || comp_length == 0) { SSLfatal(sc, SSL_AD_DECODE_ERROR, SSL_R_BAD_DECOMPRESSION); goto err; --