diff --git a/core/src/main/java/io/grpc/internal/SpiffeUtil.java b/core/src/main/java/io/grpc/internal/SpiffeUtil.java index 21232ad293b..102485ebd54 100644 --- a/core/src/main/java/io/grpc/internal/SpiffeUtil.java +++ b/core/src/main/java/io/grpc/internal/SpiffeUtil.java @@ -231,14 +231,8 @@ private static List extractCert(List> keysNode, for (Map keyNode : keysNode) { checkJwkEntry(keyNode, trustDomainName); List rawCerts = JsonUtil.getListOfStrings(keyNode, "x5c"); - if (rawCerts == null) { - throw new IllegalArgumentException(String.format("'x5c' parameter is required. Certificate " - + "loading for trust domain '%s' failed.", trustDomainName)); - } - if (rawCerts.size() != 1) { - throw new IllegalArgumentException(String.format("Exactly 1 certificate is expected, but " - + "%s found. Certificate loading for trust domain '%s' failed.", rawCerts.size(), - trustDomainName)); + if (rawCerts == null || rawCerts.isEmpty()) { + continue; } InputStream stream = new ByteArrayInputStream((CERTIFICATE_PREFIX + rawCerts.get(0) + "\n" + CERTIFICATE_SUFFIX) diff --git a/core/src/test/java/io/grpc/internal/SpiffeUtilTest.java b/core/src/test/java/io/grpc/internal/SpiffeUtilTest.java index 8888046c586..bea79704c66 100644 --- a/core/src/test/java/io/grpc/internal/SpiffeUtilTest.java +++ b/core/src/test/java/io/grpc/internal/SpiffeUtilTest.java @@ -231,6 +231,8 @@ public static class CertificateApiTest { private static final String SPIFFE_TRUST_BUNDLE_WRONG_ROOT = "spiffebundle_wrong_root.json"; private static final String SPIFFE_TRUST_BUNDLE_WRONG_SEQ = "spiffebundle_wrong_seq_type.json"; private static final String SPIFFE_TRUST_BUNDLE_MISSING_X5C = "spiffebundle_missing_x5c.json"; + private static final String SPIFFE_TRUST_BUNDLE_EMPTY_X5C = "spiffebundle_empty_x5c.json"; + private static final String SPIFFE_TRUST_BUNDLE_IGNORED_KEYS = "spiffebundle_ignored_keys.json"; private static final String DOMAIN_ERROR_MESSAGE = " Certificate loading for trust domain 'google.com' failed."; @@ -330,6 +332,54 @@ public void loadTrustBundleFromFileSuccessTest() throws Exception { assertEquals("foo.bar.com", spiffeId_ec.get().getTrustDomain()); } + @Test + public void loadTrustBundleFromFileWithMultiCertsSuccessTest() throws Exception { + SpiffeBundle tb = SpiffeUtil.loadTrustBundleFromFile( + copyFileToTmp(SPIFFE_TRUST_BUNDLE_WRONG_MULTI_CERTS)); + assertEquals(1, tb.getSequenceNumbers().size()); + assertEquals(123L, (long) tb.getSequenceNumbers().get("google.com")); + assertEquals(1, tb.getBundleMap().size()); + assertEquals(1, tb.getBundleMap().get("google.com").size()); + Optional spiffeId = SpiffeUtil.extractSpiffeId( + tb.getBundleMap().get("google.com").toArray(new X509Certificate[0])); + assertTrue(spiffeId.isPresent()); + assertEquals("foo.bar.com", spiffeId.get().getTrustDomain()); + } + + @Test + public void loadTrustBundleFromFileWithMissingX5cSuccessTest() throws Exception { + SpiffeBundle tb = SpiffeUtil.loadTrustBundleFromFile( + copyFileToTmp(SPIFFE_TRUST_BUNDLE_MISSING_X5C)); + assertEquals(1, tb.getBundleMap().size()); + assertEquals(1, tb.getBundleMap().get("google.com").size()); + } + + @Test + public void loadTrustBundleFromFileWithEmptyX5cSuccessTest() throws Exception { + SpiffeBundle tb = SpiffeUtil.loadTrustBundleFromFile( + copyFileToTmp(SPIFFE_TRUST_BUNDLE_EMPTY_X5C)); + assertEquals(1, tb.getBundleMap().size()); + assertEquals(1, tb.getBundleMap().get("google.com").size()); + Optional spiffeId = SpiffeUtil.extractSpiffeId( + tb.getBundleMap().get("google.com").toArray(new X509Certificate[0])); + assertTrue(spiffeId.isPresent()); + assertEquals("foo.bar.com", spiffeId.get().getTrustDomain()); + } + + @Test + public void loadTrustBundleFromFileWithIgnoredKeysSuccessTest() throws Exception { + SpiffeBundle tb = SpiffeUtil.loadTrustBundleFromFile( + copyFileToTmp(SPIFFE_TRUST_BUNDLE_IGNORED_KEYS)); + assertEquals(1, tb.getSequenceNumbers().size()); + assertEquals(123L, (long) tb.getSequenceNumbers().get("google.com")); + assertEquals(1, tb.getBundleMap().size()); + assertEquals(1, tb.getBundleMap().get("google.com").size()); + Optional spiffeId = SpiffeUtil.extractSpiffeId( + tb.getBundleMap().get("google.com").toArray(new X509Certificate[0])); + assertTrue(spiffeId.isPresent()); + assertEquals("foo.bar.com", spiffeId.get().getTrustDomain()); + } + @Test public void loadTrustBundleFromFileFailureTest() { // Check the exception if JSON root element is different from 'trust_domains' @@ -352,10 +402,6 @@ public void loadTrustBundleFromFileFailureTest() { iae = assertThrows(IllegalArgumentException.class, () -> SpiffeUtil .loadTrustBundleFromFile(copyFileToTmp(SPIFFE_TRUST_BUNDLE_CORRUPTED_CERT))); assertEquals("Certificate can't be parsed." + DOMAIN_ERROR_MESSAGE, iae.getMessage()); - // Check the exception if a key entry is missing the 'x5c' parameter - iae = assertThrows(IllegalArgumentException.class, () -> SpiffeUtil - .loadTrustBundleFromFile(copyFileToTmp(SPIFFE_TRUST_BUNDLE_MISSING_X5C))); - assertEquals("'x5c' parameter is required." + DOMAIN_ERROR_MESSAGE, iae.getMessage()); // Check the exception if 'kty' value differs from 'RSA' iae = assertThrows(IllegalArgumentException.class, () -> SpiffeUtil .loadTrustBundleFromFile(copyFileToTmp(SPIFFE_TRUST_BUNDLE_WRONG_KTY))); @@ -371,11 +417,6 @@ public void loadTrustBundleFromFileFailureTest() { .loadTrustBundleFromFile(copyFileToTmp(SPIFFE_TRUST_BUNDLE_WRONG_USE))); assertEquals("'use' parameter must be 'x509-svid' but 'i_am_not_x509-svid' found." + DOMAIN_ERROR_MESSAGE, iae.getMessage()); - // Check the exception if multiple certs are provided for 'x5c' - iae = assertThrows(IllegalArgumentException.class, () -> SpiffeUtil - .loadTrustBundleFromFile(copyFileToTmp(SPIFFE_TRUST_BUNDLE_WRONG_MULTI_CERTS))); - assertEquals("Exactly 1 certificate is expected, but 2 found." + DOMAIN_ERROR_MESSAGE, - iae.getMessage()); } @Test diff --git a/core/src/test/resources/io/grpc/internal/spiffebundle_empty_x5c.json b/core/src/test/resources/io/grpc/internal/spiffebundle_empty_x5c.json new file mode 100644 index 00000000000..70eabf2233c --- /dev/null +++ b/core/src/test/resources/io/grpc/internal/spiffebundle_empty_x5c.json @@ -0,0 +1,19 @@ +{ + "trust_domains": { + "google.com": { + "spiffe_sequence": 123, + "keys": [ + { + "kty": "RSA", + "use": "x509-svid", + "x5c": [] + }, + { + "kty": "RSA", + "use": "x509-svid", + "x5c": ["MIIFsjCCA5qgAwIBAgIURygVMMzdr+Q7rsUaz189JozyHMwwDQYJKoZIhvcNAQELBQAwTjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTVkwxDTALBgNVBAoMBGdSUEMxFTATBgNVBAMMDHRlc3QtY2xpZW50MTAeFw0yMTEyMjMxODQyNTJaFw0zMTEyMjExODQyNTJaME4xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEMMAoGA1UEBwwDU1ZMMQ0wCwYDVQQKDARnUlBDMRUwEwYDVQQDDAx0ZXN0LWNsaWVudDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ4AqpGetyVSqGUuBJLVFla+7bEfca7UYzfVSSZLZ/X+JDmWIVN8UIPuFib5jhMEc3XaUnFXUmM7zEtz/ZG5hapwLwOb2C3ZxOP6PQjYCJxbkLie+b43UQrFu1xxd3vMhVJgcj/AIxEpmszuqOa6kUrkYifjJADQ+64kZgl66bsTdXMCzpxyFl9xUfff59L8OX+HUfAcoZz3emjg3ZJPYURQEmjdZTOau1EjFilwHgd989Jt7NKgx30NXoHmw7nusVBIY94fL2VKN3f1XVm0dHu5NI279Q6zr0ZBU7k5T3IeHnzsUesQS4NGlklDWoVTKk73Uv9Pna8yQsSW757PEbHOGp9Knu4bnoGPOlsG81yIPipO6hTgGFK24pF97M9kpGbWqYX4+2vLlrCAfcmsHqaUPmQlYeRVTT6vw7ctYo2kyUYGtnODXk76LqewRBVvkzx75QUhfjAyb740YcDmIenc56Tq6gebJHjhEmVSehR6xIpXP7SVeurTyhPsEQnpJHtgs4dcwWOZp7BvPNzHXmJqfr7vsshie3vS5kQ0u1e1yqAqXgyDjqKXOkx+dpgUTehSJHhPNHvTc5LXRsvvXKYz6FrwR/DZ8t7BNEvPeLjFgxpH7QVJFLCvCbXs5K6yYbsnLfxFIBPRnrbJkIsK+sQwnRdnsiUdPsTkG5B2lQfQIDAQABo4GHMIGEMB0GA1UdDgQWBBQ2lBp0PiRHHvQ5IRURm8aHsj4RETAfBgNVHSMEGDAWgBQ2lBp0PiRHHvQ5IRURm8aHsj4RETAPBgNVHRMBAf8EBTADAQH/MDEGA1UdEQQqMCiGJnNwaWZmZTovL2Zvby5iYXIuY29tL2NsaWVudC93b3JrbG9hZC8xMA0GCSqGSIb3DQEBCwUAA4ICAQA1mSkgRclAl+E/aS9zJ7t8+Y4n3T24nOKKveSIjxXm/zjhWqVsLYBI6kglWtih2+PELvU8JdPqNZK34Kl0Q6FWpVSGDdWN1i6NyORt2ocggL3ke3iXxRk3UpUKJmqwz81VhA2KUHnMlyE0IufFfZNwNWWHBv13uJfRbjeQpKPhU+yf4DeXrsWcvrZlGvAET+mcplafUzCp7Iv+PcISJtUerbxbVtuHVeZCLlgDXWkLAWJN8rf0dIG4x060LJ+j6j9uRVhb9sZn1HJV+j4XdIYm1VKilluhOtNwP2d3Ox/JuTBxf7hFHXZPfMagQE5k5PzmxRaCAEMJ1l2DvUbZw+shJfSNoWcBo2qadnUaWT3BmmJRBDh7ZReib/RQ1Rd4ygOyzP3E0vkV4/gqyjLdApXh5PZP8KLQZ+1JN/sdWt7VfIt9wYOpkIqujdll51ESHzwQeAK9WVCB4UvVz6zdhItB9CRbXPreWC+wCB1xDovIzFKOVsLs5+Gqs1m7VinG2LxbDqaKyo/FB0Hxx0acBNzezLWoDwXYQrN0T0S4pnqhKD1CYPpdArBkNezUYAjS725FkApuK+mnBX3U0msBffEaUEOkcyar1EW2m/33vpetD/k3eQQkmvQf4Hbiu9AF+9cNDm/hMuXEw5EXGA91fn0891b5eEW8BJHXX0jri0aN8g=="] + } + ] + } + } +} diff --git a/core/src/test/resources/io/grpc/internal/spiffebundle_ignored_keys.json b/core/src/test/resources/io/grpc/internal/spiffebundle_ignored_keys.json new file mode 100644 index 00000000000..f1daffba60e --- /dev/null +++ b/core/src/test/resources/io/grpc/internal/spiffebundle_ignored_keys.json @@ -0,0 +1,23 @@ +{ + "trust_domains": { + "google.com": { + "spiffe_sequence": 123, + "keys": [ + { + "kty": "RSA", + "use": "x509-svid" + }, + { + "kty": "RSA", + "use": "x509-svid", + "x5c": [] + }, + { + "kty": "RSA", + "use": "x509-svid", + "x5c": ["MIIFsjCCA5qgAwIBAgIURygVMMzdr+Q7rsUaz189JozyHMwwDQYJKoZIhvcNAQELBQAwTjELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQwwCgYDVQQHDANTVkwxDTALBgNVBAoMBGdSUEMxFTATBgNVBAMMDHRlc3QtY2xpZW50MTAeFw0yMTEyMjMxODQyNTJaFw0zMTEyMjExODQyNTJaME4xCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTEMMAoGA1UEBwwDU1ZMMQ0wCwYDVQQKDARnUlBDMRUwEwYDVQQDDAx0ZXN0LWNsaWVudDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ4AqpGetyVSqGUuBJLVFla+7bEfca7UYzfVSSZLZ/X+JDmWIVN8UIPuFib5jhMEc3XaUnFXUmM7zEtz/ZG5hapwLwOb2C3ZxOP6PQjYCJxbkLie+b43UQrFu1xxd3vMhVJgcj/AIxEpmszuqOa6kUrkYifjJADQ+64kZgl66bsTdXMCzpxyFl9xUfff59L8OX+HUfAcoZz3emjg3ZJPYURQEmjdZTOau1EjFilwHgd989Jt7NKgx30NXoHmw7nusVBIY94fL2VKN3f1XVm0dHu5NI279Q6zr0ZBU7k5T3IeHnzsUesQS4NGlklDWoVTKk73Uv9Pna8yQsSW757PEbHOGp9Knu4bnoGPOlsG81yIPipO6hTgGFK24pF97M9kpGbWqYX4+2vLlrCAfcmsHqaUPmQlYeRVTT6vw7ctYo2kyUYGtnODXk76LqewRBVvkzx75QUhfjAyb740YcDmIenc56Tq6gebJHjhEmVSehR6xIpXP7SVeurTyhPsEQnpJHtgs4dcwWOZp7BvPNzHXmJqfr7vsshie3vS5kQ0u1e1yqAqXgyDjqKXOkx+dpgUTehSJHhPNHvTc5LXRsvvXKYz6FrwR/DZ8t7BNEvPeLjFgxpH7QVJFLCvCbXs5K6yYbsnLfxFIBPRnrbJkIsK+sQwnRdnsiUdPsTkG5B2lQfQIDAQABo4GHMIGEMB0GA1UdDgQWBBQ2lBp0PiRHHvQ5IRURm8aHsj4RETAfBgNVHSMEGDAWgBQ2lBp0PiRHHvQ5IRURm8aHsj4RETAPBgNVHRMBAf8EBTADAQH/MDEGA1UdEQQqMCiGJnNwaWZmZTovL2Zvby5iYXIuY29tL2NsaWVudC93b3JrbG9hZC8xMA0GCSqGSIb3DQEBCwUAA4ICAQA1mSkgRclAl+E/aS9zJ7t8+Y4n3T24nOKKveSIjxXm/zjhWqVsLYBI6kglWtih2+PELvU8JdPqNZK34Kl0Q6FWpVSGDdWN1i6NyORt2ocggL3ke3iXxRk3UpUKJmqwz81VhA2KUHnMlyE0IufFfZNwNWWHBv13uJfRbjeQpKPhU+yf4DeXrsWcvrZlGvAET+mcplafUzCp7Iv+PcISJtUerbxbVtuHVeZCLlgDXWkLAWJN8rf0dIG4x060LJ+j6j9uRVhb9sZn1HJV+j4XdIYm1VKilluhOtNwP2d3Ox/JuTBxf7hFHXZPfMagQE5k5PzmxRaCAEMJ1l2DvUbZw+shJfSNoWcBo2qadnUaWT3BmmJRBDh7ZReib/RQ1Rd4ygOyzP3E0vkV4/gqyjLdApXh5PZP8KLQZ+1JN/sdWt7VfIt9wYOpkIqujdll51ESHzwQeAK9WVCB4UvVz6zdhItB9CRbXPreWC+wCB1xDovIzFKOVsLs5+Gqs1m7VinG2LxbDqaKyo/FB0Hxx0acBNzezLWoDwXYQrN0T0S4pnqhKD1CYPpdArBkNezUYAjS725FkApuK+mnBX3U0msBffEaUEOkcyar1EW2m/33vpetD/k3eQQkmvQf4Hbiu9AF+9cNDm/hMuXEw5EXGA91fn0891b5eEW8BJHXX0jri0aN8g=="] + } + ] + } + } +}