我想了解如何签署x.509证书。
我已经设置了一个OpenSSL CA来创建一个演示证书。证书很好,我可以使用名为dumpasn1的工具查看所有相关元素。 从理论上讲,我知道我必须签署名为" tbsCertificate"其中包括属性版本,序列号签名,发行者,有效性,主题,subjectPublicKeyInfo和扩展名。
然而,当我尝试在Java中模仿它时,遗憾的是它不起作用。 我所做的是:
public static void sign(byte [] data) throws Exception
{
String algorithm = "SHA256withECDSA";
PrivateKey privKey;
KeyPair keyPair;
keyPair = getKeyPairFomPEM();
privKey = keyPair.getPrivate();
Signature ecdsa;
ecdsa = Signature.getInstance(algorithm, "BC");
ecdsa.initSign(privKey);
ecdsa.update(data);
byte[] baSignature = ecdsa.sign();
}
不幸的是,结果与证书中的签名不匹配,所以很明显我犯了一些错误。 签名算法与证书中使用的签名算法相同(SHA256withECDSA),因此我怀疑我没有选择tbsCertificate结构的正确部分。
我的证书大约有530个字节。我开始从偏移量4(跳过最初的SEQUENCE标记和长度字节)读取到扩展的末尾(在证书部分开始之前停止)。
任何人都可以判断这是否是我必须为" tbsCertificate"读取的正确字节数组。结构体? 或者我可能做出的其他错误,我现在还没有看到? 证书本身确定没问题,我使用以下Java代码仔细检查了证书和签名算法。
public static X509Certificate loadCertificate(String fileName)
{
InputStream in;
byte [] signature;
X509Certificate cert = null;
try
{
in = new FileInputStream(fileName);
CertificateFactory factory = CertificateFactory.getInstance("X.509");
cert = (X509Certificate) factory.generateCertificate(in);
signature = cert.getSignature();
System.out.println("Signature Algorithm: " + cert.getSigAlgName());
System.out.println(signature);
return cert;
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
catch (CertificateException e)
{
e.printStackTrace();
}
return cert;
}
答案 0 :(得分:0)
ECDSA没有产生稳定的签名,所以如果你的测试是你产生了相同的答案,那就不会起作用。您可以通过验证针对tbsCertificate数据提供的签名来验证证书上的签名。
您的方法适用于RSA签名,因为它是一种稳定的签名算法(使用PKCS1填充,而不是PSS)。
至于找到tbsCertificate:你似乎确实知道DER编码是什么,但我觉得有必要根据问题中的松散描述提供指导:
证书的二进制编码形式在DER中。第一个字节为0x30((构造)SEQUENCE)。下一个字节是序列的长度(< 0x80)或长度的长度(0x82 =>接下来的两个字节是big-endian长度)。下一个字节将再次为0x30,即tbsCertificate编码值的开始。然后,您可以读取该结构的长度,并计算tbsCertificate的正确结束偏移量。
证书结构可在RFC 3280中找到。 (RFC 5280中有更新,但我听说有人说'#34;没有被批准为标准"。)它也可用,以及ITU-T X.509中的属性证书 - 这是X.509证书中X.509的来源。我链接到2012版本,因为2016版本支持付费墙。