我正在Swift 4中编写一组将在Linux上运行的服务。我需要做的一件事是接收使用加密消息语法(CMS)格式进行数字签名的有效负载,提取用于签名的证书,然后验证签名。我知道Linux上的Swift不包含用于此类事情的Security或CommonCrypto框架,所以我在OpenSSL中链接以尝试帮助解决这个问题。我离C / C ++编程时间大约有两年的时间,所以我很乐意承认我对这部分代码感到满意。
我有2个简单的类来充当OpenSSL BIO
和PKCS7
数据结构的包装器。它们看起来像这样:
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安全/加密框架,我不知道任何其他选项。
答案 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数据的一个很好的描述。