dependabot[bot] opened a new pull request, #3022:
URL: https://github.com/apache/tomee/pull/3022

   Bumps [org.bouncycastle:bcpkix-jdk18on](https://github.com/bcgit/bc-java) 
from 1.85 to 1.86.
   <details>
   <summary>Changelog</summary>
   <p><em>Sourced from <a 
href="https://github.com/bcgit/bc-java/blob/main/docs/releasenotes.md";>org.bouncycastle:bcpkix-jdk18on's
 changelog</a>.</em></p>
   <blockquote>
   <h1>Bouncy Castle Crypto Package - Release Notes</h1>
   <h2>1.0 Introduction</h2>
   <p>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.</p>
   <h2>2.0 Release History</h2>
   <p><!-- raw HTML omitted --><!-- raw HTML omitted --></p>
   <h3>2.1.1 Version</h3>
   <p>Release: 1.87<br />
   Date: 2026, TBD</p>
   <h3>2.1.2 Defects Fixed</h3>
   <ul>
   <li>
   <p>A PBEKey stored in a BCFKS KeyStore was not reported as a key entry: 
isKeyEntry() returned false for it, so KeyStore.getEntry() returned null rather 
than a SecretKeyEntry, although getKey() recovered it. The PBE key entry type 
added for github <a 
href="https://redirect.github.com/bcgit/bc-java/issues/2164";>#2164</a> was 
missing from engineIsKeyEntry, and is now included.</p>
   </li>
   <li>
   <p>The CMS content-type decoders SignedData, EnvelopedData, 
AuthenticatedData, AuthEnvelopedData and EncryptedData read their mandatory 
fields by index or enumeration with no lower-bound size check, so a ContentInfo 
whose inner content was an empty or too-short SEQUENCE - malformed but 
DER-parseable - left the decode as an unchecked NoSuchElementException or 
ArrayIndexOutOfBoundsException rather than the CMSException the CMSSignedData, 
CMSEnvelopedData, CMSAuthenticatedData and CMSAuthEnvelopedData constructors 
declare (the IllegalArgumentException CMSEncryptedData documents). Each now 
rejects a short sequence with IllegalArgumentException before reading, as the 
sibling content types CompressedData and DigestedData already did, so the 
wrappers surface it as their declared exception; the case that claims an 
OPTIONAL field and then truncates the mandatory ones after it is covered too. 
The streaming parsers CMSSignedDataParser, CMSEnvelopedDataParser, 
CMSAuthenticatedDataParser, CMSA
 uthEnvelopedDataParser and CMSCompressedDataParser had the same gap and more: 
an absent or truncated inner SEQUENCE, a mandatory field of the wrong type, or 
absent encapsulated or encrypted content escaped as NullPointerException, 
ClassCastException, IllegalArgumentException or IllegalStateException. The 
asn1.cms stream parsers now report a missing mandatory field as an IOException, 
and the CMS parsers report malformed content as CMSException (&quot;Malformed 
content.&quot; / &quot;Missing content.&quot;) or the IOException they 
declare.</p>
   </li>
   <li>
   <p>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(&quot;AES&quot;) 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.</p>
   </li>
   <li>
   <p>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.</p>
   </li>
   <li>
   <p>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.</p>
   </li>
   <li>
   <p>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%.</p>
   </li>
   <li>
   <p>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 <a 
href="https://redirect.github.com/bcgit/bc-java/issues/707";>#707</a>).</p>
   </li>
   <li>
   <p>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 &quot;example.com..&quot; 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 &quot;example.com..&quot; 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 &quot;.&quot; 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 &quot;subdomains 
only&quot; (github PR <a 
href="https://redirect.github.com/bcgit/bc-java/issues/2436";>#2436</a>).</p>
   </li>
   <li>
   <p>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 <a 
href="https://redirect.github.com/bcgit/bc-java/issues/2448";>#2448</a>).</p>
   </li>
   <li>
   <p>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 wr
 ite 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.</p>
   </li>
   <li>
   <p>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 <a 
href="https://redirect.github.com/bcgit/bc-java/issues/2456";>#2456</a>).</p>
   </li>
   <li>
   <p>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.</p>
   </li>
   <li>
   <p>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.</p>
   </li>
   <li>
   <p>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 s
 egment is now written at the advanced offset, matching the equivalent step of 
the general decryption path (github PR <a 
href="https://redirect.github.com/bcgit/bc-java/issues/2447";>#2447</a>).</p>
   </li>
   <li>
   <p>The certificate path validators looked a certificate up in an indirect 
CRL by serial number alone and then compared the issuer of whichever entry came 
first, so where two issuers had each revoked the same serial number - an 
indirect CRL (RFC 5280 sec. 5.2.5) lists certificates from more than one 
issuer, and a serial number is only unique within its issuer - a certificate 
whose own entry followed the other issuer's was reported as not revoked. The BC 
provider's PKIX validator, the pkix X509RevocationChecker and the legacy 
org.bouncycastle.x509 validator now check every entry carrying the serial 
number against the issuer it applies to, the one named by its certificateIssuer 
extension or inherited from the entries before it (sec. 5.3.3), and the 
provider's X509CRL implements getRevokedCertificate(X509Certificate), the JDK's 
lookup for indirect CRLs, the same way rather than inheriting the default that 
assumes a single issuer. CRL.isRevoked() on the provider's CRLs had the same fau
 lt, stopping at the first entry carrying the serial number, and now does the 
same. The validators also missed, whatever the serial numbers, any revocation 
listed for an issuer other than the CRL issuer when the CRL had been parsed by 
the JDK's own provider, whose getRevokedCertificate(BigInteger) looks only at 
the CRL issuer's entries; they now look further whenever that lookup cannot be 
conclusive. In the jdk1.4 distribution the two provider validators read an 
entry's certificate issuer through a cast to a class the provider's own CRLs do 
not use, so an indirect CRL carrying an entry with the certificate's serial 
number failed validation with no reason given, whether or not that entry was 
the certificate's; they now share the lookup above.</p>
   </li>
   <li>
   <p>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.</p>
   </li>
   <li>
   <p>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 <a 
href="https://redirect.github.com/bcgit/bc-java/issues/2446";>#2446</a>).</p>
   </li>
   <li>
   <p>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.</p>
   </li>
   <li>
   <p>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 <a 
href="https://redirect.github.com/bcgit/bc-java/issues/2444";>#2444</a>).</p>
   </li>
   <li>
   <p>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 &quot;don't care&quot;, is unaffected, and no constructor in the 
library could produce either rejected form.</p>
   </li>
   <li>
   <p>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 <a 
href="https://redirect.github.com/bcgit/bc-java/issues/2454";>#2454</a>).</p>
   </li>
   <li>
   <p>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 <a 
href="https://redirect.github.com/bcgit/bc-java/issues/2451";>#2451</a>).</p>
   </li>
   <li>
   <p>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 <a 
href="https://redirect.github.com/bcgit/bc-java/issues/2452";>#2452</a>).</p>
   </li>
   <li>
   <p>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 f
 ailed 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 <a 
href="https://redirect.github.com/bcgit/bc-java/issues/2
 450">#2450</a>).</p>
   </li>
   <li>
   <p>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 r
 ejects 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 (&quot;SM9/XOR/NoPadding&quot;) rather than the 
SM4-mode default that Cipher.getInstance(&quot;SM9&quot;) 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.</p>
   </li>
   <li>
   <p>SM9 public-key encryption: Cipher.SM9 decrypted more than one encoding of 
a ciphertext and now takes only the DER encoding encryption produces, with a 
65-byte uncompressed C1 and a 32-byte C3; the SM9Cipher ASN.1 type holds C1 and 
C3 to those sizes too, and represents all five GM/T 0080-2020 enType values 
where it had refused SM4-CBC, -OFB and -CFB, which Cipher.SM9 does not 
implement. SM9Engine reports a ciphertext it cannot decrypt with the 
InvalidCipherTextException processBlock declares, where an out-of-range C1 
coordinate or an SM4-mode C2 of the wrong length had escaped as unchecked 
exceptions, and likewise a message too long for its SM4-mode ciphertext to fit 
an array, refuses one whose K1 is zero as it refuses one failing the MAC check, 
and after a refused init is left uninitialised rather than keyed as before. 
Cipher.SM9 counts buffered input in getOutputSize, keeps the input update() had 
buffered when doFinal throws ShortBufferException, so that the call can be 
repeat
 ed with a larger output buffer, throws that exception rather than an 
ArrayIndexOutOfBoundsException for an output offset near Integer.MAX_VALUE, 
reports its key size to a restricted crypto policy, refuses an 
AlgorithmParameterSpec on decryption as on encryption, refuses WRAP_MODE and 
UNWRAP_MODE with the UnsupportedOperationException javax.crypto.Cipher 
documents for them rather than an InvalidParameterException, and refuses a 
key-exchange or destroyed key at init with InvalidKeyException. A key destroyed 
after init is reported by the exception the operation declares for a state it 
cannot run in - sign() of Signature.SM9 with SignatureException, doFinal() of 
Cipher.SM9 and the phases of KeyAgreement.SM9 with IllegalStateException, 
decapsulate() of KEM.SM9-KEM with DecapsulateException - where Cipher.SM9 had 
reported a malformed ciphertext, sign() and decapsulate() an 
IllegalStateException neither declares, and the first phase of KeyAgreement.SM9 
had sent an ephemeral first. The encr
 yption keys, which the KEM and the key exchange share, are decoded only from 
the uncompressed form getEncoded() writes, with coordinates below q and G2 
membership checked, which a new SM9G2Point.isInSubgroup() also checks for a 
point built by arithmetic; a master public key at infinity is refused, and so, 
wherever it is formed, is a recipient whose derived point is at infinity; 
nothing encrypts or encapsulates to a recipient formed under HID_EXCHANGE 
(0x02), and no KEM or decryption key is derived or imported under it, though 
the hid may otherwise be any value the KGC publishes rather than only 0x02 or 
0x03; a null master public key or an empty identity is refused; key equality 
takes in the hid, usage, master public key and identity; a user private key 
imported through SM9EncPrivateKeyParameters.fromEncoded, fromEncodedExchangeKey 
or KeyFactory.SM9 is refused unless it is the key the KGC derives for its 
identity and hid under the master public key it is imported with, which costs a 
 pairing, where the four had been taken as given; and a new fromEncoded 
overload checks a master private key against the master public key its KGC 
published. Decryption's pairing starts its Miller loop from a random 
representative of the private key and blinds its inversions, the exponentiation 
by the sender's ephemeral no longer runs faster for a shorter exponent and 
works on its intermediate values multiplied by a random factor drawn for each 
call, and the derived keys, plaintext copies and KDF input are erased once 
used. The SM4 mode is documented as the SM4-ECB, no-IV form of the GM/T 
0044.5-2016 Annex D.1 example, which does not interoperate with peers following 
the official English edition (CBC with an untransmitted zero IV) or GB/T 
38635.2-2020 (a 16-byte IV at the front of C2). For all four SM9 functions: 
BouncyCastleProvider.getPublicKey and getPrivateKey now resolve the SM9 master 
keys; KeyFactory.SM9 answers to the SM9-ENC and SM9-SIGN names the keys report, 
reads a key on
 ly from the encoding getEncoded() writes, and gives a PKCS#8 spec from 
getKeySpec only for a master private key, where it had given a user private key 
one it could not read back; KeyPairGenerator.SM9-ENC and SM9-SIGN refuse a 
strength other than 256; the exported arithmetic, hash and KDF methods refuse 
arguments they cannot honour rather than truncating them; SM9P256V1Point 
refuses, with an UnsupportedOperationException, to write the compressed 
encoding SM9's G1 curve cannot read back; SM9Engine.getOutputSize refuses 
before init, where it had answered as for decryption; a master private key is 
decoded only from its 32 bytes, where an encoding of any length had been read 
as the scalar; on the signature side 
SM9SigMasterPrivateKeyParameters.generateUserKey refuses a null or empty 
identity, and SM9SigPrivateKeyParameters.fromEncoded a null or empty identity 
and a null master public key, as the encryption side does; SM9Sm3.h1 and h2 
take hlen from log2 n itself, as GM/T 0044.2 5.4.2 def
 ines it, rather than from n's bit length, which agree for SM9's N but not for 
every n the methods accept; the KGC's multiplications in G2 - [ks]P2 for a 
signature master key and [t2]P2 for each encryption user key - run a 
fixed-point comb over a table of multiples of P2, reading each entry in full 
and carrying the entries by a random factor drawn for each call, over a scalar 
blinded with a random multiple of N, and the subgroup check on a decoded G2 
point runs a chain of doublings and additions over the non-adjacent form of the 
BN parameter t from a random representative of the point, both in Jacobian 
coordinates, where they had worked in affine coordinates on the point and the 
scalar themselves; the multiplications of a point of G1 by a secret scalar - 
[ke]P1 for an encryption master key and [t2]P1 for each signing key, the 
signer's [l]ds and the ephemeral's multiple of the recipient's or the peer's 
point - blind the scalar in the same way and carry the entries they read by a 
rando
 m factor drawn for each call, reading each in full from an entry drawn at 
random, where they had read the scalar's own digits from entries that were the 
same for every call; the arithmetic in F_q and its extensions, which the 
pairing, G_T and G2 compute in, runs on fixed-width limbs in constant time, 
where it had run on BigInteger, G1's arithmetic in F_q reduces its sums, 
differences and products below q without branching on a comparison with q, and 
neither the exponentiation by a secret exponent in G_T, which reads its 
multipliers from a table in full, nor the multiplications by a secret scalar in 
G1 and G2 branch on the secret's bits; and a random source that yields nothing 
usable is reported rather than hanging a draw or settling it on 1.</p>
   </li>
   <li>
   <p>The SM9 KEM: KEM.SM9-KEM, KeyGenerator.SM9-KEM and the lightweight 
SM9KEMGenerator and SM9KEMExtractor now refuse, when the key or spec is handed 
over - the provider services with the checked exception their API declares - 
what they had accepted and then failed on or silently ignored: a KDF the 
provider does not service; a KDF other than the specs' default, or any 
otherInfo, in a KEMGenerateSpec or KEMExtractSpec, which the KeyGenerator had 
ignored, giving the same key whatever was asked for - KEM.SM9-KEM layers a KDF 
through a KTSParameterSpec; a key size that is not a positive whole number of 
bytes, which had given fewer bits than asked for or an empty key; and a 
key-exchange key, and, at the provider services, a destroyed key. After a 
refused init the KeyGenerator is left uninitialised, where generateKey() had 
gone on to throw a ClassCastException over the spec refused or to run the 
operation configured before it. A malformed encapsulation is reported as one 
rather than in a
 n internal class's words, and the encryption keys are checked as for 
encryption, the rules on recipients included. Decapsulation's pairing and 
encapsulation's exponentiation are hardened as decryption's and encryption's 
are, and the serialised pairing value, the KDF input and the KeyGenerator's 
copy of each secret are erased once used. SM9KEMGenerator refuses a recipient 
key of the wrong kind with IllegalArgumentException, as SM9Engine does, rather 
than with a ClassCastException.</p>
   </li>
   <li>
   <p>The SM9 key exchange: KeyAgreement.SM9 and the lightweight SM9KeyExchange 
each kept the ephemeral r after an exchange completed, so that it could be 
combined with a second peer value, where GM/T 0044.3 draws a fresh r for each 
exchange; both now discard it once the key is derived. KeyAgreement.SM9 also 
drops the previous session at the start of init and of a first phase, before 
examining the new arguments, so that a rejected call no longer leaves an 
earlier shared secret, key or ephemeral in place, and it refuses a destroyed 
key at init rather than after sending an ephemeral. SM9KeyExchange keeps its 
own copy of the peer identity and refuses a null or empty one, drops the 
confirmation tags of a completed exchange when another begins, and accepts only 
points of SM9's own G1, where a point of another curve had produced a 
&quot;shared key&quot;; and the key length must be a positive whole number of 
bytes, which KeyAgreement.SM9 and KEM.SM9-KEM had rounded in opposite 
directions. T
 he pairing on the private key and the exponentiations by r are hardened as for 
encryption, and the KDF input, the serialised pairing values and the inner hash 
of the confirmation tags are erased once used.</p>
   </li>
   <li>
   <p>SM9 signatures: Signature.SM9 accepted more than one encoding of a 
signature - a non-minimal DER length, h and S trading a byte across their 
boundary, S in the hybrid point form - and now verifies only the encoding 
sign() produces, the lightweight SM9Signer only h followed by S in uncompressed 
form, while the SM9Signature ASN.1 type holds h and S to their 32 and 65 bytes. 
The exponentiation by the signing nonce no longer runs faster for a shorter 
nonce and works on its intermediate values multiplied by a random factor drawn 
for each call, and the signing scalar l = (r - h) mod N is formed with the 
constant-time helper. Signature.SM9 draws the nonce from the SecureRandom 
handed to initSign, is left as initVerify left it however verify() returns, is 
left uninitialised by a refused init, where it had gone on signing or verifying 
under the key of the init before it, answers getParameters() with null and 
refuses a destroyed key at init; SM9Signer copies the identity it verifies unde
 r, refuses an empty identity, refuses parameters of the wrong kind and use 
before init with IllegalArgumentException and IllegalStateException, is left 
uninitialised by a refused init, catches an exception in verification only from 
decoding S, where it had reported any exception at all as a failed 
verification, and hashes the message as update() is given it, where it held all 
of it until it signed or verified and left copies of it behind. SM9Sm3.h2, 
which SM9Signer no longer calls, is deprecated. A user private key at infinity 
or in the hybrid form, and a master public key outside G2 or with a coordinate 
at or above q, are refused on decoding; key equality takes in the master public 
key and identity; a master private key can be checked on decoding against the 
master public key its KGC published, as for the encryption keys; and a user 
private key is checked on import against the master public key and identity it 
is filed under, as an encryption user key is, where one filed under anot
 her master public key or identity imported and made signatures that did not 
verify. SM9Signer also reports a key destroyed since init through the 
CryptoException generateSignature declares rather than as an 
IllegalStateException.</p>
   </li>
   <li>
   <p>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 &quot;quick check&quot; 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 
offe
 red 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 <a 
href="https://redirect.github.com/bcgit/bc-java/issues/2459";>#2459</a>).</p>
   </li>
   <li>
   <p>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(&quot;PKIX&quot;) rejects the same chain against the 
same trust anchor - and it suppressed the distribution point fetch that would o
 therwise 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 &quot;no valid CRL found&quot; 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.</p>
   </li>
   <li>
   <p>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 &quot;No valid CRL found.&quot;. All four copies are corrected: pkix, 
prov, and the prov jdk1.3 and jdk1.4 overlays.</p>
   </li>
   </ul>
   <!-- raw HTML omitted -->
   </blockquote>
   <p>... (truncated)</p>
   </details>
   <details>
   <summary>Commits</summary>
   <ul>
   <li>See full diff in <a 
href="https://github.com/bcgit/bc-java/commits";>compare view</a></li>
   </ul>
   </details>
   <br />
   
   
   [![Dependabot compatibility 
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=org.bouncycastle:bcpkix-jdk18on&package-manager=maven&previous-version=1.85&new-version=1.86)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
   
   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-automerge-start)
   [//]: # (dependabot-automerge-end)
   
   ---
   
   <details>
   <summary>Dependabot commands and options</summary>
   <br />
   
   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 this major version` will close this PR and stop 
Dependabot creating any more for this major version (unless you reopen the PR 
or upgrade to it yourself)
   - `@dependabot ignore this minor version` will close this PR and stop 
Dependabot creating any more for this minor version (unless you reopen the PR 
or upgrade to it yourself)
   - `@dependabot ignore this dependency` will close this PR and stop 
Dependabot creating any more for this dependency (unless you reopen the PR or 
upgrade to it yourself)
   
   
   </details>


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to