網頁

2017年8月30日 星期三

SSL 網路程式設計

請參考 Raspberry OPENSSL 根證書 伺服端 客戶端 產生所有需要的檔案

sudo apt-get install libssl-dev

伺服器端程式
gcc server.c -o server -lcrypto -lssl
vi server.c
#include "openssl/bio.h"  
#include "openssl/ssl.h"  
#include "openssl/err.h" 

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#define SERVER_PORT 8080
#define CA_CERT_FILE "../openssl/ca/ca.crt"
#define SERVER_CERT_FILE "../openssl/server/server.crt"
#define SERVER_KEY_FILE "../openssl/server/server.key"

typedef struct sockaddr SA;

int TcpInit()
{
    int listener;
    do{
        listener = socket(AF_INET, SOCK_STREAM, 0);
        if( listener == -1 )
            return 0;

        struct sockaddr_in sin;
        sin.sin_family = AF_INET;
        sin.sin_addr.s_addr = 0;
        sin.sin_port = htons(SERVER_PORT);

        if( bind(listener, (SA*)&sin, sizeof(sin)) < 0 )
            break;

        if( listen(listener, 5) < 0)
            break;

        return listener;
    }while(0);

    return -1;
}

void print_peer_certificate(SSL *ssl)
{  
    X509* cert= NULL;  
    X509_NAME *name=NULL;  
    char buf[8192]={0};  
    BIO *bio_cert = NULL;  
    cert = SSL_get_peer_certificate(ssl);
    if (cert == NULL) {
        printf("SSL_get_peer_certificate() == NULL\n");  
        return;
    }
    if (SSL_get_verify_result(ssl) == X509_V_OK) {
        printf("SSL_get_verify_result(ssl) == X509_V_OK\n");  
    }
    name = X509_get_subject_name(cert);  
    X509_NAME_oneline(name,buf,8191);  
    printf("ServerSubjectName:%s\n",buf);  
    memset(buf,0,sizeof(buf));  
    bio_cert = BIO_new(BIO_s_mem());  
    PEM_write_bio_X509(bio_cert, cert);  
    BIO_read( bio_cert, buf, 8191);  
    printf("SERVER CERT:\n%s\n",buf);  
    if(bio_cert)BIO_free(bio_cert);  
    if(cert)X509_free(cert);  
}


static int verify_cb(int res, X509_STORE_CTX *xs)  
{  
    printf("SSL VERIFY RESULT :%d\n",res);  
    switch (xs->error)  
    {  
        case X509_V_ERR_UNABLE_TO_GET_CRL:  
            printf(" NOT GET CRL!\n");  
            return 1;  
        default :  
            break;  
    }  
    return res;  
}

int main(int argc, char **argv)  
{  
    SSL_CTX     *ctx;  
    SSL         *ssl;  
    X509        *client_cert;  
    char szBuffer[1024];  
    int nLen;  
    struct sockaddr_in addr;   
    int nListenFd, nAcceptFd;  

    nListenFd = TcpInit();
    SSLeay_add_ssl_algorithms();  
    OpenSSL_add_all_algorithms();  
    SSL_load_error_strings();  
    ERR_load_BIO_strings();  

    memset(&addr, 0, sizeof(addr));
    int len = sizeof(addr);
    nAcceptFd = accept(nListenFd, (struct sockaddr *)&addr, &len);   
    //int iMode = 1;
    //int iret = ioctlsocket(nAcceptFd, FIONBIO, (u_long FAR*)&iMode); 
    ctx = SSL_CTX_new (SSLv23_method());
    if( ctx == NULL)
    {
        printf("SSL_CTX_new error!\n");
        return -1;
    }

#define USE_CA_CERT
#ifdef USE_CA_CERT
// 使用 CA_CERT_FILE 檢查 Client 端的證書
    printf("SSL_CTX_set_verify(SSL_VERIFY_PEER)\n");
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb);  

    if(!SSL_CTX_load_verify_locations(ctx, CA_CERT_FILE, NULL))
    {
        printf("SSL_CTX_load_verify_locations error!\n");
        ERR_print_errors_fp(stderr);
        return -1;
    }
#else
    printf("SSL_CTX_set_verify(SSL_VERIFY_NONE)\n");
    SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);  
#endif

    if(SSL_CTX_use_certificate_file(ctx, SERVER_CERT_FILE, SSL_FILETYPE_PEM) <= 0)
    {
        printf("SSL_CTX_use_certificate_file error!\n");
        ERR_print_errors_fp(stderr);
        return -1;
    }

    if(SSL_CTX_use_PrivateKey_file(ctx, SERVER_KEY_FILE, SSL_FILETYPE_PEM) <= 0)
    {
        printf("SSL_CTX_use_PrivateKey_file error!\n");
        ERR_print_errors_fp(stderr);
        return -1;
    }

    if(!SSL_CTX_check_private_key(ctx))
    {
        printf("SSL_CTX_check_private_key error!\n");
        ERR_print_errors_fp(stderr);
        return -1;
    }
    ssl = SSL_new (ctx);
    if(!ssl)
    {
        printf("SSL_new error!\n");
        ERR_print_errors_fp(stderr);
        return -1;
    }
    SSL_set_fd (ssl, nAcceptFd); 
    while(1){
        if(SSL_accept (ssl) != 1)
        {
            int icode = -1;
            ERR_print_errors_fp(stderr);
            int iret = SSL_get_error(ssl, icode);
            printf("SSL_accept error! code = %d, iret = %d\n", icode, iret);
            break;
        } else
            break;
    }
    print_peer_certificate(ssl);

    memset(szBuffer, 0, sizeof(szBuffer));  
    nLen = SSL_read(ssl,szBuffer, sizeof(szBuffer));  
    fprintf(stderr, "Get Len %d %s ok\n", nLen, szBuffer);  
    strcat(szBuffer, "\n this is from server========server resend to client");  
    SSL_write(ssl, szBuffer, strlen(szBuffer));  

    SSL_free (ssl);  
    SSL_CTX_free (ctx);  
    close(nAcceptFd);  
}

客戶端程式
gcc client.c -o client -lcrypto -lssl
vi client.c
#include "openssl/bio.h"  
#include "openssl/ssl.h"  
#include "openssl/err.h" 


#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#define SERVER_PORT 8080
#define SERVER_IP "127.0.0.1"


#define CA_CERT_FILE "../openssl/ca/ca.crt"
#define CLIENT_CERT_FILE "../openssl/client/client.crt"
#define CLIENT_KEY_FILE "../openssl/client/client.key"

void print_client_cert(char* path)  
{  
    X509 *cert =NULL;  
    FILE *fp = NULL;  
    fp = fopen(path,"rb");  
    cert = PEM_read_X509(fp, NULL, NULL, NULL);  
    X509_NAME *name=NULL;  
    char buf[8192]={0};  
    BIO *bio_cert = NULL;  
    name = X509_get_subject_name(cert);  
    X509_NAME_oneline(name,buf,8191);  
    printf("ClientSubjectName:%s\n",buf);  
    memset(buf,0,sizeof(buf));  
    bio_cert = BIO_new(BIO_s_mem());  
    PEM_write_bio_X509(bio_cert, cert);  
    BIO_read( bio_cert, buf, 8191);  
    printf("CLIENT CERT:\n%s\n",buf);  
    if(bio_cert)BIO_free(bio_cert);  
    fclose(fp);  
    if(cert) X509_free(cert);  
}

void print_peer_certificate(SSL *ssl)  
{  
    X509* cert= NULL;  
    X509_NAME *name=NULL;  
    char buf[8192]={0};  
    BIO *bio_cert = NULL;  
    cert = SSL_get_peer_certificate(ssl);
    if (cert == NULL) {
        printf("SSL_get_peer_certificate() == NULL\n");
        return;
    }
    if (SSL_get_verify_result(ssl) == X509_V_OK) {
        printf("SSL_get_verify_result(ssl) == X509_V_OK\n");  
    }
    name = X509_get_subject_name(cert);  
    X509_NAME_oneline(name,buf,8191);  
    printf("ServerSubjectName:%s\n",buf);  
    memset(buf,0,sizeof(buf));  
    bio_cert = BIO_new(BIO_s_mem());  
    PEM_write_bio_X509(bio_cert, cert);  
    BIO_read( bio_cert, buf, 8191);  
    printf("SERVER CERT:\n%s\n",buf);  
    if(bio_cert)BIO_free(bio_cert);  
    if(cert)X509_free(cert);  
}

