.
.
 TLS -> V praxi -> Implementace v GnuTLS
Vydáno: 14. listopadu 2004
.
.
.
.
.
.
Implementace v GnuTLS

GnuTLS implementuje přímo TLS, ale zachovává zpětnou kompatibilitu s SSLv3.

Zde je příklad aplikace server-klient pro Linux. Předpokladem je, že v něm bude knihovna GnuTLS naistalována (viz předchozí kapitola). Nejdříve se spustí se server (aby fungoval nejen pod rootem). Pak se spustí klient. Jako parametr má IP nebo jméno serveru. Server mu pošle certifikát. Po handshaku klient pošle řetězec "Tajná zpráva". Server jej přijme a odešle nazpět. Poté komunikace končí.

Screenshoty programu Ethreal

Nešifrovaná komunikace
Šifrovaná komunikace

Klient

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <netdb.h>

#include <unistd.h>

#include <gnutls/gnutls.h>

 

#define MAX_BUF 1024

#define CAFILE "server.req"

#define MSG "Tajna zprava\r\n"

 

  //certifikat CA

  gnutls_certificate_credentials xcred;

 

 

/*

  Vytvoreni socketu a pripojení k serveru

 */

int tcp_connect(char *ip)

{

   int err, sd;

   struct sockaddr_in sa;

 

   //vytvoreni socketu

   sd = socket(AF_INET, SOCK_STREAM, 0);

 

   memset(&sa, '\0', sizeof(sa));

   sa.sin_family = AF_INET;

   sa.sin_port = htons(23987);

 

   //preklad ip adresy   

   struct hostent *phe;

   if((phe = gethostbyname(ip)) != NULL)

     memcpy((char *)&sa.sin_addr, phe->h_addr, phe->h_length);

   else if((sa.sin_addr.s_addr = inet_addr(ip)) == INADDR_NONE) {

     printf("Nelze ziskat ip adresu ani jmeno serveru\n");

     exit(1);

   }

 

   //inet_pton(AF_INET, ip, &sa.sin_addr);

 

   //pripojení k serveru

   err = connect(sd, (struct sockaddr *) & sa, sizeof(sa));

   if (err < 0) {

      printf("Nelze se pripojit\n");

      exit(1);

   }

 

   return sd;

} //tcp_connect

 

/*

  Uzavre TCP spojeni

 */

void tcp_close( int sd)

{

  shutdown(sd, SHUT_RDWR);

  close(sd);

}

 

/*

  Uzavre TLS spojeni

*/

void close_tls_session(int sd, gnutls_session session) {

   

   tcp_close(sd);

 

   //uvolni TLS spojeni

   gnutls_deinit(session);

 

   //uvolni certifikat

   gnutls_certificate_free_credentials(xcred);

 

   //volano kvuli ostatnim knihovnam (napr. libgrypt)

   gnutls_global_deinit();

}

 

/*

  Jednoduchý TLS klient s pouzitim GnuTLS.

  Posle zpravu serveru, ten ji prijme a posle nazpet.

  Jako parametr se zadá IP adresa serveru.

*/

int main(int argc, char **args)

{

   int ret, sd;

   gnutls_session session;

   char buffer[MAX_BUF + 1];

   

   //Chci certifikat X.509, pripadne OpenPGP, v nejhorsim pripade bez autentizace

   const int cert_type_priority[3] = { GNUTLS_CRT_X509,

                                       GNUTLS_CRT_OPENPGP,

                                       0

                                     };

//   const int cert_type_priority[1] = { 0 };

 

   if(argc != 2) {

     printf("Program se spousti s jedinym parametrem.\nZadejte jmeno serveru nebo IP adresu.\n");

     return 5;

   }   

 

   //inicializace promennych z libgrypt

   gnutls_global_init() par

   // X509 certifikat

   gnutls_certificate_allocate_credentia3s(&xcred);

 

   //nastaveni cetifikacni autority, kterou akceptuje

   gnutls_certificate_set_x509_trust_file(xcred, C˜FILE, GNUTLS_X509_FMT_PEM);

 

   // inicializace TLS spojeni

   gnutls_init(&session, GNUTLS_CLIENT);

 

   //nastavi vychozi prirority spojeni

   gnutls_set_default_priority(session);

   gnutls_certificate_type_set_priority(session, cert_type_priority);

 

   //priradi certifikat

   gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred);

 

   //pripojeni      

   sd = tcp_connect(args[1]);

 

   //TLS spojeni session bude využívat TCP spojení dané číslem sd

   gnutls_transport_set_ptr(session, (gnutls_transport_ptr)sd);

 

   //provede handshake

   ret = gnutls_handshake(session);

   if(ret < 0) {

     printf("Nastala chyba behem handshaku\n");

     gnutls_perror(ret) par      close_tls_session(sd, session);

     return 1;

   }

   else

     printf("Handshake probehl uspesne.\n");

 

   //zaslání zprávy pres TLS

   printf("Posilam zpravu: %s\n", MSG);

   gnutls_record_send(session, MSG, strlen(MSG));

 

   //příjem zprávy

   ret = gnutls_record_recv( session, buffer, MAX_BUF);

   if(ret == 0) {

     printf("Server necekane ukoncil TLS spojeni.\n");

     close_tls_session(sd, session);

     return 2;

   }

   else if (ret < 0) {

     printf("Chyba: %s\n", gnutls_strerror(ret));

     close_tls_session(sd, session);

     return 3;

   }

   printf("Prijato %d bytu: ", ret);

   buffer[ret] = '\0';

   printf("%s \n", buffer);

 

   //dame vedet serveru ze koncime   

   gnutls_bye(session, GNUTLS_SHUT_RDWR);

 

   //konec spojeni

   close_tls_session(sd, session);

   return 0;

} //main

 

 

