Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Server support ALPN with OpenSSL #2102

Merged
merged 4 commits into from
Aug 30, 2023
Merged

Server support ALPN with OpenSSL #2102

merged 4 commits into from
Aug 30, 2023

Conversation

leaf-potato
Copy link
Contributor

What problem does this PR solve?

Issue Number: #1991

Problem Summary: 当前bRPC中进行SSL/TLS握手阶段没有支持ALPN扩展协议。

What is changed and the side effects?

Changed: 在ServerSSLOptions中扩展ALPN配置项。

Side effects:

  • Performance effects(性能影响): 当用户在ServerSSLOptions中设置ALPN选项时,server启动时会将ALPN选项序列化为标准格式并设置好回调函数。在SSL/TLS握手阶段会调用回调函数选择匹配的协议并返回给客户端。

  • Breaking backward compatibility(向后兼容性): 是


Check List:

  • Please make sure your changes are compilable(请确保你的更改可以通过编译).
  • When providing us with a new feature, it is best to add related tests(如果你向我们增加一个新的功能, 请添加相关测试).
  • Please follow Contributor Covenant Code of Conduct.(请遵循贡献者准则).

@leaf-potato
Copy link
Contributor Author

Client端的实现还有点问题,暂时先提交Server端的代码。还请大佬们给Review下~

@@ -44,6 +44,7 @@ class AdaptiveProtocolType {
public:
explicit AdaptiveProtocolType() : _type(PROTOCOL_UNKNOWN) {}
explicit AdaptiveProtocolType(ProtocolType type) : _type(type) {}
explicit AdaptiveProtocolType(butil::StringPiece name) { AssignWithString(name); }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里可以直接调用operator=(name),就不用改那么多了

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

好的,这个我改下

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

name = name.substr(0, CHAR_MAX);
}

