Skip to content

Commit 0e587f0

Browse files
authored
Merge pull request #1198 from sigstore/algo2
Support more hash/signing algorithms
2 parents 2adbbf8 + 9fd456c commit 0e587f0

28 files changed

Lines changed: 651 additions & 122 deletions

fuzzing/src/main/java/fuzzing/SignerVerifierFuzzer.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import com.code_intelligence.jazzer.api.FuzzedDataProvider;
1919
import dev.sigstore.AlgorithmRegistry;
20+
import dev.sigstore.UnsupportedAlgorithmException;
2021
import dev.sigstore.encryption.signers.Signer;
2122
import dev.sigstore.encryption.signers.Signers;
2223
import dev.sigstore.encryption.signers.Verifier;
@@ -39,7 +40,10 @@ public static void fuzzerTestOneInput(FuzzedDataProvider data) {
3940

4041
var unused1 = verifier.verify(byteArray, signature1);
4142
var unused2 = verifier.verifyDigest(byteArray, signature2);
42-
} catch (InvalidKeyException | NoSuchAlgorithmException | SignatureException e) {
43+
} catch (InvalidKeyException
44+
| NoSuchAlgorithmException
45+
| SignatureException
46+
| UnsupportedAlgorithmException e) {
4347
// Known exception
4448
}
4549
}

sigstore-java/src/main/java/dev/sigstore/AlgorithmRegistry.java

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,27 @@
1515
*/
1616
package dev.sigstore;
1717

18-
import static com.google.common.hash.Hashing.sha256;
19-
20-
import com.google.common.hash.HashFunction;
18+
import java.math.BigInteger;
2119
import java.security.PublicKey;
2220
import java.security.interfaces.ECPublicKey;
2321
import java.security.interfaces.RSAPublicKey;
22+
import java.util.Map;
2423

