在 Java 中签署 X.509 证书
Signing a X.509 certificate in Java
我想了解如何签署 x.509 证书。
我已经设置了 OpenSSL CA 来创建演示证书。证书很好,我可以使用名为 dumpasn1 的工具查看所有相关元素。
从理论上讲,我知道我必须签署名为 "tbsCertificate" 的结构,该结构包含属性版本、序列号签名、发行者、有效性、主题、subjectPublicKeyInfo 和扩展。
然而,当我尝试在 Java 中模仿它时,不幸的是它不起作用。
我做的是:
- 我阅读了 DER 编码证书的 "tbsCertificate" 部分
- 然后我从发证 CA 那里得到私钥
- 最后我尝试使用以下代码签署 tbsCertificate 结构:
.
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(跳过初始序列标记和长度字节)开始读取到扩展的末尾(在证书部分开始之前停止)。
谁能告诉我这是否是我必须为 "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;
}
ECDSA 不会产生稳定的签名,所以如果您的测试是您产生了相同的答案,那是行不通的。您可以通过验证针对 tbsCertificate 数据提供的签名来验证证书上的签名。
您的方法适用于 RSA 签名,因为这是一种稳定的签名算法(使用 PKCS1 填充,而不是 PSS)。
关于查找 tbsCertificate:您似乎确实知道 DER 编码是什么,但我觉得有必要根据问题中的松散描述提供指导:
证书的二进制编码形式是 DER。第一个字节将是 0x30((构造的)SEQUENCE)。下一个字节是序列的长度(< 0x80)或长度的长度(0x82 => 接下来的两个字节是大端长度)。下一个字节将再次为 0x30,即 tbsCertificate 编码值的开始。然后您可以读取该结构的长度,并计算 tbsCertificate 的正确结束偏移量。
可以在 RFC 3280. (There's an update in RFC 5280 but I've heard people say "that didn't get approved as a standard".) It's also available, along with attribute certificates, in ITU-T X.509 中找到证书结构 -- 这是 X.509 证书中的 X.509 的来源。我链接到 2012 版是因为 2016 版是付费专区。
我想了解如何签署 x.509 证书。
我已经设置了 OpenSSL CA 来创建演示证书。证书很好,我可以使用名为 dumpasn1 的工具查看所有相关元素。 从理论上讲,我知道我必须签署名为 "tbsCertificate" 的结构,该结构包含属性版本、序列号签名、发行者、有效性、主题、subjectPublicKeyInfo 和扩展。
然而,当我尝试在 Java 中模仿它时,不幸的是它不起作用。 我做的是:
- 我阅读了 DER 编码证书的 "tbsCertificate" 部分
- 然后我从发证 CA 那里得到私钥
- 最后我尝试使用以下代码签署 tbsCertificate 结构:
.
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(跳过初始序列标记和长度字节)开始读取到扩展的末尾(在证书部分开始之前停止)。
谁能告诉我这是否是我必须为 "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;
}
ECDSA 不会产生稳定的签名,所以如果您的测试是您产生了相同的答案,那是行不通的。您可以通过验证针对 tbsCertificate 数据提供的签名来验证证书上的签名。
您的方法适用于 RSA 签名,因为这是一种稳定的签名算法(使用 PKCS1 填充,而不是 PSS)。
关于查找 tbsCertificate:您似乎确实知道 DER 编码是什么,但我觉得有必要根据问题中的松散描述提供指导:
证书的二进制编码形式是 DER。第一个字节将是 0x30((构造的)SEQUENCE)。下一个字节是序列的长度(< 0x80)或长度的长度(0x82 => 接下来的两个字节是大端长度)。下一个字节将再次为 0x30,即 tbsCertificate 编码值的开始。然后您可以读取该结构的长度,并计算 tbsCertificate 的正确结束偏移量。
可以在 RFC 3280. (There's an update in RFC 5280 but I've heard people say "that didn't get approved as a standard".) It's also available, along with attribute certificates, in ITU-T X.509 中找到证书结构 -- 这是 X.509 证书中的 X.509 的来源。我链接到 2012 版是因为 2016 版是付费专区。