mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-08-30 12:12:40 +08:00
659 lines
18 KiB
Go
659 lines
18 KiB
Go
// 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
|
|
SignCert SignatureCertInfo
|
|
SealCert SignatureCertInfo
|
|
SignCertRaw []byte
|
|
SealCertRaw []byte
|
|
Certs [][]byte
|
|
SealType string
|
|
}
|
|
|
|
// 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 被签名数据原文, options 验证选项
|
|
// 返回: *sesVerifyResult 验证结果, error 错误信息
|
|
func verifySESSignature(data, signedData []byte, options *signatureVerifyOptions) (*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.SignCert = signatureCertInfo(sig.Cert)
|
|
result.SealCert = signatureCertInfo(sig.Seal.Cert)
|
|
result.SignCertRaw = sig.Cert
|
|
result.SealCertRaw = sig.Seal.Cert
|
|
result.Certs = append(result.Certs, sig.Seal.CertList.Certs...)
|
|
result.Certs = append(result.Certs, options.SignCerts...)
|
|
result.SealType = sig.Seal.PicType
|
|
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 印章属性信息, version 印章版本
|
|
// 返回: 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 {
|
|
switch signatureMethodText(method) {
|
|
case signMethodSM2SM3, signMethodSM2SM3B, signMethodSM2Sign, "SM2", "SM2SM3", "SM3SM2", "SM2WITHSM3", "SM3WITHSM2":
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// isSM3DigestMethod 判断是否为SM3摘要算法
|
|
// 入参: method 算法标识
|
|
// 返回: bool 是否为SM3摘要算法
|
|
func isSM3DigestMethod(method string) bool {
|
|
switch signatureMethodText(method) {
|
|
case signDigestSM3, signDigestSM3NoKey, signDigestSM3Key, "SM3":
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// 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:]...)
|
|
}
|