Usage sample of SSL

本文提供了一个简单的SSL服务器和客户端通信示例,展示了如何通过TCP/IP建立连接并进行数据交换,同时验证了证书的有效性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

This is a sample how client and server to communicate over SSL.

 

-- 1. server.c --

/*
 * ++
 * FACILITY:
 *
 *      Simplest SSL Server
 *
 * ABSTRACT:
 *
 *      This is an example of a SSL server with minimum functionality.
 *      The socket APIs are used to handle TCP/IP operations. This SSL
 *      server loads its own certificate and key, but it does not verify
 *      the certificate of the SSL client.
 *
 * ENVIRONMENT:
 *
 *   OpenVMS Alpha V7.2-2 or higher
 *   TCP/IP Services V5.0A or higher
 *
 * AUTHOR:
 *
 *   Taka Shinagawa, OpenVMS Security Group
 *
 * CREATION DATE:
 *
 *   1-Jan-2002
 *
 * --
 */

#include <unistd.h>
#include <string.h>

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

#include <openssl/crypto.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

#define RSA_SERVER_CERT         "server.pem"
#define RSA_SERVER_KEY          "server.key"

#define RSA_CLIENT_CERTS        "client.pem"

void main()
{
    int         err;
    int     verify_client = 1; /* Whether to verify a client certificate or not. */

    int     listen_sock;
    int     client_sock;
    struct sockaddr_in sa_server;
    struct sockaddr_in sa_client;
    size_t client_len;
    char    *str;
    char        buf[4096];

    SSL_CTX             *ctx;
        SSL                     *ssl;
    SSL_METHOD  *meth;
    X509                *client_cert = NULL;

    short int   s_port = 5555;

    /*-----------------------------------------------------------------------------------------*/
    /* Load encryption & hashing algorithms for the SSL program */
    SSL_library_init();

    /* Load the error strings for SSL & CRYPTO APIs */
    SSL_load_error_strings();

    /* Create a SSL_METHOD structure (choose a SSL/TLS protocol version) */
    meth = SSLv3_method();

    /* Create a SSL_CTX structure */
    ctx = SSL_CTX_new(meth);
        if (ctx == NULL)
        {
                fprintf(stderr, "Failed when SSL_CTX_new(). Exit./n");
                exit(1);
        }

        /* Load the server certificate into the SSL_CTX structure */
        if (SSL_CTX_use_certificate_file(ctx, RSA_SERVER_CERT, SSL_FILETYPE_PEM) <= 0) {
                ERR_print_errors_fp(stderr);
                exit(1);
    }

        /* Load the private-key corresponding to the server certificate */
    if (SSL_CTX_use_PrivateKey_file(ctx, RSA_SERVER_KEY, SSL_FILETYPE_PEM) <= 0) {
                ERR_print_errors_fp(stderr);
                exit(1);
    }

        /* Check if the server certificate and private-key matches */
        if (!SSL_CTX_check_private_key(ctx)) {
                fprintf(stderr,"Private key does not match the certificate public key/n");
                exit(1);
        }

        if(verify_client)
    {
                /* Load the RSA CA certificate into the SSL_CTX structure */
                if (!SSL_CTX_load_verify_locations(ctx, RSA_CLIENT_CERTS, NULL))
                {
                        ERR_print_errors_fp(stderr);
                        exit(1);
                }

                /* Set to require peer (client) certificate verification */
                SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL);

                /* Set the verification depth to 1 */
                SSL_CTX_set_verify_depth(ctx,1);
        }

    /* ----------------------------------------------- */
    /* Set up a TCP socket */

    listen_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);  
        if (listen_sock == -1)
        {
                perror("Cannot create a listen socket");
                exit(1);
        }

    memset (&sa_server, '/0', sizeof(sa_server));
    sa_server.sin_family        = AF_INET;
    sa_server.sin_addr.s_addr   = INADDR_ANY;
    sa_server.sin_port                  = htons(s_port);

    err = bind(listen_sock, (struct sockaddr*)&sa_server,sizeof(sa_server));
    if (err == -1)
    {
        perror("Cannot bind server socket");
        exit(1);
    }
       
        /* Wait for an incoming TCP connection. */
    err = listen(listen_sock, 5);            
    if (err == -1)
    {
        perror("Cannot listen server socket");
        exit(1);
    }

    client_len = sizeof(sa_client);

    /* Socket for a TCP/IP connection is created */
    client_sock = accept(listen_sock, (struct sockaddr*)&sa_client, &client_len);
    if (client_sock == -1)
    {
        perror("Cannot accept a client connection");
        exit(1);
    }
        close (listen_sock);    // we just accept one client connection

    printf ("Connection from %lx, port %x/n", sa_client.sin_addr.s_addr, sa_client.sin_port);

    /* ----------------------------------------------- */
    /* TCP connection is ready. */

    /* A SSL structure is created */
    ssl = SSL_new(ctx);
        if (ssl == NULL)
        {
                fprintf(stderr, "Failed when call SSL_new()./n");
                exit(1);
        }

    /* Assign the socket into the SSL structure (SSL and socket without BIO) */
    SSL_set_fd(ssl, client_sock);

    /* Perform SSL Handshake on the SSL server */
    err = SSL_accept(ssl);
        if (err == -1)
        {
                ERR_print_errors_fp(stderr);
                exit(1);
        }

    /* Informational output (optional) */
    printf("SSL connection using %s/n", SSL_get_cipher (ssl));

    if (verify_client)
    {
                /* Get the client's certificate (optional) */
        client_cert = SSL_get_peer_certificate(ssl);
        if (client_cert != NULL)
        {
                        printf ("Client certificate:/n");
   
                        str = X509_NAME_oneline(X509_get_subject_name(client_cert), 0, 0);
                        if (str  == NULL)
                        {
                                fprintf(stderr, "Cannot get client certificate's subject/n");
                                exit(1);
                        }

                        printf ("/tsubject: %s/n", str);
                        free(str);

                        str = X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0);
                        if (str == NULL)
                        {
                                fprintf(stderr, "Cannot get client certificate's ussuer/n");
                                exit(1);
                        }
                        printf ("/tissuer: %s/n", str);
                        free (str);

                        X509_free(client_cert);
                }
        else
              printf("The SSL client does not have certificate./n");
        }


        /*--------------- DATA EXCHANGE - Receive message and send reply. ---------------*/

        /* Receive data from the SSL client */
    err = SSL_read(ssl, buf, sizeof(buf) - 1);
        if (err == -1)
        {
                ERR_print_errors_fp(stderr);
                exit(1);
        }
    buf[err] = '/0';
    printf ("Received %d chars: '%s'/n", err, buf);

    /* Send data to the SSL client */
        strncpy(buf+err,buf,err);       // double the data, and send it back to client.
    err = SSL_write(ssl, buf, strlen(buf));
        if (err == -1)
        {
                ERR_print_errors_fp(stderr);
                exit(1);
        }

    /*--------------- SSL closure ---------------*/
    /* Shutdown this side (server) of the connection. */
    err = SSL_shutdown(ssl);
        if (err == -1)
        {
                ERR_print_errors_fp(stderr);
                exit(1);
        }

    /* Terminate communication on a socket */
    err = close(client_sock);
    if (err == -1)
    {
        perror("Cannot close connection socket");
        exit(1);
    }

    /* Free the SSL structure */
    SSL_free(ssl);

    /* Free the SSL_CTX structure */
    SSL_CTX_free(ctx);
}

 

