本文的核心是讲怎么把项目中的openssl库替换成wolfssl库,并且尽可能的少改工程代码。
首先需要去官网下载安装包:wolfssl下载
或者去github上下载:wolfssl下载
学习资料和论坛都在官网上可以找到,这是wolfssl的使用手册
在PC linux系统编译:
./configure后面可以跟很多选项,比如指明编译链、安装路径、静态库或者动态库等。具体说明可以执行 ./configure –help
官方关于configure的说明参考:configure –help 说明链接
交叉编译链编译:
需要用–host选项来指明交叉编译链。
./configure --prefix=$PWD/output --host=arm-linux --enable-openssh --enable-static --disable-shared
需要注意的是交叉编译链路径需要加入到PATH环境变量中,不然也是找不到的。
执行configure的目的是为了生成Makefile。需要确保在当前路径有output目录,这是通过–prefix决定的,不指定将默认安装在/usr/local目录下。生成的libwolfssl.a 静态库放到工程代码中,然后修改相关Makefile将库包含进来。并且在源码中需要包含头文件
出现如下错误信息,找不到库:
./echoserver: error while loading shared libraries: libwolfssl.so.16: cannot open shared object file: No such file or directory
有以下几种解决方法:
sudo ln -s /usr/local/lib/libwolfssl.so.16.0.0 /usr/lib/libwolfssl.so.16
gcc编译时库的依赖顺序经常出现问题:
静态库经常会出现依赖顺序问题,动态库则不会。
当A库依赖于B库时(A库引用B库的函数时,应该写在前面)则在编译的时候链接顺序应该是 -lA -lB 。
虽然提供了兼容层,但是wolfssl的机制和openssl的机制还是有些不同。尝试移植wolfssl库到嵌入式板子。移植后,写的demo程序在板子上可以运行,嵌入到工程中也没有问题。但是,移植到“发送邮件“ 那部分代码,ssl_connect函数连接远程服务器不成功。发现wolfssl和openssl在证书验证机制上是有区别的。wolfssl 客户端默认需要加载证书,而openssl则不用。这意味着如果没有加载CA来验证服务器,则会出现连接错误。官网说可以调用SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0) 来模拟openssl的行为,但这将降低安全性。经过反复试验,还是连接不上。 可能客户端还是需要加载证书。看了一些wolfssl例子,客户端都是需要加载数字证书的。如果是这样的情形,那对应每种类型的邮箱所要加载的证书也不一样(如qq和163),用户绑定的邮箱种类也不可能全部一样,处理起来将会变得很麻烦。 由于目前移植存在风险,所以还是用原来的openssl库。 这是目前遗留的问题,后续再看看。
用简单的例子来模拟,可用抓包软件研究一下。
OPEN_SSL宏来控制是否要加入wolfssl机制。客户端和服务器都是不需要加载证书的,因为客户端使用了SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0) 函数。
//server_echo.c
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <netinet/in.h>
#include <signal.h> //信号
#include <wolfssl/openssl/ssl.h> //wolfssl转openssl的兼容层
#define SERV_PORT 9877
#define LISTENQ 1024
#define MAXLINE 4096
#define OPEN_SSL
static int cleanup; /* To handle shutdown */
void sig_handler(const int sig)
{
printf("\nSIGINT handled.\n");
cleanup = 1;
return;
}
#ifdef OPEN_SSL
void str_echo_ssl(WOLFSSL* ssl)
{
int n;
char buf[MAXLINE];
while ( (n = SSL_read(ssl, buf, MAXLINE)) > 0) {
if(SSL_write(ssl, buf, n) != n) {
printf("wolfSSL_write failed");
}
}
if( n < 0 )
printf("wolfSSL_read error = %d\n", wolfSSL_get_error(ssl,n));
else if( n == 0 )
printf("The peer has closed the connection.\n");
}
#else
void str_echo(int sockfd)
{
char buff[MAXLINE];
int length=0;
printf("server begin recv\n");
while(length=recv(sockfd,buff,MAXLINE,0)) //这里是分包接收,每次接收4096个字节
{
if(length<0)
{
perror("recv");
exit(-1);
}
printf("server send\n");
if (send(sockfd,buff,MAXLINE,0) < 0)
{
perror("Send");
exit(-1);
}
bzero(buff, sizeof(buff));
}
}
#endif
int main(int argc, char **argv)
{
int listenfd, connfd,fpid;
pid_t childpid;
socklen_t clilen;
struct sockaddr_in cliaddr, servaddr;
struct sigaction act, oact; /* structures for signal handling */
act.sa_handler = sig_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGINT, &act, &oact);
#ifdef OPEN_SSL
wolfSSL_Init(); /* Initialize wolfSSL */
WOLFSSL_CTX* ctx;
/* Create and initialize WOLFSSL_CTX structure */
if ( (ctx = wolfSSL_CTX_new(wolfTLSv1_2_server_method())) == NULL){
fprintf(stderr, "wolfSSL_CTX_new error.\n");
exit(EXIT_FAILURE);
}
/* Load CA certificates into WOLFSSL_CTX */
/*if (wolfSSL_CTX_load_verify_locations(ctx,"../certs/ca-cert.pem",0) !=
SSL_SUCCESS) {
fprintf(stderr, "Error loading ../certs/ca-cert.pem, "
"please check the file.\n");
exit(EXIT_FAILURE);
}*/
/* Load server certificate into WOLFSSL_CTX */
if (wolfSSL_CTX_use_certificate_file(ctx,"../certs/server-cert.pem",
SSL_FILETYPE_PEM) != SSL_SUCCESS) {
fprintf(stderr, "Error loading ../certs/server-cert.pem, "
"please check the file.\n");
exit(EXIT_FAILURE);
}
/* Load server key into WOLFSSL_CTX */
if (wolfSSL_CTX_use_PrivateKey_file(ctx,"../certs/server-key.pem",
SSL_FILETYPE_PEM) != SSL_SUCCESS) {
fprintf(stderr, "Error loading ../certs/server-key.pem, "
"please check the file.\n");
exit(EXIT_FAILURE);
}
#endif
//建立socket连接
if ((listenfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
{
perror("socket");
exit(1);
}
printf("create socket success!\n");
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
// 设置套接字选项避免地址使用错误,为了允许地址重用,我设置整型参数(on)为 1 (不然,可以设为 0 来禁止地址重用)
int on=1;
if((setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)))<0)
{
perror("setsockopt failed");
exit(-1);
}
if(bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)
{
perror("bind");
exit(-1);
}
printf("Bind success!\n");
if(listen(listenfd, LISTENQ) == -1)
{
perror("listen");
exit(-1);
}
while(cleanup != 1)
{
clilen = sizeof(cliaddr);
printf("begin accept!\n");
if ((connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen)) < 0)
{
perror("accept");
exit(-1);
}
//
#ifdef OPEN_SSL
WOLFSSL* ssl;
/* Create WOLFSSL Object */
if( (ssl = wolfSSL_new(ctx)) == NULL) {
printf("wolfSSL_new error.\n");
exit(-1);
}
wolfSSL_set_fd(ssl, connfd);
str_echo_ssl(ssl); /* process the request */
wolfSSL_free(ssl); /* Free WOLFSSL object */
#else
/
printf("begin fork!\n");
fpid=fork();
if (fpid < 0)
{
perror("fork");
exit(-1);
}
else if (fpid == 0) //child process
{
close(listenfd); // close listening socket
str_echo(connfd); // process the request
exit(0);
}
#endif
close(connfd); // parent closes connected socket
}
#ifdef OPEN_SSL
wolfSSL_CTX_free(ctx); /* Free WOLFSSL_CTX */
printf("wolfSSL_CTX freed\n");
wolfSSL_Cleanup(); /* Free wolfSSL */
printf("wolfSSL freed\n");
#endif
exit(1);
}
OPEN_SSL宏来控制是否要加入wolfssl机制。
//client_echo.c
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <netinet/in.h>
#include <wolfssl/openssl/ssl.h> //wolfssl转openssl的兼容层
#define MAXLINE 4096
#define SERV_PORT 9877
#define OPEN_SSL
#ifdef OPEN_SSL
void str_cli_ssl(FILE *fp, SSL* ssl)
{
char sendline[MAXLINE], recvline[MAXLINE];
int n = 0;
while (fgets(sendline, MAXLINE, fp) != NULL) {
if(SSL_write(ssl, sendline, strlen(sendline)) !=
strlen(sendline)){
printf("wolfSSL_write failed");
}
if ((n = SSL_read(ssl, recvline, MAXLINE)) <= 0)
printf("wolfSSL_read error");
recvline[n] = '\0';
fputs(recvline, stdout);
}
}
#else
void str_cli(FILE *fp, int sockfd)
{
char sendline[MAXLINE], recvline[MAXLINE];
while(fgets(sendline, MAXLINE, fp) != NULL)
{
printf("sendline : %s\n",sendline);
if (send(sockfd,sendline,strlen(sendline),0) < 0)
{
perror("Send");
exit(-1);
}
if (recv(sockfd,recvline,MAXLINE,0) < 0 )
{
perror("recv");
exit(-1);
}
printf("recvline : %s\n",recvline);
fputs(recvline, stdout);
}
}
#endif
int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
if (argc != 2)
{
perror("usage: tcpcli <IPaddress>");
exit(-1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
perror("sockfd");
exit(-1);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) < 0)
{
perror("inet_pton");
exit(-1);
}
if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)
{
perror("connect");
exit(-1);
}
/
#ifdef OPEN_SSL
SSL_CTX* ctx;
SSL_library_init();
SSL_load_error_strings();
ctx = SSL_CTX_new (SSLv23_client_method());
if((ctx) == NULL)
{
printf("Fun:%s\tSSL_CTX ERROR\n", __FUNCTION__);
return -1;
}
printf("tim add SSL_CTX_set_verify test############\n");
SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0);//fix SSL_connect fail
SSL *ssl;
if( (ssl = SSL_new(ctx)) == NULL) {
fprintf(stderr, "wolfSSL_new error.\n");
exit(EXIT_FAILURE);
}
SSL_set_fd(ssl, sockfd);
int ssl_ret;
int fgCycleFlag = 1;
while(fgCycleFlag )
{
ssl_ret = SSL_connect(ssl);
switch(SSL_get_error(ssl, ssl_ret))//这里出错
{
case SSL_ERROR_NONE:
printf("Fun:%s\tSSL_ERROR_NONE,ssl_ret = %d\n", __FUNCTION__,ssl_ret);
fgCycleFlag = 0;
usleep(100000);
break;
case SSL_ERROR_WANT_WRITE:
printf("Fun:%s\tSSL_ERROR_WANT_WRITE,ssl_ret = %d\n", __FUNCTION__,ssl_ret);
usleep(100000);
break;
case SSL_ERROR_WANT_READ:
printf("Fun:%s\tSSL_ERROR_WANT_READ,ssl_ret = %d\n", __FUNCTION__,ssl_ret);
usleep(100000);
break;
default:
printf("SSL_connect:%s\n", __FUNCTION__);
return -1;
}
}
str_cli_ssl(stdin, ssl); /* do it all */
//程序不会走这里,缺少回收资源的机制,实际运用中需要及时对资源进行释放!!
if(ssl != NULL)
{
printf("Fun:%s Close SSL\n", __FUNCTION__);
SSL_shutdown (ssl);
SSL_free (ssl); /* Free SSL object */
ssl = NULL;
}
if(ctx != NULL)
{
printf("Fun:%s Close SSL\n", __FUNCTION__);
SSL_CTX_free (ctx);
ctx = NULL;
}
#else
/
str_cli(stdin, sockfd);
#endif
exit(1);
}
gcc server_ssl_echo.c -o server_ssl_echo -lwolfssl
gcc client_ssl_echo.c -o client_ssl_echo -lwolfssl
ubuntu@ubuntu:~/csdn/echo/server_ssl$ ./server_ssl_echo
create socket success!
Bind success!
begin accept!
ubuntu@ubuntu:~/csdn/echo/client_ssl$ ./client_ssl_echo 127.0.0.1
tim add SSL_CTX_set_verify test############
Fun:main SSL_ERROR_NONE,ssl_ret = 1
456
456