在 Swift 中获取 macOS Keychain 证书的 SHA1 哈希值

问题描述

我已使用此代码检索了钥匙串中的一组证书:

    let query: [String: Any] = [
        kSecclass as String: kSecclassCertificate,kSecMatchLimit as String: kSecMatchLimitAll,kSecReturnAttributes as String: false,kSecReturnData as String: true
    ]

    var result: CFTypeRef?
    
    var results : Set<CertsResult> = []


    let status = SecItemcopyMatching(query as CFDictionary,&result)
    //[Check status]

    guard let certificateData = result as? [CFData] else {
        //[Handle]
    }

从这里开始,我遍历 certificateData 并收集有关证书的信息,但我还需要获取证书的 SHA1 哈希值。我从研究中发现我需要使用 import CommonCryptoCC_SHA1,但我读过的内容没有使用 CFData

有没有什么好方法可以从这一点得到它的 SHA1?

解决方法

您可以通过自己执行散列来实现它。指纹不是证书本身的一部分。 here 上的更多信息。

import CryptoKit

let certificate = ...

let der = SecCertificateCopyData(certificate) as Data
let sha1 = Insecure.SHA1.hash(data: der)
let sha256 = SHA256.hash(data: der)

这也可以在扩展中创建。我在扩展中使用了 CommonCrypto。

import CommonCrypto

extension SecCertificate {
    var sha1: Data {
        var digest = [UInt8](repeating: 0,count: Int(CC_SHA1_DIGEST_LENGTH))
        let der = SecCertificateCopyData(self) as Data
        _ = CC_SHA1(Array(der),CC_LONG(der.count),&digest)
        return Data(digest)
    }

    var sha256: Data {
        var digest = [UInt8](repeating: 0,count: Int(CC_SHA256_DIGEST_LENGTH))
        let der = SecCertificateCopyData(self) as Data
        _ = CC_SHA256(Array(der),&digest)
        return Data(digest)
    }
}

我想提一下,自 2017 年以来,证书的 SHA-1 哈希值已被弃用,网站和科技巨头开始放弃对它们的支持。

游乐场示例

import CryptoKit
import Foundation

class CertificateStuff: NSObject,URLSessionDelegate {
    func urlSession(
        _ session: URLSession,didReceive challenge: URLAuthenticationChallenge,completionHandler: @escaping (URLSession.AuthChallengeDisposition,URLCredential?) -> Void
    ) {
        guard let serverTrust = challenge.protectionSpace.serverTrust else {
            completionHandler(.rejectProtectionSpace,nil)
            return
        }

        for index in 0 ..< SecTrustGetCertificateCount(serverTrust) {
            let certificate = SecTrustGetCertificateAtIndex(serverTrust,index)!

            let der = SecCertificateCopyData(certificate)
            let sha1 = Insecure.SHA1.hash(data: der as Data)
            let sha256 = SHA256.hash(data: der as Data)

            print(certificate)
            print(sha1)
            print(sha256)
            print()
        }
        completionHandler(.performDefaultHandling,nil)
    }

    func request(_ done: @escaping (Result<Data,Error>) -> Void) {
        let url = URL(string: "https://security.stackexchange.com/questions/14330/what-is-the-actual-value-of-a-certificate-fingerprint")!
        let request = URLRequest(url: url)
        URLSession(configuration: .default,delegate: self,delegateQueue: nil).dataTask(with: request) { (d,r,e) in
            if let e = e {
                print(e)
                return
            }
            print(d!)
        }.resume()
    }
}

CertificateStuff().request { result in print(result) }