I am trying to transfer a public RSA key generated in swift into my Nodejs server. I generated the RSA key using the following code.
private var clientPriv: SecKey?
private var clientPub: SecKey?
private init(){
let params: [String: Any] = [
String(kSecAttrKeyType): kSecAttrKeyTypeRSA,
String(kSecAttrKeySizeInBits): 4096
]
SecKeyGeneratePair(params as CFDictionary, &clientPub, &clientPriv)
}
I send the key to my server using this code
...
guard let clientPub = clientPub else { return }
let key = SecKeyCopyExternalRepresentation(clientPub, nil)! as Data
let pem = exportToPEM(data: key, withLabel: "PUBLIC KEY")
let data = ["clientPub": pem]
var urlRequest = URLRequest(url: url)
do {
try urlRequest.httpBody = JSONSerialization.data(withJSONObject: data)
urlRequest.httpMethod = "POST"
urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
}catch let err {
print(err)
}
let task = URLSession.shared.dataTask(with: urlRequest){ data, response, error in
guard let data = data, error == nil else {
return
}
...
The exportToPem helper looks like this.
public func exportToPEM(data: Data, withLabel label: String) -> String {
let key = data.base64EncodedString(options: [.lineLength64Characters])
var pem = "-----BEGIN \(label)-----\n"
pem = key
pem = "\n-----END \(label)-----\n"
return pem
}
On my Nodejs side, I am using express to handle my requests and body-parser to parse my json post data in requests. Here is what my Nodejs receiving code looks like.
app.post('/api/init', jsonParser, function (req, res) {
console.log(req.body.clientPub);
CLIENTPUB = crypto.createPublicKey({ key: req.body.clientPub, format: 'pem', type: 'pkcs1' });
console.log(CLIENTPUB);
res.write(JSON.stringify({'server-pub': SERVERPUB.toString()}));
res.end()
});
The problem is that the function crypto.createPublicKey keeps throwing an error, error:0D0680A8:asn1 encoding routines:asn1_check_tlen:wrong tag
. I have tried many different ways to write the string of my key but no matter what it seems that the crypto createPublicKey just refuses to take it. I have tried keeping the format with \n every 64 bytes or without \n at all, removing the header/footer altogether, and many other different combinations. I can not figure out why it keeps refusing to accept any format I send it. I have also tried using just the der format but that also gets refused.
Can anyone please offer me any advice on how to get this function to accept my key format?
CodePudding user response:
SecKeyCopyExternalRepresentation()
exports the public key in PKCS#1 format, which is correctly specified on the NodeJS side in the createPublicKey()
call with 'pkcs1'
for the type
parameter.
However, the header and footer texts of a PEM encoded key for PKCS#1 format are BEGIN RSA PUBLIC KEY and END RSA PUBLIC KEY, so when calling exportToPEM()
, "RSA PUBLIC KEY"
must be passed in the second parameter instead of "PUBLIC KEY"
:
let pem = exportToPEM(data: key, withLabel: "RSA PUBLIC KEY")
BEGIN PUBLIC KEY and END PUBLIC KEY are used for a PEM encoded public key in X.509/SPKI format. This is what the error message wrong tag means.