openssl 自签名证书 - socket编程应用(三)

【上一篇:openssl 自签名证书 - 制作证书(二)】

用xcode创建应用工程

1. 确认头文件搜索目录

1.根据openssl编译设置目录,比如说/usr/local/openssl/include
2.我使用homebrew安装的openssl,目录一般为/usr/local/opt/openssl/include

2.工程设置头文件搜索

左边点击project -> 中间target -> 右边Build Settings选项卡 -> Header Search Paths,双击添加路径


头文件搜索设置

3. 静态库设置

  1. 将编译出来的【libcrypto.a】【libssl.a】复制工程目录然后添加进来
  2. 我是homebrew安装的,复制【libcrypto.a】【libssl.a】到工程目录然后添加进来,“什么?我去哪里找?!”,一般是在/usr/local/opt/openssl/lib/目录下

4. 上代码

#include 

#include 
#include 
#include 
#include 
#include 

#include 
#include 

#define SSL_ROOT_DIR            "your path here..."

#define SSL_CA_PATH             SSL_ROOT_DIR "ca.crt"
#define SSL_SERVER_CER_PATH     SSL_ROOT_DIR "server.crt"
#define SSL_SERVER_KEY_PATH     SSL_ROOT_DIR "server.key"

#define SSL_CLIENT_CER_PATH     SSL_ROOT_DIR "client.crt"
#define SSL_CLIENT_KEY_PATH     SSL_ROOT_DIR "client.key"

#ifndef SSL_VERIFY
#define SSL_VERIFY          1
#endif

#if SSL_VERIFY
#define SSL_VERIFY_MODE     SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT
#else
#define SSL_VERIFY_MODE     SSL_VERIFY_NONE
#endif

int g_ssl_connect_flag = 0;
int g_ssl_server_close = 0;
int g_ssl_client_close = 0;

void ssl_show_certs(SSL * ssl, const char *label)
{
    X509 *cert;
    char *line;
    
    cert = SSL_get_peer_certificate(ssl);
    // SSL_get_verify_result(), really verify
    printf(">>> %s\n", label);
    if(SSL_get_verify_result(ssl) == X509_V_OK){
        
        printf("ssl verify ok.\n");
    }
    
    if(NULL != cert) {
        
        line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
        printf("certificate: %s\n", line);
        free(line);
        line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
        printf("ca: %s\n", line);
        free(line);
        X509_free(cert);
    } else{
        
        printf("no certificate info.\n");
    }
}

void ssl_socket_server(void){
    
    SSL_CTX *ctx = NULL;
    int sock = 0;
    ctx = SSL_CTX_new(SSLv23_server_method());
    if(NULL == ctx){
        
        fprintf(stderr, "server create ssl context fail.\n");
        ERR_print_errors_fp(stderr);
        return;
    }
    
    do{
        
        SSL_CTX_set_verify(ctx, SSL_VERIFY_MODE, NULL);
        
        if(0 >= SSL_CTX_load_verify_locations(ctx, SSL_CA_PATH, NULL)){
            
            ERR_print_errors_fp(stderr);
            fprintf(stderr, "server load ca file fail.\n");
            ERR_print_errors_fp(stderr);
            break;
        }
        
        if(0 >= SSL_CTX_use_certificate_chain_file(ctx, SSL_SERVER_CER_PATH)){
            
            fprintf(stderr, "server load cer file fail.\n");
            ERR_print_errors_fp(stderr);
            break;
        }
        
        /// set private key password if needed
        SSL_CTX_set_default_passwd_cb_userdata(ctx, "123456");
        
        if(0 >= SSL_CTX_use_PrivateKey_file(ctx, SSL_SERVER_KEY_PATH, SSL_FILETYPE_PEM)){
            
            fprintf(stderr, "server load private key file fail.\n");
            ERR_print_errors_fp(stderr);
            break;
        }
        
        if(0 >= SSL_CTX_check_private_key(ctx)){
            
            fprintf(stderr, "check server private key fail.\n");
            ERR_print_errors_fp(stderr);
            break;
        }
        
        sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
        struct sockaddr_in s_addr;
        memset(&s_addr, 0, sizeof(s_addr));
        s_addr.sin_family = AF_INET;
        s_addr.sin_port = htons(10086);
        s_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
        
        if(0 != bind(sock, (const struct sockaddr*)&s_addr, sizeof(s_addr))){
            
            fprintf(stderr, "server bind fail.\n");
            break;
        }
        
        if(0 != listen(sock, 1)){
            
            fprintf(stderr, "server lisent fail.\n");
            break;
        }
        
        struct sockaddr_in s_addr_out;
        int s_add_len = 0;
        int new_sock = 0;
        memset(&s_addr_out, 0x00, sizeof(s_addr_out));
        g_ssl_connect_flag = 1;
        SSL *ssl = NULL;
        printf("server waiting...\n");
        char msg[256] = {0};
        while(1){
            
            s_add_len = sizeof(s_addr_out);
            new_sock = accept(sock, (struct sockaddr*)&s_addr_out, (socklen_t*)&s_add_len);
            if(0 >= new_sock){
                
                continue;
            }
            
            ssl = SSL_new(ctx);
            SSL_set_fd(ssl, new_sock);
            if(1 != SSL_accept(ssl)){
                
                fprintf(stderr, "server accept ssl socket fail.\n");
                ERR_print_errors_fp(stderr);
                SSL_free(ssl);
                close(new_sock);
                continue;
            }
            
#if SSL_VERIFY
            ssl_show_certs(ssl, "serever side:");
#endif
            
            memset(msg, 0x00, 256);
            int sl = sprintf(msg, "hello client<%d> from <%s:%d>\n", new_sock, inet_ntoa(s_addr_out.sin_addr), ntohs(s_addr_out.sin_port));
            int wl = SSL_write(ssl, msg, sl);
            printf("server send %d bytes data.\n", wl);
            
            memset(msg, 0x00, 256);
            int rl = SSL_read(ssl, msg, 256);
            printf("server recv %d bytes data:\ncontent: %s\n", rl, msg);
            
            g_ssl_client_close = 1;
            
            while(1 != g_ssl_server_close){
                
                usleep(200000);
            }
            
            SSL_shutdown(ssl);
            SSL_free(ssl);
            close(new_sock);
            
            printf("server close...\n");
            break;
        }
    }while(0);
    
    shutdown(sock, 2);
    close(sock);
    SSL_CTX_free(ctx);
}

void* ssl_client_thread_(void *param){
    
    int sock = 0;
    SSL *ssl = NULL;
    SSL_CTX *ctx = SSL_CTX_new(SSLv23_client_method());
    if(NULL == ctx){
        
        fprintf(stderr, "client create ssl context fail.\n");
        ERR_print_errors_fp(stderr);
        return NULL;
    }
    
    do{
        
        do{
            
            usleep(200000);
        }while(1 != g_ssl_connect_flag);
        
        usleep(1000000);
        
        SSL_CTX_set_verify(ctx, SSL_VERIFY_MODE, NULL);
        
        if(0 >= SSL_CTX_load_verify_locations(ctx, SSL_CA_PATH, NULL)){
            
            fprintf(stderr, "client load ca file fail.\n");
            ERR_print_errors_fp(stderr);
            break;
        }
        
        if(0 >= SSL_CTX_use_certificate_chain_file(ctx, SSL_CLIENT_CER_PATH)){
            
            fprintf(stderr, "client load cer file fail.\n");
            ERR_print_errors_fp(stderr);
            break;
        }
        
        /// set private key password if needed
        SSL_CTX_set_default_passwd_cb_userdata(ctx, "123456");
        
        if(0 >= SSL_CTX_use_PrivateKey_file(ctx, SSL_CLIENT_KEY_PATH, SSL_FILETYPE_PEM)){
            
            fprintf(stderr, "client load private key file fail.\n");
            ERR_print_errors_fp(stderr);
            break;
        }
        
        if(0 >= SSL_CTX_check_private_key(ctx)){
            
            fprintf(stderr, "check client private key fail.\n");
            ERR_print_errors_fp(stderr);
            break;
        }
        
        sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
        struct sockaddr_in s_addr;
        memset(&s_addr, 0x00, sizeof(s_addr));
        s_addr.sin_family = AF_INET;
        s_addr.sin_port = htons(10086);
        s_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
        if(0 != connect(sock, (const struct sockaddr *)&s_addr, sizeof(s_addr))){
            
            printf("client connect server fail.\n");
            break;
        }
        
        ssl = SSL_new(ctx);
        SSL_set_fd(ssl, sock);
        if(1 != SSL_connect(ssl)){
            
            fprintf(stderr, "client ssl connect fail.\n");
            ERR_print_errors_fp(stderr);
            break;
        }
        
#if SSL_VERIFY
        ssl_show_certs(ssl, "client side:");
#endif
        
        char msg[256] = {0};
        int rl = SSL_read(ssl, msg, 256);
        printf("client recv %d bytes data:\ncontent: %s\n", rl, msg);
        memset(msg, 0x00, 256);
        const char *m = "hello ssl server!!";
        int sl = (int)strlen(m);
        int wl = SSL_write(ssl, m, sl);
        printf("client send %d bytes data.\n", wl);
        
        while(1 != g_ssl_client_close){
            
            usleep(200000);
        }
    }while(0);
    
    if(NULL != ssl){
        
        SSL_shutdown(ssl);
        SSL_free(ssl);
    }
    close(sock);
    SSL_CTX_free(ctx);
    g_ssl_server_close = 1;
    
    printf("client close...\n");
    
    return NULL;
}

void ssl_socket_client(void){
    
    pthread_t pt;
    if(0 > pthread_create(&pt, NULL, ssl_client_thread_, NULL)){
        
        printf("client create socket thread fail.\n");
        return;
    }
}

void ssl_socket_test(void){
    
    printf("ca path: %s\nser-req: %s\nser-key: %s\nclt-req: %s\nclt-key: %s\n", SSL_CA_PATH, SSL_SERVER_CER_PATH, SSL_SERVER_KEY_PATH, SSL_CLIENT_CER_PATH, SSL_CLIENT_KEY_PATH );
    
    SSL_library_init();
    OpenSSL_add_all_algorithms();
    SSL_load_error_strings();
    
    ssl_socket_client();
    ssl_socket_server();
}

int main(int argc, const char * argv[]) {
    // insert code here...
    printf("Hello, World!\n");
    
    ssl_socket_test();
    printf("press any key to exit...\n");
    getchar();
    
    return 0;
}

控制台主要信息输出,如下:
Hello, World!
...
server waiting...
...
server send 39 bytes data.
...
client recv 39 bytes data:
content: hello client<5> from <127.0.0.1:53269>

client send 18 bytes data.
server recv 18 bytes data:
content: hello ssl server!!
client close...
server close...
press any key to exit...

你可能感兴趣的:(openssl 自签名证书 - socket编程应用(三))