Skip to content

Commit d9ec7fe

Browse files
authored
Merge pull request #477 from sigstore/updates-to-trustroot
Updates before applying tuf to fulcio client
2 parents a4f0cd6 + de3c12e commit d9ec7fe

File tree

9 files changed

+100
-19
lines changed

9 files changed

+100
-19
lines changed

sigstore-java/src/main/java/dev/sigstore/encryption/certificates/Certificates.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package dev.sigstore.encryption.certificates;
1717

1818
import com.google.api.client.util.PemReader;
19+
import com.google.common.collect.ImmutableList;
1920
import java.io.ByteArrayInputStream;
2021
import java.io.IOException;
2122
import java.io.StringReader;
@@ -135,4 +136,16 @@ public static CertPath toCertPath(Certificate certificate) throws CertificateExc
135136
CertificateFactory cf = CertificateFactory.getInstance("X.509");
136137
return cf.generateCertPath(Collections.singletonList(certificate));
137138
}
139+
140+
/** Appends an X509Certificate to a {@link CertPath} as a leaf. */
141+
public static CertPath appendCertPath(CertPath root, Certificate certificate)
142+
throws CertificateException {
143+
CertificateFactory cf = CertificateFactory.getInstance("X.509");
144+
List<Certificate> certs =
145+
ImmutableList.<Certificate>builder()
146+
.add(certificate)
147+
.addAll(root.getCertificates())
148+
.build();
149+
return cf.generateCertPath(certs);
150+
}
138151
}

sigstore-java/src/main/java/dev/sigstore/http/GrpcChannels.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,23 @@ public static ManagedChannel newManagedChannel(URI serverUrl, HttpParams httpPar
3939
}
4040
return channelBuilder.build();
4141
}
42+
43+
/**
44+
* Create a new managed channel, this may be reused across multiple requests to a host, and must
45+
* be closed when finished.
46+
*
47+
* @param serverUrl the host to connect to
48+
* @param httpParams the http configuration
49+
* @return a reusable grpc channel
50+
*/
51+
public static ManagedChannel newManagedChannel(String serverUrl, HttpParams httpParams) {
52+
var channelBuilder =
53+
ManagedChannelBuilder.forTarget(serverUrl)
54+
.userAgent(httpParams.getUserAgent())
55+
.keepAliveTimeout(httpParams.getTimeout(), TimeUnit.SECONDS);
56+
if (httpParams.getAllowInsecureConnections()) {
57+
channelBuilder.usePlaintext();
58+
}
59+
return channelBuilder.build();
60+
}
4261
}

sigstore-java/src/main/java/dev/sigstore/trustroot/CertificateAuthorities.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
package dev.sigstore.trustroot;
1717

1818
import java.time.Instant;
19+
import java.util.Iterator;
1920
import java.util.List;
2021
import java.util.stream.Collectors;
2122
import org.immutables.value.Value;
@@ -26,7 +27,7 @@
2627
@Value.Style(
2728
depluralize = true,
2829
depluralizeDictionary = {"certificateAuthority:certificateAuthorities"})
29-
public abstract class CertificateAuthorities {
30+
public abstract class CertificateAuthorities implements Iterable<CertificateAuthority> {
3031

3132
public abstract List<CertificateAuthority> getCertificateAuthorities();
3233

@@ -74,4 +75,9 @@ public CertificateAuthority current() {
7475
}
7576
return current.get(0);
7677
}
78+
79+
@Override
80+
public Iterator<CertificateAuthority> iterator() {
81+
return getCertificateAuthorities().iterator();
82+
}
7783
}

sigstore-java/src/main/java/dev/sigstore/trustroot/CertificateAuthority.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,16 @@
1717

1818
import dev.sigstore.proto.ProtoMutators;
1919
import java.net.URI;
20+
import java.security.InvalidAlgorithmParameterException;
2021
import java.security.cert.CertPath;
2122
import java.security.cert.CertificateException;
23+
import java.security.cert.PKIXParameters;
24+
import java.security.cert.TrustAnchor;
25+
import java.security.cert.X509Certificate;
2226
import java.time.Instant;
27+
import java.util.Collections;
2328
import org.immutables.value.Value.Immutable;
29+
import org.immutables.value.Value.Lazy;
2430

