diff --git a/xds/src/main/java/io/grpc/xds/internal/security/trust/CertificateUtils.java b/xds/src/main/java/io/grpc/xds/internal/security/trust/CertificateUtils.java index d7696bbd3a6..86b6dd95c3e 100644 --- a/xds/src/main/java/io/grpc/xds/internal/security/trust/CertificateUtils.java +++ b/xds/src/main/java/io/grpc/xds/internal/security/trust/CertificateUtils.java @@ -16,50 +16,19 @@ package io.grpc.xds.internal.security.trust; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import io.netty.handler.codec.base64.Base64; -import io.netty.util.CharsetUtil; import java.io.BufferedInputStream; -import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; -import java.security.KeyException; -import java.security.KeyFactory; import java.security.PrivateKey; -import java.security.cert.Certificate; import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; -import java.security.spec.PKCS8EncodedKeySpec; -import java.util.Collection; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * Contains certificate utility method(s). */ public final class CertificateUtils { - private static final Logger logger = Logger.getLogger(CertificateUtils.class.getName()); - - private static CertificateFactory factory; - private static final Pattern KEY_PATTERN = Pattern.compile( - "-+BEGIN\\s+.*PRIVATE\\s+KEY[^-]*-+(?:\\s|\\r|\\n)+" // Header - + "([a-z0-9+/=\\r\\n]+)" // Base64 text - + "-+END\\s+.*PRIVATE\\s+KEY[^-]*-+", // Footer - Pattern.CASE_INSENSITIVE); - - private static synchronized void initInstance() throws CertificateException { - if (factory == null) { - factory = CertificateFactory.getInstance("X.509"); - } - } - /** * Generates X509Certificate array from a file on disk. * @@ -73,72 +42,15 @@ static X509Certificate[] toX509Certificates(File file) throws CertificateExcepti } /** Generates X509Certificate array from the {@link InputStream}. */ - public static synchronized X509Certificate[] toX509Certificates(InputStream inputStream) + public static X509Certificate[] toX509Certificates(InputStream inputStream) throws CertificateException, IOException { - initInstance(); - Collection certs = factory.generateCertificates(inputStream); - return certs.toArray(new X509Certificate[0]); - - } - - /** See {@link CertificateFactory#generateCertificate(InputStream)}. */ - public static synchronized X509Certificate toX509Certificate(InputStream inputStream) - throws CertificateException, IOException { - initInstance(); - Certificate cert = factory.generateCertificate(inputStream); - return (X509Certificate) cert; + return io.grpc.util.CertificateUtils.getX509Certificates(inputStream); } /** Generates a {@link PrivateKey} from the {@link InputStream}. */ public static PrivateKey getPrivateKey(InputStream inputStream) throws Exception { - ByteBuf encodedKeyBuf = readPrivateKey(inputStream); - byte[] encodedKey = new byte[encodedKeyBuf.readableBytes()]; - encodedKeyBuf.readBytes(encodedKey).release(); - PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(encodedKey); - return KeyFactory.getInstance("RSA").generatePrivate(spec); - } - - private static ByteBuf readPrivateKey(InputStream in) throws KeyException { - String content; - try { - content = readContent(in); - } catch (IOException e) { - throw new KeyException("failed to read key input stream", e); - } - Matcher m = KEY_PATTERN.matcher(content); - if (!m.find()) { - throw new KeyException("could not find a PKCS #8 private key in input stream"); - } - ByteBuf base64 = Unpooled.copiedBuffer(m.group(1), CharsetUtil.US_ASCII); - ByteBuf der = Base64.decode(base64); - base64.release(); - return der; - } - - private static String readContent(InputStream in) throws IOException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - try { - byte[] buf = new byte[8192]; - for (; ; ) { - int ret = in.read(buf); - if (ret < 0) { - break; - } - out.write(buf, 0, ret); - } - return out.toString(CharsetUtil.US_ASCII.name()); - } finally { - safeClose(out); - } - } - - private static void safeClose(OutputStream out) { - try { - out.close(); - } catch (IOException e) { - logger.log(Level.WARNING, "Failed to close a stream.", e); - } + return io.grpc.util.CertificateUtils.getPrivateKey(inputStream); } private CertificateUtils() {} diff --git a/xds/src/test/java/io/grpc/xds/internal/security/CommonTlsContextTestsUtil.java b/xds/src/test/java/io/grpc/xds/internal/security/CommonTlsContextTestsUtil.java index 6ecd549624f..8a04a3d02a7 100644 --- a/xds/src/test/java/io/grpc/xds/internal/security/CommonTlsContextTestsUtil.java +++ b/xds/src/test/java/io/grpc/xds/internal/security/CommonTlsContextTestsUtil.java @@ -17,9 +17,7 @@ package io.grpc.xds.internal.security; import static com.google.common.truth.Truth.assertThat; -import static java.nio.charset.StandardCharsets.UTF_8; -import com.google.common.io.CharStreams; import com.google.common.util.concurrent.MoreExecutors; import com.google.protobuf.BoolValue; import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CertificateProviderPluginInstance; @@ -32,14 +30,11 @@ import io.envoyproxy.envoy.type.matcher.v3.StringMatcher; import io.grpc.internal.testing.TestUtils; import io.grpc.testing.TlsTesting; +import io.grpc.util.CertificateUtils; import io.grpc.xds.EnvoyServerProtoData; -import io.grpc.xds.internal.security.trust.CertificateUtils; import io.netty.handler.ssl.SslContext; -import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.Arrays; @@ -195,22 +190,11 @@ public static EnvoyServerProtoData.UpstreamTlsContext buildUpstreamTlsContext( /** Gets a cert from contents of a resource. */ public static X509Certificate getCertFromResourceName(String resourceName) throws IOException, CertificateException { - try (ByteArrayInputStream bais = - new ByteArrayInputStream(getResourceContents(resourceName).getBytes(UTF_8))) { - return CertificateUtils.toX509Certificate(bais); + try (InputStream cert = TlsTesting.loadCert(resourceName)) { + return CertificateUtils.getX509Certificates(cert)[0]; } } - /** Gets contents of a certs resource. */ - public static String getResourceContents(String resourceName) throws IOException { - InputStream inputStream = TlsTesting.loadCert(resourceName); - String text = null; - try (Reader reader = new InputStreamReader(inputStream, UTF_8)) { - text = CharStreams.toString(reader); - } - return text; - } - @SuppressWarnings("deprecation") private static CommonTlsContext buildCommonTlsContextForCertProviderInstance( String certInstanceName, diff --git a/xds/src/test/java/io/grpc/xds/internal/security/certprovider/CommonCertProviderTestUtils.java b/xds/src/test/java/io/grpc/xds/internal/security/certprovider/CommonCertProviderTestUtils.java index c62aa2d3a81..0c71b52901b 100644 --- a/xds/src/test/java/io/grpc/xds/internal/security/certprovider/CommonCertProviderTestUtils.java +++ b/xds/src/test/java/io/grpc/xds/internal/security/certprovider/CommonCertProviderTestUtils.java @@ -16,19 +16,13 @@ package io.grpc.xds.internal.security.certprovider; -import static java.nio.charset.StandardCharsets.UTF_8; - -import com.google.common.io.CharStreams; import io.grpc.internal.FakeClock; import io.grpc.internal.TimeProvider; import io.grpc.internal.testing.TestUtils; +import io.grpc.util.CertificateUtils; import io.grpc.xds.internal.security.certprovider.FileWatcherCertificateProviderProvider.ScheduledExecutorServiceFactory; -import io.grpc.xds.internal.security.trust.CertificateUtils; -import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; import java.security.PrivateKey; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; @@ -44,17 +38,9 @@ static PrivateKey getPrivateKey(String resourceName) static X509Certificate getCertFromResourceName(String resourceName) throws IOException, CertificateException { - return CertificateUtils.toX509Certificate( - new ByteArrayInputStream(getResourceContents(resourceName).getBytes(UTF_8))); - } - - private static String getResourceContents(String resourceName) throws IOException { - InputStream inputStream = TestUtils.class.getResourceAsStream("/certs/" + resourceName); - String text = null; - try (Reader reader = new InputStreamReader(inputStream, UTF_8)) { - text = CharStreams.toString(reader); + try (InputStream cert = TestUtils.class.getResourceAsStream("/certs/" + resourceName)) { + return CertificateUtils.getX509Certificates(cert)[0]; } - return text; } /** Allow tests to register a provider using test clock. diff --git a/xds/src/test/java/io/grpc/xds/internal/security/certprovider/FileWatcherCertificateProviderTest.java b/xds/src/test/java/io/grpc/xds/internal/security/certprovider/FileWatcherCertificateProviderTest.java index ccdc7c23275..210ec056732 100644 --- a/xds/src/test/java/io/grpc/xds/internal/security/certprovider/FileWatcherCertificateProviderTest.java +++ b/xds/src/test/java/io/grpc/xds/internal/security/certprovider/FileWatcherCertificateProviderTest.java @@ -270,12 +270,12 @@ public void getCertificate_badKeyFile() throws IOException, InterruptedException CLIENT_PEM_FILE, SERVER_0_PEM_FILE, CA_PEM_FILE, - java.security.KeyException.class, + java.security.spec.InvalidKeySpecException.class, 0, 1, 0, 0, - "could not find a PKCS #8 private key in input stream"); + "Neither RSA nor EC worked"); } @Test