当我尝试在Windows上使用Oracle Java 8 JRE 172打开JCEKS类型密钥存储区时,我收到以下异常。这与早期版本的JRE一起工作正常:
INFO: ObjectInputFilter REJECTED: null, array length: -1, nRefs: 1, depth: 1, bytes: 70, ex: n/a
[...call stacks omitted to protect the innocent...]
Caused by: java.io.IOException: Invalid secret key format
at com.sun.crypto.provider.JceKeyStore.engineLoad(JceKeyStore.java:856)
at java.security.KeyStore.load(Unknown Source)
[...]
这看起来非常像JDK-8202506,但我使用Java 8,我在初始INFO消息中得到null
。
这是同一个问题吗?
在我看来,JDK-8202506问题目前在任何公开的JRE版本中都没有修复。我对吗?
更新1
这看起来很相似,他们也没有解决方案:ATLAS-2642
更新2
出于某种原因,Equinox在升级后未能看到com.sun.crypto.provider.SealedObjectForKeyProtector
类,即使它显然位于新JDK附带的JRE中:
BundleClassLoader[foo.bar.baz.crypto].loadClass(com.sun.crypto.provider.SealedObjectForKeyProtector) failed.
java.lang.ClassNotFoundException: com.sun.crypto.provider.SealedObjectForKeyProtector
at org.eclipse.osgi.framework.internal.core.BundleLoader.findClassInternal(BundleLoader.java:481)
at org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLoader.java:397)
at org.eclipse.osgi.framework.internal.core.BundleLoader.findClass(BundleLoader.java:385)
at org.eclipse.osgi.internal.baseadaptor.DefaultClassLoader.loadClass(DefaultClassLoader.java:87)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:686)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1866)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1749)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2040)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1571)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:431)
at com.sun.crypto.provider.JceKeyStore.engineLoad(JceKeyStore.java:850)
at java.security.KeyStore.load(KeyStore.java:1445)
更新3
类SealedObjectForKeyProtector.class
与sunjce_provider.jar
中的其他类不同。当我们尝试使用JD-GUI对其进行反编译时,与其他类不同,它会因内部错误而失败:
这几天我遇到了这个问题。根据我的故障排除,它是由此方法的不同返回值引起的:
sun.misc.VM.latestUserDefinedLoader()
以前(在8u171之前),此方法返回sun.misc.Launcher$ExtClassLoader
,而它在升级后返回应用程序的类加载器。在ObjectInputStream中,两个类加载器都可以成功加载com.sun.crypto.provider.SealedObjectForKeyProtector
,这只是因为ExtClassLoader是应用程序的类加载器(或父类的父类)的父类。但是,一旦应用程序的类加载器加载了SealedObjectForKeyProtector,它的类加载器就不再等于ExtClassLoader。
另一方面,在com.sun.crypto.provider.JceKeyStore
中,与ObjectInputStream
不同,SealedObjectForKeyProtector
总是由ExtClassLoader加载。因此,下面检查JceKeyStore.java:932将失败,因为类不相等:
932 if (info.serialClass() != SealedObjectForKeyProtector.class))
934 return Status.REJECTED;
然后,我们最终会得到以下日志和IOException:ObjectInputFilter
REJECTED:class com.sun.crypto.provider.SealedObjectForKeyProtector
解决方案:确保ContextClassLoader没有通过某些配置加载类com.sun.crypto.provider.SealedObjectForKeyProtector
。细节取决于ContextClassLoader。例如,对于org.powermock.core.classloader.MockClassLoader
,具体的解决方案是在下面的注释中添加相关的测试类:
@PowerMockIgnore("com.sun.*")
我目前正在使用Oracle JRE支持,并打开了一个私有错误。到目前为止我得到的信息:
解决方案:
解决方法是将以下行添加到OSGi包MANIFEST.MF中。
Eclipse-BuddyPolicy:分机
我亲自用JRE 1.8_181验证了这种解决方法,看起来很有效。
我还被告知,对于Java 9,JVM参数-Dosgi.compatibility.bootdelegation = true可以完成工作(无需更新MANIFEST.MF),但我没有Java 9环境来验证它。感谢是否有人可以尝试并让我们知道结果。
我已经完成了对该问题的完整分析,并通过JCEKS密钥库中涉及的代码部分进行了调试。每当应用程序使用自定义类加载器时,如果使用旧版Java版本的JCEKS密钥库而不是JDK 8 Update 151,您将面临问题。
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 &&
info.serialClass() != null &&
info.serialClass() != Object.class)) {
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;
}
}
在上面的JceKeyStore.class代码中,过滤器信息将始终为null,因此info.serialClass()!= SealedObjectForKeyProtector.class检查将失败。在像Equinox-Eclipse插件这样的自定义类加载器的情况下,类加载委托不会像预期的那样发生。
有两步解决方案