Skip to content

Commit 100d5a5

Browse files
committedJan 10, 2024
xds: Add EC key support
io.grpc.util.CertificateUtils does much of the same thing as xds's CertificateUtils, but also supports EC keys. The xds code pre-dates the grpc-util class, so it isn't surprising it wasn't using it. There's a good number of usages of the xds CertificateUtils, so I just got rid of the duplicate implementation, but didn't yet bother changing callers io.grpc.util.
1 parent cb03bd2 commit 100d5a5

File tree

4 files changed

+11
-129
lines changed

4 files changed

+11
-129
lines changed
 

‎xds/src/main/java/io/grpc/xds/internal/security/trust/CertificateUtils.java

+3-91
Original file line numberDiff line numberDiff line change
@@ -16,50 +16,19 @@
1616

1717
package io.grpc.xds.internal.security.trust;
1818

19-
import io.netty.buffer.ByteBuf;
20-
import io.netty.buffer.Unpooled;
21-
import io.netty.handler.codec.base64.Base64;
22-
import io.netty.util.CharsetUtil;
2319
import java.io.BufferedInputStream;
24-
import java.io.ByteArrayOutputStream;
2520
import java.io.File;
2621
import java.io.FileInputStream;
2722
import java.io.IOException;
2823
import java.io.InputStream;
29-
import java.io.OutputStream;
30-
import java.security.KeyException;
31-
import java.security.KeyFactory;
3224
import java.security.PrivateKey;
33-
import java.security.cert.Certificate;
3425
import java.security.cert.CertificateException;
35-
import java.security.cert.CertificateFactory;
3626
import java.security.cert.X509Certificate;
37-
import java.security.spec.PKCS8EncodedKeySpec;
38-
import java.util.Collection;
39-
import java.util.logging.Level;
40-
import java.util.logging.Logger;
41-
import java.util.regex.Matcher;
42-
import java.util.regex.Pattern;
4327

