使用 SpongyCastle 的 PKCS#10 客户端证书创建 Https 连接

2023-12-09

The goal

我正在努力实现与客户端证书的通信。

步骤 1:创建 PKCS#10 请求 (CSR) 并将其交给我的服务器进行签名。服务器联系人将 CSR 传递给 CA,CA 对其进行签名,并返回 PKCS#7(带有签名的 PKCS#10 和 CA 的证书)。

步骤 2:创建 PKCS#12,将其安全地存储在 Android 设备上

步骤3:创建SSL连接,以便根据证书对客户端进行身份验证。

现在,第 1 步可以使用 SpongyCastle 1.50.0.0 完美运行,但我陷入了其他步骤...... 我目前遇到了 SSL 握手异常,但我感觉我应该重新考虑我的实现。

问题

有谁知道如何实施流程?如何创建和存储客户端证书与 Android 的 SSLContext 良好配合所需的任何内容,以及如何创建这样的 SSLContext?

到目前为止我尝试过的

我的第一次尝试是使用KeyChain,但我们希望避免此处描述的用户交互。我的第二次尝试是遵循里奇·弗里德曼的脚步,但我不知道如何从 PKCS#7 和私钥创建 PKCS#12。为了坚持,我去了这个帖子,但是 (a) 它是 C#,(b) 它未加密,(c) 我认为 android 平台有更好的密钥持久机制,但我对此一无所知。最后,这段代码(用于从 PEM 和 PKCS#7 创建 PKCS12)效果不佳,因为我不知道如何获取 CER 文件及其所需的其他内容。

Thanks!


也许不是最好的代码,但它有效,它并没有严格回答您所有的问题,但也许您会找到可以使用的部分。

你的流程很好,我也在做几乎同样的事情。

我将密钥保存在动态创建的密钥库中。另外,我有密钥库,其中包含使用 openssl 工具创建的可信证书。

对于通信,我使用了 okHttp + 改造

https://github.com/square/okhttp https://github.com/square/retrofit

产生KeyPair:

public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
    keyPairGenerator.initialize(2048);
    KeyPair keyPair = keyPairGenerator.genKeyPair();
    return keyPair;
}

生成 CSR:

private static PKCS10CertificationRequest generateCSRFile(KeyPair keyPair) throws IOException, OperatorCreationException {
    String principal = "CN=company1, OU=company1, O=company1, C=GB";
    AsymmetricKeyParameter privateKey = PrivateKeyFactory.createKey(keyPair.getPrivate().getEncoded());
    AlgorithmIdentifier signatureAlgorithm = new DefaultSignatureAlgorithmIdentifierFinder()
            .find("SHA1WITHRSA");
    AlgorithmIdentifier digestAlgorithm = new DefaultDigestAlgorithmIdentifierFinder().find("SHA-1");
    ContentSigner signer = new BcRSAContentSignerBuilder(signatureAlgorithm, digestAlgorithm).build(privateKey);

    PKCS10CertificationRequestBuilder csrBuilder = new JcaPKCS10CertificationRequestBuilder(new X500Name(
            principal), keyPair.getPublic());
    ExtensionsGenerator extensionsGenerator = new ExtensionsGenerator();
    extensionsGenerator.addExtension(X509Extension.basicConstraints, true, new BasicConstraints(true));
    extensionsGenerator.addExtension(X509Extension.keyUsage, true, new KeyUsage(KeyUsage.keyCertSign
            | KeyUsage.cRLSign));
    csrBuilder.addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, extensionsGenerator.generate());
    PKCS10CertificationRequest csr = csrBuilder.build(signer);

    return csr;
}

发送csr(您可能需要将其转换为pem格式),接收证书。

初始化密钥库:

KeyStore store = KeyStore.getInstance("BKS");
InputStream in;
try {
    in = App.getInstance().getApplicationContext().openFileInput(filename);
        try {
            store.load(in, password);
        } finally {
            in.close();
        }
    } catch (FileNotFoundException e) {
        //create new keystore
        store.load(null, password);
    }

初始化信任库:

KeyStore trustStore = KeyStore.getInstance("BKS");
InputStream in = App.getInstance().getApplicationContext().getResources().openRawResource(R.raw.truststore);
try {
    trustStore.load(in, trustorePassword);
} finally {
    in.close();
}

将密钥添加到密钥库(确保您的私钥和证书匹配,如果不匹配,密钥库不会抛出异常,并且使用 okHttp 这可能会导致 libssl 崩溃(仅在 api 低于 4.1 的设备上):

keyStore.setKeyEntry(alias, privateKey, password, new X509Certificate[]{certificate});

使用自己的创建 okHttpClientSSLContext:

OkHttpClient client = new OkHttpClient();
KeyStore keyStore = App.getInstance().getKeyStoreUtil().getKeyStore();
KeyStore trustStore = App.getInstance().getKeyStoreUtil().getTrustStore();

TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);

KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, keyStorePassword);

SSLContext sslCtx = SSLContext.getInstance("TLS");
sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
client.setSslSocketFactory(sslCtx.getSocketFactory());
client.setHostnameVerifier(org.apache.http.conn.ssl.SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);

查看 Nikolay Elenkov 博客,您还可以找到许多有用的信息以及源代码。

  • http://nelenkov.blogspot.com/
  • http://nelenkov.blogspot.com/2011/11/using-ics-keychain-api.html
  • http://nelenkov.blogspot.in/2011/12/ics-trust-store-implementation.html
  • http://nelenkov.blogspot.com/2011/12/using-custom-certificate-trust-store-on.html
  • http://nelenkov.blogspot.com/2012/05/storing-application-secrets-in-androids.html
  • http://nelenkov.blogspot.com/2013/08/credential-storage-enhancements-android-43.html

@edit

发布您的例外情况

@edit2

在你的情况下,你需要提取你的X509Certificate从 Web 服务响应中,将其存储在密钥库中,并使用用于生成 CSR 请求的私钥,并将 CA 证书存储在另一个将用作信任库的密钥库中。 (可以是相同的密钥库,但不推荐)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 SpongyCastle 的 PKCS#10 客户端证书创建 Https 连接 的相关文章

