BC库使用PKCS10CertificationRequestBuilder来构造CSR,该类的注释里其实很清楚的描述了CSR的结构,如下所示:
CertificationRequest ::= SEQUENCE {
certificationRequestInfo CertificationRequestInfo,
signatureAlgorithm AlgorithmIdentifier{{ SignatureAlgorithms }},
signature BIT STRING
}
CertificationRequestInfo ::= SEQUENCE {
version INTEGER { v1(0) } (v1,...),
subject Name,
subjectPKInfo SubjectPublicKeyInfo{{ PKInfoAlgorithms }},
attributes [0] Attributes{{ CRIAttributes }}
}
Attributes { ATTRIBUTE:IOSet } ::= SET OF Attribute{{ IOSet }}
Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE {
type ATTRIBUTE.&id({IOSet}),
values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{\@type})
}
下面稍加注释:
CertificationRequest即为CSR结构,可以看到,它包含了三部分:
- certificationRequestInfo:CSR基本信息。
- signatureAlgorithm:对CSR基本信息签名时使用的签名算法。
- signature:对CSR基本信息的签名,当然一般是使用私钥来进行签名,CA在签发证书时是会使用certificationRequestInfo里的公钥来验签。
CertificationRequestInfo,CSR基本信息,其结构包含了以下四部分:
- version:版本号。
- subject:使用者信息。
- subjectPKInfo:公钥信息,里面又包含了非对称算法标识和公钥数据两部分。
- attributes:其他属性集合。
CSR的构建过程主要体现在PKCS10CertificationRequestBuilder的build方法中,理解了CSR的结构,其实其构造过程也就很好理解了,主要就是DER编码和签名:
public PKCS10CertificationRequest build(
ContentSigner signer)
{
CertificationRequestInfo info;
if (attributes.isEmpty())
{
//如果其他属性集合是空的,通过leaveOffEmpty来判断是否要编码一个空的集合到CSR中
if (leaveOffEmpty)
{
info = new CertificationRequestInfo(subject, publicKeyInfo, null);
}
else
{
info = new CertificationRequestInfo(subject, publicKeyInfo, new DERSet());
}
}
else
{
ASN1EncodableVector v = new ASN1EncodableVector();
for (Iterator it = attributes.iterator(); it.hasNext(); )
{
v.add(Attribute.getInstance(it.next()));
}
//将使用者信息、公钥信息、其他属性集合填充到CSR基本信息中
info = new CertificationRequestInfo(subject, publicKeyInfo, new DERSet(v));
}
try
{
OutputStream sOut = signer.getOutputStream();
//把CSR基本信息经过DER编码后塞到签名对象中,准备对CSR基本信息进行签名。signer中持有对应的私钥以及签名算法标识。
sOut.write(info.getEncoded(ASN1Encoding.DER));
sOut.close();
//CSR基本信息、签名算法、对CSR基本信息的签名值,就构成了一个符合PKCS10标准的CSR
return new PKCS10CertificationRequest(new CertificationRequest(info, signer.getAlgorithmIdentifier(), new DERBitString(signer.getSignature())));
}
catch (IOException e)
{
throw new IllegalStateException("cannot produce certification request signature");
}
}