gRPC-Java ssl 服务器端认证证书生成
gRPC-Java ssl server side authentication certificate generation
我一直在尝试使用 ssl 为简单的 Java gRPC 应用程序设置服务器端身份验证。我正在使用 certstrap 生成密钥和证书,如下所示:
# Create CA
$ certstrap init --common-name "GRPC"
# Create cert for host using DNS name
$ certstrap request-cert --common-name sdl10236.labs.teradata.com
$ certstrap sign server.com --CA "GRPC"
# gives the following files:
$ GRPC.crl GRPC.crt GRPC.key server.crt server.csr server.key
我有以下 java 代码,是我从他们的 hello world 示例和他们的一些单元测试中拼凑而成的,因为我找不到如何执行此操作的完整示例。
private SslProvider sslProvider = SslProvider.OPENSSL;
...
this.clientContextBuilder = GrpcSslContexts.configure(SslContextBuilder.forClient(), this.sslProvider);
try {
this.serverCertFile = this.loadCert("server.crt");
this.serverPrivateKeyFile = this.loadCert("server.key");
this.serverTrustedCaCerts = new X509Certificate[]{this.loadX509Cert("GRPC.crt")};
} catch (IOException ex) {
logger.warning("Error occurred loading certificate files.");
ex.getMessage();
ex.printStackTrace();
} catch (CertificateException cex) {
logger.warning("Error occurred loading the x509 cert.");
}
...
this.server = serverBuilder(0, this.serverCertFile, this.serverPrivateKeyFile, this.serverTrustedCaCerts).forPort(port).addService(new HelloServiceGrpc.HelloServiceImplBase() { ... }
...
private File loadCert(String name) throws IOException {
InputStream in = new BufferedInputStream(GrpcServer.class.getResourceAsStream("/certs/" + name));
File tmpFile = File.createTempFile(name, "");
tmpFile.deleteOnExit();
OutputStream os = new BufferedOutputStream(new FileOutputStream(tmpFile));
try {
int b;
while ((b = in.read()) != -1) {
os.write(b);
}
os.flush();
} finally {
in.close();
os.close();
}
return tmpFile;
}
private X509Certificate loadX509Cert(String fileName) throws CertificateException, IOException {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
logger.info("" + fileName);
InputStream in = GrpcServer.class.getResourceAsStream("/certs/" + fileName);
if (in != null) {
logger.info("Inputstream is defined.");
}
try {
return (X509Certificate) cf.generateCertificate(in);
} finally {
in.close();
}
}
private ServerBuilder<?> serverBuilder(int port, File serverCertChainFile,
File serverPrivateKeyFile, X509Certificate[] serverTrustedCaCerts) throws IOException {
SslContextBuilder sslContextBuilder = SslContextBuilder.forServer(serverCertChainFile, serverPrivateKeyFile);
GrpcSslContexts.configure(sslContextBuilder, sslProvider);
sslContextBuilder.trustManager(serverTrustedCaCerts).clientAuth(ClientAuth.REQUIRE);
return NettyServerBuilder.forPort(port).sslContext(sslContextBuilder.build());
}
当我读取程序中的证书和密钥时,x509 证书读取失败。
Exception in thread "main" java.lang.IllegalArgumentException: File does not contain valid private key: /tmp/GRPC.key5252344955683539009
at io.netty.handler.ssl.SslContextBuilder.keyManager(SslContextBuilder.java:267)
at io.netty.handler.ssl.SslContextBuilder.keyManager(SslContextBuilder.java:222)
at io.netty.handler.ssl.SslContextBuilder.forServer(SslContextBuilder.java:54)
at com.teradata.grpc.GrpcServer.serverBuilder(GrpcServer.java:152)
at com.teradata.grpc.GrpcServer.start(GrpcServer.java:69)
at com.teradata.grpc.GrpcServer.main(GrpcServer.java:111)
Caused by: java.security.KeyException: could not find a PKCS #8 private key in input stream (see http://netty.io/wiki/sslcontextbuilder-and-private-key.html for more information)
at io.netty.handler.ssl.PemReader.readPrivateKey(PemReader.java:128)
at io.netty.handler.ssl.PemReader.readPrivateKey(PemReader.java:109)
at io.netty.handler.ssl.SslContext.toPrivateKey(SslContext.java:1014)
at io.netty.handler.ssl.SslContextBuilder.keyManager(SslContextBuilder.java:265)
... 5 more
我真正的问题是生成密钥的正确方法是什么?我浏览了所有文档,并已阅读预期格式为 PEM,但 certstrap 生成 PEM 格式的 .crt 文件。我不确定我应该阅读哪些文件,而且我没有在文档中找到通过生成正确的密钥来工作的示例。
我应该注意,certstrap 生成的密钥在 C++ 中有效,但在 Java 中无效。
如有任何帮助,我们将不胜感激。
Polyglot 有一个集成测试,可以执行客户端和服务器 TLS 身份验证[1]。它还记录了 运行 的确切命令以生成证书 [2].
您应该可以从那里刷一些代码。有帮助吗?
转到错误消息中的URL似乎给出了一个很好的线索:http://netty.io/wiki/sslcontextbuilder-and-private-key.html
certstrap 生成以以下开头的密钥:
-----BEGIN RSA PRIVATE KEY-----
我看到 grpc-java 的测试键以:
开头
-----BEGIN PRIVATE KEY-----
运行 Netty 记录的命令似乎转换为测试密钥中使用的相同格式:
openssl pkcs8 -topk8 -nocrypt -in server.key -out server.key2
(也在 https://groups.google.com/forum/#!topic/grpc-io/5uAK5c9rTHw 讨论过)
我一直在尝试使用 ssl 为简单的 Java gRPC 应用程序设置服务器端身份验证。我正在使用 certstrap 生成密钥和证书,如下所示:
# Create CA
$ certstrap init --common-name "GRPC"
# Create cert for host using DNS name
$ certstrap request-cert --common-name sdl10236.labs.teradata.com
$ certstrap sign server.com --CA "GRPC"
# gives the following files:
$ GRPC.crl GRPC.crt GRPC.key server.crt server.csr server.key
我有以下 java 代码,是我从他们的 hello world 示例和他们的一些单元测试中拼凑而成的,因为我找不到如何执行此操作的完整示例。
private SslProvider sslProvider = SslProvider.OPENSSL;
...
this.clientContextBuilder = GrpcSslContexts.configure(SslContextBuilder.forClient(), this.sslProvider);
try {
this.serverCertFile = this.loadCert("server.crt");
this.serverPrivateKeyFile = this.loadCert("server.key");
this.serverTrustedCaCerts = new X509Certificate[]{this.loadX509Cert("GRPC.crt")};
} catch (IOException ex) {
logger.warning("Error occurred loading certificate files.");
ex.getMessage();
ex.printStackTrace();
} catch (CertificateException cex) {
logger.warning("Error occurred loading the x509 cert.");
}
...
this.server = serverBuilder(0, this.serverCertFile, this.serverPrivateKeyFile, this.serverTrustedCaCerts).forPort(port).addService(new HelloServiceGrpc.HelloServiceImplBase() { ... }
...
private File loadCert(String name) throws IOException {
InputStream in = new BufferedInputStream(GrpcServer.class.getResourceAsStream("/certs/" + name));
File tmpFile = File.createTempFile(name, "");
tmpFile.deleteOnExit();
OutputStream os = new BufferedOutputStream(new FileOutputStream(tmpFile));
try {
int b;
while ((b = in.read()) != -1) {
os.write(b);
}
os.flush();
} finally {
in.close();
os.close();
}
return tmpFile;
}
private X509Certificate loadX509Cert(String fileName) throws CertificateException, IOException {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
logger.info("" + fileName);
InputStream in = GrpcServer.class.getResourceAsStream("/certs/" + fileName);
if (in != null) {
logger.info("Inputstream is defined.");
}
try {
return (X509Certificate) cf.generateCertificate(in);
} finally {
in.close();
}
}
private ServerBuilder<?> serverBuilder(int port, File serverCertChainFile,
File serverPrivateKeyFile, X509Certificate[] serverTrustedCaCerts) throws IOException {
SslContextBuilder sslContextBuilder = SslContextBuilder.forServer(serverCertChainFile, serverPrivateKeyFile);
GrpcSslContexts.configure(sslContextBuilder, sslProvider);
sslContextBuilder.trustManager(serverTrustedCaCerts).clientAuth(ClientAuth.REQUIRE);
return NettyServerBuilder.forPort(port).sslContext(sslContextBuilder.build());
}
当我读取程序中的证书和密钥时,x509 证书读取失败。
Exception in thread "main" java.lang.IllegalArgumentException: File does not contain valid private key: /tmp/GRPC.key5252344955683539009
at io.netty.handler.ssl.SslContextBuilder.keyManager(SslContextBuilder.java:267)
at io.netty.handler.ssl.SslContextBuilder.keyManager(SslContextBuilder.java:222)
at io.netty.handler.ssl.SslContextBuilder.forServer(SslContextBuilder.java:54)
at com.teradata.grpc.GrpcServer.serverBuilder(GrpcServer.java:152)
at com.teradata.grpc.GrpcServer.start(GrpcServer.java:69)
at com.teradata.grpc.GrpcServer.main(GrpcServer.java:111)
Caused by: java.security.KeyException: could not find a PKCS #8 private key in input stream (see http://netty.io/wiki/sslcontextbuilder-and-private-key.html for more information)
at io.netty.handler.ssl.PemReader.readPrivateKey(PemReader.java:128)
at io.netty.handler.ssl.PemReader.readPrivateKey(PemReader.java:109)
at io.netty.handler.ssl.SslContext.toPrivateKey(SslContext.java:1014)
at io.netty.handler.ssl.SslContextBuilder.keyManager(SslContextBuilder.java:265)
... 5 more
我真正的问题是生成密钥的正确方法是什么?我浏览了所有文档,并已阅读预期格式为 PEM,但 certstrap 生成 PEM 格式的 .crt 文件。我不确定我应该阅读哪些文件,而且我没有在文档中找到通过生成正确的密钥来工作的示例。
我应该注意,certstrap 生成的密钥在 C++ 中有效,但在 Java 中无效。
如有任何帮助,我们将不胜感激。
Polyglot 有一个集成测试,可以执行客户端和服务器 TLS 身份验证[1]。它还记录了 运行 的确切命令以生成证书 [2].
您应该可以从那里刷一些代码。有帮助吗?
转到错误消息中的URL似乎给出了一个很好的线索:http://netty.io/wiki/sslcontextbuilder-and-private-key.html
certstrap 生成以以下开头的密钥:
-----BEGIN RSA PRIVATE KEY-----
我看到 grpc-java 的测试键以:
开头-----BEGIN PRIVATE KEY-----
运行 Netty 记录的命令似乎转换为测试密钥中使用的相同格式:
openssl pkcs8 -topk8 -nocrypt -in server.key -out server.key2
(也在 https://groups.google.com/forum/#!topic/grpc-io/5uAK5c9rTHw 讨论过)