Skip to content

Commit 053d87b

Browse files
committed
removed unnecessary length check in LMS PublicKeyFactory
added support for public key check to work out digest ID. updated PQCSignedDataTest to use the public key approach with LMS
1 parent 05ac657 commit 053d87b

File tree

4 files changed

+72
-17
lines changed

4 files changed

+72
-17
lines changed

core/src/main/java/org/bouncycastle/pqc/crypto/lms/LMSigParameters.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public ASN1ObjectIdentifier getDigestOID()
9494
return digestOid;
9595
}
9696

97-
static LMSigParameters getParametersForType(int type)
97+
public static LMSigParameters getParametersForType(int type)
9898
{
9999
return paramBuilders.get(type);
100100
}

core/src/main/java/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -451,10 +451,6 @@ AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Obje
451451
private LMSKeyParameters getLmsKeyParameters(byte[] keyEnc)
452452
throws IOException
453453
{
454-
if (keyEnc.length == 64)
455-
{
456-
keyEnc = Arrays.copyOfRange(keyEnc, 4, keyEnc.length);
457-
}
458454
return HSSPublicKeyParameters.getInstance(keyEnc);
459455
}
460456
}

pkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentSignerBuilder.java

Lines changed: 65 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.security.GeneralSecurityException;
66
import java.security.PrivateKey;
77
import java.security.Provider;
8+
import java.security.PublicKey;
89
import java.security.SecureRandom;
910
import java.security.Signature;
1011
import java.security.SignatureException;
@@ -27,6 +28,7 @@
2728
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
2829
import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
2930
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
31+
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
3032
import org.bouncycastle.jcajce.CompositePrivateKey;
3133
import org.bouncycastle.jcajce.io.OutputStreamFactory;
3234
import org.bouncycastle.jcajce.spec.CompositeAlgorithmSpec;
@@ -41,9 +43,14 @@
4143
import org.bouncycastle.operator.OperatorCreationException;
4244
import org.bouncycastle.operator.RuntimeOperatorException;
4345
import org.bouncycastle.operator.SignatureAlgorithmIdentifierFinder;
46+
import org.bouncycastle.pqc.crypto.lms.LMSigParameters;
47+
import org.bouncycastle.util.Pack;
4448
import org.bouncycastle.util.Strings;
4549
import org.bouncycastle.util.io.TeeOutputStream;
4650

51+
/**
52+
* General builder class for ContentSigner operators based on the JCA.
53+
*/
4754
public class JcaContentSignerBuilder
4855
{
4956
private static final Set isAlgIdFromPrivate = new HashSet();
@@ -65,30 +72,76 @@ public class JcaContentSignerBuilder
6572

6673
private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper());
6774
private SecureRandom random;
68-
private DigestAlgorithmIdentifierFinder digestAlgIdFinder;
6975

7076
private AlgorithmIdentifier sigAlgId;
7177
private AlgorithmParameterSpec sigAlgSpec;
7278

79+
/**
80+
* Construct a basic content signer where the signature algorithm name
81+
* tells us all we need to know.
82+
*
83+
* @param signatureAlgorithm the signature algorithm we perform.
84+
*/
7385
public JcaContentSignerBuilder(String signatureAlgorithm)
7486
{
7587
this(signatureAlgorithm, (AlgorithmIdentifier)null);
7688
}
7789

78-
public JcaContentSignerBuilder(String signatureAlgorithm, AlgorithmIdentifier signatureDigestAlgorithmID)
90+
//
91+
// at the moment LMS is the only algorithm like this, we can wing it with other public keys.
92+
//
93+
private static AlgorithmIdentifier getSigDigAlgId(PublicKey publicKey)
7994
{
80-
this.signatureAlgorithm = signatureAlgorithm;
81-
this.signatureDigestAlgorithm = signatureDigestAlgorithmID;
82-
this.digestAlgIdFinder = null;
95+
byte[] encoded = publicKey.getEncoded();
96+
SubjectPublicKeyInfo subInfo = SubjectPublicKeyInfo.getInstance(encoded);
97+
98+
if (subInfo.getAlgorithm().getAlgorithm().equals(PKCSObjectIdentifiers.id_alg_hss_lms_hashsig))
99+
{
100+
byte[] keyData = subInfo.getPublicKeyData().getOctets();
101+
102+
int type = Pack.bigEndianToInt(keyData, 4);
103+
LMSigParameters sigParams = LMSigParameters.getParametersForType(type);
104+
105+
return new AlgorithmIdentifier(sigParams.getDigestOID());
106+
}
107+
108+
return null;
83109
}
84110

