1、客户端程序/ OpenSSLClient.cpp#include #include using namespace std;#pragma comment (lib, Ws2_32.lib)#include openssl/ssl.h#pragma comment(lib, ssleay32.lib)#pragma comment(lib, libeay32.lib)#define SERVICE_PORT 10000const int nBufSize = 512;/ 初始化2.2版本Winsockint InitWinsock() WSADATA wsaData = 0; WORD wVe
2、r = MAKEWORD(2,2); int nRet = WSAStartup(wVer, &wsaData); if(nRet != 0) coutWinsock初始化失败,错误代码是nRetendl; return nRet;/ 创建一个套接字 SOCKET CreateSocket() SOCKET hSocket = INVALID_SOCKET; hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(hSocket = INVALID_SOCKET) int last_err = WSAGetLastError(); cou
3、t创建套接字失败,错误代码是last_errendl; return hSocket;/ 连接到服务器int ConnectServer(SOCKET hSocket) / 填充远程套接字地址 SOCKADDR_IN saServer = 0; saServer.sin_family = AF_INET; saServer.sin_port = htons(SERVICE_PORT); saServer.sin_addr.s_addr = inet_addr(127.0.0.1); / 使用远程套接字地址连接到服务器 int nRet = connect(hSocket, (SOCKADDR
4、*)&saServer, sizeof(saServer); if(nRet = SOCKET_ERROR) int last_err = WSAGetLastError(); cout连接失败,错误代码是last_errendl; return nRet;bool InitOpenSSL() if(!SSL_library_init() return false; SSL_load_error_strings(); return true;int PasswordCB(char *buf, int size, int flag, void *userdata) / 作者所创建的客户端程序私匙
5、密码是12345678 const char* pass = 12345678; if(size strlen(pass) + 1) return(0); strcpy(buf, pass); return(strlen(pass);int VerifyCB(int ok, X509_STORE_CTX *store) if(!ok) int err = X509_STORE_CTX_get_error(store); couterr:X509_verify_cert_error_string(err)endl; return ok;SSL_CTX* InitSSLContext() cons
6、t SSL_METHOD *meth = NULL; SSL_CTX* ctx = NULL; meth = SSLv23_method(); ctx = SSL_CTX_new(meth); / 加载客户端程序证书链 if(!SSL_CTX_use_certificate_chain_file(ctx, ClientAppChain.pem) cout加载客户端程序证书链失败endl; return NULL; SSL_CTX_set_default_passwd_cb(ctx, PasswordCB); / 加载客户端程序私匙文件 if(!SSL_CTX_use_PrivateKey_fi
7、le(ctx, ClientApp_PrivateKey.pem, SSL_FILETYPE_PEM) cout加载客户端程序私匙文件失败endl; return NULL; / 加载客户端程序所信任的CA if(!SSL_CTX_load_verify_locations(ctx, MyTestCA_Certificate.pem, NULL) cout加载客户端程序所信任的CA失败endl; return NULL; / 加载OpenSSL缺省信任的CA if(!SSL_CTX_set_default_verify_paths(ctx) cout 加载OpenSSL缺省信任的CA失败Ser
8、verCA-MyTestCA, / 所以可以明确验证深度是2,即最多检查ServerCA和MyTestCA两个CA SSL_CTX_set_verify_depth(ctx, 2); / SSL_VERIFY_PEER要求服务器提供证书,VerifyCB用于输出OpenSSL / 握手过程中验证服务器证书链失败时的错误信息 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, VerifyCB); SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY); return ctx;/ 简单的校验,仅检查common namebool Che
9、ckCertificate(SSL* ssl) X509* cert = SSL_get_peer_certificate(ssl); if(cert = NULL) return false; X509_NAME* subjectName = X509_get_subject_name(cert); if(subjectName = NULL) return false; char buf256; if(X509_NAME_get_text_by_NID(subjectName, NID_commonName, buf, 256) 0 ) if(strcmp(buf, serverApp)
10、= 0) return true; return false;void DoWork(SSL* ssl) char buf256; while(true) if(!fgets(buf, sizeof(buf)/sizeof(buf0), stdin) SSL_shutdown(ssl); break; int len = strlen(buf); int nSent = 0; while(nSent len) int nRet = SSL_write(ssl, buf+nSent, len-nSent); if(nRet = 0) coutSSL_write发生错误endl; SSL_clea
11、r(ssl); break; nSent += nRet; int main(int argc, char* argv) if(InitWinsock() != 0) return -1; SOCKET hSocket = INVALID_SOCKET; SSL_CTX* ctx = NULL; SSL* ssl = NULL; BIO* sbio = NULL; int nRet = 0; try if(!InitOpenSSL() throw -1; ctx = InitSSLContext(); if(ctx = NULL) throw -1; ssl = SSL_new(ctx); h
12、Socket = CreateSocket(); if(hSocket = INVALID_SOCKET) throw -1; if(ConnectServer(hSocket) = SOCKET_ERROR) throw -1; sbio = BIO_new_socket(hSocket, BIO_NOCLOSE); SSL_set_bio(ssl, sbio, sbio); if(SSL_connect(ssl) = 0) coutSSL握手发生错误endl; throw -1; if(!CheckCertificate(ssl) throw -1; DoWork(ssl); catch(
13、int excpt_err) nRet = excpt_err; /if(sbio) BIO_free(sbio); if(ssl) SSL_free(ssl); if(ctx) SSL_CTX_free(ctx); if(hSocket != INVALID_SOCKET) closesocket(hSocket); WSACleanup(); return 0; -服务器程序/ OpenSSLServer.cpp#include #include using namespace std;#pragma comment (lib, Ws2_32.lib)#include openssl/ss
14、l.h#pragma comment(lib, ssleay32.lib)#pragma comment(lib, libeay32.lib)#define SERVICE_PORT 10000const int nBufSize = 512;/ 初始化2.2版本Winsockint InitWinsock() WSADATA wsaData = 0; WORD wVer = MAKEWORD(2,2); int nRet = WSAStartup(wVer, &wsaData); if(nRet != 0) coutWinsock初始化失败,错误代码是nRetendl; return nRe
15、t;/ 创建一个套接字 SOCKET CreateSocket() SOCKET hSocket = INVALID_SOCKET; hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(hSocket = INVALID_SOCKET) int last_err = WSAGetLastError(); cout创建套接字失败,错误代码是last_errendl; return hSocket;/ 绑定和监听int BindListen(SOCKET hSocket) / 填充本地套接字地址 sockaddr_in saListen
16、= 0; saListen.sin_family = AF_INET; saListen.sin_port = htons(SERVICE_PORT); saListen.sin_addr.s_addr = htonl(INADDR_ANY); / 把本地套接字地址绑定到监听套接字 int nRet = bind(hSocket, (sockaddr*)&saListen, sizeof(sockaddr); if(nRet = SOCKET_ERROR) int last_err = WSAGetLastError(); cout绑定套接字失败,错误代码是last_errendl; else
17、 / 开始监听 nRet = listen(hSocket, 5); if(nRet = SOCKET_ERROR) int last_err = WSAGetLastError(); cout监听失败,错误代码是last_errendl; return nRet;/ 接收连接请求SOCKET AcceptRequest(SOCKET hSocket) sockaddr_in saClient = 0; int nSALen = sizeof(sockaddr); SOCKET hClientSocket = accept(hSocket, (sockaddr*)&saClient, &nSA
18、Len); if(hClientSocket = INVALID_SOCKET) int last_err = WSAGetLastError(); cout接受连接请求失败,错误代码是last_errendl; return hClientSocket;bool InitOpenSSL() if(!SSL_library_init() return false; SSL_load_error_strings(); return true;int PasswordCB(char *buf, int size, int flag, void *userdata) / 作者所创建的服务器程序私匙密
19、码是abcdefgh const char* pass = abcdefgh; if(size strlen(pass) + 1) return(0); strcpy(buf, pass); return(strlen(pass);int VerifyCB(int ok, X509_STORE_CTX *store) if(!ok) int err = X509_STORE_CTX_get_error(store); couterr:X509_verify_cert_error_string(err)endl; return ok;SSL_CTX* InitSSLContext() const
20、 SSL_METHOD *meth = NULL; SSL_CTX* ctx = NULL; meth = SSLv23_method(); ctx = SSL_CTX_new(meth); / 加载服务器程序证书链 if(!SSL_CTX_use_certificate_chain_file(ctx, serverAppChain.pem) cout加载服务器程序证书链失败endl; return NULL; SSL_CTX_set_default_passwd_cb(ctx, PasswordCB); / 加载服务器程序私匙文件 if(!SSL_CTX_use_PrivateKey_fil
21、e(ctx, ServerApp_PrivateKey.pem, SSL_FILETYPE_PEM) cout加载服务器程序私匙文件失败endl; return NULL; / 加载服务器程序所信任的CA if(!SSL_CTX_load_verify_locations(ctx, MyTestCA_Certificate.pem, NULL) cout加载服务器程序所信任的CA失败endl; return NULL; / 加载OpenSSL缺省信任的CA if(!SSL_CTX_set_default_verify_paths(ctx) cout 加载OpenSSL缺省信任的CA失败MyTe
22、stCA, / 所以可以明确验证深度是1,即只检查MyTestCA SSL_CTX_set_verify_depth(ctx, 1); / SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT要求客户端提供证书, / 如果不提供的话,则校验失败。VerifyCB用于输出OpenSSL / 握手过程中验证客户端证书链失败时的错误信息 SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, VerifyCB); SSL_CTX_set_mode(ctx, SSL_MO
23、DE_AUTO_RETRY); return ctx;/ 简单的校验,仅检查common namebool CheckCertificate(SSL* ssl) X509* cert = SSL_get_peer_certificate(ssl); if(cert = NULL) return false; X509_NAME* subjectName = X509_get_subject_name(cert); if(subjectName = NULL) return false; char buf256; if(X509_NAME_get_text_by_NID(subjectName,
24、 NID_commonName, buf, 256) 0 ) if(strcmp(buf, ClientApp) = 0) return true; return false;void DoWork(SSL* ssl) char buf256; while(true) int nRead = SSL_read(ssl, buf, sizeof(buf)/sizeof(buf0) - 1); if(nRead = 0) if(SSL_get_shutdown(ssl) & SSL_RECEIVED_SHUTDOWN) SSL_shutdown(ssl); else SSL_clear(ssl);
25、 break; bufnRead = 0; coutbuf; int main(int argc, char* argv) if(InitWinsock() != 0) return -1; SOCKET hListenSocket = INVALID_SOCKET; SOCKET hClientSocket = INVALID_SOCKET; SSL_CTX* ctx = NULL; SSL* ssl = NULL; BIO* sbio = NULL; int nRet = 0; try if(!InitOpenSSL() throw -1; ctx = InitSSLContext();
26、if(ctx = NULL) throw -1; ssl = SSL_new(ctx); hListenSocket = CreateSocket(); if(hListenSocket = INVALID_SOCKET) throw -1; if(BindListen(hListenSocket) = SOCKET_ERROR) throw -1; hClientSocket = AcceptRequest(hListenSocket); if(hClientSocket = INVALID_SOCKET) throw -1; sbio = BIO_new_socket(hClientSoc
27、ket, BIO_NOCLOSE); SSL_set_bio(ssl, sbio, sbio); if(SSL_accept(ssl) = 0) coutSSL握手发生错误endl; throw -1; if(!CheckCertificate(ssl) throw -1; DoWork(ssl); catch(int excpt_err) nRet = excpt_err; /if(sbio) BIO_free(sbio); if(ssl) SSL_free(ssl); if(ctx) SSL_CTX_free(ctx); if(hClientSocket != INVALID_SOCKET) closesocket(hClientSocket); if(hListenSocket != INVALID_SOCKET) closesocket(hListenSocket); WSACleanup(); return 0;