From d8dc283187b5c73d833ac76afca4b7294fbde616 Mon Sep 17 00:00:00 2001 From: emmansun Date: Tue, 16 Feb 2021 10:17:46 +0800 Subject: [PATCH] MAGIC - use interface to avoid implementation dependency --- sm2/sm2.go | 5 +++++ smx509/x509.go | 46 ++++++++++++++++++++++++++------------------- smx509/x509_test.go | 38 ++++++++++++++++++++++++++++++++++++- 3 files changed, 69 insertions(+), 20 deletions(-) diff --git a/sm2/sm2.go b/sm2/sm2.go index 2e2db1b..81dce98 100644 --- a/sm2/sm2.go +++ b/sm2/sm2.go @@ -63,6 +63,11 @@ type EncrypterOpts struct { PointMarshalMode pointMarshalMode } +// Signer SM2 special signer +type Signer interface { + SignWithSM2(rand io.Reader, uid, msg []byte) ([]byte, error) +} + func (mode pointMarshalMode) mashal(curve elliptic.Curve, x, y *big.Int) []byte { switch mode { case MarshalCompressed: diff --git a/smx509/x509.go b/smx509/x509.go index 6008755..7acbca8 100644 --- a/smx509/x509.go +++ b/smx509/x509.go @@ -375,20 +375,16 @@ func CreateCertificateRequest(rand io.Reader, template *x509.CertificateRequest, if !ok { return nil, errors.New("x509: certificate private key does not implement crypto.Signer") } - privKey, ok := key.(*sm2.PrivateKey) - if !ok { - ecKey, ok := key.(*ecdsa.PrivateKey) - if !ok || ecKey.Curve != sm2.P256() { - return x509.CreateCertificateRequest(rand, template, priv) - } - privKey, _ = new(sm2.PrivateKey).FromECPrivateKey(ecKey) + var hashFunc crypto.Hash + var sigAlgo pkix.AlgorithmIdentifier + hashFunc, sigAlgo, err = signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm) + if err != nil { + return nil, err } - var sigAlgo = pkix.AlgorithmIdentifier{} - sigAlgo.Algorithm = oidSignatureSM2WithSM3 var publicKeyBytes []byte var publicKeyAlgorithm pkix.AlgorithmIdentifier - publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(key.Public().(*ecdsa.PublicKey)) + publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(key.Public()) if err != nil { return nil, err } @@ -520,8 +516,23 @@ func CreateCertificateRequest(rand io.Reader, template *x509.CertificateRequest, tbsCSR.Raw = tbsCSRContents signed := tbsCSRContents + var signature []byte + if sigAlgo.Algorithm.Equal(oidSignatureSM2WithSM3) { + if smKey, ok := priv.(sm2.Signer); ok { + signature, err = smKey.SignWithSM2(rand, nil, signed) + } else { + return nil, errors.New("x509: require sm2 private key") + } + } else { + if hashFunc != 0 { + h := hashFunc.New() + h.Write(signed) + signed = h.Sum(nil) + } + + signature, err = key.Sign(rand, signed, hashFunc) + } - signature, err := privKey.SignWithSM2(rand, nil, signed) if err != nil { return } @@ -1532,7 +1543,7 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo x509.SignatureA return } - if requestedSigAlgo == 0 { + if requestedSigAlgo == 0 || sigAlgo.Algorithm.Equal(oidSignatureSM2WithSM3) { return } @@ -1671,14 +1682,11 @@ func CreateCertificate(rand io.Reader, template, parent *x509.Certificate, pub, var signature []byte if signatureAlgorithm.Algorithm.Equal(oidSignatureSM2WithSM3) { - privKey, ok := key.(*sm2.PrivateKey) - if !ok { - ecKey, ok := key.(*ecdsa.PrivateKey) - if ok && ecKey.Curve == sm2.P256() { - privKey, _ = new(sm2.PrivateKey).FromECPrivateKey(ecKey) - } + if smKey, ok := priv.(sm2.Signer); ok { + signature, err = smKey.SignWithSM2(rand, nil, signed) + } else { + return nil, errors.New("x509: require sm2 private key") } - signature, err = privKey.SignWithSM2(rand, nil, signed) } else { if hashFunc != 0 { h := hashFunc.New() diff --git a/smx509/x509_test.go b/smx509/x509_test.go index 751f452..40728c8 100644 --- a/smx509/x509_test.go +++ b/smx509/x509_test.go @@ -12,6 +12,7 @@ import ( "encoding/asn1" "encoding/base64" "encoding/hex" + "encoding/json" "encoding/pem" "errors" "fmt" @@ -141,6 +142,24 @@ FOq7cMJvODRwvMin9HwNHijXKp8iikXoAnaEHi1kLR4JtSlxH5WKTnmHUWCa54ZA 9mDH0e5odhcdkMySkwc= -----END CERTIFICATE-----` +const sm2Certificate = ` +-----BEGIN CERTIFICATE----- +MIICiDCCAiygAwIBAgIQLaGmvQznbGJOY0t9ainQKjAMBggqgRzPVQGDdQUAMC4x +CzAJBgNVBAYTAkNOMQ4wDAYDVQQKDAVOUkNBQzEPMA0GA1UEAwwGUk9PVENBMB4X +DTEzMDkxMzA4MTAyNVoXDTMzMDkwODA4MTAyNVowNDELMAkGA1UEBhMCQ04xETAP +BgNVBAoMCFVuaVRydXN0MRIwEAYDVQQDDAlTSEVDQSBTTTIwWTATBgcqhkjOPQIB +BggqgRzPVQGCLQNCAAR90R+RLQZKVBDwhIRVJR28ovu1x3duw2yxaWaY6E3lUKDW +IsmAwMOqE71MW3gQOxm68QJfPy6JT4Evil10FwyAo4IBIjCCAR4wHwYDVR0jBBgw +FoAUTDKxl9kzG8SmBcHG5YtiW/CXdlgwDwYDVR0TAQH/BAUwAwEB/zCBugYDVR0f +BIGyMIGvMEGgP6A9pDswOTELMAkGA1UEBhMCQ04xDjAMBgNVBAoMBU5SQ0FDMQww +CgYDVQQLDANBUkwxDDAKBgNVBAMMA2FybDAqoCigJoYkaHR0cDovL3d3dy5yb290 +Y2EuZ292LmNuL2FybC9hcmwuY3JsMD6gPKA6hjhsZGFwOi8vbGRhcC5yb290Y2Eu +Z292LmNuOjM4OS9DTj1hcmwsT1U9QVJMLE89TlJDQUMsQz1DTjAOBgNVHQ8BAf8E +BAMCAQYwHQYDVR0OBBYEFIkxBJF7Q6qqmr+EHZuG7vC4cJmgMAwGCCqBHM9VAYN1 +BQADSAAwRQIhAIp7/3vva+ZxFePKdqkzdGoVyGsfGHhiLLQeKrCZQ2Q5AiAmMOdf +0f0b8CilrVWdi8pfZyO6RqYfnpcJ638l7KHfNA== +-----END CERTIFICATE-----` + var testPrivateKey *rsa.PrivateKey func init() { @@ -162,6 +181,14 @@ func getPublicKey(pemContent []byte) (interface{}, error) { return ParsePKIXPublicKey(block.Bytes) } +func getCertificate(pemContent []byte) (*Certificate, error) { + block, _ := pem.Decode(pemContent) + if block == nil { + return nil, errors.New("Failed to parse PEM block") + } + return ParseCertificate(block.Bytes) +} + func parseAndCheckCsr(csrblock []byte) error { csr, err := ParseCertificateRequest(csrblock) if err != nil { @@ -171,6 +198,15 @@ func parseAndCheckCsr(csrblock []byte) error { return csr.CheckSignature() } +func Test_ParseCertificate(t *testing.T) { + cert, err := getCertificate([]byte(sm2Certificate)) + if err != nil { + t.Fatalf("%v\n", err) + } + jsonContent, err := json.Marshal(cert) + fmt.Printf("%s\n", jsonContent) +} + func TestParseCertificateRequest(t *testing.T) { block, _ := pem.Decode([]byte(csrFromAli)) if block == nil { @@ -287,7 +323,7 @@ func Test_CreateCertificateRequest(t *testing.T) { sigAlgo x509.SignatureAlgorithm }{ {"RSA", testPrivateKey, x509.SHA1WithRSA}, - {"SM2-256", sm2Priv, -1}, + {"SM2-256", sm2Priv, x509.UnknownSignatureAlgorithm}, {"ECDSA-256", ecdsa256Priv, x509.ECDSAWithSHA1}, {"ECDSA-384", ecdsa384Priv, x509.ECDSAWithSHA1}, {"ECDSA-521", ecdsa521Priv, x509.ECDSAWithSHA1},