diff --git a/fuzzing/src/main/java/util/Tuf.java b/fuzzing/src/main/java/util/Tuf.java index 4c2909c6..af73768e 100644 --- a/fuzzing/src/main/java/util/Tuf.java +++ b/fuzzing/src/main/java/util/Tuf.java @@ -17,18 +17,14 @@ import com.code_intelligence.jazzer.api.FuzzedDataProvider; import com.google.common.hash.Hashing; -import dev.sigstore.trustroot.CertificateAuthorities; import dev.sigstore.trustroot.CertificateAuthority; -import dev.sigstore.trustroot.ImmutableCertificateAuthorities; import dev.sigstore.trustroot.ImmutableCertificateAuthority; import dev.sigstore.trustroot.ImmutableLogId; import dev.sigstore.trustroot.ImmutablePublicKey; import dev.sigstore.trustroot.ImmutableSubject; import dev.sigstore.trustroot.ImmutableTransparencyLog; -import dev.sigstore.trustroot.ImmutableTransparencyLogs; import dev.sigstore.trustroot.ImmutableValidFor; import dev.sigstore.trustroot.TransparencyLog; -import dev.sigstore.trustroot.TransparencyLogs; import java.io.ByteArrayInputStream; import java.net.URI; import java.security.cert.CertPath; @@ -47,17 +43,17 @@ public final class Tuf { // ecdsa key size in bytes private static final int ECDSA_KEY_BYTES = 91; - public static TransparencyLogs transparencyLogsFrom(FuzzedDataProvider data) { - return ImmutableTransparencyLogs.builder().addTransparencyLog(genTlog(data)).build(); + public static List transparencyLogsFrom(FuzzedDataProvider data) { + return List.of(genTlog(data)); } - public static CertificateAuthorities certificateAuthoritiesFrom(FuzzedDataProvider data) + public static List certificateAuthoritiesFrom(FuzzedDataProvider data) throws CertificateException { - return ImmutableCertificateAuthorities.builder().addCertificateAuthority(genCA(data)).build(); + return List.of(genCA(data)); } private static CertPath genCertPath(FuzzedDataProvider data) throws CertificateException { - List certList = new ArrayList(); + List certList = new ArrayList<>(); CertificateFactory cf = CertificateFactory.getInstance("X.509"); certList.add( cf.generateCertificate(new ByteArrayInputStream(data.consumeBytes(MAX_CERT_SIZE)))); diff --git a/sigstore-java/src/main/java/dev/sigstore/KeylessSigner.java b/sigstore-java/src/main/java/dev/sigstore/KeylessSigner.java index 132ce2c7..d4f44915 100644 --- a/sigstore-java/src/main/java/dev/sigstore/KeylessSigner.java +++ b/sigstore-java/src/main/java/dev/sigstore/KeylessSigner.java @@ -22,6 +22,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; import com.google.errorprone.annotations.CheckReturnValue; import com.google.errorprone.annotations.concurrent.GuardedBy; +import dev.sigstore.KeylessVerifier.Builder; import dev.sigstore.encryption.certificates.Certificates; import dev.sigstore.encryption.signers.Signer; import dev.sigstore.encryption.signers.Signers; @@ -41,6 +42,7 @@ import dev.sigstore.rekor.client.RekorVerifier; import dev.sigstore.tuf.SigstoreTufClient; import java.io.IOException; +import java.net.URI; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.security.InvalidAlgorithmParameterException; @@ -132,15 +134,29 @@ public static Builder builder() { } public static class Builder { - private SigstoreTufClient sigstoreTufClient; + private TrustedRootProvider trustedRootProvider; private OidcClients oidcClients; private List oidcIdentities = Collections.emptyList(); private Signer signer; private Duration minSigningCertificateLifetime = DEFAULT_MIN_SIGNING_CERTIFICATE_LIFETIME; + private URI fulcioUri; + private URI rekorUri; @CanIgnoreReturnValue - public Builder sigstoreTufClient(SigstoreTufClient sigstoreTufClient) { - this.sigstoreTufClient = sigstoreTufClient; + public Builder fulcioUrl(URI uri) { + this.fulcioUri = uri; + return this; + } + + @CanIgnoreReturnValue + public Builder rekorUrl(URI uri) { + this.rekorUri = uri; + return this; + } + + @CanIgnoreReturnValue + public Builder trustedRoot(Path trustedRoot) { + trustedRootProvider = TrustedRootProvider.from(trustedRoot); return this; } @@ -152,7 +168,8 @@ public Builder oidcClients(OidcClients oidcClients) { /** * An allow list OIDC identities to be used during signing. If the OidcClients are misconfigured - * or pick up unexpected credentials, this should prevent signing from proceeding + * or pick up unexpected credentials, this should prevent signing from proceeding. Cannot be + * null but can be an empty list and will allow all identities. */ @CanIgnoreReturnValue public Builder allowedOidcIdentities(List oidcIdentities) { @@ -188,14 +205,17 @@ public Builder minSigningCertificateLifetime(Duration minSigningCertificateLifet public KeylessSigner build() throws CertificateException, IOException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, InvalidAlgorithmParameterException { - Preconditions.checkNotNull(sigstoreTufClient, "sigstoreTufClient"); - sigstoreTufClient.update(); - var trustedRoot = sigstoreTufClient.getSigstoreTrustedRoot(); - var fulcioClient = - FulcioClient.builder().setUri(trustedRoot.getCAs().current().getUri()).build(); + Preconditions.checkNotNull(trustedRootProvider); + var trustedRoot = trustedRootProvider.get(); + Preconditions.checkNotNull(fulcioUri); + Preconditions.checkNotNull(rekorUri); + Preconditions.checkNotNull(oidcClients); + Preconditions.checkNotNull(oidcIdentities); + Preconditions.checkNotNull(signer); + Preconditions.checkNotNull(minSigningCertificateLifetime); + var fulcioClient = FulcioClient.builder().setUri(fulcioUri).build(); var fulcioVerifier = FulcioVerifier.newFulcioVerifier(trustedRoot); - var rekorClient = - RekorClient.builder().setUri(trustedRoot.getTLogs().current().getBaseUrl()).build(); + var rekorClient = RekorClient.builder().setUri(rekorUri).build(); var rekorVerifier = RekorVerifier.newRekorVerifier(trustedRoot); return new KeylessSigner( fulcioClient, @@ -213,9 +233,12 @@ public KeylessSigner build() * ecdsa signing. */ @CanIgnoreReturnValue - public Builder sigstorePublicDefaults() throws IOException, NoSuchAlgorithmException { - sigstoreTufClient = SigstoreTufClient.builder().usePublicGoodInstance().build(); - oidcClients(OidcClients.DEFAULTS); + public Builder sigstorePublicDefaults() { + var sigstoreTufClientBuilder = SigstoreTufClient.builder().usePublicGoodInstance(); + trustedRootProvider = TrustedRootProvider.from(sigstoreTufClientBuilder); + fulcioUri = FulcioClient.PUBLIC_GOOD_URI; + rekorUri = RekorClient.PUBLIC_GOOD_URI; + oidcClients(OidcClients.PUBLIC_GOOD); signer(Signers.newEcdsaSigner()); minSigningCertificateLifetime(DEFAULT_MIN_SIGNING_CERTIFICATE_LIFETIME); return this; @@ -226,9 +249,12 @@ public Builder sigstorePublicDefaults() throws IOException, NoSuchAlgorithmExcep * signing. */ @CanIgnoreReturnValue - public Builder sigstoreStagingDefaults() throws IOException, NoSuchAlgorithmException { - sigstoreTufClient = SigstoreTufClient.builder().useStagingInstance().build(); - oidcClients(OidcClients.STAGING_DEFAULTS); + public Builder sigstoreStagingDefaults() { + var sigstoreTufClientBuilder = SigstoreTufClient.builder().useStagingInstance(); + trustedRootProvider = TrustedRootProvider.from(sigstoreTufClientBuilder); + fulcioUri = FulcioClient.STAGING_URI; + rekorUri = RekorClient.STAGING_URI; + oidcClients(OidcClients.STAGING); signer(Signers.newEcdsaSigner()); minSigningCertificateLifetime(DEFAULT_MIN_SIGNING_CERTIFICATE_LIFETIME); return this; diff --git a/sigstore-java/src/main/java/dev/sigstore/KeylessVerifier.java b/sigstore-java/src/main/java/dev/sigstore/KeylessVerifier.java index 211bf927..ecfe2a72 100644 --- a/sigstore-java/src/main/java/dev/sigstore/KeylessVerifier.java +++ b/sigstore-java/src/main/java/dev/sigstore/KeylessVerifier.java @@ -79,7 +79,7 @@ public KeylessVerifier build() var fulcioVerifier = FulcioVerifier.newFulcioVerifier(trustedRoot); var rekorVerifier = RekorVerifier.newRekorVerifier(trustedRoot); var rekorClients = - trustedRoot.getTLogs().getTransparencyLogs().stream() + trustedRoot.getTLogs().stream() .map(TransparencyLog::getBaseUrl) .distinct() .map(uri -> RekorClient.builder().setUri(uri).build()) @@ -87,15 +87,15 @@ public KeylessVerifier build() return new KeylessVerifier(fulcioVerifier, rekorClients, rekorVerifier); } - public Builder sigstorePublicDefaults() throws IOException { - var sigstoreTufClient = SigstoreTufClient.builder().usePublicGoodInstance().build(); - trustedRootProvider = TrustedRootProvider.from(sigstoreTufClient); + public Builder sigstorePublicDefaults() { + var sigstoreTufClientBuilder = SigstoreTufClient.builder().usePublicGoodInstance(); + trustedRootProvider = TrustedRootProvider.from(sigstoreTufClientBuilder); return this; } - public Builder sigstoreStagingDefaults() throws IOException { - var sigstoreTufClient = SigstoreTufClient.builder().useStagingInstance().build(); - trustedRootProvider = TrustedRootProvider.from(sigstoreTufClient); + public Builder sigstoreStagingDefaults() { + var sigstoreTufClientBuilder = SigstoreTufClient.builder().useStagingInstance(); + trustedRootProvider = TrustedRootProvider.from(sigstoreTufClientBuilder); return this; } @@ -220,7 +220,7 @@ private RekorEntry getEntryFromRekor( byte[] artifactDigest, X509Certificate leafCert, byte[] signature) throws KeylessVerificationException { // rebuild the hashedRekord so we can query the log for it - HashedRekordRequest hashedRekordRequest = null; + HashedRekordRequest hashedRekordRequest; try { hashedRekordRequest = HashedRekordRequest.newHashedRekordRequest( diff --git a/sigstore-java/src/main/java/dev/sigstore/TrustedRootProvider.java b/sigstore-java/src/main/java/dev/sigstore/TrustedRootProvider.java index b615f118..2e92676b 100644 --- a/sigstore-java/src/main/java/dev/sigstore/TrustedRootProvider.java +++ b/sigstore-java/src/main/java/dev/sigstore/TrustedRootProvider.java @@ -37,9 +37,10 @@ SigstoreTrustedRoot get() throws InvalidAlgorithmParameterException, CertificateException, InvalidKeySpecException, NoSuchAlgorithmException, IOException, InvalidKeyException; - static TrustedRootProvider from(SigstoreTufClient tufClient) { - Preconditions.checkNotNull(tufClient); + static TrustedRootProvider from(SigstoreTufClient.Builder tufClientBuilder) { + Preconditions.checkNotNull(tufClientBuilder); return () -> { + var tufClient = tufClientBuilder.build(); tufClient.update(); return tufClient.getSigstoreTrustedRoot(); }; diff --git a/sigstore-java/src/main/java/dev/sigstore/encryption/signers/Signers.java b/sigstore-java/src/main/java/dev/sigstore/encryption/signers/Signers.java index 07ed1ab8..c35f404e 100644 --- a/sigstore-java/src/main/java/dev/sigstore/encryption/signers/Signers.java +++ b/sigstore-java/src/main/java/dev/sigstore/encryption/signers/Signers.java @@ -22,16 +22,24 @@ public class Signers { /** Create a new ECDSA signer with 256 bit keysize. */ - public static EcdsaSigner newEcdsaSigner() throws NoSuchAlgorithmException { - KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC"); - keyGen.initialize(256); - return new EcdsaSigner(keyGen.generateKeyPair()); + public static EcdsaSigner newEcdsaSigner() { + try { + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC"); + keyGen.initialize(256); + return new EcdsaSigner(keyGen.generateKeyPair()); + } catch (NoSuchAlgorithmException nse) { + throw new RuntimeException("No EC algorithm found in Runtime", nse); + } } /** Create a new RSA signer with 2048 bit keysize. */ - public static RsaSigner newRsaSigner() throws NoSuchAlgorithmException { - KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); - keyGen.initialize(2048); - return new RsaSigner(keyGen.generateKeyPair()); + public static RsaSigner newRsaSigner() { + try { + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA"); + keyGen.initialize(2048); + return new RsaSigner(keyGen.generateKeyPair()); + } catch (NoSuchAlgorithmException nse) { + throw new RuntimeException("No RSA algorithm found in Runtime", nse); + } } } diff --git a/sigstore-java/src/main/java/dev/sigstore/fulcio/client/FulcioClient.java b/sigstore-java/src/main/java/dev/sigstore/fulcio/client/FulcioClient.java index ad3e5239..40d8cd2e 100644 --- a/sigstore-java/src/main/java/dev/sigstore/fulcio/client/FulcioClient.java +++ b/sigstore-java/src/main/java/dev/sigstore/fulcio/client/FulcioClient.java @@ -42,6 +42,9 @@ /** A client to communicate with a fulcio service instance over gRPC. */ public class FulcioClient { + public static final URI PUBLIC_GOOD_URI = URI.create("https://fulcio.sigstore.dev"); + public static final URI STAGING_URI = URI.create("https://fulcio.sigstage.dev"); + private final HttpParams httpParams; private final URI uri; @@ -55,7 +58,7 @@ private FulcioClient(HttpParams httpParams, URI uri) { } public static class Builder { - private URI uri = URI.create("https://fulcio.sigstore.dev"); + private URI uri = PUBLIC_GOOD_URI; private HttpParams httpParams = ImmutableHttpParams.builder().build(); private Builder() {} diff --git a/sigstore-java/src/main/java/dev/sigstore/fulcio/client/FulcioVerifier.java b/sigstore-java/src/main/java/dev/sigstore/fulcio/client/FulcioVerifier.java index f41b0a24..3b8e4faf 100644 --- a/sigstore-java/src/main/java/dev/sigstore/fulcio/client/FulcioVerifier.java +++ b/sigstore-java/src/main/java/dev/sigstore/fulcio/client/FulcioVerifier.java @@ -20,9 +20,9 @@ import dev.sigstore.encryption.certificates.transparency.CTLogInfo; import dev.sigstore.encryption.certificates.transparency.CTVerificationResult; import dev.sigstore.encryption.certificates.transparency.CTVerifier; -import dev.sigstore.trustroot.CertificateAuthorities; +import dev.sigstore.trustroot.CertificateAuthority; import dev.sigstore.trustroot.SigstoreTrustedRoot; -import dev.sigstore.trustroot.TransparencyLogs; +import dev.sigstore.trustroot.TransparencyLog; import java.io.IOException; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; @@ -46,8 +46,8 @@ /** Verifier for fulcio generated signing cerificates */ public class FulcioVerifier { - private final CertificateAuthorities cas; - private final TransparencyLogs ctLogs; + private final List cas; + private final List ctLogs; private final CTVerifier ctVerifier; public static FulcioVerifier newFulcioVerifier(SigstoreTrustedRoot trustRoot) @@ -57,11 +57,11 @@ public static FulcioVerifier newFulcioVerifier(SigstoreTrustedRoot trustRoot) } public static FulcioVerifier newFulcioVerifier( - CertificateAuthorities cas, TransparencyLogs ctLogs) + List cas, List ctLogs) throws InvalidKeySpecException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, CertificateException { List logs = new ArrayList<>(); - for (var ctLog : ctLogs.all()) { + for (var ctLog : ctLogs) { logs.add( new CTLogInfo( ctLog.getPublicKey().toJavaPublicKey(), "CT Log", ctLog.getBaseUrl().toString())); @@ -75,7 +75,7 @@ public static FulcioVerifier newFulcioVerifier( .orElse(null)); // check to see if we can use all fulcio roots (this is a bit eager) - for (var ca : cas.all()) { + for (var ca : cas) { ca.asTrustAnchor(); } @@ -83,7 +83,7 @@ public static FulcioVerifier newFulcioVerifier( } private FulcioVerifier( - CertificateAuthorities cas, TransparencyLogs ctLogs, CTVerifier ctVerifier) { + List cas, List ctLogs, CTVerifier ctVerifier) { this.cas = cas; this.ctLogs = ctLogs; this.ctVerifier = ctVerifier; @@ -122,7 +122,7 @@ private void verifyEmbeddedScts(CertPath certPath) throws FulcioVerificationExce var logId = sct.getLogID(); var entryTime = Instant.ofEpochMilli(sct.getTimestamp()); - var ctLog = ctLogs.find(logId, entryTime); + var ctLog = TransparencyLog.find(ctLogs, logId, entryTime); if (ctLog.isPresent()) { // TODO: currently we only require one valid SCT, but maybe this should be configurable? // found at least one valid sct with a matching valid log @@ -178,7 +178,7 @@ CertPath validateCertPath(CertPath signingCertificate) throws FulcioVerification } var leaf = Certificates.getLeaf(signingCertificate); - var validCAs = cas.find(leaf.getNotBefore().toInstant()); + var validCAs = CertificateAuthority.find(cas, leaf.getNotBefore().toInstant()); if (validCAs.size() == 0) { throw new FulcioVerificationException( diff --git a/sigstore-java/src/main/java/dev/sigstore/oidc/client/OidcClients.java b/sigstore-java/src/main/java/dev/sigstore/oidc/client/OidcClients.java index 2834ac08..68e3affa 100644 --- a/sigstore-java/src/main/java/dev/sigstore/oidc/client/OidcClients.java +++ b/sigstore-java/src/main/java/dev/sigstore/oidc/client/OidcClients.java @@ -20,10 +20,10 @@ /** An ordered list of oidc clients to use when looking for credentials. */ public class OidcClients { - public static final OidcClients DEFAULTS = + public static final OidcClients PUBLIC_GOOD = of(GithubActionsOidcClient.builder().build(), WebOidcClient.builder().build()); - public static final OidcClients STAGING_DEFAULTS = + public static final OidcClients STAGING = of( GithubActionsOidcClient.builder().build(), WebOidcClient.builder().setIssuer(WebOidcClient.STAGING_DEX_ISSUER).build()); diff --git a/sigstore-java/src/main/java/dev/sigstore/rekor/client/RekorClient.java b/sigstore-java/src/main/java/dev/sigstore/rekor/client/RekorClient.java index 44dee202..cad493fe 100644 --- a/sigstore-java/src/main/java/dev/sigstore/rekor/client/RekorClient.java +++ b/sigstore-java/src/main/java/dev/sigstore/rekor/client/RekorClient.java @@ -35,6 +35,9 @@ /** A client to communicate with a rekor service instance. */ public class RekorClient { + public static final URI PUBLIC_GOOD_URI = URI.create("https://rekor.sigstore.dev"); + public static final URI STAGING_URI = URI.create("https://rekor.sigstage.dev"); + public static final String REKOR_ENTRIES_PATH = "/api/v1/log/entries"; public static final String REKOR_INDEX_SEARCH_PATH = "/api/v1/index/retrieve"; @@ -52,7 +55,7 @@ private RekorClient(HttpParams httpParams, URI uri) { public static class Builder { private HttpParams httpParams = ImmutableHttpParams.builder().build(); - private URI uri = URI.create("https://rekor.sigstore.dev"); + private URI uri = PUBLIC_GOOD_URI; private Builder() {} diff --git a/sigstore-java/src/main/java/dev/sigstore/rekor/client/RekorVerifier.java b/sigstore-java/src/main/java/dev/sigstore/rekor/client/RekorVerifier.java index cd000980..7017467e 100644 --- a/sigstore-java/src/main/java/dev/sigstore/rekor/client/RekorVerifier.java +++ b/sigstore-java/src/main/java/dev/sigstore/rekor/client/RekorVerifier.java @@ -20,28 +20,28 @@ import dev.sigstore.rekor.client.RekorEntry.Checkpoint; import dev.sigstore.trustroot.SigstoreTrustedRoot; import dev.sigstore.trustroot.TransparencyLog; -import dev.sigstore.trustroot.TransparencyLogs; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SignatureException; import java.security.spec.InvalidKeySpecException; import java.util.Arrays; import java.util.Base64; +import java.util.List; import org.bouncycastle.util.encoders.Hex; /** Verifier for rekor entries. */ public class RekorVerifier { - private final TransparencyLogs tlogs; + private final List tlogs; public static RekorVerifier newRekorVerifier(SigstoreTrustedRoot trustRoot) { return newRekorVerifier(trustRoot.getTLogs()); } - public static RekorVerifier newRekorVerifier(TransparencyLogs tlogs) { + public static RekorVerifier newRekorVerifier(List tlogs) { return new RekorVerifier(tlogs); } - private RekorVerifier(TransparencyLogs tlogs) { + private RekorVerifier(List tlogs) { this.tlogs = tlogs; } @@ -61,8 +61,7 @@ public void verifyEntry(RekorEntry entry) throws RekorVerificationException { } var tlog = - tlogs - .find(Hex.decode(entry.getLogID()), entry.getIntegratedTimeInstant()) + TransparencyLog.find(tlogs, Hex.decode(entry.getLogID()), entry.getIntegratedTimeInstant()) .orElseThrow( () -> new RekorVerificationException( diff --git a/sigstore-java/src/main/java/dev/sigstore/trustroot/CertificateAuthorities.java b/sigstore-java/src/main/java/dev/sigstore/trustroot/CertificateAuthorities.java deleted file mode 100644 index 9fe1eecd..00000000 --- a/sigstore-java/src/main/java/dev/sigstore/trustroot/CertificateAuthorities.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2023 The Sigstore Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package dev.sigstore.trustroot; - -import java.time.Instant; -import java.util.Iterator; -import java.util.List; -import java.util.stream.Collectors; -import org.immutables.value.Value; -import org.immutables.value.Value.Derived; -import org.immutables.value.Value.Immutable; - -@Immutable -@Value.Style( - depluralize = true, - depluralizeDictionary = {"certificateAuthority:certificateAuthorities"}) -public abstract class CertificateAuthorities implements Iterable { - - public abstract List getCertificateAuthorities(); - - @Derived - public int size() { - return getCertificateAuthorities().size(); - } - - @Derived - public List all() { - return getCertificateAuthorities(); - } - - /** - * Find a CA by validity time, users of this method will need to then compare the key in the leaf - * to find the exact CA to validate against - * - * @param time the time the CA was expected to be valid (usually tlog entry time) - * @return a list of CAs that were valid at {@code time} - */ - public List find(Instant time) { - return getCertificateAuthorities().stream() - .filter(ca -> ca.getValidFor().contains(time)) - .collect(Collectors.toList()); - } - - /** - * Get the one an only current Certificate Authority - * - * @return the current active CA - * @throws IllegalStateException if trust root does not contain exactly one active CA - */ - public CertificateAuthority current() { - var current = - getCertificateAuthorities().stream() - .filter(CertificateAuthority::isCurrent) - .collect(Collectors.toList()); - if (current.size() == 0) { - throw new IllegalStateException("Trust root contains no current certificate authorities"); - } - if (current.size() > 1) { - throw new IllegalStateException( - "Trust root contains multiple current certificate authorities (" + current.size() + ")"); - } - return current.get(0); - } - - @Override - public Iterator iterator() { - return getCertificateAuthorities().iterator(); - } -} diff --git a/sigstore-java/src/main/java/dev/sigstore/trustroot/CertificateAuthority.java b/sigstore-java/src/main/java/dev/sigstore/trustroot/CertificateAuthority.java index cd2f6e02..0a7911ba 100644 --- a/sigstore-java/src/main/java/dev/sigstore/trustroot/CertificateAuthority.java +++ b/sigstore-java/src/main/java/dev/sigstore/trustroot/CertificateAuthority.java @@ -25,6 +25,8 @@ import java.security.cert.X509Certificate; import java.time.Instant; import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; import org.immutables.value.Value.Immutable; import org.immutables.value.Value.Lazy; @@ -64,4 +66,15 @@ public static CertificateAuthority from( .subject(Subject.from(proto.getSubject())) .build(); } + + /** + * Find a CA by validity time, users of this method will need to then compare the key in the leaf + * to find the exact CA to validate against + * + * @param time the time the CA was expected to be valid (usually tlog entry time) + * @return a list of CAs that were valid at {@code time} + */ + public static List find(List all, Instant time) { + return all.stream().filter(ca -> ca.getValidFor().contains(time)).collect(Collectors.toList()); + } } diff --git a/sigstore-java/src/main/java/dev/sigstore/trustroot/SigstoreTrustedRoot.java b/sigstore-java/src/main/java/dev/sigstore/trustroot/SigstoreTrustedRoot.java index 4071c647..1bab929a 100644 --- a/sigstore-java/src/main/java/dev/sigstore/trustroot/SigstoreTrustedRoot.java +++ b/sigstore-java/src/main/java/dev/sigstore/trustroot/SigstoreTrustedRoot.java @@ -15,44 +15,38 @@ */ package dev.sigstore.trustroot; +import com.google.api.client.util.Lists; import dev.sigstore.proto.trustroot.v1.TrustedRoot; import java.security.cert.CertificateException; +import java.util.List; +import java.util.stream.Collectors; import org.immutables.value.Value.Immutable; @Immutable public interface SigstoreTrustedRoot { /** A list of certificate authorities associated with this trustroot. */ - CertificateAuthorities getCAs(); + List getCAs(); /** A list of binary transparency logs associated with this trustroot. */ - TransparencyLogs getTLogs(); + List getTLogs(); /** A list of certificate transparency logs associated with this trustroot. */ - TransparencyLogs getCTLogs(); + List getCTLogs(); /** Create an instance from a parsed proto definition of a trustroot. */ static SigstoreTrustedRoot from(TrustedRoot proto) throws CertificateException { - var certificateAuthoritiesBuilder = ImmutableCertificateAuthorities.builder(); + List cas = Lists.newArrayList(); for (var certAuthority : proto.getCertificateAuthoritiesList()) { - certificateAuthoritiesBuilder.addCertificateAuthority( - CertificateAuthority.from(certAuthority)); + cas.add(CertificateAuthority.from(certAuthority)); } - var tlogsBuilder = ImmutableTransparencyLogs.builder(); - proto.getTlogsList().stream() - .map(TransparencyLog::from) - .forEach(tlogsBuilder::addTransparencyLog); - - var ctlogsBuilder = ImmutableTransparencyLogs.builder(); - proto.getCtlogsList().stream() - .map(TransparencyLog::from) - .forEach(ctlogsBuilder::addTransparencyLog); - - return ImmutableSigstoreTrustedRoot.builder() - .cAs(certificateAuthoritiesBuilder.build()) - .tLogs(tlogsBuilder.build()) - .cTLogs(ctlogsBuilder.build()) - .build(); + List tlogs = + proto.getTlogsList().stream().map(TransparencyLog::from).collect(Collectors.toList()); + + List ctlogs = + proto.getCtlogsList().stream().map(TransparencyLog::from).collect(Collectors.toList()); + + return ImmutableSigstoreTrustedRoot.builder().cAs(cas).tLogs(tlogs).cTLogs(ctlogs).build(); } } diff --git a/sigstore-java/src/main/java/dev/sigstore/trustroot/TransparencyLog.java b/sigstore-java/src/main/java/dev/sigstore/trustroot/TransparencyLog.java index ce52260b..f4cad805 100644 --- a/sigstore-java/src/main/java/dev/sigstore/trustroot/TransparencyLog.java +++ b/sigstore-java/src/main/java/dev/sigstore/trustroot/TransparencyLog.java @@ -19,6 +19,10 @@ import dev.sigstore.proto.trustroot.v1.TransparencyLogInstance; import java.net.URI; +import java.time.Instant; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; @Immutable public interface TransparencyLog { @@ -38,4 +42,19 @@ static TransparencyLog from(TransparencyLogInstance proto) { .publicKey(PublicKey.from(proto.getPublicKey())) .build(); } + + /** + * Find a log by validity time and logId. This will find the first log with matching log id that + * was valid at the time. + * + * @param logId the logId of the log + * @param time the time the log was expected to be valid + * @return the first log that was valid at {@code time} with logId {@code logId} + */ + static Optional find(List all, byte[] logId, Instant time) { + return all.stream() + .filter(tl -> Arrays.equals(tl.getLogId().getKeyId(), logId)) + .filter(tl -> tl.getPublicKey().getValidFor().contains(time)) + .findAny(); + } } diff --git a/sigstore-java/src/main/java/dev/sigstore/trustroot/TransparencyLogs.java b/sigstore-java/src/main/java/dev/sigstore/trustroot/TransparencyLogs.java deleted file mode 100644 index e0951fa8..00000000 --- a/sigstore-java/src/main/java/dev/sigstore/trustroot/TransparencyLogs.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2023 The Sigstore Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package dev.sigstore.trustroot; - -import java.time.Instant; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; -import org.immutables.value.Value; -import org.immutables.value.Value.Derived; -import org.immutables.value.Value.Immutable; - -@Immutable -@Value.Style(depluralize = true) -public abstract class TransparencyLogs implements Iterable { - - public abstract List getTransparencyLogs(); - - @Derived - public int size() { - return getTransparencyLogs().size(); - } - - @Derived - public List all() { - return getTransparencyLogs(); - } - - public TransparencyLog current() { - var current = - getTransparencyLogs().stream() - .filter(tl -> tl.getPublicKey().getValidFor().getEnd().isEmpty()) - .collect(Collectors.toList()); - if (current.size() == 0) { - throw new IllegalStateException("Trust root contains no current transparency logs"); - } - if (current.size() > 1) { - throw new IllegalStateException( - "Trust root contains multiple current transparency logs (" + current.size() + ")"); - } - return current.get(0); - } - - public Optional find(byte[] logId, Instant time) { - return getTransparencyLogs().stream() - .filter(tl -> Arrays.equals(tl.getLogId().getKeyId(), logId)) - .filter(tl -> tl.getPublicKey().getValidFor().contains(time)) - .findAny(); - } - - @Override - public Iterator iterator() { - return getTransparencyLogs().iterator(); - } -} diff --git a/sigstore-java/src/test/java/dev/sigstore/fulcio/client/FulcioVerifierTest.java b/sigstore-java/src/test/java/dev/sigstore/fulcio/client/FulcioVerifierTest.java index 8051b436..2b30d928 100644 --- a/sigstore-java/src/test/java/dev/sigstore/fulcio/client/FulcioVerifierTest.java +++ b/sigstore-java/src/test/java/dev/sigstore/fulcio/client/FulcioVerifierTest.java @@ -22,12 +22,12 @@ import dev.sigstore.proto.trustroot.v1.TrustedRoot; import dev.sigstore.trustroot.ImmutableLogId; import dev.sigstore.trustroot.ImmutableTransparencyLog; -import dev.sigstore.trustroot.ImmutableTransparencyLogs; import dev.sigstore.trustroot.SigstoreTrustedRoot; import java.io.IOException; import java.io.StringReader; import java.nio.charset.StandardCharsets; import java.util.Collections; +import java.util.List; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -73,12 +73,7 @@ public static void initTrustRoot() throws Exception { public void testVerifySct_nullCtLogKey() throws Exception { var signingCertificate = Certificates.fromPemChain(certsWithEmbeddedSct); var fulcioVerifier = - FulcioVerifier.newFulcioVerifier( - trustRoot.getCAs(), - ImmutableTransparencyLogs.builder() - .addAllTransparencyLogs(Collections.emptyList()) - .build()); - + FulcioVerifier.newFulcioVerifier(trustRoot.getCAs(), Collections.emptyList()); try { fulcioVerifier.verifySigningCertificate(signingCertificate); Assertions.fail(); @@ -123,16 +118,14 @@ public void invalidEmbeddedSct() throws Exception { var fulcioVerifier = FulcioVerifier.newFulcioVerifier( trustRoot.getCAs(), - ImmutableTransparencyLogs.builder() - .addTransparencyLog( - ImmutableTransparencyLog.builder() - .from(trustRoot.getCTLogs().all().get(0)) - .logId( - ImmutableLogId.builder() - .keyId("abcd".getBytes(StandardCharsets.UTF_8)) - .build()) - .build()) - .build()); + List.of( + ImmutableTransparencyLog.builder() + .from(trustRoot.getCTLogs().get(0)) + .logId( + ImmutableLogId.builder() + .keyId("abcd".getBytes(StandardCharsets.UTF_8)) + .build()) + .build())); var fve = Assertions.assertThrows( diff --git a/sigstore-java/src/test/java/dev/sigstore/rekor/client/RekorVerifierTest.java b/sigstore-java/src/test/java/dev/sigstore/rekor/client/RekorVerifierTest.java index 01f97e2f..ec1e4aea 100644 --- a/sigstore-java/src/test/java/dev/sigstore/rekor/client/RekorVerifierTest.java +++ b/sigstore-java/src/test/java/dev/sigstore/rekor/client/RekorVerifierTest.java @@ -21,7 +21,6 @@ import dev.sigstore.trustroot.ImmutableLogId; import dev.sigstore.trustroot.ImmutablePublicKey; import dev.sigstore.trustroot.ImmutableTransparencyLog; -import dev.sigstore.trustroot.ImmutableTransparencyLogs; import dev.sigstore.trustroot.ImmutableValidFor; import dev.sigstore.trustroot.SigstoreTrustedRoot; import java.io.IOException; @@ -30,6 +29,7 @@ import java.security.cert.CertificateException; import java.time.Instant; import java.time.temporal.ChronoUnit; +import java.util.List; import org.bouncycastle.util.encoders.Base64; import org.bouncycastle.util.encoders.Hex; import org.hamcrest.CoreMatchers; @@ -128,9 +128,7 @@ public void verifyEntry_logIdMismatch() throws Exception { .baseUrl(URI.create("ignored")) .build(); - var verifier = - RekorVerifier.newRekorVerifier( - ImmutableTransparencyLogs.builder().addTransparencyLog(tlog).build()); + var verifier = RekorVerifier.newRekorVerifier(List.of(tlog)); // make sure the entry time is valid for the log -- so we can determine the logid is the error // creator @@ -174,9 +172,7 @@ public void verifyEntry_logIdTimeMismatch() throws Exception { .baseUrl(URI.create("ignored")) .build(); - var verifier = - RekorVerifier.newRekorVerifier( - ImmutableTransparencyLogs.builder().addTransparencyLog(tlog).build()); + var verifier = RekorVerifier.newRekorVerifier(List.of(tlog)); // make sure logId is equal -- so we can determine the time is the error creator Assertions.assertArrayEquals( diff --git a/sigstore-java/src/test/java/dev/sigstore/trustroot/CertificateAuthoritiesTest.java b/sigstore-java/src/test/java/dev/sigstore/trustroot/CertificateAuthoritiesTest.java deleted file mode 100644 index e0a1c4c7..00000000 --- a/sigstore-java/src/test/java/dev/sigstore/trustroot/CertificateAuthoritiesTest.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2023 The Sigstore Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package dev.sigstore.trustroot; - -import java.net.URI; -import java.security.cert.CertPath; -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - -class CertificateAuthoritiesTest { - @Test - public void current_missing() { - Assertions.assertThrows( - IllegalStateException.class, - () -> ImmutableCertificateAuthorities.builder().build().current()); - } - - @Test - public void current_tooMany() { - var ca = - ImmutableCertificateAuthority.builder() - .certPath(Mockito.mock(CertPath.class)) - .uri(URI.create("abc")) - .subject(ImmutableSubject.builder().commonName("abc").organization("xyz").build()) - .validFor( - ImmutableValidFor.builder() - .start(Instant.now().minus(10, ChronoUnit.SECONDS)) - .build()) - .build(); - Assertions.assertThrows( - IllegalStateException.class, - () -> - ImmutableCertificateAuthorities.builder() - .addCertificateAuthorities(ca, ca) - .build() - .current()); - } -} diff --git a/sigstore-java/src/test/java/dev/sigstore/trustroot/SigstoreTrustedRootTest.java b/sigstore-java/src/test/java/dev/sigstore/trustroot/SigstoreTrustedRootTest.java index b8ce3049..2c727825 100644 --- a/sigstore-java/src/test/java/dev/sigstore/trustroot/SigstoreTrustedRootTest.java +++ b/sigstore-java/src/test/java/dev/sigstore/trustroot/SigstoreTrustedRootTest.java @@ -16,23 +16,18 @@ package dev.sigstore.trustroot; import static org.junit.jupiter.api.AssertionFailureBuilder.assertionFailure; -import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import com.google.common.io.Resources; import com.google.protobuf.util.JsonFormat; -import dev.sigstore.encryption.certificates.Certificates; import dev.sigstore.proto.trustroot.v1.TrustedRoot; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.security.cert.CertificateException; -import java.time.Instant; import java.time.ZonedDateTime; -import java.util.ArrayList; import java.util.List; -import java.util.Optional; import org.bouncycastle.util.encoders.Base64; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -59,7 +54,7 @@ void from_checkFields() throws Exception { assertEquals(1, trustRoot.getTLogs().size()); assertEquals(2, trustRoot.getCTLogs().size()); - var oldCA = trustRoot.getCAs().all().get(0); + var oldCA = trustRoot.getCAs().get(0); assertEquals("sigstore", oldCA.getSubject().getCommonName()); assertEquals("sigstore.dev", oldCA.getSubject().getOrganization()); assertEquals( @@ -73,7 +68,7 @@ void from_checkFields() throws Exception { Base64.toBase64String(oldCA.getCertPath().getCertificates().get(0).getEncoded())); assertNotNull(oldCA.getCertPath()); - var currCA = trustRoot.getCAs().all().get(1); + var currCA = trustRoot.getCAs().get(1); assertEquals("sigstore", currCA.getSubject().getCommonName()); assertEquals("sigstore.dev", currCA.getSubject().getOrganization()); assertEquals( @@ -88,7 +83,7 @@ void from_checkFields() throws Exception { Base64.toBase64String(currCA.getCertPath().getCertificates().get(1).getEncoded())); assertNotNull(currCA.getCertPath()); - var tlog = trustRoot.getTLogs().getTransparencyLogs().get(0); + var tlog = trustRoot.getTLogs().get(0); assertEquals("https://rekor.sigstore.dev", tlog.getBaseUrl().toString()); assertEquals("SHA2_256", tlog.getHashAlgorithm()); assertEquals( @@ -102,7 +97,7 @@ void from_checkFields() throws Exception { "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2G2Y+2tabdTV5BcGiBIx0a9fAFwrkBbmLSGtks4L3qX6yYY0zufBnhC8Ur/iy55GhWP/9A/bY2LhC30M9+RYtw==", Base64.toBase64String(tlog.getPublicKey().toJavaPublicKey().getEncoded())); - var oldCTLog = trustRoot.getCTLogs().all().get(0); + var oldCTLog = trustRoot.getCTLogs().get(0); assertEquals("https://ctfe.sigstore.dev/test", oldCTLog.getBaseUrl().toString()); assertEquals("SHA2_256", oldCTLog.getHashAlgorithm()); assertEquals( @@ -118,7 +113,7 @@ void from_checkFields() throws Exception { "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEbfwR+RJudXscgRBRpKX1XFDy3PyudDxz/SfnRi1fT8ekpfBd2O1uoz7jr3Z8nKzxA69EUQ+eFCFI3zeubPWU7w==", Base64.toBase64String(oldCTLog.getPublicKey().toJavaPublicKey().getEncoded())); - var currCTLog = trustRoot.getCTLogs().all().get(1); + var currCTLog = trustRoot.getCTLogs().get(1); assertEquals("https://ctfe.sigstore.dev/2022", currCTLog.getBaseUrl().toString()); assertEquals("SHA2_256", currCTLog.getHashAlgorithm()); assertEquals( @@ -139,54 +134,40 @@ public void getTlog_isPresent() { // exactly at start time assertTLogEntryIsPresent( - trustRoot.getTLogs()::find, key, ZonedDateTime.parse("2021-01-12T11:53:27.000Z")); + trustRoot.getTLogs(), key, ZonedDateTime.parse("2021-01-12T11:53:27.000Z")); // other random time assertTLogEntryIsPresent( - trustRoot.getTLogs()::find, key, ZonedDateTime.parse("2021-12-12T11:53:27.000Z")); + trustRoot.getTLogs(), key, ZonedDateTime.parse("2021-12-12T11:53:27.000Z")); } @Test public void getTlog_isNotPresent() { // before the start time, but valid key assertTLogEntryIsEmpty( - trustRoot.getTLogs()::find, + trustRoot.getTLogs(), Base64.decode("wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="), ZonedDateTime.parse("2021-01-01T11:53:27.000Z")); // valid time but bad key assertTLogEntryIsEmpty( - trustRoot.getTLogs()::find, + trustRoot.getTLogs(), Base64.decode("wNI8atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="), ZonedDateTime.parse("2021-12-12T11:53:27.000Z")); } - @Test - public void getCurrentTLog() { - var tlog = trustRoot.getTLogs().current(); - assertArrayEquals( - Base64.decode("wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="), tlog.getLogId().getKeyId()); - } - - @Test - public void getCurrentCTLog() { - var ctlog = trustRoot.getCTLogs().current(); - assertArrayEquals( - Base64.decode("3T0wasbHETJjGR4cmWc3AqJKXrjePK3/h4pygC8p7o4="), ctlog.getLogId().getKeyId()); - } - @Test public void getCTLog_isPresent() { var key = Base64.decode("CGCS8ChS/2hF0dFrJ4ScRWcYrBY9wzjSbea8IgY2b3I="); // exactly at start assertTLogEntryIsPresent( - trustRoot.getCTLogs()::find, key, ZonedDateTime.parse("2021-03-14T00:00:00.000Z")); + trustRoot.getCTLogs(), key, ZonedDateTime.parse("2021-03-14T00:00:00.000Z")); // in the middle assertTLogEntryIsPresent( - trustRoot.getCTLogs()::find, key, ZonedDateTime.parse("2021-10-14T00:00:00.000Z")); + trustRoot.getCTLogs(), key, ZonedDateTime.parse("2021-10-14T00:00:00.000Z")); // exactly at end time assertTLogEntryIsPresent( - trustRoot.getCTLogs()::find, key, ZonedDateTime.parse("2022-10-31T23:59:59.999Z")); + trustRoot.getCTLogs(), key, ZonedDateTime.parse("2022-10-31T23:59:59.999Z")); } @Test @@ -195,15 +176,15 @@ public void getCTLog_isNotPresent() { // before the start time, but valid key assertTLogEntryIsEmpty( - trustRoot.getCTLogs()::find, key, ZonedDateTime.parse("2019-01-01T11:53:27.000Z")); + trustRoot.getCTLogs(), key, ZonedDateTime.parse("2019-01-01T11:53:27.000Z")); // after end time, but valid key assertTLogEntryIsEmpty( - trustRoot.getCTLogs()::find, key, ZonedDateTime.parse("2022-11-01T11:53:27.000Z")); + trustRoot.getCTLogs(), key, ZonedDateTime.parse("2022-11-01T11:53:27.000Z")); // garbage key assertTLogEntryIsEmpty( - trustRoot.getCTLogs()::find, + trustRoot.getCTLogs(), Base64.decode("wNI8atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="), ZonedDateTime.parse("2021-10-14T00:00:00.000Z")); } @@ -213,23 +194,20 @@ public void getCAs_isPresent() { // exactly at start assertEquals( 1, - trustRoot - .getCAs() - .find(ZonedDateTime.parse("2021-03-07T03:20:29.000Z").toInstant()) + CertificateAuthority.find( + trustRoot.getCAs(), ZonedDateTime.parse("2021-03-07T03:20:29.000Z").toInstant()) .size()); // somewhere in the middle assertEquals( 1, - trustRoot - .getCAs() - .find(ZonedDateTime.parse("2021-04-28T03:59:59.999Z").toInstant()) + CertificateAuthority.find( + trustRoot.getCAs(), ZonedDateTime.parse("2021-04-28T03:59:59.999Z").toInstant()) .size()); // exactly at end but also overlapping with another CA assertEquals( 2, - trustRoot - .getCAs() - .find(ZonedDateTime.parse("2022-12-31T23:59:59.999Z").toInstant()) + CertificateAuthority.find( + trustRoot.getCAs(), ZonedDateTime.parse("2022-12-31T23:59:59.999Z").toInstant()) .size()); } @@ -237,35 +215,14 @@ public void getCAs_isPresent() { public void getCAs_isNotPresent() { assertEquals( 0, - trustRoot - .getCAs() - .find(ZonedDateTime.parse("2015-03-14T00:00:00.000Z").toInstant()) + CertificateAuthority.find( + trustRoot.getCAs(), ZonedDateTime.parse("2015-03-14T00:00:00.000Z").toInstant()) .size()); } - @Test - public void getCurrentCA() throws CertificateException { - var ca = trustRoot.getCAs().current(); - List certs = new ArrayList<>(2); - certs.add( - 0, - Base64.decode( - "MIICGjCCAaGgAwIBAgIUALnViVfnU0brJasmRkHrn/UnfaQwCgYIKoZIzj0EAwMwKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0yMjA0MTMyMDA2MTVaFw0zMTEwMDUxMzU2NThaMDcxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEeMBwGA1UEAxMVc2lnc3RvcmUtaW50ZXJtZWRpYXRlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE8RVS/ysH+NOvuDZyPIZtilgUF9NlarYpAd9HP1vBBH1U5CV77LSS7s0ZiH4nE7Hv7ptS6LvvR/STk798LVgMzLlJ4HeIfF3tHSaexLcYpSASr1kS0N/RgBJz/9jWCiXno3sweTAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU39Ppz1YkEZb5qNjpKFWixi4YZD8wHwYDVR0jBBgwFoAUWMAeX5FFpWapesyQoZMi0CrFxfowCgYIKoZIzj0EAwMDZwAwZAIwPCsQK4DYiZYDPIaDi5HFKnfxXx6ASSVmERfsynYBiX2X6SJRnZU84/9DZdnFvvxmAjBOt6QpBlc4J/0DxvkTCqpclvziL6BCCPnjdlIB3Pu3BxsPmygUY7Ii2zbdCdliiow=")); - certs.add( - 1, - Base64.decode( - "MIIB9zCCAXygAwIBAgIUALZNAPFdxHPwjeDloDwyYChAO/4wCgYIKoZIzj0EAwMwKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0yMTEwMDcxMzU2NTlaFw0zMTEwMDUxMzU2NThaMCoxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjERMA8GA1UEAxMIc2lnc3RvcmUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT7XeFT4rb3PQGwS4IajtLk3/OlnpgangaBclYpsYBr5i+4ynB07ceb3LP0OIOZdxexX69c5iVuyJRQ+Hz05yi+UF3uBWAlHpiS5sh0+H2GHE7SXrk1EC5m1Tr19L9gg92jYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRYwB5fkUWlZql6zJChkyLQKsXF+jAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQKsXF+jAKBggqhkjOPQQDAwNpADBmAjEAj1nHeXZp+13NWBNa+EDsDP8G1WWg1tCMWP/WHPqpaVo0jhsweNFZgSs0eE7wYI4qAjEA2WB9ot98sIkoF3vZYdd3/VtWB5b9TNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ")); - var certPath = Certificates.fromDer(certs); - assertEquals(certPath, ca.getCertPath()); - } - - @FunctionalInterface - private interface TLogQuery { - Optional find(byte[] key, Instant time); - } - - private void assertTLogEntryIsPresent(TLogQuery query, byte[] key, ZonedDateTime time) { - if (query.find(key, time.toInstant()).isEmpty()) { + private void assertTLogEntryIsPresent( + List logs, byte[] key, ZonedDateTime time) { + if (TransparencyLog.find(logs, key, time.toInstant()).isEmpty()) { assertionFailure() .reason( "expected: tlog is found: key_id(" @@ -277,8 +234,8 @@ private void assertTLogEntryIsPresent(TLogQuery query, byte[] key, ZonedDateTime } } - private void assertTLogEntryIsEmpty(TLogQuery query, byte[] key, ZonedDateTime time) { - if (query.find(key, time.toInstant()).isPresent()) { + private void assertTLogEntryIsEmpty(List logs, byte[] key, ZonedDateTime time) { + if (TransparencyLog.find(logs, key, time.toInstant()).isPresent()) { assertionFailure() .reason( "expected: tlog is not found: key_id(" diff --git a/sigstore-java/src/test/java/dev/sigstore/trustroot/TransparencyLogsTest.java b/sigstore-java/src/test/java/dev/sigstore/trustroot/TransparencyLogsTest.java deleted file mode 100644 index 44a23f63..00000000 --- a/sigstore-java/src/test/java/dev/sigstore/trustroot/TransparencyLogsTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2023 The Sigstore Authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package dev.sigstore.trustroot; - -import static org.junit.jupiter.api.Assertions.*; - -import java.net.URI; -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - -class TransparencyLogsTest { - - @Test - public void current_missing() { - Assertions.assertThrows( - IllegalStateException.class, () -> ImmutableTransparencyLogs.builder().build().current()); - } - - @Test - public void current_tooMany() { - var pk = Mockito.mock(PublicKey.class); - Mockito.when(pk.getValidFor()) - .thenReturn( - ImmutableValidFor.builder().start(Instant.now().minus(10, ChronoUnit.SECONDS)).build()); - var tlog = - ImmutableTransparencyLog.builder() - .logId(Mockito.mock(LogId.class)) - .baseUrl(URI.create("abc")) - .hashAlgorithm("sha256") - .publicKey(pk) - .build(); - Assertions.assertThrows( - IllegalStateException.class, - () -> - ImmutableTransparencyLogs.builder().addTransparencyLogs(tlog, tlog).build().current()); - } -} diff --git a/sigstore-java/src/test/java/dev/sigstore/trustroot/ValidForTest.java b/sigstore-java/src/test/java/dev/sigstore/trustroot/ValidForTest.java index b454930f..994f8d35 100644 --- a/sigstore-java/src/test/java/dev/sigstore/trustroot/ValidForTest.java +++ b/sigstore-java/src/test/java/dev/sigstore/trustroot/ValidForTest.java @@ -39,6 +39,7 @@ public void contains_withStartAndEnd() { Assertions.assertFalse(range.contains(end.plus(10, ChronoUnit.SECONDS))); } + @Test public void contains_withNoEnd() { var start = Instant.now().minus(10, ChronoUnit.MINUTES); var range = ImmutableValidFor.builder().start(start).build(); diff --git a/sigstore-java/src/test/java/dev/sigstore/tuf/SigstoreTufClientTest.java b/sigstore-java/src/test/java/dev/sigstore/tuf/SigstoreTufClientTest.java index 42e2ca17..776cd888 100644 --- a/sigstore-java/src/test/java/dev/sigstore/tuf/SigstoreTufClientTest.java +++ b/sigstore-java/src/test/java/dev/sigstore/tuf/SigstoreTufClientTest.java @@ -54,9 +54,6 @@ public void testUpdate_stagingHasTrustedRootJson() throws Exception { private void assertTrustedRootValid(SigstoreTrustedRoot trustedRoot) { Assertions.assertNotNull(trustedRoot); - Assertions.assertDoesNotThrow(() -> trustedRoot.getTLogs().current()); - Assertions.assertDoesNotThrow(() -> trustedRoot.getCTLogs().current()); - Assertions.assertDoesNotThrow(() -> trustedRoot.getCAs().current()); for (var tlog : trustedRoot.getTLogs()) { Assertions.assertDoesNotThrow(() -> tlog.getPublicKey().toJavaPublicKey());