-
Enhancement
-
Resolution: Fixed
-
P3
-
13, 14
-
b26
A DESCRIPTION OF THE PROBLEM :
With the changes made forJDK-8076190 it is possible to load PKCS12 keystores without integrity protection and no encrypted certificates.
However, it appears creating such keystore is not easily possible because passing `null` as password to KeyStore.store(OutputStream, char[]) uses an empty char[] as password instead. To work around this, the user would have to change the System / Security properties "keystore.pkcs12.macAlgorithm" and "keystore.pkcs12.certProtectionAlgorithm" which could affect concurrently running PKCS12 keystore operations.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Use the code provided below. The keystore is stored with `null` as password.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Loading the keystore with `null` as password works and all certificates are accessible.
ACTUAL -
Loading the keystore with `null` works (because integrity check is skipped, as expected), but no certificates are accessible.
---------- BEGIN SOURCE ----------
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
public class Pkcs12PasswordlessTest {
private static final String CERT_PEM =
"-----BEGIN CERTIFICATE-----\n" +
"MIICADCCAWmgAwIBAgIEdyF6ojANBgkqhkiG9w0BAQsFADAyMQ0wCwYDVQQKEwREZW1vMQ0wCwYDVQQLEwREZW" +
"1vMRIwEAYDVQQDEwlEZW1vIGNlcnQwIBcNMTkwODMxMTMwODM2WhgPMjEwOTA1MTkxMzA4MzZaMDIxDTALBgNV" +
"BAoTBERlbW8xDTALBgNVBAsTBERlbW8xEjAQBgNVBAMTCURlbW8gY2VydDCBnzANBgkqhkiG9w0BAQEFAAOBjQ" +
"AwgYkCgYEAo5ULhB6DQo8A9EH1Zxl29eK2In4Tqt3dzNAY3MQULoV6wCWUfc8dJa5RnZiOGJUxgnLPBU/UgjTi" +
"IJFohzrlHjmhWsdnbJtYA51raEG3JKNDakhBCmgoTue8veMlwegIgElV/dzfGl+HtG5wI4aJkONT0Jg8bzLOex" +
"rNvn588X8CAwEAAaMhMB8wHQYDVR0OBBYEFH/vBQPBrtPS83M2CM4p2PPZSn1HMA0GCSqGSIb3DQEBCwUAA4GB" +
"AAPM8WxouFVgP+T2oy55gqLwW3CKOvfueIX3xyAAcS2rpMayHdJ7yAQrd00kvXy+bs1eAayXyNRawT2EIX1qv7" +
"9wNn4qtmVnk8t+J9ckkoWpUCGw45F5/Q1EhVxMKjJBNbik2k1k/1SXksneIgONp+AkzISRFtq+p3J9KpVO9g2m" +
"\n-----END CERTIFICATE-----";
public static void main(String[] args) throws Exception {
byte[] keyStoreData = createKeyStoreData();
KeyStore keyStore = KeyStore.getInstance("pkcs12");
/*
* Keystore was stored with null as integrity protection password, so loading it
* with null as password should work and certificates should be accessible.
* However, certificates are not accessible because they were encrypted.
* (Integrity protection was also added, but is not checked here because null is
* used as password)
*/
keyStore.load(new ByteArrayInputStream(keyStoreData), null);
System.out.println("Loading with `null`: Has entries: " + keyStore.aliases().hasMoreElements());
/*
* Keystore was actually stored with new char[0] as password.
*/
keyStore.load(new ByteArrayInputStream(keyStoreData), new char[0]);
System.out.println("Loading with `new char[0]`: Has entries: " + keyStore.aliases().hasMoreElements());
}
private static byte[] createKeyStoreData() {
X509Certificate cert = createCert();
try {
KeyStore keyStore = KeyStore.getInstance("pkcs12");
keyStore.load(null, null); // Initialize
keyStore.setCertificateEntry("alias", cert);
ByteArrayOutputStream out = new ByteArrayOutputStream();
/*
* Storing with null as integrity protection password. Therefore expecting
* no integrity protection and unencrypted certificates.
*/
keyStore.store(out, null);
return out.toByteArray();
}
// None of these is possible
catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | IOException e) {
throw new RuntimeException(e);
}
}
private static X509Certificate createCert() {
try {
CertificateFactory factory = CertificateFactory.getInstance("X.509");
ByteArrayInputStream in = new ByteArrayInputStream(CERT_PEM.getBytes(StandardCharsets.US_ASCII));
return (X509Certificate) factory.generateCertificate(in);
}
// Certificate type is guaranteed to be supported and format is valid
catch (CertificateException e) {
throw new RuntimeException(e);
}
}
}
---------- END SOURCE ----------
FREQUENCY : always
With the changes made for
However, it appears creating such keystore is not easily possible because passing `null` as password to KeyStore.store(OutputStream, char[]) uses an empty char[] as password instead. To work around this, the user would have to change the System / Security properties "keystore.pkcs12.macAlgorithm" and "keystore.pkcs12.certProtectionAlgorithm" which could affect concurrently running PKCS12 keystore operations.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Use the code provided below. The keystore is stored with `null` as password.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Loading the keystore with `null` as password works and all certificates are accessible.
ACTUAL -
Loading the keystore with `null` works (because integrity check is skipped, as expected), but no certificates are accessible.
---------- BEGIN SOURCE ----------
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
public class Pkcs12PasswordlessTest {
private static final String CERT_PEM =
"-----BEGIN CERTIFICATE-----\n" +
"MIICADCCAWmgAwIBAgIEdyF6ojANBgkqhkiG9w0BAQsFADAyMQ0wCwYDVQQKEwREZW1vMQ0wCwYDVQQLEwREZW" +
"1vMRIwEAYDVQQDEwlEZW1vIGNlcnQwIBcNMTkwODMxMTMwODM2WhgPMjEwOTA1MTkxMzA4MzZaMDIxDTALBgNV" +
"BAoTBERlbW8xDTALBgNVBAsTBERlbW8xEjAQBgNVBAMTCURlbW8gY2VydDCBnzANBgkqhkiG9w0BAQEFAAOBjQ" +
"AwgYkCgYEAo5ULhB6DQo8A9EH1Zxl29eK2In4Tqt3dzNAY3MQULoV6wCWUfc8dJa5RnZiOGJUxgnLPBU/UgjTi" +
"IJFohzrlHjmhWsdnbJtYA51raEG3JKNDakhBCmgoTue8veMlwegIgElV/dzfGl+HtG5wI4aJkONT0Jg8bzLOex" +
"rNvn588X8CAwEAAaMhMB8wHQYDVR0OBBYEFH/vBQPBrtPS83M2CM4p2PPZSn1HMA0GCSqGSIb3DQEBCwUAA4GB" +
"AAPM8WxouFVgP+T2oy55gqLwW3CKOvfueIX3xyAAcS2rpMayHdJ7yAQrd00kvXy+bs1eAayXyNRawT2EIX1qv7" +
"9wNn4qtmVnk8t+J9ckkoWpUCGw45F5/Q1EhVxMKjJBNbik2k1k/1SXksneIgONp+AkzISRFtq+p3J9KpVO9g2m" +
"\n-----END CERTIFICATE-----";
public static void main(String[] args) throws Exception {
byte[] keyStoreData = createKeyStoreData();
KeyStore keyStore = KeyStore.getInstance("pkcs12");
/*
* Keystore was stored with null as integrity protection password, so loading it
* with null as password should work and certificates should be accessible.
* However, certificates are not accessible because they were encrypted.
* (Integrity protection was also added, but is not checked here because null is
* used as password)
*/
keyStore.load(new ByteArrayInputStream(keyStoreData), null);
System.out.println("Loading with `null`: Has entries: " + keyStore.aliases().hasMoreElements());
/*
* Keystore was actually stored with new char[0] as password.
*/
keyStore.load(new ByteArrayInputStream(keyStoreData), new char[0]);
System.out.println("Loading with `new char[0]`: Has entries: " + keyStore.aliases().hasMoreElements());
}
private static byte[] createKeyStoreData() {
X509Certificate cert = createCert();
try {
KeyStore keyStore = KeyStore.getInstance("pkcs12");
keyStore.load(null, null); // Initialize
keyStore.setCertificateEntry("alias", cert);
ByteArrayOutputStream out = new ByteArrayOutputStream();
/*
* Storing with null as integrity protection password. Therefore expecting
* no integrity protection and unencrypted certificates.
*/
keyStore.store(out, null);
return out.toByteArray();
}
// None of these is possible
catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | IOException e) {
throw new RuntimeException(e);
}
}
private static X509Certificate createCert() {
try {
CertificateFactory factory = CertificateFactory.getInstance("X.509");
ByteArrayInputStream in = new ByteArrayInputStream(CERT_PEM.getBytes(StandardCharsets.US_ASCII));
return (X509Certificate) factory.generateCertificate(in);
}
// Certificate type is guaranteed to be supported and format is valid
catch (CertificateException e) {
throw new RuntimeException(e);
}
}
}
---------- END SOURCE ----------
FREQUENCY : always
- csr for
-
JDK-8274862 Allow store password to be null when saving a PKCS12 KeyStore
-
- Closed
-