TCP Socket - C Language
Riferimenti per il file commSSL.c
#include "commSSL.h"

Vai al codice sorgente di questo file.

Funzioni

void sslerr1 (cli_conn *client)
void sslerr2 (char *file, int line)
srvSkSSLnewSSLServerChannel (const char *service)
cli_connacceptSSLConnection (srvSkSSL *server)
int sendSSLMessage (cli_conn *client, message_t *msg)
int receiveSSLMessage (cli_conn *client, message_t *msg)
int closeSSLServerSocket (srvSkSSL *server)
int closeSSLConnection (cli_conn *client)
void unloadSSL ()
cli_connretrySSLConnection (const char *hostname, const char *portno)

Variabili

int verify_client = ON

Descrizione dettagliata

Autore:
Tranchida Giulio, No. Matricola 241732
Si dichiara che il contenuto di questo file e', in ogni sua parte, opera originale dell'autore.

This program is free software; you can redistribuite it and/or modify it under the terms of the GNU/General Pubblic License as published the Free software Foundation; either version 2 of the License, or (at your opinion) any later version.

Definizione nel file commSSL.c.


Documentazione delle funzioni

srvSkSSL* newSSLServerChannel ( const char *  service)

Crea le sockets di ascolto. Open passive (server) sockets for the indicated inet service & protocol. Notice in the last sentence that "sockets" is plural. During the interim transition period while everyone is switching over to IPv6, the server application has to open two sockets on which to listen for connections... one for IPv4 traffic and one for IPv6 traffic.

Parametri:
servicePointer to a character string representing the well-known port on which to listen (can be a service name or a decimal number).
Restituisce:
  • a pointer to a new comm structure, on succes
  • a NULL pointer, on failure and sets errno

Definizione alla linea 21 del file commSSL.c.

                                                   {
        srvSkSSL * server = NULL;
        
        if (!service) {
                errno = EINVAL;
                sys_err(__FILE__,__LINE__,"Server: Error 'service' nullo.");
                return NULL;
        }

        if (!(server = calloc(1, sizeof(srvSkSSL)))) {
                sys_err(__FILE__,__LINE__,"Server: Error calloc 'server'");
                return NULL;
        }

        if (!(server->srvSk = newServerChannel(service))) {
                free (server);
                return NULL;
        }

#ifdef _DEBUG_MODE
        /* Load the error strings for SSL & CRYPTO APIs */
        SSL_load_error_strings();       /* ? valgrind ? */
#endif

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

        /* Create a SSL_CTX structure and
         * create a SSL_METHOD structure (choose a SSL/TLS protocol version) */
        server->ctx = SSL_CTX_new(SSLv3_method());

        if (!server->ctx){
                sslerr2(__FILE__,__LINE__); free (server); return NULL;
        }

        /* Load the server certificate into the SSL_CTX structure */
        if (SSL_CTX_use_certificate_file(server->ctx, RSA_SERVER_CERT, SSL_FILETYPE_PEM) <= 0) {
                sslerr2(__FILE__,__LINE__);
                closeServerSocket(server->srvSk);
                free (server);
                return NULL;
        }

        /* Load the private-key corresponding to the server certificate */
        if (SSL_CTX_use_PrivateKey_file(server->ctx, RSA_SERVER_KEY, SSL_FILETYPE_PEM) <= 0) {
                sslerr2(__FILE__,__LINE__);
                closeServerSocket(server->srvSk);
                free (server);
                return NULL;
        }

        /* Check if the server certificate and private-key matches */
        if (!SSL_CTX_check_private_key(server->ctx)){
                sys_err(__FILE__,__LINE__,"Server: Private key does not match the certificate public key");
                closeServerSocket(server->srvSk);
                free (server);
                return NULL;
        }

        if (verify_client == ON){
                /* Load the RSA CA certificate into the SSL_CTX structure */
                if (!SSL_CTX_load_verify_locations(server->ctx, RSA_SERVER_CA_CERT, NULL)) {
                        sslerr2(__FILE__,__LINE__);
                        closeServerSocket(server->srvSk);
                        free (server);
                        return NULL;
                }
                /* Set to require peer (client) certificate verification */
                SSL_CTX_set_verify(server->ctx,SSL_VERIFY_PEER,NULL);
                /* Set the verification depth to 1 */
                SSL_CTX_set_verify_depth(server->ctx,1);
        }
        return server;
}
cli_conn* acceptSSLConnection ( srvSkSSL server)

