1 /* 2 * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.crypto.provider; 27 28 import jdk.internal.misc.SharedSecrets; 29 30 import java.io.*; 31 import java.security.*; 32 import javax.crypto.*; 33 34 final class SealedObjectForKeyProtector extends SealedObject { 35 36 static final long serialVersionUID = -3650226485480866989L; 37 38 /** 39 * The InputStreamFilter for a Key object inside this SealedObject. It can 40 * be either provided as a {@link Security} property or a system property 41 * (when provided as latter, it shadows the former). If the result of this 42 * filter is {@link java.io.ObjectInputFilter.Status.UNDECIDED}, the system 43 * level filter defined by jdk.serialFilter will be consulted. The value 44 * of this property uses the same format of jdk.serialFilter. 45 */ 46 private static final String KEY_SERIAL_FILTER = "jceks.key.serialFilter"; 47 48 SealedObjectForKeyProtector(Serializable object, Cipher c) 49 throws IOException, IllegalBlockSizeException { 50 super(object, c); 51 } 52 53 SealedObjectForKeyProtector(SealedObject so) { 54 super(so); 55 } 56 57 AlgorithmParameters getParameters() { 58 AlgorithmParameters params = null; 59 if (super.encodedParams != null) { 60 try { 61 params = AlgorithmParameters.getInstance("PBE", 62 SunJCE.getInstance()); 63 params.init(super.encodedParams); 64 } catch (NoSuchAlgorithmException nsae) { 65 throw new RuntimeException( 66 "SunJCE provider is not configured properly"); 67 } catch (IOException io) { 68 throw new RuntimeException("Parameter failure: "+ 69 io.getMessage()); 70 } 71 } 72 return params; 73 } 74 75 final Key getKey(Cipher c, int maxLength) 76 throws IOException, ClassNotFoundException, IllegalBlockSizeException, 77 BadPaddingException { 78 79 try (ObjectInputStream ois = SharedSecrets.getJavaxCryptoSealedObjectAccess() 80 .getExtObjectInputStream(this, c)) { 81 AccessController.doPrivileged( 82 (PrivilegedAction<Void>) () -> { 83 ois.setObjectInputFilter(new DeserializationChecker(maxLength)); 84 return null; 85 }); 86 try { 87 @SuppressWarnings("unchecked") 88 Key t = (Key) ois.readObject(); 89 return t; 90 } catch (InvalidClassException ice) { 91 String msg = ice.getMessage(); 92 if (msg.contains("REJECTED")) { 93 throw new IOException("Rejected by the" 94 + " jceks.key.serialFilter or jdk.serialFilter" 95 + " property", ice); 96 } else { 97 throw ice; 98 } 99 } 100 } 101 } 102 103 /** 104 * The filter for the content of a SealedObjectForKeyProtector. 105 * 106 * First, the jceks.key.serialFilter will be consulted. If the result 107 * is UNDECIDED, the system level jdk.serialFilter will be consulted. 108 */ 109 private static class DeserializationChecker implements ObjectInputFilter { 110 111 private static final ObjectInputFilter OWN_FILTER; 112 113 static { 114 String prop = AccessController.doPrivileged( 115 (PrivilegedAction<String>) () -> { 116 String tmp = System.getProperty(KEY_SERIAL_FILTER); 117 if (tmp != null) { 118 return tmp; 119 } else { 120 return Security.getProperty(KEY_SERIAL_FILTER); 121 } 122 }); 123 OWN_FILTER = prop == null 124 ? null 125 : ObjectInputFilter.Config.createFilter(prop); 126 } 127 128 // Maximum possible length of anything inside 129 private final int maxLength; 130 131 private DeserializationChecker(int maxLength) { 132 this.maxLength = maxLength; 133 } 134 135 @Override 136 public ObjectInputFilter.Status checkInput( 137 ObjectInputFilter.FilterInfo info) { 138 139 if (info.arrayLength() > maxLength) { 140 return Status.REJECTED; 141 } 142 143 if (info.serialClass() == Object.class) { 144 return Status.UNDECIDED; 145 } 146 147 if (OWN_FILTER != null) { 148 Status result = OWN_FILTER.checkInput(info); 149 if (result != Status.UNDECIDED) { 150 return result; 151 } 152 } 153 154 ObjectInputFilter defaultFilter = 155 ObjectInputFilter.Config.getSerialFilter(); 156 if (defaultFilter != null) { 157 return defaultFilter.checkInput(info); 158 } 159 160 return Status.UNDECIDED; 161 } 162 } 163 }