Skip to content

Commit c2e150a

Browse files
committed
OCSPResp and OCSPReq now report any malformed encoding as CertIOException, the OCSP ASN.1 types refuse a short SEQUENCE or an element of the wrong type with IllegalArgumentException and accept a non-DER signature BIT STRING, and the provider's OCSP revocation checking reports a response that will not decode as a CertPathValidatorException, relates to github #2468.
1 parent 7518003 commit c2e150a

20 files changed

Lines changed: 568 additions & 40 deletions

File tree

‎CONTRIBUTORS.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,7 @@ We also wish to acknowledge financial and collaborative support from [CISCO](htt
532532
- subbudvk \<https://github.com/subbudvk\> - initial author on S2K parser hardening work for OpenPGP API.
533533
- mkarasik \<https://github.com/mkarasik\> - initial work on EST server-side key generation (RFC 7030 4.4).
534534
- Bernd Prünster (A-SIT Plus) \<bernd.pruenster&#064;a-sit.at\> - reported lenient ASN.1 UTCTime/GeneralizedTime parsing accepting structurally malformed content, with fuzzing-derived test cases. Additional fuzzing around date validity as well.
535-
- Naveed Khan \<https://github.com/rootvector2\> - constant time comparison of membership and confirmation tags in the MLS API. Reported unbounded array allocation in the BKS/UBER keystore load path (OutOfMemoryError DoS from a crafted keystore) and introduction of a capped decompression limit in PGPCompressedData.getDataStream(), both with POC. Original submission creating S/MIME backing temp files with owner-only permissions (PR #2326). Rejecting empty sequences in the X.509 extension parsers whose RFC 5280 syntax is SEQUENCE SIZE (1..MAX) - CRLDistPoint, CertificatePolicies, ExtendedKeyUsage, PolicyMappings, and SubjectDirectoryAttributes (PR #2331). Hardening asn1.cms.SignerInfo decode to reject a non-INTEGER version or non-tagged unsignedAttrs via getInstance rather than leaking a ClassCastException (PR #2342). Fixing an off-by-4 header-length guard in the OpenPGP NotationData signature subpacket parser (PR #2346). Rejecting CR/LF in the S/MIME streaming writer header names and values (SMIMEEnvelopedWriter/SMIMESignedWriter withHeader) to prevent MIME header injection (PR #2348). Adding minimum-length guards to the SM2 decrypt and GOST28147/DSTU7624/DESede/RC2 key-wrap unwrap paths (PR #2359). Guarding the ECDH session-key length in the JCE OpenPGP decryptor (PR #2383). Fixing the identity fast-path type guards in the OER getInstance factories and the transposed isInstance arguments in OEROptional.getObject (PR #2373). Requiring the signature handed to AIMerSigner.verifySignature to be exactly the parameter set's signature size (PR #2401). Constant time comparison of the SRP-6a evidence messages (PR #2406). Surfacing a malformed TSTInfo in a time-stamp token as TSPException rather than an unchecked exception out of the TimeStampResponse constructors (PR #2415). Rejecting a PKCS#12 PBMAC1 KDF keyLength below the RFC 9579 sec. 9 floor of 20 octets (PR #2431). Initial implementation of the empty-label guard on name-constraint host matching, having found that the canonicalisation removed only one RFC 1034 root-label dot, so a dNSName, rfc822Name host or URI host carrying more than one matched no constraint at all (PR #2436). Initial implementation of the lookup of indirect CRL entries by issuer and serial number, having found that the certification path validators compared only the issuer of the first entry carrying a certificate's serial number (PR #2464).
535+
- Naveed Khan \<https://github.com/rootvector2\> - constant time comparison of membership and confirmation tags in the MLS API. Reported unbounded array allocation in the BKS/UBER keystore load path (OutOfMemoryError DoS from a crafted keystore) and introduction of a capped decompression limit in PGPCompressedData.getDataStream(), both with POC. Original submission creating S/MIME backing temp files with owner-only permissions (PR #2326). Rejecting empty sequences in the X.509 extension parsers whose RFC 5280 syntax is SEQUENCE SIZE (1..MAX) - CRLDistPoint, CertificatePolicies, ExtendedKeyUsage, PolicyMappings, and SubjectDirectoryAttributes (PR #2331). Hardening asn1.cms.SignerInfo decode to reject a non-INTEGER version or non-tagged unsignedAttrs via getInstance rather than leaking a ClassCastException (PR #2342). Fixing an off-by-4 header-length guard in the OpenPGP NotationData signature subpacket parser (PR #2346). Rejecting CR/LF in the S/MIME streaming writer header names and values (SMIMEEnvelopedWriter/SMIMESignedWriter withHeader) to prevent MIME header injection (PR #2348). Adding minimum-length guards to the SM2 decrypt and GOST28147/DSTU7624/DESede/RC2 key-wrap unwrap paths (PR #2359). Guarding the ECDH session-key length in the JCE OpenPGP decryptor (PR #2383). Fixing the identity fast-path type guards in the OER getInstance factories and the transposed isInstance arguments in OEROptional.getObject (PR #2373). Requiring the signature handed to AIMerSigner.verifySignature to be exactly the parameter set's signature size (PR #2401). Constant time comparison of the SRP-6a evidence messages (PR #2406). Surfacing a malformed TSTInfo in a time-stamp token as TSPException rather than an unchecked exception out of the TimeStampResponse constructors (PR #2415). Rejecting a PKCS#12 PBMAC1 KDF keyLength below the RFC 9579 sec. 9 floor of 20 octets (PR #2431). Initial implementation of the empty-label guard on name-constraint host matching, having found that the canonicalisation removed only one RFC 1034 root-label dot, so a dNSName, rfc822Name host or URI host carrying more than one matched no constraint at all (PR #2436). Initial implementation of the lookup of indirect CRL entries by issuer and serial number, having found that the certification path validators compared only the issuer of the first entry carrying a certificate's serial number (PR #2464). Initial implementation of the malformed-input handling of the OCSPResp and OCSPReq parsers (PR #2468).
536536
- suraj0208 \<https://github.com/suraj0208\> - initial work on auto-detecting private key reader (JcaPrivateKeyReader).
537537
- liamgilligan \<https://github.com/liamgilligan\> - noticing the BIP-340 step numbering in the BIP340Signer signing comments was incorrect (PR #2340).
538538
- digi-scrypt \<https://github.com/digi-scrypt\> - disabling DTD and external-entity resolution in KMIPInputStream to close an XXE (local file disclosure / SSRF) exposure in KMIP XML parsing (PR #2315).

‎core/src/main/java/org/bouncycastle/asn1/ocsp/BasicOCSPResponse.java‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.bouncycastle.asn1.ocsp;
22

3+
import org.bouncycastle.asn1.ASN1BitString;
34
import org.bouncycastle.asn1.ASN1EncodableVector;
45
import org.bouncycastle.asn1.ASN1Object;
56
import org.bouncycastle.asn1.ASN1Primitive;
@@ -43,13 +44,18 @@ public BasicOCSPResponse(
4344
private BasicOCSPResponse(
4445
ASN1Sequence seq)
4546
{
47+
if (seq.size() < 3)
48+
{
49+
throw new IllegalArgumentException("Bad sequence size: " + seq.size());
50+
}
51+
4652
this.tbsResponseData = ResponseData.getInstance(seq.getObjectAt(0));
4753
this.signatureAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(1));
48-
this.signature = (DERBitString)seq.getObjectAt(2);
54+
this.signature = DERBitString.convert(ASN1BitString.getInstance(seq.getObjectAt(2)));
4955

5056
if (seq.size() > 3)
5157
{
52-
this.certs = ASN1Sequence.getInstance((ASN1TaggedObject)seq.getObjectAt(3), true);
58+
this.certs = ASN1Sequence.getInstance(ASN1TaggedObject.getInstance(seq.getObjectAt(3)), true);
5359
}
5460
}
5561

‎core/src/main/java/org/bouncycastle/asn1/ocsp/CertID.java‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ private CertID(
4141
}
4242

4343
hashAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0));
44-
issuerNameHash = (ASN1OctetString)seq.getObjectAt(1);
45-
issuerKeyHash = (ASN1OctetString)seq.getObjectAt(2);
46-
serialNumber = (ASN1Integer)seq.getObjectAt(3);
44+
issuerNameHash = ASN1OctetString.getInstance(seq.getObjectAt(1));
45+
issuerKeyHash = ASN1OctetString.getInstance(seq.getObjectAt(2));
46+
serialNumber = ASN1Integer.getInstance(seq.getObjectAt(3));
4747
}
4848

4949
public static CertID getInstance(

‎core/src/main/java/org/bouncycastle/asn1/ocsp/OCSPRequest.java‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,17 @@ public OCSPRequest(
2525
private OCSPRequest(
2626
ASN1Sequence seq)
2727
{
28+
if (seq.size() < 1)
29+
{
30+
throw new IllegalArgumentException("Bad sequence size: " + seq.size());
31+
}
32+
2833
tbsRequest = TBSRequest.getInstance(seq.getObjectAt(0));
2934

3035
if (seq.size() == 2)
3136
{
3237
optionalSignature = Signature.getInstance(
33-
(ASN1TaggedObject)seq.getObjectAt(1), true);
38+
ASN1TaggedObject.getInstance(seq.getObjectAt(1)), true);
3439
}
3540
}
3641

‎core/src/main/java/org/bouncycastle/asn1/ocsp/OCSPResponse.java‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,17 @@ public OCSPResponse(
3636
private OCSPResponse(
3737
ASN1Sequence seq)
3838
{
39+
if (seq.size() < 1)
40+
{
41+
throw new IllegalArgumentException("Bad sequence size: " + seq.size());
42+
}
43+
3944
responseStatus = OCSPResponseStatus.getInstance(seq.getObjectAt(0));
4045

4146
if (seq.size() == 2)
4247
{
4348
responseBytes = ResponseBytes.getInstance(
44-
(ASN1TaggedObject)seq.getObjectAt(1), true);
49+
ASN1TaggedObject.getInstance(seq.getObjectAt(1)), true);
4550
}
4651
}
4752

‎core/src/main/java/org/bouncycastle/asn1/ocsp/Request.java‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,17 @@ public Request(
2626
private Request(
2727
ASN1Sequence seq)
2828
{
29+
if (seq.size() < 1)
30+
{
31+
throw new IllegalArgumentException("Bad sequence size: " + seq.size());
32+
}
33+
2934
reqCert = CertID.getInstance(seq.getObjectAt(0));
3035

3136
if (seq.size() == 2)
3237
{
3338
singleRequestExtensions = Extensions.getInstance(
34-
(ASN1TaggedObject)seq.getObjectAt(1), true);
39+
ASN1TaggedObject.getInstance(seq.getObjectAt(1)), true);
3540
}
3641
}
3742

‎core/src/main/java/org/bouncycastle/asn1/ocsp/ResponseBytes.java‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ private ResponseBytes(
3838
throw new IllegalArgumentException("Bad sequence size: " + seq.size());
3939
}
4040

41-
responseType = (ASN1ObjectIdentifier)seq.getObjectAt(0);
42-
response = (ASN1OctetString)seq.getObjectAt(1);
41+
responseType = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0));
42+
response = ASN1OctetString.getInstance(seq.getObjectAt(1));
4343
}
4444

