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

SunPKCS11 deleteEntry does not retain CA certs used elsewhere

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Cannot Reproduce
    • Icon: P3 P3
    • None
    • 6u10
    • security-libs

      FULL PRODUCT VERSION :
      java version "1.6.0_10"
      Java(TM) SE Runtime Environment (build 1.6.0_10-b33)
      Java HotSpot(TM) Client VM (build 11.0-b15, mixed mode)

      ADDITIONAL OS VERSION INFORMATION :
      Windows XP or 2003:

      Microsoft Windows XP [Version 5.1.2600]
      EXTRA RELEVANT SYSTEM CONFIGURATION :
      PKCS11 config file:

      name=BTHSM
      library=C:\WINDOWS\system32\aetpkss1.dll
      description=StarKey_64K_SmartCafe
      slotListIndex=1
      attributes(generate,CKO_PRIVATE_KEY,CKK_RSA) = {
      CKA_TOKEN = true
      CKA_SIGN = true
      CKA_DECRYPT = true
      CKA_SENSITIVE = true
      CKA_PRIVATE = true
      CKA_EXTRACTABLE = false
      CKA_UNWRAP = true
      }
      attributes(*,CKO_PUBLIC_KEY,CKK_RSA) = {
      CKA_ENCRYPT = true
      CKA_VERIFY = true
      CKA_VERIFY_RECOVER = true
      CKA_WRAP = true
      }

      A DESCRIPTION OF THE PROBLEM :
      I think there is a problem with SunPKCS11 KeyStore deleteEntry where it deletes more certs than it should do. I have a keystore with 2 entries:

      IFMPROD_SIGN_008
      IFMPROD_SIGN_007

      all key entries are under the same CA hierarchy (issuing and root CA). I can use keytool to list with verbose and in each case see a nice 3 cert chain for each entry. I then use the deleteAlias to remove IFMPROD_SIGN_007 (either within a Java app or by running keytool -delete -alias). Then when I list my keystore again, IFMPROD_SIGN_008 is still there but the cert chain is missing i.e. each cert is shown on its own without the issuing and root CA certs. Using low level tools I can see that these CA certs have been removed.

      Now this causes issues when trying to use these entries with e.g. SunJSSE client auth because the server hello message specifies the trusted root but the client hasn't got the full chain in the HSM anymore and bombs the ssl neg.

      So I thought well I guess I just need to import each ca cert on its own - except you cant do that with PKCS11 because root CA certs cannot be imported on their own into the HSM using keytool.......

      Here I have recreated it using keytool alone using a G&D USB crypto device.


      keytool -keystore NONE -storepass 123456 -storetype PKCS11 -list -v

      Keystore type: PKCS11
      Keystore provider: SunPKCS11-BTHSM

      Your keystore contains 2 entries

      Alias name: IFMPROD_SIGN_007
      Entry type: keyEntry
      Certificate chain length: 3
      Certificate[1]:
      Owner: CN=CUS-GW-2002.intra.ifm.bt.com, OU=MSM, O=SMITHSBANK
      Issuer: CN=TESTISSCA, OU=MSM, O=BT
      Serial number: 1bc9d9a30000000002e6
      Valid from: Fri Apr 30 08:37:17 GMT 2010 until: Sat Apr 30 08:37:17 GMT 2011
      Certificate fingerprints:
      MD5: 7A:77:2F:64:BB:CA:31:E7:55:5B:4E:8D:04:93:6B:21
      SHA1: B5:0D:F5:A7:6F:11:31:12:00:CA:A1:B8:F5:DC:7B:6B:13:CD:68:36
      Certificate[2]:
      Owner: CN=TESTISSCA, OU=MSM, O=BT......
      Issuer: CN=DEVROOTCA, OU=IFM, O=BT Syntegra, L=Fleet, ST=Hants, C=GB, EMAILADDRE
      SS=###@###.###
      Serial number: 51e90a42000100000012
      Valid from: Mon Nov 17 13:48:12 GMT 2008 until: Sun Mar 17 12:18:55 GMT 2024
      Certificate fingerprints:
      MD5: 66:E1:25:FA:CC:02:74:95:E9:A7:E6:A7:E9:32:DF:F1
      SHA1: 07:47:3B:06:FB:11:E9:F5:94:99:1E:6E:7F:67:81:E1:63:A3:46:21
      Certificate[3]:
      Owner: CN=DEVROOTCA, OU=IFM, O=BT Syntegra, L=Fleet, ST=Hants, C=GB, EMAILADDRES
      S=###@###.###
      Issuer: CN=DEVROOTCA, OU=IFM, O=BT Syntegra, L=Fleet, ST=Hants, C=GB, EMAILADDRE
      SS=###@###.###
      Serial number: 5c3ad550252cd1804d9b9d256ed9cbbd
      Valid from: Wed Mar 17 12:03:38 GMT 2004 until: Sun Mar 17 12:18:55 GMT 2024
      Certificate fingerprints:
      MD5: 19:98:5A:49:6F:E6:94:73:B1:06:3F:07:E0:08:F0:D9
      SHA1: 28:14:A1:F7:8B:89:2D:1A:A1:AB:AE:C7:17:01:BF:60:06:32:D6:1F
      *****************************************
      *****************************************
      Alias name: IFMPROD_SIGN_008
      Entry type: keyEntry
      Certificate chain length: 3
      Certificate[1]:
      Owner: CN=CUS-GW-2002.intra.ifm.bt.com, OU=MSM, O=SMITHSBANK
      Issuer: CN=TESTISSCA, OU=MSM, O=BT
      Serial number: 1be98fcd0000000002e8
      Valid from: Fri Apr 30 09:11:55 GMT 2010 until: Sat Apr 30 09:11:55 GMT 2011
      Certificate fingerprints:
      MD5: 30:7B:7A:8A:4F:A0:5E:42:87:C6:ED:B3:A9:08:6A:74
      SHA1: 82:C9:DB:66:DF:12:DB:5A:ED:46:B9:79:3B:20:68:83:97:8A:57:EC
      Certificate[2]:
      Owner: CN=TESTISSCA, OU=MSM, O=BT
      Issuer: CN=DEVROOTCA, OU=IFM, O=BT Syntegra, L=Fleet, ST=Hants, C=GB, EMAILADDRE
      SS=###@###.###
      Serial number: 51e90a42000100000012
      Valid from: Mon Nov 17 13:48:12 GMT 2008 until: Sun Mar 17 12:18:55 GMT 2024
      Certificate fingerprints:
      MD5: 66:E1:25:FA:CC:02:74:95:E9:A7:E6:A7:E9:32:DF:F1
      SHA1: 07:47:3B:06:FB:11:E9:F5:94:99:1E:6E:7F:67:81:E1:63:A3:46:21
      Certificate[3]:
      Owner: CN=DEVROOTCA, OU=IFM, O=BT Syntegra, L=Fleet, ST=Hants, C=GB, EMAILADDRES
      S=###@###.###
      Issuer: CN=DEVROOTCA, OU=IFM, O=BT Syntegra, L=Fleet, ST=Hants, C=GB, EMAILADDRE
      SS=###@###.###
      Serial number: 5c3ad550252cd1804d9b9d256ed9cbbd
      Valid from: Wed Mar 17 12:03:38 GMT 2004 until: Sun Mar 17 12:18:55 GMT 2024
      Certificate fingerprints:
      MD5: 19:98:5A:49:6F:E6:94:73:B1:06:3F:07:E0:08:F0:D9
      SHA1: 28:14:A1:F7:8B:89:2D:1A:A1:AB:AE:C7:17:01:BF:60:06:32:D6:1F
      *****************************************

      keytool -debug -keystore NONE -storepass 123456 -storetype PKCS11 -delete -alias IFMPROD_SIGN_007
      keytool -keystore NONE -storepass 123456 -storetype PKCS11 -list -v

      Keystore type: PKCS11
      Keystore provider: SunPKCS11-BTHSM

      Your keystore contains 1 entry

      Alias name: IFMPROD_SIGN_008
      Entry type: keyEntry
      Certificate chain length: 1
      Certificate[1]:
      Owner: CN=CUS-GW-2002.intra.ifm.bt.com, OU=MSM, O=SMITHSBANK
      Issuer: CN=TESTISSCA, OU=MSM, O=BT
      Serial number: 1be98fcd0000000002e8
      Valid from: Fri Apr 30 09:11:55 GMT 2010 until: Sat Apr 30 09:11:55 GMT 2011
      Certificate fingerprints:
      MD5: 30:7B:7A:8A:4F:A0:5E:42:87:C6:ED:B3:A9:08:6A:74
      SHA1: 82:C9:DB:66:DF:12:DB:5A:ED:46:B9:79:3B:20:68:83:97:8A:57:EC
      *****************************************
      *****************************************

      JRE is 1.5.0_22 but 1.6.0_13 also does the same thing.

      Iâve looked at openjdk and can see that the code should retain CA certs if they are referenced in the chains of other key entries. What my app does is annually generate new RSA keys and gt them recertified and while thatâs happening the system can continue to use the old key+cert chain until the new one has been issued by the CA and can be loaded. I then import the new entry (as a cert chain) then if that looks good I then remove the old entry. The problem is that by removing the old entry it blows the cert chain away for the new entry and you end up with an unusable key entry.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Obtain a PKCS11 device (password 123456)
      Configure SunPKCS11 to use this device.
      Configure SunPKCS11 in java,security
      Create two key entries RSA and load cert chains issued by the same CA (say alias1 and alias2)
      List the device contents to see the two chains:
        keytool -keystore NONE -storetype PKCS11 -storepass 123456 -list -v
      Delete one of the two aliases
        keytool -keystore NONE -storetype PKCS11 -storepass 123456 -delete -alias alias1
      List the device contents to see the remaining key entry plus chain:
        keytool -keystore NONE -storetype PKCS11 -storepass 123456 -list -v



      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      At the end of the steps outlined the keytool listing SHOULD show the remaining entry with a full chain.
      ACTUAL -
      The keystore listing lists the remaining keystore entry but with the CA certificates missing

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      N/A the error is that the cert chain for the remaining key entry is destroyed making use of e.g. JSSE client auth impossible.

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      No source code required. Using keytool repeats the problem.
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      I have coded a workaround. My code seeks out a key entry that is a sibling or in some way related to the doomed entry. It then gets this sibling and its chain, removes the doomed entry then stores the entry back in again.

      /**
      * Delete the given keystore entry.
      * Updated 7/5/10: if the key entry has a certificate chain then replace this with a self-cert
      * before deleting the entry. The reason for doing this is that the deleteEntry
      * takes out the full cert chain regardless of whether or not the cert chain comp[onents are used elsewhere.
      * @param alias : doomed alias
      * @throws KeyStoreException if not found or cant remove.
      */
      public synchronized void deleteAlias(String alias)
      throws KeyStoreException
      {
      boolean deleted = false;
      if (_keyStore.containsAlias(alias)) {
      try {
      if (_keyStore.isKeyEntry(alias)) {
      X509Certificate [] certChain = findCertificateChain(alias);
      if (certChain != null && certChain.length > 0) {
      if (certChain.length > 1) {
      // Find another entry that is issued by the same issuer.
      CertificateSibling cs = new CertificateSibling();
      if (cs.findRelative(alias, certChain)) {
      _keyStore.deleteEntry(alias);
      deleted = true;
      if (cs.keyPair != null && cs.certChain != null) {
      storeKeyPair(cs.alias, cs.keyPair, cs.certChain);
      }
      }
      }
      }
      }
      }
      // if the self-cert process fails then just delete the entry.
      catch (GeneralSecurityException e) {
      }
      finally {
      if (!deleted) {
      _keyStore.deleteEntry(alias);
      }
      }
      }
      }

      public class CertificateSibling {
      String alias;
      X509Certificate [] certChain;
      KeyPair keyPair;

      /**
      * Find a single sibling entry to the given alias i.e. one that shares the same
      * issuer principal
      * @param alias : the alias whose siblings are being sought
      * @param issuer : the issuer principal
      * @return an array of strings or an array of 0 length if none found.
      * @throws KeyStoreException : failed to access the keystore.
      */
      private boolean findIndexedRelative(String alias, int parentIndex, X509Certificate [] certChain) throws KeyStoreException {
      Enumeration<String> eAliases = _keyStore.aliases();
      while (eAliases.hasMoreElements()) {
      String possibleSliblingAlias = eAliases.nextElement();
      if (!possibleSliblingAlias.equalsIgnoreCase(alias)) {
      X509Certificate [] siblingCertChain = findCertificateChain(possibleSliblingAlias);
      if (siblingCertChain != null && siblingCertChain.length > parentIndex && certChain[parentIndex].equals(siblingCertChain[parentIndex])) {
      this.alias = possibleSliblingAlias;
      this.keyPair = findKeyPair(possibleSliblingAlias, null);
      this.certChain = siblingCertChain;

      return true;
      }
      }
      }

      return false;
      }

      /**
      * Find a single sibling entry to the given alias i.e. one that shares the same
      * issuer principal
      * @param alias : the alias whose siblings are being sought
      * @param issuer : the issuer principal
      * @return an array of strings or an array of 0 length if none found.
      * @throws KeyStoreException : failed to access the keystore.
      */
      public boolean findRelative(String alias, X509Certificate [] certChain) throws KeyStoreException {
      boolean found = false;
      if (certChain == null || certChain.length <= 1) {
      return false;
      }
      for (int i = 1; !found && i < certChain.length; i++) {
      found = findIndexedRelative(alias, i, certChain);
      }
      return found;
      }
      }

            valeriep Valerie Peng
            ndcosta Nelson Dcosta (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: