1. 程式人生 > >【OpenSSL】使用SMIME/CMS傳送簽名和加密郵件

【OpenSSL】使用SMIME/CMS傳送簽名和加密郵件

1,通訊雙方的證書生成

1.1生成根節點證書

openssl genrsa -out cakey.pem 2048
openssl req -new -key cakey.pem -subj "/CN=rootca.bitbaba.com" -out cacsr.pem
openssl x509 -req -in cacsr.pem -days 999 -signkey cakey.pem -out cacert.pem
1.2生成alice的證書

openssl genrsa -out alicekey.pem 2048
openssl req -new -key cakey.pem -subj "/

[email protected]" -out alicecsr.pem
openssl x509 -req -in alicecsr.pem -days 999 -CA cacert.pem -CAKey cakey.pem -set_serial 01 -name "alice" -out alicecert.pem
openssl pkcs12 -export -in alicecert.pem -inkey alicekey.pem -certfile cacert.pem -out alice.p12

1.3生成bob的證書

openssl genrsa -out bobkey.pem 2048
openssl req -new -key bobkey.pem -subj "/

[email protected]" -out bobcsr.pem
openssl x509 -req -in bobcsr.pem -days 999 -CA cacert.pem -CAkey cakey.pem -set_serial 02 -name "bob" -out bobcert.pem
openssl pkcs12 -export -in bobcert.pem -inkey bobkey.pem -certfile cacert.pem -out bob.p12


2,郵件簽名

openssl smime -sign -in /tmp/msg.txt -signer alicecert.pem -inkey alicekey.pem -nocerts -nodetach -text -out /tmp/alicesigned.eml 


提醒:

-nodetach 把資訊原文也包含到base64塊裡面,而不是用mime格式的分隔符單獨放置,比較容易保證資訊不被郵件收發伺服器重構,導致驗證失敗。

-nocerts    是一個可選選項,如果設定的話,alice的證書(公鑰等)不會被包含到簽名信息裡面(base64塊)

-signer      在簽發郵件的時候,指定傳送人的證書位置,這裡指定alice的證書

3,簽名驗證

openssl smime -verify -in /tmp/alicesigned.eml -certfile alicecert.pem -CAfile cacert.pem


注意:

-signer  引數這個時候的意思:匯出簽發郵件的證書儲存。所以要小心覆蓋原有證書

-CAfile  設定信任的ca位置,否則驗證不通過

-certfile 是一個可選選項,如果簽名的時候指定了-nocerts,這裡可以指定驗證證書(alice),這樣網路傳輸經濟。

4,郵件加密

 smime -encrypt -in /tmp/msg.txt -from [email protected] -to [email protected] -des3 -out /tmp/msg.eml bobcert.pem


5,郵件解密

 openssl smime -decrypt -in /tmp/msg.eml -recip bobcert.pem -inkey bobkey.pem


6, 簽名並加密
openssl smime -sign -in msg.txt -signer alicecert.pem -inkey alicekey.pem -nocerts -nodetach -text | openssl smime -encrypt -des3 -from [email protected] -to [email protected] -subject HiBob  bobcert.pem

To: [email protected]
From: [email protected]
Subject: HiBob
MIME-Version: 1.0
Content-Disposition: attachment; filename="smime.p7m"
Content-Type: application/x-pkcs7-mime; smime-type=enveloped-data; name="smime.p7m"
Content-Transfer-Encoding: base64
 
