-1

I noticed BouncyCastle v1.60 does not throw an error during validation after modifying (pseudo) random bits of the response. In the two responses below, you'll notice all the a's have been swapped with b's. BouncyCastle returns the Unix epoch as the generated time.

Code:

TimeStampToken.validate(SignerInformationVerifier)

Algorithm: SHA-256

Data: "test string" (no quotes)

Response Before (as hex):

30820381301502010030100c0e4f7065726174696f6e204f6b61793082036606092a864886f70d010702a082035730820353020103310f300d060960864801650304020105003062060b2a864886f70d0109100104a0530451304f020101060200013031300d060960864801650304020105000420d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b020203e7180f32303139303230373131343130305a318202d7308202d30201013081a73081993119301706035504030c10746573742e6578616d706c652e636f6d31193017060355040b0c105465737420436572746966696361746531153013060355040a0c0c5465737420436f6d70616e793112301006035504070c09546573742043697479310b300906035504080c024e41310b3009060355040613024e41311c301a06092a864886f70d010901160d7465737440746573742e636f6d020900f107055617507892300d06096086480165030402010500a0820100301a06092a864886f70d010903310d060b2a864886f70d0109100104301c06092a864886f70d010905310f170d3139303230373131343130335a302d06092a864886f70d0109343120301e300d06096086480165030402010500a10d06092a864886f70d01010b0500302f06092a864886f70d010904312204209e495138576ec3412aad5d0ca9da6ec9db27035b63173bc36ded376c9eb43cff3064060b2a864886f70d010910022f315530533051304f300b0609608648016503040203044004612191f42ba99172120c710d91f05df8af4a5fd6ad7d6f21a1cf430a99700c1087a2f01eeac9f10125534712d5119e723c8e34fcd7fd9294e15f66112578f8300d06092a864886f70d01010b0500048201001814599f602af54afdd3bb56df2f88ee2bdc42d8204379a2d2a983195ed3e8b74aada8a6161d1e56e3cf3338bd0250df1d90e97454393d2514c6125a1d9ffec7c9530015acb5ba4e4fd7d224c225a220e15c423446d9f8ba1ffc3d4c0a63ec856799a9a3267debf6fcd3cf11fe364c183502acfcd05dee834540e2f07e4ee3bb6b590848fc90e87ba6db57aa89f101448a7665639fdc00c6839290346fa80c135f0d127861adf512f12d6e5fe52c15fe0718ba8b834b8fa56f298c5a2a830fa880e080f3b67237efef1a05cb76fedbb2a7d272bab1adb6cb9790b382a98e26e00d2def94f09efd24454cb3aa3f60490ad651ba8fee8292349e9ee3da16f8d71e

Response After (as hex):

30820381301502010030100c0e4f7065726174696f6e204f6b61793082036606092b864886f70d010702b082035730820353020103310f300d060960864801650304020105003062060b2b864886f70d0109100104b0530451304f020101060200013031300d060960864801650304020105000420d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4bc457bb8f82743f31e930b020203e7180f32303139303230373131343130305b318202d7308202d30201013081b73081993119301706035504030c10746573742e6578616d706c652e636f6d31193017060355040b0c105465737420436572746966696361746531153013060355040b0c0c5465737420436f6d70616e793112301006035504070c09546573742043697479310b300906035504080c024e41310b3009060355040613024e41311c301b06092b864886f70d010901160d7465737440746573742e636f6d020900f107055617507892300d06096086480165030402010500b0820100301b06092b864886f70d010903310d060b2b864886f70d0109100104301c06092b864886f70d010905310f170d3139303230373131343130335b302d06092b864886f70d0109343120301e300d06096086480165030402010500b10d06092b864886f70d01010b0500302f06092b864886f70d010904312204209e495138576ec3412bbd5d0cb9db6ec9db27035b63173bc36ded376c9eb43cff3064060b2b864886f70d010910022f315530533051304f300b0609608648016503040203044004612191f42bb99172120c710d91f05df8bf4b5fd6bd7d6f21b1cf430b99700c1087b2f01eebc9f10125534712d5119e723c8e34fcd7fd9294e15f66112578f8300d06092b864886f70d01010b0500048201001814599f602bf54bfdd3bb56df2f88ee2bdc42d8204379b2d2b983195ed3e8b74bbdb8b6161d1e56e3cf3338bd0250df1d90e97454393d2514c6125b1d9ffec7c9530015bcb5bb4e4fd7d224c225b220e15c423446d9f8bb1ffc3d4c0b63ec856799b9b3267debf6fcd3cf11fe364c183502bcfcd05dee834540e2f07e4ee3bb6b590848fc90e87bb6db57bb89f101448b7665639fdc00c6839290346fb80c135f0d127861bdf512f12d6e5fe52c15fe0718bb8b834b8fb56f298c5b2b830fb880e080f3b67237efef1b05cb76fedbb2b7d272bbb1bdb6cb9790b382b98e26e00d2def94f09efd24454cb3bb3f60490bd651bb8fee8292349e9ee3db16f8d71e

Time Output:

1970-01-01T00:00:00.000+0000

Certificate:

-----BEGIN CERTIFICATE-----
MIID3jCCAsagAwIBAgIJAPEHBVYXUHiSMA0GCSqGSIb3DQEBCwUAMIGZMRkwFwYD
VQQDDBB0ZXN0LmV4YW1wbGUuY29tMRkwFwYDVQQLDBBUZXN0IENlcnRpZmljYXRl
MRUwEwYDVQQKDAxUZXN0IENvbXBhbnkxEjAQBgNVBAcMCVRlc3QgQ2l0eTELMAkG
A1UECAwCTkExCzAJBgNVBAYTAk5BMRwwGgYJKoZIhvcNAQkBFg10ZXN0QHRlc3Qu
Y29tMB4XDTE5MDIwNzEwNTkxNFoXDTIwMDIwNzEwNTkxNFowgZkxGTAXBgNVBAMM
EHRlc3QuZXhhbXBsZS5jb20xGTAXBgNVBAsMEFRlc3QgQ2VydGlmaWNhdGUxFTAT
BgNVBAoMDFRlc3QgQ29tcGFueTESMBAGA1UEBwwJVGVzdCBDaXR5MQswCQYDVQQI
DAJOQTELMAkGA1UEBhMCTkExHDAaBgkqhkiG9w0BCQEWDXRlc3RAdGVzdC5jb20w
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDOCc+A01I6FG7GIQLygwjN
cOqqFE7l6TJXsmGuG7W9ndkN13zEGTIXUcWxQKYUGBp9IzifvK1ezncP/+TsJvoL
hpc3HltIKay3TB0SvLvEbyvTWsX2Vbld3VkDP1KkvmISwfeozSAjFI5J58kFreqM
xLVCHvTRPBpBZXn93uzOC1k3Hcp4DVLzl6ooib6Mst4riltOOFYNAaTMd78V/D0D
1tNDljcEMbinMmcwpARFfd3Ow0x3EacgzBiGtE+hVBvAJ5suo5berEtAwdnTQSGc
Cn/V9lheCt06fQmxTgg+tjI14cmfMXnHUvOts13aO6zn7NrXH3a52ATaXidkCmZp
AgMBAAGjJzAlMAsGA1UdDwQEAwIGwDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAN
BgkqhkiG9w0BAQsFAAOCAQEAAuvuWpWcy4JLOsdcUVZwPsrKPoMJFkhOgEbTv6zw
3W3Jhtxz7mv6uIog0/8U0oNWOjLJ5kXbe/580lywbqTLHPQmdD71yQIarUJnspLj
u90iJXgVbWtuYVLAPB1ZXdZ15gqLmgfvzSEFfZgIqaHtFjBhti3sukIREPYKrESQ
vw8kb/9fAKQI3oVSGygNSCeuRQ00upav9O9jyK2BYSmVV1Vi5jHNBL0RgANp41Tz
RrqIzjzsv1cMO3CJHxgwv8+taTZ8ATDNDvcVCLA2w1gQNYLCPUjtA1ory7TYjw0F
/it/Ksayt8ZlICC1QBR1C2ELT3PVNoSomkYlcAKXJoVQDA==
-----END CERTIFICATE-----

UPDATE

TimeStampResponse response = new TimeStampResponse(byteResponse);
token = response.getTimeStampToken();
tokenInfo = token.getTimeStampInfo();

JcaContentVerifierProviderBuilder jcaCVPB = new JcaContentVerifierProviderBuilder();
JcaDigestCalculatorProviderBuilder digestCalcPB = new JcaDigestCalculatorProviderBuilder();
DigestCalculatorProvider digestCalc = digestCalcPB.build();
ContentVerifierProvider contentVP = jcaCVPB.build(getCert()); // getCert() returns an X509Certificate object
SignerInformationVerifier signerInfo = new SignerInformationVerifier(new DefaultCMSSignatureAlgorithmNameGenerator(), new DefaultSignatureAlgorithmIdentifierFinder(), contentVP, digestCalc);

token.validate(signerInfo);
user8897013
  • 443
  • 4
  • 15
  • Please show you code. – mkl Feb 07 '19 at 11:22
  • I am not allowed to share our codebase, but I added the function used for validation above with generic classes. Keep in mind this is BC 1.60. – user8897013 Feb 07 '19 at 11:50
  • I'm pretty sure I saw an earlier question about this. Did you delete and then repost? If you cannot show your code, then there is no sense in posting this question, as it is likely to be an error in your code base rather than BC's (although BC code base is rather far from foolproof as well). – Maarten Bodewes Feb 07 '19 at 16:19
  • @MaartenBodewes: you probably saw https://crypto.stackexchange.com/questions/66487/why-is-timestamp-response-still-valid-after-scrambling-bits which is indeed deleted but I kept a bookmark of – dave_thompson_085 Feb 07 '19 at 18:03
  • I knew it; my own comment: "please ask on StackOverflow if you cannot find the error **and include the code**." – Maarten Bodewes Feb 07 '19 at 18:10
  • Yes, this is the same question. I cannot share portions of our codebase without permission, which is not a wild idea on SO. However, I did include the version and function used for validation (the previous question had a comment that said they tried and failed in 1.5, but the function they use is not supported in 1.60). Lastly, using the responses I provided, the certificate, code and hash, it should not be that difficult for someone to verify if this throws an exception for them or not. I am certain my code validates correctly well formed timestamps and errors on other common malformats... – user8897013 Feb 07 '19 at 19:38
  • ...such as too long, too short, etc. but no error for this one where bit have been swapped. Considering I provided ample information to facilitate easy reproduction, this does not seem worthy of multiple downvotes. – user8897013 Feb 07 '19 at 19:40
  • Example code provided. Please remove the downvotes if that was what they were for. – user8897013 Feb 08 '19 at 02:49
  • **A** Your example code also gives rise to an exception during parsing. **B** Chances are slim to get rid of downvotes. Usually downvoters (after leaving the down vote) move on and don't follow the downvoted question anymore. – mkl Feb 08 '19 at 09:10

1 Answers1

3

Unfortunately you initially didn't share the relevant code. Thus, I had to build some code myself, test with that code, and answer your question based on that code.

The result: For your manipulated response already parsing fails, so there is no way to try and validate it.

The code

String responseHex = "30820381301502010030100c0e4f7065726174696f6e204f6b61793082036606092a864886f70d010702a082035730820353020103310f300d060960864801650304020105003062060b2a864886f70d0109100104a0530451304f020101060200013031300d060960864801650304020105000420d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b020203e7180f32303139303230373131343130305a318202d7308202d30201013081a73081993119301706035504030c10746573742e6578616d706c652e636f6d31193017060355040b0c105465737420436572746966696361746531153013060355040a0c0c5465737420436f6d70616e793112301006035504070c09546573742043697479310b300906035504080c024e41310b3009060355040613024e41311c301a06092a864886f70d010901160d7465737440746573742e636f6d020900f107055617507892300d06096086480165030402010500a0820100301a06092a864886f70d010903310d060b2a864886f70d0109100104301c06092a864886f70d010905310f170d3139303230373131343130335a302d06092a864886f70d0109343120301e300d06096086480165030402010500a10d06092a864886f70d01010b0500302f06092a864886f70d010904312204209e495138576ec3412aad5d0ca9da6ec9db27035b63173bc36ded376c9eb43cff3064060b2a864886f70d010910022f315530533051304f300b0609608648016503040203044004612191f42ba99172120c710d91f05df8af4a5fd6ad7d6f21a1cf430a99700c1087a2f01eeac9f10125534712d5119e723c8e34fcd7fd9294e15f66112578f8300d06092a864886f70d01010b0500048201001814599f602af54afdd3bb56df2f88ee2bdc42d8204379a2d2a983195ed3e8b74aada8a6161d1e56e3cf3338bd0250df1d90e97454393d2514c6125a1d9ffec7c9530015acb5ba4e4fd7d224c225a220e15c423446d9f8ba1ffc3d4c0a63ec856799a9a3267debf6fcd3cf11fe364c183502acfcd05dee834540e2f07e4ee3bb6b590848fc90e87ba6db57aa89f101448a7665639fdc00c6839290346fa80c135f0d127861adf512f12d6e5fe52c15fe0718ba8b834b8fa56f298c5a2a830fa880e080f3b67237efef1a05cb76fedbb2a7d272bab1adb6cb9790b382a98e26e00d2def94f09efd24454cb3aa3f60490ad651ba8fee8292349e9ee3da16f8d71e";
String responseChangedHex = "30820381301502010030100c0e4f7065726174696f6e204f6b61793082036606092b864886f70d010702b082035730820353020103310f300d060960864801650304020105003062060b2b864886f70d0109100104b0530451304f020101060200013031300d060960864801650304020105000420d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4bc457bb8f82743f31e930b020203e7180f32303139303230373131343130305b318202d7308202d30201013081b73081993119301706035504030c10746573742e6578616d706c652e636f6d31193017060355040b0c105465737420436572746966696361746531153013060355040b0c0c5465737420436f6d70616e793112301006035504070c09546573742043697479310b300906035504080c024e41310b3009060355040613024e41311c301b06092b864886f70d010901160d7465737440746573742e636f6d020900f107055617507892300d06096086480165030402010500b0820100301b06092b864886f70d010903310d060b2b864886f70d0109100104301c06092b864886f70d010905310f170d3139303230373131343130335b302d06092b864886f70d0109343120301e300d06096086480165030402010500b10d06092b864886f70d01010b0500302f06092b864886f70d010904312204209e495138576ec3412bbd5d0cb9db6ec9db27035b63173bc36ded376c9eb43cff3064060b2b864886f70d010910022f315530533051304f300b0609608648016503040203044004612191f42bb99172120c710d91f05df8bf4b5fd6bd7d6f21b1cf430b99700c1087b2f01eebc9f10125534712d5119e723c8e34fcd7fd9294e15f66112578f8300d06092b864886f70d01010b0500048201001814599f602bf54bfdd3bb56df2f88ee2bdc42d8204379b2d2b983195ed3e8b74bbdb8b6161d1e56e3cf3338bd0250df1d90e97454393d2514c6125b1d9ffec7c9530015bcb5bb4e4fd7d224c225b220e15c423446d9f8bb1ffc3d4c0b63ec856799b9b3267debf6fcd3cf11fe364c183502bcfcd05dee834540e2f07e4ee3bb6b590848fc90e87bb6db57bb89f101448b7665639fdc00c6839290346fb80c135f0d127861bdf512f12d6e5fe52c15fe0718bb8b834b8fb56f298c5b2b830fb880e080f3b67237efef1b05cb76fedbb2b7d272bbb1bdb6cb9790b382b98e26e00d2def94f09efd24454cb3bb3f60490bd651bb8fee8292349e9ee3db16f8d71e";
String certificateB64 = "MIID3jCCAsagAwIBAgIJAPEHBVYXUHiSMA0GCSqGSIb3DQEBCwUAMIGZMRkwFwYD\n" + 
        "VQQDDBB0ZXN0LmV4YW1wbGUuY29tMRkwFwYDVQQLDBBUZXN0IENlcnRpZmljYXRl\n" + 
        "MRUwEwYDVQQKDAxUZXN0IENvbXBhbnkxEjAQBgNVBAcMCVRlc3QgQ2l0eTELMAkG\n" + 
        "A1UECAwCTkExCzAJBgNVBAYTAk5BMRwwGgYJKoZIhvcNAQkBFg10ZXN0QHRlc3Qu\n" + 
        "Y29tMB4XDTE5MDIwNzEwNTkxNFoXDTIwMDIwNzEwNTkxNFowgZkxGTAXBgNVBAMM\n" + 
        "EHRlc3QuZXhhbXBsZS5jb20xGTAXBgNVBAsMEFRlc3QgQ2VydGlmaWNhdGUxFTAT\n" + 
        "BgNVBAoMDFRlc3QgQ29tcGFueTESMBAGA1UEBwwJVGVzdCBDaXR5MQswCQYDVQQI\n" + 
        "DAJOQTELMAkGA1UEBhMCTkExHDAaBgkqhkiG9w0BCQEWDXRlc3RAdGVzdC5jb20w\n" + 
        "ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDOCc+A01I6FG7GIQLygwjN\n" + 
        "cOqqFE7l6TJXsmGuG7W9ndkN13zEGTIXUcWxQKYUGBp9IzifvK1ezncP/+TsJvoL\n" + 
        "hpc3HltIKay3TB0SvLvEbyvTWsX2Vbld3VkDP1KkvmISwfeozSAjFI5J58kFreqM\n" + 
        "xLVCHvTRPBpBZXn93uzOC1k3Hcp4DVLzl6ooib6Mst4riltOOFYNAaTMd78V/D0D\n" + 
        "1tNDljcEMbinMmcwpARFfd3Ow0x3EacgzBiGtE+hVBvAJ5suo5berEtAwdnTQSGc\n" + 
        "Cn/V9lheCt06fQmxTgg+tjI14cmfMXnHUvOts13aO6zn7NrXH3a52ATaXidkCmZp\n" + 
        "AgMBAAGjJzAlMAsGA1UdDwQEAwIGwDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAN\n" + 
        "BgkqhkiG9w0BAQsFAAOCAQEAAuvuWpWcy4JLOsdcUVZwPsrKPoMJFkhOgEbTv6zw\n" + 
        "3W3Jhtxz7mv6uIog0/8U0oNWOjLJ5kXbe/580lywbqTLHPQmdD71yQIarUJnspLj\n" + 
        "u90iJXgVbWtuYVLAPB1ZXdZ15gqLmgfvzSEFfZgIqaHtFjBhti3sukIREPYKrESQ\n" + 
        "vw8kb/9fAKQI3oVSGygNSCeuRQ00upav9O9jyK2BYSmVV1Vi5jHNBL0RgANp41Tz\n" + 
        "RrqIzjzsv1cMO3CJHxgwv8+taTZ8ATDNDvcVCLA2w1gQNYLCPUjtA1ory7TYjw0F\n" + 
        "/it/Ksayt8ZlICC1QBR1C2ELT3PVNoSomkYlcAKXJoVQDA==";

byte[] certificateBytes = Base64.decode(certificateB64);
X509CertificateHolder certificateHolder = new X509CertificateHolder(certificateBytes);
SignerInformationVerifier signerInformationVerifier = new JcaSimpleSignerInfoVerifierBuilder().build(certificateHolder);

//
// Validate the original timestamp response
//
byte[] responseBytes = Hex.decode(responseHex);
TimeStampResp responseResp = TimeStampResp.getInstance(responseBytes);
TimeStampToken responseToken = new TimeStampToken(responseResp.getTimeStampToken());

responseToken.validate(signerInformationVerifier);

//
// Validate the manipulated timestamp response
//
responseBytes = Hex.decode(responseChangedHex);
responseResp = TimeStampResp.getInstance(responseBytes);
responseToken = new TimeStampToken(responseResp.getTimeStampToken());

responseToken.validate(signerInformationVerifier);

The result

During the attempt to validate the manipulated timestamp response already in the line

responseResp = TimeStampResp.getInstance(responseBytes);

an exception is thrown:

java.lang.IllegalArgumentException: failed to construct sequence from byte[]: DEF length 27 object truncated by 1
    at org.bouncycastle.asn1.ASN1Sequence.getInstance(Unknown Source)
    at org.bouncycastle.asn1.tsp.TimeStampResp.getInstance(Unknown Source)
    at mkl.testarea.bc1.timestamp.ValidateTST.testValidateLikeUser8897013(ValidateTST.java:75)

