< prev index next >

src/share/classes/com/sun/crypto/provider/JceKeyStore.java

Print this page
rev 12545 : 8181370: Better keystore handling
Reviewed-by: weijun, igerasim

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this

@@ -25,24 +25,28 @@
 
 package com.sun.crypto.provider;
 
 import java.io.*;
 import java.util.*;
+import java.security.AccessController;
 import java.security.DigestInputStream;
 import java.security.DigestOutputStream;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.security.Key;
 import java.security.PrivateKey;
+import java.security.PrivilegedAction;
 import java.security.KeyStoreSpi;
 import java.security.KeyStoreException;
 import java.security.UnrecoverableKeyException;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateFactory;
 import java.security.cert.CertificateException;
 import javax.crypto.SealedObject;
 
+import sun.misc.ObjectInputFilter;
+
 /**
  * This class provides the keystore implementation referred to as "jceks".
  * This implementation strongly protects the keystore private keys using
  * triple-DES, where the triple-DES encryption/decryption key is derived from
  * the user's password.

@@ -833,15 +837,25 @@
                         entry.date = new Date(dis.readLong());
 
                         // read the sealed key
                         try {
                             ois = new ObjectInputStream(dis);
+                            final ObjectInputStream ois2 = ois;
+                            // Set a deserialization checker
+                            AccessController.doPrivileged(
+                                (PrivilegedAction<Void>)() -> {
+                                    ObjectInputFilter.Config.setObjectInputFilter(
+                                        ois2, new DeserializationChecker());
+                                    return null;
+                            });
                             entry.sealedKey = (SealedObject)ois.readObject();
                             // NOTE: don't close ois here since we are still
                             // using dis!!!
                         } catch (ClassNotFoundException cnfe) {
                             throw new IOException(cnfe.getMessage());
+                        } catch (InvalidClassException ice) {
+                            throw new IOException("Invalid secret key format");
                         }
 
                         // Add the entry to the list
                         entries.put(alias, entry);
 

@@ -898,6 +912,36 @@
         for (i=0; i<passwdBytes.length; i++)
             passwdBytes[i] = 0;
         md.update("Mighty Aphrodite".getBytes("UTF8"));
         return md;
     }
+
+    /*
+     * An ObjectInputFilter that checks the format of the secret key being
+     * deserialized.
+     */
+    private static class DeserializationChecker implements ObjectInputFilter {
+        private static final int MAX_NESTED_DEPTH = 2;
+
+        @Override
+        public ObjectInputFilter.Status
+            checkInput(ObjectInputFilter.FilterInfo info) {
+
+            // First run a custom filter
+            long nestedDepth = info.depth();
+            if ((nestedDepth == 1 &&
+                info.serialClass() != SealedObjectForKeyProtector.class) ||
+                nestedDepth > MAX_NESTED_DEPTH) {
+                return Status.REJECTED;
+            }
+
+            // Next run the default filter, if available
+            ObjectInputFilter defaultFilter =
+                ObjectInputFilter.Config.getSerialFilter();
+            if (defaultFilter != null) {
+                return defaultFilter.checkInput(info);
+            }
+
+            return Status.UNDECIDED;
+        }
+    }
 }
< prev index next >