Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8231107

Allow store password to be null when saving a PKCS12 KeyStore

    XMLWordPrintable

Details

    Description

      A DESCRIPTION OF THE PROBLEM :
      With the changes made for JDK-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


      Attachments

        Issue Links

          Activity

            People

              weijun Weijun Wang
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              8 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: