mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-08-30 12:12:40 +08:00
+38
-2
@@ -19,6 +19,8 @@ import (
|
|||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -113,10 +115,17 @@ func (r *Reader) SignatureStampPositions(stamps []SignatureStamp) ([]SignatureSt
|
|||||||
pages := signaturePageNumbers(doc)
|
pages := signaturePageNumbers(doc)
|
||||||
positions := make([]SignatureStampPosition, 0, len(stamps))
|
positions := make([]SignatureStampPosition, 0, len(stamps))
|
||||||
for _, stamp := range stamps {
|
for _, stamp := range stamps {
|
||||||
box, _ := ParseBox(stamp.Boundary)
|
page, ok := pages[stamp.PageRef]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("signature stamp page not found: %s", stamp.PageRef)
|
||||||
|
}
|
||||||
|
box, err := parseSignatureStampBox(stamp.Boundary)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
positions = append(positions, SignatureStampPosition{
|
positions = append(positions, SignatureStampPosition{
|
||||||
ID: stamp.ID,
|
ID: stamp.ID,
|
||||||
Page: pages[stamp.PageRef],
|
Page: page,
|
||||||
PageID: stamp.PageRef,
|
PageID: stamp.PageRef,
|
||||||
Boundary: stamp.Boundary,
|
Boundary: stamp.Boundary,
|
||||||
Box: box,
|
Box: box,
|
||||||
@@ -125,6 +134,33 @@ func (r *Reader) SignatureStampPositions(stamps []SignatureStamp) ([]SignatureSt
|
|||||||
return positions, nil
|
return positions, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseSignatureStampBox 解析签名外观区域
|
||||||
|
// 入参: s 区域字符串
|
||||||
|
// 返回: Box 矩形对象, error 错误信息
|
||||||
|
func parseSignatureStampBox(s string) (Box, error) {
|
||||||
|
parts := strings.Fields(s)
|
||||||
|
if len(parts) != 4 {
|
||||||
|
return Box{}, fmt.Errorf("invalid signature stamp boundary: %s", s)
|
||||||
|
}
|
||||||
|
x, err := strconv.ParseFloat(parts[0], 64)
|
||||||
|
if err != nil {
|
||||||
|
return Box{}, fmt.Errorf("invalid signature stamp boundary: %s", s)
|
||||||
|
}
|
||||||
|
y, err := strconv.ParseFloat(parts[1], 64)
|
||||||
|
if err != nil {
|
||||||
|
return Box{}, fmt.Errorf("invalid signature stamp boundary: %s", s)
|
||||||
|
}
|
||||||
|
w, err := strconv.ParseFloat(parts[2], 64)
|
||||||
|
if err != nil {
|
||||||
|
return Box{}, fmt.Errorf("invalid signature stamp boundary: %s", s)
|
||||||
|
}
|
||||||
|
h, err := strconv.ParseFloat(parts[3], 64)
|
||||||
|
if err != nil {
|
||||||
|
return Box{}, fmt.Errorf("invalid signature stamp boundary: %s", s)
|
||||||
|
}
|
||||||
|
return Box{X: x, Y: y, W: w, H: h}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// parseSignatures 解析签名文件
|
// parseSignatures 解析签名文件
|
||||||
// 入参: doc 文档结构
|
// 入参: doc 文档结构
|
||||||
// 返回: error 错误信息
|
// 返回: error 错误信息
|
||||||
|
|||||||
+78
-22
@@ -29,10 +29,13 @@ const (
|
|||||||
|
|
||||||
// digitalVerifyResult 数字签名验证结果
|
// digitalVerifyResult 数字签名验证结果
|
||||||
type digitalVerifyResult struct {
|
type digitalVerifyResult struct {
|
||||||
DataHashOK bool
|
DataHashOK bool
|
||||||
SignedOK bool
|
SignedOK bool
|
||||||
CertOK bool
|
CertOK bool
|
||||||
CertInfo SignatureCertInfo
|
Cert []byte
|
||||||
|
SignerCerts [][]byte
|
||||||
|
Certs [][]byte
|
||||||
|
CertInfo SignatureCertInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// gbtSignedData GB/T 35275 SignedData结构
|
// gbtSignedData GB/T 35275 SignedData结构
|
||||||
@@ -61,16 +64,19 @@ type gbtSignerInfo struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// verifyDigitalSignature 验证OFD数字签名
|
// verifyDigitalSignature 验证OFD数字签名
|
||||||
// 入参: method 签名算法, signedValue 签名值, signedData 被签名原文, options 验证选项
|
// 入参: method 签名算法, digestMethod 摘要算法, signedValue 签名值, signedData 被签名原文, options 验证选项
|
||||||
// 返回: *digitalVerifyResult 验证结果, error 错误信息
|
// 返回: *digitalVerifyResult 验证结果, error 错误信息
|
||||||
func verifyDigitalSignature(method string, signedValue, signedData []byte, options *signatureVerifyOptions) (*digitalVerifyResult, error) {
|
func verifyDigitalSignature(method, digestMethod string, signedValue, signedData []byte, options *signatureVerifyOptions) (*digitalVerifyResult, error) {
|
||||||
if !isSM2SignatureMethod(method) {
|
|
||||||
return nil, fmt.Errorf("unsupported signature method")
|
|
||||||
}
|
|
||||||
if isGBT35275SignedValue(signedValue) {
|
if isGBT35275SignedValue(signedValue) {
|
||||||
return verifyGBT35275SignedData(signedValue, signedData, options)
|
return verifyGBT35275SignedData(signedValue, signedData, options)
|
||||||
}
|
}
|
||||||
return verifyRawDigitalSignature(signedValue, signedData, options)
|
if isSM2SignatureMethod(method) {
|
||||||
|
return verifyRawDigitalSignature(signedValue, signedData, options)
|
||||||
|
}
|
||||||
|
if isRSASignatureMethod(method) || isECDSASignatureMethod(method) {
|
||||||
|
return verifyRawPublicKeySignature(method, digestMethod, signedValue, signedData, options)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("unsupported signature method: %s", method)
|
||||||
}
|
}
|
||||||
|
|
||||||
// verifyRawDigitalSignature 验证裸SM2数字签名
|
// verifyRawDigitalSignature 验证裸SM2数字签名
|
||||||
@@ -87,6 +93,8 @@ func verifyRawDigitalSignature(signedValue, signedData []byte, options *signatur
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
result.CertOK = true
|
result.CertOK = true
|
||||||
|
result.Cert = cert
|
||||||
|
result.SignerCerts = [][]byte{cert}
|
||||||
result.CertInfo = signatureCertInfo(cert)
|
result.CertInfo = signatureCertInfo(cert)
|
||||||
if sm2VerifySignature(pub, nil, signedData, signedValue) {
|
if sm2VerifySignature(pub, nil, signedData, signedValue) {
|
||||||
result.SignedOK = true
|
result.SignedOK = true
|
||||||
@@ -96,6 +104,31 @@ func verifyRawDigitalSignature(signedValue, signedData []byte, options *signatur
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// verifyRawPublicKeySignature 验证裸RSA或ECDSA数字签名
|
||||||
|
// 入参: method 签名算法, digestMethod 摘要算法, signedValue 签名值, signedData 被签名原文, options 验证选项
|
||||||
|
// 返回: *digitalVerifyResult 验证结果, error 错误信息
|
||||||
|
func verifyRawPublicKeySignature(method, digestMethod string, signedValue, signedData []byte, options *signatureVerifyOptions) (*digitalVerifyResult, error) {
|
||||||
|
if len(options.SignCerts) == 0 {
|
||||||
|
return nil, fmt.Errorf("signature certificate not found")
|
||||||
|
}
|
||||||
|
result := &digitalVerifyResult{DataHashOK: true}
|
||||||
|
for _, cert := range options.SignCerts {
|
||||||
|
ok, err := verifyPublicKeySignature(method, digestMethod, cert, signedData, signedValue)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result.CertOK = true
|
||||||
|
result.Cert = cert
|
||||||
|
result.SignerCerts = [][]byte{cert}
|
||||||
|
result.CertInfo = signatureCertInfo(cert)
|
||||||
|
if ok {
|
||||||
|
result.SignedOK = true
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
// verifyGBT35275SignedData 验证GB/T 35275 SignedData签名值
|
// verifyGBT35275SignedData 验证GB/T 35275 SignedData签名值
|
||||||
// 入参: signedValue 签名值, signedData 被签名原文, options 验证选项
|
// 入参: signedValue 签名值, signedData 被签名原文, options 验证选项
|
||||||
// 返回: *digitalVerifyResult 验证结果, error 错误信息
|
// 返回: *digitalVerifyResult 验证结果, error 错误信息
|
||||||
@@ -113,16 +146,16 @@ func verifyGBT35275SignedData(signedValue, signedData []byte, options *signature
|
|||||||
if len(sd.Signers) == 0 {
|
if len(sd.Signers) == 0 {
|
||||||
return nil, fmt.Errorf("invalid signed data signer info")
|
return nil, fmt.Errorf("invalid signed data signer info")
|
||||||
}
|
}
|
||||||
result := &digitalVerifyResult{}
|
result := &digitalVerifyResult{Certs: sd.rawCerts()}
|
||||||
digest := signSM3(signedData)
|
|
||||||
if len(sd.ContentDigest) != 0 && !bytes.Equal(sd.ContentDigest, digest) {
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
result.DataHashOK = true
|
|
||||||
for _, signer := range sd.Signers {
|
for _, signer := range sd.Signers {
|
||||||
if !isSM3DigestMethod(signer.DigestAlg) {
|
digest, err := signatureDigest(signer.DigestAlg, signedData)
|
||||||
return nil, fmt.Errorf("unsupported digest method")
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if len(sd.ContentDigest) != 0 && !bytes.Equal(sd.ContentDigest, digest) {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
result.DataHashOK = true
|
||||||
plain := sd.ContentDigest
|
plain := sd.ContentDigest
|
||||||
if len(signer.AuthAttrs) != 0 {
|
if len(signer.AuthAttrs) != 0 {
|
||||||
if !bytes.Equal(signer.AttrDigest, digest) {
|
if !bytes.Equal(signer.AttrDigest, digest) {
|
||||||
@@ -138,16 +171,29 @@ func verifyGBT35275SignedData(signedValue, signedData []byte, options *signature
|
|||||||
if cert == nil {
|
if cert == nil {
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
result.Cert = cert.Raw
|
||||||
|
result.SignerCerts = append(result.SignerCerts, cert.Raw)
|
||||||
result.CertInfo = signatureCertInfo(cert.Raw)
|
result.CertInfo = signatureCertInfo(cert.Raw)
|
||||||
if !isSM2SignatureMethod(signer.SignatureAlg) {
|
if isSM2SignatureMethod(signer.SignatureAlg) {
|
||||||
return nil, fmt.Errorf("unsupported signature method")
|
pub, err := parseSM2PublicKeyFromCert(cert.Raw)
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
result.CertOK = true
|
||||||
|
if !sm2VerifySignature(pub, nil, plain, signer.Signature) {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
pub, err := parseSM2PublicKeyFromCert(cert.Raw)
|
if !isRSASignatureMethod(signer.SignatureAlg) && !isECDSASignatureMethod(signer.SignatureAlg) {
|
||||||
|
return nil, fmt.Errorf("unsupported signature method: %s", signer.SignatureAlg)
|
||||||
|
}
|
||||||
|
ok, err := verifyPublicKeySignature(signer.SignatureAlg, signer.DigestAlg, cert.Raw, plain, signer.Signature)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
result.CertOK = true
|
result.CertOK = true
|
||||||
if !sm2VerifySignature(pub, nil, plain, signer.Signature) {
|
if !ok {
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -449,6 +495,16 @@ func (sd *gbtSignedData) findCert(issuer []byte, serial *big.Int) *gbtCertificat
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// rawCerts 获取SignedData证书原文
|
||||||
|
// 返回: [][]byte 证书列表
|
||||||
|
func (sd *gbtSignedData) rawCerts() [][]byte {
|
||||||
|
certs := make([][]byte, 0, len(sd.Certs))
|
||||||
|
for _, cert := range sd.Certs {
|
||||||
|
certs = append(certs, cert.Raw)
|
||||||
|
}
|
||||||
|
return certs
|
||||||
|
}
|
||||||
|
|
||||||
// asn1Explicit 解析显式标签内容
|
// asn1Explicit 解析显式标签内容
|
||||||
// 入参: raw ASN.1原始值
|
// 入参: raw ASN.1原始值
|
||||||
// 返回: asn1.RawValue 标签内容, error 错误信息
|
// 返回: asn1.RawValue 标签内容, error 错误信息
|
||||||
|
|||||||
+29
-14
@@ -65,13 +65,16 @@ type sesCertList struct {
|
|||||||
|
|
||||||
// sesVerifyResult SES签章验证结果
|
// sesVerifyResult SES签章验证结果
|
||||||
type sesVerifyResult struct {
|
type sesVerifyResult struct {
|
||||||
DataHashOK bool
|
DataHashOK bool
|
||||||
SignedOK bool
|
SignedOK bool
|
||||||
SealOK bool
|
SealOK bool
|
||||||
CertOK bool
|
CertOK bool
|
||||||
SignCert SignatureCertInfo
|
SignCert SignatureCertInfo
|
||||||
SealCert SignatureCertInfo
|
SealCert SignatureCertInfo
|
||||||
SealType string
|
SignCertRaw []byte
|
||||||
|
SealCertRaw []byte
|
||||||
|
Certs [][]byte
|
||||||
|
SealType string
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseSESSignature 解析SES签章值
|
// parseSESSignature 解析SES签章值
|
||||||
@@ -169,9 +172,9 @@ func parseSESSignatureV1(items []asn1.RawValue) (*sesSignature, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// verifySESSignature 验证SES签章值
|
// verifySESSignature 验证SES签章值
|
||||||
// 入参: data 签章值数据, signedData 被签名数据原文
|
// 入参: data 签章值数据, signedData 被签名数据原文, options 验证选项
|
||||||
// 返回: *sesVerifyResult 验证结果, error 错误信息
|
// 返回: *sesVerifyResult 验证结果, error 错误信息
|
||||||
func verifySESSignature(data, signedData []byte) (*sesVerifyResult, error) {
|
func verifySESSignature(data, signedData []byte, options *signatureVerifyOptions) (*sesVerifyResult, error) {
|
||||||
sig, err := parseSESSignature(data)
|
sig, err := parseSESSignature(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -182,6 +185,10 @@ func verifySESSignature(data, signedData []byte) (*sesVerifyResult, error) {
|
|||||||
result := &sesVerifyResult{}
|
result := &sesVerifyResult{}
|
||||||
result.SignCert = signatureCertInfo(sig.Cert)
|
result.SignCert = signatureCertInfo(sig.Cert)
|
||||||
result.SealCert = signatureCertInfo(sig.Seal.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.SealType = sig.Seal.PicType
|
||||||
result.DataHashOK = bytes.Equal(sig.DataHash, signSM3(signedData))
|
result.DataHashOK = bytes.Equal(sig.DataHash, signSM3(signedData))
|
||||||
signPub, err := parseSM2PublicKeyFromCert(sig.Cert)
|
signPub, err := parseSM2PublicKeyFromCert(sig.Cert)
|
||||||
@@ -309,7 +316,7 @@ func parseSESHeaderVersion(raw asn1.RawValue) (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// parseSESCertList 解析印章证书列表
|
// parseSESCertList 解析印章证书列表
|
||||||
// 入参: raw 印章属性信息
|
// 入参: raw 印章属性信息, version 印章版本
|
||||||
// 返回: sesCertList 证书列表, error 错误信息
|
// 返回: sesCertList 证书列表, error 错误信息
|
||||||
func parseSESCertList(raw asn1.RawValue, version int) (sesCertList, error) {
|
func parseSESCertList(raw asn1.RawValue, version int) (sesCertList, error) {
|
||||||
items, ok := asn1Children(raw.Bytes)
|
items, ok := asn1Children(raw.Bytes)
|
||||||
@@ -497,16 +504,24 @@ func signSM3(data []byte) []byte {
|
|||||||
// 入参: method 算法标识
|
// 入参: method 算法标识
|
||||||
// 返回: bool 是否为SM2签名算法
|
// 返回: bool 是否为SM2签名算法
|
||||||
func isSM2SignatureMethod(method string) bool {
|
func isSM2SignatureMethod(method string) bool {
|
||||||
method = strings.TrimSpace(method)
|
switch signatureMethodText(method) {
|
||||||
return method == signMethodSM2SM3 || method == signMethodSM2SM3B || method == signMethodSM2Sign
|
case signMethodSM2SM3, signMethodSM2SM3B, signMethodSM2Sign, "SM2", "SM2SM3", "SM3SM2", "SM2WITHSM3", "SM3WITHSM2":
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// isSM3DigestMethod 判断是否为SM3摘要算法
|
// isSM3DigestMethod 判断是否为SM3摘要算法
|
||||||
// 入参: method 算法标识
|
// 入参: method 算法标识
|
||||||
// 返回: bool 是否为SM3摘要算法
|
// 返回: bool 是否为SM3摘要算法
|
||||||
func isSM3DigestMethod(method string) bool {
|
func isSM3DigestMethod(method string) bool {
|
||||||
method = strings.TrimSpace(method)
|
switch signatureMethodText(method) {
|
||||||
return method == signDigestSM3 || method == signDigestSM3NoKey || method == signDigestSM3Key || method == "SM3"
|
case signDigestSM3, signDigestSM3NoKey, signDigestSM3Key, "SM3":
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// sesCertInList 判断证书是否在印章证书列表中
|
// sesCertInList 判断证书是否在印章证书列表中
|
||||||
|
|||||||
+472
-20
@@ -16,15 +16,24 @@ package ofdgo
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto"
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/sha1"
|
||||||
|
"crypto/sha256"
|
||||||
|
"crypto/sha512"
|
||||||
"crypto/subtle"
|
"crypto/subtle"
|
||||||
|
"crypto/x509"
|
||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"math/big"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SignatureVerifyReport 签名验证报告
|
// SignatureVerifyReport 签名验证报告
|
||||||
@@ -42,12 +51,17 @@ type SignatureVerifyReport struct {
|
|||||||
DigestMethod string
|
DigestMethod string
|
||||||
References []SignatureReferenceVerify
|
References []SignatureReferenceVerify
|
||||||
Stamps []SignatureStamp
|
Stamps []SignatureStamp
|
||||||
|
StampPositions []SignatureStampPosition
|
||||||
DigestOK bool
|
DigestOK bool
|
||||||
DataHashOK bool
|
DataHashOK bool
|
||||||
SignedValueOK bool
|
SignedValueOK bool
|
||||||
SealOK bool
|
SealOK bool
|
||||||
SealMatchOK bool
|
SealMatchOK bool
|
||||||
CertOK bool
|
CertOK bool
|
||||||
|
CertTimeChecked bool
|
||||||
|
CertTimeOK bool
|
||||||
|
CertTrustChecked bool
|
||||||
|
CertTrustOK bool
|
||||||
Valid bool
|
Valid bool
|
||||||
Error string
|
Error string
|
||||||
}
|
}
|
||||||
@@ -59,6 +73,8 @@ type SignatureCertInfo struct {
|
|||||||
Organization string
|
Organization string
|
||||||
Issuer string
|
Issuer string
|
||||||
SerialNumber string
|
SerialNumber string
|
||||||
|
NotBefore time.Time
|
||||||
|
NotAfter time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignatureReferenceVerify 签名保护文件验证结果
|
// SignatureReferenceVerify 签名保护文件验证结果
|
||||||
@@ -73,7 +89,9 @@ type SignatureReferenceVerify struct {
|
|||||||
|
|
||||||
// signatureVerifyOptions 签名验证选项
|
// signatureVerifyOptions 签名验证选项
|
||||||
type signatureVerifyOptions struct {
|
type signatureVerifyOptions struct {
|
||||||
SignCerts [][]byte
|
SignCerts [][]byte
|
||||||
|
TrustCerts [][]byte
|
||||||
|
VerifyTime *time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignatureVerifyOption 签名验证选项函数
|
// SignatureVerifyOption 签名验证选项函数
|
||||||
@@ -99,6 +117,35 @@ func WithSignatureCerts(certs ...[]byte) SignatureVerifyOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithSignatureTrustCert 添加签名信任证书
|
||||||
|
// 入参: cert DER或PEM编码证书
|
||||||
|
// 返回: SignatureVerifyOption 签名验证选项
|
||||||
|
func WithSignatureTrustCert(cert []byte) SignatureVerifyOption {
|
||||||
|
return func(o *signatureVerifyOptions) {
|
||||||
|
o.TrustCerts = append(o.TrustCerts, parseSignatureCerts(cert)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSignatureTrustCerts 添加多张签名信任证书
|
||||||
|
// 入参: certs DER或PEM编码证书列表
|
||||||
|
// 返回: SignatureVerifyOption 签名验证选项
|
||||||
|
func WithSignatureTrustCerts(certs ...[]byte) SignatureVerifyOption {
|
||||||
|
return func(o *signatureVerifyOptions) {
|
||||||
|
for _, cert := range certs {
|
||||||
|
o.TrustCerts = append(o.TrustCerts, parseSignatureCerts(cert)...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSignatureVerifyTime 设置签名证书验证时间
|
||||||
|
// 入参: t 验证时间
|
||||||
|
// 返回: SignatureVerifyOption 签名验证选项
|
||||||
|
func WithSignatureVerifyTime(t time.Time) SignatureVerifyOption {
|
||||||
|
return func(o *signatureVerifyOptions) {
|
||||||
|
o.VerifyTime = &t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// VerifySignaturesBytes 验证OFD字节数据签名
|
// VerifySignaturesBytes 验证OFD字节数据签名
|
||||||
// 入参: data OFD字节数据, opts 签名验证选项
|
// 入参: data OFD字节数据, opts 签名验证选项
|
||||||
// 返回: []SignatureVerifyReport 签名验证报告, error 错误信息
|
// 返回: []SignatureVerifyReport 签名验证报告, error 错误信息
|
||||||
@@ -186,6 +233,11 @@ func (r *Reader) verifySignature(sigListPath string, sigRef Signature, options *
|
|||||||
report.DigestMethod = sigFile.SignedInfo.References.CheckMethod
|
report.DigestMethod = sigFile.SignedInfo.References.CheckMethod
|
||||||
report.References = r.verifySignatureReferences(sigPath, sigFile.SignedInfo.References)
|
report.References = r.verifySignatureReferences(sigPath, sigFile.SignedInfo.References)
|
||||||
report.Stamps = append(report.Stamps, sigFile.SignedInfo.StampAnnot...)
|
report.Stamps = append(report.Stamps, sigFile.SignedInfo.StampAnnot...)
|
||||||
|
report.StampPositions, err = r.SignatureStampPositions(report.Stamps)
|
||||||
|
if err != nil {
|
||||||
|
report.Error = err.Error()
|
||||||
|
return report
|
||||||
|
}
|
||||||
report.DigestOK = referencesOK(report.References)
|
report.DigestOK = referencesOK(report.References)
|
||||||
signedValuePath := signatureRefPath(sigPath, sigFile.SignedValue)
|
signedValuePath := signatureRefPath(sigPath, sigFile.SignedValue)
|
||||||
signedValue, err := r.readFileExact(signedValuePath)
|
signedValue, err := r.readFileExact(signedValuePath)
|
||||||
@@ -195,7 +247,7 @@ func (r *Reader) verifySignature(sigListPath string, sigRef Signature, options *
|
|||||||
}
|
}
|
||||||
switch sigRef.Type {
|
switch sigRef.Type {
|
||||||
case SignTypeSign:
|
case SignTypeSign:
|
||||||
result, err := verifyDigitalSignature(report.SignatureMethod, signedValue, sigData, options)
|
result, err := verifyDigitalSignature(report.SignatureMethod, report.DigestMethod, signedValue, sigData, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
report.Error = err.Error()
|
report.Error = err.Error()
|
||||||
return report
|
return report
|
||||||
@@ -206,14 +258,15 @@ func (r *Reader) verifySignature(sigListPath string, sigRef Signature, options *
|
|||||||
report.CertOK = result.CertOK
|
report.CertOK = result.CertOK
|
||||||
report.SignCert = result.CertInfo
|
report.SignCert = result.CertInfo
|
||||||
report.Signer = result.CertInfo.CommonName
|
report.Signer = result.CertInfo.CommonName
|
||||||
report.Valid = report.DigestOK && report.DataHashOK && report.SignedValueOK && report.CertOK
|
report.applySignatureCertificatePolicy(options, result.SignerCerts, result.Certs)
|
||||||
|
report.Valid = report.DigestOK && report.DataHashOK && report.SignedValueOK && report.CertOK && report.certificatePolicyOK()
|
||||||
return report
|
return report
|
||||||
case "", SignTypeSeal:
|
case "", SignTypeSeal:
|
||||||
default:
|
default:
|
||||||
report.Error = fmt.Sprintf("unsupported signature type: %s", sigRef.Type)
|
report.Error = fmt.Sprintf("unsupported signature type: %s", sigRef.Type)
|
||||||
return report
|
return report
|
||||||
}
|
}
|
||||||
sesResult, err := verifySESSignature(signedValue, sigData)
|
sesResult, err := verifySESSignature(signedValue, sigData, options)
|
||||||
if sesResult != nil {
|
if sesResult != nil {
|
||||||
report.SignCert = sesResult.SignCert
|
report.SignCert = sesResult.SignCert
|
||||||
report.SealCert = sesResult.SealCert
|
report.SealCert = sesResult.SealCert
|
||||||
@@ -228,6 +281,7 @@ func (r *Reader) verifySignature(sigListPath string, sigRef Signature, options *
|
|||||||
report.SignedValueOK = sesResult.SignedOK
|
report.SignedValueOK = sesResult.SignedOK
|
||||||
report.SealOK = sesResult.SealOK
|
report.SealOK = sesResult.SealOK
|
||||||
report.CertOK = sesResult.CertOK
|
report.CertOK = sesResult.CertOK
|
||||||
|
report.applySignatureCertificatePolicy(options, [][]byte{sesResult.SignCertRaw, sesResult.SealCertRaw}, sesResult.Certs)
|
||||||
if sigFile.SignedInfo.Seal.BaseLoc != "" {
|
if sigFile.SignedInfo.Seal.BaseLoc != "" {
|
||||||
sealPath := signatureRefPath(sigPath, sigFile.SignedInfo.Seal.BaseLoc)
|
sealPath := signatureRefPath(sigPath, sigFile.SignedInfo.Seal.BaseLoc)
|
||||||
sealData, err := r.readFileExact(sealPath)
|
sealData, err := r.readFileExact(sealPath)
|
||||||
@@ -242,7 +296,7 @@ func (r *Reader) verifySignature(sigListPath string, sigRef Signature, options *
|
|||||||
}
|
}
|
||||||
report.SealMatchOK = bytes.Equal(sealData, sig.Seal.Raw)
|
report.SealMatchOK = bytes.Equal(sealData, sig.Seal.Raw)
|
||||||
}
|
}
|
||||||
report.Valid = report.DigestOK && report.DataHashOK && report.SignedValueOK && report.SealOK && report.SealMatchOK && report.CertOK
|
report.Valid = report.DigestOK && report.DataHashOK && report.SignedValueOK && report.SealOK && report.SealMatchOK && report.CertOK && report.certificatePolicyOK()
|
||||||
return report
|
return report
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,9 +375,190 @@ func signatureDigest(method string, data []byte) ([]byte, error) {
|
|||||||
if isSM3DigestMethod(method) {
|
if isSM3DigestMethod(method) {
|
||||||
return signSM3(data), nil
|
return signSM3(data), nil
|
||||||
}
|
}
|
||||||
|
if h, ok := signatureDigestHash(method); ok {
|
||||||
|
return signatureHashBytes(h, data), nil
|
||||||
|
}
|
||||||
return nil, fmt.Errorf("unsupported digest method: %s", method)
|
return nil, fmt.Errorf("unsupported digest method: %s", method)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// signatureDigestHash 获取摘要算法
|
||||||
|
// 入参: method 摘要算法
|
||||||
|
// 返回: crypto.Hash 摘要算法, bool 是否支持
|
||||||
|
func signatureDigestHash(method string) (crypto.Hash, bool) {
|
||||||
|
switch signatureMethodText(method) {
|
||||||
|
case "1.3.14.3.2.26", "SHA1":
|
||||||
|
return crypto.SHA1, true
|
||||||
|
case "2.16.840.1.101.3.4.2.4", "SHA224":
|
||||||
|
return crypto.SHA224, true
|
||||||
|
case "2.16.840.1.101.3.4.2.1", "SHA256":
|
||||||
|
return crypto.SHA256, true
|
||||||
|
case "2.16.840.1.101.3.4.2.2", "SHA384":
|
||||||
|
return crypto.SHA384, true
|
||||||
|
case "2.16.840.1.101.3.4.2.3", "SHA512":
|
||||||
|
return crypto.SHA512, true
|
||||||
|
case "2.16.840.1.101.3.4.2.5", "SHA512224":
|
||||||
|
return crypto.SHA512_224, true
|
||||||
|
case "2.16.840.1.101.3.4.2.6", "SHA512256":
|
||||||
|
return crypto.SHA512_256, true
|
||||||
|
default:
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// signatureMethodHash 获取签名算法对应摘要算法
|
||||||
|
// 入参: method 签名算法, digestMethod 摘要算法
|
||||||
|
// 返回: crypto.Hash 摘要算法, error 错误信息
|
||||||
|
func signatureMethodHash(method, digestMethod string) (crypto.Hash, error) {
|
||||||
|
switch signatureMethodText(method) {
|
||||||
|
case "1.2.840.113549.1.1.5", "RSASHA1", "SHA1RSA", "SHA1WITHRSA":
|
||||||
|
return crypto.SHA1, nil
|
||||||
|
case "1.2.840.113549.1.1.14", "RSASHA224", "SHA224RSA", "SHA224WITHRSA":
|
||||||
|
return crypto.SHA224, nil
|
||||||
|
case "1.2.840.113549.1.1.11", "RSASHA256", "SHA256RSA", "SHA256WITHRSA":
|
||||||
|
return crypto.SHA256, nil
|
||||||
|
case "1.2.840.113549.1.1.12", "RSASHA384", "SHA384RSA", "SHA384WITHRSA":
|
||||||
|
return crypto.SHA384, nil
|
||||||
|
case "1.2.840.113549.1.1.13", "RSASHA512", "SHA512RSA", "SHA512WITHRSA":
|
||||||
|
return crypto.SHA512, nil
|
||||||
|
case "1.2.840.10045.4.1", "ECDSASHA1", "SHA1ECDSA", "SHA1WITHECDSA":
|
||||||
|
return crypto.SHA1, nil
|
||||||
|
case "1.2.840.10045.4.3.1", "ECDSASHA224", "SHA224ECDSA", "SHA224WITHECDSA":
|
||||||
|
return crypto.SHA224, nil
|
||||||
|
case "1.2.840.10045.4.3.2", "ECDSASHA256", "SHA256ECDSA", "SHA256WITHECDSA":
|
||||||
|
return crypto.SHA256, nil
|
||||||
|
case "1.2.840.10045.4.3.3", "ECDSASHA384", "SHA384ECDSA", "SHA384WITHECDSA":
|
||||||
|
return crypto.SHA384, nil
|
||||||
|
case "1.2.840.10045.4.3.4", "ECDSASHA512", "SHA512ECDSA", "SHA512WITHECDSA":
|
||||||
|
return crypto.SHA512, nil
|
||||||
|
}
|
||||||
|
if h, ok := signatureDigestHash(digestMethod); ok {
|
||||||
|
return h, nil
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("unsupported signature method: %s", method)
|
||||||
|
}
|
||||||
|
|
||||||
|
// signatureHashBytes 计算摘要
|
||||||
|
// 入参: h 摘要算法, data 原文数据
|
||||||
|
// 返回: []byte 摘要值
|
||||||
|
func signatureHashBytes(h crypto.Hash, data []byte) []byte {
|
||||||
|
switch h {
|
||||||
|
case crypto.SHA1:
|
||||||
|
sum := sha1.Sum(data)
|
||||||
|
return sum[:]
|
||||||
|
case crypto.SHA224:
|
||||||
|
sum := sha256.Sum224(data)
|
||||||
|
return sum[:]
|
||||||
|
case crypto.SHA256:
|
||||||
|
sum := sha256.Sum256(data)
|
||||||
|
return sum[:]
|
||||||
|
case crypto.SHA384:
|
||||||
|
sum := sha512.Sum384(data)
|
||||||
|
return sum[:]
|
||||||
|
case crypto.SHA512:
|
||||||
|
sum := sha512.Sum512(data)
|
||||||
|
return sum[:]
|
||||||
|
case crypto.SHA512_224:
|
||||||
|
sum := sha512.Sum512_224(data)
|
||||||
|
return sum[:]
|
||||||
|
case crypto.SHA512_256:
|
||||||
|
sum := sha512.Sum512_256(data)
|
||||||
|
return sum[:]
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// isRSASignatureMethod 判断是否为RSA签名算法
|
||||||
|
// 入参: method 算法标识
|
||||||
|
// 返回: bool 是否为RSA签名算法
|
||||||
|
func isRSASignatureMethod(method string) bool {
|
||||||
|
switch signatureMethodText(method) {
|
||||||
|
case "1.2.840.113549.1.1.1", "1.2.840.113549.1.1.5", "1.2.840.113549.1.1.11", "1.2.840.113549.1.1.12", "1.2.840.113549.1.1.13", "1.2.840.113549.1.1.14", "RSA", "RSASHA1", "RSASHA224", "RSASHA256", "RSASHA384", "RSASHA512", "SHA1RSA", "SHA224RSA", "SHA256RSA", "SHA384RSA", "SHA512RSA", "SHA1WITHRSA", "SHA224WITHRSA", "SHA256WITHRSA", "SHA384WITHRSA", "SHA512WITHRSA":
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// isECDSASignatureMethod 判断是否为ECDSA签名算法
|
||||||
|
// 入参: method 算法标识
|
||||||
|
// 返回: bool 是否为ECDSA签名算法
|
||||||
|
func isECDSASignatureMethod(method string) bool {
|
||||||
|
switch signatureMethodText(method) {
|
||||||
|
case "1.2.840.10045.4.1", "1.2.840.10045.4.3.1", "1.2.840.10045.4.3.2", "1.2.840.10045.4.3.3", "1.2.840.10045.4.3.4", "ECDSA", "ECDSASHA1", "ECDSASHA224", "ECDSASHA256", "ECDSASHA384", "ECDSASHA512", "SHA1ECDSA", "SHA224ECDSA", "SHA256ECDSA", "SHA384ECDSA", "SHA512ECDSA", "SHA1WITHECDSA", "SHA224WITHECDSA", "SHA256WITHECDSA", "SHA384WITHECDSA", "SHA512WITHECDSA":
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// signatureMethodText 规范化算法标识
|
||||||
|
// 入参: method 算法标识
|
||||||
|
// 返回: string 规范化算法标识
|
||||||
|
func signatureMethodText(method string) string {
|
||||||
|
method = strings.TrimSpace(method)
|
||||||
|
if strings.HasPrefix(strings.ToLower(method), "urn:oid:") {
|
||||||
|
method = method[len("urn:oid:"):]
|
||||||
|
}
|
||||||
|
if idx := strings.LastIndexAny(method, "#/"); idx >= 0 && idx+1 < len(method) {
|
||||||
|
method = method[idx+1:]
|
||||||
|
}
|
||||||
|
method = strings.ToUpper(method)
|
||||||
|
method = strings.NewReplacer("-", "", "_", "", " ", "").Replace(method)
|
||||||
|
return method
|
||||||
|
}
|
||||||
|
|
||||||
|
// verifyPublicKeySignature 验证公钥签名
|
||||||
|
// 入参: method 签名算法, digestMethod 摘要算法, cert 证书, signedData 被签名数据, signedValue 签名值
|
||||||
|
// 返回: bool 是否验证通过, error 错误信息
|
||||||
|
func verifyPublicKeySignature(method, digestMethod string, cert, signedData, signedValue []byte) (bool, error) {
|
||||||
|
if !isRSASignatureMethod(method) && !isECDSASignatureMethod(method) {
|
||||||
|
return false, fmt.Errorf("unsupported signature method: %s", method)
|
||||||
|
}
|
||||||
|
h, err := signatureMethodHash(method, digestMethod)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
digest := signatureHashBytes(h, signedData)
|
||||||
|
if len(digest) == 0 {
|
||||||
|
return false, fmt.Errorf("unsupported digest method")
|
||||||
|
}
|
||||||
|
x509Cert, err := x509.ParseCertificate(cert)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
switch pub := x509Cert.PublicKey.(type) {
|
||||||
|
case *rsa.PublicKey:
|
||||||
|
if !isRSASignatureMethod(method) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return rsa.VerifyPKCS1v15(pub, h, digest, signedValue) == nil, nil
|
||||||
|
case *ecdsa.PublicKey:
|
||||||
|
if !isECDSASignatureMethod(method) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return verifyECDSASignature(pub, digest, signedValue), nil
|
||||||
|
default:
|
||||||
|
return false, fmt.Errorf("unsupported public key algorithm")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// verifyECDSASignature 验证ECDSA签名
|
||||||
|
// 入参: pub 公钥, digest 摘要, sig 签名值
|
||||||
|
// 返回: bool 是否验证通过
|
||||||
|
func verifyECDSASignature(pub *ecdsa.PublicKey, digest, sig []byte) bool {
|
||||||
|
if ecdsa.VerifyASN1(pub, digest, sig) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if len(sig) == 0 || len(sig)%2 != 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
n := len(sig) / 2
|
||||||
|
r := new(big.Int).SetBytes(sig[:n])
|
||||||
|
s := new(big.Int).SetBytes(sig[n:])
|
||||||
|
return ecdsa.Verify(pub, digest, r, s)
|
||||||
|
}
|
||||||
|
|
||||||
// signatureRefPath 解析签名文件引用路径
|
// signatureRefPath 解析签名文件引用路径
|
||||||
// 入参: basePath 基准路径, refPath 引用路径
|
// 入参: basePath 基准路径, refPath 引用路径
|
||||||
// 返回: string 包内文件路径
|
// 返回: string 包内文件路径
|
||||||
@@ -351,6 +586,138 @@ func referencesOK(refs []SignatureReferenceVerify) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// applySignatureCertificatePolicy 应用签名证书策略
|
||||||
|
// 入参: options 验证选项, certs 待验证证书, extraCerts 证书池
|
||||||
|
func (report *SignatureVerifyReport) applySignatureCertificatePolicy(options *signatureVerifyOptions, certs [][]byte, extraCerts [][]byte) {
|
||||||
|
certs = compactSignatureCerts(certs)
|
||||||
|
if options.VerifyTime != nil {
|
||||||
|
report.CertTimeChecked = true
|
||||||
|
report.CertTimeOK = signatureCertsValidAt(certs, *options.VerifyTime)
|
||||||
|
}
|
||||||
|
if len(options.TrustCerts) != 0 {
|
||||||
|
report.CertTrustChecked = true
|
||||||
|
report.CertTrustOK = true
|
||||||
|
for _, cert := range certs {
|
||||||
|
if !signatureCertTrusted(cert, options, extraCerts) {
|
||||||
|
report.CertTrustOK = false
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(certs) == 0 {
|
||||||
|
report.CertTrustOK = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// certificatePolicyOK 判断证书策略是否通过
|
||||||
|
// 返回: bool 是否通过
|
||||||
|
func (report SignatureVerifyReport) certificatePolicyOK() bool {
|
||||||
|
if report.CertTimeChecked && !report.CertTimeOK {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if report.CertTrustChecked && !report.CertTrustOK {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// signatureCertsValidAt 判断证书是否在指定时间有效
|
||||||
|
// 入参: certs 证书列表, t 验证时间
|
||||||
|
// 返回: bool 是否有效
|
||||||
|
func signatureCertsValidAt(certs [][]byte, t time.Time) bool {
|
||||||
|
if len(certs) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, cert := range certs {
|
||||||
|
info, err := parseSignatureCertificate(cert)
|
||||||
|
if err != nil || t.Before(info.NotBefore) || t.After(info.NotAfter) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// signatureCertTrusted 判断证书是否受信任
|
||||||
|
// 入参: cert 证书, options 验证选项, extraCerts 额外证书池
|
||||||
|
// 返回: bool 是否受信任
|
||||||
|
func signatureCertTrusted(cert []byte, options *signatureVerifyOptions, extraCerts [][]byte) bool {
|
||||||
|
pool := compactSignatureCerts(append(append(append([][]byte{}, options.SignCerts...), extraCerts...), options.TrustCerts...))
|
||||||
|
return signatureCertTrustedBy(cert, pool, options.TrustCerts, make(map[string]bool))
|
||||||
|
}
|
||||||
|
|
||||||
|
// signatureCertTrustedBy 判断证书是否可链到信任证书
|
||||||
|
// 入参: cert 证书, pool 证书池, trusts 信任证书, visited 已访问证书
|
||||||
|
// 返回: bool 是否受信任
|
||||||
|
func signatureCertTrustedBy(cert []byte, pool, trusts [][]byte, visited map[string]bool) bool {
|
||||||
|
if len(cert) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, trust := range trusts {
|
||||||
|
if bytes.Equal(cert, trust) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
key := string(cert)
|
||||||
|
if visited[key] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
visited[key] = true
|
||||||
|
c, err := parseSignatureCertificate(cert)
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, issuerCert := range pool {
|
||||||
|
if bytes.Equal(cert, issuerCert) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
issuer, err := parseSignatureCertificate(issuerCert)
|
||||||
|
if err != nil || !bytes.Equal(c.Issuer, issuer.Subject) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if ok, err := verifyCertificateSignature(c, issuerCert); err != nil || !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if signatureCertTrustedBy(issuerCert, pool, trusts, visited) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// verifyCertificateSignature 验证证书签名
|
||||||
|
// 入参: cert 证书信息, issuerCert 颁发者证书
|
||||||
|
// 返回: bool 是否验证通过, error 错误信息
|
||||||
|
func verifyCertificateSignature(cert signatureCertificate, issuerCert []byte) (bool, error) {
|
||||||
|
if isSM2SignatureMethod(cert.SignatureAlg) {
|
||||||
|
pub, err := parseSM2PublicKeyFromCert(issuerCert)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return sm2VerifySignature(pub, nil, cert.TBS, cert.Signature), nil
|
||||||
|
}
|
||||||
|
return verifyPublicKeySignature(cert.SignatureAlg, "", issuerCert, cert.TBS, cert.Signature)
|
||||||
|
}
|
||||||
|
|
||||||
|
// compactSignatureCerts 清理证书列表
|
||||||
|
// 入参: certs 证书列表
|
||||||
|
// 返回: [][]byte 清理后的证书列表
|
||||||
|
func compactSignatureCerts(certs [][]byte) [][]byte {
|
||||||
|
out := make([][]byte, 0, len(certs))
|
||||||
|
seen := make(map[string]bool)
|
||||||
|
for _, cert := range certs {
|
||||||
|
if len(cert) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
key := string(cert)
|
||||||
|
if seen[key] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seen[key] = true
|
||||||
|
out = append(out, cert)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// xmlElementRaw 提取XML元素原始字节
|
// xmlElementRaw 提取XML元素原始字节
|
||||||
// 入参: data XML数据, localName 元素名称
|
// 入参: data XML数据, localName 元素名称
|
||||||
// 返回: []byte 元素原始字节, error 错误信息
|
// 返回: []byte 元素原始字节, error 错误信息
|
||||||
@@ -395,6 +762,45 @@ func xmlElementRaw(data []byte, localName string) ([]byte, error) {
|
|||||||
// 入参: data DER编码证书
|
// 入参: data DER编码证书
|
||||||
// 返回: SignatureCertInfo 签名证书信息
|
// 返回: SignatureCertInfo 签名证书信息
|
||||||
func signatureCertInfo(data []byte) SignatureCertInfo {
|
func signatureCertInfo(data []byte) SignatureCertInfo {
|
||||||
|
cert, err := parseSignatureCertificate(data)
|
||||||
|
if err != nil {
|
||||||
|
return SignatureCertInfo{}
|
||||||
|
}
|
||||||
|
subject := certificateNameValues(cert.SubjectValue)
|
||||||
|
issuer := certificateNameValues(cert.IssuerValue)
|
||||||
|
info := SignatureCertInfo{
|
||||||
|
Subject: certificateNameString(subject),
|
||||||
|
CommonName: certificateNameFirst(subject, "2.5.4.3"),
|
||||||
|
Organization: certificateNameFirst(subject, "2.5.4.10"),
|
||||||
|
Issuer: certificateNameString(issuer),
|
||||||
|
NotBefore: cert.NotBefore,
|
||||||
|
NotAfter: cert.NotAfter,
|
||||||
|
}
|
||||||
|
if cert.Serial != nil {
|
||||||
|
info.SerialNumber = cert.Serial.String()
|
||||||
|
}
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
|
||||||
|
// signatureCertificate 签名证书结构
|
||||||
|
type signatureCertificate struct {
|
||||||
|
Raw []byte
|
||||||
|
TBS []byte
|
||||||
|
Issuer []byte
|
||||||
|
IssuerValue asn1.RawValue
|
||||||
|
Subject []byte
|
||||||
|
SubjectValue asn1.RawValue
|
||||||
|
Serial *big.Int
|
||||||
|
NotBefore time.Time
|
||||||
|
NotAfter time.Time
|
||||||
|
SignatureAlg string
|
||||||
|
Signature []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseSignatureCertificate 解析签名证书
|
||||||
|
// 入参: data DER编码证书
|
||||||
|
// 返回: signatureCertificate 签名证书结构, error 错误信息
|
||||||
|
func parseSignatureCertificate(data []byte) (signatureCertificate, error) {
|
||||||
var cert struct {
|
var cert struct {
|
||||||
TBSCertificate asn1.RawValue
|
TBSCertificate asn1.RawValue
|
||||||
SignatureAlgorithm asn1.RawValue
|
SignatureAlgorithm asn1.RawValue
|
||||||
@@ -402,32 +808,78 @@ func signatureCertInfo(data []byte) SignatureCertInfo {
|
|||||||
}
|
}
|
||||||
rest, err := asn1.Unmarshal(data, &cert)
|
rest, err := asn1.Unmarshal(data, &cert)
|
||||||
if err != nil || len(rest) != 0 {
|
if err != nil || len(rest) != 0 {
|
||||||
return SignatureCertInfo{}
|
return signatureCertificate{}, fmt.Errorf("invalid certificate")
|
||||||
}
|
}
|
||||||
items, ok := asn1Children(cert.TBSCertificate.Bytes)
|
items, ok := asn1Children(cert.TBSCertificate.Bytes)
|
||||||
if !ok {
|
if !ok {
|
||||||
return SignatureCertInfo{}
|
return signatureCertificate{}, fmt.Errorf("invalid tbs certificate")
|
||||||
}
|
}
|
||||||
idx := 0
|
idx := 0
|
||||||
if len(items) > 0 && items[0].Class == asn1.ClassContextSpecific && items[0].Tag == 0 {
|
if len(items) > 0 && items[0].Class == asn1.ClassContextSpecific && items[0].Tag == 0 {
|
||||||
idx++
|
idx++
|
||||||
}
|
}
|
||||||
if len(items) <= idx+4 {
|
if len(items) <= idx+5 {
|
||||||
return SignatureCertInfo{}
|
return signatureCertificate{}, fmt.Errorf("invalid certificate")
|
||||||
}
|
}
|
||||||
serial, _ := asn1IntegerBig(items[idx])
|
serial, err := asn1IntegerBig(items[idx])
|
||||||
subject := certificateNameValues(items[idx+4])
|
if err != nil {
|
||||||
issuer := certificateNameValues(items[idx+2])
|
return signatureCertificate{}, err
|
||||||
info := SignatureCertInfo{
|
|
||||||
Subject: certificateNameString(subject),
|
|
||||||
CommonName: certificateNameFirst(subject, "2.5.4.3"),
|
|
||||||
Organization: certificateNameFirst(subject, "2.5.4.10"),
|
|
||||||
Issuer: certificateNameString(issuer),
|
|
||||||
}
|
}
|
||||||
if serial != nil {
|
validity, err := parseCertificateValidity(items[idx+3])
|
||||||
info.SerialNumber = serial.String()
|
if err != nil {
|
||||||
|
return signatureCertificate{}, err
|
||||||
}
|
}
|
||||||
return info
|
alg, err := parseGBTAlgorithm(cert.SignatureAlgorithm)
|
||||||
|
if err != nil {
|
||||||
|
return signatureCertificate{}, err
|
||||||
|
}
|
||||||
|
if cert.SignatureValue.BitLength%8 != 0 {
|
||||||
|
return signatureCertificate{}, fmt.Errorf("invalid certificate signature")
|
||||||
|
}
|
||||||
|
return signatureCertificate{
|
||||||
|
Raw: append([]byte(nil), data...),
|
||||||
|
TBS: append([]byte(nil), cert.TBSCertificate.FullBytes...),
|
||||||
|
Issuer: append([]byte(nil), items[idx+2].FullBytes...),
|
||||||
|
IssuerValue: items[idx+2],
|
||||||
|
Subject: append([]byte(nil), items[idx+4].FullBytes...),
|
||||||
|
SubjectValue: items[idx+4],
|
||||||
|
Serial: serial,
|
||||||
|
NotBefore: validity[0],
|
||||||
|
NotAfter: validity[1],
|
||||||
|
SignatureAlg: alg,
|
||||||
|
Signature: append([]byte(nil), cert.SignatureValue.Bytes...),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseCertificateValidity 解析证书有效期
|
||||||
|
// 入参: raw 证书有效期ASN.1值
|
||||||
|
// 返回: [2]time.Time 生效和失效时间, error 错误信息
|
||||||
|
func parseCertificateValidity(raw asn1.RawValue) ([2]time.Time, error) {
|
||||||
|
items, ok := asn1Children(raw.Bytes)
|
||||||
|
if !ok || len(items) != 2 {
|
||||||
|
return [2]time.Time{}, fmt.Errorf("invalid certificate validity")
|
||||||
|
}
|
||||||
|
notBefore, err := asn1Time(items[0])
|
||||||
|
if err != nil {
|
||||||
|
return [2]time.Time{}, err
|
||||||
|
}
|
||||||
|
notAfter, err := asn1Time(items[1])
|
||||||
|
if err != nil {
|
||||||
|
return [2]time.Time{}, err
|
||||||
|
}
|
||||||
|
return [2]time.Time{notBefore, notAfter}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// asn1Time 解析ASN.1时间
|
||||||
|
// 入参: raw ASN.1原始值
|
||||||
|
// 返回: time.Time 时间, error 错误信息
|
||||||
|
func asn1Time(raw asn1.RawValue) (time.Time, error) {
|
||||||
|
var t time.Time
|
||||||
|
rest, err := asn1.Unmarshal(raw.FullBytes, &t)
|
||||||
|
if err != nil || len(rest) != 0 {
|
||||||
|
return time.Time{}, fmt.Errorf("invalid time")
|
||||||
|
}
|
||||||
|
return t, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// certificateNameValues 解析证书名称字段
|
// certificateNameValues 解析证书名称字段
|
||||||
|
|||||||
Reference in New Issue
Block a user