Thus, the response cannot be parsed. As a consequence, TimeStampToken.validate cannot be called for it.

Using your code

After you eventually published your code, I also tested that code:

responseBytes = Hex.decode(responseChangedHex);
TimeStampResponse response = new TimeStampResponse(responseBytes);
TimeStampToken token = response.getTimeStampToken();
TimeStampTokenInfo tokenInfo = token.getTimeStampInfo();

But also here I get an exception already while parsing the manipulated response:

java.io.EOFException: DEF length 27 object truncated by 1
    at org.bouncycastle.asn1.DefiniteLengthInputStream.read(Unknown Source)
    at org.bouncycastle.asn1.ASN1StreamParser.readObject(Unknown Source)
    at org.bouncycastle.asn1.ASN1StreamParser.readVector(Unknown Source)
    at org.bouncycastle.asn1.DERSequenceParser.getLoadedObject(Unknown Source)
    at org.bouncycastle.asn1.ASN1StreamParser.readVector(Unknown Source)
    at org.bouncycastle.asn1.DERSetParser.getLoadedObject(Unknown Source)
    at org.bouncycastle.asn1.ASN1StreamParser.readVector(Unknown Source)
    at org.bouncycastle.asn1.DERSequenceParser.getLoadedObject(Unknown Source)
    at org.bouncycastle.asn1.ASN1StreamParser.readVector(Unknown Source)
    at org.bouncycastle.asn1.DERSequenceParser.getLoadedObject(Unknown Source)
    at org.bouncycastle.asn1.ASN1StreamParser.readVector(Unknown Source)
    at org.bouncycastle.asn1.DERSequenceParser.getLoadedObject(Unknown Source)
    at org.bouncycastle.asn1.ASN1StreamParser.readVector(Unknown Source)
    at org.bouncycastle.asn1.DERSetParser.getLoadedObject(Unknown Source)
    at org.bouncycastle.asn1.ASN1StreamParser.readVector(Unknown Source)
    at org.bouncycastle.asn1.DERSequenceParser.getLoadedObject(Unknown Source)
    at org.bouncycastle.asn1.ASN1StreamParser.readVector(Unknown Source)
    at org.bouncycastle.asn1.ASN1StreamParser.readTaggedObject(Unknown Source)
    at org.bouncycastle.asn1.ASN1InputStream.buildObject(Unknown Source)
    at org.bouncycastle.asn1.ASN1InputStream.readObject(Unknown Source)
    at org.bouncycastle.asn1.ASN1InputStream.buildEncodableVector(Unknown Source)
    at org.bouncycastle.asn1.ASN1InputStream.buildDEREncodableVector(Unknown Source)
    at org.bouncycastle.asn1.ASN1InputStream.buildObject(Unknown Source)
    at org.bouncycastle.asn1.ASN1InputStream.readObject(Unknown Source)
    at org.bouncycastle.asn1.ASN1InputStream.buildEncodableVector(Unknown Source)
    at org.bouncycastle.asn1.ASN1InputStream.buildDEREncodableVector(Unknown Source)
    at org.bouncycastle.asn1.ASN1InputStream.buildObject(Unknown Source)
    at org.bouncycastle.asn1.ASN1InputStream.readObject(Unknown Source)
    at org.bouncycastle.tsp.TimeStampResponse.readTimeStampResp(Unknown Source)
    at org.bouncycastle.tsp.TimeStampResponse.<init>(Unknown Source)
    at org.bouncycastle.tsp.TimeStampResponse.<init>(Unknown Source)
    at mkl.testarea.bc1.timestamp.ValidateTST.testValidateLikeUser8897013(ValidateTST.java:98)

i.e. in this line

TimeStampResponse response = new TimeStampResponse(responseBytes);

As a consequence, TimeStampToken.validate cannot be called for your response even if one uses TimeStampResponse instead of TimeStampResp.

BC versions

As you expressed doubts in a comment: I do use BC 1.60 for the test having both bcprov-jdk15on-1.60.jar and bcpkix-jdk15on-1.60.jar in my classpath and having registered BC as security provider:

Security.addProvider(new BouncyCastleProvider());

To me this is a completely normal BC setup.

mkl
  • 90,588
  • 15
  • 125
  • 265
  • Thank you for your efforts. Let me take a look at where I might have gone wrong. – user8897013 Feb 07 '19 at 19:44
  • Got permission to share some code. Thanks for understanding. Is the method in my example not the way to go? Yours is a lot simpler and cleaner! – user8897013 Feb 08 '19 at 02:48
  • I think your example code is using BC v1.37 or similar based on your TimeStampResp class. I mentioned I was using 1.60, and the new class is TimeStampResponse. There is not a getInstance() method for this new [class](https://www.bouncycastle.org/docs/pkixdocs1.5on/org/bouncycastle/tsp/TimeStampResponse.html). Unfortunately, BC does not keep readily linked archives, so if you click the link for 1.61 (latest) you will have to modify it to 1.60. [Modified Link](https://www.bouncycastle.org/download/bcpkix-jdk15on-160.zip). – user8897013 Feb 08 '19 at 06:28
  • 1.60 does contain `org.bouncycastle.asn1.tsp.TimeStampResp` (in "bcprov-jdk15on-1.60.jar"), and that class has a static `getInstance(Object)` method. Please, before writing a comment claiming others did something wrong, verify your claim. – mkl Feb 08 '19 at 08:40
  • Thank you for your time. Sorry for the delay, but I am able to reproduce the EOF error now and marked this as the answer. Very curious to know if there is a reason to use TimeStampResp over TimeStampResponse? Why would they have two classes? ...and I'm actually still not clear on the differences between the two libraries (bcprov vs. bcpkix) other than [this](https://stackoverflow.com/questions/29211582/how-do-bcprov-and-bcprov-ext-differ). Please share. – user8897013 Feb 21 '19 at 02:29
  • @user8897013 Essentially the prov jar is used when accessing BC functionality as a Java security provider while the pkix jar is for direct usage. I cannot comment on the implementation of the same functionality in different objects in both library, though. I can only guess that it's historically grown that way... – mkl Mar 25 '19 at 15:22