SSLeay

Vývojové prostředí pro SSL označované jako SSLref je možné získat u firmy Netscape. Díky exportním umezením USA a Kanady je omezen export tohoto software. Na serveru v Austrálii  ftp://ftp.psy.uq.edu.au/pub/Crypto/SSL/  se objevil free ekvivalent tohoto software pod názvem SSLeay (bližší informace na http://www.psy.uq.edu.au/~ftp/Crypto). Navíc SSLeay nemá žádná omezení ani na délku šifrovacích klíčů. Pokud si vyvinete vlastní software  v tomto prostředí nebo pou6ijete software vyvinutý na bázi SSLeay, pak při šifrování např. algoritmem IDEA a 128 bitovým klíčem se netřeba asi ničeho obávat. Jsou tam též informace o HTTPS serverech Apache a NCSA httpd a o klientech Mosaic přepracovaných za využití SSLeay, tj. umožnujících celosvětově používat dlouhé klíče.

Dále jsou tam informace i o software vyvinutém na SSLeay pro ostatní aplikační protokoly (TELNET, FTP,...). Software pro TELNET přes SSL lze nalézt na  http://www.psy.uq.edu.au/~ftp/Crypto/telnet.html. Software pro RSH přes SSL lze např. nalézt na  http://www.quick.com.au/ftp/pub/sjg/ .

Obdobně jako existuje neamerická verze SSLref existuje i neamerická verze pro SETref (protokol SET vychází částečně ze SSL, ale je určen zejména pro elektronický obchod). Vývojové verze aplikačního programového interface (API) pro SETref je obtížné získat, ale neamerická verze označovaná jako BSAFEeay je vystavena na   https://www.cypherpunks.to/  Tentokráte už ani nemá tento server   asijsko-pacifickou IP-adresu, jak by se dalo usuzovat z top level domény TO, ale evropskou (TO odpovídá republice Tonga, která leží severně od Nového Zélandu).

SSLeay obsahuje jednak API, ale také některé hotové programy. Hotové programy jsou určeny zejména pro tvorbu skriptů nebo samostatně jako pomocné utility.
 

SSLeay API

 Zopakujeme si klasické schéma programování pomocí socketů (tj. "bez SSL"):


 
Kde:

Knihovny SSLeay toto schéma rozšiřují:


 
Kde:
 
void SSL_load_error_strings(void) inicializuje obsluhu chyb
SSL_CTX  *SSL_CTX_new(void) alokuje strukturu SSL_CTX, která bude obsahovat parametry SSL-relace, tzv. context structure (CTX)
SSL *SSL_new(SSL_CTX *ssl_ctx) inicializuje strukturu SSL_CTX ("inicializuje kontext relace")
void SSL_free(SSL *s) deinicialaizuje kontext relace
void SSL_CTX_free (SSL_CTX* ctx) dealokuje paměť struktury kontextu relace
int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, char *file, int type)  specifikuje soubor s privátními klíči. Při otevírání tohoto souboru je uživatel dotázán na přístupové heslo (pass phrase). Pomocí PEM_set_getkey_callback() lze tento dotaz obejít
int SSL_CTX_use_certificate_file(SSL_CTX *ctx, char *file, int type) specifikuje soubor s certifikáty
void SSL_set_fd(SSL *s, int fd) přiřazení SSL-relace ke konkrétnímu TCP-spojení. 
int SSL_accept(SSL *s) server bude očekávat spojení od klienta
int SSL_connect(SSL *s) klient navazuje SSL-relaci
read() a write() jsou nahrazeny: 
  • int SSL_read(SSL *s,char *buf,int len) příjem dat (obdoba čtení ze souboru)
  • int SSL_write(SSL *s,char *buf,int len) odesílání dat (obdoba zápisu do souboru)
Součástí distribuce jsou i jednoduché v C++ vytvořené  příklady klienta i serveru. Následující  příklady jsou  převzaty z   ftp://ftp.psy.uq.edu.au/pub/Crypto/SSL/. Jedná se o jednoduchého klienta, který  na server odesílá řetězec "Hello World!" a server jej pošle zpět. (Abych nemohl být podezírán z porušení autorských práv, tak jem v příkladech  ani kometáře nepřeložil do češtiny, jediné co jsem tam vložil jen formátování v jazyce HTML.)
 
