基于BearSSL实现自签名证书双向认证测试代码

清疚 2022-12-07 04:28 146阅读 0赞

客户端、服务器端双向认证大致过程:可以参考:https://blog.csdn.net/fengbingchun/article/details/106856332

(1). 客户端发起连接请求;

(2). 服务器端返回消息,包含服务器端证书server.crt;

(3). 客户端验证服务器端证书server.crt的合法性;

(4). 客户端向服务器端发送客户端证书client.crt;

(5). 服务器端验证客户端证书client.crt,并将选定的加密方案发给客户端;

(6). 客户端发送随机生成的对称公钥给服务器端;

(7). 服务器端获取客户端发送的对称公钥;

接下来双方即可进行数据传输。

  1. **使用OpenSSL****生成自签名证书**:可以参考:[https://blog.csdn.net/fengbingchun/article/details/107386847][https_blog.csdn.net_fengbingchun_article_details_107386847]
  2. 1. 生成自签名服务器端证书:

(1). 产生长度为3072的rsa私钥server.key;

(2). 创建服务器端证书签名请求(Certificate Signing Request)文件server.csr: CN填写本地测试机的IP,或域名,这里填写的IP或域名需要与代码中保持一致,填写域名可能需要修改本地/etc/hosts文件;

(3). 创建服务器端证书server.crt;

执行命令如下:

  1. LD_LIBRARY_PATH=../lib ./openssl genrsa -out server.key 3072
  2. LD_LIBRARY_PATH=../lib ./openssl req -new -out server.csr -key server.key -subj "/C=cn/ST=beijing/L=haidian/O=FBC/OU=test/CN=10.4.96.33/emailAddress=fengbingchun@163.com"
  3. LD_LIBRARY_PATH=../lib ./openssl x509 -req -in server.csr -out server.crt -signkey server.key -days 3650
  1. 生成自签名客户端证书:

(1). 产生长度为3072的rsa私钥client.key;

(2). 创建客户端端证书签名请求client.csr;

(3). 创建客户端证书client.crt;

执行命令如下:

  1. LD_LIBRARY_PATH=../lib ./openssl genrsa -out client.key 3072
  2. LD_LIBRARY_PATH=../lib ./openssl req -new -out client.csr -key client.key -subj "/C=cn/ST=beijing/L=haidian/O=Spring/OU=server_test/CN=XXXX/emailAddress=Spring@client_test.com"
  3. LD_LIBRARY_PATH=../lib ./openssl x509 -req -in client.csr -out client.crt -signkey client.key -days 3650

通过bearssl**的工具brssl将相关证书文件生成bearssl支持的C**代码

(1). 将服务端证书server.crt生成trust anchors,将其存放在trust_anchors.inc文件中;

(2). 将服务器端证书server.crt生成server chain,将其存放在chain.inc文件中;

(3). 将服务器端私钥server.key生成server rsa,将其存放在key.inc文件中;

(4). 将客户端证书client.crt生成trust anchors,将其存放在trust_anchors.inc文件中;

(5). 将客户端证书client.crt生成client chain,将其存放在chain.inc文件中;

(6). 将客户端私钥client.key生成client rsa,将其存放在key.inc文件中;

执行命令如下:

  1. ./brssl ta server.crt
  2. ./brssl chain server.crt
  3. ./brssl skey -C server.key
  4. ./brssl ta client.crt
  5. ./brssl chain client.crt
  6. ./brssl skey -C client.key

测试代码段如下:

  1. namespace {
  2. // reference: bearssl/samples: client_basic.c/server_basic.c
  3. // 客户端连接服务器:host为服务器端ipv4或域名,port为端口号
  4. SOCKET client_connect(const char *host, const char *port)
  5. {
  6. struct addrinfo hints, *si;
  7. memset(&hints, 0, sizeof hints);
  8. hints.ai_family = AF_INET;
  9. hints.ai_socktype = SOCK_STREAM;
  10. // getaddrinfo: 获取主机信息,既支持ipv4也支持ipv6
  11. auto err = getaddrinfo(host, port, &hints, &si);
  12. if (err != 0) {
  13. fprintf(stderr, "fail to getaddrinfo: %s\n", gai_strerror(err));
  14. return INVALID_SOCKET;
  15. }
  16. SOCKET fd = INVALID_SOCKET;
  17. struct addrinfo* p = nullptr;
  18. for (p = si; p != nullptr; p = p->ai_next) {
  19. struct sockaddr* sa = (struct sockaddr *)p->ai_addr;
  20. if (sa->sa_family != AF_INET) // 仅处理AF_INET
  21. continue;
  22. struct in_addr addr;
  23. addr.s_addr = ((struct sockaddr_in *)(p->ai_addr))->sin_addr.s_addr;
  24. // inet_ntoa: 将二进制类型的IP地址转换为字符串类型
  25. fprintf(stdout, "server ip: %s, family: %d, socktype: %d, protocol: %d\n",
  26. inet_ntoa(addr), p->ai_family, p->ai_socktype, p->ai_protocol);
  27. // 创建流式套接字
  28. fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
  29. if (fd < 0 || fd == INVALID_SOCKET) {
  30. auto err_code = get_error_code();
  31. std::error_code ec(err_code, std::system_category());
  32. fprintf(stderr, "fail to socket: %d, error code: %d, message: %s\n", fd, err_code, ec.message().c_str());
  33. continue;
  34. }
  35. // 连接,connect函数的第二参数是一个指向数据结构sockaddr的指针,其中包括客户端需要连接的服务器的目的端口和IP地址,以及协议类型
  36. #ifdef __linux__
  37. auto ret = connect(fd, p->ai_addr, p->ai_addrlen); // 在windows上直接调用此语句会返回-1,还未查到原因?
  38. #else
  39. struct sockaddr_in server_addr;
  40. memset(&server_addr, 0, sizeof(server_addr));
  41. server_addr.sin_family = AF_INET;
  42. server_addr.sin_port = htons(server_port_);
  43. auto ret = inet_pton(AF_INET, server_ip_, &server_addr.sin_addr);
  44. if (ret != 1) {
  45. fprintf(stderr, "fail to inet_pton: %d\n", ret);
  46. return -1;
  47. }
  48. ret = connect(fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
  49. #endif
  50. if ( ret < 0) {
  51. auto err_code = get_error_code();
  52. std::error_code ec(err_code, std::system_category());
  53. fprintf(stderr, "fail to connect: %d, error code: %d, message: %s\n", ret, err_code, ec.message().c_str());
  54. close(fd);
  55. continue;
  56. }
  57. break;
  58. }
  59. if (p == nullptr) {
  60. freeaddrinfo(si);
  61. fprintf(stderr, "fail to socket or connect\n");
  62. return INVALID_SOCKET;
  63. }
  64. freeaddrinfo(si);
  65. return fd;
  66. }
  67. // 接收数据
  68. int sock_read(void *ctx, unsigned char *buf, size_t len)
  69. {
  70. for (;;) {
  71. #ifdef _MSC_VER
  72. auto rlen = recv(*(int*)ctx, (char*)buf, len, 0);
  73. #else
  74. auto rlen = recv(*(int*)ctx, (char*)buf, len, 0);
  75. #endif
  76. //fprintf(stderr, "recv length: %d\n", rlen);
  77. if (rlen <= 0) {
  78. if (rlen < 0 && errno == EINTR) {
  79. continue;
  80. }
  81. auto err_code = get_error_code();
  82. std::error_code ec(err_code, std::system_category());
  83. fprintf(stderr, "fail to recv: %d, err code: %d, message: %s\n", rlen, err_code, ec.message().c_str());
  84. return -1;
  85. }
  86. return (int)rlen;
  87. }
  88. }
  89. // 发送数据
  90. int sock_write(void *ctx, const unsigned char *buf, size_t len)
  91. {
  92. for (;;) {
  93. #ifdef _MSC_VER
  94. auto wlen = send(*(int *)ctx, (const char*)buf, len, 0);
  95. #else
  96. // MSG_NOSIGNAL: 禁止send函数向系统发送异常消息
  97. auto wlen = send(*(int *)ctx, buf, len, MSG_NOSIGNAL);
  98. #endif
  99. //fprintf(stderr, "send length: %d\n", wlen);
  100. if (wlen <= 0) {
  101. if (wlen < 0 && errno == EINTR) {
  102. continue;
  103. }
  104. auto err_code = get_error_code();
  105. std::error_code ec(err_code, std::system_category());
  106. fprintf(stderr, "fail to send: %d, err code: %d, message: %s\n", wlen, err_code, ec.message().c_str());
  107. return -1;
  108. }
  109. return (int)wlen;
  110. }
  111. }
  112. // 服务器端绑定、监听
  113. SOCKET server_bind_listen(const char *host, const char *port)
  114. {
  115. struct addrinfo hints, *si;
  116. memset(&hints, 0, sizeof hints);
  117. hints.ai_family = AF_INET;
  118. hints.ai_socktype = SOCK_STREAM;
  119. auto ret = getaddrinfo(host, port, &hints, &si);
  120. if (ret != 0) {
  121. fprintf(stderr, "fail to getaddrinfo: %s\n", gai_strerror(ret));
  122. return INVALID_SOCKET;
  123. }
  124. SOCKET fd = INVALID_SOCKET;
  125. struct addrinfo* p = nullptr;
  126. for (p = si; p != nullptr; p = p->ai_next) {
  127. struct sockaddr *sa = (struct sockaddr *)p->ai_addr;
  128. if (sa->sa_family != AF_INET) // 仅处理AF_INET
  129. continue;
  130. struct in_addr addr;
  131. addr.s_addr = ((struct sockaddr_in *)(p->ai_addr))->sin_addr.s_addr;
  132. // inet_ntoa: 将二进制类型的IP地址转换为字符串类型
  133. fprintf(stdout, "server ip: %s, family: %d, socktype: %d, protocol: %d\n",
  134. inet_ntoa(addr), p->ai_family, p->ai_socktype, p->ai_protocol);
  135. // 创建流式套接字
  136. fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
  137. if (fd < 0 || fd == INVALID_SOCKET) {
  138. auto err_code = get_error_code();
  139. std::error_code ec(err_code, std::system_category());
  140. fprintf(stderr, "fail to socket: %d, error code: %d, message: %s\n", fd, err_code, ec.message().c_str());
  141. continue;
  142. }
  143. int opt = 1;
  144. #ifdef _MSC_VER
  145. ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof opt);
  146. #else
  147. ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt);
  148. #endif
  149. if (ret < 0) {
  150. fprintf(stderr, "fail to setsockopt: send\n");
  151. return INVALID_SOCKET;
  152. }
  153. // 绑定地址端口
  154. ret = bind(fd, sa, sizeof(*sa));
  155. if (ret < 0) {
  156. auto err_code = get_error_code();
  157. std::error_code ec(err_code, std::system_category());
  158. fprintf(stderr, "fail to bind: %d, error code: %d, message: %s\n", ret, err_code, ec.message().c_str());
  159. close(fd);
  160. continue;
  161. }
  162. break;
  163. }
  164. if (p == nullptr) {
  165. freeaddrinfo(si);
  166. fprintf(stderr, "fail to socket or bind\n");
  167. return INVALID_SOCKET;
  168. }
  169. freeaddrinfo(si);
  170. ret = listen(fd, server_listen_queue_length_);
  171. if (ret < 0) {
  172. auto err_code = get_error_code();
  173. std::error_code ec(err_code, std::system_category());
  174. fprintf(stderr, "fail to listen: %d, error code: %d, message: %s\n", ret, err_code, ec.message().c_str());
  175. close(fd);
  176. return INVALID_SOCKET;
  177. }
  178. return fd;
  179. }
  180. // 服务器端接收客户端的连接
  181. SOCKET server_accept(SOCKET server_fd)
  182. {
  183. struct sockaddr_in sa;
  184. socklen_t sa_len = sizeof sa;
  185. auto fd = accept(server_fd, (struct sockaddr*)&sa, &sa_len);
  186. if (fd < 0) {
  187. auto err_code = get_error_code();
  188. std::error_code ec(err_code, std::system_category());
  189. fprintf(stderr, "fail to accept: %d, error code: %d, message: %s\n", fd, err_code, ec.message().c_str());
  190. return -1;
  191. }
  192. if (sa.sin_family != AF_INET) {
  193. fprintf(stderr, "fail: sa_family should be equal AF_INET: %d\n", sa.sin_family);
  194. return -1;
  195. }
  196. struct in_addr addr;
  197. addr.s_addr = sa.sin_addr.s_addr;
  198. // inet_ntoa: 将二进制类型的IP地址转换为字符串类型
  199. fprintf(stdout, "client ip: %s\n", inet_ntoa(addr));
  200. return fd;
  201. }
  202. // Check whether we closed properly or not
  203. void check_ssl_error(const br_ssl_client_context& sc)
  204. {
  205. if (br_ssl_engine_current_state(&sc.eng) == BR_SSL_CLOSED) {
  206. auto ret = br_ssl_engine_last_error(&sc.eng);
  207. if (ret == 0) {
  208. fprintf(stdout, "closed properly\n");
  209. } else {
  210. fprintf(stderr, "SSL error %d\n", ret);
  211. }
  212. } else {
  213. fprintf(stderr, "socket closed without proper SSL termination\n");
  214. }
  215. }
  216. void check_ssl_error(const br_ssl_server_context& ss)
  217. {
  218. if (br_ssl_engine_current_state(&ss.eng) == BR_SSL_CLOSED) {
  219. auto ret = br_ssl_engine_last_error(&ss.eng);
  220. if (ret == 0) {
  221. fprintf(stdout, "closed properly\n");
  222. } else {
  223. fprintf(stderr, "SSL error %d\n", ret);
  224. }
  225. } else {
  226. fprintf(stderr, "socket closed without proper SSL termination\n");
  227. }
  228. }
  229. // reference: bearssl/samples/custom_profile.c
  230. void set_ssl_engine_suites(br_ssl_client_context sc)
  231. {
  232. static const uint16_t suites[] = {
  233. BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
  234. BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
  235. BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
  236. BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
  237. BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
  238. BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
  239. BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
  240. BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
  241. BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
  242. BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
  243. BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
  244. BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
  245. BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
  246. BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
  247. BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
  248. BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
  249. BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
  250. BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,
  251. BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
  252. BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
  253. BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
  254. BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
  255. BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
  256. BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
  257. BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
  258. BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
  259. BR_TLS_RSA_WITH_AES_128_GCM_SHA256,
  260. BR_TLS_RSA_WITH_AES_256_GCM_SHA384,
  261. BR_TLS_RSA_WITH_AES_128_CBC_SHA256,
  262. BR_TLS_RSA_WITH_AES_256_CBC_SHA256,
  263. BR_TLS_RSA_WITH_AES_128_CBC_SHA,
  264. BR_TLS_RSA_WITH_AES_256_CBC_SHA,
  265. BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
  266. BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
  267. BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
  268. BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
  269. BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA
  270. };
  271. br_ssl_engine_set_suites(&sc.eng, suites, (sizeof suites) / (sizeof suites[0]));
  272. }
  273. } // namespace
  274. int test_bearssl_self_signed_certificate_client()
  275. {
  276. #ifdef _MSC_VER
  277. init_server_trust_anchors();
  278. #endif
  279. const char* host = server_ip_;
  280. const char* port = std::to_string(server_port_).c_str();
  281. // Open the socket to the target server
  282. SOCKET fd = client_connect(host, port);
  283. if (fd < 0 || fd == INVALID_SOCKET) {
  284. fprintf(stderr, "fail to client connect: %d\n", fd);
  285. return -1;
  286. }
  287. // Initialise the client context
  288. br_ssl_client_context sc;
  289. br_x509_minimal_context xc;
  290. br_ssl_client_init_full(&sc, &xc, SERVER_TAs, SERVER_TAs_NUM);
  291. set_ssl_engine_suites(sc);
  292. // 以下单条语句用于双向认证中
  293. br_ssl_client_set_single_rsa(&sc, CLIENT_CHAIN, CLIENT_CHAIN_LEN, &CLIENT_RSA, br_rsa_pkcs1_sign_get_default());
  294. // Set the I/O buffer to the provided array
  295. unsigned char iobuf[BR_SSL_BUFSIZE_BIDI];
  296. br_ssl_engine_set_buffer(&sc.eng, iobuf, sizeof iobuf, 1);
  297. // Reset the client context, for a new handshake
  298. // 若设置br_ssl_client_reset函数的第二个参数为nullptr,则客户端无需验证服务器端的ip或域名,
  299. // 若第二个参数不为nullptr,则这里的host与使用命令生成server.csr时的CN要保持一致
  300. auto ret = br_ssl_client_reset(&sc, host/*nullptr*/, 0);
  301. if ( ret == 0) {
  302. check_ssl_error(sc);
  303. fprintf(stderr, "fail to br_ssl_client_reset: %d\n", ret);
  304. return -1;
  305. }
  306. // Initialise the simplified I/O wrapper context
  307. br_sslio_context ioc;
  308. br_sslio_init(&ioc, &sc.eng, sock_read, &fd, sock_write, &fd);
  309. // Write application data unto a SSL connection
  310. const char* source_buffer = "https://blog.csdn.net/fengbingchun";
  311. auto length = strlen(source_buffer) + 1; // 以空字符作为发送结束的标志
  312. ret = br_sslio_write_all(&ioc, source_buffer, length);
  313. if (ret < 0) {
  314. check_ssl_error(sc);
  315. fprintf(stderr, "fail to br_sslio_write_all: %d\n", ret);
  316. return -1;
  317. }
  318. // SSL is a buffered protocol: we make sure that all our request bytes are sent onto the wire
  319. ret = br_sslio_flush(&ioc);
  320. if (ret < 0) {
  321. check_ssl_error(sc);
  322. fprintf(stderr, "fail to br_sslio_flush: %d\n", ret);
  323. return -1;
  324. }
  325. // Read the server's response
  326. std::vector<char> vec;
  327. for (;;) {
  328. unsigned char tmp[512];
  329. ret = br_sslio_read(&ioc, tmp, sizeof tmp);
  330. if (ret < 0) {
  331. check_ssl_error(sc);
  332. fprintf(stderr, "fail to br_sslio_read: %d\n", ret);
  333. return -1;
  334. }
  335. bool flag = false;
  336. std::for_each(tmp, tmp + ret, [&flag, &vec](const char& c) {
  337. if (c == '\0') flag = true; // 以空字符作为接收结束的标志
  338. else vec.emplace_back(c);
  339. });
  340. if (flag == true) break;
  341. }
  342. fprintf(stdout, "server's response: ");
  343. std::for_each(vec.data(), vec.data() + vec.size(), [](const char& c){
  344. fprintf(stdout, "%c", c);
  345. });
  346. fprintf(stdout, "\n");
  347. // Close the SSL connection
  348. if (fd >= 0) {
  349. ret = br_sslio_close(&ioc);
  350. if (ret < 0) {
  351. check_ssl_error(sc);
  352. fprintf(stderr, "fail to br_sslio_close: %d\n", ret);
  353. return -1;
  354. }
  355. }
  356. // Close the socket
  357. close(fd);
  358. return 0;
  359. }
  360. int test_bearssl_self_signed_certificate_server()
  361. {
  362. #ifdef _MSC_VER
  363. init_client_trust_anchors();
  364. #endif
  365. // Open the server socket
  366. SOCKET fd = server_bind_listen(server_ip_, std::to_string(server_port_).c_str());
  367. if (fd < 0 || fd == INVALID_SOCKET) {
  368. fprintf(stderr, "fail to server_bind_listen: %d\n", fd);
  369. return -1;
  370. }
  371. // Process each client, one at a time
  372. for (;;) {
  373. SOCKET fd2 = server_accept(fd);
  374. if (fd2 < 0 || fd2 == INVALID_SOCKET) {
  375. fprintf(stderr, "fail to server_accept: %d\n", fd2);
  376. return -1;
  377. }
  378. // Initialise the context with the cipher suites and algorithms
  379. // SSL server profile: full_rsa
  380. br_ssl_server_context sc;
  381. br_ssl_server_init_full_rsa(&sc, SERVER_CHAIN, SERVER_CHAIN_LEN, &SERVER_RSA);
  382. // 以下8条语句用于双向认证中
  383. br_x509_minimal_context xc;
  384. br_x509_minimal_init(&xc, &br_sha1_vtable, CLIENT_TAs, CLIENT_TAs_NUM);
  385. br_ssl_engine_set_default_rsavrfy(&sc.eng);
  386. br_ssl_engine_set_default_ecdsa(&sc.eng);
  387. br_x509_minimal_set_rsa(&xc, br_rsa_pkcs1_vrfy_get_default());
  388. br_x509_minimal_set_ecdsa(&xc, br_ec_get_default(), br_ecdsa_vrfy_asn1_get_default());
  389. br_ssl_engine_set_x509(&sc.eng, &xc.vtable);
  390. br_ssl_server_set_trust_anchor_names_alt(&sc, CLIENT_TAs, CLIENT_TAs_NUM);
  391. // Set the I/O buffer to the provided array
  392. unsigned char iobuf[BR_SSL_BUFSIZE_BIDI];
  393. br_ssl_engine_set_buffer(&sc.eng, iobuf, sizeof iobuf, 1);
  394. // Reset the server context, for a new handshake
  395. auto ret = br_ssl_server_reset(&sc);
  396. if (ret == 0) {
  397. check_ssl_error(sc);
  398. fprintf(stderr, "fail to br_ssl_server_reset: %d\n", ret);
  399. return -1;
  400. }
  401. // Initialise the simplified I/O wrapper context
  402. br_sslio_context ioc;
  403. br_sslio_init(&ioc, &sc.eng, sock_read, &fd2, sock_write, &fd2);
  404. std::vector<char> vec;
  405. for (;;) {
  406. unsigned char tmp[512];
  407. ret = br_sslio_read(&ioc, tmp, sizeof tmp);
  408. if (ret < 0) {
  409. check_ssl_error(sc);
  410. fprintf(stderr, "fail to br_sslio_read: %d\n", ret);
  411. return -1;
  412. }
  413. bool flag = false;
  414. std::for_each(tmp, tmp + ret, [&flag, &vec](const char& c) {
  415. if (c == '\0') flag = true; // 以空字符作为接收结束的标志
  416. else vec.emplace_back(c);
  417. });
  418. if (flag == true) break;
  419. }
  420. fprintf(stdout, "message from the client: ");
  421. std::for_each(vec.data(), vec.data() + vec.size(), [](const char& c){
  422. fprintf(stdout, "%c", c);
  423. });
  424. fprintf(stdout, "\n");
  425. // Write a response and close the connection
  426. auto str = std::to_string(vec.size());
  427. std::vector<char> vec2(str.size() + 1);
  428. memcpy(vec2.data(), str.data(), str.size());
  429. vec2[str.size()] = '\0'; // 以空字符作为发送结束的标志
  430. ret = br_sslio_write_all(&ioc, vec2.data(), vec2.size());
  431. if (ret < 0) {
  432. check_ssl_error(sc);
  433. fprintf(stderr, "fail to br_sslio_write_all: %d\n", ret);
  434. return -1;
  435. }
  436. ret = br_sslio_close(&ioc);
  437. if (ret < 0) {
  438. check_ssl_error(sc);
  439. fprintf(stderr, "fail to br_sslio_close: %d\n", ret);
  440. return -1;
  441. }
  442. close(fd2);
  443. }
  444. return 0;
  445. }

执行结果如下:服务器端为linux,客户端为windows,客户端发送”https://blog.csdn.net/fengbingchun“,并以空格作为结束标志,服务器端接收后计算字符串的长度,然后将长度返回给客户端,客户端将从服务器端收到的信息print。以上代码中注释掉br_ssl_client_set_single_rsa和br_ssl_server_set_trust_anchor_names_alt等函数即可实现单向认证。

20200915101351677.png

以上测试的完整代码见:GitHub OpenSSL_Test/funset_bearssl.cpp

GitHub:https://github.com/fengbingchun/OpenSSL_Test

发表评论

表情:
评论列表 (有 0 条评论,146人围观)

还没有评论,来说两句吧...

相关阅读