1、概要
在案例之前,我们需要了解一下啥是ASN1?ASN.1抽象语法标记是一种 ISO/ITU-T 标准,描述了一种对数据进行表示、编码、传输和解码的数据格式。它提供了一整套正规的格式用于描述对象的结构,而不管语言上如何执行及这些数据的具体指代,也不用去管到底是什么样的应用程序。也就是说不管C语言、Java、Python都是能够将ASN1编码结构进行相互转化。其次简单说一下bc这个库是啥?BC全名是BouncyCastle,他是一个第三方密码算法相关得库,包括国密算法SM2,对称,非对称等等。
2、案例
下面主要是通过BC库,通过一些GM/T国密标准文档去实现ASN1结构封装得案例,来帮助大家封装ASN1结构代码。首先ASN1结构类型主要有三大类型。我会对分别三种使用java进行封装
-
SEQUENCE // 基本序列结构
- ENUMERATED // 枚举结构
- CHIOCE // 选择结构
-
出除了基本结构还有常用得类型也需要大家了解一下:Extensions、ASN1OctetString、ASN1Integer、ASN1GeneralizedTime、ASN1BitString规律就是一般都是根据下面得结构属性名称加一个ASN1就是这个类型(但是实际中也是需要自己去试)。
public class AppUserInfo extends ASN1Object {
private ASN1Integer userCertNo;
private SubjectPublicKeyInfo userPubKey;
private ASN1GeneralizedTime notBefore;
private ASN1GeneralizedTime notAfter;
private ASN1OctetString userName;
private ASN1IA5String dsCode;
private ASN1IA5String extendInfo;
private static final int TAG_USER_NAME = 0;
private static final int TAG_DS_CODE = 1;
private static final int TAG_EXTEND_INFO = 2;
public static AppUserInfo getInstance(ASN1TaggedObject obj, boolean explicit)
{
return getInstance(ASN1Sequence.getInstance(obj, explicit));
}
public static AppUserInfo getInstance(Object obj) {
if (obj instanceof AppUserInfo) {
return (AppUserInfo) obj;
} else {
return obj != null ? new AppUserInfo(ASN1Sequence.getInstance(obj)) : null;
}
}
public AppUserInfo(ASN1Sequence sequence) {
if (sequence.size() == 7) {
this.userCertNo = ASN1Integer.getInstance(sequence.getObjectAt(0));
this.userPubKey = SubjectPublicKeyInfo.getInstance(sequence.getObjectAt(1));
this.notBefore = ASN1GeneralizedTime.getInstance(sequence.getObjectAt(2));
this.notAfter = ASN1GeneralizedTime.getInstance(sequence.getObjectAt(3));
this.userName = ASN1OctetString.getInstance(sequence.getObjectAt(4));
this.dsCode = ASN1IA5String.getInstance(sequence.getObjectAt(5));
this.extendInfo = ASN1IA5String.getInstance(sequence.getObjectAt(6));
} else {
throw new IllegalArgumentException("Bad sequence size: " + sequence.size());
}
}
@Override
public ASN1Primitive toASN1Primitive() {
ASN1EncodableVector vec = new ASN1EncodableVector(7);
vec.add(this.userCertNo);
vec.add(this.userPubKey);
vec.add(this.notBefore);
vec.add(this.notAfter);
vec.add(this.userName);
vec.add(this.dsCode);
vec.add(this.extendInfo);
return new DERSequence(vec);
}
}
import java.math.BigInteger;
import org.bouncycastle.asn1.ASN1Enumerated;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1Primitive;
/**
* OCSP RFC 2560, RFC 6960
* <p>
* The OCSPResponseStatus enumeration.
* <pre>
* OCSPResponseStatus ::= ENUMERATED {
* successful (0), --Response has valid confirmations
* malformedRequest (1), --Illegal confirmation request
* internalError (2), --Internal error in issuer
* tryLater (3), --Try again later
* --(4) is not used
* sigRequired (5), --Must sign the request
* unauthorized (6) --Request unauthorized
* }
* </pre>
*/
public class OCSPResponseStatus
extends ASN1Object
{
public static final int SUCCESSFUL = 0;
public static final int MALFORMED_REQUEST = 1;
public static final int INTERNAL_ERROR = 2;
public static final int TRY_LATER = 3;
public static final int SIG_REQUIRED = 5;
public static final int UNAUTHORIZED = 6;
private ASN1Enumerated value;
/**
* RFC 2560, RFC 6960
* <p>
* The OCSPResponseStatus enumeration.
* <pre>
* OCSPResponseStatus ::= ENUMERATED {
* successful (0), --Response has valid confirmations
* malformedRequest (1), --Illegal confirmation request
* internalError (2), --Internal error in issuer
* tryLater (3), --Try again later
* --(4) is not used
* sigRequired (5), --Must sign the request
* unauthorized (6) --Request unauthorized
* }
* </pre>
*/
public OCSPResponseStatus(
int value)
{
this(new ASN1Enumerated(value));
}
private OCSPResponseStatus(
ASN1Enumerated value)
{
this.value = value;
}
public static OCSPResponseStatus getInstance(
Object obj)
{
if (obj instanceof OCSPResponseStatus)
{
return (OCSPResponseStatus)obj;
}
else if (obj != null)
{
return new OCSPResponseStatus(ASN1Enumerated.getInstance(obj));
}
return null;
}
public int getIntValue()
{
return value.intValueExact();
}
public BigInteger getValue()
{
return value.getValue();
}
public ASN1Primitive toASN1Primitive()
{
return value;
}
}
import org.bouncycastle.asn1.ASN1Choice;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1Null;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.ASN1Util;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DERTaggedObject;
public class CertStatus
extends ASN1Object
implements ASN1Choice
{
private int tagNo;
private ASN1Encodable value;
/**
* create a CertStatus object with a tag of zero.
*/
public CertStatus()
{
tagNo = 0;
value = DERNull.INSTANCE;
}
public CertStatus(
RevokedInfo info)
{
tagNo = 1;
value = info;
}
public CertStatus(
int tagNo,
ASN1Encodable value)
{
this.tagNo = tagNo;
this.value = value;
}
private CertStatus(
ASN1TaggedObject choice)
{
int tagNo = choice.getTagNo();
switch (tagNo)
{
case 0:
value = ASN1Null.getInstance(choice, false);
break;
case 1:
value = RevokedInfo.getInstance(choice, false);
break;
case 2:
// UnknownInfo ::= NULL
value = ASN1Null.getInstance(choice, false);
break;
default:
throw new IllegalArgumentException("Unknown tag encountered: " + ASN1Util.getTagText(choice));
}
this.tagNo = tagNo;
}
public static CertStatus getInstance(
Object obj)
{
if (obj == null || obj instanceof CertStatus)
{
return (CertStatus)obj;
}
else if (obj instanceof ASN1TaggedObject)
{
return new CertStatus((ASN1TaggedObject)obj);
}
throw new IllegalArgumentException("unknown object in factory: " + obj.getClass().getName());
}
public static CertStatus getInstance(
ASN1TaggedObject obj,
boolean explicit)
{
return getInstance(obj.getObject()); // must be explicitly tagged
}
public int getTagNo()
{
return tagNo;
}
public ASN1Encodable getStatus()
{
return value;
}
/**
* Produce an object suitable for an ASN1OutputStream.
* <pre>
* CertStatus ::= CHOICE {
* good [0] IMPLICIT NULL,
* revoked [1] IMPLICIT RevokedInfo,
* unknown [2] IMPLICIT UnknownInfo }
* </pre>
*/
public ASN1Primitive toASN1Primitive()
{
return new DERTaggedObject(false, tagNo, value);
}
}