随机推荐

  • 使用 jQuery,在元素上设置 Draggable 可防止单击可拖动元素时触发模糊

    使用 jQuery 当您在文本框上设置模糊事件并将另一个元素设置为可拖动时 当您单击可拖动元素时 模糊事件不会在 FireFox 中触发 IE 稍微好一点 你得到了模糊事件 但你没有得到可拖动元素上的点击事件 如果您没有在draggable
  • 如何使用python连接到远程Windows机器来执行命令?

    我是 Python 新手 我正在尝试制作一个连接到远程 Windows 计算机并在那里执行命令并测试端口连接的脚本 这是我正在编写的代码 但它不起作用 基本上 我想要它返回本地机器数据 而不是远程机器数据 import wmi import
  • Keras 替换输入层

    我拥有的代码 我无法更改 使用 Resnetmy input tensor作为输入张量 model1 keras applications resnet50 ResNet50 input tensor my input tensor wei
  • KARATE:lowerCaseResponseHeaders 设置为 true 将redirect_uri 中的参数值也设置为小写

    我想用karate configure lowerCaseResponseHeaders true 用于测试环境之一 但问题是它在redirect uri中放入了小写的状态值 该值在responseHeaders locationPOST
  • 是否有一种更简单(更轻便)的方法可以使用 JavaFX 8 将文本置于“区域”中心?

    所以 首先 我已经实现了我想要的 那就是在 区域 的中心显示一定量的文本 截图 右上角 现在 我遇到的问题是如何实现这一点 这是整个选项卡的 FXML 摘录
  • Android SQLite 表未创建

    我正在尝试创建一个统计表 但由于某种原因 直到我调用它才创建StatisticsAdapter insertEntry 首次 之后 我可以删除该代码 重新加载新版本 然后一切正常 由于这在现实生活中行不通 我想知道如何创建一个空表 目前有一
  • 添加 API 应用程序时出现 Azure 逻辑应用程序错误

    我正在使用逻辑应用程序 API 应用程序进行 POC 以从本地 SQL 获取记录 我在 API 应用程序中创建了 SQL 连接器 还创建了逻辑应用程序 但是当尝试在逻辑应用程序设计器中添加 SQL Connector API 应用程序时 它
  • 更新SqlAlchemy多对多关联表中的值

    根据下表 如何更新用户所在的组 我觉得我必须遗漏一些明显的东西 但到目前为止我还没有找到任何东西来说明如何做到这一点 group permission table Table group permission metadata Column
  • 在 WPF 中呈现日志视图的快速方法是什么?

    我正在编写一个需要类似日志的视图 类似于 IM 客户端在对话中显示消息的方式 的应用程序 并且每秒可能有许多更新 速度在这里是一个问题 由于大量传入事件而导致应用程序锁定是一个可能的问题 我需要选择和基本文本格式 因此手动渲染可能会变得相当
  • JQuery 对象承诺的目的是什么?

    几年来 我一直在处理一个兼职问题 其中一些 DOM 元素用 jquery 加载html函数调用后无法立即访问该函数 该行为有点像在不等待文档就绪事件的情况下执行函数 虽然 html 假设是同步的 这所以答案 还有这个one 建议使用承诺ht
  • 如何在wpf中设置TAborder

    我有一个问题 我制作了一个运行良好的 wpf 应用程序 但是我想设置每个表单的制表符顺序 但我在 Vs2008 Express 版本中没有得到任何制表符顺序 我该如何解决这个问题 有谁可以帮助我吗 提前致谢 沙申克 要使 TabIndex
  • scanf 正在使用未初始化的变量; C [重复]

    这个问题在这里已经有答案了 我确信这里有一个愚蠢的错误 但是我无法弄清楚 这是我的代码的一部分 char moving scanf s moving 当我用 gcc 编译它时 它显示以下内容 newmatrix c 38 7 warning
  • 保留并删除 Newtonsoft.Json 中的尾随零

    我的 C 应用程序中的 Newtonsoft JsonConverter 存在问题 我有带尾随零的小数 转换为 json 后 缺少零 Example input decimal 1 99000 output json 1 99 我有自己的转
  • 创建会话时如何获取IP地址?

    In my grails应用程序 我已经实现了接口HttpSessionListener监听会话创建 如下所示 class MyHttpSessionListener implements HttpSessionListener publi
  • 通过Ajax回调在产品页面显示woocommerce通知

    我正在尝试在产品页面中显示 woocommerce 通知 该通知应通过 ajax 回调函数显示 并由按钮触发 回调工作正常 但没有显示任何通知 这是我的代码 jQuery AJAX document ready function retur
  • mkfifo 导致终端挂起?

    Does mkfifo根本无法与 Cygwin 一起使用 一组简单的命令 例如 mkfifo my pipe echo 1234 gt my pipe 只会导致终端永远停留在光标闪烁的状态 我 做错事 了吗 不 你没有做错任何事either
  • 如何隐藏 PrimeFaces 资源的“ln”和“v”实现/版本相关参数

    我在我的应用程序中使用 primefaces 和 primefaces extensions 对于 css 和 js 文件等每个资源 该资源的 GET 请求中还有一个 ln 和 v 查询参数 如下所示 primefaces extensio
  • 使用 xp_cmdshell 通过 DTEXEC 传递变量 (SQL Server 2008)

    我创建了一个 SSIS 包 将 Excel 文件导入到我的数据库中 我创建了一个变量 我想将其用作 Excel 连接管理器的 Excel 文件路径 我的 SSIS 包中的变量名称是 ExcelSource 它应该代表完整路径 我想最终动态设
  • Flutter:如何在Swiper中完成特定逻辑后显示下一个索引,其中GridView也在Swiper中设置?

    我正在尝试制作一个文字游戏 首先 索引将是白色的 如果用户单击正确的答案 则索引将变为绿色并进入下一个屏幕 并且下一个屏幕中的索引将为白色 再次 如果用户单击不正确的答案 则索引将变为红色 并且不要放开下一页直到用户输入正确答案 我在 Sw
  • 使用 SpongyCastle 的 PKCS#10 客户端证书创建 Https 连接

    The goal 我正在努力实现与客户端证书的通信 步骤 1 创建 PKCS 10 请求 CSR 并将其交给我的服务器进行签名 服务器联系人将 CSR 传递给 CA CA 对其进行签名 并返回 PKCS 7 带有签名的 PKCS 10 和