openssl进行加密通信服务器端代码

来源:互联网 发布:新潮都网络批发城 编辑:程序博客网 时间:2024/06/06 14:27

直接上代码,代码中有详细的注释:

#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <netinet/in.h>#include <sys/socket.h>#include <unistd.h>#include <sys/time.h>#include <arpa/inet.h>//openssl头文件#include <openssl/ssl.h>#include <openssl/err.h>int main(int argc, char *argv[]){int listen_fd=-1;              /* TCP监听套接字 */int accept_fd=-1;              /* 已连接TCP套接字 */struct sockaddr_in server_addr;bzero(&server_addr, sizeof(server_addr));SSL_CTX *ctx=NULL;             /* SSL会话环境 */SSL *ssl=NULL;                 /* SSL安全套接字 */char buf[50]={0};              /* 服务器接收数据buffer */if( 3!=argc ){printf("argcment wrong:ip port\n");}do{//使用SSL_CTX_new()创建会话环境,建立连接时要使用协议由TLS_server_method()来定。如果这一步出错,需要查看错误栈来查看原因if( NULL==(ctx=SSL_CTX_new(TLS_server_method())) )   {ERR_print_errors_fp(stdout);break;}//服务器需要进行用户证书和私匙加载,必须验证两者的一致性;客户端不需要这3步if( 0>=SSL_CTX_use_certificate_file(ctx, "./cacert.pem", SSL_FILETYPE_PEM/*SSL_FILETYPE_ASN1*/) ) /* 为SSL会话加载用户证书 */{ERR_print_errors_fp(stdout);break;}if( 0>=SSL_CTX_use_PrivateKey_file(ctx, "./privkey.pem", SSL_FILETYPE_PEM/*SSL_FILETYPE_ASN1*/) ) /* 为SSL会话加载用户私钥 */{ERR_print_errors_fp(stdout);break;}if(!SSL_CTX_check_private_key(ctx))                                  /* 验证私钥和证书是否相符 */{ERR_print_errors_fp(stdout);break;}//TCP服务器:创建、绑定、监听if( -1==(listen_fd=socket(PF_INET, SOCK_STREAM, 0)) ){printf("socket wrong\n");break;} server_addr.sin_family = PF_INET;server_addr.sin_port = htons(atoi(argv[2]));server_addr.sin_addr.s_addr = inet_addr(argv[1]);if( -1==(bind(listen_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))) ) {printf("bind wrong\n");break;}if( -1==(listen(listen_fd, 2)) ){printf("listen wrong\n");break;}//服务器和客户端建立连接if( -1==(accept_fd=accept(listen_fd, NULL, NULL)) )    //tcp层连接{printf("accept wrong\n");break;}else //ssl层连接{ssl=SSL_new(ctx);            /* 由会话环境申请一个SSL层套接字 */SSL_set_fd(ssl, accept_fd);  /* 绑定SSL层套接字和TCP层套接字 */if( -1==SSL_accept(ssl) )    /* SSL层握手 */ {printf("SSL_accept wrong\n");SSL_shutdown(ssl);   SSL_free(ssl);ssl=NULL;close(accept_fd);accept_fd=-1;break;}}}while(0);//在SSL层接收数据SSL_read(ssl, buf, 50);printf("%s\n", buf);/* 关闭SSL连接,释放SSL安全套接字资源 */if( NULL!=ssl ){SSL_shutdown(ssl);  //关闭一个活的TLS/SSL连接,会向对端发送"close notify",告诉对方SSL_free(ssl);      //减少ssl的引用次数,如果引用次数为零,就移除ssl指向的对象、释放分配的内存;如果ssl是NULL,什么都不做ssl=NULL;}/* 关闭TCP连接 */if( -1!=accept_fd){close(accept_fd);      accept_fd=-1;}/* 释放SSL会话环境 */if( NULL!=ctx ){SSL_CTX_free(ctx);//减少ctx的引用次数,如果引用次数为零,就移除ctx指向的对象、释放分配的内存;如果ctx是NULL,什么都不做ctx=NULL;}return 0;}
关于openssl的初始化工作:使用OPENSSL_init_ssl()和OPENSSL_init_crypto(),openssl,不使用也会自动默认初始化,所以不用显式调用这两个函数;除非默认初始化不满足我们的要求,才会显式调用这两个函数。

另外一个在创建ssl层连接时,需要在服务器端加载用户证书和用户私匙,后续会介绍如何使用openssl提供的工具来生成这2个东西。