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

U OpenSSL je vidět, že jsou rozdíly mezi psaním aplikace TLS a SSL jsou minimální.

Zde je příklad aplikace server-klient pro Linux. Předpokladem je, že v něm bude knihovna OpenSSL 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čí.

Klient

#include <openssl/ssl.h>

#include <openssl/err.h>

#include <sys/socket.h>

#include <netdb.h>

#include <errno.h>

#include <string.h>

#include <unistd.h>

 

  int sock;

  struct sockaddr_in sock_addr;

  char data[1024+1];

  int len;

  SSL_CTX *ssl_ctx;

  SSL *tls;

  char str[10],*name;

  X509 *cert;

 

/*

  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);

   }

 

   //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

 

 

  /*

    TLS klient realizovany pomoci OpenSSL.

    Klient se spousti s jedinym parametrem ip nebo jmeno serveru.

  */

  int main(int argc, char** args)

  {

   if(argc != 2) {

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

     return 5;

   }  

 

    SSL_load_error_strings();

    SSLeay_add_ssl_algorithms();

   

    //bude to TLS klient

    if(!(ssl_ctx = SSL_CTX_new(TLSv1_client_method()))) {

      ERR_print_errors_fp(stderr);

      return 1;

    }

 

    //pripojeni

    sock = tcp_connect(args[1]);

 

    //priprava na handshake

    if(!(tls = SSL_new(ssl_ctx))) {

      ERR_print_errors_fp(stderr);

      return 1;

    }

    //spojeni socketu se tls

    if(!SSL_set_fd(tls, sock)) {

      ERR_print_errors_fp(stderr);

      return 1;

    }

    //provedeni handshaku

    if(SSL_connect(tls) != 1) {

      ERR_print_errors_fp(stderr);

      return 1;

    }

 

    //info o serveru 

    printf("Pouzita sifra %s\n", SSL_get_cipher(tls));

    if(!(cert = SSL_get_peer_certificate(tls))) {

      printf("Server neposlal certifikat\n");

      ERR_print_errors_fp(stderr);

    }

    else {

      if((name = X509_NAME_oneline(X509_get_subject_name(cert),0,0))) {

        printf("Certifikat serveru: %s\n",name);

        free(name);

      }

      X509_free(cert);

    }

   

    //odeslu zpravu

    strcpy(str, "Tajna zprava\r\n");

    len = strlen(str);

    printf("Odesilam %d bytu: %s ", len, str);       

    if(SSL_write(tls, str,len) != len) {

      ERR_print_errors_fp(stderr);

      return 1;

    }

 

    //prijmu zpravu

    if ((len = SSL_read(tls, data, 1024)) <= 0) {

      ERR_print_errors_fp(stderr);

      return 1;

    }

    data[len]=0;

    //vypisu

    printf("Prijmuto %d bytu: %s", len, data);       

 

    //uklid

    SSL_free(tls);

    close(sock);

  } //main

 

Server

#include <openssl/ssl.h>

#include <openssl/err.h>

#include <sys/socket.h>

#include <netdb.h>

#include <errno.h>

#include <string.h>

#include <unistd.h>

 

  int sock,csock;

  struct sockaddr_in sock_addr, csock_addr;

  socklen_t csock_addr_len;

  char buf[1024+1];

  int len, so=1;

  SSL_CTX *ssl_ctx;

  SSL *tls;

 

 

/*

  TLS server realizovany pomocí OpenSSL.

  Spousti se bez prametru

*/

  int main(void)

  {

    //priprava   

    SSL_load_error_strings();

    SSLeay_add_ssl_algorithms();

   

    //bude to TLS server

            if (!(ssl_ctx = SSL_CTX_new(TLSv1_server_method()))) {

      ERR_print_errors_fp(stderr);

      return 1;

    }

 

    //nactu klice a certifikaty    

    if (SSL_CTX_use_certificate_file(ssl_ctx, "server.pem", SSL_FILETYPE_PEM) <= 0) {

      ERR_print_errors_fp(stderr);

      return 1;

    }

    if (SSL_CTX_use_PrivateKey_file(ssl_ctx, "server.key", SSL_FILETYPE_PEM) <= 0) {

      ERR_print_errors_fp(stderr);

      return 1;

    }

    if (!SSL_CTX_check_private_key(ssl_ctx)) {

      printf("Privatni klic neopovida certifikatu\n");

      return 1;

    }

 

    //otevru socket

    if ((sock = socket(PF_INET, SOCK_STREAM, 0)) == -1) {

      printf("Nelze vytvorit socket.\n");

      return 1;

    }

    //nastavim vlastnosti socketu

    so = 1;

    if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&so, 4) == -1) {

      printf("Nelze nastavit vlastnosti socketu.\n");

      return 1;

    }

 

    sock_addr.sin_family = AF_INET;

    sock_addr.sin_addr.s_addr = INADDR_ANY;

    sock_addr.sin_port=htons(23987);

 

    //na socket napojim server   

    if(bind(sock, (struct sockaddr*)&sock_addr, sizeof(struct sockaddr_in)) == -1) {

      printf("Socket nelze spojit s portem\n");

      return 1;

    }

    //server zacne poslouchat

    if(listen(sock, 10) == -1) {

      printf("Server nemuze poslouchat na zadanem portu.\n");

      return 1;

    }

   

    printf("Server bezi na portu 23987...\n");

    while(1) {

      //prislo spojeni

      if((csock = accept(sock, (struct sockaddr*)&csock_addr, &csock_addr_len)) == -1) {

        printf("Nelze prijmout spojeni.\n");

        return 1;

      }

 

      //priprava na Handshake

      if (!(tls = SSL_new(ssl_ctx))) {

        ERR_print_errors_fp(stderr);

        return 1;

      }

      //ssl spojeni svazu s prijatym socketem

                  if (!SSL_set_fd(tls, csock)) {

        ERR_print_errors_fp(stderr);

        return 1;

      }

     

                  //provedeni handshaku

      if (SSL_accept(tls)!=1) {

        ERR_print_errors_fp(stderr);

        close(csock);

        continue;

      }  

   

      //prijmu zpravu od klienta

      if((len = SSL_read(tls, buf, 1024)) <= 0) {

        ERR_print_errors_fp(stderr);

        close(csock);

        continue;

      }

     

      buf[len]=0;

      printf("Prijato: %s\n", buf, len);

 

      //odeslu nazpet

      printf("Odesilam: %s\n", buf, strlen(buf));

      if((len = SSL_write(tls, buf, strlen(buf))) <= 0) {

        ERR_print_errors_fp(stderr);

      }

    }

    //uklid

    SSL_free(tls);

    close(sock);

 

    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™ .
.