char lenght = static_cast<char>(name.size());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lenght -> length

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -521,6 +558,10 @@ SSL_CTX* CreateServerSSLContext(const std::string& certificate,

#endif // OPENSSL_NO_DH

// Set ALPN callback to choose application protocol.
if (SetServerALPNCallback(ssl_ctx.get(), alpns) != 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

如果alpns为空串,则不需要SetServerALPNCallback

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -686,6 +688,10 @@ friend class Controller;
ServerOptions _options;
butil::EndPoint _listen_addr;

// ALPN extention protocol-list format. Server initialize this with alpns options.
// OpenSSL API use this variable to avoid conversion at each handshake.
std::string _row_alpns;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

row在这里是什么意思?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

和options.alpns做区分,这儿为格式转化后TLS使用的原始数据

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

row -> raw?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

是的,手误~

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -642,6 +642,33 @@ int Server::InitializeOnce() {
return 0;
}

int Server::InitALPNOptions(ServerSSLOptions* options) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里options不会被修改

int Server::InitALPNOptions(const ServerSSLOptions* options);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

butil::StringSplitter split(alpns.data(), alpns.data() + alpns.size(), ',');

std::string row_protocol;
for (; split; split++) {
Copy link
Contributor

@cdjingit cdjingit Feb 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for (butil::StringSplitter split(alpns.data(), ','); split; ++split) {
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

写法参考的src/brpc/details/ssl_helper.cpp文件中ParseSSLProtocols函数里的实现
可能的1个改动点:split++ => ++split

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

split在for 循环外并没有用到,应该包在for 里面。

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -1913,7 +1946,7 @@ int Server::AddCertificate(const CertInfo& cert) {
ssl_ctx.filters = cert.sni_filters;
ssl_ctx.ctx = std::make_shared<SocketSSLContext>();
SSL_CTX* raw_ctx = CreateServerSSLContext(cert.certificate, cert.private_key,
_options.ssl_options(), &ssl_ctx.filters);
_options.ssl_options(), &_row_alpns, &ssl_ctx.filters);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

代码缩进

SSL_CTX* raw_ctx = CreateServerSSLContext(
    cert.certificate, cert.private_key, 
    _options.ssl_options(), &_row_alpns, &ssl_ctx.filters);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -441,6 +441,42 @@ static int SetSSLOptions(SSL_CTX* ctx, const std::string& ciphers,
return 0;
}

static int ServerALPNCallback(SSL* ssl,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

代码缩进

static int ServerALPNCallback(
    SSL* ssl, const unsigned char** out, unsigned char* outlen,
    const unsigned char* in, unsigned int inlen, void* arg)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

好像第1个参数都没单独换行。是说第2、3行没有和第1个参数缩进对齐?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

static int ServerALPNCallback(SSL* ssl, const unsigned char** out, unsigned char* outlen,
                              const unsigned char* in, unsigned int inlen, void* arg);
或者这样
static int ServerALPNCallback(
    SSL* ssl, const unsigned char** out, unsigned char* outlen,
    const unsigned char* in, unsigned int inlen, void* arg)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

if (select_result == OPENSSL_NPN_NEGOTIATED) {
return SSL_TLSEXT_ERR_OK;
}
return SSL_TLSEXT_ERR_NOACK;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return select_result == OPENSSL_NPN_NEGOTIATED ? SSL_TLSEXT_ERR_OK : SSL_TLSEXT_ERR_NOACK;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -833,6 +874,23 @@ void Print(std::ostream& os, X509* cert, const char* sep) {
os << butil::StringPiece(bufp, len);
}

std::string ALPNProtocolToString(const AdaptiveProtocolType& protocol) {
std::string name = protocol.name();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

用butil::StringPiece

butil::StringPiece name(protocol.name());
if (name.starts_with("http")) {
    name.set("http/1.1");
}
....

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@chenzhangyi
Copy link
Member

能加一下文档说明下这个实现逻辑,以及补充一下UT么? 牵涉到协议实现,希望尽量能严谨和完整一点

@leaf-potato
Copy link
Contributor Author

能加一下文档说明下这个实现逻辑,以及补充一下UT么? 牵涉到协议实现,希望尽量能严谨和完整一点

@chenzhangyi 可以的,文档&UT后续我都补充下。Client端还没实现完,UT可能需要使用OpenSSL命令来验证协商是否正确

@wwbmmm
Copy link
Contributor

wwbmmm commented Feb 9, 2023

UT编译失败了:
brpc_ssl_unittest.cpp:342:66: error: too few arguments to function call, expected 5, have 4
brpc::SSLOptions(), NULL);

const_cast<unsigned char**>(out), outlen,
reinterpret_cast<const unsigned char*>(alpns->data()), alpns->size(),
in, inlen);
return (select_result == OPENSSL_NPN_NEGOTIATED)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

如果没选择到,返回SSL_TLSEXT_ERR_NOACK会直接断开SSL链接吗?
和返回SSL_TLSEXT_ERR_ALERT_FATAL区别是啥?

@@ -642,6 +642,31 @@ int Server::InitializeOnce() {
return 0;
}

int Server::InitALPNOptions(const ServerSSLOptions* options) {
if (options == nullptr) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

如果openssl版本不支持,这里就直接报错?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

并不是 这儿是判断ServerSSLOptions是否为nullptr

@Menci Menci mentioned this pull request May 16, 2023
@leaf-potato
Copy link
Contributor Author

UT编译失败了:
brpc_ssl_unittest.cpp:342:66: error: too few arguments to function call, expected 5, have 4
brpc::SSLOptions(), NULL);

@wwbmmm 编译失败已解决,同时补充了本次功能的UT和文档


```c++
ServerSSLOptions ssl_options;
ssl_options->alpns = "http, h2, baidu_std";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

应该是ssl_options.alpns吧?

              const ::example::EchoRequest* request,
              ::example::EchoResponse* response,
              ::google::protobuf::Closure* done) {
void Echo(::google::protobuf::RpcController* cntl_base,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

无关的改动,有点多

@leaf-potato
Copy link
Contributor Author

@wwbmmm 请问下PR还有需要修改的地儿嘛

@wwbmmm
Copy link
Contributor

wwbmmm commented Aug 2, 2023

LGTM

@leaf-potato
Copy link
Contributor Author

@wwbmmm 大佬 求问考虑合入了嘛~

@wwbmmm wwbmmm merged commit 09acd32 into apache:master Aug 30, 2023
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants