日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

用openssl跟Gmail的smtp对话(一)

發布時間:2025/6/17 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 用openssl跟Gmail的smtp对话(一) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、目的 Gmail的webmail雖然常常報系統遇到錯誤,用起來不太爽,但是smtp/pop3還是蠻厚道的。 服務穩定,被GFW攔截的概率也小一些,可能是采用SSL加密通訊的緣故吧。所以研究一下gmail的smtp連接還是很有意義的。我們先用手頭上的工具進行實際操作,對ssl的連接有個感性的認識,然后用C寫一個測試程序,最終的目標是用C++寫一個COM可以供ASP調用,當然所謂的C++當然是指基于M$的ATL了,純C++的COM是學院派的人干的活,作為工程人員應用才是首要目的。為什么要寫成COM的,因為縱觀網絡編程的世界就asp沒有實現(或者實現了沒有開源)gmail的發信功能,不管jmail還是codsys都沒有,可是是沒有必要,或者是我孤陋寡聞,其他的php、asp.net、java都很容易實現此功能。在asp遍地的過度,寫出來估計還是有一定價值的。 二、要求
  • SSL的大致內容,搞清楚C/S間如何握手的就行了
  • OpenSSL,開源的成功案例,沒有OpenSSL估計我們只能望機興嘆了,搞明白SSL的算法好像不是一兩個月能明白的,所有掌握Openssl是必須的,不用太深入,但是起碼能知道如何建立ssl的上下文和封裝socket的發送和接收。
  • C/C++基礎,上過理工科的人都應該知道。俺打算用C來寫HelloGmail程序,被逼無奈啊,誰讓OpenSSL是用C寫的呢!
  • COM基礎,至少要知道COM是如何實現二進制級代碼共享的,如何用ATL做COM的。俺得畢業論文是搞fortran和java的混合編程,所以對混合編程情有獨鐘。當時還不知道有COM這回事,走了很多的彎路:java調c++寫的dll,c++的dll調fotran的dll,相當的丑陋 ^^
  • 三、開始 1.簡單的認識 我們先在cmd窗口連連gmail看看,把過程弄明白先。由于采用了ssl,所以用普通的telnet是無法直接連接到gmail的smtp的,我們需要openssl構建一個ssl層,由openssl來負責繁瑣的ssl協議 我們先要編譯OpenSSL,下面這篇博文已經寫得很好,俺就不啰嗦了 http://blog.tom.com/blog/read.php?bloggerid=329665&blogid=41867 我在E:/openssl-0.9.8e下

    E:/openssl-0.9.8e/out32dll>openssl s_client -connect smtp.gmail.com:465
    Loading 'screen' into random state - done
    CONNECTED(00000790)
    depth=0 /C=US/ST=California/L=Mountain View/O=Google Inc/CN=smtp.gmail.com
    verify error:num=20:unable to get local issuer certificate
    verify return:1
    depth=0 /C=US/ST=California/L=Mountain View/O=Google Inc/CN=smtp.gmail.com
    verify error:num=27:certificate not trusted
    verify return:1
    depth=0 /C=US/ST=California/L=Mountain View/O=Google Inc/CN=smtp.gmail.com
    verify error:num=21:unable to verify the first certificate
    verify return:1
    ---
    Certificate chain
    ?0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=smtp.gmail.com
    ???i:/C=ZA/ST=Western Cape/L=Cape Town/O=Thawte Consulting cc/OU=Certification S
    ervices Division/CN=Thawte Premium Server CA/emailAddress=premium-server@thawte.
    com
    ---
    Server certificate
    -----BEGIN CERTIFICATE-----
    MIIDYzCCAsygAwIBAgIQYZrZzKZNh1fKVFuUlZ6rKzANBgkqhkiG9w0BAQUFADCB
    zjELMAkGA1UEBhMCWkExFTATBgNVBAgTDFdlc3Rlcm4gQ2FwZTESMBAGA1UEBxMJ
    Q2FwZSBUb3duMR0wGwYDVQQKExRUaGF3dGUgQ29uc3VsdGluZyBjYzEoMCYGA1UE
    CxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjEhMB8GA1UEAxMYVGhh
    d3RlIFByZW1pdW0gU2VydmVyIENBMSgwJgYJKoZIhvcNAQkBFhlwcmVtaXVtLXNl
    cnZlckB0aGF3dGUuY29tMB4XDTA3MDczMDE2NTgwN1oXDTA4MDcyOTE2NTgwN1ow
    aDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1v
    dW50YWluIFZpZXcxEzARBgNVBAoTCkdvb2dsZSBJbmMxFzAVBgNVBAMTDnNtdHAu
    Z21haWwuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQF2mUMNM+qw/i
    wMVSP2D0pgKb0M3RyWHBTQkno3W4y5TeH8LALnqv9/+Th4wZ5PrZ7YPQjmCxdtz6
    Lm5Yx19nDXNw97or6SXvAoZSF+bwh76UFqxpImAGJzvj8Ro7rNkMidJa+KgGaIng
    sIcWuqsj0rrK1AXoUHKmO4N5t0c6XwIDAQABo4GmMIGjMB0GA1UdJQQWMBQGCCsG
    AQUFBwMBBggrBgEFBQcDAjBABgNVHR8EOTA3MDWgM6Axhi9odHRwOi8vY3JsLnRo
    YXd0ZS5jb20vVGhhd3RlUHJlbWl1bVNlcnZlckNBLmNybDAyBggrBgEFBQcBAQQm
    MCQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnRoYXd0ZS5jb20wDAYDVR0TAQH/
    BAIwADANBgkqhkiG9w0BAQUFAAOBgQCUoTmFzdJX+2Pz9FhI+H88lFIeBcFnxpPO
    CHO7zs/J3ZI6ZmkuQm4az89tRqvKvRFrQm2CRlzntqWjSdcsIYlKKGZ32iclpNKw
    1aW/Q3IIyyZTTUo9DJezyCrFBV7JxFXOQgYd45+YxPVUNnkw1lTd4RqweuB5p7r4
    nObS2EE7cA==
    -----END CERTIFICATE-----
    subject=/C=US/ST=California/L=Mountain View/O=Google Inc/CN=smtp.gmail.com
    issuer=/C=ZA/ST=Western Cape/L=Cape Town/O=Thawte Consulting cc/OU=Certification
    ?Services Division/CN=Thawte Premium Server CA/emailAddress=premium-server@thawt
    e.com
    ---
    No client certificate CA names sent
    ---
    SSL handshake has read 1025 bytes and written 314 bytes
    ---
    New, TLSv1/SSLv3, Cipher is DES-CBC3-SHA
    Server public key is 1024 bit
    Compression: NONE
    Expansion: NONE
    SSL-Session:
    ????Protocol : TLSv1
    ????Cipher : DES-CBC3-SHA
    ????Session-ID: AA41A4829FAB5945984CCE49EF1A135703C437F1F169F1BB9D2E8417D6B50B38

    ????Session-ID-ctx:
    ????Master-Key: BEE0D063AF73B0645845F359D8E8A488EC33A38497D381C46ECE6F0E7C8DBFB0
    2EA5A1EE3FFD583DD111EC9567EE6D8F
    ????Key-Arg : None
    ????Start Time: 1188884689
    ????Timeout : 300 (sec)
    ????Verify return code: 21 (unable to verify the first certificate)
    ---
    220 mx.google.com ESMTP c5sm1770312qbc
    EHLO localhost
    250-mx.google.com at your service, [218.80.208.72]
    250-SIZE 28311552
    250-8BITMIME
    250-AUTH LOGIN PLAIN
    250 ENHANCEDSTATUSCODES
    AUTH LOGIN
    334 VXNlcm5hbWU6
    eHVxaW55b25nQGdtYWlsLmNvbQ==
    334 UGFzc3dvcmQ6
    xxxxxxxxx
    235 2.7.0 Accepted

    上面的連接其實是有問題,因為我們沒有裝載我們的證書,所以到RCPT命令的時候,gmail就把我們給踢了,我們在C寫的HelloGmail中將會裝載我們的自己的證書。

    2.用C寫發信程序

    #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;
    }

    參考資料 Beginner's Tutorial: COM/ATL Simple Project

    轉載于:https://www.cnblogs.com/mtcnn/archive/2009/09/07/9410143.html

    總結

    以上是生活随笔為你收集整理的用openssl跟Gmail的smtp对话(一)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。