1

I have created public key and private key in my smartcard(Dongle) using safenet sdk's own library. I realized that Both are in PKCS#8 format. Both Private key and Public Key starts with "BEGIN PUBLIC KEY" and "BEGIN PRIVATE KEY" instead of "BEGIN RSA PUBLIC KEY" and "BEGIN RSA PRIVATE KEY".

I also signed CertificationInfo's(ex: Distinguished Names such as common name, postal code etc.). Then I am sending PubLic Key and the signed Data to my swift application to generate csr.

In csr generation step, I converted the public key to rsa format by removing first 32 characters, then convert it to SecKey to generate csr. I found that, after extracting seckey to Data, it is same before and after the SecKey conversion.

But, when i validate the signature with public key, It says that "Signature is invalid". Is it because the public key is in PKCS#1 format and the private key by whom the CertificationInfo is signed is in PKCS#8 format?

If this is the reason, what will be the probable fix to resolve the issue? Do i need to convert the Key format in native end(using C code)? What is the mechanism of generating PKCS#1 format key in C? Or, Is there any way to generate PKCS#8 SecKey using swift?

My csr generation code is below

public func buildCSRAndReturnStringUsingDongle(enrollmentId: String, password: String) -> String? {
        let tagPublic = "public" + enrollmentId
        self.dongle = DongleManager.getInstance()
        self.dongle?.generateKeyPair(enrollmentId: enrollmentId, password: password)
        
        let publicKeyFromDongle: String = (self.dongle?.getPublicKeyBits(enrollmentId: enrollmentId, password: password))!

        print("Public Key is: \n",publicKeyFromDongle.dropFirst(32))

                let keyDict: [NSString: Any] = [

                        kSecAttrKeyType: kSecAttrKeyTypeRSA,

                        kSecAttrKeyClass: kSecAttrKeyClassPublic,
                        
                        kSecAttrApplicationTag: tagPublic.data(using: .utf8),

                    ]

                    var error: Unmanaged<CFError>?
                let publicKeyFromDongleEncodedData = publicKeyFromDongle.dropFirst(32).data(using: .utf8)!

                let publicKeyFromDongleData = Data(base64Encoded: publicKeyFromDongleEncodedData)
                
        guard let publicKeySecKey = SecKeyCreateWithData(publicKeyFromDongleData! as CFData, keyDict as CFDictionary, &error) else {

                        print("Failed to create public key:", error!.takeRetainedValue())

                        return nil

                    }
        //var error:Unmanaged<CFError>?
        if let cfdata = SecKeyCopyExternalRepresentation(publicKeySecKey, &error) {
           let data:Data = cfdata as Data
           let b64Key = data.base64EncodedString()
           print("after : \n")
           print(b64Key)
        }
        let publickeyBits = KeyPairManager.getInstance().getPublicKeyBits(publicKey: publicKeySecKey, enrollmentId: enrollmentId).0!
        print("public key bits conversion: \n");
        print(publickeyBits)
        
//        let publickeyBits = publicKeyFromDongle.data(using: String.Encoding(rawValue: NSASCIIStringEncoding)) as! CFData as Data
        let publickeyBitss = publicKeyFromDongleData as! CFData as Data
        print("public key 64: \n")
        print(publickeyBitss)
        
        let certificationRequestInfo = buldCertificationRequestInfo(publickeyBits)
        let bytes: [UInt8] = certificationRequestInfo.map { $0 }
        let certificationRequestStr = String(decoding: bytes, as: UTF8.self)
        let signaturedStringData = self.dongle?.signn(password: password, data : certificationRequestInfo as CFData, enrollmentId: enrollmentId)
        print("signatured string with data: \n")
        print(signaturedStringData)
        var signature = [UInt8](repeating: 0, count: 256)
        var signatureLen: Int = signature.count
        let signatureData = signaturedStringData!.data(using: .hexadecimal)

        signatureData!.copyBytes(to: &signature, count: signatureData!.count)
        if let string = String(bytes: signature, encoding: .utf8) {
            print(string)
        } else {
            print("not a valid UTF-8 sequence")
        }
        signatureLen = signatureData!.count
        print("signature length: " + String(signatureLen))
        print("signature: "+signatureData!.base64EncodedString())

        var certificationRequest = Data(capacity: 1024)
        certificationRequest.append(certificationRequestInfo)

        let shaBytes = keyAlgorithm.sequenceObjectEncryptionType
        print("shaBytes are \n");
        print(shaBytes)
        certificationRequest.append(shaBytes, count: shaBytes.count)

        var signData = Data(capacity: 2049)
        let zero: UInt8 = 0 // Prepend zero
        signData.append(zero)
        signData.append(signature, count: signatureLen)
        appendBITSTRING(signData, into: &certificationRequest)

        enclose(&certificationRequest, by: sequenceTag) // Enclose into SEQUENCE
        //print("certification request: "+certificationRequest.base64EncodedString())
        
        let csrString = certificationRequest.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))
            .addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)
        print(csrString)


        let head = "-----BEGIN CERTIFICATE REQUEST-----\n"
        let foot = "-----END CERTIFICATE REQUEST-----\n"
        var isMultiple = false
        var newCSRString = head

        //Check if string size is a multiple of 64
        if csrString!.count % 64 == 0 {
            isMultiple = true
        }

        for (integer, character) in csrString!.enumerated() {
            newCSRString.append(character)

            if (integer != 0) && ((integer + 1) % 64 == 0) {
                newCSRString.append("\n")
            }

            if (integer == csrString!.count-1) && !isMultiple {
                newCSRString.append("\n")
            }

        }

        newCSRString += foot

        return newCSRString
    }
ahad alam
  • 69
  • 7
  • 2
    That public key header is not indicative of PKCS8 format. – President James K. Polk Jun 19 '23 at 15:19
  • 1
    Okay.Thanks for the information. But, the private key header is also "BEGIN PRIVATE KEY" instead of "BEGIN RSA PRIVATE KEY". Can it be probable issue while verifying the signature with public key? Because public key header is now " BEGIN RSA PUBLIC KEY". I found the difference between two types from https://stackoverflow.com/questions/18039401/how-can-i-transform-between-the-two-styles-of-public-key-format-one-begin-rsa – ahad alam Jun 19 '23 at 15:25
  • 1
    I hate to harp on this but you need to provide code. So far you've shown the code for key pair generation, and that's good but not enough. I doubt the problem is in key pair generation, I think the problem is most likely in the generation of the PKCS#10 CSR itself. So please show the code where you create the CSR. – President James K. Polk Jun 19 '23 at 16:18
  • 1
    Thanks for suggesting me some probable reason. When I am creating and retrieving key from apple's keychain, the csr is generated correctly and it's working perfectly.It's on another method. For Dongle use case, i have to modify a bit in csr generation code. I have added the method here. you can check the code now. – ahad alam Jun 19 '23 at 16:31
  • 1
    I will try my best but I'm not familiar with Apple crypto APIs or Swift. Is there any online documentation of the dongle APIs? – President James K. Polk Jun 19 '23 at 16:33
  • @PresidentJamesK.Polk this is the documentation for safenet sdk. https://thalesdocs.com/gphsm/ptk/5.9/docs/Content/PTK-C_Program/PKCS_11_Cmd_Ref/PKCS_11_cmd_ref.htm – ahad alam Jun 22 '23 at 03:35

0 Answers0