【问题标题】:certificatesInBundle doesn't append self signed certificatescertificateInBundle 不附加自签名证书
【发布时间】:2024-01-15 07:22:01
【问题描述】:

在我的情况下,使用便捷方法 ServerTrustPolicy.certificatesInBundle() 似乎无法正常工作

// MARK: - Bundle Location

/**
    Returns all certificates within the given bundle with a `.cer` file extension.

    - parameter bundle: The bundle to search for all `.cer` files.

    - returns: All certificates within the given bundle.
*/
public static func certificatesInBundle(bundle: NSBundle = NSBundle.mainBundle()) -> [SecCertificate] {
    var certificates: [SecCertificate] = []

    let paths = Set([".cer", ".CER", ".crt", ".CRT", ".der", ".DER"].map { fileExtension in
        bundle.pathsForResourcesOfType(fileExtension, inDirectory: nil)
    }.flatten())

    for path in paths {
        if let
            certificateData = NSData(contentsOfFile: path),   // <-- we get the data of the certificate in bundle 
            certificate = SecCertificateCreateWithData(nil, certificateData)  // <-- The problem is here, the certificate is not set neither errors.
        {
            certificates.append(certificate)  // <-- this doesn't run
        }
    }

    return certificates
}

可能与自签名证书的格式有关。我完全使用了这篇博文中的#tip 5。 Five Tips for Using Self Signed SSL Certificates with iOS

问题是SecCertificateCreateWithData 方法的限制是什么,哪些证书格式可以接受?更好的是,我可以在哪里阅读有关此特定问题的更多信息。

我的代码似乎是正确的,没什么特别的,可能是最常用的 sn-ps 之一:P

let defaultManager:Alamofire.Manager = {

    let serverTrustPolicies: [String: ServerTrustPolicy] = [
        "localhost": .PinCertificates(
            certificates: ServerTrustPolicy.certificatesInBundle(),
            validateCertificateChain: true,
            validateHost: true
        )
    ]

    let configuration = NSURLSessionConfiguration.ephemeralSessionConfiguration()
    configuration.HTTPAdditionalHeaders = Alamofire.Manager.defaultHTTPHeaders


    return Alamofire.Manager(
        configuration: configuration,
        serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
    )
}()

【问题讨论】:

    标签: ios ssl https ssl-certificate alamofire


    【解决方案1】:

    SecCertificateCreateWithData 返回 nil 的最可能原因是该文件是 PEM 而不是 DER 格式。

    根据documentation,数据应包含

    X.509 的 DER(可分辨编码规则)表示 证书

    如果您的数据以“-----BEGIN...”开头,则格式错误。 PEM 可以使用 OpenSSL 转换为 DER(反之亦然) - 这是一个方便的参考 https://www.sslshopper.com/article-most-common-openssl-commands.html

    此外,如果是自签名证书(由“localhost”判断),validateCertificateChain 属性应该为 false。否则请求将失败并返回“cancelled” NSError。

    此外,从 iOS9 开始,应将 App Transport Security 设置设置为允许任意加载(在 Info.plist 中)。这是唯一允许您的应用评估自签名证书的设置。没有它,Alamofire 信任策略机制将无法发挥作用。

    【讨论】:

    • 我发现它是什么,我在 iOS 9.0 中做到了,不允许任意加载。它实际上是编码。 Apple 只需要 DER,它会在任何其他编码中静默失败。不允许任意负载。你实际上打开了后门,如果你这样做,你就没有使用证书。我会带着正确的答案回来。
    【解决方案2】:

    我遇到了类似的问题。 Alamofire 找不到我的证书,ServerTrustPolicy.certificatesInBundle() 方法没有返回任何内容。

    问题是当我将证书拖到我的 Xcode 项目中时,我没有选择“添加到目标:MyProjectName”。

    【讨论】:

    • 你在开玩笑吧...谢谢,这是我的问题。
    【解决方案3】:

    确保您下载了 der 格式的证书并正确添加到您的项目中。

    之后定义一个静态 SessionManager,如下所述

    public static let sharedManager: SessionManager = {
        let serverTrustPolicies: [String: ServerTrustPolicy] = [
            "subdomain.domain.com": .pinCertificates(
                certificates: ServerTrustPolicy.certificates(),
                validateCertificateChain: false,
                validateHost: true
            ),
            "insecure.expired-apis.com": .disableEvaluation
        ]
    
    
        let manager = Alamofire.SessionManager(serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies))
    
        return manager
    }()
    

    那么就可以调用上面的sharedManager了:

    YourHttpClassName.sharedManager.request(url, method: .get, headers: headers).response { response in
    
                print("Request: \(response.request)")
                print("Response: \(response.response)")
                print("Error: \(response.error)")
    
                debugPrint(response)
    
    
            }
    

    它应该适用于您的自签名证书。

    【讨论】: