Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

PKCS12 problem with JSS

17 views
Skip to first unread message

David Stutzman

unread,
Oct 17, 2007, 2:16:02 PM10/17/07
to
I'm generating keys in the softoken and then exporting them to PKCS12
files with their freshly issued certs. I get the private key using the
getEncryptedPrivateKeyInfo method of CryptoStore.

This epki is reporting a 16 byte salt but when I ask the algorithm for
its salt size, I get 20.

When I try to unwrap the key I get:
javax.crypto.BadPaddingException: Given final block not properly padded

Using PBEAlgorithm pbeAlgorithm = PBEAlgorithm.PBE_SHA1_DES3_CBC;
pbeAlgorithm.getSaltLength() = 20

Encrypted private key info's salt: 0x6d469a0e62d57c5482e589562eeb2236

I've tried some of the other algorithms and it appears the
getEncryptedPrivateKeyInfo (which is one of the native methods of JSS)
*always* returns an EPKI with 16 bytes of salt and it's confusing other
applications/APIs that are expecting more or less (8 and 20 seem to be
the most popular).

Dave

David Stutzman

unread,
Oct 18, 2007, 9:49:26 AM10/18/07
to

If it matters...The reason I need to decrypt the key first is that if I
just take the EPKI structure and pass it right into the PKCS12, then it
can only be read by MS-CAPI and java's keytool. OpenSSL will not be
able to read the resulting PKCS12 file.
I am also constrained to using PBE_SHA1_DES3_CBC as the other algorithms
result in PKCS12 files that are unreadable by anything but NSS itself.
That's not a huge issue as that is the algorithm I would like to use
anyway, just mentioning it for the compatibility angle.

If I use keytool -list -keystore foo.p12 -storetype PKCS12 then Java can
read the resulting PKCS12 even though I can't seem to decrypt the EPKI
myself programatically. keytool reports that it is using the SunJSSE
provider for the KeyStore implementation.

When I re-encrypt the key using the SafeBag.createEncryptedPrivateKeyBag
method I end up with algorithm parameters that make sense. The method
calls PBEAlgorithm .getSaltLength() and ends up with a 20 byte salt and
uses "DEFAULT_ITERATIONS" of 1. These structures can be handled by all
other toolkits I've tested with:
100 25: . . . . . . . . . . . . . SEQUENCE {
<04 14>
102 20: . . . . . . . . . . . . . . OCTET STRING
: . . . . . . . . . 11 37 D3 96 E3 DB 55 24 .7....U$
: . . . . . . . . . B4 EA 64 7E 15 B0 CB D6 ..d~....
: . . . . . . . . . 8C F3 38 2E ..8.
<02 01>
124 1: . . . . . . . . . . . . . . INTEGER 1
: . . . . . . . . . . . . . . }

I'm open to tweaking the NSS code, if necessary. I *think* I see where
the salt/iteration count are being obtained in
http://mxr.mozilla.org/security/source/security/nss/lib/pk11wrap/pk11pbe.c#409

Would I be barking up the wrong tree if I was looking in there for
changing the size of the salt?

I guess another question, why does NSS use a different salt size for the
same algorithm than JSS?

Thanks,
Dave

Glen Beasley

unread,
Oct 18, 2007, 3:16:57 PM10/18/07
to David Stutzman, dev-tec...@lists.mozilla.org
hi David,

you should file two bugs:

JSS has different Salt size than NSS for PBE

NSS appears to only handle PBE_SHA1_DES3_CBC for PKCS12

I will try to work on the bugs shortly.

thanks,

glen

> _______________________________________________
> dev-tech-crypto mailing list
> dev-tec...@lists.mozilla.org
> https://lists.mozilla.org/listinfo/dev-tech-crypto
>

Nelson B

unread,
Oct 18, 2007, 4:01:25 PM10/18/07
to
David,
I agree with Glen that there are (at least) two separate issues here,
and that bugs should be filed on both of them.

The first issue is (apparently) that PKCS#12 files created with JSS
that use an algorithm other than PBE_SHA1_DES3_CBC are unreadable by
OpenSSL. The bug should be filed against JSS. Please include code
and steps by which the problem can be reproduced.

