Skip to content

Commit

Permalink
removed unnecessary length check in LMS PublicKeyFactory
Browse files Browse the repository at this point in the history
added support for public key check to work out digest ID.
updated PQCSignedDataTest to use the public key approach with LMS
  • Loading branch information
dghgit committed Dec 3, 2024
1 parent 05ac657 commit 053d87b
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public ASN1ObjectIdentifier getDigestOID()
return digestOid;
}

static LMSigParameters getParametersForType(int type)
public static LMSigParameters getParametersForType(int type)
{
return paramBuilders.get(type);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -451,10 +451,6 @@ AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Obje
private LMSKeyParameters getLmsKeyParameters(byte[] keyEnc)
throws IOException
{
if (keyEnc.length == 64)
{
keyEnc = Arrays.copyOfRange(keyEnc, 4, keyEnc.length);
}
return HSSPublicKeyParameters.getInstance(keyEnc);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.security.GeneralSecurityException;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.SignatureException;
Expand All @@ -27,6 +28,7 @@
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.jcajce.CompositePrivateKey;
import org.bouncycastle.jcajce.io.OutputStreamFactory;
import org.bouncycastle.jcajce.spec.CompositeAlgorithmSpec;
Expand All @@ -41,9 +43,14 @@
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.RuntimeOperatorException;
import org.bouncycastle.operator.SignatureAlgorithmIdentifierFinder;
import org.bouncycastle.pqc.crypto.lms.LMSigParameters;
import org.bouncycastle.util.Pack;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.io.TeeOutputStream;

/**
* General builder class for ContentSigner operators based on the JCA.
*/
public class JcaContentSignerBuilder
{
private static final Set isAlgIdFromPrivate = new HashSet();
Expand All @@ -65,30 +72,76 @@ public class JcaContentSignerBuilder

private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper());
private SecureRandom random;
private DigestAlgorithmIdentifierFinder digestAlgIdFinder;

private AlgorithmIdentifier sigAlgId;
private AlgorithmParameterSpec sigAlgSpec;

/**
* Construct a basic content signer where the signature algorithm name
* tells us all we need to know.
*
* @param signatureAlgorithm the signature algorithm we perform.
*/
public JcaContentSignerBuilder(String signatureAlgorithm)
{
this(signatureAlgorithm, (AlgorithmIdentifier)null);
}

public JcaContentSignerBuilder(String signatureAlgorithm, AlgorithmIdentifier signatureDigestAlgorithmID)
//
// at the moment LMS is the only algorithm like this, we can wing it with other public keys.
//
private static AlgorithmIdentifier getSigDigAlgId(PublicKey publicKey)
{
this.signatureAlgorithm = signatureAlgorithm;
this.signatureDigestAlgorithm = signatureDigestAlgorithmID;
this.digestAlgIdFinder = null;
byte[] encoded = publicKey.getEncoded();
SubjectPublicKeyInfo subInfo = SubjectPublicKeyInfo.getInstance(encoded);

if (subInfo.getAlgorithm().getAlgorithm().equals(PKCSObjectIdentifiers.id_alg_hss_lms_hashsig))
{
byte[] keyData = subInfo.getPublicKeyData().getOctets();

int type = Pack.bigEndianToInt(keyData, 4);
LMSigParameters sigParams = LMSigParameters.getParametersForType(type);

return new AlgorithmIdentifier(sigParams.getDigestOID());
}

return null;
}

public JcaContentSignerBuilder(String signatureAlgorithm, DigestAlgorithmIdentifierFinder digestAlgIdFinder)
/**
* Constructor which calculates the digest algorithm used from the public key, if necessary.
* <p>
* Some PKIX operations, such as CMS signing, require the digest algorithm used for in the
* signature. Some algorithms, such as LMS, use different digests with different parameter sets but the same OID
* is used to represent the signature. In this case we either need to be told what digest is associated
* with the parameter set, or we need the public key so we can work it out.
* </p>
*
* @param signatureAlgorithm the signature algorithm we perform.
* @param verificationKey the public key associated with our private key.
*/
public JcaContentSignerBuilder(String signatureAlgorithm, PublicKey verificationKey)
{
this.signatureAlgorithm = signatureAlgorithm;
this.signatureDigestAlgorithm = null;
this.digestAlgIdFinder = digestAlgIdFinder;
this(signatureAlgorithm, getSigDigAlgId(verificationKey));
}

/**
* Constructor which includes the digest algorithm identifier used.
* <p>
* Some PKIX operations, such as CMS signing, require the digest algorithm used for in the
* signature, this constructor allows the digest algorithm identifier to
* be explicitly specified.
* </p>
*
* @param signatureAlgorithm the signature algorithm we perform.
* @param signatureDigestAlgorithmID the public key associated with our private key.
*/
public JcaContentSignerBuilder(String signatureAlgorithm, AlgorithmIdentifier signatureDigestAlgorithmID)
{
this.signatureAlgorithm = signatureAlgorithm;
this.signatureDigestAlgorithm = signatureDigestAlgorithmID;
}

public JcaContentSignerBuilder(String signatureAlgorithm, AlgorithmParameterSpec sigParamSpec)
{
this(signatureAlgorithm, sigParamSpec, null);
Expand Down Expand Up @@ -158,6 +211,7 @@ public ContentSigner build(PrivateKey privateKey)
{
this.sigAlgId = getSigAlgId(privateKey);
}

final AlgorithmIdentifier signatureAlgId = sigAlgId;
final Signature sig = helper.createSignature(sigAlgId);

Expand Down Expand Up @@ -197,11 +251,11 @@ public byte[] getSignature()
}
};

if (signatureDigestAlgorithm != null || digestAlgIdFinder != null)
if (signatureDigestAlgorithm != null)
{
return new ExtendedContentSigner()
{
private final AlgorithmIdentifier digestAlgorithm = (signatureDigestAlgorithm != null) ? signatureDigestAlgorithm : digestAlgIdFinder.find(contentSigner.getAlgorithmIdentifier());
private final AlgorithmIdentifier digestAlgorithm = signatureDigestAlgorithm;
private final ContentSigner signer = contentSigner;

public AlgorithmIdentifier getDigestAlgorithmIdentifier()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ public void testLmsEncapsulated()

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

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

gen.addCertificates(certs);

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

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

Set<AlgorithmIdentifier> digAlgIds = s.getDigestAlgorithmIDs();

assertTrue(digAlgIds.contains(new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256)));
assertTrue(digAlgIds.size() == 1);

certs = s.getCertificates();

SignerInformationStore signers = s.getSignerInfos();
Expand Down

0 comments on commit 053d87b

Please sign in to comment.