使用OpenSSL生成密钥
本文以《gRPC基本使用的C++示例工程》文章中的示例MFC工程为基础,添加SSL相关代码。
例如在工程生成目录(D:\SoftwareDevelopment\gRPC_Study\gRPC_Example\x64\Debug)下创建ssl文件夹,然后生成有效期365天的密钥。
1、安装OpenSSL
可以在官网下载、源码编译,本文使用vcpkg进行安装。
vcpkg install openssl
2、设置环境变量
- Path里添加openssl的安装路径,例如:D:\SoftwareDevelopment\vcpkg\installed\x64-windows\tools\openssl
- 添加用户变量OPENSSL_CONF,设置值为openssl文件夹的openssl.cnf文件路径,例如:D:\SoftwareDevelopment\vcpkg\installed\x64-windows\tools\openssl\openssl.cn
3、生成key和证书
openssl genrsa -out D:\SoftwareDevelopment\gRPC_Study\gRPC_Example\x64\Debug\ssl\server.key 2048
openssl req -new -x509 -days 365 -subj "/C=CN/L=Beijing/O=mengmei/CN=localhost" -key D:\SoftwareDevelopment\gRPC_Study\gRPC_Example\x64\Debug\ssl\server.key -out D:\SoftwareDevelopment\gRPC_Study\gRPC_Example\x64\Debug\ssl\server.crt
openssl genrsa -out D:\SoftwareDevelopment\gRPC_Study\gRPC_Example\x64\Debug\ssl\client.key 2048
openssl req -new -x509 -days 365 -subj "/C=CN/L=Shanghai/O=mengmei/CN=localhost" -key D:\SoftwareDevelopment\gRPC_Study\gRPC_Example\x64\Debug\ssl\client.key -out D:\SoftwareDevelopment\gRPC_Study\gRPC_Example\x64\Debug\ssl\client.crt
subj
参数说明
字段 | 字段含义 | 示例 |
---|---|---|
/C= | Country 国家 | CN |
/ST= | State or Province 省 | Beijing |
/L= | Location or City 城市 | Shanghai |
/O= | Organization 组织或企业 | mengmei |
/OU= | Organization Unit 部门 | dev |
/CN= | Common Name 域名或IP | localhost |
服务端关键代码
_builder = make_unique<ServerBuilder>();
// _builder->AddListeningPort(serverAddr, grpc::InsecureServerCredentials());// 监听不需要认证的连接
auto GetFileString = [&](string extraFilePath)
{
char buf[MAX_PATH] = { 0 };
GetModuleFileNameA(NULL, buf, MAX_PATH * sizeof(char));
GetLongPathNameA(buf, buf, MAX_PATH * sizeof(char));
PathRemoveFileSpecA(buf);
PathAppendA(buf, extraFilePath.c_str());
ifstream in(buf);
istreambuf_iterator<char> beg(in), end;
string str(beg, end);
return str;
};
// 增加SSL验证
grpc::SslServerCredentialsOptions sslOpts{};
sslOpts.client_certificate_request = GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY;
sslOpts.pem_key_cert_pairs.push_back(grpc::SslServerCredentialsOptions::PemKeyCertPair{ GetFileString("ssl/server.key"), GetFileString("ssl/server.crt") });
sslOpts.pem_root_certs = GetFileString("ssl/client.crt");
auto creds = grpc::SslServerCredentials(sslOpts);
_builder->AddListeningPort(serverAddr, creds);
客户端关键代码
auto GetFileString = [&](string extraFilePath)
{
char buf[MAX_PATH] = { 0 };
GetModuleFileNameA(NULL, buf, MAX_PATH * sizeof(char));
GetLongPathNameA(buf, buf, MAX_PATH * sizeof(char));
PathRemoveFileSpecA(buf);
PathAppendA(buf, extraFilePath.c_str());
ifstream in(buf);
istreambuf_iterator<char> beg(in), end;
string str(beg, end);
return str;
};
// 创建gRPC channel
// _channel = grpc::CreateChannel(serverAddr, grpc::InsecureChannelCredentials()); // 监听不需要认证的连接
// 增加SSL验证
grpc::SslCredentialsOptions sslOpts;
sslOpts.pem_root_certs = GetFileString("ssl/server.crt");
sslOpts.pem_private_key = GetFileString("ssl/client.key");
sslOpts.pem_cert_chain = GetFileString("ssl/client.crt");
auto creds = grpc::SslCredentials(sslOpts);
_channel = grpc::CreateChannel(serverAddr, creds);
_stub = UserService::NewStub(_channel);