1. 程式人生 > >SSL握手通信詳解及linux下c/c++ SSL Socket代碼舉例

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

perf 加密技術 rec 套件 amp lin codes errno 機構

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

摘自:http://www.169it.com/article/3215130236.html

分享到:8 發布時間:2013-8-13

本文導語: SSL(Secure Sockets Layer 安全套接層),及其繼任者傳輸層安全(Transport Layer Security,TLS)是為網絡通信提供安全及數據完整性的一種安全協議。TLS與SSL在傳輸層對網絡連接進行加密。 安全證書既包含了用於加密數據的密鑰,...

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

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

客戶與服務器通信時,首先要進行SSL握手,SSL握手主要完成以下任務:

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

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

3)確定使用的加密算法。

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

以下是SSL握手的具體流程:

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

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

(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的代碼參考。

客戶端代碼如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 #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 int OpenConnection(const char *hostname, int port) { int sd; struct hostent *host; struct sockaddr_in addr; if ( (host = gethostbyname(hostname)) == NULL ) { printf(‘Eroor: %sn‘,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, (struct sockaddr*)&addr, sizeof(addr)) != 0 ) { close(sd); perror(hostname); abort(); } return sd; } 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: %sn‘,stderr); abort(); } return ctx; } void ShowCerts(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: %sn", line); free(line); /* free the malloc‘ed string */ line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0); printf("Issuer: %sn", line); free(line); /* free the malloc‘ed string */ X509_free(cert); /* free the malloc‘ed certificate copy */ } else printf("No certificates.n"); } int main(int count, char *strings[]) { SSL_CTX *ctx; int server; SSL *ssl; char buf[1024]; int bytes; 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: %sn‘,stderr); ERR_print_errors_fp(stderr); } else { char *msg = "HelloWorld"; printf("Connected with %s encryptionn", 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 */ return 0; }

服務端代碼如下:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 #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 using namespace std; int OpenListener(int port) { int sd; struct sockaddr_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, (struct sockaddr*)&addr, sizeof(addr)) != 0 ) { perror("can‘t bind port"); abort(); } if ( listen(sd, 10) != 0 ) { perror("Can‘t configure listening port"); abort(); } return sd; } SSL_CTX* InitServerCTX(void) { SSL_CTX *ctx = NULL; #if OPENSSL_VERSION_NUMBER >= 0x10000000L const SSL_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(); } return ctx; } void LoadCertificates(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 certificaten"); abort(); } printf("LoadCertificates Compleate Successfully.....n"); } void ShowCerts(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: %sn", line); free(line); line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0); printf("Issuer: %sn", line); free(line); X509_free(cert); } else printf("No certificates.n"); } void Servlet(SSL* ssl) /* Serve the connection -- threadable */ { char buf[1024]; char reply[1024]; int sd, bytes; const char* HTMLecho="<html><body><pre>%s</pre></body></html>nn"; 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 */ } int main(int count, char *strings[]) { SSL_CTX *ctx; int server; 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) { struct sockaddr_in addr; socklen_t len = sizeof(addr); SSL *ssl; int client = accept(server, (struct sockaddr*)&addr, &len); /* accept connection as usual */ printf("Connection: %s:%dn",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 */ }

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