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

KeyStore getEntry is not thread-safe

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P4 P4
    • 23
    • None
    • security-libs
    • None

      When the KeyStore is concurrently modified, keyStore.getEntry might fail or return a non-matching private key / certificate pair. This is because PKCS12KeyStore.engineGetEntry calls engineGetKey and engineGetCertificateChain without any synchronization with engineSetEntry.

      This is a problem for the PKIX KeyManager (sun.security.ssl.X509KeyManagerImpl), which retrieves the entries from the KeyStore on every handshake. Currently this only impacts the handshakes that are running at the same time as the keystore update, but in JDK-8322767 we are exploring caching the entries on first use, and caching the incorrect entries would affect all handshakes until the next keystore update.

      To reproduce:
      - Create a PKCS12 key store, and 2 KeyStore.PrivateKeyEntry instances, one with EC key/certificate, one with RSA key/certificate.
      - create one thread that calls setEntry in a loop using the same alias, but alternating between the entries:
      - in another thread call getEntry in a loop
      see the attached reproducer (incomplete, needs keys).

      The code quickly fails with the following exception:
      Exception in thread "main" java.lang.IllegalArgumentException: private key algorithm does not match algorithm of public key in end entity certificate (at index 0)
      at java.base/java.security.KeyStore$PrivateKeyEntry.<init>(KeyStore.java:552)
      at java.base/sun.security.pkcs12.PKCS12KeyStore.engineGetEntry(PKCS12KeyStore.java:1338)
      at java.base/sun.security.util.KeyStoreDelegator.engineGetEntry(KeyStoreDelegator.java:174)
      at java.base/java.security.KeyStore.getEntry(KeyStore.java:1576)


      Reproducer:
          public static final String TEST = "test";
          private static void test(KeyStore ks, KeyStore.PrivateKeyEntry ec,
                                   KeyStore.PrivateKeyEntry rsa,
                                   KeyStore.PasswordProtection protParam)
                  throws Exception {
              ks.setEntry(TEST, ec, protParam);

              new Thread(()->{while(true) {
                  try {
                      ks.setEntry(TEST, ec, protParam);
                      ks.setEntry(TEST, rsa, protParam);
                  } catch (KeyStoreException e) {
                      e.printStackTrace();
                      System.exit(1);
                  }
              }
              }).start();
              while(true) {
                  ks.getEntry(TEST, protParam);
              }
          }

            hchao Haimay Chao
            djelinski Daniel Jelinski
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: