Skip to content

Commit 8844a6b

Browse files
authored
fix: enforce non-root path for X.509 SVID leaf SPIFFE IDs (#417)
Signed-off-by: Max Lambrecht <maxlambrecht@gmail.com>
1 parent 91e20cc commit 8844a6b

File tree

2 files changed

+45
-0
lines changed

2 files changed

+45
-0
lines changed

java-spiffe-core/src/main/java/io/spiffe/svid/x509svid/X509Svid.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ private static X509Svid createX509Svid(final byte[] certsBytes,
217217
final PrivateKey privateKey = generatePrivateKey(privateKeyBytes, keyFileFormat, x509Certificates);
218218
final SpiffeId spiffeId = getSpiffeId(x509Certificates);
219219

220+
validateLeafSpiffeId(spiffeId);
220221
validateLeafCertificate(x509Certificates.get(0));
221222

222223
// there are intermediate CA certificates
@@ -227,6 +228,13 @@ private static X509Svid createX509Svid(final byte[] certsBytes,
227228
return new X509Svid(spiffeId, x509Certificates, privateKey, hint);
228229
}
229230

231+
private static void validateLeafSpiffeId(final SpiffeId spiffeId) throws X509SvidException {
232+
final String path = spiffeId.getPath();
233+
if (path == null || path.isEmpty()) {
234+
throw new X509SvidException("Leaf certificate SPIFFE ID must have a non-root path");
235+
}
236+
}
237+
230238
private static SpiffeId getSpiffeId(final List<X509Certificate> x509Certificates) throws X509SvidException {
231239
final SpiffeId spiffeId;
232240
try {

java-spiffe-core/src/test/java/io/spiffe/svid/x509svid/X509SvidTest.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package io.spiffe.svid.x509svid;
22

3+
import io.spiffe.exception.InvalidSpiffeIdException;
34
import io.spiffe.exception.X509SvidException;
45
import io.spiffe.spiffeid.SpiffeId;
56
import io.spiffe.spiffeid.TrustDomain;
7+
import io.spiffe.utils.CertAndKeyPair;
68
import org.junit.jupiter.api.Test;
79
import org.junit.jupiter.params.ParameterizedTest;
810
import org.junit.jupiter.params.provider.Arguments;
@@ -18,8 +20,11 @@
1820
import java.util.stream.Stream;
1921

2022
import static io.spiffe.utils.TestUtils.toUri;
23+
import static io.spiffe.utils.X509CertificateTestUtils.createCertificate;
24+
import static io.spiffe.utils.X509CertificateTestUtils.createRootCA;
2125
import static org.junit.jupiter.api.Assertions.assertEquals;
2226
import static org.junit.jupiter.api.Assertions.assertNotNull;
27+
import static org.junit.jupiter.api.Assertions.assertThrows;
2328
import static org.junit.jupiter.api.Assertions.fail;
2429

2530
class X509SvidTest {
@@ -315,6 +320,38 @@ void testGetChainArray() throws URISyntaxException, X509SvidException {
315320
assertEquals(x509Svid.getChain().get(1), x509CertificatesArray[1]);
316321
}
317322

323+
@Test
324+
void parseRaw_leafSpiffeIdWithoutPath_isRejected() throws Exception {
325+
CertAndKeyPair rootCa = createRootCA("C = US, O = SPIFFE", "spiffe://example.org");
326+
CertAndKeyPair leaf = createCertificate("C = US, O = SPIRE", "C = US, O = SPIFFE", "spiffe://example.org", rootCa, false);
327+
328+
byte[] certBytes = leaf.getCertificate().getEncoded();
329+
byte[] keyBytes = leaf.getKeyPair().getPrivate().getEncoded();
330+
331+
X509SvidException exception = assertThrows(
332+
X509SvidException.class,
333+
() -> X509Svid.parseRaw(certBytes, keyBytes)
334+
);
335+
336+
assertEquals("Leaf certificate SPIFFE ID must have a non-root path", exception.getMessage());
337+
}
338+
339+
@Test
340+
void parseRaw_leafSpiffeIdWithRootOnlyPath_isRejected() throws Exception {
341+
CertAndKeyPair rootCa = createRootCA("C = US, O = SPIFFE", "spiffe://example.org");
342+
CertAndKeyPair leaf = createCertificate("C = US, O = SPIRE", "C = US, O = SPIFFE", "spiffe://example.org/", rootCa, false);
343+
344+
byte[] certBytes = leaf.getCertificate().getEncoded();
345+
byte[] keyBytes = leaf.getKeyPair().getPrivate().getEncoded();
346+
347+
InvalidSpiffeIdException exception = assertThrows(
348+
InvalidSpiffeIdException.class,
349+
() -> X509Svid.parseRaw(certBytes, keyBytes)
350+
);
351+
352+
assertEquals("Path cannot have a trailing slash", exception.getMessage());
353+
}
354+
318355
@ParameterizedTest
319356
@MethodSource("provideX509SvidScenarios")
320357
void parseX509Svid(TestCase testCase) {

0 commit comments

Comments
 (0)