Skip to content

Commit 559e3ba

Browse files
authored
internal: Allow EC Keys in SPIFFE Bundle Map parsing (grpc#12399)
SPIFFE Bundle Map parsing was originally implemented to only support RSA keys. It should also support EC keys.
1 parent 53393e0 commit 559e3ba

File tree

3 files changed

+142
-6
lines changed

3 files changed

+142
-6
lines changed

core/src/main/java/io/grpc/internal/SpiffeUtil.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.google.common.base.Splitter;
2424
import com.google.common.collect.ImmutableList;
2525
import com.google.common.collect.ImmutableMap;
26+
import com.google.common.collect.ImmutableSet;
2627
import com.google.common.io.Files;
2728
import java.io.ByteArrayInputStream;
2829
import java.io.File;
@@ -51,7 +52,7 @@ public final class SpiffeUtil {
5152

5253
private static final Integer URI_SAN_TYPE = 6;
5354
private static final String USE_PARAMETER_VALUE = "x509-svid";
54-
private static final String KTY_PARAMETER_VALUE = "RSA";
55+
private static final ImmutableSet<String> KTY_PARAMETER_VALUES = ImmutableSet.of("RSA", "EC");
5556
private static final String CERTIFICATE_PREFIX = "-----BEGIN CERTIFICATE-----\n";
5657
private static final String CERTIFICATE_SUFFIX = "-----END CERTIFICATE-----";
5758
private static final String PREFIX = "spiffe://";
@@ -205,10 +206,12 @@ public static SpiffeBundle loadTrustBundleFromFile(String trustBundleFile) throw
205206

206207
private static void checkJwkEntry(Map<String, ?> jwkNode, String trustDomainName) {
207208
String kty = JsonUtil.getString(jwkNode, "kty");
208-
if (kty == null || !kty.equals(KTY_PARAMETER_VALUE)) {
209-
throw new IllegalArgumentException(String.format("'kty' parameter must be '%s' but '%s' "
210-
+ "found. Certificate loading for trust domain '%s' failed.", KTY_PARAMETER_VALUE,
211-
kty, trustDomainName));
209+
if (kty == null || !KTY_PARAMETER_VALUES.contains(kty)) {
210+
throw new IllegalArgumentException(
211+
String.format(
212+
"'kty' parameter must be one of %s but '%s' "
213+
+ "found. Certificate loading for trust domain '%s' failed.",
214+
KTY_PARAMETER_VALUES, kty, trustDomainName));
212215
}
213216
if (jwkNode.containsKey("kid")) {
214217
throw new IllegalArgumentException(String.format("'kid' parameter must not be set. "

core/src/test/java/io/grpc/internal/SpiffeUtilTest.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ public static class CertificateApiTest {
218218
private static final String SERVER_0_PEM_FILE = "server0.pem";
219219
private static final String TEST_DIRECTORY_PREFIX = "io/grpc/internal/";
220220
private static final String SPIFFE_TRUST_BUNDLE = "spiffebundle.json";
221+
private static final String SPIFFE_TRUST_BUNDLE_WITH_EC_KTY = "spiffebundle_ec.json";
221222
private static final String SPIFFE_TRUST_BUNDLE_MALFORMED = "spiffebundle_malformed.json";
222223
private static final String SPIFFE_TRUST_BUNDLE_CORRUPTED_CERT =
223224
"spiffebundle_corrupted_cert.json";
@@ -311,6 +312,21 @@ public void loadTrustBundleFromFileSuccessTest() throws Exception {
311312
.toArray(new X509Certificate[0]));
312313
assertTrue(spiffeId.isPresent());
313314
assertEquals("foo.bar.com", spiffeId.get().getTrustDomain());
315+
316+
SpiffeBundle tb_ec = SpiffeUtil.loadTrustBundleFromFile(
317+
copyFileToTmp(SPIFFE_TRUST_BUNDLE_WITH_EC_KTY));
318+
assertEquals(2, tb_ec.getSequenceNumbers().size());
319+
assertEquals(12035488L, (long) tb_ec.getSequenceNumbers().get("example.com"));
320+
assertEquals(-1L, (long) tb_ec.getSequenceNumbers().get("test.example.com"));
321+
assertEquals(3, tb_ec.getBundleMap().size());
322+
assertEquals(0, tb_ec.getBundleMap().get("test.google.com.au").size());
323+
assertEquals(1, tb_ec.getBundleMap().get("example.com").size());
324+
assertEquals(2, tb_ec.getBundleMap().get("test.example.com").size());
325+
Optional<SpiffeId> spiffeId_ec =
326+
SpiffeUtil.extractSpiffeId(tb_ec.getBundleMap().get("example.com")
327+
.toArray(new X509Certificate[0]));
328+
assertTrue(spiffeId_ec.isPresent());
329+
assertEquals("foo.bar.com", spiffeId_ec.get().getTrustDomain());
314330
}
315331

316332
@Test
@@ -338,7 +354,8 @@ public void loadTrustBundleFromFileFailureTest() {
338354
// Check the exception if 'kty' value differs from 'RSA'
339355
iae = assertThrows(IllegalArgumentException.class, () -> SpiffeUtil
340356
.loadTrustBundleFromFile(copyFileToTmp(SPIFFE_TRUST_BUNDLE_WRONG_KTY)));
341-
assertEquals("'kty' parameter must be 'RSA' but 'null' found." + DOMAIN_ERROR_MESSAGE,
357+
assertEquals(
358+
"'kty' parameter must be one of [RSA, EC] but 'null' found." + DOMAIN_ERROR_MESSAGE,
342359
iae.getMessage());
343360
// Check the exception if 'kid' has a value
344361
iae = assertThrows(IllegalArgumentException.class, () -> SpiffeUtil
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
{
2+
"trust_domains": {
3+
"test.google.com.au": {},
4+
"example.com": {
5+
"spiffe_sequence": 12035488,
6+
"keys": [
7+
{
8+
9+
"kty": "EC",
10+
"use": "x509-svid",
11+
"x5c": ["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
41+
GA91fn0891b5eEW8BJHXX0jri0aN8g=="],
42+
"n": "<base64urlUint-encoded value>",
43+
"e": "AQAB"
44+
}
45+
]
46+
},
47+
"test.example.com": {
48+
"keys": [
49+
{
50+
"kty": "RSA",
51+
"use": "x509-svid",
52+
"x5c": ["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
82+
GA91fn0891b5eEW8BJHXX0jri0aN8g=="],
83+
"n": "<base64urlUint-encoded value>",
84+
"e": "AQAB"
85+
},
86+
{
87+
"kty": "RSA",
88+
"use": "x509-svid",
89+
"x5c": ["MIIELTCCAxWgAwIBAgIUVXGlXjNENtOZbI12epjgIhMaShEwDQYJKoZIhvcNAQEL
90+
BQAwVjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
91+
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEPMA0GA1UEAwwGdGVzdGNhMB4XDTI0
92+
MDkxNzE2MTk0NFoXDTM0MDkxNTE2MTk0NFowTjELMAkGA1UEBhMCVVMxCzAJBgNV
93+
BAgMAkNBMQwwCgYDVQQHDANTVkwxDTALBgNVBAoMBGdSUEMxFTATBgNVBAMMDHRl
94+
c3QtY2xpZW50MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOcTjjcS
95+
SfG/EGrr6G+f+3T2GXyHHfroQFi9mZUz80L7uKBdECOImID+YhoK8vcxLQjPmEEv
96+
FIYgJT5amugDcYIgUhMjBx/8RPJaP/nGmBngAqsuuNCaZfyaHBRqN8XdS/AwmsI5
97+
Wo+nru0+0/7aQFdqqtd2+e9dHjUWwgHxXvMgC4hkHpsdCGIZWVzWyBliwTYQYb1Y
98+
yYe1LzqqQA5OMbZfKOY9MYDCEYOliRiunOn30iIOHj9V5qLzWGfSyxCRuvLRdEP8
99+
iDeNweHbdaKuI80nQmxuBdRIspE9k5sD1WA4vLZpeg3zggxp4rfLL5zBJgb/33D3
100+
d9Rkm14xfDPihhkCAwEAAaOB+jCB9zBZBgNVHREEUjBQhiZzcGlmZmU6Ly9mb28u
101+
YmFyLmNvbS9jbGllbnQvd29ya2xvYWQvMYYmc3BpZmZlOi8vZm9vLmJhci5jb20v
102+
Y2xpZW50L3dvcmtsb2FkLzIwHQYDVR0OBBYEFG9GkBgdBg/p0U9/lXv8zIJ+2c2N
103+
MHsGA1UdIwR0MHKhWqRYMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0
104+
YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMM
105+
BnRlc3RjYYIUWrP0VvHcy+LP6UuYNtiL9gBhD5owDQYJKoZIhvcNAQELBQADggEB
106+
AJ4Cbxv+02SpUgkEu4hP/1+8DtSBXUxNxI0VG4e3Ap2+Rhjm3YiFeS/UeaZhNrrw
107+
UEjkSTPFODyXR7wI7UO9OO1StyD6CMkp3SEvevU5JsZtGL6mTiTLTi3Qkywa91Bt
108+
GlyZdVMghA1bBJLBMwiD5VT5noqoJBD7hDy6v9yNmt1Sw2iYBJPqI3Gnf5bMjR3s
109+
UICaxmFyqaMCZsPkfJh0DmZpInGJys3m4QqGz6ZE2DWgcSr1r/ML7/5bSPjjr8j4
110+
WFFSqFR3dMu8CbGnfZTCTXa4GTX/rARXbAO67Z/oJbJBK7VKayskL+PzKuohb9ox
111+
jGL772hQMbwtFCOFXu5VP0s="]
112+
}
113+
]
114+
}
115+
}
116+
}

0 commit comments

Comments
 (0)