【问题标题】:Storing a KeyStore in Java: empty file and unable to reload在 Java 中存储 KeyStore:空文件且无法重新加载
【发布时间】:2023-03-16 01:55:01
【问题描述】:

所以,我的问题有一些非常具体的部分,但我会尽我最大的努力将它们排除在外。

我正在尝试做的事情:我正在插入我的 eID 卡(电子身份证)。从理论上讲,我应该能够使用 Java KeyStore 保存其上的密钥库和证书。我可以这样加载 eID 卡:

/*Load from eID*/
KeyStore keyStore = null;
try (FileOutputStream fos = new FileOutputStream(Constants.fullFileEID)) {
    /*Load*/
    Security.addProvider(new BeIDProvider());
    keyStore = KeyStore.getInstance("BeID");
    keyStore.load(null);

所以我正在加载 keyStore(通过添加提供程序,这要归功于我添加的外部库)。作为记录:常量是我正在使用的常量类,而 fullFileEID 是应保存 EID 的完整文件路径(该路径,除了文件本身,存在)。

然后我尝试打印一些细节(我正在记录到一个文件,因为我的 System.out 中已经有一个非常大的日志,只是为了保持清晰):

    /*Test*/
    FileLogging.writeToFile("Type: " + keyStore.getType());
    FileLogging.writeToFile("Authentication certificate: " + keyStore.getCertificate("Authentication").getClass());
    FileLogging.writeToFile("Authentication serialized: " + Serialization.serialize(keyStore.getCertificate("Authentication")));
    FileLogging.writeToFile("Signature certificate: " + keyStore.getCertificate("Signature").getClass());
    FileLogging.writeToFile("Signature serialized: " + Serialization.serialize(keyStore.getCertificate("Signature")));
    FileLogging.writeToFile("Provider: " + keyStore.getProvider());
    FileLogging.writeToFile("Should be saved in " + Constants.fullFileEID);

我在那里得到了很多有趣的细节。它不为空,一切似乎都加载得很完美(我的 keyStore 中有两个别名,“Authentication”和“Signature”)。记录一下:序列化是我的另一个 Helper 类,它将对它接收到的对象进行序列化和 Base64 编码 - serialize 函数接收 Serializable 作为参数。

这是我得到的(我截断了序列化的字符串):

Type: BeID
Authentication certificate: class sun.security.x509.X509CertImpl
Authentication serialized: rO0ABXNyAC1qYXZhLnNlY3VyaXR5LmNlcnQuQ2VydGlma[...]
Signature certificate: class sun.security.x509.X509CertImpl
Signature serialized: rO0ABXNyAC1qYXZhLnNlY3VyaXR5LmNlcnQuQ2VydGlmaWNhdG[...]
Provider: BeIDProvider version 1.0
Should be saved in [fullFilePath]\eID.jks

所以证书本身来自“普通”类,它们没有子类化,所以序列化方法中应该存在我不知道的特殊情况......因此,序列化本身也可以完美运行。

好的,所以测试是肯定的,我认为:是时候实际存储我的文件了。

    /*Save*/
    keyStore.store(fos, "xxxx".toCharArray());
    System.out.println("keystore: ");
    keyStore.store(System.out, "xxxx".toCharArray());
} catch (Exception e) {
    Util.handleLogging(e);
}

所以,我使用上面创建的 FileOutputStream 到 store 到 keyStore。 (“xxxx”是密码 - 我不确定它是否需要成为卡的密码,因为我已经可以读取和打印认证卡的内容而无需提供任何密码)。我还尝试将输出“打印”到 System.out。

现在是有趣的部分:创建的文件是空的。它是由这个函数创建的(或者至少一个更早的文件被覆盖了)。如果文件不存在,则创建。但它有 0kb 大,当然,它不起作用。

我做错了什么?我真的不明白有什么问题?我怀疑在实际保存过程中是否出现任何问题,我至少会得到一个异常(如 CertificateException,应该在文档中“如果密钥库数据中包含的任何证书无法存储”时抛出)?

我不得不承认,我不喜欢没有人需要为我提供密码才能读取卡中的数据。我觉得这不对。

【问题讨论】:

    标签: java serialization certificate x509certificate keystore


    【解决方案1】:

    比利时 eID 具有 Java 密钥库的特定实现。如果您查看实现 be.fedict.commons.eid.jca.BeIDKeyStore,您会发现 store 方法没有实现。

    @Override
    public void engineStore(final OutputStream stream, final char[] password)
            throws IOException, NoSuchAlgorithmException, CertificateException {
    }
    

    我遇到了同样的问题,但我还没有找到解决方案。

    【讨论】:

    • 我想的也差不多。一方面我理解为什么(能够保存某人的私钥和东西并不安全),但另一方面......我不知道如何解决这个问题。我们需要的任何东西在那个类中都是私有的。
    • 这取决于你需要什么。如果您需要卡中的某些特定证书,您可以随时使用 EID 查看器将它们导出为 DER 或 PEM 文件,然后将它们导入您的应用程序中。
    • 我需要它来进行远程签名,所以我想我会导出一个 PEM 文件来导入该证书。这似乎行得通。
    • 这里面临同样的问题,密钥库为空,但使用基于阿拉丁的 USB 令牌。有人找到工作了吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-02-12
    • 2017-10-15
    • 1970-01-01
    • 1970-01-01
    • 2011-02-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多