Skip to content

Bump org.bouncycastle:bcpkix-jdk18on from 1.76 to 1.84 in the maven group across 1 directory - #84

Closed
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/maven/maven-2531a232e3
Closed

dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/maven/maven-2531a232e3

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Sep 28, 2026

Copy link
Copy Markdown
Contributor

Bumps the maven group with 1 update in the / directory: org.bouncycastle:bcpkix-jdk18on.

Updates org.bouncycastle:bcpkix-jdk18on from 1.76 to 1.84

Changelog

Sourced from org.bouncycastle:bcpkix-jdk18on's changelog.

Bouncy Castle Crypto Package - Release Notes

1.0 Introduction

The Bouncy Castle Crypto package is a Java implementation of cryptographic algorithms. The package is organised so that it contains a light-weight API suitable for use in any environment (including the J2ME) with the additional infrastructure to conform the algorithms to the JCE framework.

2.0 Release History

2.1.1 Version

Release: 1.87
Date: 2026, TBD

2.1.2 Defects Fixed

  • A KeyAgreement asked for its shared secret before doPhase returned data rather than refusing. javax.crypto.KeyAgreement specifies IllegalStateException for that state, but nothing in the provider tracked it, so each SPI handed back whatever its result field held: for Diffie-Hellman that was the private value itself - engineInit seeded result with x, so generateSecret() returned the private exponent padded to the prime's length and generateSecret("AES") an all-zero key taken from that padding - while ECDH returned null and its named-algorithm overload raised NullPointerException. BaseAgreementSpi now records whether a doPhase has completed the agreement since the last init and refuses the request with an IllegalStateException naming the algorithm, so every family in the provider - DH, ECDH and ECMQV, the SM2 exchange, both ECGOST families, XDH, SM9 and NewHope - answers the same way, and the DH SPI no longer holds the private value in that field at all.

  • Mac.getInstance and KeyGenerator.getInstance by the HMAC SHA-512/224 and SHA-512/256 object identifiers (1.2.840.113549.2.12 and .13) failed, although the same algorithms resolved by name and the matching SecretKeyFactory aliases were registered: the SHA512 mappings called addHMACAlgorithm for the two truncated variants without the addHMACAlias that registers their OIDs against Mac and KeyGenerator. Both are now aliased, as every other HMAC in that class already was.

  • A KTSParameterSpec naming an HKDF key-derivation function with a parameters field - a form the provider does not service - was accepted at Cipher init and then failed out of wrap or unwrap with an unchecked IllegalStateException neither method declares. The KTS key-wrapping Ciphers (ML-KEM, Classic McEliece, FrodoKEM, the composite KEM and RSA-KEM) now validate the spec's KDF when they take it, reporting an unserviceable one as the InvalidAlgorithmParameterException engineInit declares, which is what the javax.crypto.KEM services already did through KdfUtil.resolveKemSpec.

  • A DTLS handshake deadlocked when a handshake message ahead of the peer's ChangeCipherSpec (a client's CertificateVerify, say) was lost while the ChangeCipherSpec and Finished behind it arrived: the record layer moved its read epoch on at the ChangeCipherSpec and then discarded every retransmission of the lost message as belonging to the old epoch, whose records are only accepted once the handshake has completed. Each side then waited on the other until a handshake timeout, if one was configured, ended it. Every client-authenticated handshake, and every handshake in which the server issues a NewSessionTicket, was exposed. Until the handshake completes, handshake records from the current epoch are now still accepted after the read epoch has moved on, and each message is checked against the epoch of the record that carried it. The DTLS loopback tests now run their handshakes at 10% datagram loss in each direction, with a client-authenticated handshake at 25%.

  • The lightweight SubjectPublicKeyInfoFactory and PrivateKeyInfoFactory encoded a GOST R 34.10-2012 key on one of the legacy CryptoPro curves under id-GostR3410-2001, although RFC 9215 sec. 4.2 permits those curves for 2012 keys. The digestParamSet now decides: a GOST R 34.11-94 parameter set means 2001 (RFC 4491 sec. 2.3.2), a GOST R 34.11-2012 digest or none means 2012 with 256/512 taken from the curve field size, and any other value is rejected. GOST3410PublicKeyAlgParameters treats digestParamSet as OPTIONAL on both read and write per RFC 9215, and PrivateKeyInfoFactory now passes attributes through for ECGOST3410 keys (bc-csharp github #707).

  • The name-constraint host canonicalisation removed a single RFC 1034 root-label dot, the only empty label a name may legally carry, but nothing refused the ones that are not legal: a dNSName, rfc822Name host or uniformResourceIdentifier host such as "example.com.." kept a phantom empty label after the strip and so matched no constraint at all, escaping an excluded subtree naming the host it appears to carry. A tested name whose host carries an empty label - a second trailing dot, a doubled dot or a leading dot - is now refused outright wherever a constraint of that type is in force, rather than canonicalised into a name it is not: removing the extra dots would decide on the caller's behalf that "example.com.." names example.com, which is not how a consumer resolving or comparing the name reads it, and refusing fails closed in both directions where canonicalising would newly admit such a name under a permitted subtree. The single trailing dot is canonicalised as before, a bare "." remains the root label rather than an empty one, and the guard is scoped to the host, so the doubled dot a quoted local part may legally carry is unaffected. Constraints are untouched - one may still begin with a dot, which is how this implementation spells "subdomains only" (github PR #2436).

  • SSLContext.createSSLEngine() from the BCJSSE provider in the 1.86 bctls jar failed with NoSuchMethodError on every JDK from 9 up, leaving engine-based users of the provider (Netty, Vert.x and the like) unable to open a connection. The jdk1.5 and jdk1.9 copies of the package-private SSLEngineUtil had declared create(ContextData) with different return types since 2019 - SSLEngine and ProvSSLEngine - and the root ProvSSLContextSpi, compiled against the first, is paired at runtime with the versions/9 copy on any modern JDK. Until 1.86 the java9 compile had hidden this by implicitly recompiling the whole base tree into META-INF/versions/9 (447 classes, ProvSSLContextSpi among them); the -implicit:none added in 1.86 to stop that duplication exposed the mismatch. The jdk1.9 copy now declares the same return type as the root one, a JDK 25 test creates engines against the built jar, and a new multiReleaseCheck Gradle task on every distributed jar reads the constant pool of each class in the jar and in the sibling BC jars it depends on and fails the build when a member reference does not resolve against the copy of its target that a JDK would pair it with, so the class of defect cannot ship again; the same check runs on arbitrary jars, a published release included, as multiReleaseCheckJar (github #2448).

  • The BCFKS key store derived its scrypt keys with the block size r in place of the parallelization parameter p, while writing the p the caller configured out to the store: BcFKSKeyStoreSpi passed getBlockSize() to SCrypt.generate for both arguments and never read the encoded parallelization parameter at all, so every store whose ScryptConfig gave a p other than its r encoded parameters that do not derive its own keys. The store was self-consistent - BC read back what BC wrote - but a conformant RFC 7914 reader computed a different key and so failed the integrity check and the store decryption, and BC could not open such a store written by anyone else. Derivation now follows RFC 7914. A store written by 1.86 or earlier is still read: the integrity check is retried under the old convention, and where a signature check leaves no MAC to settle it the store decryption is retried instead, in both cases reporting the failure of the encoded parameters rather than of the fallback. The write side is governed by org.bouncycastle.bcfks.scrypt_p_eq_r, default true, which writes p equal to r whatever the ScryptConfig asked for: the two conventions then agree, so a store written here is both RFC 7914 correct and readable by 1.86 and earlier. Clearing the property honours the configured p, which those releases cannot read unless p already equals r; the default is intended to become false in a later release, once enough of the installed base is writing parameters that describe themselves. Loading with a BCFKSLoadStoreParameter carrying a ScryptConfig accepts an encoded p equal to either the configured p or the block size, so a store round trips under the configuration that wrote it whichever way the property was set; every other parameter is compared as before. The parallelization parameter is now bounded alongside the cost parameter before the derivation, as the PKCS#8 and PKCS#12 scrypt paths already bound it.

  • Building an evidence record was cubic in the number of data objects: SortedHashList and SortedIndexedHashList held their hashes in a LinkedList and found each insertion point by walking it with get(index), so a single add() was quadratic in the position it inserted at and building a list of n hashes cubic, and both lists sit on the generation path - the reduced hash tree of ERSArchiveTimeStampGenerator, the Merkle tree of BinaryTreeRootCalculator.computeRootHash(), and the hash list of every ERSDataGroup. Each now collects its hashes and sorts them once, in toList(); the sort is stable and the old insertion placed a hash after the last one comparing equal to it, which is where a stable sort puts it, so the order of the leaves and every root hash are unchanged. getFirst() answers with a scan rather than a sort and toList() sorts a copy, so neither accessor disturbs what has been added. Generating a time-stamp request over 8,000 data objects goes from about 210 seconds to under a tenth of a second, and 100,000 objects, which the old code could not reach in any practical time, takes about 0.2 seconds (github #2456).

  • An ERSDataGroup recomputed its hash on every request rather than taking it from the cache ERSCachingData exists to provide: the group overrode getHash(), which left the calculateHash() the cache calls unreachable - and wrong, as it copied the member hashes with a loop bounded by the size of the empty list it was copying into, so it would have digested nothing had anything reached it. The computation is back in calculateHash() and the override is gone, so a group's hash is computed once per digest algorithm and previous-chain hash, as every other ERSData's is. The value itself is unchanged.

  • ERSArchiveTimeStampGenerator rebuilt its reduced hash tree from the data objects on every call, so the usual generateTimeStampRequest() followed by generateArchiveTimeStamp() or generateArchiveTimeStamps() built it twice. The leaves are now built once and dropped when data or a previous chain is added. A Set of the data groups it had been given, which nothing ever read, has gone with it.

  • Grain-128AEAD returned corrupted plaintext from a decryption driven in chunks. The stream cipher data operator splits a processBytes() call that spans the buffered authentication tag into two output segments, the bytes released from the tag buffer and then the bytes taken straight from the caller's input, and wrote the second segment at the caller's output offset instead of after the first, so the second segment overwrote the head of the first and the tail of the reported output was never written at all. The call still returned the full byte count, and because the engine's state update depends on the input and the keystream rather than on where the output lands, the tag still verified: the wrong plaintext came back with no error raised. Any chunk after the first that carried more than the 8 byte tag length was affected. Grain-128AEAD is the only engine that uses this operator, and one shot decryption, the encryption path and every other AEAD engine were unaffected. The second segment is now written at the advanced offset, matching the equivalent step of the general decryption path (github PR #2447).

  • The AEAD stream cipher data operator, which Grain-128AEAD alone uses, wrote its output without first checking that the caller's buffer was long enough, so a short output buffer surfaced as an ArrayIndexOutOfBoundsException from inside the engine rather than as the OutputLengthException the general path reports for every other AEAD engine. Both directions of processBytes(), and processByte(), now check before anything is written or buffered, and only when the call releases output, as the general path does.

  • The RFC 9709 content-encryption AlgorithmIdentifier, which carries the real algorithm inside the parameters of an outer id-alg-cek-hkdf-sha256, was unwrapped at only one of the points where a CMS recipient makes a decision about it. Key-size validation was corrected for plain key transport in 1.86, but the same call in the KEK, RSA-KTS and KEM recipients, and in the key-transport recipient's own ORI-KEM branch, still compared the recovered key against the outer identifier, which registers no key size, so setKeySizeValidation(true) silently checked nothing there; the setAllowedContentAlgorithms allow-list and the setMinimumTagSize floor were applied to the outer identifier on every recipient family, including the one already corrected, so neither constrained an RFC 9709 message. The unwrap now happens once for the key-size check and once for the two policy checks, and every recipient polices and validates the content-encryption algorithm the message actually carries. A recipient with no allow-list, no tag floor and no key-size validation configured behaves exactly as before; a caller who listed id-alg-cek-hkdf-sha256 in an allow-list in order to admit RFC 9709 messages must now list the content-encryption algorithms themselves (github PR #2446).

  • A CMS message whose EncryptedContentInfo named the RFC 9709 key derivation but carried no readable content-encryption AlgorithmIdentifier in its parameters was reported as a NullPointerException, or as an IllegalArgumentException from the ASN.1 decoder, out of methods declared to throw CMSException, RecipientInformation.getContent() among them. The four places that resolve the wrapper - the CEK derivation, the content cipher selection, the key-size check, and the recipient's allowed-algorithm and tag-size checks - now share one resolver, which reports an absent or unreadable inner algorithm as a CMSException.

  • The two YubiKey OpenPGP smart-card decryptor factories zeroized the user PIN array the KeyPassphraseProvider handed them rather than a copy of it, in a finally block after each private-key operation. Both providers BC ships return the application's own array by reference - DefaultKeyPassphraseProvider hands back the char[] it has cached for the key, and the provider inside OpenPGPApi.editKey returns its argument - so the first card operation destroyed the caller's PIN and the next private-key operation presented an all-zero PIN to the card, which the card refuses at the cost of a PIN retry. The PIN is now fetched as a clone the card operation owns - in OpenPGPSmartCard.requireUserPin, where the smart-card restructuring of this release put the fetch the two factories used to make - and KeyPassphraseProvider.getKeyPassword records that the array it returns stays owned by the provider (github PR #2444).

  • The CRMF PKIPublicationInfo structure accepted, and could be built with, publication information RFC 4211 sec. 6.3 forbids: pubInfos MUST NOT be present if the action is dontPublish, and the field is SEQUENCE SIZE (1..MAX), so a present one is never empty. Both contradictions are now rejected with an IllegalArgumentException, on parsing and on construction from an array of SinglePubInfo. An absent pubInfos with the pleasePublish action, which is how the RFC spells "don't care", is unaffected, and no constructor in the library could produce either rejected form.

  • The CMS RFC 8418 key agreement schemes (dhSinglePass-stdDH-hkdf-sha256/384/512, used with X25519 and X448) derived the key-encryption key with the user keying material in the entityUInfo of the ECC-CMS-SharedInfo but never as the HKDF salt, where RFC 8418 sec. 2.2 requires both - its recipe is salt = ukm, PRK = HKDF-Extract(salt, K), KEK = HKDF-Expand(PRK, DER(ECC-CMS-SharedInfo), SizeInOctets(KEK)). A message carrying a ukm therefore did not interoperate with a conforming implementation in either direction. The ukm is now passed as the salt as well, on both the generating and the receiving side, for those three schemes. A message with a ukm written by 1.86, the only release with RFC 8418 support, is not readable by this release and vice versa; messages without a ukm, and the X9.63-KDF key agreement schemes, are unaffected. The round-trip test now covers both the ukm and no-ukm cases for all six curve and scheme combinations, and checks the key-encryption key against the RFC's own recipe rather than only against BC itself (github #2454).

  • A JKS store shorter than the SHA-1 checksum it ends with threw an unchecked ArrayIndexOutOfBoundsException out of KeyStore.load, which declares IOException for a store it cannot read: JKSKeyStoreSpi.validateStream subtracted the digest size from the raw store length without checking it, so the digest update clamped its negative length to zero and the System.arraycopy that lifted the stored checksum out failed on a negative source index. The length is now checked against the checksum plus the 12-byte header before the checksum position is used, and a store too short to carry either is reported as an EOFException. The JKS store is reached through the compatibility probe in AdaptingKeyStoreSpi, so any key store type that probes for it was exposed, and the legacy jdk1.1 and jdk1.4 provider copies carry the same fix (github #2451).

  • A custom Argon2BytesGenerator.BlockPool was left to zeroise the blocks it recycled itself, and had no way to know how many blocks to hold: the generator returned each block to the pool with the password-derived data still in it, so only the FixedBlockPool BC ships cleared them, and sizing any other pool meant replicating the internal memory alignment and the block count of the fill step. The generator now clears every block before it goes back, so a pool neither has to clear nor can observe that data, and Argon2BytesGenerator.getBlockCount(memory, lanes) gives the number of blocks a run takes - which the default pool now uses, so it no longer discards and reallocates the four blocks of the fill step on every call. FixedBlockPool drops the two clears it no longer needs, leaving one zeroisation per block per use rather than two, and a generateBytes() that fails part way through now returns and clears the blocks it took, along with its own working buffer, rather than leaving both to the garbage collector (github #2452).

  • The PKCS#12 key stores wrote the MAC key-derivation parameters of a file they had loaded into every file they wrote afterwards, under whatever password the caller stored with. For PKCS12-PBMAC1 that carried the loaded file's PBKDF2 salt, iteration count, key length and PRF, because the parameters were minted only when the store held none and were then assigned back, so the branch ran once per store object rather than once per write - which also meant one store reused a single PBKDF2 salt across every write, including writes under different passwords, with no file loaded at all. The classic store inherited the MAC salt length and digest algorithm the same way, so a file declaring a zero-length MAC salt was re-stored with one, and a file it had loaded under RFC 9579 handed on that file's PBKDF2 salt too, both stores reading PBMAC1. The values were also latched before the MAC was verified and were not cleared by the load(null, null) a caller must issue to recover, so a file that failed the check left them behind for the caller's own file. The PBKDF2 salt and the MAC salt are now generated for every write, the MAC salt at no fewer than 8 octets, nothing is latched until the file has verified, and an AlgorithmIdentifier supplied through a PKCS12StoreParameter is still written as it was given. A loaded file's PRF, key length, digest algorithm and MacData iteration count are still kept, the last as before; the PBKDF2 count is kept where it is at least the count being written with and raised to it otherwise, since the file being re-stored is not the one that count was chosen for - RFC 9579's own test vectors ask for 2048. That count is now org.bouncycastle.pkcs12.pbkdf2_it_count, default 65,536, the write-side counterpart for a PBMAC1 MAC of what org.bouncycastle.pkcs12.store_it_count is for the PBE. Reading is unaffected: a file's MAC is verified with the parameters it carries, whatever they are (github #2450).

  • Cipher.SM9 took its data-encapsulation mode for decryption from the ciphertext rather than from the mode the Cipher was configured with. The GM/T 0080-2020 SM9Cipher structure names the mode in an enType field, but GM/T 0044.4 defines the authenticator as C3 = MAC(K2, C2), over the encapsulated message alone, so enType is not covered by it: re-encoding a ciphertext with the other enType leaves C1, C3 and C2 untouched and steers the recipient into the other mode. GM/T 0044.4 takes K1 and K2 from a single KDF output of klen = mlen + K2_len bits in stream mode and K1_len + K2_len bits in SM4 mode, where K1_len = 128, so when C2 is 16 bytes long the two modes make the identical KDF call and derive the same K1 and K2: a one-block SM4 ciphertext relabelled as stream mode passes the MAC check and the recipient returns K1 xor C2 - from which both the SM4 key K1 and the padded plaintext block follow, wherever that output is observable. CipherSpi now decrypts in the configured mode and rejects a ciphertext whose enType disagrees with it, so the mode is symmetric between encryption and decryption. That check compares two values a relabelling attacker can make agree, and so does not by itself protect a recipient whose Cipher is configured for stream mode - the relabelled one-block ciphertext then matches the configuration - so SM9Engine additionally refuses a 16-byte C2, the one C2 length at which the two modes collide, in both modes and both directions: on decryption, and on encryption a 16-byte message in stream mode and a message of fewer than 16 bytes, which pads to one block, in SM4 mode. Refusing the length on decryption protects the recipient that does so, but the message a relabelled ciphertext gives away is the SM4-mode sender's, who cannot tell whether the recipient's implementation refuses it, which is why the SM4 mode no longer produces one; messages of every other length are unchanged in both modes. A stream-mode ciphertext must accordingly be decrypted through a stream-mode Cipher ("SM9/XOR/NoPadding") rather than the SM4-mode default that Cipher.getInstance("SM9") gives; a message of fewer than 16 bytes has to be sent in stream mode, and one of exactly 16 bytes - a 128-bit key, say - in SM4 mode; and a ciphertext made by an earlier version whose C2 is 16 bytes long is no longer decrypted, whichever mode wrote it - a one-block SM4-mode ciphertext, or a stream-mode one carrying a 16-byte message. The SM9 KEM is unaffected.

  • Decrypting an OpenPGP message in two steps - recovering the session key from a SKESK packet and then decrypting the SEIPD v1 body through PGPEncryptedDataList.extractSessionKeyEncryptedData() - stopped detecting a wrong passphrase. 1.86 suppressed the legacy CFB "quick check" on the two repeated prefix bytes for every session-key decryption, to close the Mister-Zuccherato oracle on the path a PKESK session key reaches, but the same class also carries password-derived session keys, where reporting the check is what identifies a wrong passphrase and lets the next passphrase or SKESK packet be tried. A SKESK v4 packet deriving the session key from the S2K output directly (no encrypted session key) yields a well formed session key for any passphrase, so a wrong one no longer failed at all: it surfaced as a parse or integrity failure further down the stream. BouncyCastle's own high-level API decrypts this way, so OpenPGPMessageProcessor took the first wrong passphrase offered for a success and never tried the remaining ones. A new PGPEncryptedDataList.extractSessionKeyEncryptedData(boolean) states whether the session key came from a password: true restores the check and with it the PGPDataValidationException on a wrong passphrase, the existing no-argument method goes on suppressing it, and the high-level API passes true on its passphrase paths alone, so a session key recovered from a public key operation is still never quick checked (github #2459).

  • Both copies of PKIXCertPathReviewer (org.bouncycastle.pkix.jcajce and the legacy org.bouncycastle.x509) took the first date-valid CRL issued by the certificate's issuer as an answer about that certificate, applying neither of the RFC 5280 sec. 6.3.3 rules that decide whether a CRL covers it: the (b)(2)(i) match between a name in the CRL's issuing distribution point and a name in the certificate's distribution point, and the (d) intersection of the revocation reasons the two assert. Only the (b)(2)(ii) to (iv) onlyContains booleans were applied. A CA-signed, in-date CRL with no entries, scoped to another distribution point or to a partition of the revocation reasons, was therefore reported as proof of non-revocation - isValidCertPath() true with an empty error list for a certificate its own CA had revoked for key compromise, where CertPathValidator("PKIX") rejects the same chain against the same trust anchor - and it suppressed the distribution point fetch that would otherwise have retrieved the authoritative CRL. Where the reviewer makes the trust decision rather than serving as diagnostics beside a real validation this is a revocation bypass, and SignedMailValidator (bcmail) reaches it with the CRLs carried inside the signed message. Both copies now apply the (b)(2)(i) name match and require a CRL to cover every revocation reason before it can settle the certificate's status, through the public PKIXCRLValidator helpers the validation engine already uses, and keep looking when a candidate does not qualify - falling back, as before, to the distribution point fetch and then to the existing "no valid CRL found" error. A CRL carrying no issuing distribution point, one naming the certificate's own distribution point, and one naming the certificate issuer (the distribution point the engine falls back to) are all still accepted.

  • RFC3280CertPathUtilities.checkCRL threw java.lang.NullPointerException rather than a CertPathValidatorException when every candidate CRL for a distribution point was skipped instead of rejected, which is what happens when the reasons a CRL covers add nothing to those already checked - the RFC 5280 sec. 6.3.3 (d) case - since the exception it rethrows is only ever recorded in a catch block. Validation failed closed either way, but outside the declared contract of CertPathValidator.validate(); a run with nothing recorded now reports "No valid CRL found.". All four copies are corrected: pkix, prov, and the prov jdk1.3 and jdk1.4 overlays.

  • TupleHash prefixed an element of 2^28 bytes or more with a length computed in int arithmetic: org.bouncycastle.crypto.digests.XofUtils built the encode_string prefix of NIST SP 800-185 sec. 2.3.3 as left_encode(len * 8) with len an int, so the bit length wrapped before it reached the long parameter it was passed to. A single 256 MiB update wrapped it negative, and left_encode sizes its output by shifting its argument right eight bits at a time, which never reaches zero from a negative value, so the call did not return; at 512 MiB the length wrapped to zero and the element carried the prefix of an empty one, letting two different tuples absorb the same byte string - the ambiguity the tuple encoding of sec. 5.3 exists to prevent. The multiply is now widened, as the other left_encode and right_encode call sites in CSHAKEDigest, KMAC, TupleHash and ParallelHash already were, and left_encode and right_encode refuse a negative length rather than spinning on one, so a negative output length handed to the three-argument doFinal of TupleHash, ParallelHash or KMAC reports IllegalArgumentException instead of not returning. An element below 2^28 bytes is unaffected, the two arithmetics agreeing exactly there.

  • KeyAgreement.init() reported an initialisation it could not carry out as an unchecked exception for the unified and VKO agreements, where the JCA declares InvalidKeyException and InvalidAlgorithmParameterException. The ECCDHU and X25519U/X448U services took a plain UserKeyingMaterialSpec, or no spec at all, and carried it into the agreement, throwing ClassCastException from the cast that follows; the DHU and DH MQV services accepted the initialisation and then threw NullPointerException from doPhase, where the absent spec is read back; and the ECGOST3410 and ECGOST3410-2012 VKO services put a null where the UKM belongs, although RFC 7836 sec. 4.3 makes the UKM optional with the value 1. Each of them now reports a parameter error as ECMQV already did, and the VKO agreements apply the RFC 7836 default, so an agreement initialised without a UserKeyingMaterialSpec derives the key a UKM of 1 gives rather than failing. The user keying material itself was not being dropped anywhere: every key agreement service carrying a key derivation function was checked for it.

  • The RFC 5990 RSA-KTS CMS recipients (JceKTSKeyTransEnvelopedRecipient and JceKTSKeyTransAuthenticatedRecipient, through JceKTSKeyUnwrapper) took the keyLength carried in the message's RsaKemParameters as the number of octets for the key encapsulation mechanism to derive, and only compared it with the key-wrapping algorithm once the derivation had been done. EnvelopedData is not integrity protected and the recipient reaches this before anything about the message has been verified, so the declared length decided how much the key derivation function was asked to produce, and a large enough one also overflowed the bit count it was converted into. RFC 5990 sec. 4 fixes the length of the derived key as the key length of the data encapsulation mechanism's key-wrapping algorithm, so the recipient now derives that length and rejects a keyLength which disagrees with it before deriving anything, reporting it as the CMSException the API declares - the check the RFC 9629 KEMRecipientInfo path already made against its kekLength.

  • The read-side well-formedness checks on UTCTime and GeneralizedTime bounded the day at 01-31 without regard to the month, so the 30th of February, the 31st of April and the 29th of February in a common year were all accepted and the lenient calendar behind getDate() rolled each into the following month: "180230101423Z" was read back as the 2nd of March 2018, an instant some other encoding already denotes, and a certificate validity or CRL update time could name a day that does not exist. The day is now checked against the length of the month, February following the Gregorian leap rule and a UTCTime's two-digit year resolved through the RFC 5280 sec. 4.1.2.5.1 window, so such a value is rejected on read as OpenSSL rejects it. The JDK's own CertificateFactory accepts and rolls these, so org.bouncycastle.asn1.allow_non_der_time - already the switch for the write-side DER restrictions - also admits the impossible day for a caller that has to read what it accepts; the impossible month and the zero day stay rejected either way.

  • When the provider's CertPathBuilder validated the certification path of an indirect CRL's signer, it did so with the builder defaults rather than the caller's PKIXBuilderParameters: the maximum path length was always 5 and the excluded certificates set was always empty, so a signer the caller had excluded could still vouch for a CRL, a caller's tighter path length limit was not applied to the signer's path, and a caller's looser one (or no limit at all) could leave a longer but otherwise valid signer path rejected. Both settings now carry through to the CRL signer's path build.

  • The provider's CertPathBuilder applied PKIXBuilderParameters.setMaxPathLength() one certificate too leniently, building a path with one intermediate certificate more than the limit (so a limit of 0 admitted a target and one intermediate, and the default of 5 admitted six), and counted self-issued certificates against it. The limit now counts the non-self-issued intermediate certificates, as PKIXBuilderParameters defines it, so a path which only built because of the extra certificate, one with six intermediates under the default limit for example, now needs the limit raised.

  • The DSTU 7624 (Kalyna) GCM mode and MAC, KGCMBlockCipher and KGMac, accepted an operation with both the associated text and the data empty, which DSTU 7624:2014 sec. 12.1 excludes. Its tag is then E_K(0), which is the GHASH key itself: Kalyna GCM does not mask the tag with a nonce-derived block as NIST GCM does, so a caller who authenticated an empty message disclosed the authentication key, and anyone holding it can construct a different message with the same tag as any other message seen under that key. The decrypting side accepted E_K(0) as the tag of an empty message in the same way. Both directions now reject the case, encryption and KGMac with a DataLengthException and decryption with an InvalidCipherTextException; either one of the associated text and the data may still be empty. The Mac.DSTU7624GMAC services were affected through KGMac.

... (truncated)

Commits

Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore <dependency name> major version will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself)
  • @dependabot ignore <dependency name> minor version will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself)
  • @dependabot ignore <dependency name> will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself)
  • @dependabot unignore <dependency name> will remove all of the ignore conditions of the specified dependency
  • @dependabot unignore <dependency name> <ignore condition> will remove the ignore condition of the specified dependency and ignore conditions
    You can disable automated security fix PRs for this repo from the Security Alerts page.

Bumps the maven group with 1 update in the / directory: [org.bouncycastle:bcpkix-jdk18on](https://github.com/bcgit/bc-java).


Updates `org.bouncycastle:bcpkix-jdk18on` from 1.76 to 1.84
- [Changelog](https://github.com/bcgit/bc-java/blob/main/docs/releasenotes.md)
- [Commits](https://github.com/bcgit/bc-java/commits)

---
updated-dependencies:
- dependency-name: org.bouncycastle:bcpkix-jdk18on
  dependency-version: '1.84'
  dependency-type: direct:production
  dependency-group: maven
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot Bot added dependencies Pull requests that update a dependency file java Pull requests that update java code labels Sep 28, 2026
@Sporiff Sporiff closed this Sep 29, 2026
@Sporiff
Sporiff deleted the dependabot/maven/maven-2531a232e3 branch September 29, 2026 14:12
@dependabot @github

dependabot Bot commented on behalf of github Sep 29, 2026

Copy link
Copy Markdown
Contributor Author

This pull request was built based on a group rule. Closing it will not ignore any of these versions in future pull requests.

To ignore these dependencies, configure ignore rules in dependabot.yml

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file java Pull requests that update java code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant