【OpenSSL】使用SMIME发送签名和加密邮件

本文详细介绍了证书生成过程,包括根节点证书、alice和bob的证书生成,并阐述了邮件签名、加密及验证方法。重点讲解了SSL/TLS安全通信的基础知识。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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 "/emailAddress=imalice.freemail@gmail.com" -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 "/emailAddress=iambob.freemail@gmail.com" -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 imalice.freemail@gmail.com -to iambob.freemail@gmail.com -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 imalice.freemail@gmail.com -to iambob.freemail@gmail.com -subject HiBob  bobcert.pem

To: iambob.freemail@gmail.com
From: imalice.freemail@gmail.com
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 imalice.freemail@gmail.com -to iambob.freemail@gmail.com -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



<think>嗯,用户想知道如何使用OpenSSL验证PKCS7格式的软件签名。首先,我得回忆一下PKCS7的相关知识。PKCS7是一种加密消息语法标准,常用于数字签名证书传输。验证签名通常需要签名文件、原始数据相关的证书链。 根据用户提供的引用,特别是引用[2]引用[4],里面提到了使用OpenSSL库进行验证的代码示例。不过用户可能需要的是命令行的方法,而不仅仅是编程实现。记得OpenSSL命令行工具可以处理PKCS7签名,可能需要用到openssl smime或者openssl cms命令。 首先,用户需要准备几个文件:签名文件(通常是.p7b或.p7s格式)、原始数据文件(被签名的内容),以及可能的证书链文件(比如根证书或中间证书)。验证过程中,需要确保签名中的证书链是可信的,可能需要用到信任的CA证书。 然后,参考引用[3]中提到生成PKCS12证书的步骤,可能验证时也需要用到类似的证书私钥。不过验证签名一般不需要私钥,只需要公钥证书。可能需要用-certfile参数指定证书文件。 接下来,具体的命令可能是这样的:使用openssl smime -verify命令,指定输入签名文件、原始数据、证书文件输出结果。例如: openssl smime -verify -in signature.p7s -content original.txt -certfile cert.pem -noverify 这里的-noverify可能用于跳过证书链验证,但实际应用中应该避免,确保证书链完整且可信。 另外,引用[2]中提到的使用OpenSSL库验证签名的C代码,用户可能需要更详细的命令行步骤。可能需要将签名文件、原始数据、以及相关证书准备好,然后执行验证命令,检查返回结果是否正确。 还要注意,如果签名是分离式(detached),则需要使用-content参数指定原始数据文件;如果是嵌入式签名,可能不需要。例如,对于分离式签名,命令中需要包含-content original.txt,而嵌入式则不需要。 用户可能遇到的问题包括证书链不完整、证书不受信任,或者签名文件格式不正确。需要提示用户确保所有必要的证书都已包含,并且格式正确(如PEM或DER)。 最后,总结步骤应该是:准备文件,执行验证命令,解析输出结果。如果验证成功,OpenSSL会输出验证成功的信息,否则会报错。同时,需要注意OpenSSL版本差异,不同版本可能命令参数有所不同,建议用户确认自己使用OpenSSL版本。</think>### 使用OpenSSL验证PKCS7格式的软件签名方法 #### 步骤1:准备必要文件 1. **签名文件**:PKCS7格式的签名文件(通常为`.p7b`或`.p7s`) 2. **原始数据文件**:被签名的原始文件(例如`original.txt`) 3. **证书链文件**:签名者证书及信任链证书(例如`cert.pem`) --- #### 步骤2:使用OpenSSL命令行验证签名 ```bash openssl smime -verify \ -in signature.p7s \ # 输入PKCS7签名文件 -content original.txt \ # 被签名的原始文件(分离式签名时必须) -inform DER \ # 指定签名文件格式(DER或PEM,默认PEM) -certfile cert.pem \ # 签名者证书或信任链证书 -noverify # 可选:跳过证书链验证(仅测试时使用) ``` --- #### 步骤3:解析验证结果 - **验证成功**:终端输出`Verification successful` - **验证失败**:显示具体错误(例如`Verification Failure`或证书错误) --- #### 关键参数说明 1. **`-content`**:仅用于分离式签名(Detached Signature),需与原始文件匹配 2. **`-inform DER`**:若签名文件为二进制格式(非PEM),必须添加此参数 3. **`-certfile`**:若签名中未包含证书链,需手动指定证书文件[^2] --- #### 示例代码(C语言验证签名) 参考引用[4]的签名验证逻辑,核心代码如下: ```c #include <openssl/pkcs7.h> #include <openssl/x509.h> PKCS7 *p7 = d2i_PKCS7_bio(in_bio, NULL); // 读取PKCS7签名 X509_STORE *store = X509_STORE_new(); // 初始化证书信任库 X509_STORE_add_cert(store, cert); // 添加信任的根证书 int result = PKCS7_verify(p7, NULL, store, in_data, NULL, PKCS7_NOVERIFY); // 返回1表示验证成功,0表示失败[^4] ``` --- #### 常见问题排查 1. **证书链不完整** 错误提示:`unable to get local issuer certificate` 解决方法:通过`-certfile`补充中间证书或根证书 2. **签名格式错误** 错误提示:`no content type` 解决方法:检查签名文件是否为PKCS7格式(可通过`openssl pkcs7 -in file.p7s -text`验证) ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值