我使用acme client acme4j创建了一个SSL证书:https://github.com/shred/acme4j。
但是在我生成自签名证书时,我在解析它时遇到异常。这是我生成的证书:
{Version: V3
Subject: T=spid: yuz8xxz
Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11
Key: Sun RSA public key, 2048 bits
modulus:
public exponent: 65537
Validity: [From: Mon Apr 10 17:56:36 IST 2017,
To: Mon Apr 17 17:56:36 IST 2017]
Issuer: T=spid: yuz8xxz
SerialNumber: [ 015b57d4 807c]
Certificate Extensions: 1
[1]: ObjectId: 1.3.6.1.5.5.7.1.26 Criticality=false
**Extension unknown: DER encoded OCTET string =**
0000: 04 23 30 21 A0 12 16 07 79 75 7A 38 78 78 7A 16 .#0!....yuz8xxz.
0010: 07 79 75 7A 38 78 78 7A A1 0B 16 06 31 32 33 34 .yuz8xxz....1234
0020: 35 36 02 01 01 56...
]
Algorithm: [SHA256withRSA]
Signature:
]
}
答案 0 :(得分:2)
1.3.6.1.5.5.7.1.26
似乎是电话号码(TN)授权列表的OID,它仅在草稿文档(https://datatracker.ietf.org/doc/draft-ietf-stir-certificates/)中定义; BouncyCastle可能没有漂亮的打印机,所以它会显示原始编码的有效载荷。
虽然我不是电话专家,但我很确定(' yuz8xxz',' yuz8xxz')不是有效的服务提供商代码列表,以及' 123456' - ' 123456'不是有效的电话号码范围。因此,使用此证书扩展程序,您正在寻找的内容还不清楚,如果让我们加密签名,我会非常惊讶。
答案 1 :(得分:2)
Acme4j代码使用java.security.cert.X509Certificate
类。此类的toString()
方法(使用 Sun的默认提供程序时)会生成此“扩展名未知”输出(根据corresponding code)。
因此,为了正确解析它(获取格式化输出),您可能必须更改acme4j的代码(或编写自己的代码),包括解析此扩展的代码。
在我的测试中( Java 7 和 BouncyCastle 1.56 ),我创建了一个X509Certificate
的包装器,并基于BouncyCastle创建了一个format
方法代码(我复制了大部分内容,只添加了TNAuthorizationList
扩展名的代码)。下面的代码不是最佳的(不良的异常处理和一些不赞成的类),但你可以得到一个想法。
import org.bouncycastle.asn1.*;
import org.bouncycastle.asn1.misc.*;
import org.bouncycastle.asn1.util.ASN1Dump;
import org.bouncycastle.asn1.x509.*;
import org.bouncycastle.util.encoders.Hex;
public class CertificateWrapper {
private X509Certificate cert;
public CertificateWrapper(X509Certificate cert) {
this.cert = cert;
}
public String format() throws Exception {
StringBuffer buf = new StringBuffer();
String nl = System.getProperty("line.separator");
buf.append(" [0] Version: ").append(this.cert.getVersion()).append(nl);
buf.append(" SerialNumber: ").append(this.cert.getSerialNumber()).append(nl);
buf.append(" IssuerDN: ").append(this.cert.getIssuerDN().toString()).append(nl);
buf.append(" Start Date: ").append(this.cert.getNotBefore()).append(nl);
buf.append(" Final Date: ").append(this.cert.getNotAfter()).append(nl);
buf.append(" SubjectDN: ").append(this.cert.getSubjectDN().toString()).append(nl);
buf.append(" Public Key: ").append(this.cert.getPublicKey()).append(nl);
buf.append(" Signature Algorithm: ").append(this.cert.getSigAlgName()).append(nl);
byte[] sig = this.cert.getSignature();
buf.append(" Signature: ").append(new String(Hex.encode(sig, 0, 20))).append(nl);
for (int i = 20; i < sig.length; i += 20) {
if (i < sig.length - 20) {
buf.append(" ").append(new String(Hex.encode(sig, i, 20))).append(nl);
} else {
buf.append(" ").append(new String(Hex.encode(sig, i, sig.length - i))).append(nl);
}
}
TBSCertificateStructure tbs = TBSCertificateStructure.getInstance(ASN1Sequence.fromByteArray(cert.getTBSCertificate()));
X509Extensions extensions = tbs.getExtensions();
if (extensions != null) {
Enumeration e = extensions.oids();
if (e.hasMoreElements()) {
buf.append(" Extensions: \n");
}
while (e.hasMoreElements()) {
ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement();
X509Extension ext = extensions.getExtension(oid);
if (ext.getValue() != null) {
byte[] octs = ext.getValue().getOctets();
ASN1InputStream dIn = new ASN1InputStream(octs);
buf.append(" critical(").append(ext.isCritical()).append(") ");
try {
if (oid.equals(Extension.basicConstraints)) {
buf.append(BasicConstraints.getInstance((ASN1Sequence) dIn.readObject())).append(nl);
} else if (oid.equals(Extension.keyUsage)) {
buf.append(KeyUsage.getInstance((DERBitString) dIn.readObject())).append(nl);
} else if (oid.equals(MiscObjectIdentifiers.netscapeCertType)) {
buf.append(new NetscapeCertType((DERBitString) dIn.readObject())).append(nl);
} else if (oid.equals(MiscObjectIdentifiers.netscapeRevocationURL)) {
buf.append(new NetscapeRevocationURL((DERIA5String) dIn.readObject())).append(nl);
} else if (oid.equals(MiscObjectIdentifiers.verisignCzagExtension)) {
buf.append(new VerisignCzagExtension((DERIA5String) dIn.readObject())).append(nl);
//*********************************************************
// *** HERE: code to handle TNAuthorizationList ***
//*********************************************************
} else if (oid.equals(TNAuthorizationList.TN_AUTH_LIST_OID)) {
buf.append(TNAuthorizationList.getInstance((ASN1Sequence) dIn.readObject())).append(nl);
} else {
buf.append(oid.getId());
buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl);
}
} catch (Exception ex) {
buf.append(oid.getId());
buf.append(" value = ").append("*****").append(nl);
}
} else {
buf.append(nl);
}
}
}
return buf.toString();
}
}
然后,您只需使用此包装而不是X509Certificate
:
X509Certificate cert = ...
System.out.println("Certificate " + new CertificateWrapper(cert).format());
输出格式与SUN的默认提供程序不同,但您可以自定义它以获得所需内容。
PS :此问题是this one的补充(或“续集”)。 OP的代码已提供here,TNAuthorizationList
类位于accepted answer。但由于这个问题是一个不同的问题(相关但不同),因此它被视为一个单独的问题。