2524
public class AlgorithmRegistry {
2625

26+
// order to differentiate between the various ec curves
27+
private static final Map<BigInteger, SigningAlgorithm> ECDSA_ORDERS =
28+
Map.of(
29+
new BigInteger(
30+
"115792089210356248762697446949407573529996955224135760342422259061068512044369"),
31+
SigningAlgorithm.PKIX_ECDSA_P256_SHA_256,
32+
new BigInteger(
33+
"39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942643"),
34+
SigningAlgorithm.PKIX_ECDSA_P384_SHA_384,
35+
new BigInteger(
36+
"6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449"),
37+
SigningAlgorithm.PKIX_ECDSA_P521_SHA_512);
38+
2739
/**
2840
* Determine the signing algorithm based on the public key.
2941
*
@@ -53,11 +65,12 @@ public static SigningAlgorithm getSigningAlgorithm(PublicKey publicKey)
5365
if ("EC".equals(algorithm) || "ECDSA".equals(algorithm)) {
5466
if (publicKey instanceof ECPublicKey) {
5567
var ecKey = (ECPublicKey) publicKey;
56-
int fieldSize = ecKey.getParams().getCurve().getField().getFieldSize();
57-
if (fieldSize == 256) {
58-
return SigningAlgorithm.PKIX_ECDSA_P256_SHA_256;
68+
var order = ecKey.getParams().getOrder();
69+
var signingAlgorithm = ECDSA_ORDERS.get(order);
70+
if (signingAlgorithm == null) {
71+
throw new UnsupportedAlgorithmException("Unsupported EC key with order: " + order);
5972
}
60-
throw new UnsupportedAlgorithmException("Unsupported EC field size: " + fieldSize);
73+
return signingAlgorithm;
6174
}
6275
throw new IllegalStateException("EC/ECDSA key must be an instance of ECPublicKey");
6376
}
@@ -70,9 +83,9 @@ public enum SigningAlgorithm {
7083
PKIX_RSA_PKCS1V15_4096_SHA256(HashAlgorithm.SHA2_256),
7184

7285
// ECDSA
73-
PKIX_ECDSA_P256_SHA_256(HashAlgorithm.SHA2_256);
74-
// TODO: PKIX_ECDSA_P384_SHA_384(HashAlgorithm.SHA2_384),
75-
// TODO: PKIX_ECDSA_P521_SHA_512(HashAlgorithm.SHA2_512);
86+
PKIX_ECDSA_P256_SHA_256(HashAlgorithm.SHA2_256),
87+
PKIX_ECDSA_P384_SHA_384(HashAlgorithm.SHA2_384),
88+
PKIX_ECDSA_P521_SHA_512(HashAlgorithm.SHA2_512);
7689

7790
private final HashAlgorithm hashAlgorithm;
7891

@@ -86,30 +99,30 @@ public HashAlgorithm getHashAlgorithm() {
8699
}
87100

88101
public enum HashAlgorithm {
89-
SHA2_256("SHA256", 32, sha256());
90-
// TODO: SHA2_384("SHA384", 48, sha384()),
91-
// TODO: SHA2_512("SHA512", 64, sha512());
102+
SHA2_256("SHA256", "sha256", 32),
103+
SHA2_384("SHA384", "sha384", 48),
104+
SHA2_512("SHA512", "sha512", 64);
92105

93106
private final String name;
107+
private final String lowercase;
94108
private final int length;
95-
private final HashFunction hashFunction;
96109

97-
HashAlgorithm(String name, int length, HashFunction hashFunction) {
110+
HashAlgorithm(String name, String lowercase, int length) {
98111
this.name = name;
112+
this.lowercase = lowercase;
99113
this.length = length;
100-
this.hashFunction = hashFunction;
101114
}
102115

103116
public String toString() {
104117
return name;
105118
}
106119

107-
public int getLength() {
108-
return length;
120+
public String toLowercaseString() {
121+
return lowercase;
109122
}
110123

111-
HashFunction getHashFunction() {
112-
return hashFunction;
124+
public int getLength() {
125+
return length;
113126
}
114127
}
115128
}

sigstore-java/src/main/java/dev/sigstore/KeylessSigner.java

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import com.google.api.client.util.Preconditions;
1919
import com.google.common.collect.ImmutableList;
2020
import com.google.common.collect.ImmutableMap;
21-
import com.google.common.hash.Hashing;
2221
import com.google.errorprone.annotations.CanIgnoreReturnValue;
2322
import com.google.errorprone.annotations.CheckReturnValue;
2423
import com.google.errorprone.annotations.concurrent.GuardedBy;
@@ -30,6 +29,7 @@
3029
import dev.sigstore.bundle.ImmutableSignature;
3130
import dev.sigstore.bundle.ImmutableTimestamp;
3231
import dev.sigstore.dsse.InTotoPayload;
32+
import dev.sigstore.encryption.Hashers;
3333
import dev.sigstore.encryption.certificates.Certificates;
3434
import dev.sigstore.encryption.signers.Signer;
3535
import dev.sigstore.encryption.signers.Signers;
@@ -59,6 +59,7 @@
5959
import dev.sigstore.rekor.client.RekorVerifier;
6060
import dev.sigstore.rekor.v2.client.RekorV2Client;
6161
import dev.sigstore.rekor.v2.client.RekorV2ClientHttp;
62+
import dev.sigstore.timestamp.client.HashAlgorithm;
6263
import dev.sigstore.timestamp.client.ImmutableTimestampRequest;
6364
import dev.sigstore.timestamp.client.TimestampClient;
6465
import dev.sigstore.timestamp.client.TimestampClientHttp;
@@ -452,6 +453,8 @@ public List<Bundle> sign(List<byte[]> artifactDigests) throws KeylessSignerExcep
452453
lock.readLock().unlock();
453454
}
454455

456+
var hashFunction = Hashers.from(signingAlgorithm.getHashAlgorithm());
457+
455458
var bundleBuilder =
456459
ImmutableBundle.builder()
457460
.certPath(signingCert)
@@ -465,11 +468,11 @@ public List<Bundle> sign(List<byte[]> artifactDigests) throws KeylessSignerExcep
465468
Preconditions.checkNotNull(
466469
timestampVerifier, "Timestamp verifier must be configured for Rekor v2");
467470

468-
var signatureDigest = Hashing.sha256().hashBytes(signature).asBytes();
471+
var signatureDigest = hashFunction.hashBytes(signature).asBytes();
469472

470473
var tsReq =
471474
ImmutableTimestampRequest.builder()
472-
.hashAlgorithm(dev.sigstore.timestamp.client.HashAlgorithm.SHA256)
475+
.hashAlgorithm(HashAlgorithm.from(signingAlgorithm.getHashAlgorithm()))
473476
.hash(signatureDigest)
474477
.build();
475478

@@ -534,7 +537,10 @@ public List<Bundle> sign(List<byte[]> artifactDigests) throws KeylessSignerExcep
534537
} else if (rekorClient != null) { // Using Rekor v1
535538
var rekorRequest =
536539
HashedRekordRequest.newHashedRekordRequest(
537-
artifactDigest, signingCertPemBytes, signature);
540+
artifactDigest,
541+
signingAlgorithm.getHashAlgorithm(),
542+
signingCertPemBytes,
543+
signature);
538544

539545
RekorResponse rekorResponse;
540546
try {
@@ -654,11 +660,9 @@ public Map<Path, Bundle> signFiles(List<Path> artifacts) throws KeylessSignerExc
654660
var digests = new ArrayList<byte[]>(artifacts.size());
655661
for (var artifact : artifacts) {
656662
var artifactByteSource = com.google.common.io.Files.asByteSource(artifact.toFile());
663+
var hashFunction = Hashers.from(signingAlgorithm);
657664
try {
658-
digests.add(
659-
artifactByteSource
660-
.hash(signingAlgorithm.getHashAlgorithm().getHashFunction())
661-
.asBytes());
665+
digests.add(artifactByteSource.hash(hashFunction).asBytes());
662666
} catch (IOException ex) {
663667
throw new KeylessSignerException("Failed to hash artifact " + artifact);
664668
}
@@ -795,11 +799,12 @@ public Bundle attest(String payload) throws KeylessSignerException {
795799
.addVerifiers(verifier)
796800
.build();
797801

798-
var signatureDigest = Hashing.sha256().hashBytes(dsseSigned.getSignature()).asBytes();
802+
var hashFunction = Hashers.from(signingAlgorithm);
803+
var signatureDigest = hashFunction.hashBytes(dsseSigned.getSignature()).asBytes();
799804

800805
var tsReq =
801806
ImmutableTimestampRequest.builder()
802-
.hashAlgorithm(dev.sigstore.timestamp.client.HashAlgorithm.SHA256)
807+
.hashAlgorithm(HashAlgorithm.from(signingAlgorithm.getHashAlgorithm()))
803808
.hash(signatureDigest)
804809
.build();
805810

0 commit comments

Comments
 (0)