accetta una connessione da parte di un client

Parametri:
serverstruttura dati della socket di ascolto del server
Restituisce:
  • a pointer to a new 'cli_conn' structure, on succes
  • a NULL pointer, on failure and sets errno

Definizione alla linea 98 del file commSSL.c.

                                                 {
        int               cli_sk = 0, err = 0;
#ifdef _DEBUG_MODE
        X509            * client_cert = NULL;
        char            * str = NULL;
#endif
        cli_conn        * client = NULL;

        /* In caso di errore la acceptConnection ritorna -1 */
        if ((cli_sk =  acceptConnection(server->srvSk)) == -1){
                sys_err(__FILE__,__LINE__,"Server: acceptSSLConnection");
                return NULL;
        }

        if (!(client = calloc(1, sizeof(cli_conn)))){
                sys_err(__FILE__,__LINE__,"Server: acceptSSLConnection 'calloc'");
                return NULL;
        }
        client->socket = cli_sk;

        /* A SSL structure is created */
        client->ssl = SSL_new(server->ctx);
        if (!client->ssl){
                sys_err(__FILE__,__LINE__,"Server: Error on create new SSL ctx");
                sslerr2(__FILE__,__LINE__);
                free (client);
                return NULL;
        }

        /* Assign the socket into the SSL structure (SSL and socket without BIO) */
        SSL_set_fd(client->ssl, cli_sk);

        /* Perform SSL Handshake on the SSL server */
        if ((err = SSL_accept(client->ssl)) == -1){
                sslerr2(__FILE__,__LINE__);
                free (client);
                return NULL;
        }

#ifdef _DEBUG_MODE
        /* Informational output (optional) */
        printf("Server: connessione SSL %s\n", SSL_get_cipher (client->ssl));

        if (verify_client == ON){
                /* Get the client's certificate (optional) */
                client_cert = SSL_get_peer_certificate(client->ssl);
                if (client_cert != NULL){
                        printf ("Client certificate:\n");
                        str = X509_NAME_oneline(X509_get_subject_name(client_cert), 0, 0);
                        if (str == NULL){
                                free (client);
                                return NULL;
                        }
                        printf ("\t subject: %s\n", str);
                        free (str);
                        str = X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0);
                        if (str == NULL){
                                free (client);
                                return NULL;
                        }
                        printf ("\t issuer: %s\n", str);
                        free (str);
                        X509_free(client_cert);
                }
                else
                        printf("Server: The SSL client does not have certificate.\n");
        }
#endif

        return client;
}
int sendSSLMessage ( cli_conn client,
message_t msg 
)

scrive un messaggio sul channel di trasmissione

Parametri:
clientstruttura di comunicazione del client
msgstruttura che contiene il messaggio da scrivere
Restituisce:
  • -1 se errore (sets errno)
  • n il numero di caratteri inviati (se OK)

Definizione alla linea 172 del file commSSL.c.

                                                     {
        int char_sent = 0, sent = 0;

        if ((sent = SSL_write(client->ssl, &(msg->type), sizeof(char))) < 0){
                sys_err(__FILE__,__LINE__,"Error send message 'type'");
                sslerr1(client);
                return -1;
        }
        char_sent = sent;

        if ((sent = SSL_write(client->ssl, &(msg->length), sizeof(unsigned int))) < 0){
                sys_err(__FILE__,__LINE__,"Error send message 'length'");
                sslerr1(client);
                return -1;
        }
        char_sent += sent;

        if (msg->length!=0){
                if ((sent = SSL_write(client->ssl, msg->buffer, msg->length)) < 0){
                        sys_err(__FILE__,__LINE__,"Error send message 'buffer' ");
                        sslerr1(client);
                        return -1;
                }
                char_sent += sent;
        }
        return char_sent;
}
int receiveSSLMessage ( cli_conn client,
message_t msg 
)

legge un messaggio dal channel di trasmissione

Parametri:
clientstruttura di comunicazione del cliente
msgstruttura che conterra' il messagio letto (deve essere allocata all'esterno della funzione, tranne il campo buffer)
Restituisce:
  • -1 se errore (errno settato),
  • SEOF se EOF sul socket
  • lung lunghezza del buffer letto, se OK