MIIGKQYJKoZIhvcNAQcDoIIGGjCCBhYCAQAxggFmMIIBYgIBADBKMEUxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQCAQMwDQYJKoZIhvcNAQEBBQAEggEAdmR6L5KWIhmIFBwj
UV2wxBb8S20+TH+ZsQ7NtHN/FucV+LMkRWsif03ExRqnsLwigQSXinigsOrgpovn
X8JpfiOQp3cg6KEyhX0+q2Ziiu4qRNZLCKoWXZ4oxyYORe8PT1R9NwSfnfVcHvec
duyOMYdp3T50844CXQ0NMv/FjEv5bdhN5TdPvEhyOcaQ4g/Fhsh0kPPFVNWnLFIw
6p+2K5sZr749RvGuzmZuwd4WvAtPO/bgBks7sbR8mR7jXLZaq8Q/NHN913Jq5Pf2
VATbIDUbvbD2Znv22NJOt600Et+yi4xHT/TG5TXVYZSuayOPhVkX032Gycgp3c35
UaYHozCCBKUGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQI525g7nh7tU6AggSAxAL5
yGDcR3M+xZZELlG1/JcUKWLUmZQoqKyKtT5gk61lMJ6Si4LcQSlYP+IySeAYB9fw
RY+uKepW0snNHMO/IrT+EtKn/qJgm/OJSEf5YrCwmJx/k1Pv2BZu4GeTmnB5cfKx
xTus0bhiGR7tqWRv9XrexhdeUKumyJMzr9Vxzfnz+ahTk510npW3Ei+4rKkQOO3z
mrwRUril/J9onvInkvjAOwMceKTyjrCzEJv3f5JMreqwSjeTnxQcihJHdqPo1NpZ
RSNIsG83Hz2/mMNuRgVQi7DVWqJlcsv4OG9J6Dw6Xp7bnskppoMYMsZzOon0X4o+
JTjb9lyhxcXPE8htbd3qg1EroMByoWD/HcKLYv00vo1Gd5mgHCEqp0a6/WrpLlGQ
JDJDFqJ2TEJCbgAiTejxns+t/zQyC9iOVSP+S1/rkzuZV28O7zCDjJwxGK1rUFa1
Epa4jlciFyppuzzxYICxSDNVAfFsGLW3heuxFqew3aUufDcjzhkDYGrZpWd91C0/
WYqVQM5VYtpqTZHUfNAkFvyuB2jqi265/rvsgpIb1mlC3ee4DbAqAz9a8HMMajkN
rRWGuGm9S/Zz4QskAaNYdQXqmv2UT2NmDhcv+zGqH0vzlGs0k9Ae0My1cucBPmFO
NjbM11yHTSKN1sqlRtzQiCi7IbM5B4Q2O8/jhvO07ezRz5Fj4o4PxpElQ/7mtusg
Fz97HA4guZ+8Ig/NoG7HkdJh5Ju0fTGnqDosG3jXJWtJlXrsA3qHwdbk1Z8ux7xf
L6fVmO2dEBUkc6ihMvDgyZByUbyauEfyCwSb0UfJeJbbfY9UmsBWbU635rLn5Fcx
MTY9JwoD/SgEYRm3XhxphO+xy2LAVal4GULlcqtXeGKLUzuRavn/MCP7V5xLEX8Z
3hih/eJ/OFOUL/Hndr5py3oLavhV+mFwNTJrQ2Jrk9DwnsnUS70Z8nEKbe9O41Xl
rcll6nLMnY6qXmA47tz5NM7uPGBpus5cInRnI2ndGnGJt0pW30ubn1gH/sYA6iwR
aWTz4gxo1h9pVfJ6z8P6guXJaS5X6NLGVfl6EPs1EwEEbc0zd3r9iphcARtnI4U6
fOa5QeRWd8KI/XpSS9KXM90Jdphxz1E1iD9VGkFPhxRq0HMaEZu2ggD2HUTHibyZ
9fV9f6wf2Hx4Wng1Eh1PDiffnIYkrEYdfu2Uqt7HaYxz1T0qbrkHNJOjT8eZ3aZW
yLn/bEDeyxeLcsGDOt6hdW0C0PaoLzv6okKbprLgx4Dfxfh0ytu1m/M6WoVO3/QB
ELvxshSBc77P4+UAAlDjRhpQRuDOa0xU5DHeb3DDogRGw8nWpleyqQsTlgQmzYWJ
w8ps+VbrGTn3hNkGcLgkqXWy5uLocuj+61RB8HZAdNMhjAKHvr9pGhac1hbLW7aP
uehFCfCo4P0vDNJpjV7JDG8y+j89guGbC8ew3Hd7LYGucdGYWgnKxBRpmG5dJ7Vi
swGNTSOWATI+Lz+sySCVHyrKbsf3IfFsjdMZxQrZttnm63q5rRam/F0VMbEE


7,解密並驗證

openssl smime -decrypt -in enc.eml -recip bobcert.pem -inkey bobkey.pem | openssl smime -verify -certfile alicecert.pem -CAfile cacert.pem


Content-Type: text/plain
 
 Hello, World !
Verification successful


管道命令

openssl smime -sign -in msg.txt -signer alicecert.pem -inkey alicekey.pem -nocerts -nodetach -text | \
openssl smime -encrypt -des3 -from [email protected] -to [email protected] -subject HiBob  bobcert.pem | \
openssl smime -decrypt -recip bobcert.pem -inkey bobkey.pem | \
openssl smime -verify -certfile alicecert.pem -CAfile cacert.pem

8,郵件傳送

關於smtp客戶端的例子

9,郵件接收

關於pop3的例子

備註:

1)關於cms的一些資料結構定義

子結構的詳細定義可以參考:https://github.com/openssl/openssl/blob/master/crypto/cms/cms_lcl.h

struct CMS_ContentInfo_st {
    ASN1_OBJECT *contentType;
    union {
        ASN1_OCTET_STRING *data;
        CMS_SignedData *signedData;
        CMS_EnvelopedData *envelopedData;
        CMS_DigestedData *digestedData;
        CMS_EncryptedData *encryptedData;
        CMS_AuthenticatedData *authenticatedData;
        CMS_CompressedData *compressedData;
        ASN1_TYPE *other;
        /* Other types ... */
        void *otherData;
    } d;
};


PKCS7的遞推定義

/*-
Encryption_ID           DES-CBC
Digest_ID               MD5
Digest_Encryption_ID    rsaEncryption
Key_Encryption_ID       rsaEncryption
*/
 
typedef struct pkcs7_issuer_and_serial_st {
    X509_NAME *issuer;
    ASN1_INTEGER *serial;
} PKCS7_ISSUER_AND_SERIAL;
 
typedef struct pkcs7_signer_info_st {
    ASN1_INTEGER *version;      /* version 1 */
    PKCS7_ISSUER_AND_SERIAL *issuer_and_serial;
    X509_ALGOR *digest_alg;
    STACK_OF(X509_ATTRIBUTE) *auth_attr; /* [ 0 ] */
    X509_ALGOR *digest_enc_alg;
    ASN1_OCTET_STRING *enc_digest;
    STACK_OF(X509_ATTRIBUTE) *unauth_attr; /* [ 1 ] */
    /* The private key to sign with */
    EVP_PKEY *pkey;
} PKCS7_SIGNER_INFO;
 
DECLARE_STACK_OF(PKCS7_SIGNER_INFO)
DECLARE_ASN1_SET_OF(PKCS7_SIGNER_INFO)
 
typedef struct pkcs7_recip_info_st {
    ASN1_INTEGER *version;      /* version 0 */
    PKCS7_ISSUER_AND_SERIAL *issuer_and_serial;
    X509_ALGOR *key_enc_algor;
    ASN1_OCTET_STRING *enc_key;
    X509 *cert;                 /* get the pub-key from this */
} PKCS7_RECIP_INFO;
 
DECLARE_STACK_OF(PKCS7_RECIP_INFO)
DECLARE_ASN1_SET_OF(PKCS7_RECIP_INFO)
 
typedef struct pkcs7_signed_st {
    ASN1_INTEGER *version;      /* version 1 */
    STACK_OF(X509_ALGOR) *md_algs; /* md used */
    STACK_OF(X509) *cert;       /* [ 0 ] */
    STACK_OF(X509_CRL) *crl;    /* [ 1 ] */
    STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
    struct pkcs7_st *contents;
} PKCS7_SIGNED;
/*
 * The above structure is very very similar to PKCS7_SIGN_ENVELOPE. How about
 * merging the two
 */
 
typedef struct pkcs7_enc_content_st {
    ASN1_OBJECT *content_type;
    X509_ALGOR *algorithm;
    ASN1_OCTET_STRING *enc_data; /* [ 0 ] */
    const EVP_CIPHER *cipher;
} PKCS7_ENC_CONTENT;
 
