digitalbazaar / forge

A native implementation of TLS in Javascript and tools to write crypto-based and network-heavy webapps
https://digitalbazaar.com/
Other
5.06k stars 781 forks source link

Import encrypted pkcs#12 - not able to read private key #258

Closed fsp77 closed 9 years ago

fsp77 commented 9 years ago

I have been trying to import an encrypted pkcs#12 into forge. I created the pkcs#12 using openssl:

openssl pkcs12 -export -inkey keypairs/key01.pem -in keypairs/cert01.pem -certfile cacert.pem -out keypairs/pkcs01.p12

I have so far been able to read the certificates using this procedure:

function pkcsFromFile(file) {
    return fs.readFileSync(file);
}
var p12Buffer = pkcsFromFile("/home/xyz/bkup/pkcs01.p12");
var p12Der = forge.util.binary.raw.encode(new Uint8Array(p12Buffer));
var p12Asn1 = forge.asn1.fromDer(p12Der);
var p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, false, 'passwd');
var certBags = p12.getBags({bagType: forge.pki.oids.certBag});

^^ I could extract all the certificates from certBags.

Actual Issue: Getting the private key has proved a bit difficult... here's what I have tried:

var pkeyBags = p12.getBags({bagType: forge.pki.oids.keyBag}); // returns an empty bag
var pkeyBags = p12.getBags({bagType: forge.pki.oids.pkcs8ShroudedKeyBag});

^^getBags with bagType = pkcs8ShroudedKeyBag returns a bag but am not able to decrypt it.

> var pkeyBags =  p12.getBags({bagType: forge.pki.oids.pkcs8ShroudedKeyBag}, "passwd");
undefined
> pkeyBags
{ '1.2.840.113549.1.12.10.1.2': 
   [ { type: '1.2.840.113549.1.12.10.1.2',
       attributes: [Object],
       key: [Object] } ] }
> forge.pki.oids.pkcs8ShroudedKeyBag
'1.2.840.113549.1.12.10.1.2'
> forge.pki.privateKeyToPem(pkeyBags[forge.pki.oids.pkcs8ShroudedKeyBag][0].key)

^^ This gives me a key but this is not the same as the one I encoded into the pkcs#12 envelope.

BaurzhanSakhariev commented 9 years ago
 var keyBags = p12.getBags({bagType: forge.pki.oids.pkcs8ShroudedKeyBag});
 var bag = keyBags[forge.pki.oids.pkcs8ShroudedKeyBag][0];
 var privateKey = bag.key;

Now you may convert forge key to PEM:

   var pem = forge.pki.publicKeyToPem(publicKey);
   var 64pem = forge.util.decode64(pem);

this function returns key data with BEGIN,END headers, if you want to get pure b64 PEM key without headers, use:

var asn1 = forge.pki.privateKeyToAsn1(privateKey);
var der = forge.asn1.toDer(asn1);
var b64key = forge.util.encode64(der.getBytes()); //same with PEM above, but without headers.

Also, extracting cert from certBag:

var certBags = p12.getBags({bagType: forge.pki.oids.certBag});
var bag = certBags[forge.pki.oids.certBag][0];
cert = bag.cert;
fsp77 commented 9 years ago

Baurzhan Sakhariev: thanks for checking.

Sorry if I was not clear...

I have tried what you suggested (please also see my first note); the key that is output from forge.pki.privateKeyToPem(pkeyBags[forge.pki.oids.pkcs8ShroudedKeyBag][0].key) does not match the private key I had encoded into the pkcs#12 using openssl.

Also tried your suggestion:

var asn1 = forge.pki.privateKeyToAsn1(privateKey);
var der = forge.asn1.toDer(asn1);
var b64key = forge.util.encode64(der.getBytes()); //same with PEM above, but without headers.

Got the same key as from forge.pki.privateKeyToPem

BaurzhanSakhariev commented 9 years ago

Second approach returns pem key without "BEGIN/END RSA PRIVATE KEY" headers so, 2 approaches are not fully same but I guess you didn't take headers to account. But binary(asn-der-b64) != binary(pem), because pem binary takes to account headers. I mean, if you comparing binary outputs of ssl and binary of pem you should compare binary of ssl with binary(without headers). If you already comparing binaries without headers or even tried to compare both variants I didn't know the reason, sorry.

fsp77 commented 9 years ago

My bad: Yes, I see that now. Sorry about the wild goose chase. My test was failing because I was doing a Buffer.compare.

