#include "stdafx.h"
/****************************************************************************************** *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"
#include <openssl/sha.h> #include <openssl/hmac.h> #include <openssl/evp.h> #include <openssl/bio.h> #include <openssl/buffer.h>
/*所有需要的参数信息都在此处以#define的形式提供*/ #define CERTF "client.pem" /*客户端的证书(需经CA签名)*/ #define KEYF "client.key" /*客户端的私钥(建议加密存储)*/ #define CACERT "ca.pem" /*CA 的证书*/ #define PORT 465 /*服务端的端口*/ #define SERVER_ADDR "209.85.147.111" /*服务段的IP地址*/ #define GMAILUSERNAME "[email protected]"/*Gmail 帐号*/ #define GMAILPASSWORD "xxxx"/*Gmail 帐号密码*/
#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 put_line(SSL* ssl,char* cmd) { int err; printf("C: %s",cmd); err = SSL_write (ssl, cmd, strlen(cmd)); CHK_SSL(err); return 1; }
/*读数据*/ int get_line(SSL* ssl) { char buf [4096]; int err; err = SSL_read (ssl, buf, sizeof(buf) - 1); CHK_SSL(err); buf[err] = '/0'; printf ("S: :%s", buf); free(buf); return 1; }
char *base64_encode(char *input) { BIO *bmem, *b64; BUF_MEM *bptr;
b64 = BIO_new(BIO_f_base64()); bmem = BIO_new(BIO_s_mem()); b64 = BIO_push(b64, bmem); BIO_write(b64, input, strlen(input)); BIO_flush(b64); BIO_get_mem_ptr(b64, &bptr);
char *buff = (char *)malloc(bptr->length); memcpy(buff, bptr->data, bptr->length-1); buff[bptr->length-1] = 0;
BIO_free_all(b64);
return buff; }
/*捏造信头*/ char* makeHeader() { char buf[128]; char tmp[1024]; char *rnt,*next; int n,length;
n = length = 0;
next = tmp;
n = sprintf(buf,"Date: %s/r/n","date"); memcpy(tmp,buf,n); next+= n; length += n;
n = sprintf(buf,"Return-Path: %s/r/n",GMAILUSERNAME); memcpy(next,buf,n); next+= n; length += n;
n = sprintf(buf,"To: %s/r/n",GMAILUSERNAME); memcpy(next,buf,n); next+= n; length += n; n = sprintf(buf, "From: =?UTF-8?B?%s?= <%s>/r/n",base64_encode(GMAILUSERNAME),GMAILUSERNAME); memcpy(next,buf,n); next+= n; length += n; n = sprintf(buf, "Subject: =?UTF-8?B?%s?=/r/n",base64_encode("Test mail via C")); memcpy(next,buf,n); next+= n; length += n;
n = sprintf(buf, "MIME-Version: 1.0/r/n"); memcpy(next,buf,n); next+= n; length += n;
n = sprintf(buf, "Content-Transfer-Encoding: base64/r/n"); memcpy(next,buf,n); next+= n; length += n;
n = sprintf(buf, "Content-Type: text/html; charset=/"UTF-8/"/r/n/r/n"); memcpy(next,buf,n); next+= n; length += n;
tmp[length] = 0;
rnt = (char *)malloc(length); strcpy(rnt, tmp); return rnt; }
char* makeBody(char* instr) { char* tmp; char* rnt; tmp = base64_encode(instr);
rnt = (char *)malloc(strlen(tmp)); strcpy(rnt, tmp); rnt = strcat(rnt,"/r/n");
return rnt; }
int main () { int err; int sd; struct sockaddr_in sa; SSL_CTX* ctx; SSL* ssl; X509* server_cert; char* str; 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_library_init(); SSL_load_error_strings(); /*为打印调试信息作准备*/
meth=SSLv23_method(); ctx = SSL_CTX_new (meth); CHK_NULL(ctx);
SSL_CTX_set_default_passwd_cb_userdata(ctx, "password");
if(!(SSL_CTX_use_certificate_chain_file(ctx, CERTF))){ ERR_print_errors_fp(stderr); exit(-2); } if(!(SSL_CTX_use_PrivateKey_file(ctx, CERTF,SSL_FILETYPE_PEM))){ ERR_print_errors_fp(stderr); exit(-3); }
/* Load the CAs we trust*/ if(!(SSL_CTX_load_verify_locations(ctx, CACERT,0))){ printf("Load CA failed!/n"); exit(-4); }
/*构建随机数生成机制,WIN32平台必需*/ srand( (unsigned)time( NULL ) ); for( int i = 0; i < 100;i++ ) seed_int[i] = 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"); get_line(ssl); put_line(ssl,"EHLO localhost/r/n"); get_line(ssl); put_line(ssl,"AUTH LOGIN/r/n"); get_line(ssl); str = strcat(base64_encode(GMAILUSERNAME),"/r/n"); put_line(ssl,str); free(str); get_line(ssl); str = strcat(base64_encode(GMAILPASSWORD),"/r/n"); put_line(ssl,str); free(str); get_line(ssl); put_line(ssl,"MAIL FROM:<[email protected]>/r/n"); get_line(ssl); put_line(ssl,"RCPT TO:<[email protected]>/r/n"); get_line(ssl); put_line(ssl,"DATA/r/n"); get_line(ssl); str = makeHeader(); put_line(ssl,str); free(str);
str = makeBody("body"); put_line(ssl,str); free(str);
put_line(ssl,"/r/n./r/n"); get_line(ssl); put_line(ssl,"QUIT/r/n"); get_line(ssl);
/* 收尾工作 */ SSL_shutdown (ssl); /* send SSL/TLS close_notify */ shutdown (sd,2); SSL_free (ssl); SSL_CTX_free (ctx);
return 0; }
|