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čí.
#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
#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