sample_chain/common/signer/signer.go

276 lines
8.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)
}