4545
public static ResponseBytes getInstance(

‎core/src/main/java/org/bouncycastle/asn1/ocsp/ResponseData.java‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ private ResponseData(
8080
{
8181
int index = 0;
8282

83+
if (seq.size() < 3)
84+
{
85+
throw new IllegalArgumentException("Bad sequence size: " + seq.size());
86+
}
87+
8388
if (seq.getObjectAt(0) instanceof ASN1TaggedObject)
8489
{
8590
ASN1TaggedObject o = (ASN1TaggedObject)seq.getObjectAt(0);
@@ -101,14 +106,19 @@ private ResponseData(
101106
this.version = V1;
102107
}
103108

109+
if (seq.size() < index + 3)
110+
{
111+
throw new IllegalArgumentException("Bad sequence size: " + seq.size());
112+
}
113+
104114
this.responderID = ResponderID.getInstance(seq.getObjectAt(index++));
105115
this.producedAt = ASN1GeneralizedTime.getInstance(seq.getObjectAt(index++));
106-
this.responses = (ASN1Sequence)seq.getObjectAt(index++);
116+
this.responses = ASN1Sequence.getInstance(seq.getObjectAt(index++));
107117

108118
if (seq.size() > index)
109119
{
110120
this.responseExtensions = Extensions.getInstance(
111-
(ASN1TaggedObject)seq.getObjectAt(index), true);
121+
ASN1TaggedObject.getInstance(seq.getObjectAt(index)), true);
112122
}
113123
}
114124

‎core/src/main/java/org/bouncycastle/asn1/ocsp/RevokedInfo.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ private RevokedInfo(
4343
if (seq.size() > 1)
4444
{
4545
this.revocationReason = CRLReason.getInstance(ASN1Enumerated.getInstance(
46-
(ASN1TaggedObject)seq.getObjectAt(1), true));
46+
ASN1TaggedObject.getInstance(seq.getObjectAt(1)), true));
4747
}
4848
}
4949

‎core/src/main/java/org/bouncycastle/asn1/ocsp/Signature.java‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.bouncycastle.asn1.ocsp;
22

3+
import org.bouncycastle.asn1.ASN1BitString;
34
import org.bouncycastle.asn1.ASN1EncodableVector;
45
import org.bouncycastle.asn1.ASN1Object;
56
import org.bouncycastle.asn1.ASN1Primitive;
@@ -44,12 +45,12 @@ private Signature(
4445
}
4546

4647
signatureAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0));
47-
signature = (DERBitString)seq.getObjectAt(1);
48+
signature = DERBitString.convert(ASN1BitString.getInstance(seq.getObjectAt(1)));
4849

4950
if (seq.size() == 3)
5051
{
5152
certs = ASN1Sequence.getInstance(
52-
(ASN1TaggedObject)seq.getObjectAt(2), true);
53+
ASN1TaggedObject.getInstance(seq.getObjectAt(2)), true);
5354
}
5455
}
5556

0 commit comments

Comments
 (0)