mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-08-30 12:12:40 +08:00
feat(签名验签): 支持签名验签
This commit is contained in:
@@ -0,0 +1,637 @@
|
||||
// Copyright 2025-2026 肖其顿 (XIAO QI DUN)
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package ofdgo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/asn1"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
signDigestSM3 = "1.2.156.10197.1.401"
|
||||
signDigestSM3NoKey = "1.2.156.10197.1.401.1"
|
||||
signDigestSM3Key = "1.2.156.10197.1.401.2"
|
||||
signMethodSM2SM3 = "1.2.156.10197.1.501"
|
||||
signMethodSM2SM3B = "1.2.156.10197.501"
|
||||
signMethodSM2Sign = "1.2.156.10197.1.301.1"
|
||||
signCurveSM2P256 = "1.2.156.10197.1.301"
|
||||
signECPublicKey = "1.2.840.10045.2.1"
|
||||
signASN1Sequence = 16
|
||||
signPublicKeySize = 65
|
||||
)
|
||||
|
||||
// sesSignature SES签章值
|
||||
type sesSignature struct {
|
||||
ToSign []byte
|
||||
Cert []byte
|
||||
SignAlg string
|
||||
Signature []byte
|
||||
DataHash []byte
|
||||
Seal *sesSeal
|
||||
}
|
||||
|
||||
// sesSeal SES电子印章
|
||||
type sesSeal struct {
|
||||
Raw []byte
|
||||
SignData []byte
|
||||
Cert []byte
|
||||
SignAlg string
|
||||
Signature []byte
|
||||
PicType string
|
||||
PicData []byte
|
||||
CertList sesCertList
|
||||
}
|
||||
|
||||
// sesCertList SES印章证书列表
|
||||
type sesCertList struct {
|
||||
Certs [][]byte
|
||||
Digests [][]byte
|
||||
}
|
||||
|
||||
// sesVerifyResult SES签章验证结果
|
||||
type sesVerifyResult struct {
|
||||
DataHashOK bool
|
||||
SignedOK bool
|
||||
SealOK bool
|
||||
CertOK bool
|
||||
}
|
||||
|
||||
// parseSESSignature 解析SES签章值
|
||||
// 入参: data 签章值数据
|
||||
// 返回: *sesSignature SES签章值, error 错误信息
|
||||
func parseSESSignature(data []byte) (*sesSignature, error) {
|
||||
var root asn1.RawValue
|
||||
rest, err := asn1.Unmarshal(data, &root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(rest) != 0 || root.Tag != signASN1Sequence || !root.IsCompound {
|
||||
return nil, fmt.Errorf("invalid ses signature")
|
||||
}
|
||||
items, ok := asn1Children(root.Bytes)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid ses signature items")
|
||||
}
|
||||
if len(items) == 2 {
|
||||
return parseSESSignatureV1(items)
|
||||
}
|
||||
if len(items) < 4 || len(items) > 5 {
|
||||
return nil, fmt.Errorf("invalid ses signature items")
|
||||
}
|
||||
cert, err := asn1OctetString(items[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
alg, err := asn1OIDString(items[2])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
signature, err := asn1BitStringBytes(items[3])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tbsItems, ok := asn1Children(items[0].Bytes)
|
||||
if !ok || len(tbsItems) < 5 {
|
||||
return nil, fmt.Errorf("invalid ses toSign")
|
||||
}
|
||||
seal, err := parseSESSeal(tbsItems[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dataHash, err := asn1BitOrOctetBytes(tbsItems[3])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &sesSignature{
|
||||
ToSign: append([]byte(nil), items[0].FullBytes...),
|
||||
Cert: cert,
|
||||
SignAlg: alg,
|
||||
Signature: signature,
|
||||
DataHash: dataHash,
|
||||
Seal: seal,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// parseSESSignatureV1 解析SES V1签章值
|
||||
// 入参: items ASN.1子元素
|
||||
// 返回: *sesSignature SES签章值, error 错误信息
|
||||
func parseSESSignatureV1(items []asn1.RawValue) (*sesSignature, error) {
|
||||
signature, err := asn1BitStringBytes(items[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tbsItems, ok := asn1Children(items[0].Bytes)
|
||||
if !ok || len(tbsItems) != 7 {
|
||||
return nil, fmt.Errorf("invalid ses v1 toSign")
|
||||
}
|
||||
seal, err := parseSESSeal(tbsItems[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dataHash, err := asn1BitOrOctetBytes(tbsItems[3])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cert, err := asn1OctetString(tbsItems[5])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
alg, err := asn1OIDString(tbsItems[6])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &sesSignature{
|
||||
ToSign: append([]byte(nil), items[0].FullBytes...),
|
||||
Cert: cert,
|
||||
SignAlg: alg,
|
||||
Signature: signature,
|
||||
DataHash: dataHash,
|
||||
Seal: seal,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// verifySESSignature 验证SES签章值
|
||||
// 入参: data 签章值数据, signedData 被签名数据原文
|
||||
// 返回: *sesVerifyResult 验证结果, error 错误信息
|
||||
func verifySESSignature(data, signedData []byte) (*sesVerifyResult, error) {
|
||||
sig, err := parseSESSignature(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !isSM2SignatureMethod(sig.SignAlg) || !isSM2SignatureMethod(sig.Seal.SignAlg) {
|
||||
return nil, fmt.Errorf("unsupported signature method")
|
||||
}
|
||||
result := &sesVerifyResult{}
|
||||
result.DataHashOK = bytes.Equal(sig.DataHash, signSM3(signedData))
|
||||
signPub, err := parseSM2PublicKeyFromCert(sig.Cert)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
sealPub, err := parseSM2PublicKeyFromCert(sig.Seal.Cert)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
result.SignedOK = sm2VerifySignature(signPub, nil, sig.ToSign, sig.Signature)
|
||||
result.SealOK = sm2VerifySignature(sealPub, nil, sig.Seal.SignData, sig.Seal.Signature)
|
||||
result.CertOK = sesCertInList(sig.Cert, sig.Seal.CertList)
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// parseSESSeal 解析SES电子印章
|
||||
// 入参: raw ASN.1原始值
|
||||
// 返回: *sesSeal SES电子印章, error 错误信息
|
||||
func parseSESSeal(raw asn1.RawValue) (*sesSeal, error) {
|
||||
items, ok := asn1Children(raw.Bytes)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid ses seal")
|
||||
}
|
||||
if len(items) == 2 {
|
||||
return parseSESSealV1(raw, items)
|
||||
}
|
||||
if len(items) < 4 || len(items) > 5 {
|
||||
return nil, fmt.Errorf("invalid ses seal")
|
||||
}
|
||||
cert, err := asn1OctetString(items[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
alg, err := asn1OIDString(items[2])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
signature, err := asn1BitStringBytes(items[3])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
infoItems, ok := asn1Children(items[0].Bytes)
|
||||
if !ok || len(infoItems) < 4 || len(infoItems) > 5 {
|
||||
return nil, fmt.Errorf("invalid ses seal info")
|
||||
}
|
||||
version, err := parseSESHeaderVersion(infoItems[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
certList, err := parseSESCertList(infoItems[2], version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
picType, picData, err := parseSESPicture(infoItems[3])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &sesSeal{
|
||||
Raw: append([]byte(nil), raw.FullBytes...),
|
||||
SignData: append([]byte(nil), items[0].FullBytes...),
|
||||
Cert: cert,
|
||||
SignAlg: alg,
|
||||
Signature: signature,
|
||||
PicType: picType,
|
||||
PicData: picData,
|
||||
CertList: certList,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// parseSESSealV1 解析SES V1电子印章
|
||||
// 入参: raw ASN.1原始值, items ASN.1子元素
|
||||
// 返回: *sesSeal SES电子印章, error 错误信息
|
||||
func parseSESSealV1(raw asn1.RawValue, items []asn1.RawValue) (*sesSeal, error) {
|
||||
infoItems, ok := asn1Children(items[0].Bytes)
|
||||
if !ok || len(infoItems) < 4 || len(infoItems) > 5 {
|
||||
return nil, fmt.Errorf("invalid ses v1 seal info")
|
||||
}
|
||||
signItems, ok := asn1Children(items[1].Bytes)
|
||||
if !ok || len(signItems) != 3 {
|
||||
return nil, fmt.Errorf("invalid ses v1 sign info")
|
||||
}
|
||||
cert, err := asn1OctetString(signItems[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
alg, err := asn1OIDString(signItems[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
signature, err := asn1BitStringBytes(signItems[2])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
certList, err := parseSESCertListV1(infoItems[2])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
picType, picData, err := parseSESPicture(infoItems[3])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
signData := asn1SequenceBytes(items[0].FullBytes, signItems[0].FullBytes, signItems[1].FullBytes)
|
||||
return &sesSeal{
|
||||
Raw: append([]byte(nil), raw.FullBytes...),
|
||||
SignData: signData,
|
||||
Cert: cert,
|
||||
SignAlg: alg,
|
||||
Signature: signature,
|
||||
PicType: picType,
|
||||
PicData: picData,
|
||||
CertList: certList,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// parseSESHeaderVersion 解析印章头版本
|
||||
// 入参: raw 印章头信息
|
||||
// 返回: int 版本号, error 错误信息
|
||||
func parseSESHeaderVersion(raw asn1.RawValue) (int, error) {
|
||||
items, ok := asn1Children(raw.Bytes)
|
||||
if !ok || len(items) < 2 {
|
||||
return 0, fmt.Errorf("invalid ses header")
|
||||
}
|
||||
return asn1Integer(items[1])
|
||||
}
|
||||
|
||||
// parseSESCertList 解析印章证书列表
|
||||
// 入参: raw 印章属性信息
|
||||
// 返回: sesCertList 证书列表, error 错误信息
|
||||
func parseSESCertList(raw asn1.RawValue, version int) (sesCertList, error) {
|
||||
items, ok := asn1Children(raw.Bytes)
|
||||
if !ok || len(items) < 3 {
|
||||
return sesCertList{}, fmt.Errorf("invalid ses property")
|
||||
}
|
||||
if version < 4 {
|
||||
return parseSESCertInfoList(items[2])
|
||||
}
|
||||
if len(items) < 4 {
|
||||
return sesCertList{}, fmt.Errorf("invalid ses cert list")
|
||||
}
|
||||
listType, err := asn1Integer(items[2])
|
||||
if err != nil {
|
||||
return sesCertList{}, err
|
||||
}
|
||||
switch listType {
|
||||
case 1:
|
||||
return parseSESCertInfoList(items[3])
|
||||
case 2:
|
||||
return parseSESCertDigestList(items[3])
|
||||
default:
|
||||
return sesCertList{}, fmt.Errorf("unsupported ses cert list type")
|
||||
}
|
||||
}
|
||||
|
||||
// parseSESCertListV1 解析SES V1证书列表
|
||||
// 入参: raw 证书列表ASN.1值
|
||||
// 返回: sesCertList 证书列表, error 错误信息
|
||||
func parseSESCertListV1(raw asn1.RawValue) (sesCertList, error) {
|
||||
certs, ok := asn1Children(raw.Bytes)
|
||||
if !ok || len(certs) == 0 {
|
||||
return sesCertList{}, fmt.Errorf("invalid ses cert list")
|
||||
}
|
||||
list := sesCertList{Certs: make([][]byte, 0, len(certs))}
|
||||
for _, item := range certs {
|
||||
list.Certs = append(list.Certs, append([]byte(nil), item.FullBytes...))
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
|
||||
// parseSESCertInfoList 解析SES证书信息列表
|
||||
// 入参: raw 证书信息列表ASN.1值
|
||||
// 返回: sesCertList 证书列表, error 错误信息
|
||||
func parseSESCertInfoList(raw asn1.RawValue) (sesCertList, error) {
|
||||
certs, ok := asn1Children(raw.Bytes)
|
||||
if !ok || len(certs) == 0 {
|
||||
return sesCertList{}, fmt.Errorf("invalid ses cert list")
|
||||
}
|
||||
list := sesCertList{Certs: make([][]byte, 0, len(certs))}
|
||||
for _, item := range certs {
|
||||
cert, err := asn1OctetString(item)
|
||||
if err != nil {
|
||||
return sesCertList{}, err
|
||||
}
|
||||
list.Certs = append(list.Certs, cert)
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
|
||||
// parseSESCertDigestList 解析SES证书摘要列表
|
||||
// 入参: raw 证书摘要列表ASN.1值
|
||||
// 返回: sesCertList 证书列表, error 错误信息
|
||||
func parseSESCertDigestList(raw asn1.RawValue) (sesCertList, error) {
|
||||
items, ok := asn1Children(raw.Bytes)
|
||||
if !ok || len(items) == 0 {
|
||||
return sesCertList{}, fmt.Errorf("invalid ses cert digest list")
|
||||
}
|
||||
list := sesCertList{Digests: make([][]byte, 0, len(items))}
|
||||
for _, item := range items {
|
||||
fields, ok := asn1Children(item.Bytes)
|
||||
if !ok || len(fields) < 2 {
|
||||
return sesCertList{}, fmt.Errorf("invalid ses cert digest")
|
||||
}
|
||||
digest, err := asn1OctetString(fields[1])
|
||||
if err != nil {
|
||||
return sesCertList{}, err
|
||||
}
|
||||
list.Digests = append(list.Digests, digest)
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
|
||||
// parseSESPicture 解析印章图片
|
||||
// 入参: raw 印章图片信息
|
||||
// 返回: string 图片类型, []byte 图片数据, error 错误信息
|
||||
func parseSESPicture(raw asn1.RawValue) (string, []byte, error) {
|
||||
items, ok := asn1Children(raw.Bytes)
|
||||
if !ok || len(items) < 4 {
|
||||
return "", nil, fmt.Errorf("invalid ses picture")
|
||||
}
|
||||
picType := normalizeSealType(strings.ToLower(strings.TrimSpace(asn1String(items[0]))))
|
||||
picData, err := asn1OctetString(items[1])
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if picType == "ofd" {
|
||||
if data := trimOFDPackage(picData); len(data) > 0 {
|
||||
picData = data
|
||||
}
|
||||
}
|
||||
return picType, picData, nil
|
||||
}
|
||||
|
||||
// parseSM2PublicKeyFromCert 从证书解析SM2公钥
|
||||
// 入参: data DER编码证书
|
||||
// 返回: sm2PublicKey SM2公钥, error 错误信息
|
||||
func parseSM2PublicKeyFromCert(data []byte) (sm2PublicKey, error) {
|
||||
var cert struct {
|
||||
TBSCertificate asn1.RawValue
|
||||
SignatureAlgorithm asn1.RawValue
|
||||
SignatureValue asn1.BitString
|
||||
}
|
||||
rest, err := asn1.Unmarshal(data, &cert)
|
||||
if err != nil {
|
||||
return sm2PublicKey{}, err
|
||||
}
|
||||
if len(rest) != 0 {
|
||||
return sm2PublicKey{}, fmt.Errorf("invalid certificate")
|
||||
}
|
||||
items, ok := asn1Children(cert.TBSCertificate.Bytes)
|
||||
if !ok {
|
||||
return sm2PublicKey{}, fmt.Errorf("invalid tbs certificate")
|
||||
}
|
||||
idx := 0
|
||||
if len(items) > 0 && items[0].Class == asn1.ClassContextSpecific && items[0].Tag == 0 {
|
||||
idx++
|
||||
}
|
||||
if len(items) <= idx+5 {
|
||||
return sm2PublicKey{}, fmt.Errorf("invalid public key info")
|
||||
}
|
||||
return parseSM2PublicKeyInfo(items[idx+5])
|
||||
}
|
||||
|
||||
// parseSM2PublicKeyInfo 解析SM2公钥信息
|
||||
// 入参: raw SubjectPublicKeyInfo原始值
|
||||
// 返回: sm2PublicKey SM2公钥, error 错误信息
|
||||
func parseSM2PublicKeyInfo(raw asn1.RawValue) (sm2PublicKey, error) {
|
||||
var spki struct {
|
||||
Algorithm asn1.RawValue
|
||||
SubjectPublicKey asn1.BitString
|
||||
}
|
||||
rest, err := asn1.Unmarshal(raw.FullBytes, &spki)
|
||||
if err != nil {
|
||||
return sm2PublicKey{}, err
|
||||
}
|
||||
if len(rest) != 0 {
|
||||
return sm2PublicKey{}, fmt.Errorf("invalid subject public key info")
|
||||
}
|
||||
algItems, ok := asn1Children(spki.Algorithm.Bytes)
|
||||
if !ok || len(algItems) < 2 {
|
||||
return sm2PublicKey{}, fmt.Errorf("invalid public key algorithm")
|
||||
}
|
||||
alg, err := asn1OIDString(algItems[0])
|
||||
if err != nil {
|
||||
return sm2PublicKey{}, err
|
||||
}
|
||||
curve, err := asn1OIDString(algItems[1])
|
||||
if err != nil {
|
||||
return sm2PublicKey{}, err
|
||||
}
|
||||
if alg != signECPublicKey || curve != signCurveSM2P256 {
|
||||
return sm2PublicKey{}, fmt.Errorf("unsupported public key algorithm")
|
||||
}
|
||||
key := spki.SubjectPublicKey.Bytes
|
||||
if len(key) != signPublicKeySize || key[0] != 4 {
|
||||
return sm2PublicKey{}, fmt.Errorf("invalid sm2 public key")
|
||||
}
|
||||
return sm2PublicKey{
|
||||
X: new(big.Int).SetBytes(key[1:33]),
|
||||
Y: new(big.Int).SetBytes(key[33:65]),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// signSM3 计算SM3摘要
|
||||
// 入参: data 原文数据
|
||||
// 返回: []byte 摘要值
|
||||
func signSM3(data []byte) []byte {
|
||||
h := newSM3()
|
||||
h.Write(data)
|
||||
return h.Sum(nil)
|
||||
}
|
||||
|
||||
// isSM2SignatureMethod 判断是否为SM2签名算法
|
||||
// 入参: method 算法标识
|
||||
// 返回: bool 是否为SM2签名算法
|
||||
func isSM2SignatureMethod(method string) bool {
|
||||
method = strings.TrimSpace(method)
|
||||
return method == signMethodSM2SM3 || method == signMethodSM2SM3B || method == signMethodSM2Sign
|
||||
}
|
||||
|
||||
// isSM3DigestMethod 判断是否为SM3摘要算法
|
||||
// 入参: method 算法标识
|
||||
// 返回: bool 是否为SM3摘要算法
|
||||
func isSM3DigestMethod(method string) bool {
|
||||
method = strings.TrimSpace(method)
|
||||
return method == signDigestSM3 || method == signDigestSM3NoKey || method == signDigestSM3Key || method == "SM3"
|
||||
}
|
||||
|
||||
// sesCertInList 判断证书是否在印章证书列表中
|
||||
// 入参: cert DER编码证书, list 证书列表
|
||||
// 返回: bool 是否存在
|
||||
func sesCertInList(cert []byte, list sesCertList) bool {
|
||||
for _, item := range list.Certs {
|
||||
if bytes.Equal(cert, item) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
digest := signSM3(cert)
|
||||
for _, item := range list.Digests {
|
||||
if bytes.Equal(digest, item) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// asn1OctetString 解析ASN.1八位字符串
|
||||
// 入参: raw ASN.1原始值
|
||||
// 返回: []byte 字节数据, error 错误信息
|
||||
func asn1OctetString(raw asn1.RawValue) ([]byte, error) {
|
||||
var out []byte
|
||||
rest, err := asn1.Unmarshal(raw.FullBytes, &out)
|
||||
if err != nil || len(rest) != 0 {
|
||||
return nil, fmt.Errorf("invalid octet string")
|
||||
}
|
||||
return append([]byte(nil), out...), nil
|
||||
}
|
||||
|
||||
// asn1BitStringBytes 解析ASN.1位字符串
|
||||
// 入参: raw ASN.1原始值
|
||||
// 返回: []byte 字节数据, error 错误信息
|
||||
func asn1BitStringBytes(raw asn1.RawValue) ([]byte, error) {
|
||||
var bits asn1.BitString
|
||||
rest, err := asn1.Unmarshal(raw.FullBytes, &bits)
|
||||
if err != nil || len(rest) != 0 || bits.BitLength%8 != 0 {
|
||||
return nil, fmt.Errorf("invalid bit string")
|
||||
}
|
||||
return append([]byte(nil), bits.Bytes...), nil
|
||||
}
|
||||
|
||||
// asn1BitOrOctetBytes 解析ASN.1位字符串或八位字符串
|
||||
// 入参: raw ASN.1原始值
|
||||
// 返回: []byte 字节数据, error 错误信息
|
||||
func asn1BitOrOctetBytes(raw asn1.RawValue) ([]byte, error) {
|
||||
if raw.Tag == asn1.TagOctetString {
|
||||
return asn1OctetString(raw)
|
||||
}
|
||||
return asn1BitStringBytes(raw)
|
||||
}
|
||||
|
||||
// asn1OIDString 解析ASN.1对象标识符
|
||||
// 入参: raw ASN.1原始值
|
||||
// 返回: string OID字符串, error 错误信息
|
||||
func asn1OIDString(raw asn1.RawValue) (string, error) {
|
||||
var oid asn1.ObjectIdentifier
|
||||
rest, err := asn1.Unmarshal(raw.FullBytes, &oid)
|
||||
if err != nil || len(rest) != 0 {
|
||||
return "", fmt.Errorf("invalid oid")
|
||||
}
|
||||
return oid.String(), nil
|
||||
}
|
||||
|
||||
// asn1Integer 解析ASN.1整数
|
||||
// 入参: raw ASN.1原始值
|
||||
// 返回: int 整数值, error 错误信息
|
||||
func asn1Integer(raw asn1.RawValue) (int, error) {
|
||||
var out int
|
||||
rest, err := asn1.Unmarshal(raw.FullBytes, &out)
|
||||
if err != nil || len(rest) != 0 {
|
||||
return 0, fmt.Errorf("invalid integer")
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// asn1String 解析ASN.1字符串
|
||||
// 入参: raw ASN.1原始值
|
||||
// 返回: string 字符串
|
||||
func asn1String(raw asn1.RawValue) string {
|
||||
var s string
|
||||
if _, err := asn1.Unmarshal(raw.FullBytes, &s); err != nil {
|
||||
return strings.TrimSpace(string(raw.Bytes))
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// asn1SequenceBytes 编码ASN.1序列
|
||||
// 入参: parts 序列元素DER数据
|
||||
// 返回: []byte ASN.1序列DER数据
|
||||
func asn1SequenceBytes(parts ...[]byte) []byte {
|
||||
var content []byte
|
||||
for _, part := range parts {
|
||||
content = append(content, part...)
|
||||
}
|
||||
return asn1Wrap(0x30, content)
|
||||
}
|
||||
|
||||
// asn1SetBytes 编码ASN.1集合
|
||||
// 入参: content 集合内容DER数据
|
||||
// 返回: []byte ASN.1集合DER数据
|
||||
func asn1SetBytes(content []byte) []byte {
|
||||
return asn1Wrap(0x31, content)
|
||||
}
|
||||
|
||||
// asn1Wrap 包装ASN.1标签
|
||||
// 入参: tag ASN.1标签, content 内容DER数据
|
||||
// 返回: []byte ASN.1 DER数据
|
||||
func asn1Wrap(tag byte, content []byte) []byte {
|
||||
out := []byte{tag}
|
||||
out = append(out, asn1LengthBytes(len(content))...)
|
||||
out = append(out, content...)
|
||||
return out
|
||||
}
|
||||
|
||||
// asn1LengthBytes 编码ASN.1长度
|
||||
// 入参: n 内容长度
|
||||
// 返回: []byte ASN.1长度编码
|
||||
func asn1LengthBytes(n int) []byte {
|
||||
if n < 128 {
|
||||
return []byte{byte(n)}
|
||||
}
|
||||
var buf [8]byte
|
||||
i := len(buf)
|
||||
for n > 0 {
|
||||
i--
|
||||
buf[i] = byte(n)
|
||||
n >>= 8
|
||||
}
|
||||
out := []byte{0x80 | byte(len(buf)-i)}
|
||||
return append(out, buf[i:]...)
|
||||
}
|
||||
Reference in New Issue
Block a user