Definizione alla linea 201 del file commSSL.c.

                                                        {
        int ricevuti=0, tmp_cnt=0, read_cnt=0;
        char * buffer = NULL;

        /* Se la struttura del messaggio non e' allocata.. */
        if (!msg && !(msg = calloc(1, sizeof(message_t)))){
                sys_err(__FILE__,__LINE__,"Error calloc 'msg': ");
                return -1;
        }

        /* Leggo il tipo del messaggio */
        if ((ricevuti = SSL_read(client->ssl, &(msg->type), sizeof(char))) < 0){
                sys_err(__FILE__,__LINE__,"Error read message 'type': ");
                sslerr1(client);
                return -1;
        }
        read_cnt = ricevuti;

        /* Leggo la dimensione del messaggio */
        if ((ricevuti = SSL_read(client->ssl, &(msg->length), sizeof(unsigned int))) < 0){
                sys_err(__FILE__,__LINE__,"Error read message 'length': ");
                sslerr1(client);
                return -1;
        }
        read_cnt += ricevuti;

        /* Leggo il messaggio reale */
        if (msg->length!=0){
                if (!(buffer = calloc(msg->length+1, sizeof(char)))){
                        sys_err(__FILE__,__LINE__,"Error calloc 'buffer': ");
                        return -1;
                }
                if (!(msg->buffer = calloc(msg->length+1, sizeof(char)))){
                        sys_err(__FILE__,__LINE__,"Error calloc 'msg->buffer': ");
                        return -1;
                }
                while(tmp_cnt < msg->length){
                        if ((ricevuti = SSL_read(client->ssl, buffer, msg->length-tmp_cnt)) < 0){
                                sys_err(__FILE__,__LINE__,"Error read message 'buffer': ");
                                sslerr1(client);
                                return -1;
                        }
                        tmp_cnt += ricevuti;
                        if (ricevuti > 0) strncat (msg->buffer, buffer, ricevuti);
                }
                free (buffer);
                read_cnt += tmp_cnt;
        }
        return read_cnt;
}
int closeSSLServerSocket ( srvSkSSL server)

Distrugge un canale di ascolto (server-side)

Parametri:
serverstruttura dati della socket di ascolto del server
Restituisce:
  • 0 on succes,
  • -1 se errore (sets errno)

Definizione alla linea 253 del file commSSL.c.

                                           {
        if (!server) return 0;

        /* Liberiamo la struttura del contesto SSL */
        if (server->ctx) SSL_CTX_free (server->ctx);
        if (server->srvSk) closeServerSocket(server->srvSk);
        free (server);
        server = NULL;
        return 0;
}
int closeSSLConnection ( cli_conn client)

Chiude un socket

Parametri:
clientstruttura di comunicazione del client
Restituisce:
  • 0 on succes,
  • -1 se errore (sets errno)

Definizione alla linea 265 del file commSSL.c.

                                         {
        if (!client) return 0;  /* Puntatore nullo, ritorno */

        if (client->ssl){
                SSL_shutdown (client->ssl);
                SSL_free (client->ssl);
        }
        if (client->ctx) SSL_CTX_free (client->ctx);
        if (client->socket) closeConnection(client->socket);
        free (client);
        client = NULL;
        return 0;
}
void unloadSSL ( )

Cerca di scaricare tutta la merda messa in memoria dalle librerie SSL

Definizione alla linea 279 del file commSSL.c.

                {
        /* Ma quanta merda !!! */
        ERR_remove_state(0);
        EVP_cleanup();                                  /* Thread unsafe */
        CRYPTO_cleanup_all_ex_data();   /* Thread unsafe */
        ERR_free_strings();
        /*sk_SSL_COMP_free (SSL_COMP_get_compression_methods());*/
}
cli_conn* retrySSLConnection ( const char *  hostname,
const char *  service 
)

crea una socket di trasmissione verso il server, tentando la connessione per un massimo di due minuti se MAXSLEEP e' 128

Parametri:
hostnameIndirizzo del server
serviceNome del servizio (noto) o numero di porta del server
Restituisce:
  • a pointer to a new 'cli_conn' structure, on succes
  • a NULL pointer, on failure and sets errno

