如何在Swift中解析x509证书并提取其密钥签名?

4
我正在尝试生成一对RSA密钥,然后将X.509证书添加到公钥头部。为此,我使用SwiftyRSA库。
问题在于当我将X.509证书添加到头部时,无法解析公钥。在此之后,当我打印公钥时,它仍然与没有证书时相同。
但是,当我打印字节时,它显示不同的字节。没有证书时,它显示270个字节,有证书时,它显示294个字节。这意味着它正在添加证书,但未使用证书进行解析。
在深入阅读SwiftyRSA库后,它说:

警告:使用SwiftyRSA的方法存储(或创建)PublicKey实例将自动剥离密钥头。有关更多信息,请参见上面的Under the hood。

如果值得一提,甚至还有仍然开放的案例
我仍在寻找解决方案,但找不到任何解决方案。我尝试实现的代码如下:
    if let password = passwordTextField.text {

        //Generate RSA
        guard let keyPair = try? SwiftyRSA.generateRSAKeyPair(sizeInBits: 2048),
              let privateKeyPem = try? keyPair.privateKey.pemString(),
              let publicKeyPem = try? keyPair.publicKey.pemString()
        else {
            return
        }
        
        /// Generate Certificate in format X.509 from Public Key
        let publicKey = try! PublicKey(data: keyPair.publicKey.data())
        let publicKeyData = try! keyPair.publicKey.data()
        let publicKey_with_X509_header = try! SwiftyRSA.prependX509KeyHeader(keyData: publicKeyData)
        
        let publicKey509 = try! PublicKey(data: publicKey_with_X509_header)
        
        print(try! publicKey.pemString()) // Without Certificate
        print(try! publicKey509.pemString()) // With Certificate
        // These two print results are completely the same, but it should be different.

        // Encrypt private key
        let salt = String.random(length: 32)
        let aesKey = Array(String((password + salt).prefix(32)).utf8)
        let iv = [UInt8](String(salt.prefix(16)).utf8)
        guard let aes = try? AES(key: aesKey, blockMode: CBC(iv: iv), padding: .pkcs7),
              let inputData = privateKeyPem.data(using: .utf8),
              let encryptedBytes = try? aes.encrypt(inputData.bytes)
        else {
            return
        }

        let encryptedData = NSData(bytes: encryptedBytes, length: encryptedBytes.count)
        let base64String = encryptedData.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))

        // Print keys and salt
        print(try! publicKey509.pemString())
        print(base64String)
        print(salt)
        
    }

我如何使用 x509 证书解析公钥? 我会感激任何帮助。
1个回答

2
如上所述,你无法使用SwiftyRSA创建x509证书。实际上,你可以使用Security框架来完成此操作。
首先,你需要创建Data的扩展,用于将证书添加到公钥中。
extension Data {
    public func dataByPrependingX509Header() -> Data { 
        let result = NSMutableData()
        let encodingLength: Int = (self.count + 1).encodedOctets().count
        let OID: [CUnsignedChar] = [0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00]
        var builder: [CUnsignedChar] = []
        
        // ASN.1 SEQUENCE
        builder.append(0x30)
        
        // Overall size, made of OID + bitstring encoding + actual key
        
        let size = OID.count + 2 + encodingLength + self.count
        let encodedSize = size.encodedOctets()
        builder.append(contentsOf: encodedSize)
        result.append(builder, length: builder.count)
        result.append(OID, length: OID.count)
        builder.removeAll(keepingCapacity: false)
        builder.append(0x03)
        builder.append(contentsOf: (self.count + 1).encodedOctets())
        builder.append(0x00)
        result.append(builder, length: builder.count)
        
        // Actual key bytes
        result.append(self)
        return result as Data
        
    }
    
}

然后,请确保您import Security,并将您的代码更改为:

    // Generate keys
    if let password = passwordTextField.text {
        //Generate RSA
        let attributes: [String: Any] = [
            String(kSecAttrKeyType):            kSecAttrKeyTypeRSA,
            String(kSecAttrKeySizeInBits):      4096, // you can change the size to 2048, but 4096 has higher security.
            String(kSecPrivateKeyAttrs): [
                String(kSecAttrIsPermanent):    true,
                String(kSecAttrApplicationTag): "com.example.keys.mykey"]
        ]
        var error: Unmanaged<CFError>?
        
        // Private Key
        guard let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {
            fatalError("Error: \(error.debugDescription)")
        }
        
        let privateKeyData = SecKeyCopyExternalRepresentation(privateKey, &error)
        let privData = privateKeyData as Data?
        let privateKeyString = privData!.base64EncodedString()
        print("Private Key")
        print(privateKeyString)

        // You'll probably need to structure Private and public key to go in new line every time after 76 character
        let structuredPrivateKeyString = privateKeyString.inserting(separator: "\n", every: 76)
        let privateKeyFinal = "-----BEGIN RSA PRIVATE KEY-----\n" + structuredPrivateKeyString + "\n\n-----END RSA PRIVATE KEY-----" 
        print(privateKeyFinal)
        
        // Public Key
        let publicKey = SecKeyCopyPublicKey(privateKey) // generate public key from private key
        let publicKeyData = SecKeyCopyExternalRepresentation(publicKey!, &error)
        let pubData = publicKeyData as Data? // We need to turn it into data so we can add the certificate or print it as string
        print("Public Key")
        print(pubData!.base64EncodedString())
        
        // Add x509 certificate to public key
        let publicKeyX509 = SecKeyCopyPublicKey(privateKey)
        let publicKeyDataX509 = SecKeyCopyExternalRepresentation(publicKeyX509!, &error)
        let pubData1 = publicKeyDataX509 as Data?
        let x509Data = pubData1!.dataByPrependingX509Header() // Here we add the certificate (Function that we created previosly in Data extension).
        var publicKeyX509String = x509Data.base64EncodedString()
        print("Public Key x509")
        print(publicKeyX509String)
        
        let structuredPublicKeyX509String = publicKeyX509String.inserting(separator: "\n", every: 76)
        
        let publicKeyFinal = "-----BEGIN RSA PUBLIC KEY-----\n\(structuredPublicKeyX509String)\n\n-----END RSA PUBLIC KEY-----"
        print("Public Key for the API")
        print(publicKeyFinal)
        
        // Encrypt private key
        let salt = String.random(length: 32)
        let aesKey = Array(String((password + salt).prefix(32)).utf8)
        let iv = [UInt8](String(salt.prefix(16)).utf8)
        guard let aes = try? AES(key: aesKey, blockMode: CBC(iv: iv), padding: .pkcs7),
              let inputData = privateKeyFinal.data(using: .utf8),
              let encryptedBytes = try? aes.encrypt(inputData.bytes)
        else {
            setLoadingView(visible: false)
            return
        }

        let encryptedData = NSData(bytes: encryptedBytes, length: encryptedBytes.count)
        let base64String = encryptedData.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))

        // Print keys and salt
        print(publicKeyFinal)
        print(base64String)
        print(salt)
    }

注意:我在每行添加了一个注释,标明了我认为重要的内容,这样你就会知道发生了什么。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接