-- 2. client.c --

/*
 * ++
 * FACILITY:
 *
 *      Simplest SSL Server
 *
 * ABSTRACT:
 *
 *      This is an example of a SSL server with minimum functionality.
 *      The socket APIs are used to handle TCP/IP operations. This SSL
 *      server loads its own certificate and key, but it does not verify
 *      the certificate of the SSL client.
 *
 * ENVIRONMENT:
 *
 *   OpenVMS Alpha V7.2-2 or higher
 *   TCP/IP Services V5.0A or higher
 *
 * AUTHOR:
 *
 *   Taka Shinagawa, OpenVMS Security Group
 *
 * CREATION DATE:
 *
 *   1-Jan-2002
 *
 * --
 */

#include <unistd.h>
#include <string.h>

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

#include <openssl/crypto.h>
#include <openssl/ssl.h>
#include <openssl/err.h>

#define RSA_CLIENT_CERT     "client.pem"
#define RSA_CLIENT_KEY      "client.key"

#define RSA_SERVER_CERTS        "server.pem"


void main()
{
        int     err;
    int     verify_client = 1; /* Whether to verify a client certificate or not. */

    int         sock;
    struct sockaddr_in server_addr;
    char        *str;
    char        buf [4096];
    char        hello[80];

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

    short int   s_port = 5555;
    const char  *s_ipaddr = "127.0.0.1";
   
    /*----------------------------------------------------------*/
    printf ("Message to be sent to the SSL server: ");
    //fgets (hello, 80, stdin);
    scanf("%s",hello);
    
    /* Load encryption & hashing algorithms for the SSL program */
    SSL_library_init();

    /* Load the error strings for SSL & CRYPTO APIs */
    SSL_load_error_strings();

    /* Create an SSL_METHOD structure (choose an SSL/TLS protocol version) */
    meth = SSLv3_method();

    /* Create an SSL_CTX structure */
    ctx = SSL_CTX_new(meth);                
        if (ctx == NULL)
        {
                fprintf(stderr, "Failed when SSL_CTX_new(). Exit./n");
                exit(1);
        }


    /*-------------------------------------------------------------------------*/
    if(verify_client)
    {
                /* Load the client certificate into the SSL_CTX structure */
                if (SSL_CTX_use_certificate_file(ctx, RSA_CLIENT_CERT, SSL_FILETYPE_PEM) <= 0) {
                        ERR_print_errors_fp(stderr);
                        exit(1);
                }

                /* Load the private-key corresponding to the client certificate */
                if (SSL_CTX_use_PrivateKey_file(ctx, RSA_CLIENT_KEY, SSL_FILETYPE_PEM) <= 0) {
                        ERR_print_errors_fp(stderr);
                        exit(1);
                }

                /* Check if the client certificate and private-key matches */
                if (!SSL_CTX_check_private_key(ctx)) {
                        fprintf(stderr,"Private key does not match the certificate public key/n");
                        exit(1);
                }
        }

        /* Load the RSA CA certificate into the SSL_CTX structure       */
        /* This will allow this client to verify the server's           */
    /* certificate.                                                                                     */
    if (!SSL_CTX_load_verify_locations(ctx, RSA_SERVER_CERTS, NULL)) {
                ERR_print_errors_fp(stderr);
                exit(1);
        }

        /* Set flag in context to require peer (server) certificate verification */
    SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL);
    SSL_CTX_set_verify_depth(ctx,1);

    /* ----------------------------------------------------------------- */
    /* Set up a TCP socket */

    sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);    
        if (sock == -1)
        {
                perror("Cannot create a client socket");
                exit(1);
        }

    memset (&server_addr, '/0', sizeof(server_addr));
    server_addr.sin_family      = AF_INET;
    server_addr.sin_port        = htons(s_port);       /* Server Port number */
    server_addr.sin_addr.s_addr = inet_addr(s_ipaddr);   /* Server IP */

    /* Establish a TCP/IP connection to the SSL client */
    err = connect(sock, (struct sockaddr*) &server_addr, sizeof(server_addr));
        if (err == -1)
        {
                perror("Cannot connect to server");
                exit(1);
        }

    /* ----------------------------------------------- */
    /* An SSL structure is created */
    ssl = SSL_new (ctx);
    if (ssl == NULL)
    {  
                fprintf(stderr, "Failed when call SSL_new()./n");
        exit(1);
    }

    /* Assign the socket into the SSL structure (SSL and socket without BIO) */
    SSL_set_fd(ssl, sock);

    /* Perform SSL Handshake on the SSL client */
    err = SSL_connect(ssl);
        if (err ==-1)
        {
                ERR_print_errors_fp(stderr);
                exit(1);
        }

    /* Informational output (optional) */
    printf ("SSL connection using %s/n", SSL_get_cipher (ssl));


    /* Get the server's certificate (optional) */
    server_cert = SSL_get_peer_certificate (ssl);    
    if (server_cert != NULL)
    {
                printf ("Server certificate:/n");

                str = X509_NAME_oneline(X509_get_subject_name(server_cert),0,0);
                if (str == NULL)
                {
                        fprintf(stderr, "Cannot get server certificate's subject/n");
                        exit(1);
                }
                printf ("/tsubject: %s/n", str);
                free (str);

                str = X509_NAME_oneline(X509_get_issuer_name(server_cert),0,0);
                if (str == NULL)
                {
                        fprintf(stderr, "Cannot get server certificate's issuer/n");
                        exit(1);
                }
                printf ("/tissuer: %s/n", str);
                free(str);

                X509_free (server_cert);
        }
    else
                printf("The SSL server does not have certificate./n");


        /*--------------- DATA EXCHANGE - send message and receive reply. ---------------*/

    /* Send data to the SSL server */
    err = SSL_write(ssl, hello, strlen(hello));
        if (err == -1)
        {
                ERR_print_errors_fp(stderr);
                exit(1);
        }

    /* Receive data from the SSL server */
    err = SSL_read(ssl, buf, sizeof(buf)-1);              
        if (err == -1)
        {
                ERR_print_errors_fp(stderr);
                exit(1);
        }
    buf[err] = '/0';
    printf ("Received %d chars:'%s'/n", err, buf);

    /*--------------- SSL closure ---------------*/
    /* Shutdown the client side of the SSL connection */
    err = SSL_shutdown(ssl);
        if (err ==-1)
        {
                ERR_print_errors_fp(stderr);
                exit(1);
        }

    /* Terminate communication on a socket */
    err = close(sock);
        if (err == -1)
        {
                perror("Cannot close socket");
                exit(1);
        }

    /* Free the SSL structure */
    SSL_free(ssl);

    /* Free the SSL_CTX structure */
    SSL_CTX_free(ctx);
}

 

