最近在做服务器端的SSL支持,服务器端用的网络IO库是libuv,由于libuv官方是不会支持ssl的,因此得自己实现。
原理应该是将 libuv获取到的数据喂给OPENSSL的BIO,然后判断是否握手完毕。注意:SSL的客户端发送给服务器端的数据首先是SSL握手数据,然后再是http等头数据。
本文仅仅是记录了在服务器端初始化的流程,便于以后参考。
在用OPENSSL做服务器端时 ,服务器端需要首先配置证书与私钥文件,然后用 SSL_set_accept_state() 来设置为服务器端,这个函数告诉SSL等待客户端连接hello握手。然后将从原始SOCKET读取到的客户端数据写入BIO的 reader(rbio),等待握手完成。
ctx = SSL_CTX_new(SSLv3_server_method()); // This is the server!
SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
ssl = SSL_new(ctx);
rbio = BIO_new(BIO_s_mem());
wbio = BIO_new(BIO_s_mem());
SSL_set_bio(ssl, rbio, wbio);
SSL_set_accept_state(ssl); // 用SSL_set_accept_state来设置为服务器端
//将从客户端读取到的数据写入到 SSL的 reader BIO,这些数据是客户端发送的握手数据
do {
uint8_t buf[1024];
int buf_size = read_from_client_socket(client, buf, 1024);
BIO_write(rbio, buf, buf_size);
if (!SSL_is_init_finished(ssl)) {
SSL_do_handshake(ssl);
}
else {
break;
}
}while(1);
do {
//准备要发送给客户端的数据,例如从文件或者其它地方获取的
uint8_t data[4096];
int data_len;
....
BIO_write(rbio, data, data_len);
char buf[4096];
int ret = SSL_read(ssl, buf, sizeof(buf));
if (ret < 0) {
int err = SSL_get_error(client -> ssl, ret);
if (err == SSL_ERROR_WANT_READ) {
} else if (err == SSL_ERROR_WANT_WRITE) {
}
}
}while(1);
用 SSL_is_init_finished(ssl) 函数判断握手是否完成,如果没有完成,就调用 SSL_do_handshake(ssl)。然后从 BIO_writer 里读取数据并发送给客户端。