| #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 "xuqinyong@gmail.com"/*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:<xuqinyong@gmail.com>/r/n"); ????get_line(ssl); ????put_line(ssl,"RCPT TO:<xuqinyong@gmail.com>/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; }
|