How to create a PKCS12 compatible with iOS's Multipeer Connectivity with node-forge?

假如想象 提交于 2020-01-07 07:46:06

问题


I am trying to achieve Multipeer Connectivity communications security through clients authentication using X509 certificate.

To do so, I am generating the clients' certificates in my server using node-forge. First, the X509 is created then it is transformed into a PKCS12 base64 string that is returned to the client.

That is basically the code I am using :

var username = "client1"

// Create key pair
var pki = forge.pki;
var keys = pki.rsa.generateKeyPair(2048);
var cert = pki.createCertificate();


// Creating the certificate
cert.publicKey = keys.publicKey;
cert.serialNumber = '01'; // TODO : generate random number and have a little custom algo to verify it !!

cert.validity.notBefore = new Date();
cert.validity.notAfter = new Date();
cert.validity.notAfter.setTime(cert.validity.notBefore.getTime() + msWeek);

var subject = [{
    name : "commonName",
    value : username
}, {
    name : "organizationName",
    value : "My Company"
}, {
    name : "organizationalUnitName",
    value : "MU"
}, {
    name : "stateOrProvinceName",
    value : "Ile-de-France"
}, {
    name : "countryName",
    value : "FR"
}, {
    name : "localityName",
    value : "Paris"
}, {
    name : "emailAddress",
    value : "hello@world.com"
} ];

var issuer = [{
    name : "commonName",
    value : "MPC App"
}, {
    name : "organizationName",
    value : "My Company"
}, {
    name : "organizationalUnitName",
    value : "MU"
}, {
    name : "stateOrProvinceName",
    value : "Ile-de-France"
}, {
    name : "countryName",
    value : "FR"
}, {
    name : "localityName",
    value : "Paris"
}, {
    name : "emailAddress",
    value : "hello@world.com"
} ];
cert.setSubject(subject);
cert.setIssuer(issuer);

// Extensions 
cert.setExtensions([{
    name: 'basicConstraints',
    cA : true
} , {
    name : 'keyUsage',
    digitalSignature : true,
    keyCertSign : true,
    nonRepudiation : true,
    keyEncipherment : true,
    dataEncipherment : true
}, {
    name : 'extKeyUsage',
    clientAuth : true,
    serverAuth : false,
    codeSigning : true,
    emailProtection : false,
    timeStamping : true
}, {
    name : 'nsCertType',
    client : true,
    server : false,
    email : false,
    objsign : true,
    sslCA : false,
    emailCA : false,
    objCA : false
}]);

cert.sign(keys.privateKey);
var asn1Cert = pki.certificateToAsn1(cert);

// Create PKCS#12 from the certificate and encode to base64 string 
var p12Asn1 = forge.pkcs12.toPkcs12Asn1(keys.privateKey , cert, "iPhone");
var p12Der = forge.asn1.toDer(p12Asn1).getBytes();
return forge.util.encode64(p12Der); 

However, when I import it in my iOS application, runtime keeps crashing telling me it has failed to read the contents of the PKCS#12 (different error from the bad password error though) by returning errSecDecode.

I don't know which part of my code is causing this error even though I suspect the extensions to be at the origin of these issues, by the way I don't really know what suits best to my usecase (two clients authenticating themselves for each other in order to communicate with MultiPeer Connectivity).

I would also like to know if I am doing something wrong when I encode my PKCS#12 to a base64 string ?

If it helps, here is the code I'm using to import the PKCS#12 in the iOS side after recovering the base64 string from the server.

private func generateIdentity (base64p12 : String, password : String?) {
    print("gen id")
    let p12KeyFileContent = NSData(base64EncodedString: base64p12, options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)

    if (p12KeyFileContent == nil) {
        NSLog("Cannot read PKCS12 data")
        return
    }

    let options = [String(kSecImportExportPassphrase):password ?? ""]
    var citems: CFArray? = nil
    let resultPKCS12Import = withUnsafeMutablePointer(&citems) { citemsPtr in
        SecPKCS12Import(p12KeyFileContent!, options, citemsPtr)
    }
    if (resultPKCS12Import != errSecSuccess) {
        print("resultPKCS12Import :", resultPKCS12Import)
        return
    }

    let items = citems! as NSArray
    let myIdentityAndTrust = items.objectAtIndex(0) as! NSDictionary
    let identityKey = String(kSecImportItemIdentity)

    identity = myIdentityAndTrust[identityKey] as! SecIdentityRef
    hasCertificate = true
    print("cert cre", identity)
} 

Thank you in advance

edit : By decoding the base64 string with node-forge, I can see the infos I entered when the certificate was created, also they are well printed without poorly rendered character.

Now I am asking myself whether iOS is throwing this error on purpose to retain me from using certificates that are not created with their specific tool (Apple Keychain if I remember well).


回答1:


Apparently, iOS's Security Framework requires the PKCS#12 to be using TripleDES encryption algorithm.

So, replacing the line :

var p12Asn1 = forge.pkcs12.toPkcs12Asn1(keys.privateKey , cert, "iPhone");

with :

var p12Asn1 = forge.pkcs12.toPkcs12Asn1(keys.privateKey , cert, "iPhone", {algorithm : '3des'});

works like a charm.

At this point I still don't understand why Apple's documentation is so inexhaustive on the subject :/ .



来源:https://stackoverflow.com/questions/38567748/how-to-create-a-pkcs12-compatible-with-ioss-multipeer-connectivity-with-node-fo

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!