我在 C 中找到了一个非常好的SSL/TLS 服务器-客户端示例,我想对其进行调整以与 BIO 库一起使用。我几乎成功了,除了运行服务器时出现的一个错误:
$ ./ssl-server
68671:error:140950D3:SSL routines:SSL3_READ_N:read bio not set:/SourceCache/OpenSSL098/OpenSSL098-35.1/src/ssl/s3_pkt.c:203:
我gcc -o ssl-server SSL-Server.c -lssl -lcrypto -Wall
用来编译服务器:
//SSL-Server.c
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <resolv.h>
#include "openssl/ssl.h"
#include "openssl/err.h"
#define FAIL -1
#define PORT "2013"
SSL_CTX* InitServerCTX(void)
{
SSL_METHOD *method;
SSL_CTX *ctx;
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
method = SSLv3_server_method();
ctx = SSL_CTX_new(method);
if( ctx == NULL )
{
ERR_print_errors_fp(stderr);
abort();
}
return ctx;
}
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
if( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
if( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 )
{
ERR_print_errors_fp(stderr);
abort();
}
if( !SSL_CTX_check_private_key(ctx) )
{
fprintf(stderr, "Private key does not match the public certificate\n");
abort();
}
}
void ShowCerts(SSL* ssl)
{
X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl);
if ( cert != NULL )
{
printf("Server certificates:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("Subject: %s\n", line);
free(line);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line);
free(line);
X509_free(cert);
}
else
{
printf("No certificates.\n");
}
}
void Servlet(SSL* ssl)
{
char buf[1024];
int sd, bytes;
if( SSL_accept(ssl) == FAIL )
{
ERR_print_errors_fp(stderr);
}
else
{
ShowCerts(ssl);
bytes = SSL_read(ssl, buf, sizeof(buf));
if( bytes > 0 )
{
buf[bytes] = 0;
printf("Client msg: \"%s\"\n", buf);
SSL_write(ssl, "back message", strlen("back message"));
}
else
{
ERR_print_errors_fp(stderr);
}
}
sd = SSL_get_fd(ssl);
SSL_free(ssl);
close(sd);
}
int main(int count, char *strings[])
{
SSL_CTX *ctx;
BIO *acc, *client;
SSL_library_init();
ctx = InitServerCTX();
LoadCertificates(ctx, "mycert.pem", "mycert.pem");
acc = BIO_new_accept(PORT);
if(!acc)
{
printf("Error creating server socket");
}
while(1)
{
if(BIO_do_accept(acc) <= 0)
{
printf("Error binding server socket");
}
SSL *ssl;
client = BIO_pop(acc);
if(!(ssl = SSL_new(ctx)))
{
printf("Error creating SSL context");
}
SSL_set_bio(ssl, client, client);
// Here should be created threads
Servlet(ssl);
}
SSL_CTX_free(ctx);
}
我gcc -o ssl-client SSL-Client.c -lssl -lcrypto -Wall
用来编译客户端:
//SSL-Client.c
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <resolv.h>
#include <netdb.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/bio.h>
#define FAIL -1
#define SERVER "localhost"
#define PORT "2013"
SSL_CTX* InitCTX(void)
{
SSL_METHOD *method;
SSL_CTX *ctx;
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
method = SSLv3_client_method();
ctx = SSL_CTX_new(method);
if( ctx == NULL )
{
ERR_print_errors_fp(stderr);
abort();
}
return ctx;
}
void ShowCerts(SSL* ssl)
{
X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl);
if( cert != NULL )
{
printf("Server certificates:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("Subject: %s\n", line);
free(line);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line);
free(line);
X509_free(cert);
}
else
{
printf("No certificates.\n");
}
}
int main(int count, char *strings[])
{
SSL_CTX *ctx;
SSL *ssl;
BIO *conn;
char buf[1024];
int bytes;
SSL_library_init();
ctx = InitCTX();
conn = BIO_new_connect(SERVER ":" PORT);
if(!conn)
{
printf("Error creating connection BIO");
}
if(BIO_do_connect(conn) <= 0)
{
printf("Error connecting to remote machine");
}
ssl = SSL_new(ctx);
SSL_set_bio(ssl, conn, conn);
if( SSL_connect(ssl) <= 0 )
{
printf("Error connecting SSL object");
}
else
{
printf("Connected!");
ShowCerts(ssl);
SSL_write(ssl, "ana are mere", strlen("ana are mere") );
bytes = SSL_read(ssl, buf, sizeof(buf));
printf("%s\n", buf);
SSL_free(ssl);
}
SSL_CTX_free(ctx);
return 0;
}
我正在使用openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout mycert.pem -out mycert.pem
命令生成证书。
一切正常,消息发送正常。请忽略缺少错误检查并原谅代码中的全部混乱,这只是为了学习目的。
谁能指出我出了什么问题?你能告诉我是否犯了重大错误,我正在努力学习吗?(例如例行呼叫顺序、重大安全问题等)
谢谢!