问题描述
我正在处理具有多个唯一标识的从属进程的分布式应用程序,这些进程将通过启用SSL的套接字与主应用程序进行通信。该应用程序是用Java编写的。
I am working on a distributed application with a number of uniquely identified slave processes that will communicate with a master application via SSL enabled sockets. The application is written in java.
我需要一些帮助来了解SSLSocket,或者更确切地说,是它们使用的证书。
I need some help understanding SSLSockets, or rather, the certificates they use.
我正在寻找的是一个可以告诉我我是否正确理解了证书链基本工作原理的人,但是我也不会拒绝代码示例。
What i am looking for is someone who can tell me if i have understood the basic workings of certificate chains correctly, but i wouldn't say no to a code sample either.
我想要一个服务器本身具有CA签名证书的设置,每个从属服务器都将获得由主应用程序创建的自己的证书。
I would like a setup where the server itself has a CA signed certificate, and every slave will get their own certificate created by the master application.
CA->Main server cert->Master SSL cert
CA->Main server cert->Slave SSL cert 1
CA->Main server cert->Slave SSL cert 2
CA->Main server cert->Slave SSL cert 3
第一个问题:这种证书链是解决问题的正确方法吗?
我想这是使主服务器和从属服务器都具有唯一身份而不用CA对每个证书进行签名的最简单方法。
First question: Is this kind of certificate chain the correct way to tackle the problem?I am thinking this is the simplest way of achieving the master and slaves all have a unique identity without having to CA sign every certificate.
第二个问题:
如何以编程方式在Java中创建SSL证书?我正在尝试在这里创建链中的最后一个证书,假设我现在已经拥有主服务器证书。
到目前为止,我已经生成了用于证书的密钥(类型为RSA):
Second question:How do i programatically go about creating an SSL certificate in java? I am trying to create the last certificate in the chain here, assuming i already have the "Main server cert" for now.I have gotten so far as generating a key for the certificate (Where type is RSA):
public KeyPair generateKeypair(String type, int bytes)
throws NoSuchAlgorithmException{
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(type);
keyPairGenerator.initialize(bytes);
return keyPairGenerator.generateKeyPair();
}
X509Principal issuer = PrincipalUtil.getSubjectX509Principal(serverCert);
SubjectPublicKeyInfo key
= SubjectPublicKeyInfo.getInstance(kpair.getPublic().getEncoded());
X509v3CertificateBuilder certGen
= new X509v3CertificateBuilder(
issuer,
BigInteger.valueOf(new SecureRandom().nextInt()),
before,
after,
subject,
key
);
AlgorithmIdentifier sigAlgId
= new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1withRSA");
AlgorithmIdentifier digAlgId
= new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
我不认为将serverCert设置为颁发者足以签署证书吗?据我了解,我需要以某种方式在链中的下一个证书上签名新证书,但是我该怎么做?我是否使用serverCert的私钥对证书签名?
I don't assume that setting the serverCert as the issuer is enough to sign the certificate? As far as i have understood i need to sign the new certificate with the next certificate in the chain somehow, but how do i do that? Do i sign the certificate with the serverCert's private key like:
AsymmetricKeyParameter akp
= PrivateKeyFactory.createKey(serverPrivateKey.getEncoded());
AlgorithmIdentifier sigAlgId
= new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1withRSA");
AlgorithmIdentifier digAlgId
= new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
ContentSigner sigGen
= new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(akp);
我还错过了其他任何步骤吗?
Are there any other steps i missed?
推荐答案
从技术角度来看,您的解决方案是正确的。但是,请不要忘记安全性注意事项:谁可以请求证书,如何执行身份验证,证书/私钥如何分配到服务器...
From a technical point of view your solution is correct. However do not forget the security considerations: who can request a certificate, how the authentication is performed, how the certificates/private keys are distributed to the servers...
这些元素对于生成证书是必不可少的:
These elements are mandatory for a certificate generation:
- 主题名称
- 颁发者名称
- 证书序列号
- 主题公钥
- 有效期(不早于,不晚于)
- Subject Name
- Issuer name
- certificate serial number
- subject public key
- validity dates (not before, not after)
添加一些扩展名也是一个好习惯:
It is also a good practice to add some extensions:
- 主题密钥标识符
- 授权密钥标识符
- 基本约束
- 密钥用法
- 扩展的密钥用法
- Subject Key Identifier
- Authority Key Indentifier
- Basic Constraints
- Key Usage
- Extended Key Usages
此代码段概述了证书的生成:
This code snippet outlines the certificate generation:
ContentSigner getCertSigner(PrivateKey issuerKey) {
AsymmetricKeyParameter akp = PrivateKeyFactory.createKey(issuerKey.getEncoded());
AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1withRSA");
AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
return new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(akp);
}
X509CertificateHolder generateCertificate(X509Certificate issuerCert, PrivateKey issuerKey, X500Name subject, PublicKey subjectKey, Date notBefore, Date notAfter) {
X509Principal issuerDN = PrincipalUtil.getSubjectX509Principal(issuerCert);
SubjectPublicKeyInfo key = SubjectPublicKeyInfo.getInstance(subjectKey.getEncoded());
X509v3CertificateBuilder builder = new X509v3CertificateBuilder(issuerDN, BigInteger.valueOf(new SecureRandom().nextInt()), before, after, subject, key);
// Add authority key identifier
builder.addExtension(X509Extension.authorityKeyIdentifier, false, JcaX509ExtensionUtils.createAuthorityKeyIdentifier(issuerCert));
// Add subject key identifier
builder.addExtension(X509Extension.subjectKeyIdentifier, false, JcaX509ExtensionUtils.createSubjectKeyIdentifier(subjectKey));
// Add basic constraints
builder.addExtension(X509Extension.basicConstraints, true, new BasicConstraints(false));
// Add key usage
KeyUsage keyUsage = new KeyUsage(KeyUsage.keyEncipherment|KeyUsage.digitalSignature);
builder.addExtension(X509Extension.keyUsage, true, keyUsage);
// Add extended key usage
ExtendedKeyUsage extKeyUsage = new ExtendedKeyUsage(KeyPurposeId.id_kp_serverAuth);
builder.addExtension(X509Extension.extendedKeyUsage, false, extKeyUsage);
return builder.build(getCertSigner(issuerKey));
}
更新:根据Martin Nielsen的修正代码评论。
UPDATE: fixed the code according to Martin Nielsen's comment.
这篇关于创建用于SSL通信的证书的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!