SSL握手通訊詳解及linux下c/c++ SSL Socket代碼舉例

SSL(Secure Sockets Layer 安全套接層),及其繼任者傳輸層安全(Transport Layer Security,TLS)是爲網絡通訊提供安全及數據完整性的一種安全協議。TLS與SSL在傳輸層對網絡鏈接進行加密。 html

  安全證書既包含了用於加密數據的密鑰,又包含了用於證明身份的數字簽名。安全證書採用公鑰加密技術。公鑰加密是指使用一對非對稱的密鑰進行加密或解密。每一對密鑰由公鑰和私鑰組成。公鑰被普遍發佈。私鑰是隱祕的,不公開。用公鑰加密的數據只可以被私鑰解密。反過來,使用私鑰加密的數據只能被公鑰解密。這個非對稱的特性使得公鑰加密頗有用。在安全證書中包含着一對非對稱的密鑰。只有安全證書的全部者才知道私鑰。當通訊方A將本身的安全證書發送給通訊方B時,實際上發給通訊方B的是公開密鑰,接着通訊方B能夠向通訊方A發送用公鑰加密的數據,只有通訊方A才能使用私鑰對數據進行解密,從而得到通訊方B發送的原始數據。安全證書中的數字簽名部分是通訊方A的電子身份證。數字簽名告訴通訊方B該信息確實由通訊方A發出,不是僞造的,也沒有被篡改。 linux

  客戶與服務器通訊時,首先要進行SSL握手,SSL握手主要完成如下任務: c++

  1)協商使用的加密套件。加密套件中包括一組加密參數,這些參數指定了加密算法和密鑰的長度等信息。 算法

  2)驗證對方的身份,此操做是可選的。 安全

  3)肯定使用的加密算法。 服務器

  4)SSL握手過程採用非對稱加密方法傳遞數據,由此來創建一個安全的SSL會話。SSL握手完成後,通訊雙方將採用對稱加密方法傳遞實際的應用數據。 網絡

   如下是SSL握手的具體流程: socket

(1)客戶將本身的SSL版本號、加密參數、與SSL會話有關的數據及其餘一些必要信息發送到服務器。 加密

(2)服務器將本身的SSL版本號、加密參數、與SSL會話有關的數據及其餘一些必要信息發送給客戶,同時發給客戶的還有服務器的證書。若是服務器須要驗證客戶身份,服務器還會發出要求客戶提供安全證書的請求。 spa

(3)客戶端驗證服務器證書,若是驗證失敗,就提示不能創建SSL鏈接。若是成功,那麼繼續下一步驟。

(4)客戶端爲本次SSL會話生成預備主密碼(pre-master secret),並將其用服務器公鑰加密後發送給服務器。

(5)若是服務器要求驗證客戶身份,客戶端還要對另一些數據簽名後,將其與客戶端證書一塊兒發送給服務器。

(6)若是服務器要求驗證客戶身份,則檢查簽署客戶證書的CA(Certificate Authority,證書機構)是否可信。若是不在信任列表中,結束本次會話。若是檢查經過,服務器用本身的私鑰解密收到的預備主密碼(pre-master secret),並用它經過某些算法生成本次會話的主密碼(master secret)。

(7)客戶端與服務器端均使用此主密碼(master secret)生成這次會話的會話密鑰(對稱密鑰)。在雙方SSL握手結束後傳遞任何消息均使用此會話密鑰。這樣作的主要緣由是對稱加密比非對稱加密的運算量要低一個數量級以上,可以顯著提升雙方會話時的運算速度。

(8)客戶端通知服務器此後發送的消息都使用這個會話密鑰進行加密,並通知服務器客戶端已經完成本次SSL握手。

(9)服務器通知客戶端此後發送的消息都使用這個會話密鑰進行加密,並通知客戶端服務器已經完成本次SSL握手。

(10)本次握手過程結束,SSL會話已經創建。在接下來的會話過程當中,雙方使用同一個會話密鑰分別對發送和接收的信息進行加密和解密。

如下爲 linux c/c++ SSL socket Client和Server的代碼參考。

客戶端代碼以下:

#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <sys/socket.h>
#include <resolv.h>
#include <netdb.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#define FAIL    -1
intOpenConnection(constchar*hostname,intport)
{  intsd;
structhostent *host;
structsockaddr_in addr;
if( (host = gethostbyname(hostname)) == NULL )
{
    printf('Eroor: %s\n',hostname);
    perror(hostname);
    abort();
}
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = *(long*)(host->h_addr);
if( connect(sd, (structsockaddr*)&addr,sizeof(addr)) != 0 )
{
    close(sd);
    perror(hostname);
    abort();
}
returnsd;
}
SSL_CTX* InitCTX(void)
{   SSL_METHOD *method;
SSL_CTX *ctx;
OpenSSL_add_all_algorithms(); /* Load cryptos, et.al. */
SSL_load_error_strings();  /* Bring in and register error messages */
method = SSLv2_client_method(); /* Create new client-method instance */
ctx = SSL_CTX_new(method);  /* Create new context */
if( ctx == NULL )
{
    ERR_print_errors_fp(stderr);
    printf('Eroor: %s\n',stderr);
    abort();
}
returnctx;
}
voidShowCerts(SSL* ssl)
{   X509 *cert;
    char*line;
    cert = SSL_get_peer_certificate(ssl);/* get the server's certificate */
    if( cert != NULL )
    {
    printf("Server certificates:\n");
    line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
    printf("Subject: %s\n", line);
    free(line);      /* free the malloc'ed string */
    line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
    printf("Issuer: %s\n", line);
    free(line);      /* free the malloc'ed string */
    X509_free(cert);    /* free the malloc'ed certificate copy */
}
else
    printf("No certificates.\n");
}
intmain(intcount,char*strings[])
{   SSL_CTX *ctx;
intserver;
SSL *ssl;
charbuf[1024];
intbytes;
char*hostname, *portnum;
if( count != 3 )
{
    printf("usage: %s <hostname> <portnum>\n", strings[0]);
    exit(0);
}
SSL_library_init();
hostname=strings[1];
portnum=strings[2];
ctx = InitCTX();
server = OpenConnection(hostname,atoi(portnum));
ssl = SSL_new(ctx);     /* create new SSL connection state */
SSL_set_fd(ssl, server);   /* attach the socket descriptor */
if( SSL_connect(ssl) == FAIL )  /* perform the connection */
{
    printf('Eroor: %s\n',stderr);
    ERR_print_errors_fp(stderr);
}
else
{  char*msg ="HelloWorld";
    printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
    ShowCerts(ssl);       /* get any certs */
    SSL_write(ssl, msg,strlen(msg));  /* encrypt & send message */
    bytes = SSL_read(ssl, buf,sizeof(buf));/* get reply & decrypt */
    buf[bytes] = 0;
    printf("Received: \"%s\"\n", buf);
    SSL_free(ssl);       /* release connection state */
}
close(server);        /* close socket */
SSL_CTX_free(ctx);       /* release context */
return0;
}

服務端代碼以下:

#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <resolv.h>
#include "openssl/ssl.h"
#include "openssl/err.h"
#define FAIL    -1
usingnamespacestd;
intOpenListener(intport)
{  intsd;
structsockaddr_in addr;
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY;
if( bind(sd, (structsockaddr*)&addr,sizeof(addr)) != 0 )
{
    perror("can't bind port");
    abort();
}
if( listen(sd, 10) != 0 )
{
    perror("Can't configure listening port");
    abort();
}
returnsd;
}
SSL_CTX* InitServerCTX(void)
{
SSL_CTX *ctx = NULL;
    #if OPENSSL_VERSION_NUMBER >= 0x10000000L
           constSSL_METHOD *method;
    #else
            SSL_METHOD *method;
    #endif
    SSL_library_init();
    OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
    SSL_load_error_strings();  /* load all error messages */
    method = SSLv23_client_method();/* create new server-method instance */
    ctx = SSL_CTX_new(method);  /* create new context from method */
    if( ctx == NULL )
    {
        ERR_print_errors_fp(stderr);
        abort();
    }
    returnctx;
}
voidLoadCertificates(SSL_CTX* ctx,char* CertFile,char* KeyFile)
{
//New lines
    if(SSL_CTX_load_verify_locations(ctx, CertFile, KeyFile) != 1)
        ERR_print_errors_fp(stderr);
    if(SSL_CTX_set_default_verify_paths(ctx) != 1)
        ERR_print_errors_fp(stderr);
    //End new lines
/* set the local certificate from CertFile */
if( SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0 )
{
    ERR_print_errors_fp(stderr);
    abort();
}
/* set the private key from KeyFile (may be the same as CertFile) */
if( SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0 )
{
    ERR_print_errors_fp(stderr);
    abort();
}
/* verify private key */
if( !SSL_CTX_check_private_key(ctx) )
{
    fprintf(stderr,"Private key does not match the public certificate\n");
    abort();
}
printf("LoadCertificates Compleate Successfully.....\n");
}
voidShowCerts(SSL* ssl)
{   X509 *cert;
char*line;
cert = SSL_get_peer_certificate(ssl);/* Get certificates (if available) */
if( cert != NULL )
{
    printf("Server certificates:\n");
    line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
    printf("Subject: %s\n", line);
    free(line);
    line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
    printf("Issuer: %s\n", line);
    free(line);
    X509_free(cert);
}
else
    printf("No certificates.\n");
}
voidServlet(SSL* ssl)/* Serve the connection -- threadable */
{  charbuf[1024];
charreply[1024];
intsd, bytes;
constchar* HTMLecho="<html><body><pre>%s</pre></body></html>\n\n";
if( SSL_accept(ssl) == FAIL )    /* do SSL-protocol accept */
    ERR_print_errors_fp(stderr);
else
{
    ShowCerts(ssl);       /* get any certificates */
    bytes = SSL_read(ssl, buf,sizeof(buf));/* get request */
    if( bytes > 0 )
    {
        buf[bytes] = 0;
        printf("Client msg: \"%s\"\n", buf);
        sprintf(reply, HTMLecho, buf);  /* construct reply */
        SSL_write(ssl, reply,strlen(reply));/* send reply */
    }
    else
        ERR_print_errors_fp(stderr);
}
sd = SSL_get_fd(ssl);      /* get socket connection */
SSL_free(ssl);        /* release SSL state */
close(sd);         /* close connection */
}
intmain(intcount,char*strings[])
{   SSL_CTX *ctx;
intserver;
char*portnum;
if( count != 2 )
{
    printf("Usage: %s <portnum>\n", strings[0]);
    exit(0);
}
else
{
    printf("Usage: %s <portnum>\n", strings[1]);
}
SSL_library_init();
portnum = strings[1];
ctx = InitServerCTX();       /* initialize SSL */
LoadCertificates(ctx,"/home/stud/kawsar/mycert.pem","/home/stud/kawsar/mycert.pem"); /* load certs */
server = OpenListener(atoi(portnum));   /* create server socket */
while(1)
{  structsockaddr_in addr;
    socklen_t len =sizeof(addr);
    SSL *ssl;
    intclient = accept(server, (structsockaddr*)&addr, &len); /* accept connection   as usual */
    printf("Connection: %s:%d\n",inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
    ssl = SSL_new(ctx);             /* get new SSL state with context */
    SSL_set_fd(ssl, client);     /* set connection socket to SSL state */
    Servlet(ssl);        /* service connection */
}
close(server);         /* close server socket */
SSL_CTX_free(ctx);        /* release context */
}
相關文章
相關標籤/搜索