我需要在两个桌面Java应用程序之间进行通信,最好的方法是使用SSL(以防止嗅探器)。我控制客户端和服务器,所以自签名是可以的。
我的问题是,是否可以通过编程方式从头开始制作和使用证书(即最终用户不必亲自做任何事情)。
如果可以的话,你能给我一些指示吗?
答案 0 :(得分:4)
我的问题是,是否可以从头开始制作和使用证书 以编程方式(即最终用户不必在物理上做 他自己的任何事情。)
在考虑生成证书(以编程方式与否)之前,您需要决定如何验证它们。在两个桌面应用程序的上下文中,验证服务器证书的传统方法可能不合适。
证书的目的是提供一种验证远程方身份的方法,以防止中间人攻击。验证方使用已经信任的东西进行验证;不这样做会使证书毫无意义。
在传统模型(具有固定服务器)中,服务器证书是PKI的一部分并由CA颁发。客户端根据它信任的一组CA证书验证其真实性(通常使用RFC 5280中描述的规则,并验证证书对于正在查找的主机名是否有效(如何完成此操作取决于协议但RFC 6125)中描述了最佳和历史实践。这两个步骤都是防止MITM攻击的必要步骤。它类似于使用护照验证某人的身份:您要检查护照是否真实且来自您信任的机构,并且您想要检查名称(或图片)是否与您要查找的名称(或您面前的面孔)相匹配。
在两个桌面应用程序之间建立通信时,您肯定会遇到以下两个方面的问题:如何让客户端验证证书是由您信任的实体颁发的,并发布给您要通信的实体用。如果您以编程方式生成证书,则无论是哪一方,它肯定都是自签名的,这将使得从另一方面验证其真实性变得困难而没有其他交换方式(独立于此SSL / TLS通信)。此外,桌面往往没有固定的主机名,因此在这种情况下,基于DNS(甚至IP地址)的标识符可能不足。
您需要考虑以远程方可以验证其信任的方式发布证书的方法,并考虑识别方案以确保证书属于正确的实体(这通常是证书的主题DN或主题备用名称扩展名是什么。)
做出这些决定后,您可以使用BouncyCastle的org.bouncycastle.x509.X509V3CertificateGenerator
生成证书(X.509 v3证书应该允许您添加证书的扩展名,例如用于密钥使用目的,如果你需要它们)。 BouncyCastle wiki上有各种示例(对于v1,v3和/或自签名,即Subject = Issuer)。我会说不幸的是,使用这个很容易(信任的行政方面将是最难的)。
如果两个桌面应用程序实际上都是更集中的应用程序的一部分,则可以从应用程序中生成的证书请求(CSR)运行颁发此证书的服务。中央服务器将有效地运行您自己的CA,您的桌面应用程序将信任该CA.根据组织的复杂程度,有可用的工具,或者你也可以使用BouncyCastle来实现它,使用相同的类(如果你实现了CRL / OSCP以便能够撤销证书,那就更好了)。在这种情况下,您可以使应用程序生成CSR并将其提交给中央CA.可以使用PKCS10CertificationRequest
使用BouncyCastle生成CSR。同样,您的CA如何使用外部信息验证CSR来自正确的一方,也是一个管理问题,也许您可以将其与电子邮件验证方案或类似的方案联系起来。
生成证书后,您将能够使用Java's JSSE作为SSL / TLS堆栈(通常使用SSLSocket
)。您可能必须使用自定义X509TrustManager
来实施证书验证(如果您无法使用传统CA模型,则取决于您设计方案以验证证书的方式)。只需确保您不使用在check*
方法中不执行任何操作的信任管理器;有很多这方面的例子:在这种情况下你可能根本不使用证书,如果你没有做任何事情来验证它们(这会使连接容易受到MITM攻击)。
答案 1 :(得分:1)
您可以使用基于JCE的解决方案及其SSLSocket, docs for jdk6及其实现:SSLSocketImpl。
Java SSL SSH:
您有Jsch lib可以使用SSH协议连接到任何服务器。
用于SSL的Java工具箱:
你有Bouncy Castle。 看看他们的resources和他们的documentation。维基为some usefull examples提供了最新版本:
ContentSigner sigGen = ...;
PublicKey publicKey = ....;
Date startDate = new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000);
Date endDate = new Date(System.currentTimeMillis() + 365 * 24 * 60 * 60 * 1000);
X509v1CertificateBuilder v1CertGen = new JcaX509v1CertificateBuilder(
new X500Principal("CN=Test"),
BigInteger.ONE,
startDate, endDate,
new X500Principal("CN=Test"),
publicKey);
X509CertificateHolder certHolder = v1CertGen.build(sigGen);