Swift(Linux):提取CMS/PKCS#7 Certs并验证容器签名?

Sha*_*man 7 c openssl digital-signature swift pkcs#7

我正在Swift 4中编写一组将在Linux上运行的服务.我需要做的一件事是接收使用加密消息语法(CMS)格式进行数字签名的有效负载,提取用于签名的证书,然后验证签名.我知道Linux上的Swift不包含用于此类事情的Security或CommonCrypto框架,所以我在OpenSSL中链接以尝试帮助解决这个问题.我距离我的C/C++编程时间已经有两年了,所以我很乐意承认我对这部分代码感到满意.

我有2个简单的类来充当OpenSSL BIOPKCS7数据结构的包装器.它们看起来像这样:

import Foundation
import OpenSSL

public final class BIOWrapper {

    public var bio = BIO_new(BIO_s_mem())

    public init(data: Data) {
        data.withUnsafeBytes { pointer -> Void in
            BIO_write(self.bio, pointer, Int32(data.count))
        }
    }

    public init() {}

    deinit {
        BIO_free(self.bio)
    }
}

public final class PKCS7Wrapper {

    public var pkcs7: UnsafeMutablePointer<PKCS7>

    public init(pkcs7: UnsafeMutablePointer<PKCS7>) {
        self.pkcs7 = pkcs7
    }

    deinit {
        PKCS7_free(self.pkcs7)
    }
}
Run Code Online (Sandbox Code Playgroud)

我能够成功提取PKCS#7容器数据并验证数据类型代码值是否正在NID_pkcs7_signed使用此代码:

let reqData = Data(bytes: reqBytes)
        guard reqData.count > 0 else {
            print("Empty request body")
            return nil
        }

        let bioWrapper = BIOWrapper(data: reqData)
        guard let container = d2i_PKCS7_bio(bioWrapper.bio, nil) else {
            print("No container")
            return nil
        }

        let pkcs7Wrapper = PKCS7Wrapper(pkcs7: container)
        let dataTypeCode = OBJ_obj2nid((pkcs7Wrapper.pkcs7.pointee.d.sign).pointee.contents.pointee.type)
        print("dataTypeCode : \(dataTypeCode)")

        if dataTypeCode == NID_pkcs7_data {
            print("GOT DATA!")
        } else {
            print("Didn't get data")
            return nil
        }

       let pkcs7SignedTypeCode = OBJ_obj2nid(pkcs7Wrapper.pkcs7.pointee.type)
        if let signed = pkcs7SignedTypeCode == NID_pkcs7_signed {
            print("Signed : \(signed)")
        }
Run Code Online (Sandbox Code Playgroud)

但是,我现在已经到了我被卡住的地步.如何从PKCS#7有效负载中获取X.509证书数据?我可以看到pkcs7Wrapper.pkcs7.pointee.d.sign.pointee.cert数据结构应该包含证书链数据.它的数据类型是UnsafeMutablePointer<stack_st_x509>,我认为PKCS7_verify一旦我在内存中获得X.509证书数据,我就可以找出使用OpenSSL 方法的代码.我只是不知道该怎么做.

我发现这个资源谈论验证OSX/iOS上的收据,这些收据涉及很多相同的问题.他们从文件系统获取X.509证书,并将数据传递给PKCS7_verify方法.我只需要知道如何从PKCS#7容器中获取证书数据.

谁能帮我这个?我认识到从Swift调用C并不理想,但是由于没有一个良好的Swift安全/加密框架,我不知道任何其他选项.

mni*_*tic 4

答案的核心部分在您链接的代码中:

let store = X509_STORE_new()
X509_STORE_add_cert(store, appleRootX509)
OpenSSL_add_all_digests()
let result = PKCS7_verify(receiptPKCS7, nil, store, nil, nil, 0)
if result != 1 {
    log.atLevelDebug(id: 0, source: "Main", message: "Receipt signature verification failed")
    exit(errorCode)
}
Run Code Online (Sandbox Code Playgroud)

您似乎缺少的是您不必自己从 PKCS7 数据中提取 X509 证书。该PKCS7_verify 函数将执行此操作作为验证的一部分:

尝试查找所有签名者的证书,首先查找 certs 参数(如果它不为 NULL),然后查找 p7 结构本身中包含的任何证书。如果无法找到任何签名者的证书,则操作将失败。

因此,您需要自己加载的唯一证书是根证书,您已经观察到它们从文件系统加载链接代码中的文件系统加载。

如果由于某种原因您仍然确实需要 Swift 解决方案从 PKCS7 数据中提取证书,则必须为 PKCS7 构建 ASN.1 解析器。不确定这是否适用于 Swift,这个简单的代码是快速搜索产生的,是对 PKCS7 数据的很好的描述。