typedef struct pkcs7_enveloped_st {
    ASN1_INTEGER *version;      /* version 0 */
    STACK_OF(PKCS7_RECIP_INFO) *recipientinfo;
    PKCS7_ENC_CONTENT *enc_data;
} PKCS7_ENVELOPE;
 
typedef struct pkcs7_signedandenveloped_st {
    ASN1_INTEGER *version;      /* version 1 */
    STACK_OF(X509_ALGOR) *md_algs; /* md used */
    STACK_OF(X509) *cert;       /* [ 0 ] */
    STACK_OF(X509_CRL) *crl;    /* [ 1 ] */
    STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
    PKCS7_ENC_CONTENT *enc_data;
    STACK_OF(PKCS7_RECIP_INFO) *recipientinfo;
} PKCS7_SIGN_ENVELOPE;
 
typedef struct pkcs7_digest_st {
    ASN1_INTEGER *version;      /* version 0 */
    X509_ALGOR *md;             /* md used */
    struct pkcs7_st *contents;
    ASN1_OCTET_STRING *digest;
} PKCS7_DIGEST;
 
typedef struct pkcs7_encrypted_st {
    ASN1_INTEGER *version;      /* version 0 */
    PKCS7_ENC_CONTENT *enc_data;
} PKCS7_ENCRYPT;
 
typedef struct pkcs7_st {
    /*
     * The following is non NULL if it contains ASN1 encoding of this
     * structure
     */
    unsigned char *asn1;
    long length;
# define PKCS7_S_HEADER  0
# define PKCS7_S_BODY    1
# define PKCS7_S_TAIL    2
    int state;                  /* used during processing */
    int detached;
    ASN1_OBJECT *type;
    /* content as defined by the type */
    /*
     * all encryption/message digests are applied to the 'contents', leaving
     * out the 'type' field.
     */
    union {
        char *ptr;
        /* NID_pkcs7_data */
        ASN1_OCTET_STRING *data;
        /* NID_pkcs7_signed */
        PKCS7_SIGNED *sign;
        /* NID_pkcs7_enveloped */
        PKCS7_ENVELOPE *enveloped;
        /* NID_pkcs7_signedAndEnveloped */
        PKCS7_SIGN_ENVELOPE *signed_and_enveloped;
        /* NID_pkcs7_digest */
        PKCS7_DIGEST *digest;
        /* NID_pkcs7_encrypted */
        PKCS7_ENCRYPT *encrypted;
        /* Anything else */
        ASN1_TYPE *other;
    } d;
} PKCS7;


PKCS7 vs CMS

PKCS#7 is an old standard from RSA Labs, published later on as an "informational RFC". Then, a new versions was produced, as an "Internet standard", i.e. with the seal of approval from the powers-that-be at IETF; a new name was invented for that: CMS. Newer versions were subsequently defined: RFC 3369, RFC 3852, RFC 5652. You can consider CMS and PKCS#7 to both designate the same standard, which has several versions.
 
