实现了ASN.1语法,对数字证书进行解析,并对RSA WITH SHA256的证书进行验签。使用.net core c#编写。
ASN.1语法解析代码
using System;
using System.Collections.Generic;
using System.Numerics;
using System.Globalization;
namespace ASN1
{
enum TLVType {
Boolean = 0x1,
Integer = 0x2,
BitString = 0x3,
OctetString = 0x4,
Null = 0x5,
Object = 0x6,
PrintableString = 0x13,
UTCTime = 0x17,
Sequence = 0x30,
Set = 0x31,
Version = 0xA0,
Extensions = 0xA3
}
class Bytes
{
public static byte[] SubBytes(byte[] bytes, int start)
{
byte[] t = new byte[bytes.Length - start];
Array.Copy(bytes, start, t, 0, t.Length);
return t;
}
public static byte[] SubBytes(byte[] bytes, int start, int len)
{
byte[] t = new byte[len];
Array.Copy(bytes, start, t, 0, t.Length);
return t;
}
public static byte[] Concat(byte[] b1, byte[] b2)
{
byte[] t = new byte[b1.Length + b2.Length];
Array.Copy(b1, t, b1.Length);
Array.Copy(b2, 0, t, b1.Length, b2.Length);
return t;
}
}
abstract class TLV
{
protected byte _tag;
protected byte[] _length = null;
protected byte[] _data = null;
protected byte[] _ori = null;
protected TLV(byte[] buf)
{
_tag = buf[0];
int lengthSize = getTLVLengthSize(Bytes.SubBytes(buf, 1));
_length = Bytes.SubBytes(buf, 1, lengthSize);
int dataSize = getTLVDataSize(_length);
_data = Bytes.SubBytes(buf, 1 + lengthSize, dataSize);
_ori = Bytes.SubBytes(buf, 0, 1 + lengthSize + _data.Length);
}
public byte Tag { get { return _tag; } }
public byte[] Data { get { return _data; } }
public int LenthSize { get { return _length.Length; } }
public int DataSize { get { return _data.Length; } }
public int Size { get { return 1 + _length.Length + _data.Length; } }
public byte[] Original { get { return _ori; } }
int getTLVDataSize(byte[] buf)
{
int len = 0;
if (buf[0] < 0x80)
{
len = buf[0];
}
else if (buf[0] > 0x80)
{
int i = buf[0] - 0x80;
if (i > 0) len = buf[1];
if (i > 1) len = len << 8 | buf[2];
if (i > 2) len = len << 8 | buf[3];
if (i > 3) len = len << 8 | buf[4];
}
else if (buf[0] == 0x80)
{
int i = 0;
while (buf[i + 2] != 0 && buf[i + 3] != 0)
{
i++;
}
if (i > 0) len = buf[1];
if (i > 1) len = len << 8 | buf[2];
if (i > 2) len = len << 8 | buf[3];
if (i > 3) len = len << 8 | buf[4];
}
return len;
}
int getTLVLengthSize(byte[] buf)
{
if (buf[0] < 0x80)
return 1;
else if (buf[0] > 0x80)
return 1 + buf[0] - 0x80;
else if (buf[0] == 0x80)
{
}
throw new NotSupportedException();
}
int getTLVSize(TLV tlv)
{
return 1 + getTLVLengthSize(_length) + getTLVDataSize(_length);
}
}
class BooleanTLV : TLV
{
private bool b;
public BooleanTLV(byte[] buf) : base(buf)
{
b = Data[0] != 0;
}
public bool Value { get { return b; } }
}
class ObjectTLV : TLV
{
private uint[] identifer;
public ObjectTLV(byte[] buf) : base(buf)
{
byte[] data = Data;
List<uint> r = new List<uint>();
r.Add((uint)data[0] / 40);
r.Add((uint)data[0] % 40);
int i = 1;
uint m = 0;
while (i < data.Length)
{
m = (uint)((uint)(m << 7) | (uint)(data[i] & 0x7f));
if ((data[i] & 0x80) == 0)
{
r.Add(m);
m = 0;
}
i++;
}
identifer = r.ToArray();
}
public uint[] Identifer { get { return identifer; } }
}
class PrintableStringTLV : TLV
{
string s = "";
public PrintableStringTLV(byte[] buf) : base(buf)
{
for (int i=0; i<Data.Length; i++)
{
s += (char)Data[i];
}
}
public string GetPrintableString()
{
return s;
}
}
class OctetStringTLV : TLV
{
public OctetStringTLV(byte[] buf) : base(buf)
{
}
public byte[] Bytes { get { return Data; } }
}
class IntegerTLV : TLV
{
private BigInteger _intValue;
public IntegerTLV(byte[] buf) : base(buf)
{
// byte[] t = new byte[Data.Length];
// Array.Copy(Data, t, Data.Length);
// Array.Reverse(t);
_intValue = new BigInteger(Data, true, true);
}
public BigInteger IntValue { get { return _intValue; } }
public byte[] ByteValue { get { return _intValue.ToByteArray(); } }
}
class NullTLV : TLV
{
public NullTLV(byte[] buf) : base(buf)
{
}
}
class UTCTimeTLV : TLV
{
private DateTime date;
public UTCTimeTLV(byte[] buf) : base(buf)
{
string s = "";
for (int i=0; i<Data.Length; i++)
{
s += (char) (Data[i]);
}
date = DateTime.ParseExact(s, "yyMMddHHmmssZ", null, DateTimeStyles.AdjustToUniversal);
}
public DateTime Date { get { return date; } }
}
class BitStringTLV : TLV
{
public BitStringTLV(byte[] buf) : base(buf)
{
}
public byte[] ValidData() {
byte fill = Data[0];
if (fill != 0)
{
throw new NotImplementedException();
}
return Bytes.SubBytes(Data, 1);
}
}
class ExtensionsTLV : TLV
{
private SequenceTLV seq;
public ExtensionsTLV(byte[] buf) : base(buf)
{
seq = new SequenceTLV(Data);
}
public SequenceTLV Sequence { get { return seq; } }
}
class SequenceTLV : TLV
{
protected TLV[] children;
public SequenceTLV(byte[] buf) : base(buf)
{
List<TLV> tlvs = new List<TLV>();
int i = 0;
while (i < Data.Length)
{
byte[] bs = Bytes.SubBytes(Data, i);
TLV tlv = null;
if ((byte)TLVType.Boolean == Data[i])
{
tlv = new BooleanTLV(bs);
}
else if ((byte)TLVType.Integer == Data[i])
{
tlv = new IntegerTLV(bs);
}
else if ((byte) TLVType.OctetString == Data[i])
{
tlv = new OctetStringTLV(bs);
}
else if ((byte) TLVType.PrintableString == Data[i])
{
tlv = new PrintableStringTLV(bs);
}
else if ((byte) TLVType.Version == Data[i])
{
tlv = new VersionTLV(bs);
}
else if ((byte)TLVType.Sequence == Data[i])
{
tlv = new SequenceTLV(bs);
}
else if ((byte)TLVType.Object == Data[i])
{
tlv = new ObjectTLV(bs);
}
else if ((byte)TLVType.Null == Data[i])
{
tlv = new NullTLV(bs);
}
else if ((byte)TLVType.Set == Data[i])
{
tlv = new SetTLV(bs);
}
else if ((byte)TLVType.UTCTime == Data[i])
{
tlv = new UTCTimeTLV(bs);
}
else if ((byte)TLVType.BitString == Data[i])
{
tlv = new BitStringTLV(bs);
}
else if ((byte)TLVType.Extensions == Data[i])
{
tlv = new ExtensionsTLV(bs);
}
else
{
throw new NotSupportedException();
}
if (tlv != null)
tlvs.Add(tlv);
i += tlv.Size;
}
children = tlvs.ToArray();
}
public TLV[] Children { get { return children; } }
}
class SetTLV : SequenceTLV
{
public SetTLV(byte[] buf) : base(buf)
{
}
}
class VersionTLV : TLV
{
private IntegerTLV ver;
public VersionTLV(byte[] buf) : base(buf)
{
ver = new IntegerTLV(Data);
}
public string Version { get { return ver.IntValue.ToString(); } }
}
}
对证书字段进行显示:
数字证书验签代码:
private byte[] RSADecrypt(BigInteger? PublicKey)
{
if (PublicKey == null) // 如果是自签名证书,不需要传入上级公钥,传入null
{
PublicKey = _tbsCertificate.SubjectPublicKeyInfo.Modules; // 取自己的公钥
}
BigInteger exponent = _tbsCertificate.SubjectPublicKeyInfo.Exponent;
BigInteger msg = new BigInteger(_signatureValue.ValidData(), true, true);
BigInteger value = BigInteger.ModPow(msg, exponent, PublicKey.Value);
// return value.ToByteArray(false, true); ?? why miss 0
// fix code For ==> BigInteger.ToByteArray(false, true)
byte[] t = new byte[value.GetByteCount() + 1];
Array.Copy(value.ToByteArray(false, true), 0, t, 1, t.Length - 1);
return t;
}
private byte[] RSA_PKCS1_PADDING(byte[] buf)
{
const int BT = 1;
int PS;
if (BT == 0)
PS = 0;
else if (BT == 1)
PS = 0xFF;
else
PS = new Random().Next(1, 255);
if (buf[0] != 0 && buf[1] != BT)
throw new Exception();
int p = 2;
while (p < buf.Length)
{
if (buf[p++] == 0)
break;
}
int n = buf.Length - p;
byte[] r = new byte[n];
Array.Copy(buf, p, r, 0, r.Length);
return r;
}
public bool Verify(BigInteger? PublicKey)
{
// RSA PublicKey Decrypt
byte[] decrypt = RSADecrypt(PublicKey);
// RDA Padding
byte[] values = RSA_PKCS1_PADDING(decrypt);
SequenceTLV tlvs = new SequenceTLV(values);
OctetStringTLV otlv = (OctetStringTLV)tlvs.Children[1];
byte[] result = otlv.Bytes;
// SHA-256
byte[] hash = SHA256Managed.Create().ComputeHash(msg);
// compare hash And values
if (hash.Length != result.Length)
return false;
for (int i = 0; i < result.Length; i++)
{
if (result[i] != hash[i])
{
return false;
}
}
return true;
}
对于自签名证书,利用自己的公钥进行验签