/******************************************************************SSL/TLS客户端程序WIN32版(以demos/cli.cpp为基础)*需要用到动态连接库libeay32.dll,ssleay.dll,*同时在setting中加入ws2_32.lib libeay32.lib ssleay32.lib,*以上库文件在编译openssl后可在out32dll目录下找到,*所需证书文件请参照文章自行生成*/*****************************************************************/#include <stdio.h>#include <stdlib.h>#include <memory.h>#include <errno.h>#include <sys/types.h>#include <winsock2.h>#include "openssl/rsa.h" #include "openssl/crypto.h"#include "openssl/x509.h"#include "openssl/pem.h"#include "openssl/ssl.h"#include "openssl/err.h"#include "openssl/rand.h"/*所有需要的参数信息都在此处以#define的形式提供*/#define CERTF "client.crt" /*客户端的证书(需经CA签名)*/#define KEYF "client.key" /*客户端的私钥(建议加密存储)*/#define CACERT "ca.crt" /*CA 的证书*/#define PORT 1111 /*服务端的端口*/#define SERVER_ADDR "127.0.0.1" /*服务段的IP地址*/#define CHK_NULL(x) if ((x)==NULL) exit (-1)#define CHK_ERR(err,s) if ((err)==-1) { perror(s); exit(-2); }#define CHK_SSL(err) if ((err)==-1) { ERR_print_errors_fp(stderr); exit(-3); }int main (){int err;int sd;struct sockaddr_in sa;SSL_CTX* ctx;SSL* ssl;X509* server_cert;char* str;char buf [4096];SSL_METHOD *meth;int seed_int[100]; /*存放随机序列*/WSADATA wsaData;if(WSAStartup(MAKEWORD(2,2),&wsaData) != 0){printf("WSAStartup()fail:%d\n",GetLastError());return -1;} OpenSSL_add_ssl_algorithms(); /*初始化*/SSL_load_error_strings(); /*为打印调试信息作准备*/meth = TLSv1_client_method(); /*采用什么协议(SSLv2/SSLv3/TLSv1)在此指定*/ctx = SSL_CTX_new (meth); CHK_NULL(ctx);SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL); /*验证与否*/SSL_CTX_load_verify_locations(ctx,CACERT,NULL); /*若验证,则放置CA证书*/if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0) {ERR_print_errors_fp(stderr);exit(-2);}if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0) {ERR_print_errors_fp(stderr);exit(-3);}if (!SSL_CTX_check_private_key(ctx)) {printf("Private key does not match the certificate public key\n");exit(-4);} /*构建随机数生成机制,WIN32平台必需*/srand( (unsigned)time( NULL ) );for( int i = 0; i < 100;i++ )seed_int = rand();RAND_seed(seed_int, sizeof(seed_int));/*以下是正常的TCP socket建立过程 .............................. */printf("Begin tcp socket...\n");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 (SERVER_ADDR); /* Server IP */sa.sin_port = htons (PORT); /* Server Port number */err = connect(sd, (struct sockaddr*) &sa,sizeof(sa)); CHK_ERR(err, "connect");/* TCP 链接已建立.开始 SSL 握手过程.......................... */printf("Begin SSL negotiation \n");ssl = SSL_new (ctx); CHK_NULL(ssl);SSL_set_fd (ssl, sd);err = SSL_connect (ssl);CHK_SSL(err);/*打印所有加密算法的信息(可选)*/printf ("SSL connection using %s\n", SSL_get_cipher (ssl));/*得到服务端的证书并打印些信息(可选) */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),0,0);CHK_NULL(str);printf ("\t subject: %s\n", str);Free (str);str = X509_NAME_oneline (X509_get_issuer_name (server_cert),0,0);CHK_NULL(str);printf ("\t issuer: %s\n", str);Free (str);X509_free (server_cert); /*如不再需要,需将证书释放 *//* 数据交换开始,用SSL_write,SSL_read代替write,read */printf("Begin SSL data exchange\n");err = SSL_write (ssl, "Hello World!", strlen("Hello World!")); CHK_SSL(err);err = SSL_read (ssl, buf, sizeof(buf) - 1); CHK_SSL(err);buf[err] = '\0';printf ("Got %d chars:'%s'\n", err, buf);SSL_shutdown (ssl); /* send SSL/TLS close_notify *//* 收尾工作 */shutdown (sd,2);SSL_free (ssl);SSL_CTX_free (ctx);return 0;}/****************************************************************** EOF - cli.cpp*****************************************************************/
/******************************************************************SSL/TLS服务端程序WIN32版(以demos/server.cpp为基础)*需要用到动态连接库libeay32.dll,ssleay.dll,*同时在setting中加入ws2_32.lib libeay32.lib ssleay32.lib,*以上库文件在编译openssl后可在out32dll目录下找到,*所需证书文件请参照文章自行生成.*****************************************************************/#include <stdio.h>#include <stdlib.h>#include <memory.h>#include <errno.h>#include <sys/types.h>#include <winsock2.h>#include "openssl/rsa.h" #include "openssl/crypto.h"#include "openssl/x509.h"#include "openssl/pem.h"#include "openssl/ssl.h"#include "openssl/err.h"/*所有需要的参数信息都在此处以#define的形式提供*/#define CERTF "server.crt" /*服务端的证书(需经CA签名)*/#define KEYF "server.key" /*服务端的私钥(建议加密存储)*/#define CACERT "ca.crt" /*CA 的证书*/#define PORT 1111 /*准备绑定的端口*/#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); }int 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_METHOD *meth;WSADATA wsaData;if(WSAStartup(MAKEWORD(2,2),&wsaData) != 0){printf("WSAStartup()fail:%d\n",GetLastError());return -1;}SSL_load_error_strings(); /*为打印调试信息作准备*/OpenSSL_add_ssl_algorithms(); /*初始化*/meth = TLSv1_server_method(); /*采用什么协议(SSLv2/SSLv3/TLSv1)在此指定*/ctx = SSL_CTX_new (meth);CHK_NULL(ctx);SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL); /*验证与否*/SSL_CTX_load_verify_locations(ctx,CACERT,NULL); /*若验证,则放置CA证书*/if (SSL_CTX_use_certificate_file(ctx, CERTF, SSL_FILETYPE_PEM) <= 0) {ERR_print_errors_fp(stderr);exit(3);}if (SSL_CTX_use_PrivateKey_file(ctx, KEYF, SSL_FILETYPE_PEM) <= 0) {ERR_print_errors_fp(stderr);exit(4);}if (!SSL_CTX_check_private_key(ctx)) {printf("Private key does not match the certificate public key\n");exit(5);}SSL_CTX_set_cipher_list(ctx,"RC4-MD5"); /*开始正常的TCP socket过程.................................*/printf("Begin TCP socket...\n");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 (PORT); err = bind(listen_sd, (struct sockaddr*) &sa_serv,sizeof (sa_serv));CHK_ERR(err, "bind");/*接受TCP链接*/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");closesocket (listen_sd);printf ("Connection from %lx, port %x\n",sa_cli.sin_addr.s_addr, sa_cli.sin_port);/*TCP连接已建立,进行服务端的SSL过程. */printf("Begin server side SSL\n");ssl = SSL_new (ctx); CHK_NULL(ssl);SSL_set_fd (ssl, sd);err = SSL_accept (ssl);printf("SSL_accept finished\n");CHK_SSL(err);/*打印所有加密算法的信息(可选)*/printf ("SSL connection using %s\n", SSL_get_cipher (ssl));/*得到服务端的证书并打印些信息(可选) */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), 0, 0);CHK_NULL(str);printf ("\t subject: %s\n", str);Free (str);str = X509_NAME_oneline (X509_get_issuer_name (client_cert), 0, 0);CHK_NULL(str);printf ("\t issuer: %s\n", str);Free (str);X509_free (client_cert);/*如不再需要,需将证书释放 */}elseprintf ("Client does not have certificate.\n");/* 数据交换开始,用SSL_write,SSL_read代替write,read */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);/* 收尾工作*/shutdown (sd,2);SSL_free (ssl);SSL_CTX_free (ctx);return 0;}/****************************************************************** EOF - serv.cpp*****************************************************************/
/** OpenSSL SSL/TLS Https Client example* Only for Unix/Linux:* cc -c https.c* cc -o https https.c -lssl* OpenSSL library needed.** 同时支持普通的socket连接以及基于普通socket基础之上的ssl* 连接。这对于已有的socket程序修改来说会比较方便,不至于* 和原来的结构发生太大的冲突.* 要注意的一点,似乎当使用socket套接字来创建ssl连接的时候,* 如果套接字是采用非阻塞方式建立的话,会导致ssl会话失败,不* 知道为什么。所以这里对于提供给https的套接字采用了普通的* connect方法创建。**/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <stdarg.h>#include <errno.h>#include <fcntl.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include <openssl/crypto.h>#include <openssl/ssl.h>#include <openssl/err.h>#include <openssl/rand.h>#define BUF_LEN 1024#define MAX_STRING_LEN 2048//xnet_select x defines#define READ_STATUS 0#define WRITE_STATUS 1#define EXCPT_STATUS 2/* flag to set request with ssl or not. */static int bIsHttps = 1;static int timeout_sec = 10;static int timeout_microsec = 0;void err_doit(int errnoflag, const char *fmt, va_list ap);void err_quit(const char *fmt, ...);int create_tcpsocket(const char *host, const unsigned short port);int xnet_select(int s, int sec, int usec, short x);int main(int argc, char* argv[]){char* host = "127.0.0.1";unsigned short port = 80;int fd;SSL *ssl;SSL_CTX *ctx;int n,ret;char buf[BUF_LEN];char* requestpath = "/";if( argc == 5 ){host = argv[1];port = atoi(argv[2]);requestpath = argv[3];bIsHttps = atoi(argv[4]);}/* make connection to the cache server */fd = create_tcpsocket(host, port);/* http request. */sprintf(buf, "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n",requestpath, host);if(bIsHttps != 1){if(xnet_select(fd, timeout_sec, timeout_microsec, WRITE_STATUS)>0){/* send off the message */write(fd, buf, strlen(buf));}else{err_quit("Socket I/O Write Timeout %s:%d\n", host, port);}printf("Server response:\n");while (xnet_select(fd, timeout_sec, timeout_microsec, READ_STATUS)>0){if ((n = read(fd, buf, BUF_LEN-1)) > 0) {buf[n] = '\0';printf("%s", buf);}else{break;}}// close the plain socket handler.close(fd);}else{SSL_load_error_strings();SSL_library_init();ctx = SSL_CTX_new(SSLv23_client_method());if ( ctx == NULL ){err_quit("init SSL CTX failed:%s\n",ERR_reason_error_string(ERR_get_error()));}ssl = SSL_new(ctx);if ( ssl == NULL ){err_quit("new SSL with created CTX failed:%s\n",ERR_reason_error_string(ERR_get_error()));}ret = SSL_set_fd(ssl, fd);if ( ret == 0 ){err_quit("add SSL to tcp socket failed:%s\n",ERR_reason_error_string(ERR_get_error()));}/* PRNG */RAND_poll();while ( RAND_status() == 0 ){unsigned short rand_ret = rand() % 65536;RAND_seed(&rand_ret, sizeof(rand_ret));}/* SSL Connect */ret = SSL_connect(ssl);if( ret != 1 ){err_quit("SSL connection failed:%s\n",ERR_reason_error_string(ERR_get_error()));}// https socket write.SSL_write(ssl, buf, strlen(buf));while((n = SSL_read(ssl, buf, BUF_LEN-1)) > 0){buf[n] = '\0';write(1, buf, n); }if(n != 0){err_quit("SSL read failed:%s\n",ERR_reason_error_string(ERR_get_error()));}// close ssl tunnel.ret = SSL_shutdown(ssl); if( ret != 1 ){close(fd);err_quit("SSL shutdown failed:%s\n",ERR_reason_error_string(ERR_get_error()));}// close the plain socket handler.close(fd);// clear ssl resource.SSL_free(ssl); SSL_CTX_free(ctx);ERR_free_strings();}}/* create common tcp socket connection */int create_tcpsocket(const char *host, const unsigned short port){int ret;char * transport = "tcp";struct hostent *phe; /* pointer to host information entry */struct protoent *ppe; /* pointer to protocol information entry */struct sockaddr_in sin; /* an Internet endpoint address */int s; /* socket descriptor and socket type */memset(&sin, 0, sizeof(sin));sin.sin_family = AF_INET;if ((sin.sin_port = htons(port)) == 0)err_quit("invalid port \"%d\"\n", port);/* Map host name to IP address, allowing for dotted decimal */if( phe = gethostbyname(host) )memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);else if( (sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE )err_quit("can't get \"%s\" host entry\n", host);/* Map transport protocol name to protocol number */if ( (ppe = getprotobyname(transport)) == 0)err_quit("can't get \"%s\" protocol entry\n", transport);/* Allocate a common TCP socket */s = socket(PF_INET, SOCK_STREAM, ppe->p_proto);if (s < 0)err_quit("can't create socket: %s\n", strerror(errno));if(bIsHttps != 1){/* Connect the socket with timeout */fcntl(s,F_SETFL, O_NONBLOCK);if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) == -1){if (errno == EINPROGRESS){// it is in the connect process struct timeval tv; fd_set writefds; tv.tv_sec = timeout_sec; tv.tv_usec = timeout_microsec; FD_ZERO(&writefds); FD_SET(s, &writefds); if(select(s+1,NULL,&writefds,NULL,&tv)>0){ int len=sizeof(int); //下面的一句一定要,主要针对防火墙 getsockopt(s, SOL_SOCKET, SO_ERROR, &errno, &len); if(errno != 0) ret = 1;elseret = 0;}elseret = 2;//timeout or error happen }else ret = 1; }else{ret = 1;}}else{/* create common tcp socket.seems non-block type is not supported by ssl. */ret = connect(s, (struct sockaddr *)&sin, sizeof(sin));}if(ret != 0){close(s);err_quit("can't connect to %s:%d\n", host, port);}return s;}/*s - SOCKETsec - timeout secondsusec - timeout microsecondsx - select status*/int xnet_select(int s, int sec, int usec, short x){int st = errno;struct timeval to;fd_set fs;to.tv_sec = sec;to.tv_usec = usec;FD_ZERO(&fs);FD_SET(s, &fs);switch(x){case READ_STATUS:st = select(s+1, &fs, 0, 0, &to);break;case WRITE_STATUS:st = select(s+1, 0, &fs, 0, &to);break;case EXCPT_STATUS:st = select(s+1, 0, 0, &fs, &to);break;}return(st);}void err_doit(int errnoflag, const char *fmt, va_list ap){int errno_save;char buf[MAX_STRING_LEN];errno_save = errno; vsprintf(buf, fmt, ap);if (errnoflag)sprintf(buf + strlen(buf), ": %s", strerror(errno_save));strcat(buf, "\n");fflush(stdout);fputs(buf, stderr);fflush(NULL);return;}/* Print a message and terminate. */void err_quit(const char *fmt, ...){va_list ap;va_start(ap, fmt);err_doit(0, fmt, ap);va_end(ap);exit(1);}
posted on 2010-11-09 13:49 flyonok 阅读(8451) 评论(1) 编辑 收藏 引用 所属分类: openssl
我的client需要加载可信ca列表,用SSL_CTX_load_verify_locations函数的话,参数中的文件是否用根证书?怎么生成啊? 回复 更多评论
Powered by: C++博客 Copyright © flyonok