JSS includes some SAMPLE code for creating PKCS#12 files. It's not
technically part of JSS (as I understand it) and it's known to have
several faults. So, odds are good that this is just a problem with
that JSS sample code.

If that problem turns out to NOT be JSS code, but is lower level,
then this is potentially an NSS-OpenSSL interoperability issue.
If we determine that it is, then we'll turn the bug into an NSS bug.
It might prove to be an OpenSSL issue rather than an NSS issue.

The second issue is some inconsistent results regarding PBE salt size.
The most we can say (based on the report quoted below) is that the
results disagree with each other. It's difficult to say which is wrong.
Again, this should be filed as a JSS bug, and it should include steps
and/or code to reproduce the problem.

Thanks.


--
Nelson B
12345678901234567890123456789012345678901234567890123456789012345678901234567890
00000000011111111112222222222333333333344444444445555555555666666666677777777778

David Stutzman

unread,
Oct 19, 2007, 7:12:37 AM10/19/07
to
Nelson B wrote:
> The first issue is (apparently) that PKCS#12 files created with JSS
> that use an algorithm other than PBE_SHA1_DES3_CBC are unreadable by
> OpenSSL. The bug should be filed against JSS. Please include code
> and steps by which the problem can be reproduced.

Do I hardcode a key/cert into the code so you guys can build some PKCS12
files with the different algorithms? Or can I just attach some sample
PKCS12 files I've created and some code/psuedocode for how I made them?

Dave

David Stutzman

unread,
Oct 19, 2007, 12:13:55 PM10/19/07
to
Per Nelson and Glen I filed
https://bugzilla.mozilla.org/show_bug.cgi?id=400404.

I know you said there are 2 separate issues but I think the first issue
(incompatible PKCS12 files) is caused by the second (salt sizes for
PBEAlgs) so I only filed the one bug. Based on my testing I think as
long as I get the correct salt size whenever I encrypt something, then I
should have no problems decrypting.

As usual, Feel free to contact me for more info, test materials, code
snippets.

Dave

David Stutzman

unread,
Oct 23, 2007, 7:46:22 AM10/23/07
to
I did a lot of playing around yesterday. I added a note to the bug
showing where the 16 byte salt is set as a #define and used no matter
what algorithm is passed in from JSS. Unfortunately that didn't help
out with decrypting the key.

What I have determined is that if JSS creates an EPKI structure, it is
readable elsewhere whereas the NSS EPKI is mostly only readable by NSS.

2 things I'd like to point out:

- The password converter. I need to pass one into the EPKI.decrypt
method in JSS. The *only* way I can decrypt an NSS EPKI is with the
following:
class PWConverter implements KeyGenerator.CharToByteConverter {
public byte[] convert(char[] chars) {
try {
String s = new String(chars);
byte[] raw = s.getBytes("UTF-8");
byte[] cooked = new byte[raw.length + 1];
System.arraycopy(raw, 0, cooked, 0, raw.length);
// Hex hex = new Hex();
// System.out.println("password bytes : " + new
String(hex.encode(cooked), "UTF-8"));
return cooked;
}
catch (Exception e) {
return null;
}
}
}