-- 3. compile server&client --

#: cat Makefile

CFLAGS += -I/opt/exp/lib/openssl/include
LDFLAGS += -lsocket -lnsl -lrt -L/opt/exp/lib/openssl/lib -lssl -lcrypto

all : client server

client : client.c
        cc $(CFLAGS) $(LDFLAGS) -o $@ $^
server : server.c
        cc $(CFLAGS) $(LDFLAGS) -o $@ $^

clean:
        rm -rf client server

 

-- 4. generate server & client's private key and certificate --

 

-- for server --
openssl genrsa -out server.key 2048
openssl req -new -x509 -key server.key -out server.pem -days 1095

-- for client --
openssl genrsa -out client.key 2048
openssl req -new -x509 -key client.key -out client.pem -days 1095

 

-- 5. execute the server & client

#: ./server
Connection from 7f000001, port f5ed
SSL connection using AES256-SHA
Client certificate:
        subject: /C=CN/ST=BJ/L=bj/O=company/OU=product/CN=aclient
        issuer: /C=CN/ST=BJ/L=bj/O=company/OU=product/CN=aclient
Received 3 chars: '123'

 

#: ./client
Message to be sent to the SSL server: 123
SSL connection using AES256-SHA
Server certificate:
        subject: /C=CN/ST=BJ/L=bj/O=company/OU=product/CN=aserver
        issuer: /C=CN/ST=BJ/L=bj/O=company/OU=product/CN=aserver
Received 6 chars:'123123'

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值