利用OpenSSL建立SSL安全通信(C/S)

客户端服务端基于opensslssl/tls通信

可以进行tls双向认证,并且可以选定protocol,支持tlsv1.2 分别对应客户端和服务端,后续可以通过openssl engine引擎进行算法替换

服务端

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#include "openssl/crypto.h"
#include "openssl/ssl.h"
#include "openssl/err.h"
#include "openssl/rsa.h"      
#include "openssl/crypto.h"


#define CACERT "../cert/ca.crt"
#define SERVER_CRT "../cert/server.crt"
#define SERVER_KEY "../cert/server.key"
#define CHK_ERR(err,s) if ((err)==-1) { perror(s); exit(-2); }
#define SERVER_ADDR "172.16.39.197"
#define PORT 20001
#define SERVER_mode 1
#define CLIENT_mode 0
SSL_CTX* InitSSL(char *ca_path,char *client_crt_path,char *client_key_path,int mothflag)
{
    SSL_CTX* ctx=NULL;
    SSL_METHOD *meth;
    int status;
 
    /* * 算法初始化 * */   
    SSL_library_init();
    // 加载SSL错误信息
    SSL_load_error_strings();
 
    // 添加SSL的加密/HASH算法
    SSLeay_add_ssl_algorithms();
    
    /*采用什么协议(SSLv2/SSLv3/TLSv1)在此指定*/
    if(mothflag)
        meth = (SSL_METHOD *)TLSv1_2_server_method();
    else
        meth = (SSL_METHOD *)TLSv1_2_client_method();
    /* 创建SSL会话环境 */
    ctx = SSL_CTX_new (meth);                    
    if(ctx == NULL)
    {
        printf ("SSL_CTX_new error\n");
        return NULL;
    }
  
    // /*验证与否,是否要验证对方*/
   SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL);   
    // /*若验证对方,则放置CA证书*/
   SSL_CTX_load_verify_locations(ctx,ca_path,NULL); 

    /*加载自己的证书*/
    if (SSL_CTX_use_certificate_file(ctx, client_crt_path, SSL_FILETYPE_PEM) <= 0) 
    {
        printf("SSL_CTX_use_certificate_file error\n");
        goto exit;
    }
    /*加载自己的私钥,以用于签名*/
    if (SSL_CTX_use_PrivateKey_file(ctx, client_key_path, SSL_FILETYPE_PEM) <= 0) 
    {
        printf("SSL_CTX_use_PrivateKey_file error\n");
        goto exit;
    }

    // 设置证书私钥文件的密码
    //SSL_CTX_set_default_passwd_cb_userdata(ctx, pw);

    /*调用了以上两个函数后,检验一下自己的证书与私钥是否配对*/
    if (!SSL_CTX_check_private_key(ctx)) 
    {
        printf("SSL_CTX_check_private_key error\n");
        goto exit;
    } 
    return ctx;

exit:
    if(ctx) SSL_CTX_free (ctx);
    return NULL;
}

int main()
{
    int sd=0;
    int confd=0;
    SSL* ssl=NULL;
    SSL_CTX* ctx=NULL;
    struct sockaddr_in sa_serv={0};
    struct sockaddr_in sa_cli={0};
    ctx=InitSSL(CACERT,SERVER_CRT,SERVER_KEY,SERVER_mode);
    if(ctx==NULL) return -1;

    /* 指定加密器类型 */
    // SSL_CTX_set_cipher_list (ctx, "ECDHE-RSA-AES256-SHA");
    // SSL_CTX_set_mode (ctx, SSL_MODE_AUTO_RETRY);

    /*以下是正常的TCP socket建立过程 .............................. */
    printf("Begin tcp socket...\n");

    sd = socket (AF_INET, SOCK_STREAM, 0);  

    sa_serv.sin_family      = AF_INET;
    sa_serv.sin_addr.s_addr = inet_addr("172.16.39.197");
    sa_serv.sin_port        = htons (PORT);         
    
    int opt = 1;
    if(setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0)
    {
        fprintf(stderr,"[tskIpRev]: setsockopt(SO_REUSEADDR) error\n");
        return 0;
    }
    
    bind(sd, (struct sockaddr*) &sa_serv,sizeof (sa_serv));

    /*接受TCP链接*/
    listen (sd, 5);                   
 
    int client_len = sizeof(sa_cli);
    sd = accept (sd, (struct sockaddr*) &sa_cli, &client_len);

    /* TCP 链接已建立.开始 SSL 握手过程.......................... */
    printf("Begin SSL negotiation \n");

    /*申请一个SSL套接字*/
    ssl = SSL_new (ctx);                        
    if(ssl <= 0)
    {
        printf("Error creating SSL new \n");
        goto exit;
    }

    /*绑定读写套接字*/
    SSL_set_fd (ssl, sd);
    SSL_accept (ssl);               
    printf("链接已建立.开始 SSL 握手过程 \n");

    /*打印所有加密算法的信息(可选)*/
    printf ("SSL connection using %s\n", SSL_get_cipher (ssl));

    /*得到服务端的证书并打印些信息(可选) */
    X509* server_cert = SSL_get_peer_certificate (ssl);      
    printf ("Server certificate:\n");

    char *str = X509_NAME_oneline (X509_get_subject_name (server_cert),0,0);
    printf ("/t subject: %s\n", str);
    free (str);

    str = X509_NAME_oneline (X509_get_issuer_name  (server_cert),0,0);
    printf ("/t issuer: %s\n", str);
    free (str);

    X509_free (server_cert);  /*如不再需要,需将证书释放 */

    /* 数据交换开始,用SSL_write,SSL_read代替write,read */
    printf("Begin SSL data exchange\n");

    unsigned char buf[300]={0};
    while(1)
    {
        memset (buf,0,300);
        int ret = SSL_read (ssl, buf, sizeof(buf)); 
        if(ret <= 0 )
            break;
        printf ("Got %d chars:'%s'\n", ret, buf);
    }
    SSL_shutdown (ssl);  /* send SSL/TLS close_notify */
    /* 收尾工作 */
    shutdown (sd,2);

exit:
    if(sd > 0) close (sd);
    if(confd > 0) close (confd); 
    if(ctx) SSL_CTX_free(ctx);
    if(ssl) SSL_free (ssl);
    return 0;
}
客户端

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#include "openssl/crypto.h"
#include "openssl/ssl.h"
#include "openssl/err.h"
#include "openssl/rsa.h"      
#include "openssl/crypto.h"


#define CACERT "../cert/ca.crt"
#define CLIENT_CRT "../cert/client.crt"
#define CLIENT_KEY "../cert/client.key"
#define CHK_ERR(err,s) if ((err)==-1) { perror(s); exit(-2); }
#define SERVER_ADDR "172.16.39.197"
#define PORT 20001

#define SERVER_mode 1
#define CLIENT_mode 0

SSL_CTX* InitSSL(char *ca_path,char *client_crt_path,char *client_key_path,int mothflag)
{
    SSL_CTX* ctx=NULL;
    SSL_METHOD *meth;
    int status;
 
    /* * 算法初始化 * */   
    SSL_library_init();
    // 加载SSL错误信息
    SSL_load_error_strings();
 
    // 添加SSL的加密/HASH算法
    SSLeay_add_ssl_algorithms();
    
    /*采用什么协议(SSLv2/SSLv3/TLSv1)在此指定*/
    if(mothflag)
        meth = (SSL_METHOD *)TLSv1_2_server_method();
    else
        meth = (SSL_METHOD *)TLSv1_2_client_method();
    /* 创建SSL会话环境 */
    ctx = SSL_CTX_new (meth);                    
    if(ctx == NULL)
    {
        printf ("SSL_CTX_new error\n");
        return NULL;
    }
  
    // /*验证与否,是否要验证对方*/
   SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL);   
    // /*若验证对方,则放置CA证书*/
   SSL_CTX_load_verify_locations(ctx,ca_path,NULL); 

    /*加载自己的证书*/
    if (SSL_CTX_use_certificate_file(ctx, client_crt_path, SSL_FILETYPE_PEM) <= 0) 
    {
        printf("SSL_CTX_use_certificate_file error\n");
        goto exit;
    }
    /*加载自己的私钥,以用于签名*/
    if (SSL_CTX_use_PrivateKey_file(ctx, client_key_path, SSL_FILETYPE_PEM) <= 0) 
    {
        printf("SSL_CTX_use_PrivateKey_file error\n");
        goto exit;
    }

       // 设置证书私钥文件的密码
    //SSL_CTX_set_default_passwd_cb_userdata(ctx, pw);

    /*调用了以上两个函数后,检验一下自己的证书与私钥是否配对*/
    if (!SSL_CTX_check_private_key(ctx)) 
    {
        printf("SSL_CTX_check_private_key error\n");
        goto exit;
    } 
    return ctx;