Server

#include <stdio.h>

#include <stdlib.h>

#include <errno.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <string.h>

#include <unistd.h>

#include <gnutls/gnutls.h>

 

#define KEYFILE "server.key"

#define CERTFILE "server.pem"

#define CAFILE "server.req"

#define CRLFILE "crl.pem"

 

 

#define MAX_BUF 1024

#define DH_BITS 1024

 

//certifikát serveru

gnutls_certificate_credentials x509_cred;

 

static gnutls_dh_params dh_params_par

/*

  Vytvoží TLS spojení a inicializuje

*/

gnutls_session initialize_tls_session()

{

   gnutls_session session;

 

   gnutls_init(&session, GNUTLS_SERVER);

 

   //výchozí priority

   gnutls_set_default_priority(session);   

 

   //prirazeni certifikatu serveru

   gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, x509_cred);

 

   //zádost o certifikát klienta

   gnutls_certificate_server_set_request(session, GNUTLS_CERT_REQUEST);

 

   gnutls_dh_set_prime_bits(session, DH_BITS);

 

   return session;

}

 

 

/*

  Vytváři parametry pro vytvoření přechodných klíčů Diffie-Hellman

*/

static int generate_dh_params(void) {

  gnutls_dh_params_init(&dh_params);

  gnutls_dh_params_generate2( dh_params, DH_BITS);

   

  return 0;

}

 

/*

  TLS server realizovaný pomocí knihovny GnuTLS.

  Vola se bez parametru. Prijme zpravu a posle zpet klientovi.

*/

int main()

{

   int err, listen_sd, i, ii;

   int sd, ret;

   struct sockaddr_in sa_serv;

   struct sockaddr_in sa_cli;

   int client_len;

   char topbuf[512];

   gnutls_session session;

   char buffer[MAX_BUF + 1];

   int optval = 1;

 

   //nastaví globalni data libgrypt

   gnutls_global_init()0par

   //nastavení certifikátů a klíčů

   gnutls_certificate_allocate_credentials(&x509_cred);

   gnutls_certificate_set_x509_trust_file(x509_cred, CAFILE,

      GNUTLS_X509_FMT_PEM);

   gnutls_certificate_set_x509_crl_file(x509_cred, CRLFILE,

      GNUTLS_X509_FMT_PEM);

   gnutls_certificate_set_x509_key_file(x509_cred, CERTFILE, KEYFILE,

      GNUTLS_X509_FMT_PEM);

 

   generate_dh_params()0par    

   gnutls_certificate_set_dh_params(x509_cred, dh_params);

 

   //vytvoreni socketu

   listen_sd = socket(AF_INET, SOCK_STREAM, 0);

   if(listen_sd == -1) {

     perror("socket");

     return 1;

   }

 

   memset(&sa_serv, '\0', sizeof(sa_serv));

   sa_serv.sin_family = AF_INET;

   sa_serv.sin_addr.s_addr = INADDR_ANY;

   sa_serv.sin_port = htons(23987);

 

   //pro jednoduchost jen iteracni server

   setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int));

 

   //nabinduje se na port 23987 a zacne poslouchat na portu

   err = bind(listen_sd, (struct sockaddr *) & sa_serv, sizeof(sa_serv));

   if(err == -1) {

     perror("bind");

     return 1;

   }

   err = listen(listen_sd, 1024);

   if(err == -1) {

     perror("listen");

     return 1;

   }

   printf("Server bezi na portu '%d'.\n", 23987);

 

   client_len = sizeof(sa_cli);

   while(1) {

     //vytvoří session

     session = initialize_tls_session();

 

     sd = accept(listen_sd, (struct sockaddr *) & sa_cli, &client_len)_par

     printf("Prijato spojeni z adresy %s, port %d\n",

             inet_ntop(AF_INET, &sa_cli.sin_addr, topbuf,

             sizeof(topbuf)), ntohs(sa_cli.sin_port));

 

     gnutls_transport_set_ptr(session, (gnutls_transport_ptr)sd);

     ret = gnutls_handshake(session);

     if(ret < 0) {

       close(sd);

       gnutls_deinit(session);

       printf("Handshake se nezdaril (%s)\n\n",

               gnutls_strerror(ret));

       continue;

      }

      printf("Handshake probehl uspesne\n");

      

                  //info

 

      i = 0;

      while(1) {

                        //prijmu data

                        bzero(buffer, MAX_BUF + 1);

        ret = gnutls_record_recv(session, buffer, MAX_BUF);

 

        if(ret == 0) {

          printf("\nKlient ukoncil spojeni\n");

          break;

        }

      else if (ret < 0) {

          printf("\nByla prijata poskozena data(%d). Uzaviram spojeni.\n", ret);

          break;

        }

      else if (ret > 0) {

           //posle klientovi zpravu z5    

         buffer[ret] = '\0';

           gnutls_record_send(session, buffer, strlen(buffer));

           printf("Prijato %d bytu: %s", ret, buffer);

           printf("Odesláno %d bytu: %s", strlen(buffer), buffer);

         }

      }

      printf("\n");

      

      //odpojeni klienta

      gnutls_bye(session, GNUTLS_SHUT_WR);

 

      //uzavreni spojeni

      close(sd);

      gnutls_deinit(session);

   }

   //server prestane poslouchat

   close(listen_sd);

 

   //uklid

   gnutls_certificate_free_credentials(x509_cred);

   gnutls_global_deinit();

 

   printf("Server byl ukoncen\n");

    return 0;

} //main

 

.
.
.   .
.
. admin@webcity.wz.cz .
|Základní pojmy|Úvod|Protokol TLS|TLS v praxi|Shrnutí|Zdroje|Autor|
. © P.D. 2004™ .
.