/* cli.cpp  -  Minimal ssleay client for Unix 
   30.9.1996, Sampo Kellomaki <sampo@iki.fi> */ 

#include <stdio.h> 
#include <memory.h> 
#include <errno.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <netdb.h> 

#include "rsa.h"       /* SSLeay stuff */ 
#include "crypto.h" 
#include "x509.h" 
#include "pem.h" 
#include "ssl.h" 
#include "err.h" 

#define CHK_NULL(x) if ((x)==NULL) exit (1) 
#define CHK_ERR(err,s) if ((err)==-1) { perror(s); exit(1); } 
#define CHK_SSL(err) if ((err)==-1) { ERR_print_errors_fp(stderr); exit(2); } 

void main () 
{ 
  int err; 
  int sd; 
  struct sockaddr_in sa; 
  SSL_CTX* ctx; 
  SSL*     ssl; 
  X509*    server_cert; 
  char*    str; 
  char     buf [4096]; 

  SSL_load_error_strings(); 
  ctx = SSL_CTX_new ();                        CHK_NULL(ctx); 
   
  /* ----------------------------------------------- */ 
  /* Create a socket and connect to server using normal socket calls. */ 
   
  sd = socket (AF_INET, SOCK_STREAM, 0);       CHK_ERR(sd, "socket"); 
  
  memset (&sa, '\0', sizeof(sa)); 
  sa.sin_family      = AF_INET; 
  sa.sin_addr.s_addr = inet_addr ("127.0.0.1");   /* Server IP */ 
  sa.sin_port        = htons     (1111);          /* Server Port number */ 
   
  err = connect(sd, (struct sockaddr*) &sa, 
                sizeof(sa));                   CHK_ERR(err, "connect"); 

  /* ----------------------------------------------- */ 
  /* Now we have TCP conncetion. Start SSL negotiation. */ 
   
  ssl = SSL_new (ctx);                         CHK_NULL(ssl);     
  SSL_set_fd (ssl, sd); 
  err = SSL_connect (ssl);                     CHK_SSL(err); 
     
  /* Following two steps are optional and not required for 
     data exchange to be successful. */ 
   
  /* Get the cipher - opt */ 

  printf ("SSL connection using %s\n", SSL_get_cipher (ssl)); 
   
  /* Get server's certificate (note: beware of dynamic allocation) - opt */ 

  server_cert = SSL_get_peer_certificate (ssl);       CHK_NULL(server_cert); 
  printf ("Server certificate:\n"); 
   
  str = X509_NAME_oneline (X509_get_subject_name (server_cert)); 
  CHK_NULL(str); 
  printf ("\t subject: %s\n", str); 
  Free (str); 

  str = X509_NAME_oneline (X509_get_issuer_name  (server_cert)); 
  CHK_NULL(str); 
  printf ("\t issuer: %s\n", str); 
  Free (str); 

  /* We could do all sorts of certificate verification stuff here before 
     deallocating the certificate. */ 

  X509_free (server_cert); 
   
  /* --------------------------------------------------- */ 
  /* DATA EXCHANGE - Send a message and receive a reply. */ 

  err = SSL_write (ssl, "Hello World!", strlen("Hello World!"));  CHK_SSL(err); 
   
  shutdown (sd, 1);  /* Half close, send EOF to server. */ 
   
  err = SSL_read (ssl, buf, sizeof(buf) - 1);                     CHK_SSL(err); 
  buf[err] = '\0'; 
  printf ("Got %d chars:'%s'\n", err, buf); 

  /* Clean up. */ 

  close (sd); 
  SSL_free (ssl); 
  SSL_CTX_free (ctx); 
} 
/* EOF - cli.cpp */

 
 
/* serv.cpp  -  Minimal ssleay server for Unix  
   30.9.1996, Sampo Kellomaki <sampo@iki.fi> */  

#include <stdio.h>  
#include <memory.h>  
#include <errno.h>  
#include <sys/types.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  
#include <netdb.h>  

#include "rsa.h"       /* SSLeay stuff */ 
#include "crypto.h" 
#include "x509.h" 
#include "pem.h" 
#include "ssl.h" 
#include "err.h" 

#define HOME "/usr/users/sampo/sibs/tim/"  
#define CERTF HOME "plain-cert.pem"  
#define KEYF  HOME "plain-key.pem"  

#define CHK_NULL(x) if ((x)==NULL) exit (1)  
#define CHK_ERR(err,s) if ((err)==-1) { perror(s); exit(1); }  
#define CHK_SSL(err) if ((err)==-1) { ERR_print_errors_fp(stderr); exit(2); }  

void main ()  
 
  int err;  
  int listen_sd;  
  int sd;  
  struct sockaddr_in sa_serv;  
  struct sockaddr_in sa_cli;  
  int client_len;  
  SSL_CTX* ctx;  
  SSL*     ssl;  
  X509*    client_cert;  
  char*    str;  
  char     buf [4096];  

  /* SSL preliminaries. We keep the certificate and key with the context. */  

  SSL_load_error_strings();  
  ctx = SSL_CTX_new ();   CHK_NULL(ctx);  
  
  err = SSL_CTX_use_RSAPrivateKey_file (ctx, KEYF,  SSL_FILETYPE_PEM);  
  CHK_SSL(err);  
  
  err = SSL_CTX_use_certificate_file   (ctx, CERTF, SSL_FILETYPE_PEM);  
  CHK_SSL(err);  
  
  /* ----------------------------------------------- */  
  /* Prepare TCP socket for receiving connections */  

  listen_sd = socket (AF_INET, SOCK_STREAM, 0);   CHK_ERR(listen_sd, "socket"); 
  
  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 (1111);          /* Server Port number */  
  
  err = bind(listen_sd, (struct sockaddr*) &sa_serv,  
             sizeof (sa_serv));                   CHK_ERR(err, "bind");  
  
  /* Receive a TCP connection. */  
  
  err = listen (listen_sd, 5);                    CHK_ERR(err, "listen");  
  
  client_len = sizeof(sa_cli);  
  sd = accept (listen_sd, (struct sockaddr*) &sa_cli, &client_len);  
  CHK_ERR(sd, "accept");  
  close (listen_sd);  

  printf ("Connection from %lx, port %x\n",  
          sa_cli.sin_addr.s_addr, sa_cli.sin_port);  
  
  /* ----------------------------------------------- */  
  /* TCP connection is ready. Do server side SSL. */  

  ssl = SSL_new (ctx);                           CHK_NULL(ssl);  
  SSL_set_fd (ssl, sd);  
  err = SSL_accept (ssl);                        CHK_SSL(err);  
  
  /* Get the cipher - opt */  
  
  printf ("SSL connection using %s\n", SSL_get_cipher (ssl));  
  
  /* Get client's certificate (note: beware of dynamic allocation) - opt */  

  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));  
    CHK_NULL(str);  
    printf ("\t subject: %s\n", str);  
    Free (str);  
  
    str = X509_NAME_oneline (X509_get_issuer_name  (client_cert));  
    CHK_NULL(str);  
    printf ("\t issuer: %s\n", str);  
    Free (str);  
  
    /* We could do all sorts of certificate verification stuff here before  
       deallocating the certificate. */  
  
    X509_free (client_cert);  
  } else  
    printf ("Client does not have certificate.\n");  

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

  err = SSL_read (ssl, buf, sizeof(buf) - 1);                   CHK_SSL(err);  
  buf[err] = '\0';  
  printf ("Got %d chars:'%s'\n", err, buf);  
  
  err = SSL_write (ssl, "I hear you.", strlen("I hear you."));  CHK_SSL(err);  

  /* Clean up. */  

  close (sd);  
  SSL_free (ssl);  
  SSL_CTX_free (ctx);  
 
/* EOF - serv.cpp */

 
 V příkladech je uveden i server, který je v UNIXu startován pomocí superserveru inetd. Po prostudování těchto příkladů můžete přejít ke studiu "opravdového" klienta  s_client   i serveru  s_server , které můžete spouštět pomocí programu ssleay (viz následující kapitola).