static int verify_cb(int res, X509_STORE_CTX *xs)  
{  
    printf("SSL VERIFY RESULT :%d\n",res);  
    switch (xs->error)  
    {  
        case X509_V_ERR_UNABLE_TO_GET_CRL:  
            printf(" NOT GET CRL!\n");  
            return 1;  
        default :  
            break;  
    }  
    return res;  
}

int main(int argc, char **argv)  
{  
    char *address = SERVER_IP;

    if(argc > 1)
    {
        address = argv[1];
    }

    SSL_METHOD  *meth;  
    SSL_CTX     *ctx;  
    SSL         *ssl;  

    int nFd;  
    int nLen;  
    char szBuffer[1024];  

    SSLeay_add_ssl_algorithms();  
    OpenSSL_add_all_algorithms();  
    SSL_load_error_strings();  
    ERR_load_BIO_strings();  

    print_client_cert(CLIENT_CERT_FILE);

    // 使用SSL V3,V2  
    ctx = SSL_CTX_new (SSLv23_method());
    if( ctx == NULL)
    {
        printf("SSL_CTX_new error!\n");
        ERR_print_errors_fp(stderr);
        return -1;
    }

#define USE_CA_CERT
#ifdef USE_CA_CERT
// 使用 CA_CERT_FILE 檢查 Server 端的證書
    printf("SSL_CTX_set_verify(SSL_VERIFY_PEER)\n");
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_cb);  

    if(!SSL_CTX_load_verify_locations(ctx, CA_CERT_FILE, NULL))
    {
        printf("SSL_CTX_load_verify_locations error!\n");
        ERR_print_errors_fp(stderr);
        return -1;
    }
#else
    printf("SSL_CTX_set_verify(SSL_VERIFY_NONE)\n");
    SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);  
#endif

#define USE_CERT
#ifdef USE_CERT
    printf("SSL_CTX_use_certificate_file start!\n");
    if(SSL_CTX_use_certificate_file(ctx, CLIENT_CERT_FILE, SSL_FILETYPE_PEM) <= 0)
    {
        printf("SSL_CTX_use_certificate_file error!\n");
        ERR_print_errors_fp(stderr);
        return -1;
    }

    printf("SSL_CTX_use_PrivateKey_file start!\n");
    if(SSL_CTX_use_PrivateKey_file(ctx, CLIENT_KEY_FILE, SSL_FILETYPE_PEM) <= 0)
    {
     printf("SSL_CTX_use_PrivateKey_file error!\n");
     ERR_print_errors_fp(stderr);
     return -1;
    }

    if(!SSL_CTX_check_private_key(ctx))
    {
     printf("SSL_CTX_check_private_key error!\n");
     ERR_print_errors_fp(stderr);
     return -1;
    }
#endif

    nFd = socket(AF_INET, SOCK_STREAM, 0); 

    struct sockaddr_in addr; 
    addr.sin_addr.s_addr = inet_addr(address);
    addr.sin_family = AF_INET;
    addr.sin_port = htons(SERVER_PORT);

    if(connect(nFd, (struct sockaddr *)&addr, sizeof(addr)) < 0)  
    {  
        printf("connect\n"); 
        ERR_print_errors_fp(stderr);
        return -1;  
    }  

    ssl = SSL_new (ctx);
    if( ssl == NULL)
    {
        printf("SSL_new error!\n");
        ERR_print_errors_fp(stderr);
        return -1;
    }
    SSL_set_fd (ssl, nFd);  
    if( SSL_connect (ssl) != 1)
    {
        printf("SSL_new error!\n");
        ERR_print_errors_fp(stderr);
        return -1;
    }

    print_peer_certificate(ssl);

    sprintf(szBuffer, "\nthis is from client+++++++++++++++client send to server");  
    SSL_write(ssl, szBuffer, strlen(szBuffer));  

    memset(szBuffer, 0, sizeof(szBuffer));  
    nLen = SSL_read(ssl,szBuffer, sizeof(szBuffer));  
    fprintf(stderr, "Get Len %d %s ok\n", nLen, szBuffer);  

    SSL_free (ssl);  
    SSL_CTX_free (ctx);  
    close(nFd);     
}



沒有留言:

張貼留言