Skip to content

Commit 8c6d4ad

Browse files
committed
F6: Properly handle failing backends, add test for failing signature, decryption
1 parent 3dc8e52 commit 8c6d4ad

3 files changed

Lines changed: 131 additions & 6 deletions

File tree

‎pg/src/main/java/org/bouncycastle/openpgp/api/AbstractOpenPGPDocumentSignatureGenerator.java‎

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -267,11 +267,20 @@ protected PGPSignatureGenerator initSignatureGenerator(
267267
PGPPublicKey publicKey = signingKey.getPGPPublicKey();
268268
for (PGPContentSignerBuilderProviderFactory sigFac : customContentSignerBuilderProviderFactories)
269269
{
270-
PGPContentSignerBuilderProvider sigProv = sigFac.getPGPContentSignerBuilderProvider(
271-
signingKey, passphraseProvider, parameters.getSignatureHashAlgorithmId());
272-
if (sigProv == null)
270+
PGPContentSignerBuilderProvider sigProv;
271+
try
272+
{
273+
sigProv = sigFac.getPGPContentSignerBuilderProvider(
274+
signingKey, passphraseProvider, parameters.getSignatureHashAlgorithmId());
275+
if (sigProv == null)
276+
{
277+
// no matching card found
278+
continue;
279+
}
280+
}
281+
catch (PGPException e)
273282
{
274-
// no matching card found
283+
// No matching card found
275284
continue;
276285
}
277286

@@ -292,7 +301,7 @@ protected PGPSignatureGenerator initSignatureGenerator(
292301
return Utils.applyDefaultSubpackets(publicKey, parameters, parameters.getSignatureCreationTime(), null, sigGen);
293302
}
294303

295-
throw new IllegalStateException("Cannot initialize signature generator for external key " + signingKey.getKeyIdentifier());
304+
throw new PGPException("Cannot initialize signature generator for external key " + signingKey.getKeyIdentifier());
296305
}
297306
else
298307
{

‎pgsc/src/test/java/org/bouncycastle/openpgp/smartcard/test/AllTests.java‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ public void testUnits()
2929
{
3030
new ShortenedOpenPGPIdentifierForLegacyDevicesTest(),
3131
new PublicKeyConverterTest(),
32-
new MultiBackendTest()
32+
new MultiBackendTest(),
33+
new FailingBackendTest()
3334
};
3435

3536
for (int i = 0; i != tests.length; i++)
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package org.bouncycastle.openpgp.smartcard.test;
2+
3+
import org.bouncycastle.openpgp.PGPException;
4+
import org.bouncycastle.openpgp.api.KeyPairGeneratorCallback;
5+
import org.bouncycastle.openpgp.api.KeyPassphraseProvider;
6+
import org.bouncycastle.openpgp.api.OpenPGPApi;
7+
import org.bouncycastle.openpgp.api.OpenPGPKey;
8+
import org.bouncycastle.openpgp.api.OpenPGPMessageInputStream;
9+
import org.bouncycastle.openpgp.api.OpenPGPMessageOutputStream;
10+
import org.bouncycastle.openpgp.api.bc.BcOpenPGPApi;
11+
import org.bouncycastle.openpgp.operator.PGPContentSignerBuilderProvider;
12+
import org.bouncycastle.openpgp.operator.PGPKeyPairGenerator;
13+
import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
14+
import org.bouncycastle.openpgp.smartcard.ExternalOpenPGPKeyUtils;
15+
import org.bouncycastle.openpgp.smartcard.OpenPGPSmartCardManager;
16+
import org.bouncycastle.openpgp.smartcard.simulator.SimulatorOpenPGPSmartCard;
17+
import org.bouncycastle.openpgp.smartcard.simulator.SimulatorOpenPGPSmartCardBackend;
18+
import org.bouncycastle.util.Arrays;
19+
import org.bouncycastle.util.io.Streams;
20+
import org.bouncycastle.util.test.SimpleTest;
21+
22+
import java.io.ByteArrayInputStream;
23+
import java.io.ByteArrayOutputStream;
24+
import java.nio.charset.StandardCharsets;
25+
26+
public class FailingBackendTest
27+
extends SimpleTest
28+
{
29+
@Override
30+
public String getName()
31+
{
32+
return "FailingBackendTest";
33+
}
34+
35+
@Override
36+
public void performTest()
37+
throws Exception
38+
{
39+
OpenPGPApi api = new BcOpenPGPApi();
40+
ExternalOpenPGPKeyUtils keyUtils = new ExternalOpenPGPKeyUtils(api.getImplementation());
41+
OpenPGPKey key = api.generateKey(4)
42+
.withPrimaryKey((KeyPairGeneratorCallback) PGPKeyPairGenerator::generateLegacyEd25519KeyPair)
43+
.addSigningSubkey((KeyPairGeneratorCallback) PGPKeyPairGenerator::generateLegacyEd25519KeyPair)
44+
.addEncryptionSubkey((KeyPairGeneratorCallback) PGPKeyPairGenerator::generateLegacyX25519KeyPair)
45+
.build();
46+
OpenPGPKey externalKey = keyUtils.toExternalKey(key);
47+
48+
OpenPGPSmartCardManager manager = new OpenPGPSmartCardManager();
49+
SimulatorOpenPGPSmartCardBackend failingBackend = new SimulatorOpenPGPSmartCardBackend() {
50+
@Override
51+
public String getName()
52+
{
53+
return "FailingSimulatorOpenPGPSmartCardBackend";
54+
}
55+
56+
@Override
57+
public PublicKeyDataDecryptorFactory providePublicKeyDataDecryptorFactory(
58+
OpenPGPKey.OpenPGPSecretKey decryptionKeyStub,
59+
KeyPassphraseProvider userPinProvider)
60+
throws PGPException
61+
{
62+
throw new PGPException("Fail to provide PublicKeyDataDecryptorFactory");
63+
}
64+
65+
@Override
66+
public PGPContentSignerBuilderProvider getPGPContentSignerBuilderProvider(
67+
OpenPGPKey.OpenPGPSecretKey signingKey,
68+
KeyPassphraseProvider userPinProvider,
69+
int hashAlgorithmId)
70+
throws PGPException
71+
{
72+
throw new PGPException("Fail to provide PGPContentSignerBuilderProvider");
73+
}
74+
};
75+
76+
SimulatorOpenPGPSmartCardBackend workingBackend = new SimulatorOpenPGPSmartCardBackend() {
77+
@Override
78+
public String getName()
79+
{
80+
return "WorkingSimulatorOpenPGPSmartCard";
81+
}
82+
};
83+
workingBackend.addSmartCard(SimulatorOpenPGPSmartCard.createSimulatedCardFrom(workingBackend, key));
84+
85+
manager.addBackend(failingBackend);
86+
manager.addBackend(workingBackend);
87+
88+
byte[] message = "Hello, World!\n".getBytes(StandardCharsets.UTF_8);
89+
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
90+
OpenPGPMessageOutputStream mOut = api.signAndOrEncryptMessage()
91+
.addCustomPGPContentSignerBuilderProviderFactory(manager)
92+
.addSigningKey(externalKey)
93+
.addEncryptionCertificate(key.toCertificate())
94+
.open(bOut);
95+
mOut.write(message);
96+
mOut.close();
97+
98+
ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray());
99+
OpenPGPMessageInputStream mIn = api.decryptAndOrVerifyMessage()
100+
.addPublicKeyDataDecryptorFactoryProvider(manager)
101+
.addVerificationCertificate(key.toCertificate())
102+
.addDecryptionKey(externalKey)
103+
.process(bIn);
104+
bOut = new ByteArrayOutputStream();
105+
Streams.pipeAll(mIn, bOut);
106+
mIn.close();
107+
isTrue(Arrays.areEqual(message, bOut.toByteArray()));
108+
isTrue(mIn.getResult().getSignatures().get(0).isValid());
109+
}
110+
111+
public static void main(String[] args)
112+
{
113+
runTest(new FailingBackendTest());
114+
}
115+
}

0 commit comments

Comments
 (0)