One question still though: why is forge returning an RSA private key (PKCS#1) when a PKCS#8 bag is requested.

fsp77 commented 9 years ago

Sure will do. Many thanks at the interim though. Cheers.

dlongley commented 9 years ago

why is forge returning an RSA private key (PKCS#1) when a PKCS#8 bag is requested.

Forge deserializes the private key entirely, it only maintains an association with the type of bag from which it came (which is how you filter the pkcs12 contents). You can serialize it back to a PKCS#8 container by doing this:

// convert a Forge private key to an ASN.1 RSAPrivateKey
var rsaPrivateKey = forge.pki.privateKeyToAsn1(privateKey);

// wrap an RSAPrivateKey ASN.1 object in a PKCS#8 ASN.1 PrivateKeyInfo
var privateKeyInfo = forge.pki.wrapRsaPrivateKey(rsaPrivateKey);

// then you can convert to DER, etc. like before
var der = forge.asn1.toDer(privateKeyInfo);
fsp77 commented 9 years ago

Thanks for that info. Closing this issue now. Cheers.

NishantDesai1306 commented 8 years ago

When i use

var p12Der = forge.util.decode64(p12File);
var p12Asn1 = forge.asn1.fromDer(p12Der);
var p12 = forge.pkcs12.pkcs12FromAsn1(p12Asn1, password);
var keyBags = p12.getBags({bagType: forge.pki.oids.pkcs8ShroudedKeyBag});
var bag = keyBags[forge.pki.oids.pkcs8ShroudedKeyBag][0];
var privateKey = bag.key;
var asn1 = forge.pki.privateKeyToAsn1(privateKey);
var der = forge.asn1.toDer(asn1);
var b64key = forge.util.encode64(der.getBytes()); //same with PEM above, but without headers.
console.log("key : ",b64key);

The problem that i am facing is that when i log the key (last line of code in above snippet) i get RSA PRIVATE KEY. On searching on internet i found out that RSA PRIVATE KEY is traditional format in PKCS#1 and to get PRIVATE KEY from it I need to convert it into PKCS#8 form

I did it using this command in openssl openssl pkcs8 -topk8 -inform pem -in file.key -outform pem -nocrypt -out file.pem

I just wanna know how can i do this in javascript ?? Any help is appreciated

dlongley commented 8 years ago

Try this:

var publicKey = forge.pki.setRsaPublicKey(privateKey.n, privateKey.e);
var pem = forge.pki.publicKeyToPem(publicKey);
dlongley commented 8 years ago

@NishantDesai1306,

Oh, sorry, I misread your comment. You want PKCS#8 form, one minute, I'll get a code sample for that.

dlongley commented 8 years ago

@NishantDesai1306,

// convert a Forge private key to an ASN.1 RSAPrivateKey
var rsaPrivateKey = forge.pki.privateKeyToAsn1(privateKey);

// wrap an RSAPrivateKey ASN.1 object in a PKCS#8 ASN.1 PrivateKeyInfo
var privateKeyInfo = forge.pki.wrapRsaPrivateKey(rsaPrivateKey);

// convert a PKCS#8 ASN.1 PrivateKeyInfo to PEM (unencrypted)
var pem = forge.pki.privateKeyInfoToPem(privateKeyInfo);

If you want encryption:

// encrypts a PrivateKeyInfo and outputs an EncryptedPrivateKeyInfo
var encryptedPrivateKeyInfo = forge.pki.encryptPrivateKeyInfo(
  privateKeyInfo, 'password', {
    algorithm: 'aes256', // 'aes128', 'aes192', 'aes256', '3des'
  });

// converts an EncryptedPrivateKeyInfo to PEM
var pem = forge.pki.encryptedPrivateKeyToPem(encryptedPrivateKeyInfo);
NishantDesai1306 commented 8 years ago

thanks it worked flawless On Apr 12, 2016 7:55 PM, "Dave Longley" notifications@github.com wrote:

@NishantDesai1306 https://github.com/NishantDesai1306,

// convert a Forge private key to an ASN.1 RSAPrivateKeyvar rsaPrivateKey = forge.pki.privateKeyToAsn1(privateKey); // wrap an RSAPrivateKey ASN.1 object in a PKCS#8 ASN.1 PrivateKeyInfovar privateKeyInfo = forge.pki.wrapRsaPrivateKey(rsaPrivateKey); // convert a PKCS#8 ASN.1 PrivateKeyInfo to PEMvar pem = forge.pki.privateKeyInfoToPem(privateKeyInfo); // encrypts a PrivateKeyInfo and outputs an EncryptedPrivateKeyInfovar encryptedPrivateKeyInfo = forge.pki.encryptPrivateKeyInfo( privateKeyInfo, 'password', { algorithm: 'aes256', // 'aes128', 'aes192', 'aes256', '3des' }); // converts an EncryptedPrivateKeyInfo to PEMvar pem = forge.pki.encryptedPrivateKeyToPem(encryptedPrivateKeyInfo);

— You are receiving this because you were mentioned. Reply to this email directly or view it on GitHub https://github.com/digitalbazaar/forge/issues/258#issuecomment-208932429