85-
public JcaContentSignerBuilder(String signatureAlgorithm, DigestAlgorithmIdentifierFinder digestAlgIdFinder)
111+
/**
112+
* Constructor which calculates the digest algorithm used from the public key, if necessary.
113+
* <p>
114+
* Some PKIX operations, such as CMS signing, require the digest algorithm used for in the
115+
* signature. Some algorithms, such as LMS, use different digests with different parameter sets but the same OID
116+
* is used to represent the signature. In this case we either need to be told what digest is associated
117+
* with the parameter set, or we need the public key so we can work it out.
118+
* </p>
119+
*
120+
* @param signatureAlgorithm the signature algorithm we perform.
121+
* @param verificationKey the public key associated with our private key.
122+
*/
123+
public JcaContentSignerBuilder(String signatureAlgorithm, PublicKey verificationKey)
86124
{
87-
this.signatureAlgorithm = signatureAlgorithm;
88-
this.signatureDigestAlgorithm = null;
89-
this.digestAlgIdFinder = digestAlgIdFinder;
125+
this(signatureAlgorithm, getSigDigAlgId(verificationKey));
90126
}
91127

128+
/**
129+
* Constructor which includes the digest algorithm identifier used.
130+
* <p>
131+
* Some PKIX operations, such as CMS signing, require the digest algorithm used for in the
132+
* signature, this constructor allows the digest algorithm identifier to
133+
* be explicitly specified.
134+
* </p>
135+
*
136+
* @param signatureAlgorithm the signature algorithm we perform.
137+
* @param signatureDigestAlgorithmID the public key associated with our private key.
138+
*/
139+
public JcaContentSignerBuilder(String signatureAlgorithm, AlgorithmIdentifier signatureDigestAlgorithmID)
140+
{
141+
this.signatureAlgorithm = signatureAlgorithm;
142+
this.signatureDigestAlgorithm = signatureDigestAlgorithmID;
143+
}
144+
92145
public JcaContentSignerBuilder(String signatureAlgorithm, AlgorithmParameterSpec sigParamSpec)
93146
{
94147
this(signatureAlgorithm, sigParamSpec, null);
@@ -158,6 +211,7 @@ public ContentSigner build(PrivateKey privateKey)
158211
{
159212
this.sigAlgId = getSigAlgId(privateKey);
160213
}
214+
161215
final AlgorithmIdentifier signatureAlgId = sigAlgId;
162216
final Signature sig = helper.createSignature(sigAlgId);
163217

@@ -197,11 +251,11 @@ public byte[] getSignature()
197251
}
198252
};
199253

200-
if (signatureDigestAlgorithm != null || digestAlgIdFinder != null)
254+
if (signatureDigestAlgorithm != null)
201255
{
202256
return new ExtendedContentSigner()
203257
{
204-
private final AlgorithmIdentifier digestAlgorithm = (signatureDigestAlgorithm != null) ? signatureDigestAlgorithm : digestAlgIdFinder.find(contentSigner.getAlgorithmIdentifier());
258+
private final AlgorithmIdentifier digestAlgorithm = signatureDigestAlgorithm;
205259
private final ContentSigner signer = contentSigner;
206260

207261
public AlgorithmIdentifier getDigestAlgorithmIdentifier()

pkix/src/test/java/org/bouncycastle/cms/test/PQCSignedDataTest.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ public void testLmsEncapsulated()
306306

307307
DigestCalculatorProvider digCalcProv = new JcaDigestCalculatorProviderBuilder().setProvider(BC).build();
308308

309-
gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(digCalcProv).build(new JcaContentSignerBuilder("LMS", new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256)).setProvider(BC).build(_origLmsKP.getPrivate()), _origLmsCert));
309+
gen.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(digCalcProv).build(new JcaContentSignerBuilder("LMS", _origLmsCert.getPublicKey()).setProvider(BC).build(_origLmsKP.getPrivate()), _origLmsCert));
310310

311311
gen.addCertificates(certs);
312312

@@ -317,6 +317,11 @@ public void testLmsEncapsulated()
317317

318318
s = new CMSSignedData(ContentInfo.getInstance(aIn.readObject()));
319319

320+
Set<AlgorithmIdentifier> digAlgIds = s.getDigestAlgorithmIDs();
321+
322+
assertTrue(digAlgIds.contains(new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256)));
323+
assertTrue(digAlgIds.size() == 1);
324+
320325
certs = s.getCertificates();
321326

322327
SignerInformationStore signers = s.getSignerInfos();

0 commit comments

Comments
 (0)