SafeBag.createEncryptedPrivateKeyBag
(http://mxr.mozilla.org/security/source/security/jss/org/mozilla/jss/pkcs12/SafeBag.java#307)
creates an EPKI internally from the PrivateKeyInfo (PKI) you pass in.
When it creates the EPKI it passes in a
http://mxr.mozilla.org/security/source/security/jss/org/mozilla/jss/pkcs12/PasswordConverter.java.
If I pass one of these to the decrypt method of the EPKI class on an
NSS generated EPKI the ASN1 decode fails, presumably because the decrypt
went wrong. My guess is something is different between the C and Java
representations of the password.
Again, loading the epki from the filesystem that I mentioned above (that
was generated by JSS) I tested using the EPKI.decrypt both with null and
"new PasswordCoverter()" as the second argument. null resulted in an
error about padding, "new PasswordConverter()" was able to successfully
decrypt the EPKI. Perhaps NSS and JSS are generating different bytes
out the password and hence different sym. keys?

- Somewhat related to the first point. I changed the code for SafeBag
class to write out the EPKI it creates during
createEncryptedPrivateKeyBag. This EPKI is readable via OpenSSL
(openssl pkcs8 -in test.p8 -inform DER).
After seeing this, I changed my PKCS12 code to read that p8 from the
filesystem instead of actually extracting it from the db. In this case
I was able to decrypt the key using only Java methods into a PKI, use
ASN1Util to decode it back into a JSS PKI and continue on building the
PKCS12. The resulting PKCS12 is readable by OpenSSL, Java and MS-CAPI.

All of this testing was done using PBEAlgorithm.PBE_SHA1_DES3_CBC since
the SafeBag.createEncryptedPrivateKeyBag method is hardcoded to use
that, and I'd like to use that one anyway.

Hopefully I've presented this info in a somewhat coherent manner.

Dave

David Stutzman

unread,
Nov 6, 2007, 10:55:10 AM11/6/07
to
I've created a test class and a db to be used with it that shows the
following issues I get while exporting credentials to PKCS12 files using
JSS.

1) FIPS enabled generates PBA key error (this issue was first mentioned
in a separate thread)
2) 4 of the 8 PBEAlgorithms won't export the EPKI (though I don't really
care so much about these personally)
3) 3 of the 4 that will export the EPKI(PBEAlgorithm.PBE_SHA1_DES3_CBC
works) generate incompatible PKCS12 files (as long as certs area also
included with key, see note in code)
4) The "default" and supplied CharToByteConverter (PasswordConverter
from pkcs12 package) do not work with EPKI's passed back from NSS. A
"custom" one must be written.

I'm just asking here first to see where you want this info. I filed a
bug for the previously mentioned salt size issue but never made one for
any of the other problems. How would you like me to handle this?

Thanks,
Dave

Glen Beasley

unread,
Nov 6, 2007, 1:39:46 PM11/6/07
to David Stutzman, dev-tec...@lists.mozilla.org

Could you zip up your test class and db then send to my email.

thank you,

glen

David Stutzman

unread,
Nov 15, 2007, 1:23:26 PM11/15/07
to Glen Beasley
I was looking at how the password was getting converted to bytes today.
The PKCS12 spec (downloaded from
http://www.rsa.com/rsalabs/node.asp?id=2138, page 14) says the password
bytes are BMPStrings with a null terminator and no byte order marks. It
shows a sample password of "Beavis" and the bytes (in hex) that should
be produced from that password:
00 42 00 65 00 61 00 76 00 69 00 73 00 00

Both the JSS and BC BMPString classes produce correct output when given
"Beavis\0" (ignoring they have the byte order marks at the front which
could be removed fairly easily).
The PasswordConverter class in PKCS12 package does the proper thing
completely on its own if passed in "Beavis". It removes the BOM and adds
the NULL at the end and everything is 2 bytes per char.
The 4th is basically just doing the same thing that the code inside the
PWConverter class (code below) does.

JSS bmpstring password bytes : 1e0e0042006500610076006900730000
BC bmpstring password bytes : 1e0e0042006500610076006900730000
JSS pw converter password bytes : 0042006500610076006900730000
Java password bytes : 4265617669730000
custom password bytes : 4265617669730000
Jss password object charToByte : 42656176697300

What's weird is that the last line of output is the thing that will
successfully decrypt the epki bytes passed back from NSS and that
doesn't make
sense at all because it's not 2 bytes per char, but it does have 2 bytes
for
the null at the end. (I found out why below...)

- When getEncryptedPrivateKeyInfo is called you pass in a
org.mozilla.jss.util.Password. This gets passed down to NSS which calls
back to the java object and runs the non-public method getByteCopy()
(http://mxr.mozilla.org/security/source/security/jss/org/mozilla/jss/pkcs11/PK11Store.c#532).

- getByteCopy calls charToByte which is hardcoded to use a
null-terminated UTF8 (which only adds 1 of the null bytes so at this
point we end up with 42656176697300 after inputting "Beavis" as the
password)
(http://mxr.mozilla.org/security/source/security/jss/org/mozilla/jss/util/Password.java#216)
- The native nss code then goes on to add the second 1 byte null at the
end in a somewhat shady way
(http://mxr.mozilla.org/security/source/security/jss/org/mozilla/jss/pkcs11/PK11Store.c#534).
It just adds one to the length. I'm not 100% on NSS coding
conventions (or C for that matter), but I don't see anywhere in there
where the memory for the SECItem holding the password is zeroed so is
just adding 1 to the length ok?

So if the Password object was created with the password "Beavis" the
bytes that NSS would use for creating the epki would be 4265617669730000.

I'm pretty sure this is where the incompatiblities are coming from. The
only reason the PKCS12 is usable after JSS builds it is that JSS itself
re-encrypts the key by calling SafeBag.createEncryptedPrivateKeyBag, you
pass in a password object and when it creates the epki internally it
passes in an instance of PasswordConverter from the pkcs12 package
(http://mxr.mozilla.org/security/source/security/jss/org/mozilla/jss/pkcs12/SafeBag.java#307)
(which, as demonstrated above, produces bytes according to the PKCS12
spec) so the java/jss-built EPKI is encrypted according to spec). The
same goes for AuthenticatedSafe.addEncryptedSafeContents, it also uses a
"PasswordConverter" instance
(http://mxr.mozilla.org/security/source/security/jss/org/mozilla/jss/pkcs12/AuthenticatedSafes.java#354).
This is why the shady home-grown KeyGenerator.CharToByteConverter is
needed for decrypting the CryptoStore-provided epki(NSS at a lower
level) which doesn't act according to the PKCS12 spec. This is why
openssl and Java cannot decrypt these EPKI structures, they're deriving
the wrong key given the same password text.

So it seems the Password class needs a way to specify what "char to
byte" conversion method should be used as null-terminated UTF8 is not
the correct way to do it in all cases. That or maybe provide a way to
pass the converted bytes themselves in to the NSS-native method
Java_org_mozilla_jss_pkcs11_PK11Store_getEncryptedPrivateKeyInfo?
(http://mxr.mozilla.org/security/source/security/jss/org/mozilla/jss/pkcs11/PK11Store.c#482).

The code to produce the above samples (some BouncyCastle classes):

Hex hex = new Hex();

char[] passChars = new char[]{'B','e','a','v','i','s','\0'};
String passString = "Beavis\0";

//JSS BMPString
BMPString testString = new BMPString(passChars);
byte[] passBytes = ASN1Util.encode(testString);
System.out.println("JSS bmpstring password bytes : " + new
String(hex.encode(passBytes)));

//BC bmpstring
org.bouncycastle.asn1.DERBMPString bcBMPString = new
org.bouncycastle.asn1.DERBMPString(passString);
byte[] bcPassBytes = bcBMPString.getDEREncoded();
System.out.println("BC bmpstring password bytes : " + new
String(hex.encode(bcPassBytes)));

//JSS pkcs12.PasswordConverter
PasswordConverter pc = new PasswordConverter();
byte[] jssPWbytes = pc.convert("Beavis".toCharArray());
System.out.println("JSS pw converter password bytes : " + new
String(hex.encode(jssPWbytes)));

//these 2 match output
byte[] javaPassBytes = (passString + '\0').getBytes("UTF-8");
System.out.println("Java password bytes : " + new
String(hex.encode(javaPassBytes)));

PWConverter converter = new PWConverter();
byte[] customPassBytes = converter.convert(passChars);
System.out.println("custom password bytes : " + new
String(hex.encode(customPassBytes)));

byte[] jssPasswordBytes =
password.charToByte("Beavis".toCharArray());
System.out.println("Jss password object charToByte : " +
new String(hex.encode(jssPasswordBytes)));

Our PWConverter:


class PWConverter implements KeyGenerator.CharToByteConverter {
public byte[] convert(char[] chars) {
try {
String s = new String(chars);
byte[] raw = s.getBytes("UTF-8");
byte[] cooked = new byte[raw.length + 1];
System.arraycopy(raw, 0, cooked, 0, raw.length);

return cooked;
}
catch (Exception e) {
return null;
}
}
}

Dave

0 new messages