exit:
    if(ctx) SSL_CTX_free (ctx);
    return NULL;
}

int main()
{
    int sd=0;
    int confd=0;
    SSL* ssl=NULL;
    SSL_CTX* ctx=NULL;
    struct sockaddr_in sa={0};
    ctx=InitSSL(CACERT,CLIENT_CRT,CLIENT_KEY,CLIENT_mode);
    if(ctx==NULL) return -1;

    /* 指定加密器类型 */
    SSL_CTX_set_cipher_list (ctx, "ECDHE-RSA-AES256-SHA");
    SSL_CTX_set_mode (ctx, SSL_MODE_AUTO_RETRY);

    /*以下是正常的TCP socket建立过程 .............................. */
    printf("Begin tcp socket...\n");

    sd= socket (AF_INET, SOCK_STREAM, 0);       
    if(sd <= 0)
    {
        perror("socket");
        goto exit;
    }
    
    sa.sin_family      = AF_INET;
    sa.sin_addr.s_addr = inet_addr(SERVER_ADDR);   /* Server IP */
    sa.sin_port        = htons(PORT);          /* Server Port number */
    confd = connect(sd, (struct sockaddr*)&sa, sizeof(sa)); 
    if(confd < 0)
    {
        printf("connect error=%d\n",confd);
        goto exit;
    }


    /* TCP 链接已建立.开始 SSL 握手过程.......................... */
    printf("Begin SSL negotiation \n");

    /*申请一个SSL套接字*/
    ssl = SSL_new (ctx);                        
    if(ssl <= 0)
    {
        printf("Error creating SSL new \n");
        goto exit;
    }

    /*绑定读写套接字*/
    SSL_set_fd (ssl, sd);
    SSL_connect (ssl);               
    printf("链接已建立.开始 SSL 握手过程 \n");


    /*打印所有加密算法的信息(可选)*/
    printf ("SSL connection using %s\n", SSL_get_cipher (ssl));

    /*得到服务端的证书并打印些信息(可选) */
    X509* server_cert = SSL_get_peer_certificate (ssl);      
    printf ("Server certificate:\n");

    char *str = X509_NAME_oneline (X509_get_subject_name (server_cert),0,0);
    printf ("/t subject: %s\n", str);
    free (str);

    str = X509_NAME_oneline (X509_get_issuer_name  (server_cert),0,0);
    printf ("/t issuer: %s\n", str);
    free (str);

    X509_free (server_cert);  /*如不再需要,需将证书释放 */

    /* 数据交换开始,用SSL_write,SSL_read代替write,read */
    printf("Begin SSL data exchange\n");

    unsigned char buf[300]={0};
    while(1)
    {
        gets(buf);
        int ret = SSL_write (ssl, buf, sizeof(buf)); 
        memset (buf, 0, sizeof(buf));
    }
    SSL_shutdown (ssl);  /* send SSL/TLS close_notify */
    /* 收尾工作 */
    shutdown (sd,2);
exit:
    if(sd > 0) close (sd);
    if(confd > 0) close (confd); 
    if(ctx) SSL_CTX_free(ctx);
    if(ssl) SSL_free (ssl);
    return 0;
}
编译脚本
#bin/bash
@rm sl cl
gcc ../src/ssl_client.c  -lcrypto -lssl -ldl  -g -o cl
gcc ../src/ssl_ser.c -lcrypto -lssl -ldl -o sl
#gcc  rsa_engine.c   -lcrypto -lssl -ldl  -g -o engINE
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值