0

我在文件 testSmimeMsg.txt 中有这样的消息:

ABC is our biggest acquisition ever and as you can imagine, customers
and partners alike are eager to hear how we plan to integrate it into
XYZ.  Specifically, how are we going to bring the two traditionally
separate silos of desktop and mobile together?
To help explain our vision for uniting we released a
video describing our architecture and
technology integration plans.  Definitely watch the video to learn more,
and the rest of this blog will give you a summary of our plans and a bit
more color on certain areas.

我使用以下命令来制作明确的签名消息:

$ openssl smime -sign -in testSmimeMsg.txt -out testSmimeClearTextMessage.txt -signer sender.pem

sender.pem 是从 .p12 文件生成的,它具有 CERTIFICATE 和 RSA PRIVATE KEY 内容。然后我使用以下命令来验证我刚刚创建的签名消息。

$ openssl smime -verify -in testSmimeClearTextMessage.txt -noverify -out testSmimeVerifiedClearTextMessage.txt

结果是验证成功,并且 testSmimeVerifiedClearTextMessage.txt 中的内容与 testSmimeMsg.txt 相同。完美的!现在假设我想通过 PKCS7_verify() 方法验证相同的内容。C代码

jbyteArray aw_SMIME_Verify_Signature_And_Get_Message(JNIEnv *env, jobject obj, jbyteArray signedMsg, jstring senderCertPath, jstring rootCertPath)
{
    //SenderCertPath and rootCertPath are currently NULL. For now, I just want openssl
    //to extract the signer cert from message and verify message. Root certificate and chain
    //of trust verification etc is ignored for now.

    jbyteArray cmsContent = NULL;


    PKCS7 *pkcs7 = NULL;

    OpenSSL_add_all_algorithms();
    ERR_load_crypto_strings();
    ERR_load_X509_strings();
    ERR_load_PKCS7_strings();
    ERR_load_BIO_strings();

    pkcs7 = getP7FromEncryptedMessage_SMIME(env, signedMsg); //this works. pkcs7 is non null.

    if (pkcs7 == NULL) {
        LOGE ("aw_SMIME_Verify_Signature_And_Get_Message: Error reading p7 from message. Returning");
        goto exit_free;
    }
    cmsContent = verify_Signature_And_Get_Message(env, pkcs7, senderCertPath, rootCertPath);

    exit_free:
    if (pkcs7) {
        PKCS7_free(pkcs7);
        pkcs7 = NULL;
    }

    return cmsContent;
}

------------------------------
PKCS7 *getP7FromEncryptedMessage_SMIME(JNIEnv *env, jbyteArray encryptedSMIMEMessage) {

    BIO *in = NULL;
    int encryptedMessageLength = 0;
    const unsigned char *encryptedBuf = NULL;
    PKCS7 *p7 = NULL;

    //obtain the p7 structure from the encrypted message
    encryptedMessageLength = env->GetArrayLength(encryptedSMIMEMessage);                    //get size of encrypted message byte[]
    encryptedBuf = (const unsigned char *)env->GetByteArrayElements(encryptedSMIMEMessage, 0);                                              //create a buffer of that size
    in = BIO_new(BIO_s_mem());
    BIO_set_mem_eof_return(in, 0);
    BIO_write(in, encryptedBuf, encryptedMessageLength);                                    //create a BIO with the char* of encrypted message

    p7 = SMIME_read_PKCS7(in, NULL);                                            //get the p7 structure

    if(in) {
        BIO_free(in);
    }
    if (encryptedBuf) {
        env->ReleaseByteArrayElements(encryptedSMIMEMessage, (jbyte *)encryptedBuf, 0);
    }

    return p7;

}
----------------------
jbyteArray verify_Signature_And_Get_Message(JNIEnv *env, PKCS7 *pkcs7, jstring senderCertPath, jstring rootCertPath)
{
    X509* rootCert = NULL;
    X509* senderCert = NULL;
    STACK_OF(X509) *st1 = NULL;
    X509_STORE* m_store = NULL;
    BIO *out = BIO_new(BIO_s_mem());
    BIO_set_fp(out, stdout, BIO_NOCLOSE);
    BUF_MEM *bptr = NULL;
    jbyteArray cmsContent = NULL;
    int cmsLen = 0;

    if(rootCertPath != NULL) {
        rootCert = getCertificateFromPath(env, rootCertPath);
        m_store = X509_STORE_new();
        //TODO: check what to be in cert store
        X509_STORE_add_cert(m_store,rootCert);
    }

    if(senderCertPath != NULL) {
        senderCert = getCertificateFromPath(env, senderCertPath);
        st1 = sk_X509_new_null();
        sk_X509_push(st1, senderCert);
    }
    //st1 and m_store are NULL as they are not used for now.
    int verifyResult = PKCS7_verify( pkcs7, st1, m_store, NULL, out, PKCS7_NOVERIFY);
    if(verifyResult != 1) {   //FAILS HERE!!!!
        LOGE ("verify_Signature_And_Get_Message: Error verifying signer certificate. Returning");
        LOGE(ERR_error_string(ERR_get_error(), NULL));
        goto exit_free;
    }
    BIO_get_mem_ptr(out, &bptr);

    cmsLen = bptr->length;
    cmsContent = env->NewByteArray(cmsLen);
    env->SetByteArrayRegion(cmsContent, 0, cmsLen, (jbyte *)bptr->data);

    exit_free:
    if (serverCert) {
        X509_free(serverCert);
        serverCert = NULL;
    }
    if (rootCert) {
        X509_free(rootCert);
        rootCert = NULL;
    }
    if (m_store) {
        X509_STORE_free(m_store);
        m_store = NULL;
    }
    if (st1) {
        sk_X509_pop_free(st1, X509_free);
    }
    if (out) {
        BIO_free_all(out);
        out = NULL;
    }

    return cmsContent;
}

运行时,出现错误:

 verify_Signature_And_Get_Message: Error verifying signer certificate. Returning
 error:2107507A:PKCS7 routines:PKCS7_verify:no content

有人可以告诉我有什么问题吗?请注意,如果我传递了一个签名数据消息,并且代码未更改,它就可以工作。我得到了验证成功和明文数据,但是当我发送一个明确的签名数据时,它失败了。请帮忙。

4

1 回答 1

0

我解决了这个问题。问题是我没有使用 PKCS7_read_SMIME() API 的内容参数。如果消息是明确签名的,则在此参数中返回消息内容,然后需要将其与 NODETACHED 标志一起传递给 PKCS7_verify() 方法。有关更多详细信息,请参阅这两个 API 的 openssl 文档。

于 2014-06-06T17:29:38.307 回答