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

时间:2018-03-23 14:01:07

标签: c swift openssl digital-signature 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)
    }
}

我能够使用以下代码成功提取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)")
        }

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

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

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

1 个答案:

答案 0 :(得分: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)
}

您似乎缺少的是您不必自己从PKCS7数据中提取X509证书。 PKCS7_verify function will do it作为验证的一部分:

  

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

因此,您需要自己加载的唯一证书是您在linked code中从文件系统加载的根证书。

如果由于某种原因仍然需要Swift解决方案从PKCS7数据中提取证书,则必须为PKCS7构建ASN.1解析器。不确定Swift是否可以使用,this simple code是快速搜索产生的,this是对PKCS7数据的一个很好的描述。