Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup #850

Merged
merged 1 commit into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 0 additions & 39 deletions fuzzing/src/main/java/fuzzing/TufKeysFuzzer.java

This file was deleted.

85 changes: 1 addition & 84 deletions sigstore-java/src/main/java/dev/sigstore/encryption/Keys.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,22 @@
*/
package dev.sigstore.encryption;

import static org.bouncycastle.jce.ECPointUtil.decodePoint;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.ECPoint;
import java.security.spec.ECPublicKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.List;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.jce.spec.ECNamedCurveSpec;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.util.encoders.DecoderException;
Expand Down Expand Up @@ -74,6 +64,7 @@ public static PublicKey parsePublicKey(byte[] keyBytes)
"sigstore public keys must be only a single PEM encoded public key");
}
JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
converter.setProvider(BouncyCastleProvider.PROVIDER_NAME);
if (keyObj instanceof SubjectPublicKeyInfo) {
PublicKey pk = converter.getPublicKey((SubjectPublicKeyInfo) keyObj);
if (!SUPPORTED_KEY_TYPES.contains(pk.getAlgorithm())) {
Expand Down Expand Up @@ -115,78 +106,4 @@ public static PublicKey parsePkcs1RsaPublicKey(byte[] contents)
KeyFactory factory = KeyFactory.getInstance("RSA");
return factory.generatePublic(keySpec);
}

/**
* Valid values for scheme are:
*
* <ol>
* <li><a href="https://ed25519.cr.yp.to/">ed25519</a>
* <li><a
* href="https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm">ecdsa-sha2-nistp256</a>
* </ol>
*
* @see <a
* href="https://theupdateframework.github.io/specification/latest/index.html#role-role">spec</a>
* @param contents keyBytes
* @param scheme signing scheme
* @return java {link PublicKey}
* @throws NoSuchAlgorithmException if we don't support the scheme provided
* @throws InvalidKeySpecException if the public key material is invalid
*/
public static PublicKey constructTufPublicKey(byte[] contents, String scheme)
throws NoSuchAlgorithmException, InvalidKeySpecException {
if (contents == null || contents.length == 0) {
throw new InvalidKeySpecException("key contents was empty");
}
switch (scheme) {
case "ed25519":
{
final KeyFactory kf = KeyFactory.getInstance("Ed25519");
X509EncodedKeySpec keySpec;
// tuf allows raw keys only for ed25519 (non PEM):
// https://github.com/theupdateframework/specification/blob/c51875f445d8a57efca9dadfbd5dbdece06d87e6/tuf-spec.md#key-objects--file-formats-keys
if (contents.length == 32) {
var params =
new SubjectPublicKeyInfo(
new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519), contents);
try {
keySpec = new X509EncodedKeySpec(params.getEncoded());
} catch (IOException e) {
throw new RuntimeException(e);
}
} else {
keySpec = new X509EncodedKeySpec(contents);
}
return kf.generatePublic(keySpec);
}
case "ecdsa":
case "ecdsa-sha2-nistp256":
{
// spec for P-256 curve
ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec("P-256");
// create a KeyFactory with ECDSA (Elliptic Curve Diffie-Hellman) algorithm and use
// BouncyCastle as the provider
KeyFactory kf = null;
try {
kf = KeyFactory.getInstance("ECDSA", BouncyCastleProvider.PROVIDER_NAME);
} catch (NoSuchProviderException e) {
throw new RuntimeException(e);
}

// code below just creates the public key from key contents using the curve parameters
// (spec variable)
try {
ECNamedCurveSpec params =
new ECNamedCurveSpec("P-256", spec.getCurve(), spec.getG(), spec.getN());
ECPoint point = decodePoint(params.getCurve(), contents);
ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(point, params);
return kf.generatePublic(pubKeySpec);
} catch (IllegalArgumentException | NullPointerException ex) {
throw new InvalidKeySpecException("ecdsa key was not parseable", ex);
}
}
default:
throw new RuntimeException(scheme + " not currently supported");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,6 @@

/** Autodetection for verification algorithms based on public keys used. */
public class Verifiers {
@FunctionalInterface
public interface Supplier {
public Verifier newVerifier(PublicKey publicKey) throws NoSuchAlgorithmException;
}

/** Returns a new verifier for the provided public key to use during verification. */
public static Verifier newVerifier(PublicKey publicKey) throws NoSuchAlgorithmException {
if (publicKey.getAlgorithm().equals("RSA")) {
Expand Down
121 changes: 3 additions & 118 deletions sigstore-java/src/test/java/dev/sigstore/encryption/KeysTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,11 @@
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.util.encoders.Hex;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledForJreRange;
import org.junit.jupiter.api.condition.JRE;

class KeysTest {

Expand Down Expand Up @@ -73,24 +69,15 @@ void parsePublicKey_ec() throws IOException, InvalidKeySpecException, NoSuchAlgo
}

@Test
@EnabledForJreRange(max = JRE.JAVA_14)
void parsePublicKey_ed25519_withBouncyCastle()
void parsePublicKey_ed25519()
throws IOException, InvalidKeySpecException, NoSuchAlgorithmException {
PublicKey result =
Keys.parsePublicKey(Resources.toByteArray(Resources.getResource(ED25519_PUB_PATH)));
// BouncyCastle names the algorithm differently than the JDK (Ed25519 vs EdDSA)
// BouncyCastle names the algorithm differently than the JDK (Ed25519 vs EdDSA) but we
// force the converter to use BouncyCastle always.
assertEquals("Ed25519", result.getAlgorithm());
}

@Test
@EnabledForJreRange(min = JRE.JAVA_15)
void parsePublicKey_ed25519_withStdLib()
throws IOException, InvalidKeySpecException, NoSuchAlgorithmException {
PublicKey result =
Keys.parsePublicKey(Resources.toByteArray(Resources.getResource(ED25519_PUB_PATH)));
assertEquals("EdDSA", result.getAlgorithm());
}

@Test
void parsePublicKey_dsaShouldFail() {
Assertions.assertThrows(
Expand All @@ -106,108 +93,6 @@ void parseTufPublicKeyPemEncoded_sha2_nistp256()
assertEquals("ECDSA", result.getAlgorithm());
}

@Test
void parseTufPublicKey_ecdsa() throws NoSuchAlgorithmException, InvalidKeySpecException {
PublicKey key =
Keys.constructTufPublicKey(
Hex.decode(
"04cbc5cab2684160323c25cd06c3307178a6b1d1c9b949328453ae473c5ba7527e35b13f298b41633382241f3fd8526c262d43b45adee5c618fa0642c82b8a9803"),
"ecdsa-sha2-nistp256");
assertNotNull(key);
assertEquals("ECDSA", key.getAlgorithm());
}

@Test
void parseTufPublicKey_ecdsaBad() {
Assertions.assertThrows(
InvalidKeySpecException.class,
() -> {
Keys.constructTufPublicKey(
Hex.decode(
"04cbcdcab2684160323c25cd06c3307178a6b1d1c9b949328453ae473c5ba7527e35b13f298b41633382241f3fd8526c262d43b45adee5c618fa0642c82b8a9803"),
"ecdsa-sha2-nistp256");
});
}

@Test
@EnabledForJreRange(min = JRE.JAVA_15)
void parseTufPublicKey_ed25519_java15Plus()
throws NoSuchAlgorithmException, InvalidKeySpecException {
// {@code step crypto keypair ed25519.pub /dev/null --kty OKP --curve Ed25519}
// copy just the key part out of ed25519.pub removing PEM header and footer
// {@code echo $(copied content) | base64 -d | hexdump -v -e '/1 "%02x" '}
PublicKey key =
Keys.constructTufPublicKey(
Hex.decode(
"302a300506032b65700321008b2e369230c3b97f4627fd6a59eb054a83ec15ed929ab3d983a40ffd322a223d"),
"ed25519");
assertNotNull(key);
assertEquals("EdDSA", key.getAlgorithm());
}

@Test
@EnabledForJreRange(max = JRE.JAVA_14)
void parseTufPublicKey_ed25519_lteJava14()
throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException {
// {@code step crypto keypair ed25519.pub /dev/null --kty OKP --curve Ed25519}
// copy just the key part out of ed25519.pub removing PEM header and footer
// {@code echo $(copied content) | base64 -d | hexdump -v -e '/1 "%02x" '}
PublicKey key =
Keys.constructTufPublicKey(
Hex.decode(
"302a300506032b65700321008b2e369230c3b97f4627fd6a59eb054a83ec15ed929ab3d983a40ffd322a223d"),
"ed25519");
assertNotNull(key);
assertEquals("Ed25519", key.getAlgorithm());
}

@Test
@EnabledForJreRange(min = JRE.JAVA_15)
void parseTufPublicKey_ed25519_rawBytes_java15plus() throws Exception {
PublicKey key =
Keys.constructTufPublicKey(
Hex.decode("2d7218ce609f85de4b0d29d9e679cfd73e96756652f7069a0cf00acb752e5d3c"),
"ed25519");
assertNotNull(key);
assertEquals("EdDSA", key.getAlgorithm());
}

@Test
@EnabledForJreRange(max = JRE.JAVA_14)
void parseTufPublicKey_ed25519_rawBytes_lteJava14() throws Exception {
PublicKey key =
Keys.constructTufPublicKey(
Hex.decode("2d7218ce609f85de4b0d29d9e679cfd73e96756652f7069a0cf00acb752e5d3c"),
"ed25519");
assertNotNull(key);
assertEquals("Ed25519", key.getAlgorithm());
}

@Test
void parseTufPublicKey_ed25519Bad() {
Assertions.assertThrows(
InvalidKeySpecException.class,
() ->
Keys.constructTufPublicKey(
Hex.decode(
"302b300506032b65700321008b2e369230c3b97f4627fd6a59eb054a83ec15ed929ab3d983a40ffd322a223d"),
"ed25519"));
}

@Test
void parseTufPublicKey_rsa() throws NoSuchAlgorithmException, InvalidKeySpecException {
// {@code step crypto keypair ed25519.pub /dev/null --kty OKP --curve Ed25519}
// copy just the key part out of ed25519.pub removing PEM header and footer
// {@code echo $(copied content) | base64 -d | hexdump -v -e '/1 "%02x" '}
Assertions.assertThrows(
RuntimeException.class,
() ->
Keys.constructTufPublicKey(
Hex.decode(
"302a300506032b65700321008b2e369230c3b97f4627fd6a59eb054a83ec15ed929ab3d983a40ffd322a223d"),
"rsassa-pss-sha256"));
}

@Test
void parsePkixPublicKey_rsa() throws NoSuchAlgorithmException, InvalidKeySpecException {
var base64Key =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

class FileSystemTufStoreTest {

public static final String PROD_REPO = "real/prod";
public static final String REPO = "synthetic/test-template";

@Test
void newFileSystemStore_empty(@TempDir Path repoBase) throws IOException {
Expand All @@ -37,7 +37,7 @@ void newFileSystemStore_empty(@TempDir Path repoBase) throws IOException {

@Test
void newFileSystemStore_hasRepo(@TempDir Path repoBase) throws IOException {
TestResources.setupRepoFiles(PROD_REPO, repoBase, "root.json");
TestResources.setupRepoFiles(REPO, repoBase, "root.json");
FileSystemTufStore tufStore = FileSystemTufStore.newFileSystemStore(repoBase);
assertTrue(tufStore.readMeta(RootRole.ROOT, Root.class).isPresent());
}
Expand All @@ -47,15 +47,15 @@ void writeMeta(@TempDir Path repoBase) throws IOException {
FileSystemTufStore tufStore = FileSystemTufStore.newFileSystemStore(repoBase);
assertFalse(repoBase.resolve("root.json").toFile().exists());
tufStore.writeMeta(
RootRole.ROOT, TestResources.loadRoot(TestResources.UPDATER_REAL_TRUSTED_ROOT));
RootRole.ROOT, TestResources.loadRoot(TestResources.UPDATER_SYNTHETIC_TRUSTED_ROOT));
assertEquals(2, repoBase.toFile().list().length, "Expect 2: root.json plus the /targets dir.");
assertTrue(repoBase.resolve("root.json").toFile().exists());
assertTrue(repoBase.resolve("targets").toFile().isDirectory());
}

@Test
void clearMeta(@TempDir Path repoBase) throws IOException {
TestResources.setupRepoFiles(PROD_REPO, repoBase, "snapshot.json", "timestamp.json");
TestResources.setupRepoFiles(REPO, repoBase, "snapshot.json", "timestamp.json");
FileSystemTufStore tufStore = FileSystemTufStore.newFileSystemStore(repoBase);
assertTrue(repoBase.resolve("snapshot.json").toFile().exists());
assertTrue(repoBase.resolve("timestamp.json").toFile().exists());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ class PassthroughCacheMetaStoreTest {
@BeforeAll
public static void readAllMeta() throws IOException {
Path timestampResource =
Path.of(Resources.getResource("dev/sigstore/tuf/real/prod/timestamp.json").getPath());
Path.of(
Resources.getResource("dev/sigstore/tuf/synthetic/test/repository/timestamp.json")
.getPath());
timestamp = GSON.get().fromJson(Files.newBufferedReader(timestampResource), Timestamp.class);
}

Expand Down
Loading
Loading