Definizione alla linea 289 del file commSSL.c.

                                                                         {
        cli_conn        * client = NULL;
#ifdef _DEBUG_MODE
        X509            * server_cert;
        char            * str = NULL;
#endif

        if (!hostname){
                errno = EINVAL;
                sys_err(__FILE__,__LINE__,"Server: retrySSLConnection 'hostname' nullo.");
                return NULL;
        }
        if (!portno){
                errno = EINVAL;
                sys_err(__FILE__,__LINE__,"Server: retrySSLConnection 'portno' nullo.");
                return NULL;
        }

        if (!(client = calloc(1, sizeof(cli_conn)))){
                sys_err(__FILE__,__LINE__,"Client: Error calloc 'client': ");
                return NULL;
        }

        client->socket = retryConnection(hostname, portno);
        if (client->socket == -1) return NULL;

#ifdef _DEBUG_MODE
        /* Register the error strings for libcrypto & libssl
         * Se la memoria e' un problema.. allora e' bene evitare. */
        SSL_load_error_strings();
#endif

        /* Register the available ciphers and digests */
        SSL_library_init();                     /* ? valgrind ? */

        /* New context saying we are a client, and using SSL 2 or 3 */
        client->ctx = SSL_CTX_new(SSLv3_method());
        if (!client->ctx){
                sys_err(__FILE__,__LINE__,"Client: Error on create new SSL ctx");
                sslerr2(__FILE__,__LINE__); free (client); return NULL;
        }

        if (verify_client == ON){
                /* Load the client certificate into the SSL_CTX structure */
                if (SSL_CTX_use_certificate_file(client->ctx, RSA_CLIENT_CERT, SSL_FILETYPE_PEM) <= 0) {
                        sslerr2(__FILE__,__LINE__);
                        close(client->socket);
                        free (client);
                        return NULL;
                }

                /* Load the private-key corresponding to the client certificate *//* ? valgrind ? */
                if (SSL_CTX_use_PrivateKey_file(client->ctx, RSA_CLIENT_KEY, SSL_FILETYPE_PEM) <= 0) {
                        sslerr2(__FILE__,__LINE__);
                        close(client->socket);
                        free (client);
                        return NULL;
                }

                /* Check if the client certificate and private-key matches */
                if (!SSL_CTX_check_private_key(client->ctx)){
                        sys_err(__FILE__,__LINE__,"Client: Private key does not match the certificate public key");
                        close(client->socket);
                        free (client);
                        return NULL;
                }
        }

        /* 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(client->ctx, RSA_CLIENT_CA_CERT, NULL)){
                close(client->socket);
                sslerr2(__FILE__,__LINE__);
                free (client);
                return NULL;
        }

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

        /* Create an SSL struct for the connection */
        client->ssl = SSL_new(client->ctx);
        if (!client->ssl){
                sslerr2(__FILE__,__LINE__);
                close(client->socket);
                free (client);
                return NULL;
        }

        /* Connect the SSL struct to our connection */
        if (!SSL_set_fd(client->ssl, client->socket)){
                sslerr2(__FILE__,__LINE__);
                close(client->socket);
                free (client);
                return NULL;
        }

        /* Initiate SSL handshake */
        if (SSL_connect(client->ssl) != 1){
                sslerr2(__FILE__,__LINE__);
                close(client->socket);
                free (client);
                return NULL;
        }

#ifdef _DEBUG_MODE
        /* Informational output (optional) */
        printf ("SSL connection using %s\n", SSL_get_cipher(client->ssl));

        /* Get the server's certificate (optional) */
        server_cert = SSL_get_peer_certificate(client->ssl);

        if (server_cert != NULL){
                printf ("Server certificate:\n");

                if (!(str = X509_NAME_oneline(X509_get_subject_name(server_cert),0,0))){
                        sys_err(__FILE__,__LINE__,"Client: 'X509_get_subject_name'");
                        close(client->socket);
                        free (client);
                        return NULL;
                }
                printf ("\t subject: %s\n", str);
                free (str);

                if (!(str = X509_NAME_oneline(X509_get_issuer_name(server_cert),0,0))){
                        sys_err(__FILE__,__LINE__,"Client: 'X509_get_iusser_name'");
                        close(client->socket);
                        free (client);
                        return NULL;
                }
                printf ("\t issuer: %s\n", str);
                free(str);
                X509_free (server_cert);
        }
        else
                printf("The SSL server does not have certificate.\n");
#endif

        return client;
}

Documentazione delle variabili

int verify_client = ON

To verify a client certificate, set ON

Definizione alla linea 18 del file commSSL.c.