You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit e0dce82
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: docs/releasenotes.html
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -195,7 +195,7 @@ <h3>2.1.3 Additional Features and Functionality</h3>
195
195
<li>SMAUG-T post-quantum key encapsulation mechanism (Module-Lizard / MLWE+MLWR), per the SMAUG-T v1.2.0 reference specification. Lightweight implementation in org.bouncycastle.pqc.crypto.smaugt covering all four parameter sets — smaugt_mode1, smaugt_mode3, smaugt_mode5 (NIST security categories 1/3/5) and smaugt_modet (TiMER, the bandwidth-optimised variant using the D2 encoding) — via SmaugTKeyPairGenerator, SmaugTKEMGenerator, SmaugTKEMExtractor and the matching SmaugTPublicKeyParameters / SmaugTPrivateKeyParameters. KAT-tested against the four PQCkemKAT_smaugt_*.rsp test vectors from the SMAUG-T reference distribution (100 cases per parameter set). JCE provider plumbing is registered through BCPQC: KeyPairGenerator.SmaugT, KeyFactory.SmaugT, KeyGenerator.SmaugT, Cipher.SmaugT (key wrap/unwrap), SmaugTParameterSpec (four constants + fromName lookup), SmaugTKey interface and BCSmaugTPublicKey / BCSmaugTPrivateKey. Four BC-arc OIDs in BCObjectIdentifiers (pqc_kem_smaugt.{1..4}) cover the SubjectPublicKeyInfo / PrivateKeyInfo wire form via the PublicKeyFactory / PrivateKeyFactory / SubjectPublicKeyInfoFactory / PrivateKeyInfoFactory converter plumbing, and BouncyCastleProvider.loadPQCKeys() registers a SmaugTKeyFactorySpi against each OID so the standard BC provider can decode SMAUG-T-bearing certificates and PKCS#8 keys without BCPQC in the lookup chain. The decode paths validate their input lengths up front: SmaugTPublicKeyParameters and SmaugTPrivateKeyParameters reject an encoding whose length does not match the parameter set, and SmaugTKEMExtractor rejects an encapsulation of the wrong length, so a malformed key or ciphertext arriving through PublicKeyFactory / PrivateKeyFactory fails with an IllegalArgumentException at decode time rather than an ArrayIndexOutOfBoundsException later during encapsulation or decapsulation; BCSmaugTPrivateKey.hashCode() derives from the parameter set rather than the secret private encoding.</li>
196
196
<li>Server-side OCSP stapling with the org.bouncycastle.tls API is now documented and covered by an example. The protocol support has been in place for some time - AbstractTlsServer echoes a client's "status_request" (RFC 6066 sec. 8) or "status_request_v2" (RFC 6961 sec. 2.2) extension, and TlsServerProtocol / DTLSServerProtocol then send whatever TlsServer.getCertificateStatus() returns as a "certificate_status" message - but the callback's contract was not spelled out. Its javadoc, and that of AbstractTlsServer.allowCertificateStatus() / allowMultiCertStatus(), now describe when the callback is reached, how SecurityParameters.getStatusRequestVersion() selects between a single ocsp response and an ocsp_multi list ordered against the certificate chain, and that TLS 1.3 does not use this path (RFC 8446 sec. 4.4.2.1 carries the response in a per-CertificateEntry extension instead). A new misc-module example, org.bouncycastle.tls.examples.OCSPStaplingServerExample, runs both variants end to end. Note this is the low-level TLS API; for the BCJSSE provider see the following entry. See github issue #1157.</li>
197
197
<li>Server-side OCSP stapling with the org.bouncycastle.tls API now also works in TLS 1.3, where it previously had no protocol support at all: RFC 8446 sec. 4.4.2.1 replaces the "certificate_status" handshake message with a "status_request" extension on the CertificateEntry carrying the certificate each response answers for, and TlsServerProtocol assembles those itself from the same TlsServer.getCertificateStatus() callback the earlier versions use, rather than leaving a TlsServer implementation to attach them to the Certificate its credentials supply - which was the only way to staple in TLS 1.3 and is not something the callback's shape suggested. The two shapes the callback may return are both accepted: a CertificateStatusType.ocsp status answers for the end-entity certificate, and an ocsp_multi status answers positionally, entry i of its list for certificate i of the chain, so a server with responses for the intermediates as well returns the ocsp_multi shape even though the status request version is 1 in TLS 1.3. An entry the server has itself given a "status_request" extension is left as it stands, so an implementation already doing this by hand is unaffected. A response too large for the entry to carry is dropped rather than stapled: a CertificateEntry's extensions are written with a 16-bit length, leaving room for 65527 bytes of response where the entry has no other extensions, and nothing bounds an OCSP response below that, so letting one through would cost the handshake rather than just the staple. The wire form of the extension is now created and read through TlsExtensionsUtils.createStatusRequestExtension13 / readStatusRequestExtension13, alongside the create/read pair every other extension has; the BCJSSE provider, which had been encoding it privately, goes through the same path. See github issue #1157.</li>
198
-
<li>Client-side OCSP stapling with the org.bouncycastle.tls API now works in TLS 1.3, where TlsServerCertificate.getCertificateStatus() had always answered null: the value it returns is set from the "certificate_status" message, and RFC 8446 sec. 4.4.2.1 sends no such message, carrying each response in a "status_request" extension of the CertificateEntry holding the certificate it answers for instead. A low-level client was left to read those extensions itself, which only the BCJSSE provider did. The client now reads them as the Certificate message arrives - the exact inverse of what a BC server does when it staples - and hands them back through the new TlsServerCertificate.getCertificateStatusAt(int), one per certificate of getCertificate(), null where that certificate was left unstapled. This reads the same way whichever version was negotiated: up to TLS 1.2 the ocsp_multi list of a "certificate_status" message is positional in the same sense (RFC 6961 sec. 2.2), so a caller pairing responses with the certificates they answer for no longer has to know which version delivered them. getCertificateStatus() is unchanged up to TLS 1.2, where it remains the message as it arrived, and in TLS 1.3 answers for the end-entity certificate. Two consequences worth noting. TlsServerCertificate has gained a method, so an implementation of that interface outside BC will not compile until it adds one - BC constructs the only implementation itself, so a caller that merely receives one through TlsAuthentication.notifyServerCertificate is unaffected. And a client that asked for a staple now reads what arrives, so a server that mis-staples in TLS 1.3 - an extension carrying trailing bytes, the ocsp_multi form RFC 8446 does not admit there, or an unparseable body - fails the handshake with a decode_error alert where the bytes previously went unread; AbstractTlsClient.getCertificateStatusRequest() asks for a staple by default, so this applies unless a client overrides it to return null. A staple the client did not ask for is still ignored rather than made a handshake failure. The BCJSSE client, which took this strictness when it began reading TLS 1.3 staples, now shares the one implementation rather than carrying its own (github #1485).</li>
198
+
<li>Client-side OCSP stapling with the org.bouncycastle.tls API now works in TLS 1.3, where TlsServerCertificate.getCertificateStatus() had always answered null: the value it returns is set from the "certificate_status" message, and RFC 8446 sec. 4.4.2.1 sends no such message, carrying each response in a "status_request" extension of the CertificateEntry holding the certificate it answers for instead. A low-level client was left to read those extensions itself, which only the BCJSSE provider did. The client now reads them as the Certificate message arrives - the exact inverse of what a BC server does when it staples - and hands them back through the new TlsServerCertificate.getCertificateStatusAt(int), one per certificate of getCertificate(), null where that certificate was left unstapled (and for an index that names no certificate of the chain). This reads the same way whichever version was negotiated: up to TLS 1.2 the ocsp_multi list of a "certificate_status" message is positional in the same sense (RFC 6961 sec. 2.2), so a caller pairing responses with the certificates they answer for no longer has to know which version delivered them. getCertificateStatus() is unchanged up to TLS 1.2, where it remains the message as it arrived, and in TLS 1.3 answers for the end-entity certificate. Two consequences worth noting. TlsServerCertificate has gained a method, so an implementation of that interface outside BC will not compile until it adds one - BC constructs the only implementation itself, so a caller that merely receives one through TlsAuthentication.notifyServerCertificate is unaffected. And a client that asked for a staple now reads what arrives, so a server that mis-staples in TLS 1.3 - an extension carrying trailing bytes, the ocsp_multi form RFC 8446 does not admit there, or an unparseable body - fails the handshake with a decode_error alert where the bytes previously went unread; AbstractTlsClient.getCertificateStatusRequest() asks for a staple by default, so this applies unless a client overrides it to return null. A staple the client did not ask for is still ignored rather than made a handshake failure. The BCJSSE client, which took this strictness when it began reading TLS 1.3 staples, now shares the one implementation rather than carrying its own (github #1485).</li>
199
199
<li>org.bouncycastle.operator.DefaultAlgorithmNameFinder now names KEM algorithm OIDs, which it previously did not do for any KEM at all - getAlgorithmName() handed back the OID string unchanged. Added: ML-KEM (FIPS 203, the three NIST OIDs); and FrodoKEM and Classic McEliece on the ISO/IEC 18033-2 arc, which is what the BC provider registers them under, all eight and all sixteen parameter sets respectively. The coverage is restricted to the standardised assignments - BouncyCastle's own pre-standard arcs for these two families, including a Classic McEliece 348864 that ISO never published, are deliberately left unnamed as those parameters are to be phased out. Names follow the canonical form the matching lightweight parameter class uses - MLKEMParameters.getName(), FrodoKEMParameters.getName(), CMCEParameters.getName() - so they are also the names the BC provider registers the algorithms under. NTRU and HQC remain unnamed.</li>
200
200
<li>org.bouncycastle.operator.KemAlgorithmIdentifierFinder and its DefaultKemAlgorithmIdentifierFinder implementation are the KEM counterpart of SignatureAlgorithmIdentifierFinder, turning a KEM algorithm name into the AlgorithmIdentifier that names it in a SubjectPublicKeyInfo, a CMS KEMRecipientInfo (RFC 9629) or a CMP KemCiphertextInfo - previously a caller had to assemble that identifier from the OID constants by hand, as BouncyCastle's own TLS and composite-KEM code still does through private switches. Names are matched without regard to case and cover the same set the name finder now names, so the two directions round-trip; an unrecognised name raises IllegalArgumentException rather than returning null, and hasAlgorithm(String) tests for support without catching, in the same way AlgorithmNameFinder.hasAlgorithmName does for the reverse direction. DefaultSignatureAlgorithmIdentifierFinder gains the same hasAlgorithm(String) method; it sits on the implementation rather than on SignatureAlgorithmIdentifierFinder, since adding a method to that long-published interface would break every implementation outside the library. Each KEM parameter set has its own OID, so every identifier returned has an absent parameters field - compare received identifiers with AlgorithmIdentifier.areEquivalent rather than equals, so a peer that spells the algorithm with an explicit NULL still matches. A new parent interface, org.bouncycastle.operator.AlgorithmIdentifierFinder, carries the shared find(String) contract, extended by SignatureAlgorithmIdentifierFinder, KemAlgorithmIdentifierFinder and DigestAlgorithmIdentifierFinder - the finders that behave alike, matching names without regard to case and throwing IllegalArgumentException for a name they do not recognise. MacAlgorithmIdentifierFinder stays outside the hierarchy, as it returns null for an unrecognised name instead. Existing implementations are unaffected, as the parent requires only the method its subinterfaces already declared. Two changes to DefaultDigestAlgorithmIdentifierFinder bring it into that contract. Its name lookup now throws IllegalArgumentException("Unknown digest algorithm requested: ...") where it used to return null, matching the signature and KEM finders; its other two overloads are untouched, so find(AlgorithmIdentifier) still returns null when it cannot derive a digest from a signature algorithm, which github #1767 relies on, and a name given in dotted OID form is still read as one. Callers that treated the null as an error are unaffected beyond the exception type - org.bouncycastle.est.HttpAuth, the only one in the library that branched on it, still reports an unrecognised HTTP Digest algorithm as an IOException - while JcaContentSignerBuilder and JcaAlgorithmParametersConverter, which dereferenced the result without checking, now name the offending algorithm instead of raising a bare NullPointerException. DefaultDigestAlgorithmIdentifierFinder also gains a hasAlgorithm(String), answering for exactly the names find(String) accepts - the digest name table or a name in dotted OID form - so the two cannot disagree. And name matching now folds case in all four finders: DefaultDigestAlgorithmIdentifierFinder was the one that did not, looking its digest names up verbatim, and it now upper cases the supplied name first. Every key in its table was already upper case, so that only widens what matches and cannot change a lookup that already succeeded; a name given in dotted OID form is still passed through unfolded.</li>
201
201
<li>org.bouncycastle.jcajce.provider.util.SecurityExceptions gained an invalidAlgorithmParameterException(String, Throwable) factory, for the same reason as its siblings: java.security.InvalidAlgorithmParameterException only grew a cause-taking constructor in Java 5, so code that has to compile for the legacy Java 4 distributions attaches the cause through initCause instead. Use the factory rather than rolling that call at the throw site.</li>
0 commit comments