Swift (Linux):提取 CMS/PKCS#7 证书并验证容器签名?
Swift (Linux): Extract CMS/PKCS#7 Certs and Validate Container Signature?
我正在 Swift 4 中编写一组服务,这些服务将在 Linux 上 运行。我需要做的一件事是接收使用加密消息语法 (CMS) 格式进行数字签名的有效负载,提取用于对其进行签名的证书,然后验证签名。我知道 Linux 上的 Swift 不包含用于此类事情的 Security 或 CommonCrypto 框架,因此我已链接到 OpenSSL 以尝试帮助解决此问题。我的 C/C++ 编程日已经过去了大约 2 年,所以我欣然承认我在这部分代码上不知所措。
我有 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 没有一个好的 security/cryptography 框架,我不知道任何其他选择。
答案的核心部分在您链接的代码中:
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 作为验证的一部分:
An attempt is made to locate all the signer's certificates, first looking in the certs parameter (if it is not NULL) and then looking in any certificates contained in the p7 structure itself. If any signer's certificates cannot be located the operation fails.
因此,您需要自己加载的唯一证书是您观察到它们从 linked code.
中的文件系统加载的根证书
如果出于某种原因您仍然确实需要 Swift 解决方案来从 PKCS7 数据中提取证书,则必须为 PKCS7 构建一个 ASN.1 解析器。不确定这是否适用于 Swift,this simple code is what a quick search yielded, and this 是对 PKCS7 数据的很好描述。
我正在 Swift 4 中编写一组服务,这些服务将在 Linux 上 运行。我需要做的一件事是接收使用加密消息语法 (CMS) 格式进行数字签名的有效负载,提取用于对其进行签名的证书,然后验证签名。我知道 Linux 上的 Swift 不包含用于此类事情的 Security 或 CommonCrypto 框架,因此我已链接到 OpenSSL 以尝试帮助解决此问题。我的 C/C++ 编程日已经过去了大约 2 年,所以我欣然承认我在这部分代码上不知所措。
我有 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 没有一个好的 security/cryptography 框架,我不知道任何其他选择。
答案的核心部分在您链接的代码中:
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 作为验证的一部分:
An attempt is made to locate all the signer's certificates, first looking in the certs parameter (if it is not NULL) and then looking in any certificates contained in the p7 structure itself. If any signer's certificates cannot be located the operation fails.
因此,您需要自己加载的唯一证书是您观察到它们从 linked code.
中的文件系统加载的根证书如果出于某种原因您仍然确实需要 Swift 解决方案来从 PKCS7 数据中提取证书,则必须为 PKCS7 构建一个 ASN.1 解析器。不确定这是否适用于 Swift,this simple code is what a quick search yielded, and this 是对 PKCS7 数据的很好描述。