4428
/**
4529
* Contains certificate utility method(s).
4630
*/
4731
public final class CertificateUtils {
48-
private static final Logger logger = Logger.getLogger(CertificateUtils.class.getName());
49-
50-
private static CertificateFactory factory;
51-
private static final Pattern KEY_PATTERN = Pattern.compile(
52-
"-+BEGIN\\s+.*PRIVATE\\s+KEY[^-]*-+(?:\\s|\\r|\\n)+" // Header
53-
+ "([a-z0-9+/=\\r\\n]+)" // Base64 text
54-
+ "-+END\\s+.*PRIVATE\\s+KEY[^-]*-+", // Footer
55-
Pattern.CASE_INSENSITIVE);
56-
57-
private static synchronized void initInstance() throws CertificateException {
58-
if (factory == null) {
59-
factory = CertificateFactory.getInstance("X.509");
60-
}
61-
}
62-
6332
/**
6433
* Generates X509Certificate array from a file on disk.
6534
*
@@ -73,72 +42,15 @@ static X509Certificate[] toX509Certificates(File file) throws CertificateExcepti
7342
}
7443

7544
/** Generates X509Certificate array from the {@link InputStream}. */
76-
public static synchronized X509Certificate[] toX509Certificates(InputStream inputStream)
45+
public static X509Certificate[] toX509Certificates(InputStream inputStream)
7746
throws CertificateException, IOException {
78-
initInstance();
79-
Collection<? extends Certificate> certs = factory.generateCertificates(inputStream);
80-
return certs.toArray(new X509Certificate[0]);
81-
82-
}
83-
84-
/** See {@link CertificateFactory#generateCertificate(InputStream)}. */
85-
public static synchronized X509Certificate toX509Certificate(InputStream inputStream)
86-
throws CertificateException, IOException {
87-
initInstance();
88-
Certificate cert = factory.generateCertificate(inputStream);
89-
return (X509Certificate) cert;
47+
return io.grpc.util.CertificateUtils.getX509Certificates(inputStream);
9048
}
9149

9250
/** Generates a {@link PrivateKey} from the {@link InputStream}. */
9351
public static PrivateKey getPrivateKey(InputStream inputStream)
9452
throws Exception {
95-
ByteBuf encodedKeyBuf = readPrivateKey(inputStream);
96-
byte[] encodedKey = new byte[encodedKeyBuf.readableBytes()];
97-
encodedKeyBuf.readBytes(encodedKey).release();
98-
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(encodedKey);
99-
return KeyFactory.getInstance("RSA").generatePrivate(spec);
100-
}
101-
102-
private static ByteBuf readPrivateKey(InputStream in) throws KeyException {
103-
String content;
104-
try {
105-
content = readContent(in);
106-
} catch (IOException e) {
107-
throw new KeyException("failed to read key input stream", e);
108-
}
109-
Matcher m = KEY_PATTERN.matcher(content);
110-
if (!m.find()) {
111-
throw new KeyException("could not find a PKCS #8 private key in input stream");
112-
}
113-
ByteBuf base64 = Unpooled.copiedBuffer(m.group(1), CharsetUtil.US_ASCII);
114-
ByteBuf der = Base64.decode(base64);
115-
base64.release();
116-
return der;
117-
}
118-
119-
private static String readContent(InputStream in) throws IOException {
120-
ByteArrayOutputStream out = new ByteArrayOutputStream();
121-
try {
122-
byte[] buf = new byte[8192];
123-
for (; ; ) {
124-
int ret = in.read(buf);
125-
if (ret < 0) {
126-
break;
127-
}
128-
out.write(buf, 0, ret);
129-
}
130-
return out.toString(CharsetUtil.US_ASCII.name());
131-
} finally {
132-
safeClose(out);
133-
}
134-
}
135-
136-
private static void safeClose(OutputStream out) {
137-
try {
138-
out.close();
139-
} catch (IOException e) {
140-
logger.log(Level.WARNING, "Failed to close a stream.", e);
141-
}
53+
return io.grpc.util.CertificateUtils.getPrivateKey(inputStream);
14254
}
14355

14456
private CertificateUtils() {}

‎xds/src/test/java/io/grpc/xds/internal/security/CommonTlsContextTestsUtil.java

+3-19
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,7 @@
1717
package io.grpc.xds.internal.security;
1818

1919
import static com.google.common.truth.Truth.assertThat;
20-
import static java.nio.charset.StandardCharsets.UTF_8;
2120

22-
import com.google.common.io.CharStreams;
2321
import com.google.common.util.concurrent.MoreExecutors;
2422
import com.google.protobuf.BoolValue;
2523
import io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.CertificateProviderPluginInstance;
@@ -32,14 +30,11 @@
3230
import io.envoyproxy.envoy.type.matcher.v3.StringMatcher;
3331
import io.grpc.internal.testing.TestUtils;
3432
import io.grpc.testing.TlsTesting;
33+
import io.grpc.util.CertificateUtils;
3534
import io.grpc.xds.EnvoyServerProtoData;
36-
import io.grpc.xds.internal.security.trust.CertificateUtils;
3735
import io.netty.handler.ssl.SslContext;
38-
import java.io.ByteArrayInputStream;
3936
import java.io.IOException;
4037
import java.io.InputStream;
41-
import java.io.InputStreamReader;
42-
import java.io.Reader;
4338
import java.security.cert.CertificateException;
4439
import java.security.cert.X509Certificate;
4540
import java.util.Arrays;
@@ -195,22 +190,11 @@ public static EnvoyServerProtoData.UpstreamTlsContext buildUpstreamTlsContext(
195190
/** Gets a cert from contents of a resource. */
196191
public static X509Certificate getCertFromResourceName(String resourceName)
197192
throws IOException, CertificateException {
198-
try (ByteArrayInputStream bais =
199-
new ByteArrayInputStream(getResourceContents(resourceName).getBytes(UTF_8))) {
200-
return CertificateUtils.toX509Certificate(bais);
193+
try (InputStream cert = TlsTesting.loadCert(resourceName)) {
194+
return CertificateUtils.getX509Certificates(cert)[0];
201195
}
202196
}
203197

204-
/** Gets contents of a certs resource. */
205-
public static String getResourceContents(String resourceName) throws IOException {
206-
InputStream inputStream = TlsTesting.loadCert(resourceName);
207-
String text = null;
208-
try (Reader reader = new InputStreamReader(inputStream, UTF_8)) {
209-
text = CharStreams.toString(reader);
210-
}
211-
return text;
212-
}
213-
214198
@SuppressWarnings("deprecation")
215199
private static CommonTlsContext buildCommonTlsContextForCertProviderInstance(
216200
String certInstanceName,

‎xds/src/test/java/io/grpc/xds/internal/security/certprovider/CommonCertProviderTestUtils.java

+3-17
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,13 @@
1616

1717
package io.grpc.xds.internal.security.certprovider;
1818

19-
import static java.nio.charset.StandardCharsets.UTF_8;
20-
21-
import com.google.common.io.CharStreams;
2219
import io.grpc.internal.FakeClock;
2320
import io.grpc.internal.TimeProvider;
2421
import io.grpc.internal.testing.TestUtils;
22+
import io.grpc.util.CertificateUtils;
2523
import io.grpc.xds.internal.security.certprovider.FileWatcherCertificateProviderProvider.ScheduledExecutorServiceFactory;
26-
import io.grpc.xds.internal.security.trust.CertificateUtils;
27-
import java.io.ByteArrayInputStream;
2824
import java.io.IOException;
2925
import java.io.InputStream;
30-
import java.io.InputStreamReader;
31-
import java.io.Reader;
3226
import java.security.PrivateKey;
3327
import java.security.cert.CertificateException;
3428
import java.security.cert.X509Certificate;
@@ -44,17 +38,9 @@ static PrivateKey getPrivateKey(String resourceName)
4438

4539
static X509Certificate getCertFromResourceName(String resourceName)
4640
throws IOException, CertificateException {
47-
return CertificateUtils.toX509Certificate(
48-
new ByteArrayInputStream(getResourceContents(resourceName).getBytes(UTF_8)));
49-
}
50-
51-
private static String getResourceContents(String resourceName) throws IOException {
52-
InputStream inputStream = TestUtils.class.getResourceAsStream("/certs/" + resourceName);
53-
String text = null;
54-
try (Reader reader = new InputStreamReader(inputStream, UTF_8)) {
55-
text = CharStreams.toString(reader);
41+
try (InputStream cert = TestUtils.class.getResourceAsStream("/certs/" + resourceName)) {
42+
return CertificateUtils.getX509Certificates(cert)[0];
5643
}
57-
return text;
5844
}
5945

6046
/** Allow tests to register a provider using test clock.

‎xds/src/test/java/io/grpc/xds/internal/security/certprovider/FileWatcherCertificateProviderTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -270,12 +270,12 @@ public void getCertificate_badKeyFile() throws IOException, InterruptedException
270270
CLIENT_PEM_FILE,
271271
SERVER_0_PEM_FILE,
272272
CA_PEM_FILE,
273-
java.security.KeyException.class,
273+
java.security.spec.InvalidKeySpecException.class,
274274
0,
275275
1,
276276
0,
277277
0,
278-
"could not find a PKCS #8 private key in input stream");
278+
"Neither RSA nor EC worked");
279279
}
280280

281281
@Test

0 commit comments

Comments
 (0)
Please sign in to comment.