Background: What Works
From time to time we have to use a piece of Java software that reads PKCS#12 keystores. For this particular project, we have to create public/private pairs on an as-needed basis, and we store the keys in PKCS12 files because it's stable and pretty much everything can read that format.
Because we do a lot of Java in-house, we have keytool sitting around, and so we figured hey, just use keytool to create the private key and certificate. A typical instance looks like this:
keytool -keystore MyLuggage.p12 -storepass 123456 -storetype pkcs12
-alias "......"
-genkeypair -keyalg RSA -keysize typically_2048_or_3072 -sigalg SHA256withRSA
-ext "KeyUsage=dataEncipherment,digitalSignature,keyEncipherment"
-startdate ....
-dname "......."
The actual -keysize varies between 2048 and 8192 in practice; for the purposes of this question it hasn't seemed to make a difference what gets used, but obviously we use key lengths appropriate to the task if we get to choose them at all (usually dictated by the constraints of other software, or dictated by some regulation that's handed to us).
This has always worked, in that other software -- including the Java software mentioned at the start -- can read the keystore and make use of the private keys within. (And the public key can be exported and used, etc.)
Here's What Breaks
The software recently got upgraded to a version that uses the FIPS 140 certified Java libraries from RSA. ("BSAFE" or "JSAFE" depending on who you ask.) And now, trying to open previously-created PKCS#12 files fails with
java.lang.SecurityException: Algorithm not allowable in FIPS140 mode: PBE/PKCS12/SHA1/RC2/CBC/40
at ......
at java.security.KeyStore.load(Unknown Source)
The elided ...... frames are in the RSA source that we don't have and looks to use function names that have been obfuscated in any case. So looking at their source to try and figure out what exactly it's testing to cause this, isn't an option.
So, what is causing this? The only algorithms we've chosen are the "RSA" key generation and "SHA256withRSA" signature, both of which are permitted by FIPS 140-2. I've been looking again through keytool -genkeypair -help output and there don't seem to be any other algorithm or security options. (We've avoided using -keypass because PKCS#12 tools really hate it when the keystore password and the key password are different, and keytool -genkeypair defaults the key password to the keystore password.) The rest of the error message is confusing, as we don't specify the use of SHA-1 or RC2 (!) anywhere.
Googling around points to people having trouble with creating SSL certificates, which we're not doing here, and the solutions given seem to be specific to Tomcat.
Is this a problem with how we're creating the keystore, how we're creating the key pair in the keystore, or some "feature" of FIPS 140 that we haven't previously encountered?
PKCS#12 stores the private key encrypted with a password derived key. It looks like keytool uses pbeWithSHAAnd128BitRC2-CBC (pkcs-12PbeIds 5), an PBES1 algorithm for doing so. Even the keytool.exe of Oracle Java 9 does use this algorithm as you can verify by uploading a .p12 file to the online ASN.1 decoder decoding a sample PKCS#12 file.
If I read the PKCS#12 standard correctly PBES1 was long ago superseeded by the "newer" version of the key derivation system named "PBES2" (mostly PBKDF2 based) with should be used instead. But keytool does not make use of it. This is my interpretation of the error message.
Therefore the certificate and the key may be acceptable, but the PKCS#12 container is not acceptable. You may try to extract key and certificate and save them in a new PKCS#12 file using a current software like OpenSSL (or you simply generate the whole PKCS#12 file directly using OpenSSL).
OpenSSL has the option to specify the PBE used for key and certificate encryption (parameters -keypbe and -certpbe in PKCS#12 mode). I have not checked it but and algorithm like AES-256-CBC should be FIPS140 compatible.
Related
we run a standard web API over https with a regular purchased SSL certificate. Our clients just access it via https, the certificate is trusted via default system RootCA.
A new client is using a Java communication server that requires the certificate in a PKCS12 keystore. How can we generate the PKS12 keystore from our key/csr/crt/pem files?
I did some research, most examples are requiring a private key. Of course I do not want to share our private key with the client.
Can a PKCS12 keystore be created without private key, similar to standard RootCA in browsers?
Thanks, bluepuma
YES-ish.
Although PFX-now-PKCS12 was designed primarily to store or transfer a privatekey and cert and chain cert(s) as a clump, and most commonly is used for that, it is capable of storing one or more 'lone' cert(s) not matched to any privatekey. And you are correct the client wanting to connect to you should have in their truststore ideally the root cert for your server cert's chain, or alternatively your server cert itself, but decidedly not your privatekey.
openssl can actually create such a PKCS12:
openssl pkcs12 -export -in certfile.pem [-name $name] -nokeys -out blah.p12
# if you don't specify -name it defaults to 1 (the digit one) which can be mildly confusing
# instead of being prompted for the password you can use -passout with several forms
# described on the openssl man page, but consider the warning below
But the result won't work in Java if they use the standard (Sun/Oracle/OpenJDK) cryptoproviders, which (in 8+) support lone cert(s) in a PKCS12 as 'trustedCert' entries in Java only if the(each) certbag has a special Sun-defined attribute which the Java providers write when they create such a file, but OpenSSL doesn't.
Instead use Java's keytool in 8:
jre8/bin/keytool -importcert -keystore blah.p12 -storetype pkcs12 -file $certfile [-alias $name]
or in 9+ where pkcs12 is now the default:
jre9+/bin/keytool -importcert -keystore blah.p12 -file $certfile [-alias $name]
If you don't specify the alias it defaults to mykey. In both cases you can add -storepass $pw to avoid being prompted for it, but as a result the password will be visible on your screen, in the command history of your shell or other command processor it is has one, and in most cases to other processes run on your system concurrently, (any of) which may be a security issue or not. You can also add -noprompt to avoid the confirmation prompt.
But user207421 is (roughly) correct that using such a truststore can break other SSL/TLS connection(s) made from their system, at least from the same JVM, unless the individual calls specify individual, separate truststores, and if they had coded that they would know how to handle (and ask for) a simpler certificate format, such as PEM.
Reading through some URLs and it fairly common for stating that the following command is used to create a public/private key pair.
keytool -genkey -alias mydomain -keyalg RSA -keystore keystore.jks -storepass password
Then it continues on and indicates the following command is used to create a self signed certificate.
keytool -genkey -alias selfsigned -keyalg RSA -keystore keystore.jks -storepass password -validity 360
From what I see, the only difference is adding "-validity 360".
Question 1 - Does simply adding "-validity 360" change from generating a key pair to a self-signed certificate?
Question 2 - Are "key pairs" and "self-signed certificate" essentially synonymous?
Question 3 - could either the key pair or "self-signed certificate" be used for an official CSR?
Question 1 - Does simply adding "-validity 360" change from generating a key pair to a self-signed certificate?
No. -genkeypair (the official name since about 2005) or the less accurate synonym -genkey always generates a keypair and a selfsigned certificate, and stores the privatekey and the cert (together) in the keystore. The only difference -validity 360 makes is whether the specified value or the default value is used for the validity period.
Question 2 - Are "key pairs" and "self-signed certificate" essentially synonymous?
No. In this situation they are linked, but they are different things. A keypair, and separate privatekey and publickey, can be used for some things without any certificate (selfsigned or otherwise) using storage other than a Java keystore, and a selfsigned cert (which includes the publickey) can be used for some things without the privatekey. For example SSH normally uses the 'bare' keypair for server authentication and frequently for client authentication. PGP uses a signed-publickey format that functions as a kind of certificate but very much unlike the X.509/PKIX certificates used in a Java keystore, and in SSL/TLS/HTTPS/etc and codesigning (and SMIME).
As an analogy that comes up frequently on travel.SX, consider an airline ticket and a suitcase of clothes. When you buy an airline ticket traditionally it included the ability to have a certain amount of luggage, often a few suitcases up to a weight limit, carried with you on your flight -- though nowadays this varies in widely disliked and contentious ways. It is possible to ride an airplane flight without taking a suitcase if you want, although it means at your destination you may not have any clothes to wear. It is also possible and fairly common to use a suitcase to carry clothes without an airline ticket in many places other than an airplane, such as a car, cab, bus, train, or relative's or friend's house.
Question 3 - could either the key pair or "self-signed certificate" be used for an official CSR?
A key pair could be used to generate a CSR(*) if you provided the subject name from another source. But Java keystore doesn't actually store key pair plus self-signed cert, but rather private key plus self-signed cert (or other cert); the public key is accessibly stored only in the cert, and the public key (from the cert) is needed and used to generate the CSR.
A self-signed cert, or any other cert, by itself cannot be used to generate a CSR(*) because the CSR must be signed using the private key.
(*) Actually CSR is a generic concept and there are many kinds of CSR with varying rules. I am talking here about only the kind of CSR specified by PKCS10 aka RFC2986 et rel, which is the (only) one generated by Java and most other common tools, and the one required by practically all Internet CAs.
You're quite right, the self-signed certificate and a CSR request both start with the keytool -genkey command. The difference is what you do with it next.
For a self-signed certificate there's not much more to do. You might to export it, to install as a trusted certificate at the client end, with keytool -export:
keytool -export -alias selfsigned -file selfsigned.cer -keystore keystore.jks -storepass password
For the CSR request, you would then create this with keytool -certreq:
keytool -certreq -alias mydomain -file mydomain.csr -keystore keystore.jks -storepass password
Up to you with the validity period. It's not crucial for either route, though with a self-signed certificate you'll typically want more than the default of 90 days.
what does the abbreviation UBER mean? I know that UBEr is a BouncyCastle-Keystore, etc. but i don't know what the abbreviation mean.
thanks
I think it's a reference to the German word "Über" (over or super) and is not an abbreviation. Per the BoncyCastle Specifications
The Bouncy Castle package has three implementation of a keystore.
The first "BKS" is a keystore that will work with the keytool in the same fashion as the Sun "JKS" keystore. The keystore is resistent to tampering but not inspection.
The second, Keystore.BouncyCastle, or Keystore.UBER will only work with the keytool if the password is provided on the command line, as the entire keystore is encrypted with a PBE based on SHA1 and Twofish. PBEWithSHAAndTwofish-CBC. This makes the entire keystore resistant to tampering and inspection, and forces verification. The Sun JDK provided keytool will attempt to load a keystore even if no password is given, this is impossible for this version. (One might wonder about going to all this trouble and then having the password on the command line! New keytool anyone?).
We are at a big organization with a several applications that are developed for internal and external use. One of those application is distributed as Java Webstart application and after a lot of trial and error we now have proper signing and packaging in place.
The only problem: we use a self-signed certificate. Users see a warning about an unknown/unverified vendor and this is just not nice.
Fortunately, the IT department of the organization has one certificate that is accepted on all workstations (via a site-wide policy, I assume). If we use this accepted certificate to sign the JARs and create the Webstart archive, everything should be fine. Naturally, the IT department does not want to distribute the accepted certificate to all developers or put it on the build server, because this would be against the purpose and introduce a lot of vulnerabilities.
What would be the right way to generate a code-signing certificate signed by this accepted certificate?
My assumption, based on what I know from normal openssl procedures to generate certificates used in web servers:
Generate a CSR with
Send CSR to IT security
IT generates a certificate from the CSR with accepted certificate. This certificate should have a short validity (1 week / 1 month / 1 quarter ?)
Import into java keytool for signing
Make sure keytool is only available to authorized users
Would this work? Are there any objections in terms of security or organizational obstacles?
If the above is correct, I would need some pointers especially with item 3. I found a somewhat related question: How do you sign Certificate Signing Request with your Certification Authority?.
Any help is appreciated.
If the corporation has its own CA root cert, which yes had to be pushed to every client/relier by some means such as GPO or installing all systems (or maybe their JREs?) from a customized image, then your approach is almost correct:
generate keypair and CSR
send CSR to corporate CA, they send you back cert
combine cert with keypair in keystore and use keystore
You can do all steps but the last with OpenSSL, but it's extra work:
1: openssl req -newkey or openssl genpkey|genrsa|etc then openssl req -new
3: openssl pkcs12 -export plus keytool -importkeystore -srcstoretype pkcs12
Since you want to end up with a Java keystore it's easier to just use Java throughout:
1: keytool -genkeypair then keytool -certreq
3: keytool -importcert
keytool is a program available on every machine that has any JRE installed; you can't effectively restrict it. It is the keystore file containing your keypair (and specifically your privatekey) that must be protected. Use a strong password; set file/dir permissions/ACL; keep a secure backup; all the usual.
On the other hand, if the corporation has a code-signing cert (and key) which is trusted because the cert was obtained from (issued by) a well-known CA like Verisign, they almost certainly cannot issue you a subordinate certificate. Only a CA cert (with its key) can issue subordinate certs, and while technically it is possible for a trusted CA to issue your corporation a CA cert, if you then issue any bad certs it reflects on them and can put them out of business (see DigiNotar) and they don't want that.
I want to sign an applet using netbeans, but i don't want to self-sign it because since the Java 7u51 was released it is considered as unsigned. How do I get a keystore password?
You're asking the wrong question.
You need a keypair.
You need a CSR.
You need to get the CSR signed by a CA.
All this stuff goes into a keystore, and not the one that came with the JDK or JRE. That's a truststore, and has an entirely different purpose.
So, you need to either create a new keystore, with the keytool, in which case you get to choose your own password, or you need to use an existing keystore, typically $HOME/.keystore, in which case you must already know its password.
Then you do:
keytool -genkey ...
keytool -certreq ...
Get the CA to sign the CSR just generated.
keytool -importcert ..., importing the signed CSR, using the same alias as at 1-2.
Note that NetBeans has nothing to do with any of this.