2531
@Immutable
2632
public abstract class CertificateAuthority {
@@ -36,6 +42,19 @@ public boolean isCurrent() {
3642
return getValidFor().contains(Instant.now());
3743
}
3844

45+
@Lazy
46+
public TrustAnchor asTrustAnchor()
47+
throws CertificateException, InvalidAlgorithmParameterException {
48+
var certs = getCertPath().getCertificates();
49+
X509Certificate fulcioRootObj = (X509Certificate) certs.get(certs.size() - 1);
50+
TrustAnchor fulcioRootTrustAnchor = new TrustAnchor(fulcioRootObj, null);
51+
52+
// validate the certificate can be a trust anchor
53+
new PKIXParameters(Collections.singleton(fulcioRootTrustAnchor));
54+
55+
return fulcioRootTrustAnchor;
56+
}
57+
3958
public static CertificateAuthority from(
4059
dev.sigstore.proto.trustroot.v1.CertificateAuthority proto) throws CertificateException {
4160
return ImmutableCertificateAuthority.builder()

sigstore-java/src/main/java/dev/sigstore/trustroot/PublicKey.java

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,28 +19,30 @@
1919
import java.security.NoSuchAlgorithmException;
2020
import java.security.spec.InvalidKeySpecException;
2121
import org.immutables.value.Value.Immutable;
22+
import org.immutables.value.Value.Lazy;
2223

2324
@Immutable
24-
public interface PublicKey {
25-
byte[] getRawBytes();
25+
public abstract class PublicKey {
26+
public abstract byte[] getRawBytes();
2627

27-
String getKeyDetails();
28+
public abstract String getKeyDetails();
2829

29-
ValidFor getValidFor();
30+
public abstract ValidFor getValidFor();
3031

31-
static PublicKey from(dev.sigstore.proto.common.v1.PublicKey proto) {
32+
@Lazy
33+
public java.security.PublicKey toJavaPublicKey()
34+
throws InvalidKeySpecException, NoSuchAlgorithmException {
35+
if (!getKeyDetails().equals("PKIX_ECDSA_P256_SHA_256")) {
36+
throw new InvalidKeySpecException("Unsupported key algorithm: " + getKeyDetails());
37+
}
38+
return Keys.parsePkixPublicKey(getRawBytes(), "EC");
39+
}
40+
41+
public static PublicKey from(dev.sigstore.proto.common.v1.PublicKey proto) {
3242
return ImmutablePublicKey.builder()
3343
.rawBytes(proto.getRawBytes().toByteArray())
3444
.keyDetails(proto.getKeyDetails().name())
3545
.validFor(ValidFor.from(proto.getValidFor()))
3646
.build();
3747
}
38-
39-
static java.security.PublicKey toJavaPublicKey(PublicKey publicKey)
40-
throws InvalidKeySpecException, NoSuchAlgorithmException {
41-
if (!publicKey.getKeyDetails().equals("PKIX_ECDSA_P256_SHA_256")) {
42-
throw new InvalidKeySpecException("Unsupported key algorithm: " + publicKey.getKeyDetails());
43-
}
44-
return Keys.parsePkixPublicKey(publicKey.getRawBytes(), "EC");
45-
}
4648
}

sigstore-java/src/main/java/dev/sigstore/trustroot/Subject.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
import org.immutables.value.Value.Immutable;
2020

2121
@Immutable
22-
interface Subject {
22+
public interface Subject {
2323
String getOrganization();
2424

2525
String getCommonName();

sigstore-java/src/main/java/dev/sigstore/trustroot/TransparencyLogs.java

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

1818
import java.time.Instant;
1919
import java.util.Arrays;
20+
import java.util.Iterator;
2021
import java.util.List;
2122
import java.util.Optional;
2223
import java.util.stream.Collectors;
@@ -26,7 +27,7 @@
2627

2728
@Immutable
2829
@Value.Style(depluralize = true)
29-
public abstract class TransparencyLogs {
30+
public abstract class TransparencyLogs implements Iterable<TransparencyLog> {
3031

3132
public abstract List<TransparencyLog> getTransparencyLogs();
3233

@@ -64,4 +65,9 @@ public Optional<TransparencyLog> find(byte[] logId, Instant time) {
6465
tl.getPublicKey().getValidFor().getEnd().orElse(Instant.now()).compareTo(time) >= 0)
6566
.findAny();
6667
}
68+
69+
@Override
70+
public Iterator<TransparencyLog> iterator() {
71+
return getTransparencyLogs().iterator();
72+
}
6773
}

sigstore-java/src/test/java/dev/sigstore/encryption/certificates/CertificatesTest.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
public class CertificatesTest {
2929
static final String CERT_CHAIN = "dev/sigstore/samples/certs/cert.pem";
3030
static final String CERT = "dev/sigstore/samples/certs/cert-single.pem";
31+
static final String CERT_GH = "dev/sigstore/samples/certs/cert-githuboidc.pem";
3132

3233
@Test
3334
public void testCertificateTranslation() throws IOException, CertificateException {
@@ -130,4 +131,19 @@ public void toCertPath() throws Exception {
130131
Assertions.assertEquals(1, certPath.getCertificates().size());
131132
Assertions.assertEquals(cert, certPath.getCertificates().get(0));
132133
}
134+
135+
@Test
136+
public void appendCertPath() throws Exception {
137+
var certPath =
138+
Certificates.fromPemChain(Resources.toByteArray(Resources.getResource(CERT_CHAIN)));
139+
var cert = Certificates.fromPem(Resources.toByteArray(Resources.getResource(CERT_GH)));
140+
141+
Assertions.assertEquals(2, certPath.getCertificates().size());
142+
var appended = Certificates.appendCertPath(certPath, cert);
143+
144+
Assertions.assertEquals(3, appended.getCertificates().size());
145+
Assertions.assertEquals(cert, appended.getCertificates().get(0));
146+
Assertions.assertEquals(certPath.getCertificates().get(0), appended.getCertificates().get(1));
147+
Assertions.assertEquals(certPath.getCertificates().get(1), appended.getCertificates().get(2));
148+
}
133149
}

sigstore-java/src/test/java/dev/sigstore/trustroot/SigstoreTrustedRootTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ void from_checkFields() throws Exception {
100100
Base64.toBase64String(tlog.getLogId().getKeyId()));
101101
assertEquals(
102102
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE2G2Y+2tabdTV5BcGiBIx0a9fAFwrkBbmLSGtks4L3qX6yYY0zufBnhC8Ur/iy55GhWP/9A/bY2LhC30M9+RYtw==",
103-
Base64.toBase64String(PublicKey.toJavaPublicKey(tlog.getPublicKey()).getEncoded()));
103+
Base64.toBase64String(tlog.getPublicKey().toJavaPublicKey().getEncoded()));
104104

105105
var oldCTLog = trustRoot.getCTLogs().all().get(0);
106106
assertEquals("https://ctfe.sigstore.dev/test", oldCTLog.getBaseUrl().toString());
@@ -116,7 +116,7 @@ void from_checkFields() throws Exception {
116116
Base64.toBase64String(oldCTLog.getLogId().getKeyId()));
117117
assertEquals(
118118
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEbfwR+RJudXscgRBRpKX1XFDy3PyudDxz/SfnRi1fT8ekpfBd2O1uoz7jr3Z8nKzxA69EUQ+eFCFI3zeubPWU7w==",
119-
Base64.toBase64String(PublicKey.toJavaPublicKey(oldCTLog.getPublicKey()).getEncoded()));
119+
Base64.toBase64String(oldCTLog.getPublicKey().toJavaPublicKey().getEncoded()));
120120

121121
var currCTLog = trustRoot.getCTLogs().all().get(1);
122122
assertEquals("https://ctfe.sigstore.dev/2022", currCTLog.getBaseUrl().toString());
@@ -130,7 +130,7 @@ void from_checkFields() throws Exception {
130130
Base64.toBase64String(currCTLog.getLogId().getKeyId()));
131131
assertEquals(
132132
"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEiPSlFi0CmFTfEjCUqF9HuCEcYXNKAaYalIJmBZ8yyezPjTqhxrKBpMnaocVtLJBI1eM3uXnQzQGAJdJ4gs9Fyw==",
133-
Base64.toBase64String(PublicKey.toJavaPublicKey(currCTLog.getPublicKey()).getEncoded()));
133+
Base64.toBase64String(currCTLog.getPublicKey().toJavaPublicKey().getEncoded()));
134134
}
135135

136136
@Test

0 commit comments

Comments
 (0)