pkcs7: remove deprecated method SignWithSM2

This commit is contained in:
Sun Yimin 2024-12-19 15:42:19 +08:00 committed by GitHub
parent 6b18205bba
commit d199697b20
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 89 additions and 53 deletions

View File

@ -306,6 +306,24 @@ func calculateSM2Hash(pub *ecdsa.PublicKey, data, uid []byte) ([]byte, error) {
``` ```
公钥加密就没啥特殊只要确保输出密文的编码格式和KMS一致即可。 公钥加密就没啥特殊只要确保输出密文的编码格式和KMS一致即可。
## 基于密码硬件定制SM2私钥
密码硬件SDF/SKF中的私钥通常是无法导出的但通常提供了签名、解密APIs供调用为了和本软件库集成通常需要自定义实现以下接口
1. `crypto.Signer`,这个接口的实现通常把传入的数据作为哈希值。
2. `crypto.Decrypter`,这个接口用于解密操作。
通常需要实现四个方法:
1. `Public() crypto.PublicKey`
2. `Sign(rand io.Reader, digest []byte, opts SignerOpts) (signature []byte, err error)`
3. `Decrypt(rand io.Reader, msg []byte, opts DecrypterOpts) (plaintext []byte, err error)`
第一个返回公钥的方法是必须要实现的后面的方法取决于这个KEY的用途。
**注意**
`Sign(rand io.Reader, digest []byte, opts SignerOpts) (signature []byte, err error)`方法通常用于对哈希值作签名,最好遵从以下实现逻辑:检查`opts`是否是`*sm2.SM2SignerOption`类型,如果是,则把传入的`digest`作为原始数据进行处理,具体实现可以参考`sm2.SignASN1`函数。当然,目前不管三七二十一,简单当作原始数据大多数情况下都没有问题。实现者可以根据实际应用情况酌情处理。
如果密码硬件有自己的随机数源,可以忽略传入的`rand`
## SM2扩展应用 ## SM2扩展应用
SM2的一些扩展应用譬如从签名中恢复公钥、半同态加密、环签名等大多尚处于POC状态也无相关标准。其它扩展应用但凡椭圆曲线公钥密码算法能用到的场合包括但不限于 SM2的一些扩展应用譬如从签名中恢复公钥、半同态加密、环签名等大多尚处于POC状态也无相关标准。其它扩展应用但凡椭圆曲线公钥密码算法能用到的场合包括但不限于
* [确定性签名](https://datatracker.ietf.org/doc/html/rfc6979) * [确定性签名](https://datatracker.ietf.org/doc/html/rfc6979)

View File

@ -19,12 +19,12 @@ import (
// SignedData is an opaque data structure for creating signed data payloads // SignedData is an opaque data structure for creating signed data payloads
type SignedData struct { type SignedData struct {
sd signedData sd signedData
certs []*smx509.Certificate certs []*smx509.Certificate
data, messageDigest []byte data []byte
contentTypeOid asn1.ObjectIdentifier contentTypeOid asn1.ObjectIdentifier
digestOid asn1.ObjectIdentifier digestOid asn1.ObjectIdentifier
encryptionOid asn1.ObjectIdentifier encryptionOid asn1.ObjectIdentifier
} }
// NewSignedData takes data and initializes a PKCS7 SignedData struct that is // NewSignedData takes data and initializes a PKCS7 SignedData struct that is
@ -167,30 +167,11 @@ func (sd *SignedData) AddSignerChain(ee *smx509.Certificate, pkey crypto.Private
sd.sd.DigestAlgorithmIdentifiers = append(sd.sd.DigestAlgorithmIdentifiers, sd.sd.DigestAlgorithmIdentifiers = append(sd.sd.DigestAlgorithmIdentifiers,
pkix.AlgorithmIdentifier{Algorithm: sd.digestOid, Parameters: asn1.NullRawValue}, pkix.AlgorithmIdentifier{Algorithm: sd.digestOid, Parameters: asn1.NullRawValue},
) )
hasher, err := getHashForOID(sd.digestOid)
if err != nil {
return err
}
h := newHash(hasher, sd.digestOid)
h.Write(sd.data)
sd.messageDigest = h.Sum(nil)
encryptionOid, err := getOIDForEncryptionAlgorithm(pkey, sd.digestOid) encryptionOid, err := getOIDForEncryptionAlgorithm(pkey, sd.digestOid)
if err != nil { if err != nil {
return err return err
} }
attrs := &attributes{} finalAttrs, signature, err := sd.signWithAttributes(pkey, config)
attrs.Add(OIDAttributeContentType, sd.sd.ContentInfo.ContentType)
attrs.Add(OIDAttributeMessageDigest, sd.messageDigest)
attrs.Add(OIDAttributeSigningTime, time.Now().UTC())
for _, attr := range config.ExtraSignedAttributes {
attrs.Add(attr.Type, attr.Value)
}
finalAttrs, err := attrs.ForMarshalling()
if err != nil {
return err
}
// create signature of signed attributes
signature, err := signAttributes(finalAttrs, pkey, hasher)
if err != nil { if err != nil {
return err return err
} }
@ -216,6 +197,34 @@ func (sd *SignedData) AddSignerChain(ee *smx509.Certificate, pkey crypto.Private
return nil return nil
} }
func (sd *SignedData) signWithAttributes(pkey crypto.PrivateKey, config SignerInfoConfig) ([]attribute, []byte, error) {
hasher, err := getHashForOID(sd.digestOid)
if err != nil {
return nil, nil, err
}
h := newHash(hasher, sd.digestOid)
h.Write(sd.data)
messageDigest := h.Sum(nil)
attrs := &attributes{}
attrs.Add(OIDAttributeContentType, sd.sd.ContentInfo.ContentType)
attrs.Add(OIDAttributeMessageDigest, messageDigest)
attrs.Add(OIDAttributeSigningTime, time.Now().UTC())
for _, attr := range config.ExtraSignedAttributes {
attrs.Add(attr.Type, attr.Value)
}
finalAttrs, err := attrs.ForMarshalling()
if err != nil {
return nil, nil, err
}
// create signature of signed attributes
signature, err := signAttributes(finalAttrs, pkey, hasher)
if err != nil {
return nil, nil, err
}
return finalAttrs, signature, nil
}
func newHash(hasher crypto.Hash, hashOid asn1.ObjectIdentifier) hash.Hash { func newHash(hasher crypto.Hash, hashOid asn1.ObjectIdentifier) hash.Hash {
var h hash.Hash var h hash.Hash
if hashOid.Equal(OIDDigestAlgorithmSM3) || hashOid.Equal(OIDDigestAlgorithmSM2SM3) { if hashOid.Equal(OIDDigestAlgorithmSM3) || hashOid.Equal(OIDDigestAlgorithmSM2SM3) {
@ -240,20 +249,7 @@ func (sd *SignedData) SignWithoutAttr(ee *smx509.Certificate, pkey crypto.Privat
if err != nil { if err != nil {
return err return err
} }
key, ok := pkey.(crypto.Signer) if signature, err = signData(sd.data, pkey, hasher); err != nil {
if !ok {
return errors.New("pkcs7: private key does not implement crypto.Signer")
}
_, isSM2 := pkey.(sm2.Signer)
if isSM2 {
signature, err = key.Sign(rand.Reader, sd.data, sm2.DefaultSM2SignerOpts)
} else {
h := newHash(hasher, sd.digestOid)
h.Write(sd.data)
sd.messageDigest = h.Sum(nil)
signature, err = key.Sign(rand.Reader, sd.messageDigest, hasher)
}
if err != nil {
return err return err
} }
var ias issuerAndSerial var ias issuerAndSerial
@ -380,20 +376,33 @@ func signAttributes(attrs []attribute, pkey crypto.PrivateKey, hasher crypto.Has
if err != nil { if err != nil {
return nil, err return nil, err
} }
return signData(attrBytes, pkey, hasher)
}
if key, ok := pkey.(sm2.Signer); ok { // signData signs the provided data using the given private key and hash function.
return key.SignWithSM2(rand.Reader, nil, attrBytes) // It returns the signed data or an error if the signing process fails.
} func signData(data []byte, pkey crypto.PrivateKey, hasher crypto.Hash) ([]byte, error) {
h := hasher.New()
h.Write(attrBytes)
hash := h.Sum(nil)
key, ok := pkey.(crypto.Signer) key, ok := pkey.(crypto.Signer)
if !ok { if !ok {
return nil, errors.New("pkcs7: private key does not implement crypto.Signer") return nil, errors.New("pkcs7: private key does not implement crypto.Signer")
} }
return key.Sign(rand.Reader, hash, hasher) hash := data
var opts crypto.SignerOpts = hasher
if !hasher.Available() {
// if you pass a private key with type *ecdsa.PrivateKey and the curve is SM2,
// you will get unexpected signature.
if sm2.IsSM2PublicKey(key.Public()) {
opts = sm2.DefaultSM2SignerOpts
} else {
return nil, fmt.Errorf("pkcs7: unsupported hash function %s", hasher)
}
} else {
h := hasher.New()
h.Write(data)
hash = h.Sum(nil)
}
return key.Sign(rand.Reader, hash, opts)
} }
// concats and wraps the certificates in the RawValue structure // concats and wraps the certificates in the RawValue structure

View File

@ -87,6 +87,7 @@ func testSign(t *testing.T, isSM bool, content []byte, sigalgs []x509.SignatureA
} }
} }
} }
func TestSign(t *testing.T) { func TestSign(t *testing.T) {
content := []byte("Hello World") content := []byte("Hello World")
sigalgs := []x509.SignatureAlgorithm{ sigalgs := []x509.SignatureAlgorithm{

View File

@ -25,8 +25,17 @@ import (
// should be performed. // should be performed.
var directSigning crypto.Hash = 0 var directSigning crypto.Hash = 0
// Signer SM2 special signer // Signer is an interface for an opaque private key that can be used for
// signing operations. For example, an SM2 key kept in a hardware module.
// Deprecated: please use crypto.Signer directly.
type Signer interface { type Signer interface {
// Public returns the public key corresponding to the opaque,
// private key.
Public() crypto.PublicKey
// SignWithSM2 signs raw message with the private key, possibly using entropy from
// rand, and the user ID (UID). If the UID is not provided, a default UID (1234567812345678) is used.
// The signature is generated using the SM2 algorithm.
SignWithSM2(rand io.Reader, uid, msg []byte) ([]byte, error) SignWithSM2(rand io.Reader, uid, msg []byte) ([]byte, error)
} }
@ -251,8 +260,8 @@ func bigIntToBytes(curve elliptic.Curve, value *big.Int) []byte {
} }
// CalculateSM2Hash calculates the SM2 hash for the given public key, data, and user ID (UID). // CalculateSM2Hash calculates the SM2 hash for the given public key, data, and user ID (UID).
// If the UID is not provided, a default UID (1234567812345678) is used. // If the UID is not provided, a default UID (1234567812345678) is used.
// The public key must be valid, otherwise will be panic. // The public key must be valid, otherwise will be panic.
// This function is used to calculate the hash value for SM2 signature. // This function is used to calculate the hash value for SM2 signature.
func CalculateSM2Hash(pub *ecdsa.PublicKey, data, uid []byte) ([]byte, error) { func CalculateSM2Hash(pub *ecdsa.PublicKey, data, uid []byte) ([]byte, error) {
if len(uid) == 0 { if len(uid) == 0 {
@ -650,7 +659,6 @@ func randomPoint(c *sm2Curve, rand io.Reader, checkOrderMinus1 bool) (k *bigmod.
// randomPoint rejects a candidate for being higher than the modulus. // randomPoint rejects a candidate for being higher than the modulus.
var testingOnlyRejectionSamplingLooped func() var testingOnlyRejectionSamplingLooped func()
// RecoverPublicKeysFromSM2Signature attempts to recover the public keys from an SM2 signature. // RecoverPublicKeysFromSM2Signature attempts to recover the public keys from an SM2 signature.
// This function takes a hash and a signature as input and returns a slice of possible public keys // This function takes a hash and a signature as input and returns a slice of possible public keys
// that could have generated the given signature. // that could have generated the given signature.