changeset 1705:e4582bc440c8

8181370: Better keystore handling Reviewed-by: weijun, igerasim
author igerasim
date Sun, 02 Jul 2017 15:17:19 -0700
parents a871b5d19701
children ed8ead4b62a1
files src/share/classes/com/sun/crypto/provider/JceKeyStore.java
diffstat 1 files changed, 48 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/crypto/provider/JceKeyStore.java	Wed Jul 05 13:21:08 2017 -0700
+++ b/src/share/classes/com/sun/crypto/provider/JceKeyStore.java	Sun Jul 02 15:17:19 2017 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2011, 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
@@ -27,12 +27,14 @@
 
 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;
@@ -41,6 +43,8 @@
 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
@@ -834,11 +838,24 @@
                         // read the sealed key
                         try {
                             ois = new ObjectInputStream(dis);
+                            final ObjectInputStream ois2 = ois;
+                            // Set a deserialization checker
+                            AccessController.doPrivileged(
+                                    new PrivilegedAction<Void>() {
+                                        @Override
+                                        public Void run() {
+                                            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
@@ -896,4 +913,34 @@
         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;
+        }
+    }
 }