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/binary"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -113,10 +115,17 @@ func (r *Reader) SignatureStampPositions(stamps []SignatureStamp) ([]SignatureSt
|
||||
pages := signaturePageNumbers(doc)
|
||||
positions := make([]SignatureStampPosition, 0, len(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{
|
||||
ID: stamp.ID,
|
||||
Page: pages[stamp.PageRef],
|
||||
Page: page,
|
||||
PageID: stamp.PageRef,
|
||||
Boundary: stamp.Boundary,
|
||||
Box: box,
|
||||
@@ -125,6 +134,33 @@ func (r *Reader) SignatureStampPositions(stamps []SignatureStamp) ([]SignatureSt
|
||||
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 解析签名文件
|
||||
// 入参: doc 文档结构
|
||||
// 返回: error 错误信息
|
||||
|
||||
+70
-14
@@ -32,6 +32,9 @@ type digitalVerifyResult struct {
|
||||
DataHashOK bool
|
||||
SignedOK bool
|
||||
CertOK bool
|
||||
Cert []byte
|
||||
SignerCerts [][]byte
|
||||
Certs [][]byte
|
||||
CertInfo SignatureCertInfo
|
||||
}
|
||||
|
||||
@@ -61,17 +64,20 @@ type gbtSignerInfo struct {
|
||||
}
|
||||
|
||||
// verifyDigitalSignature 验证OFD数字签名
|
||||
// 入参: method 签名算法, signedValue 签名值, signedData 被签名原文, options 验证选项
|
||||
// 入参: method 签名算法, digestMethod 摘要算法, signedValue 签名值, signedData 被签名原文, options 验证选项
|
||||
// 返回: *digitalVerifyResult 验证结果, error 错误信息
|
||||
func verifyDigitalSignature(method string, signedValue, signedData []byte, options *signatureVerifyOptions) (*digitalVerifyResult, error) {
|
||||
if !isSM2SignatureMethod(method) {
|
||||
return nil, fmt.Errorf("unsupported signature method")
|
||||
}
|
||||
func verifyDigitalSignature(method, digestMethod string, signedValue, signedData []byte, options *signatureVerifyOptions) (*digitalVerifyResult, error) {
|
||||
if isGBT35275SignedValue(signedValue) {
|
||||
return verifyGBT35275SignedData(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数字签名
|
||||
// 入参: signedValue 签名值, signedData 被签名原文, options 验证选项
|
||||
@@ -87,6 +93,8 @@ func verifyRawDigitalSignature(signedValue, signedData []byte, options *signatur
|
||||
continue
|
||||
}
|
||||
result.CertOK = true
|
||||
result.Cert = cert
|
||||
result.SignerCerts = [][]byte{cert}
|
||||
result.CertInfo = signatureCertInfo(cert)
|
||||
if sm2VerifySignature(pub, nil, signedData, signedValue) {
|
||||
result.SignedOK = true
|
||||
@@ -96,6 +104,31 @@ func verifyRawDigitalSignature(signedValue, signedData []byte, options *signatur
|
||||
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签名值
|
||||
// 入参: signedValue 签名值, signedData 被签名原文, options 验证选项
|
||||
// 返回: *digitalVerifyResult 验证结果, error 错误信息
|
||||
@@ -113,16 +146,16 @@ func verifyGBT35275SignedData(signedValue, signedData []byte, options *signature
|
||||
if len(sd.Signers) == 0 {
|
||||
return nil, fmt.Errorf("invalid signed data signer info")
|
||||
}
|
||||
result := &digitalVerifyResult{}
|
||||
digest := signSM3(signedData)
|
||||
result := &digitalVerifyResult{Certs: sd.rawCerts()}
|
||||
for _, signer := range sd.Signers {
|
||||
digest, err := signatureDigest(signer.DigestAlg, signedData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(sd.ContentDigest) != 0 && !bytes.Equal(sd.ContentDigest, digest) {
|
||||
return result, nil
|
||||
}
|
||||
result.DataHashOK = true
|
||||
for _, signer := range sd.Signers {
|
||||
if !isSM3DigestMethod(signer.DigestAlg) {
|
||||
return nil, fmt.Errorf("unsupported digest method")
|
||||
}
|
||||
plain := sd.ContentDigest
|
||||
if len(signer.AuthAttrs) != 0 {
|
||||
if !bytes.Equal(signer.AttrDigest, digest) {
|
||||
@@ -138,10 +171,10 @@ func verifyGBT35275SignedData(signedValue, signedData []byte, options *signature
|
||||
if cert == nil {
|
||||
return result, nil
|
||||
}
|
||||
result.Cert = cert.Raw
|
||||
result.SignerCerts = append(result.SignerCerts, cert.Raw)
|
||||
result.CertInfo = signatureCertInfo(cert.Raw)
|
||||
if !isSM2SignatureMethod(signer.SignatureAlg) {
|
||||
return nil, fmt.Errorf("unsupported signature method")
|
||||
}
|
||||
if isSM2SignatureMethod(signer.SignatureAlg) {
|
||||
pub, err := parseSM2PublicKeyFromCert(cert.Raw)
|
||||
if err != nil {
|
||||
return result, err
|
||||
@@ -150,6 +183,19 @@ func verifyGBT35275SignedData(signedValue, signedData []byte, options *signature
|
||||
if !sm2VerifySignature(pub, nil, plain, signer.Signature) {
|
||||
return result, nil
|
||||
}
|
||||
continue
|
||||
}
|
||||
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 {
|
||||
return result, err
|
||||
}
|
||||
result.CertOK = true
|
||||
if !ok {
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
result.SignedOK = true
|
||||
return result, nil
|
||||
@@ -449,6 +495,16 @@ func (sd *gbtSignedData) findCert(issuer []byte, serial *big.Int) *gbtCertificat
|
||||
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 解析显式标签内容
|
||||
// 入参: raw ASN.1原始值
|
||||
// 返回: asn1.RawValue 标签内容, error 错误信息
|
||||
|
||||
+22
-7
@@ -71,6 +71,9 @@ type sesVerifyResult struct {
|
||||
CertOK bool
|
||||
SignCert SignatureCertInfo
|
||||
SealCert SignatureCertInfo
|
||||
SignCertRaw []byte
|
||||
SealCertRaw []byte
|
||||
Certs [][]byte
|
||||
SealType string
|
||||
}
|
||||
|
||||
@@ -169,9 +172,9 @@ func parseSESSignatureV1(items []asn1.RawValue) (*sesSignature, error) {
|
||||
}
|
||||
|
||||
// verifySESSignature 验证SES签章值
|
||||
// 入参: data 签章值数据, signedData 被签名数据原文
|
||||
// 入参: data 签章值数据, signedData 被签名数据原文, options 验证选项
|
||||
// 返回: *sesVerifyResult 验证结果, error 错误信息
|
||||
func verifySESSignature(data, signedData []byte) (*sesVerifyResult, error) {
|
||||
func verifySESSignature(data, signedData []byte, options *signatureVerifyOptions) (*sesVerifyResult, error) {
|
||||
sig, err := parseSESSignature(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -182,6 +185,10 @@ func verifySESSignature(data, signedData []byte) (*sesVerifyResult, error) {
|
||||
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)
|
||||
@@ -309,7 +316,7 @@ func parseSESHeaderVersion(raw asn1.RawValue) (int, error) {
|
||||
}
|
||||
|
||||
// parseSESCertList 解析印章证书列表
|
||||
// 入参: raw 印章属性信息
|
||||
// 入参: raw 印章属性信息, version 印章版本
|
||||
// 返回: sesCertList 证书列表, error 错误信息
|
||||
func parseSESCertList(raw asn1.RawValue, version int) (sesCertList, error) {
|
||||
items, ok := asn1Children(raw.Bytes)
|
||||
@@ -497,16 +504,24 @@ func signSM3(data []byte) []byte {
|
||||
// 入参: method 算法标识
|
||||
// 返回: bool 是否为SM2签名算法
|
||||
func isSM2SignatureMethod(method string) bool {
|
||||
method = strings.TrimSpace(method)
|
||||
return method == signMethodSM2SM3 || method == signMethodSM2SM3B || method == signMethodSM2Sign
|
||||
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 {
|
||||
method = strings.TrimSpace(method)
|
||||
return method == signDigestSM3 || method == signDigestSM3NoKey || method == signDigestSM3Key || method == "SM3"
|
||||
switch signatureMethodText(method) {
|
||||
case signDigestSM3, signDigestSM3NoKey, signDigestSM3Key, "SM3":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// sesCertInList 判断证书是否在印章证书列表中
|
||||
|
||||
+471
-19
@@ -16,15 +16,24 @@ package ofdgo
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rsa"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"crypto/subtle"
|
||||
"crypto/x509"
|
||||
"encoding/asn1"
|
||||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// SignatureVerifyReport 签名验证报告
|
||||
@@ -42,12 +51,17 @@ type SignatureVerifyReport struct {
|
||||
DigestMethod string
|
||||
References []SignatureReferenceVerify
|
||||
Stamps []SignatureStamp
|
||||
StampPositions []SignatureStampPosition
|
||||
DigestOK bool
|
||||
DataHashOK bool
|
||||
SignedValueOK bool
|
||||
SealOK bool
|
||||
SealMatchOK bool
|
||||
CertOK bool
|
||||
CertTimeChecked bool
|
||||
CertTimeOK bool
|
||||
CertTrustChecked bool
|
||||
CertTrustOK bool
|
||||
Valid bool
|
||||
Error string
|
||||
}
|
||||
@@ -59,6 +73,8 @@ type SignatureCertInfo struct {
|
||||
Organization string
|
||||
Issuer string
|
||||
SerialNumber string
|
||||
NotBefore time.Time
|
||||
NotAfter time.Time
|
||||
}
|
||||
|
||||
// SignatureReferenceVerify 签名保护文件验证结果
|
||||
@@ -74,6 +90,8 @@ type SignatureReferenceVerify struct {
|
||||
// signatureVerifyOptions 签名验证选项
|
||||
type signatureVerifyOptions struct {
|
||||
SignCerts [][]byte
|
||||
TrustCerts [][]byte
|
||||
VerifyTime *time.Time
|
||||
}
|
||||
|
||||
// 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字节数据签名
|
||||
// 入参: data OFD字节数据, opts 签名验证选项
|
||||
// 返回: []SignatureVerifyReport 签名验证报告, error 错误信息
|
||||
@@ -186,6 +233,11 @@ func (r *Reader) verifySignature(sigListPath string, sigRef Signature, options *
|
||||
report.DigestMethod = sigFile.SignedInfo.References.CheckMethod
|
||||
report.References = r.verifySignatureReferences(sigPath, sigFile.SignedInfo.References)
|
||||
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)
|
||||
signedValuePath := signatureRefPath(sigPath, sigFile.SignedValue)
|
||||
signedValue, err := r.readFileExact(signedValuePath)
|
||||
@@ -195,7 +247,7 @@ func (r *Reader) verifySignature(sigListPath string, sigRef Signature, options *
|
||||
}
|
||||
switch sigRef.Type {
|
||||
case SignTypeSign:
|
||||
result, err := verifyDigitalSignature(report.SignatureMethod, signedValue, sigData, options)
|
||||
result, err := verifyDigitalSignature(report.SignatureMethod, report.DigestMethod, signedValue, sigData, options)
|
||||
if err != nil {
|
||||
report.Error = err.Error()
|
||||
return report
|
||||
@@ -206,14 +258,15 @@ func (r *Reader) verifySignature(sigListPath string, sigRef Signature, options *
|
||||
report.CertOK = result.CertOK
|
||||
report.SignCert = result.CertInfo
|
||||
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
|
||||
case "", SignTypeSeal:
|
||||
default:
|
||||
report.Error = fmt.Sprintf("unsupported signature type: %s", sigRef.Type)
|
||||
return report
|
||||
}
|
||||
sesResult, err := verifySESSignature(signedValue, sigData)
|
||||
sesResult, err := verifySESSignature(signedValue, sigData, options)
|
||||
if sesResult != nil {
|
||||
report.SignCert = sesResult.SignCert
|
||||
report.SealCert = sesResult.SealCert
|
||||
@@ -228,6 +281,7 @@ func (r *Reader) verifySignature(sigListPath string, sigRef Signature, options *
|
||||
report.SignedValueOK = sesResult.SignedOK
|
||||
report.SealOK = sesResult.SealOK
|
||||
report.CertOK = sesResult.CertOK
|
||||
report.applySignatureCertificatePolicy(options, [][]byte{sesResult.SignCertRaw, sesResult.SealCertRaw}, sesResult.Certs)
|
||||
if sigFile.SignedInfo.Seal.BaseLoc != "" {
|
||||
sealPath := signatureRefPath(sigPath, sigFile.SignedInfo.Seal.BaseLoc)
|
||||
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.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
|
||||
}
|
||||
|
||||
@@ -321,9 +375,190 @@ func signatureDigest(method string, data []byte) ([]byte, error) {
|
||||
if isSM3DigestMethod(method) {
|
||||
return signSM3(data), nil
|
||||
}
|
||||
if h, ok := signatureDigestHash(method); ok {
|
||||
return signatureHashBytes(h, data), nil
|
||||
}
|
||||
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 解析签名文件引用路径
|
||||
// 入参: basePath 基准路径, refPath 引用路径
|
||||
// 返回: string 包内文件路径
|
||||
@@ -351,6 +586,138 @@ func referencesOK(refs []SignatureReferenceVerify) bool {
|
||||
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元素原始字节
|
||||
// 入参: data XML数据, localName 元素名称
|
||||
// 返回: []byte 元素原始字节, error 错误信息
|
||||
@@ -395,6 +762,45 @@ func xmlElementRaw(data []byte, localName string) ([]byte, error) {
|
||||
// 入参: data DER编码证书
|
||||
// 返回: 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 {
|
||||
TBSCertificate asn1.RawValue
|
||||
SignatureAlgorithm asn1.RawValue
|
||||
@@ -402,32 +808,78 @@ func signatureCertInfo(data []byte) SignatureCertInfo {
|
||||
}
|
||||
rest, err := asn1.Unmarshal(data, &cert)
|
||||
if err != nil || len(rest) != 0 {
|
||||
return SignatureCertInfo{}
|
||||
return signatureCertificate{}, fmt.Errorf("invalid certificate")
|
||||
}
|
||||
items, ok := asn1Children(cert.TBSCertificate.Bytes)
|
||||
if !ok {
|
||||
return SignatureCertInfo{}
|
||||
return signatureCertificate{}, 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+4 {
|
||||
return SignatureCertInfo{}
|
||||
if len(items) <= idx+5 {
|
||||
return signatureCertificate{}, fmt.Errorf("invalid certificate")
|
||||
}
|
||||
serial, _ := asn1IntegerBig(items[idx])
|
||||
subject := certificateNameValues(items[idx+4])
|
||||
issuer := certificateNameValues(items[idx+2])
|
||||
info := SignatureCertInfo{
|
||||
Subject: certificateNameString(subject),
|
||||
CommonName: certificateNameFirst(subject, "2.5.4.3"),
|
||||
Organization: certificateNameFirst(subject, "2.5.4.10"),
|
||||
Issuer: certificateNameString(issuer),
|
||||
serial, err := asn1IntegerBig(items[idx])
|
||||
if err != nil {
|
||||
return signatureCertificate{}, err
|
||||
}
|
||||
if serial != nil {
|
||||
info.SerialNumber = serial.String()
|
||||
validity, err := parseCertificateValidity(items[idx+3])
|
||||
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 解析证书名称字段
|
||||
|
||||
Reference in New Issue
Block a user