TCP Socket - C Language
commSSL.c
Vai alla documentazione di questo file.
00001 
00013 #include "commSSL.h"
00014 
00015 void sslerr1(cli_conn * client);
00016 void sslerr2(char * file, int line);
00017 
00018 int verify_client = ON; 
00020 /* Crea una connessione SSL (server-side) sopra una connessione TCP */
00021 srvSkSSL * newSSLServerChannel(const char *service){
00022         srvSkSSL * server = NULL;
00023         
00024         if (!service) {
00025                 errno = EINVAL;
00026                 sys_err(__FILE__,__LINE__,"Server: Error 'service' nullo.");
00027                 return NULL;
00028         }
00029 
00030         if (!(server = calloc(1, sizeof(srvSkSSL)))) {
00031                 sys_err(__FILE__,__LINE__,"Server: Error calloc 'server'");
00032                 return NULL;
00033         }
00034 
00035         if (!(server->srvSk = newServerChannel(service))) {
00036                 free (server);
00037                 return NULL;
00038         }
00039 
00040 #ifdef _DEBUG_MODE
00041         /* Load the error strings for SSL & CRYPTO APIs */
00042         SSL_load_error_strings();       /* ? valgrind ? */
00043 #endif
00044 
00045         /* Load encryption & hashing algorithms for the SSL program */
00046         SSL_library_init();                     /* ? valgrind ? */
00047 
00048         /* Create a SSL_CTX structure and
00049          * create a SSL_METHOD structure (choose a SSL/TLS protocol version) */
00050         server->ctx = SSL_CTX_new(SSLv3_method());
00051 
00052         if (!server->ctx){
00053                 sslerr2(__FILE__,__LINE__); free (server); return NULL;
00054         }
00055 
00056         /* Load the server certificate into the SSL_CTX structure */
00057         if (SSL_CTX_use_certificate_file(server->ctx, RSA_SERVER_CERT, SSL_FILETYPE_PEM) <= 0) {
00058                 sslerr2(__FILE__,__LINE__);
00059                 closeServerSocket(server->srvSk);
00060                 free (server);
00061                 return NULL;
00062         }
00063 
00064         /* Load the private-key corresponding to the server certificate */
00065         if (SSL_CTX_use_PrivateKey_file(server->ctx, RSA_SERVER_KEY, SSL_FILETYPE_PEM) <= 0) {
00066                 sslerr2(__FILE__,__LINE__);
00067                 closeServerSocket(server->srvSk);
00068                 free (server);
00069                 return NULL;
00070         }
00071 
00072         /* Check if the server certificate and private-key matches */
00073         if (!SSL_CTX_check_private_key(server->ctx)){
00074                 sys_err(__FILE__,__LINE__,"Server: Private key does not match the certificate public key");
00075                 closeServerSocket(server->srvSk);
00076                 free (server);
00077                 return NULL;
00078         }
00079 
00080         if (verify_client == ON){
00081                 /* Load the RSA CA certificate into the SSL_CTX structure */
00082                 if (!SSL_CTX_load_verify_locations(server->ctx, RSA_SERVER_CA_CERT, NULL)) {
00083                         sslerr2(__FILE__,__LINE__);
00084                         closeServerSocket(server->srvSk);
00085                         free (server);
00086                         return NULL;
00087                 }
00088                 /* Set to require peer (client) certificate verification */
00089                 SSL_CTX_set_verify(server->ctx,SSL_VERIFY_PEER,NULL);
00090                 /* Set the verification depth to 1 */
00091                 SSL_CTX_set_verify_depth(server->ctx,1);
00092         }
00093         return server;
00094 }
00095 
00096 /* Accetta una connessione da parte di un client e ritorna il
00097  * descrittore del canale di trasmissione con il client */
00098 cli_conn * acceptSSLConnection(srvSkSSL * server){
00099         int               cli_sk = 0, err = 0;
00100 #ifdef _DEBUG_MODE
00101         X509            * client_cert = NULL;
00102         char            * str = NULL;
00103 #endif
00104         cli_conn        * client = NULL;
00105 
00106         /* In caso di errore la acceptConnection ritorna -1 */
00107         if ((cli_sk =  acceptConnection(server->srvSk)) == -1){
00108                 sys_err(__FILE__,__LINE__,"Server: acceptSSLConnection");
00109                 return NULL;
00110         }
00111 
00112         if (!(client = calloc(1, sizeof(cli_conn)))){
00113                 sys_err(__FILE__,__LINE__,"Server: acceptSSLConnection 'calloc'");
00114                 return NULL;
00115         }
00116         client->socket = cli_sk;
00117 
00118         /* A SSL structure is created */
00119         client->ssl = SSL_new(server->ctx);
00120         if (!client->ssl){
00121                 sys_err(__FILE__,__LINE__,"Server: Error on create new SSL ctx");
00122                 sslerr2(__FILE__,__LINE__);
00123                 free (client);
00124                 return NULL;
00125         }
00126 
00127         /* Assign the socket into the SSL structure (SSL and socket without BIO) */
00128         SSL_set_fd(client->ssl, cli_sk);
00129 
00130         /* Perform SSL Handshake on the SSL server */
00131         if ((err = SSL_accept(client->ssl)) == -1){
00132                 sslerr2(__FILE__,__LINE__);
00133                 free (client);
00134                 return NULL;
00135         }
00136 
00137 #ifdef _DEBUG_MODE
00138         /* Informational output (optional) */
00139         printf("Server: connessione SSL %s\n", SSL_get_cipher (client->ssl));
00140 
00141         if (verify_client == ON){
00142                 /* Get the client's certificate (optional) */
00143                 client_cert = SSL_get_peer_certificate(client->ssl);
00144                 if (client_cert != NULL){
00145                         printf ("Client certificate:\n");
00146                         str = X509_NAME_oneline(X509_get_subject_name(client_cert), 0, 0);
00147                         if (str == NULL){
00148                                 free (client);
00149                                 return NULL;
00150                         }
00151                         printf ("\t subject: %s\n", str);
00152                         free (str);
00153                         str = X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0);
00154                         if (str == NULL){
00155                                 free (client);
00156                                 return NULL;
00157                         }
00158                         printf ("\t issuer: %s\n", str);
00159                         free (str);
00160                         X509_free(client_cert);
00161                 }
00162                 else
00163                         printf("Server: The SSL client does not have certificate.\n");
00164         }
00165 #endif
00166 
00167         return client;
00168 }
00169 
00170 /* Scrive un messaggio sul canale di trasmissione rispettando
00171  * la struttura che contiene il messaggio da scrivere  */
00172 int sendSSLMessage(cli_conn * client, message_t *msg){
00173         int char_sent = 0, sent = 0;
00174 
00175         if ((sent = SSL_write(client->ssl, &(msg->type), sizeof(char))) < 0){
00176                 sys_err(__FILE__,__LINE__,"Error send message 'type'");
00177                 sslerr1(client);
00178                 return -1;
00179         }
00180         char_sent = sent;
00181 
00182         if ((sent = SSL_write(client->ssl, &(msg->length), sizeof(unsigned int))) < 0){
00183                 sys_err(__FILE__,__LINE__,"Error send message 'length'");
00184                 sslerr1(client);
00185                 return -1;
00186         }
00187         char_sent += sent;
00188 
00189         if (msg->length!=0){
00190                 if ((sent = SSL_write(client->ssl, msg->buffer, msg->length)) < 0){
00191                         sys_err(__FILE__,__LINE__,"Error send message 'buffer' ");
00192                         sslerr1(client);
00193                         return -1;
00194                 }
00195                 char_sent += sent;
00196         }
00197         return char_sent;
00198 }
00199 
00200 /* Legge un messaggio dal canale di trasmissione */
00201 int receiveSSLMessage(cli_conn * client, message_t *msg){
00202         int ricevuti=0, tmp_cnt=0, read_cnt=0;
00203         char * buffer = NULL;
00204 
00205         /* Se la struttura del messaggio non e' allocata.. */
00206         if (!msg && !(msg = calloc(1, sizeof(message_t)))){
00207                 sys_err(__FILE__,__LINE__,"Error calloc 'msg': ");
00208                 return -1;
00209         }
00210 
00211         /* Leggo il tipo del messaggio */
00212         if ((ricevuti = SSL_read(client->ssl, &(msg->type), sizeof(char))) < 0){
00213                 sys_err(__FILE__,__LINE__,"Error read message 'type': ");
00214                 sslerr1(client);
00215                 return -1;
00216         }
00217         read_cnt = ricevuti;
00218 
00219         /* Leggo la dimensione del messaggio */
00220         if ((ricevuti = SSL_read(client->ssl, &(msg->length), sizeof(unsigned int))) < 0){
00221                 sys_err(__FILE__,__LINE__,"Error read message 'length': ");
00222                 sslerr1(client);
00223                 return -1;
00224         }
00225         read_cnt += ricevuti;
00226 
00227         /* Leggo il messaggio reale */
00228         if (msg->length!=0){
00229                 if (!(buffer = calloc(msg->length+1, sizeof(char)))){
00230                         sys_err(__FILE__,__LINE__,"Error calloc 'buffer': ");
00231                         return -1;
00232                 }
00233                 if (!(msg->buffer = calloc(msg->length+1, sizeof(char)))){
00234                         sys_err(__FILE__,__LINE__,"Error calloc 'msg->buffer': ");
00235                         return -1;
00236                 }
00237                 while(tmp_cnt < msg->length){
00238                         if ((ricevuti = SSL_read(client->ssl, buffer, msg->length-tmp_cnt)) < 0){
00239                                 sys_err(__FILE__,__LINE__,"Error read message 'buffer': ");
00240                                 sslerr1(client);
00241                                 return -1;
00242                         }
00243                         tmp_cnt += ricevuti;
00244                         if (ricevuti > 0) strncat (msg->buffer, buffer, ricevuti);
00245                 }
00246                 free (buffer);
00247                 read_cnt += tmp_cnt;
00248         }
00249         return read_cnt;
00250 }
00251 
00252 /* Chiude e distrugge la socket di ascolto del server */
00253 int closeSSLServerSocket(srvSkSSL * server){
00254         if (!server) return 0;
00255 
00256         /* Liberiamo la struttura del contesto SSL */
00257         if (server->ctx) SSL_CTX_free (server->ctx);
00258         if (server->srvSk) closeServerSocket(server->srvSk);
00259         free (server);
00260         server = NULL;
00261         return 0;
00262 }
00263 
00264 /* Chiude e distrugge una socket (client) */
00265 int closeSSLConnection(cli_conn * client){
00266         if (!client) return 0;  /* Puntatore nullo, ritorno */
00267 
00268         if (client->ssl){
00269                 SSL_shutdown (client->ssl);
00270                 SSL_free (client->ssl);
00271         }
00272         if (client->ctx) SSL_CTX_free (client->ctx);
00273         if (client->socket) closeConnection(client->socket);
00274         free (client);
00275         client = NULL;
00276         return 0;
00277 }
00278 
00279 void unloadSSL(){
00280         /* Ma quanta merda !!! */
00281         ERR_remove_state(0);
00282         EVP_cleanup();                                  /* Thread unsafe */
00283         CRYPTO_cleanup_all_ex_data();   /* Thread unsafe */
00284         ERR_free_strings();
00285         /*sk_SSL_COMP_free (SSL_COMP_get_compression_methods());*/
00286 }
00287 
00288 /* Stabilisce una connessione usando un layer SSL */
00289 cli_conn * retrySSLConnection(const char * hostname, const char * portno){
00290         cli_conn        * client = NULL;
00291 #ifdef _DEBUG_MODE
00292         X509            * server_cert;
00293         char            * str = NULL;
00294 #endif
00295 
00296         if (!hostname){
00297                 errno = EINVAL;
00298                 sys_err(__FILE__,__LINE__,"Server: retrySSLConnection 'hostname' nullo.");
00299                 return NULL;
00300         }
00301         if (!portno){
00302                 errno = EINVAL;
00303                 sys_err(__FILE__,__LINE__,"Server: retrySSLConnection 'portno' nullo.");
00304                 return NULL;
00305         }
00306 
00307         if (!(client = calloc(1, sizeof(cli_conn)))){
00308                 sys_err(__FILE__,__LINE__,"Client: Error calloc 'client': ");
00309                 return NULL;
00310         }
00311 
00312         client->socket = retryConnection(hostname, portno);
00313         if (client->socket == -1) return NULL;
00314 
00315 #ifdef _DEBUG_MODE
00316         /* Register the error strings for libcrypto & libssl
00317          * Se la memoria e' un problema.. allora e' bene evitare. */
00318         SSL_load_error_strings();
00319 #endif
00320 
00321         /* Register the available ciphers and digests */
00322         SSL_library_init();                     /* ? valgrind ? */
00323 
00324         /* New context saying we are a client, and using SSL 2 or 3 */
00325         client->ctx = SSL_CTX_new(SSLv3_method());
00326         if (!client->ctx){
00327                 sys_err(__FILE__,__LINE__,"Client: Error on create new SSL ctx");
00328                 sslerr2(__FILE__,__LINE__); free (client); return NULL;
00329         }
00330 
00331         if (verify_client == ON){
00332                 /* Load the client certificate into the SSL_CTX structure */
00333                 if (SSL_CTX_use_certificate_file(client->ctx, RSA_CLIENT_CERT, SSL_FILETYPE_PEM) <= 0) {
00334                         sslerr2(__FILE__,__LINE__);
00335                         close(client->socket);
00336                         free (client);
00337                         return NULL;
00338                 }
00339 
00340                 /* Load the private-key corresponding to the client certificate *//* ? valgrind ? */
00341                 if (SSL_CTX_use_PrivateKey_file(client->ctx, RSA_CLIENT_KEY, SSL_FILETYPE_PEM) <= 0) {
00342                         sslerr2(__FILE__,__LINE__);
00343                         close(client->socket);
00344                         free (client);
00345                         return NULL;
00346                 }
00347 
00348                 /* Check if the client certificate and private-key matches */
00349                 if (!SSL_CTX_check_private_key(client->ctx)){
00350                         sys_err(__FILE__,__LINE__,"Client: Private key does not match the certificate public key");
00351                         close(client->socket);
00352                         free (client);
00353                         return NULL;
00354                 }
00355         }
00356 
00357         /* Load the RSA CA certificate into the SSL_CTX structure
00358          * This will allow this client to verify the server's
00359          * certificate. */
00360         if (!SSL_CTX_load_verify_locations(client->ctx, RSA_CLIENT_CA_CERT, NULL)){
00361                 close(client->socket);
00362                 sslerr2(__FILE__,__LINE__);
00363                 free (client);
00364                 return NULL;
00365         }
00366 
00367         /* Set flag in context to require peer (server) certificate
00368          * verification */
00369         SSL_CTX_set_verify(client->ctx,SSL_VERIFY_PEER,NULL);
00370         SSL_CTX_set_verify_depth(client->ctx,1);
00371 
00372         /* Create an SSL struct for the connection */
00373         client->ssl = SSL_new(client->ctx);
00374         if (!client->ssl){
00375                 sslerr2(__FILE__,__LINE__);
00376                 close(client->socket);
00377                 free (client);
00378                 return NULL;
00379         }
00380 
00381         /* Connect the SSL struct to our connection */
00382         if (!SSL_set_fd(client->ssl, client->socket)){
00383                 sslerr2(__FILE__,__LINE__);
00384                 close(client->socket);
00385                 free (client);
00386                 return NULL;
00387         }
00388 
00389         /* Initiate SSL handshake */
00390         if (SSL_connect(client->ssl) != 1){
00391                 sslerr2(__FILE__,__LINE__);
00392                 close(client->socket);
00393                 free (client);
00394                 return NULL;
00395         }
00396 
00397 #ifdef _DEBUG_MODE
00398         /* Informational output (optional) */
00399         printf ("SSL connection using %s\n", SSL_get_cipher(client->ssl));
00400 
00401         /* Get the server's certificate (optional) */
00402         server_cert = SSL_get_peer_certificate(client->ssl);
00403 
00404         if (server_cert != NULL){
00405                 printf ("Server certificate:\n");
00406 
00407                 if (!(str = X509_NAME_oneline(X509_get_subject_name(server_cert),0,0))){
00408                         sys_err(__FILE__,__LINE__,"Client: 'X509_get_subject_name'");
00409                         close(client->socket);
00410                         free (client);
00411                         return NULL;
00412                 }
00413                 printf ("\t subject: %s\n", str);
00414                 free (str);
00415 
00416                 if (!(str = X509_NAME_oneline(X509_get_issuer_name(server_cert),0,0))){
00417                         sys_err(__FILE__,__LINE__,"Client: 'X509_get_iusser_name'");
00418                         close(client->socket);
00419                         free (client);
00420                         return NULL;
00421                 }
00422                 printf ("\t issuer: %s\n", str);
00423                 free(str);
00424                 X509_free (server_cert);
00425         }
00426         else
00427                 printf("The SSL server does not have certificate.\n");
00428 #endif
00429 
00430         return client;
00431 }
00432 
00433 /*__________________________________________________________________________ */
00434 
00435 #ifdef _DEBUG_MODE
00436 
00437 void sslerr1(cli_conn * client){
00438         int err = 0;
00439         fprintf(stderr,"SSL error number %i\n", SSL_get_error(client->ssl, err));
00440         ERR_print_errors_fp(stderr);
00441 }
00442 
00443 void sslerr2(char * file, int line){
00444         fprintf(stderr,"Errore file %s, linea %d\n", file, line-1);
00445         ERR_print_errors_fp(stderr);
00446 }
00447 
00448 #else
00449 
00450 void sslerr1(cli_conn * client){}
00451 
00452 void sslerr2(char * file, int line){}
00453 #endif
00454