我需要在我的证书中添加OID 1.3.6.1.5.5.7.1.26的新扩展。我在我的证书中获得了这个OID扩展,但是有以下错误:
证书扩展:101: ObjectId: 1.3.6.1.5.5.7.1.26 Criticality=false 扩展未知: DER编码的八进制字符串= 0000: 04 0C 30 0A 13 08 33 39 20 64 63 20 32 62 ..0 39 dc 2b
我希望这个OID能够被识别,类似于其他扩展,如AuthorityInfoAccess,等。
我需要编辑 X509类的jar吗?
我使用ACME4j作为客户端,Letsencrypt作为我的服务器。
这里是注册证书的code代码。
public void sign(KeyPair keypair) throws IOException {
//Security.addProvider(new BouncyCastleProvider());
Objects.requireNonNull(keypair, "keypair");
if (namelist.isEmpty()) {
throw new IllegalStateException("No domain was set");
}
try {
GeneralName[] gns = new GeneralName[namelist.size()];
for (int ix = 0; ix < namelist.size(); ix++) {
gns[ix] = new GeneralName(GeneralName.dNSName,namelist.get(ix));
}
SignatureAlgorithmIdentifierFinder algFinder = new
DefaultSignatureAlgorithmIdentifierFinder();
GeneralNames subjectAltName = new GeneralNames(gns);
PKCS10CertificationRequestBuilder p10Builder = new JcaPKCS10CertificationRequestBuilder(namebuilder.build(), keypair.getPublic());
ExtensionsGenerator extensionsGenerator = new ExtensionsGenerator();
extensionsGenerator.addExtension(Extension.subjectAlternativeName, false, subjectAltName);
//extensionsGenerator.addExtension(Extension.authorityInfoAccess, true, subjectAltName);
//extensionsGenerator.addExtension(new ASN1ObjectIdentifier("TBD"), false, subjectAltName);
//extensionsGenerator.addExtension(new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.24"), false, subjectAltName);
extensionsGenerator.addExtension(new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.26").intern(), false, subjectAltName);
//extentionsGenerator.addExtension();
p10Builder.addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, extensionsGenerator.generate());
PrivateKey pk = keypair.getPrivate();
/*JcaContentSignerBuilder csBuilder = new JcaContentSignerBuilder(
pk instanceof ECKey ? EC_SIGNATURE_ALG : EC_SIGNATURE_ALG);
ContentSigner signer = csBuilder.build(pk);*/
if(pk instanceof ECKey)
{
AlgorithmIdentifier sigAlg = algFinder.find("SHA1withECDSA");
AlgorithmIdentifier digAlg = new DefaultDigestAlgorithmIdentifierFinder().
find(sigAlg);
ContentSigner signer = new JcaContentSignerBuilder("SHA256with"+pk.getAlgorithm()).setProvider(BOUNCY_CASTL E_PROVIDER).build(keypair.getPrivate());
csr=p10Builder.build(signer);
System.out.println("ZIPED CSR ECDSA: "+csr);
}
else
{
ContentSigner signer = new JcaContentSignerBuilder("SHA256with"+pk.getAlgorithm()).build(keypair.getPrivate ());
csr = p10Builder.build(signer);
System.out.println("ZIPED CSR RSA: "+csr);
}
//csr = p10Builder.build(signer);
} catch (Exception ex) {
ex.printStackTrace();;
}
}
发布于 2017-03-29 13:16:59
注意:对于这些代码,我在1.56上使用了bcprov- for 15。
关于您的代码的一些评论。首先,请注意ASN1结构:
TNAuthorizationList ::= SEQUENCE SIZE (1..MAX) OF TNEntry
TNEntry ::= CHOICE {
spc [0] ServiceProviderCodeList,
range [1] TelephoneNumberRange,
one E164Number
}
注意,TNEntry
是选择,TNAuthorizationList
是TNEntry
对象的序列。因此,你的类名应该改为TNEntry
。在下面的代码中,请记住我已经将类名更改为TNEntry
。
我在这门课上也改变了一些东西。在getInstance(Object obj)
方法中,spc和range字段的类型不正确(根据ASN1定义,它们都是序列):
switch (tag) {
case spc:
case range: // both are sequences
return new TNEntry(tag, ASN1Sequence.getInstance(tagObj, false));
// not sure about "one" field, as it's not tagged
}
我只是不知道如何处理one字段,因为它没有标记。也许它应该是一个DERIA5String
,或者有另一种类型的“无标记”选择。
在同一个类中(请记住,我已经将它的名称更改为TNEntry
),我还删除了构造函数public TNEntry(int tag, String name)
,因为我不确定它是否适用(至少我不需要使用它,但如果需要,可以保留它),并且我已经更改了toString
方法以返回一个更易读的字符串:
public String toString() {
String sep = System.getProperty("line.separator");
StringBuffer buf = new StringBuffer();
buf.append(this.getClass().getSimpleName());
buf.append(" [").append(tag);
buf.append("]: ");
switch (tag) {
case spc:
buf.append("ServiceProviderCodeList: ").append(sep);
ASN1Sequence seq = (ASN1Sequence) this.obj;
int size = seq.size();
for (int i = 0; i < size; i++) {
// all elements are DERIA5Strings
DERIA5String str = (DERIA5String) seq.getObjectAt(i);
buf.append(" ");
buf.append(str.getString());
buf.append(sep);
}
break;
case range:
buf.append("TelephoneNumberRange: ").append(sep);
// there are always 2 elements in TelephoneNumberRange
ASN1Sequence s = (ASN1Sequence) this.obj;
DERIA5String str = (DERIA5String) s.getObjectAt(0);
buf.append(" start: ");
buf.append(str.getString());
buf.append(sep);
ASN1Integer count = (ASN1Integer) s.getObjectAt(1);
buf.append(" count: ");
buf.append(count.toString());
buf.append(sep);
break;
default:
buf.append(obj.toString());
}
return buf.toString();
}
我还创建了一个TNAuthorizationList
类,它保存了sequence of TNEntry
对象(请记住,我已经将您的类名更改为TNEntry
,所以这个TNAuthorizationList
类是不同的)。请注意,我还创建了一个常量来保存OID (只是为了使事情变得简单一些):
public class TNAuthorizationList extends ASN1Object {
// put OID in a constant, so I don't have to remember it all the time
public static final ASN1ObjectIdentifier TN_AUTH_LIST_OID = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.1.26");
private TNEntry[] entries;
public TNAuthorizationList(TNEntry[] entries) {
this.entries = entries;
}
public static TNAuthorizationList getInstance(Object obj) {
if (obj instanceof TNAuthorizationList) {
return (TNAuthorizationList) obj;
}
if (obj != null) {
return new TNAuthorizationList(ASN1Sequence.getInstance(obj));
}
return null;
}
public static TNAuthorizationList getInstance(ASN1TaggedObject obj, boolean explicit) {
return getInstance(ASN1Sequence.getInstance(obj, explicit));
}
private TNAuthorizationList(ASN1Sequence seq) {
this.entries = new TNEntry[seq.size()];
for (int i = 0; i != seq.size(); i++) {
entries[i] = TNEntry.getInstance(seq.getObjectAt(i));
}
}
public TNEntry[] getEntries() {
TNEntry[] tmp = new TNEntry[entries.length];
System.arraycopy(entries, 0, tmp, 0, entries.length);
return tmp;
}
@Override
public ASN1Primitive toASN1Primitive() {
return new DERSequence(entries);
}
public String toString() {
String sep = System.getProperty("line.separator");
StringBuffer buf = new StringBuffer();
buf.append(this.getClass().getSimpleName());
buf.append(":").append(sep);
for (TNEntry tnEntry : entries) {
buf.append(" ");
buf.append(tnEntry.toString());
buf.append(sep);
}
return buf.toString();
}
}
现在,为了将这个扩展添加到证书中,我已经完成了以下代码(使用一些示例数据,因为我不知道在实际情况下每个字段应该是什么):
X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(etc...);
// create TNEntries for TNAuthorizationList
TNEntry[] entries = new TNEntry[2];
// create a "spc" entry
DERIA5String[] cList = new DERIA5String[] { new DERIA5String("spc1"), new DERIA5String("spc2") };
DERSequence spc = new DERSequence(cList);
entries[0] = TNEntry.getInstance(new DERTaggedObject(false, TNEntry.spc, spc));
// create a "range" entry
DERSequence range = new DERSequence(new ASN1Encodable[] { new DERIA5String("123456"), new ASN1Integer(1) });
entries[1] = TNEntry.getInstance(new DERTaggedObject(false, TNEntry.range, range));
TNAuthorizationList tnAuthList = new TNAuthorizationList(entries);
builder.addExtension(TNAuthorizationList.TN_AUTH_LIST_OID, false, tnAuthList);
一旦您拥有了证书对象(在我的示例中是一个X509Certificate
),您可以这样做:
// cert is a X509Certificate instance
ASN1Primitive value = X509ExtensionUtil.fromExtensionValue(cert.getExtensionValue(TNAuthorizationList.TN_AUTH_LIST_OID.getId()));
TNAuthorizationList authList = TNAuthorizationList.getInstance(value);
System.out.println(authList.toString());
产出如下:
TNAuthorizationList:
TNEntry [0]: ServiceProviderCodeList:
spc1
spc2
TNEntry [1]: TelephoneNumberRange:
start: 123456
count: 1
备注:
TNEntry
,因为它没有标记(我不知道它是否必须是DERIA5String
,或者是否有另一种类型的对象用于“未标记”字段)。ServiceProviderCodeList
可以有1到3个元素,所以您可以验证它的大小。TelephoneNumberRange
:start字段有一个特定的格式(我认为它意味着只有这些字符被接受),所以您也可以验证它ServiceProviderCodeList
和TelephoneNumberRange
创建值,我手工创建了DERSequence
对象,但如果需要,可以为它们创建自定义类:ServiceProviderCodeList
可以在其构造函数中保存一个DERIA5String
列表并执行正确的验证(大小从1到3),TelephoneNumberRange
可以有start和countE 271
字段(适当验证E 172
startE 273
值)-以及toASN1Primitive
只需要以正确的顺序返回其字段的DERSequence
。
对于您的解析问题,我检查了acme4j代码,它使用了一个java.security.cert.X509Certificate
类。这个类的toString()
方法(当使用Sun的默认提供程序时)生成这个“扩展未知”输出(根据相应的代码)。
因此,为了正确解析它(显示上面描述的格式化输出),您可能需要更改acme4j的代码(或者编写自己的代码),创建一个新的toString()
方法,并在这个方法中包含新的TNAuthorizationList
类。
当您提供显示如何使用acme4j的代码时,如果需要,我将相应地更新这个答案。
发布于 2017-03-28 12:58:29
由于OID 1.3.6.1.5.5.7.1.26仍然是一个草案,我相信像这样的工具和系统--让我们加密--承认这个扩展是不太可能的(在这个扩展成为正式之后,他们很可能会这么做,而且我真的不知道这种批准背后的官僚程序)。
这意味着你可能要对它进行编码。几年来,我一直在使用B儿GURE,但从未创建过新的ASN1结构。但是如果有必要的话,我会把它的源代码作为最初的指导。
考虑到这个扩展的ASN1结构:
TNAuthorizationList ::= SEQUENCE SIZE (1..MAX) OF TNEntry
TNEntry ::= CHOICE {
spc [0] ServiceProviderCodeList,
range [1] TelephoneNumberRange,
one E164Number
}
ServiceProviderCodeList ::= SEQUENCE SIZE (1..3) OF IA5String
-- Service Provider Codes may be OCNs, various SPIDs, or other
-- SP identifiers from the telephone network
TelephoneNumberRange ::= SEQUENCE {
start E164Number,
count INTEGER
}
E164Number ::= IA5String (SIZE (1..15)) (FROM ("0123456789#*"))
扩展值必须是SEQUENCE
of TNEntry
。因此,您可以使用ASN1Sequence
(或它的子类DERSequence
),并将TNEntry
实例放入其中。
要创建TNEntry
,您需要实现ASN1Choice
(查看GeneralName
类的源代码并执行类似的操作)。
依此类推,直到将整个结构映射到它们各自的类,使用Bouncy 内置类来支持您(有DERIA5String
for IA5String
和DERInteger
for INTEGER
,可以在ServiceProviderCodeList
和TelephoneNumberRange
中使用)。
之后,您可以构建自己的解析器,它可以识别这个扩展。但就像我说的,别指望其他工具能认出它来。
发布于 2017-03-29 03:59:08
现在,为了测试目的,我只是从我的CA Boulder传递一个字符串值。因此,要阅读它,这是用于ASN1的自定义TNAUthList对象STructure。
public class TNAuthorizationList extends ASN1Object implements ASN1Choice{
public static final int spc = 0;
public static final int range = 1;
private ASN1Encodable obj;
private int tag;
public TNAuthorizationList(
int tag,
ASN1Encodable name)
{
this.obj = name;
this.tag = tag;
}
public TNAuthorizationList(
int tag,
String name)
{
this.tag = tag;
if (tag == spc)
{
this.obj = new DERIA5String(name);
}
else if (tag == range)
{
this.obj = new ASN1ObjectIdentifier(name);
}
else
{
throw new IllegalArgumentException("can't process String for tag: " + tag);
}
}
public static TNAuthorizationList getInstance(
Object obj)
{
if (obj == null || obj instanceof TNAuthorizationList)
{
return (TNAuthorizationList)obj;
}
if (obj instanceof ASN1TaggedObject)
{
ASN1TaggedObject tagObj = (ASN1TaggedObject)obj;
int tag = tagObj.getTagNo();
switch (tag)
{
case spc:
return new TNAuthorizationList(tag, DERIA5String.getInstance(tagObj, false));
}
}
if (obj instanceof byte[])
{
try
{
return getInstance(ASN1Primitive.fromByteArray((byte[])obj));
}
catch (IOException e)
{
throw new IllegalArgumentException("unable to parse encoded general name");
}
}
throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
}
public static TNAuthorizationList getInstance(
ASN1TaggedObject tagObj,
boolean explicit)
{
return TNAuthorizationList.getInstance(ASN1TaggedObject.getInstance(tagObj, true));
}
public int getTagNo()
{
return tag;
}
public ASN1Encodable getSpc()
{
return obj;
}
public String toString()
{
StringBuffer buf = new StringBuffer();
buf.append(tag);
buf.append(": ");
switch (tag)
{
case spc:
buf.append(DERIA5String.getInstance(obj).getString());
break;
default:
buf.append(obj.toString());
}
return buf.toString();
}
/**
*TNEntry ::= CHOICE {
* spc [0] ServiceProviderCodeList,
* range [1] TelephoneNumberRange,
* one E164Number
* }
*/
@Override
public ASN1Primitive toASN1Primitive() {
// TODO Auto-generated method stub
return new DERTaggedObject(false, tag, obj);
}
}
正如您所建议的,我已经将OID值传递给X509Util类并打印输出。
ASN1Object o = X509ExtensionUtil.fromExtensionValue(cert.getExtensionValue("1.3.6.1.5.5.7.1.26"));
System.out.println("ASN1 Object: "+o);
System.out.println("get Class "+o.getClass());
而O/P是
ASN1 Object: [SPID : 39 dc 2b]
get Class class org.bouncycastle.asn1.DLSequence
这样行吗。如何用我的自定义ASN1结构来解析它呢?
https://stackoverflow.com/questions/43045079
复制相似问题