CMS (PKCS#7) is a format for applying encryption, signatures and/or integrity checks on arbitrary binary messages (which can be large). It can be nested. It is the basis for some protocols such as time stamping. It is also frequently (ab)used as a container for X.509 certificates: the SignedData type includes a field for a set of signatures (and that set can be empty), and also a field to store arbitrary X.509 certificates which are considered as "potentially useful" for whoever processes the object.
 
CMS is nominally backward compatible: there are version fields at various places, and a library which understands a version of CMS should be able to process messages from older versions; moreover, such a library should also produce messages which are compatible with other versions, inasmuch as it is feasible given the message contents. See section 5.1 for an example: the "version" fields are set to the minimal values which still make sense given what else is in the structure.

        if (noout) {
            if (print)
                CMS_ContentInfo_print_ctx(out, cms, 0, NULL);
        } else if (outformat == FORMAT_SMIME) {
            if (to)
                BIO_printf(out, "To: %s\n", to);
            if (from)
                BIO_printf(out, "From: %s\n", from);
            if (subject)
                BIO_printf(out, "Subject: %s\n", subject);
            if (operation == SMIME_RESIGN)
                ret = SMIME_write_CMS(out, cms, indata, flags);
            else
                ret = SMIME_write_CMS(out, cms, in, flags);
        } else if (outformat == FORMAT_PEM)
            ret = PEM_write_bio_CMS_stream(out, cms, in, flags);
        else if (outformat == FORMAT_ASN1)
            ret = i2d_CMS_bio_stream(out, cms, in, flags);
        else {
            BIO_printf(bio_err, "Bad output format for CMS file\n");
            goto end;
        }

    else {
        if (to)
            BIO_printf(out, "To: %s\n", to);
        if (from)
            BIO_printf(out, "From: %s\n", from);
        if (subject)
            BIO_printf(out, "Subject: %s\n", subject);
        if (outformat == FORMAT_SMIME) {
            if (operation == SMIME_RESIGN)
                SMIME_write_PKCS7(out, p7, indata, flags);
            else
                SMIME_write_PKCS7(out, p7, in, flags);
        } else if (outformat == FORMAT_PEM)
            PEM_write_bio_PKCS7_stream(out, p7, in, flags);
        else if (outformat == FORMAT_ASN1)
            i2d_PKCS7_bio_stream(out, p7, in, flags);
        else {
            BIO_printf(bio_err, "Bad output format for PKCS#7 file\n");
            goto end;
        }

2) smtp如何傳送郵件

https://technet.microsoft.com/en-us/library/dd441082.aspx

https://tools.ietf.org/html/rfc821

https://tools.ietf.org/html/rfc2554

https://tools.ietf.org/html/rfc2821

http://tools.ietf.org/html/rfc5321

郵件如何在smtp伺服器之間路由 http://en.wikipedia.org/wiki/MX_record

如何通過郵件地址字尾的domain來查詢郵件伺服器(smtp)的地址:nslookup -type=mx sina.com
--------------------- 
作者:開心樂源 
來源:CSDN 
原文:https://blog.csdn.net/hacode/article/details/43851927 
版權宣告:本文為博主原創文章,轉載請附上博文連結!

相關推薦

OpenSSL使用SMIME/CMS傳送簽名加密郵件

1,通訊雙方的證書生成 1.1生成根節點證書 openssl genrsa -out cakey.pem 2048 openssl req -new -key cakey.pem -subj "/CN=rootca.bitbaba.com" -out cacsr.pem

OpenSSL使用SMIME傳送簽名加密郵件

1,通訊雙方的證書生成 1.1生成根節點證書 openssl genrsa -out cakey.pem 2048 openssl req -new -key cakey.pem -subj "/CN=rootca.bitbaba.com" -out cacsr.pem

rtmp協議傳送mp3aac裸流的方法

本文轉自部落格:https://blog.csdn.net/dfb714620427/article/details/71173463 --------------------------------------------------------------------------------

乾貨使用Java傳送各種格式的郵件

          測試可用:          有些重複程式碼沒有給註釋。類的方法作用自行檢視API瞭解,最後附上原始碼。         首先使用JavaMail的jar,官網可下載。        公共靜態的常量: public final static Str

轉載Hadoop 2.7.3 Hbase 1.2.4安裝教程

啟動 運行 property new rop net 文本文 .tar.gz cor 轉載地址:http://blog.csdn.net/napoay/article/details/54136398 目錄(?)[+] 一、機器環境

bzoj3261最大異或

異或 ... urn fin pri bit names -- else 就是一個可持久化Trie....... #include<bits/stdc++.h> #define N 600005 using namespace std; inline int

C字符串常量字符數組

gcc pre class fun 後者 一段 put light cmp 此次博客是轉載某位博主的文章,不過現在找不到了,所以先聲明一下。 先貼一段代碼: #include <stdio.h> int main(int argc, const char**

Jenkins怎麽啟動停止服務

class jenkins配置 con 曾經 每次 一個 sta base dsm 筆者沒有把Jenkins配置到tomcat中,每次都是用命令行來啟動Jenkins。但是遇到一個問題:Jenkins一直是開著的,想關閉也關閉不了。百度了一些資料,均不靠譜(必須吐槽一下百

Servlet深入淺出Java重定向請求轉發

列表 url地址 ssi 什麽 stack led 要去 處理 代碼 import java.text.*; import java.util.*; import java.io.*; import javax.servlet.http.*; i

bzoj3281最大異或 可持久化Trie樹

log pac 序列 str char s pan pri scan bool 題目描述 給定一個非負整數序列 {a},初始長度為 N。 有M個操作,有以下兩種操作類型:1、A x:添加操作,表示在序列末尾添加一個數 x,序列的長度 N+1。2、Q l r x

Python格式化字符串format函數

blog 結構 位置 傳遞 color 格式 數據結構 格式符 -- ## 本文基於Python3,可能存在部分內容不適配Python2 1. 最簡單的字符串的輸出: str1 = ‘popma is so cool‘ print(str1) 輸出: popma is

線性代數-矩陣-5矩陣化簡 CC++實現

tar tput c++ spec 但是 exc c++語言 emp opened 點擊這裏可以跳轉至 【1】矩陣匯總:http://www.cnblogs.com/HongYi-Liang/p/7287369.html 【2】矩陣生成:http://www.cnblog

python的淺拷貝深拷貝

end ont code append pen ron 實例 賦值 深拷貝 直接賦值:其實就是對象的引用(別名)。 淺拷貝(copy):拷貝父對象,不會拷貝對象的內部的子對象。 深拷貝(deepcopy): copy 模塊的 deepcopy 方法,完全拷貝了父對象及其

Java裏面的intInteger的區別

之間 assert 默認 out val 就會 java常量池 使用 spa int和Integer的區別 1、Integer是int的包裝類,int則是java的一種基本數據類型 2、Integer變量必須實例化後才能使用,而int變量不需要 3、Integer實際是對象

轉載表單中 Readonly Disabled 的區別

作用 .net 單元 ont 應該 表單元 als 利用 取數 今天寫代碼,遇到表單提交的問題,某個字段在不同的情況下,要傳遞不同的值進行賦值,試過一些方法都有些問題,後來請教前端同學,使用 disabled 這個屬性終於搞定了問題,查到一篇講解 readonly 和 di

DTOJ1001:長方形周長面積

作品 預處理 -s 簡化 賦值語句 標準輸入cin 麻煩 ret class DTOJ 1001:長方形周長和面積 解題報告 ——由翺翔的逗比w原創 題目信息: 題目描述 已知長方形的長和寬,求長方形的周長和面積? 輸入 一行:空格隔開的兩個整數,表示長和寬 輸

pythonpython值傳遞問題內存管理機制

python1)值傳遞問題python中到底是"值傳遞"還是"引用傳遞",主要取決於對象是否是可變的. 1)函數傳參: ·基本數據類型:int、float、str;元祖屬於不可變對象;傳遞的是"原值"的拷貝 ·列表、字典、類、類實例屬於可變對象;傳遞的是"值引用" 2)

轉載圖解 Python 深拷貝淺拷貝

div 原子 總結 但是 home 後來 idt scrip 需要 作者:田小計劃 出處:http://www.cnblogs.com/wilber2013/ Python中,對象的賦值,拷貝(深/淺拷貝)之間是有差異的,如果使用的時候不註意,就可能產生意外的結果。

轉載關於java 的InputStreamOutputStream的理解

class n) sep ring inpu 寫入 clas close ava 關於InputStream和OutputStream的輸入輸出方向的理解 InputStream輸入類,首先需要讀取的內容轉化成輸入流,再從它那裏進行讀取,先關聯源;之後過程中關聯目的,這樣形

托管代碼非托管代碼的區別

產生 沒有 匯編代碼 cati 一行 包含 虛擬機 被調用 庫類 什麽是托管代碼(managed code)? 托管代碼是一microsoft的中間語言(IL),他主要的作用是在.NET FRAMEWORK的公共語言運行庫(CLR)執行代碼前去編譯