MAGIC - refactoring

This commit is contained in:
Emman 2021-06-28 11:20:47 +08:00
parent 99767f315f
commit bdc049b882
4 changed files with 144 additions and 62 deletions

1
go.mod
View File

@ -3,6 +3,7 @@ module github.com/emmansun/gmsm
go 1.14
require (
github.com/pkg/errors v0.9.1
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a
golang.org/x/sys v0.0.0-20210603125802-9665404d3644
)

View File

@ -603,3 +603,9 @@ func (z *zr) Read(dst []byte) (n int, err error) {
}
var zeroReader = &zr{}
// IsSM2PublicKey check if given public key is SM2 public key or not
func IsSM2PublicKey(publicKey interface{}) bool {
pub, ok := publicKey.(*ecdsa.PublicKey)
return ok && strings.EqualFold(P256().Params().Name, pub.Curve.Params().Name)
}

View File

@ -8,9 +8,11 @@ import (
"crypto/ed25519"
"crypto/elliptic"
"crypto/rsa"
"crypto/sha1"
"crypto/x509"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/pem"
"errors"
"fmt"
"io"
@ -207,6 +209,8 @@ type pkcs1PublicKey struct {
E int
}
const SM2WithSM3 x509.SignatureAlgorithm = 99
var signatureAlgorithmDetails = []struct {
algo x509.SignatureAlgorithm
name string
@ -231,6 +235,7 @@ var signatureAlgorithmDetails = []struct {
{x509.ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, x509.ECDSA, crypto.SHA384},
{x509.ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, x509.ECDSA, crypto.SHA512},
{x509.PureEd25519, "Ed25519", oidSignatureEd25519, x509.Ed25519, crypto.Hash(0) /* no pre-hashing */},
{SM2WithSM3, "SM2-SM3", oidSignatureSM2WithSM3, x509.ECDSA, crypto.Hash(0) /* no pre-hashing */},
}
// pssParameters reflects the parameters in an AlgorithmIdentifier that
@ -565,17 +570,7 @@ func (c *Certificate) CheckSignatureFrom(parent *Certificate) error {
// CheckSignature verifies that signature is a valid signature over signed from
// c's public key.
func (c *Certificate) CheckSignature(algo x509.SignatureAlgorithm, signed, signature []byte) error {
key, ok := c.PublicKey.(*ecdsa.PublicKey)
if !ok {
return c.Certificate.CheckSignature(algo, signed, signature)
}
if key.Curve != sm2.P256() {
return c.Certificate.CheckSignature(algo, signed, signature)
}
if !sm2.VerifyASN1WithSM2(key, nil, signed, signature) {
return errors.New("x509: SM2 verification failure")
}
return nil
return checkSignature(algo, signed, signature, c.PublicKey)
}
func (c *Certificate) hasNameConstraints() bool {
@ -591,6 +586,69 @@ func (c *Certificate) getSANExtension() []byte {
return nil
}
func signaturePublicKeyAlgoMismatchError(expectedPubKeyAlgo x509.PublicKeyAlgorithm, pubKey interface{}) error {
return fmt.Errorf("x509: signature algorithm specifies an %s public key, but have public key of type %T", expectedPubKeyAlgo.String(), pubKey)
}
// checkSignature verifies that signature is a valid signature over signed from
// a crypto.PublicKey.
func checkSignature(algo x509.SignatureAlgorithm, signed, signature []byte, publicKey crypto.PublicKey) (err error) {
var hashType crypto.Hash
var pubKeyAlgo x509.PublicKeyAlgorithm
isSM2 := (algo == SM2WithSM3)
for _, details := range signatureAlgorithmDetails {
if details.algo == algo {
hashType = details.hash
pubKeyAlgo = details.pubKeyAlgo
}
}
switch hashType {
case crypto.Hash(0):
if !isSM2 && pubKeyAlgo != x509.Ed25519 {
return x509.ErrUnsupportedAlgorithm
}
case crypto.MD5:
return x509.InsecureAlgorithmError(algo)
default:
if !hashType.Available() {
return x509.ErrUnsupportedAlgorithm
}
h := hashType.New()
h.Write(signed)
signed = h.Sum(nil)
}
switch pub := publicKey.(type) {
case *rsa.PublicKey:
if pubKeyAlgo != x509.RSA {
return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub)
}
if isRSAPSS(algo) {
return rsa.VerifyPSS(pub, hashType, signed, signature, &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash})
} else {
return rsa.VerifyPKCS1v15(pub, hashType, signed, signature)
}
case *ecdsa.PublicKey:
if pubKeyAlgo != x509.ECDSA {
return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub)
}
if (!isSM2 && !ecdsa.VerifyASN1(pub, signed, signature)) || !sm2.VerifyASN1WithSM2(pub, nil, signed, signature) {
return errors.New("x509: ECDSA verification failure")
}
case ed25519.PublicKey:
if pubKeyAlgo != x509.Ed25519 {
return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub)
}
if !ed25519.Verify(pub, signed, signature) {
return errors.New("x509: Ed25519 verification failure")
}
return
}
return x509.ErrUnsupportedAlgorithm
}
// CheckCRLSignature checks that the signature in crl is from c.
func (c *Certificate) CheckCRLSignature(crl *pkix.CertificateList) error {
algo := getSignatureAlgorithmFromAI(crl.SignatureAlgorithm)
@ -1239,6 +1297,14 @@ func ParseCertificate(asn1Data []byte) (*Certificate, error) {
return &Certificate{*result}, nil
}
func ParseCertificatePEM(data []byte) (*Certificate, error) {
block, _ := pem.Decode(data)
if block == nil {
return nil, errors.New("failed to decode PEM block containing CSR")
}
return ParseCertificate(block.Bytes)
}
// ParseCertificates parses one or more certificates from the given ASN.1 DER
// data. The certificates must be concatenated with no intermediate padding.
func ParseCertificates(asn1Data []byte) ([]*Certificate, error) {
@ -1707,7 +1773,7 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo x509.SignatureA
// just an empty SEQUENCE.
var emptyASN1Subject = []byte{0x30, 0}
// CreateCertificate creates a new X.509v3 certificate based on a template.
// CreateCertificate creates a new X.509 v3 certificate based on a template.
// The following members of template are used:
//
// - AuthorityKeyId
@ -1756,7 +1822,7 @@ var emptyASN1Subject = []byte{0x30, 0}
// The AuthorityKeyId will be taken from the SubjectKeyId of parent, if any,
// unless the resulting certificate is self-signed. Otherwise the value from
// template will be used.
func CreateCertificate(rand io.Reader, template, parent *x509.Certificate, pub, priv interface{}) (cert []byte, err error) {
func CreateCertificate(rand io.Reader, template, parent *x509.Certificate, pub, priv interface{}) ([]byte, error) {
key, ok := priv.(crypto.Signer)
if !ok {
return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
@ -1775,12 +1841,12 @@ func CreateCertificate(rand io.Reader, template, parent *x509.Certificate, pub,
asn1Issuer, err := subjectBytes(parent)
if err != nil {
return
return nil, err
}
asn1Subject, err := subjectBytes(template)
if err != nil {
return
return nil, err
}
authorityKeyId := template.AuthorityKeyId
@ -1788,9 +1854,29 @@ func CreateCertificate(rand io.Reader, template, parent *x509.Certificate, pub,
authorityKeyId = parent.SubjectKeyId
}
subjectKeyId := template.SubjectKeyId
if len(subjectKeyId) == 0 && template.IsCA {
// SubjectKeyId generated using method 1 in RFC 5280, Section 4.2.1.2:
// (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the
// value of the BIT STRING subjectPublicKey (excluding the tag,
// length, and number of unused bits).
h := sha1.Sum(publicKeyBytes)
subjectKeyId = h[:]
}
// Check that the signer's public key matches the private key, if available.
type privateKey interface {
Equal(crypto.PublicKey) bool
}
if privPub, ok := key.Public().(privateKey); !ok {
return nil, errors.New("x509: internal error: supported public key does not implement Equal")
} else if parent.PublicKey != nil && !privPub.Equal(parent.PublicKey) {
return nil, errors.New("x509: provided PrivateKey doesn't match parent's PublicKey")
}
extensions, err := buildExtensions(template, bytes.Equal(asn1Subject, emptyASN1Subject), authorityKeyId)
if err != nil {
return
return nil, err
}
encodedPublicKey := asn1.BitString{BitLength: len(publicKeyBytes) * 8, Bytes: publicKeyBytes}
@ -1807,7 +1893,7 @@ func CreateCertificate(rand io.Reader, template, parent *x509.Certificate, pub,
tbsCertContents, err := asn1.Marshal(c)
if err != nil {
return
return nil, err
}
c.Raw = tbsCertContents
@ -1830,15 +1916,27 @@ func CreateCertificate(rand io.Reader, template, parent *x509.Certificate, pub,
}
signature, err = key.Sign(rand, signed, signerOpts)
if err != nil {
return
return nil, err
}
return asn1.Marshal(certificate{
signedCert, err := asn1.Marshal(certificate{
nil,
c,
signatureAlgorithm,
asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
})
if err != nil {
return nil, err
}
// Check the signature to ensure the crypto.Signer behaved correctly.
// We skip this check if the signature algorithm is MD5WithRSA as we
// only support this algorithm for signing, and not verification.
if sigAlg := getSignatureAlgorithmFromAI(signatureAlgorithm); sigAlg != x509.MD5WithRSA {
if err := checkSignature(sigAlg, c.Raw, signature, key.Public()); err != nil {
return nil, fmt.Errorf("x509: signature over certificate returned by signer is invalid: %w", err)
}
}
return signedCert, nil
}
// ParseCRL parses a CRL from the given bytes. It's often the case that PEM
@ -2218,6 +2316,16 @@ func ParseCertificateRequest(asn1Data []byte) (*CertificateRequest, error) {
return parseCertificateRequest(&csr)
}
// ParseCertificateRequestPEM parses a single certificate request from the
// given PEM data.
func ParseCertificateRequestPEM(data []byte) (*CertificateRequest, error) {
block, _ := pem.Decode(data)
if block == nil {
return nil, errors.New("failed to decode PEM block containing CSR")
}
return ParseCertificateRequest(block.Bytes)
}
func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error) {
if !oidSignatureSM2WithSM3.Equal(in.SignatureAlgorithm.Algorithm) {
return nil, errors.New("unsupport signature algorithm")
@ -2268,30 +2376,9 @@ func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error
return out, nil
}
// CheckSignature reports whether the signature on c is valid.
func CheckSignature(c *x509.CertificateRequest) error {
if c.PublicKeyAlgorithm == x509.ECDSA {
pub, ok := c.PublicKey.(*ecdsa.PublicKey)
if ok && strings.EqualFold(sm2.P256().Params().Name, pub.Curve.Params().Name) {
return checkSignature(c, pub)
}
}
return c.CheckSignature()
}
// CheckSignature reports whether the signature on c is valid.
func (c *CertificateRequest) CheckSignature() error {
return CheckSignature(&c.CertificateRequest)
}
// checkSignature verifies that signature is a valid signature over signed from
// a crypto.PublicKey.
func checkSignature(c *x509.CertificateRequest, publicKey *ecdsa.PublicKey) (err error) {
signed := c.RawTBSCertificateRequest
if !sm2.VerifyASN1WithSM2(publicKey, nil, signed, c.Signature) {
return errors.New("x509: SM2 verification failure")
}
return
return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificateRequest, c.Signature, c.PublicKey)
}
// CreateRevocationList creates a new X.509 v2 Certificate Revocation List,

View File

@ -180,16 +180,8 @@ 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)
func parseAndCheckCsr(csrPem []byte) error {
csr, err := ParseCertificateRequestPEM(csrPem)
if err != nil {
return err
}
@ -198,7 +190,7 @@ func parseAndCheckCsr(csrblock []byte) error {
}
func Test_ParseCertificate(t *testing.T) {
cert, err := getCertificate([]byte(sm2Certificate))
cert, err := ParseCertificatePEM([]byte(sm2Certificate))
if err != nil {
t.Fatalf("%v\n", err)
}
@ -207,11 +199,7 @@ func Test_ParseCertificate(t *testing.T) {
}
func TestParseCertificateRequest(t *testing.T) {
block, _ := pem.Decode([]byte(csrFromAli))
if block == nil {
t.Fatal("Failed to parse PEM block")
}
err := parseAndCheckCsr(block.Bytes)
err := parseAndCheckCsr([]byte(csrFromAli))
if err != nil {
t.Fatal(err)
}
@ -221,7 +209,7 @@ func TestCreateCertificateRequest(t *testing.T) {
priv, _ := sm2.GenerateKey(rand.Reader)
names := pkix.Name{CommonName: "TestName"}
var template = x509.CertificateRequest{Subject: names}
var template = x509.CertificateRequest{Subject: names, SignatureAlgorithm: SM2WithSM3}
csrblock, err := CreateCertificateRequest(rand.Reader, &template, priv)
if err != nil {
t.Fatal(err)
@ -312,7 +300,7 @@ func Test_CreateCertificateRequest(t *testing.T) {
sigAlgo x509.SignatureAlgorithm
}{
{"RSA", testPrivateKey, x509.SHA1WithRSA},
{"SM2-256", sm2Priv, x509.UnknownSignatureAlgorithm},
{"SM2-256", sm2Priv, SM2WithSM3},
{"ECDSA-256", ecdsa256Priv, x509.ECDSAWithSHA1},
{"ECDSA-384", ecdsa384Priv, x509.ECDSAWithSHA1},
{"ECDSA-521", ecdsa521Priv, x509.ECDSAWithSHA1},
@ -405,17 +393,17 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
}{
{"RSA/RSA", &testPrivateKey.PublicKey, testPrivateKey, true, x509.SHA1WithRSA},
{"RSA/ECDSA", &testPrivateKey.PublicKey, ecdsaPriv, false, x509.ECDSAWithSHA384},
{"RSA/SM2", &testPrivateKey.PublicKey, sm2Priv, false, x509.UnknownSignatureAlgorithm},
{"RSA/SM2", &testPrivateKey.PublicKey, sm2Priv, false, SM2WithSM3},
{"ECDSA/RSA", &ecdsaPriv.PublicKey, testPrivateKey, false, x509.SHA256WithRSA},
{"ECDSA/ECDSA", &ecdsaPriv.PublicKey, ecdsaPriv, true, x509.ECDSAWithSHA1},
{"ECDSA/SM2", &ecdsaPriv.PublicKey, sm2Priv, false, x509.UnknownSignatureAlgorithm},
{"ECDSA/SM2", &ecdsaPriv.PublicKey, sm2Priv, false, SM2WithSM3},
{"SM2/ECDSA", &sm2Priv.PublicKey, ecdsaPriv, false, x509.ECDSAWithSHA1},
{"RSAPSS/RSAPSS", &testPrivateKey.PublicKey, testPrivateKey, true, x509.SHA256WithRSAPSS},
{"ECDSA/RSAPSS", &ecdsaPriv.PublicKey, testPrivateKey, false, x509.SHA256WithRSAPSS},
{"SM2/RSAPSS", &sm2Priv.PublicKey, testPrivateKey, false, x509.SHA256WithRSAPSS},
{"RSAPSS/ECDSA", &testPrivateKey.PublicKey, ecdsaPriv, false, x509.ECDSAWithSHA384},
{"Ed25519", ed25519Pub, ed25519Priv, true, x509.PureEd25519},
{"SM2", &sm2Priv.PublicKey, sm2Priv, true, x509.UnknownSignatureAlgorithm},
{"SM2", &sm2Priv.PublicKey, sm2Priv, true, SM2WithSM3},
}
testExtKeyUsage := []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}