package signer import ( "crypto" "crypto/ecdsa" "crypto/rand" "crypto/sha256" "crypto/x509" "encoding/asn1" "encoding/pem" "math/big" "os" "strings" pb "schain/proto" "schain/proto/util" "github.com/pkg/errors" ) // Config 用户签名的配置(里面包含MSPID 用户属于那个组织,IdentityPath 用户证书的地址,KeyPath 用户密钥的地址) type Config struct { MSPID string IdentityPath string KeyPath string } // Signer 用户的签名,包含公钥、私钥和用户的身份 type Signer struct { privateKey *ecdsa.PrivateKey publicKeyKey *ecdsa.PublicKey creator []byte } type ECDSASignature struct { R, S *big.Int } // NewSigner 根据配置创建一个用户签名 func NewSigner(conf *Config) (*Signer, error) { sId, err := serializeIdentity(conf.IdentityPath, conf.MSPID) if err != nil { return nil, errors.WithStack(err) } //加载私钥 privateKey, err := loadPrivateKey(conf.KeyPath) if err != nil { return nil, errors.WithStack(err) } //加载公钥,需要先调取用户证书,再从证书中获取公钥 publicKey, err := loadPublicKey(conf.IdentityPath) if err != nil { return nil, errors.WithStack(err) } return &Signer{ creator: sId, privateKey: privateKey, publicKeyKey: publicKey, }, nil } // 序列化身份,客户端证书和组织id func serializeIdentity(clientCert string, mspID string) ([]byte, error) { //获取证书并返回证书里的内容b b, err := os.ReadFile(clientCert) if err != nil { return nil, errors.WithStack(err) } if err := validateEnrollmentCertificate(b); err != nil { return nil, err } //Decode将在输入中找到下一个PEM格式的块(证书、私钥等)。它返回该块和输入的其余部分。 /*pem格式中的块数据 pem.Block type Block struct { Type string // 类型,如 "CERTIFICATE"、"PRIVATE KEY"、"PUBLIC KEY" 等 Headers map[string]string // 标题,如 "Proc-Type"、"DEK-Info" 等 Bytes []byte // 数据部分的字节切片 }*/ bl, _ := pem.Decode(b) if bl == nil { return nil, err } //从给定的ASN.1 DER数据中解析单个证书,证书结构体如下 /*type Certificate struct { Raw []byte // 完整的 DER 编码证书数据 RawTBSCertificate []byte // 证书内容的 DER 编码(不包含签名) RawSubjectPublicKeyInfo []byte // 主体公钥的 DER 编码 RawSubject []byte // 主体字段的 DER 编码 RawIssuer []byte // 颁发者字段的 DER 编码 SignatureAlgorithm SignatureAlgorithm // 签名算法 PublicKeyAlgorithm PublicKeyAlgorithm // 公钥算法 PublicKey interface{} // 公钥 Version int // 证书版本号 SerialNumber *big.Int // 序列号 Issuer pkix.Name // 颁发者 Subject pkix.Name // 主体 NotBefore time.Time // 有效期开始时间 NotAfter time.Time // 有效期结束时间 KeyUsage KeyUsage // 密钥用途 ExtKeyUsage []ExtKeyUsage // 扩展密钥用途 UnknownExtKeyUsage []asn1.ObjectIdentifier // 未知的扩展密钥用途 BasicConstraintsValid bool // 是否启用基本约束验证 IsCA bool // 是否是证书颁发机构 MaxPathLen int // 最大路径长度约束 MaxPathLenZero bool // 最大路径长度约束是否为零 SubjectKeyId []byte // 主体密钥标识符 AuthorityKeyId []byte // 颁发者密钥标识符 OCSPServer []string // OCSP 服务器列表 IssuingCertificateURL []string // 颁发者证书 URL 列表 DNSNames []string // 域名列表 EmailAddresses []string // 电子邮件地址列表 IPAddresses []net.IP // IP 地址列表 URIs []string // 统一资源标识符列表 PermittedDNSDomainsCritical bool // 允许的 DNS 域名是否为关键扩展 PermittedDNSDomains []string // 允许的 DNS 域名列表 CRLDistributionPointsCritical bool // CRL 分发点是否为关键扩展 CRLDistributionPoints []string // CRL 分发点列表 PolicyIdentifiers []asn1.ObjectIdentifier // 策略标识符 // ... 其他字段 }*/ key, err := x509.ParseCertificate(bl.Bytes) if err != nil { return nil, err } //将公钥对象转换为 DER 编码的 PKIX //(Public-Key Infrastructure Cross-Certificate Interoperability Specification)公钥格式的字节切片 publicKeyBytes, err := x509.MarshalPKIXPublicKey(key.PublicKey) if err != nil { return nil, err } sId := &pb.Creator{ Mspid: mspID, IdBytes: publicKeyBytes, } return util.MarshalOrPanic(sId), nil } // 验证注册证书 func validateEnrollmentCertificate(b []byte) error { bl, _ := pem.Decode(b) if bl == nil { return errors.Errorf("enrollment certificate isn't a valid PEM block") } if bl.Type != "CERTIFICATE" { return errors.Errorf("enrollment certificate should be a certificate, got a %s instead", strings.ToLower(bl.Type)) } //从给定的ASN.1 DER数据中解析单个证书 if _, err := x509.ParseCertificate(bl.Bytes); err != nil { return errors.Errorf("enrollment certificate is not a valid x509 certificate: %v", err) } return nil } func (si *Signer) Serialize() ([]byte, error) { return si.creator, nil } // 返回一个长度为 32 的字节数组,表示计算得到的 SHA256 校验和 func (si *Signer) Sign(msg []byte) ([]byte, error) { digest := sha256.Sum256(msg) return signECDSA(si.privateKey, digest[:]) } // 验证 ECDSA 签名 func (si *Signer) Verify(signature, msg []byte) bool { //计算消息的哈希值 digest := sha256.Sum256(msg) return verifyECDSA(si.publicKeyKey, signature, digest[:]) } // Verify 验证签名是否正确 func Verify(creatorBytes []byte, signature, msg []byte) error { creator, err := util.UnmarshalCreator(creatorBytes) if err != nil { return err } publicKey, err := x509.ParsePKIXPublicKey(creator.IdBytes) if err != nil { return err } publicKeyKey := publicKey.(*ecdsa.PublicKey) digest := sha256.Sum256(msg) if !verifyECDSA(publicKeyKey, signature, digest[:]) { return errors.New("verifySignature error") } return nil } // 根据文件加载用户的私钥 func loadPrivateKey(file string) (*ecdsa.PrivateKey, error) { b, err := os.ReadFile(file) if err != nil { return nil, errors.WithStack(err) } bl, _ := pem.Decode(b) if bl == nil { return nil, errors.Errorf("failed to decode PEM block from %s", file) } key, err := parsePrivateKey(bl.Bytes) if err != nil { return nil, err } return key.(*ecdsa.PrivateKey), nil } // 根据文件加载用户的公钥 func loadPublicKey(file string) (*ecdsa.PublicKey, error) { b, err := os.ReadFile(file) if err != nil { return nil, errors.WithStack(err) } bl, _ := pem.Decode(b) if bl == nil { return nil, errors.Errorf("failed to decode PEM block from %s", file) } key, err := x509.ParseCertificate(bl.Bytes) if err != nil { return nil, err } publicKey := key.PublicKey return publicKey.(*ecdsa.PublicKey), nil } func parsePrivateKey(der []byte) (crypto.PrivateKey, error) { // OpenSSL 1.0.0 generates PKCS#8 keys. if key, err := x509.ParsePKCS8PrivateKey(der); err == nil { switch key := key.(type) { // Fabric only supports ECDSA at the moment. case *ecdsa.PrivateKey: return key, nil default: return nil, errors.Errorf("found unknown private key type (%T) in PKCS#8 wrapping", key) } } // OpenSSL ecparam generates SEC1 EC private keys for ECDSA. key, err := x509.ParseECPrivateKey(der) if err != nil { return nil, errors.Errorf("failed to parse private key: %v", err) } return key, nil } func signECDSA(k *ecdsa.PrivateKey, digest []byte) (signature []byte, err error) { r, s, err := ecdsa.Sign(rand.Reader, k, digest) if err != nil { return nil, err } return asn1.Marshal(ECDSASignature{R: r, S: s}) } func verifyECDSA(pubKey *ecdsa.PublicKey, signature, digest []byte) bool { // 解析 ASN.1 编码的签名数据 var sig ECDSASignature _, err := asn1.Unmarshal(signature, &sig) if err != nil { return false } // 使用 ECDSA 签名算法对消息的哈希值进行验证 return ecdsa.Verify(pubKey, digest, sig.R, sig.S) }