mirror of
https://github.com/emmansun/gmsm.git
synced 2025-04-21 17:56:19 +08:00
MAGIC - refactoring
This commit is contained in:
parent
99767f315f
commit
bdc049b882
1
go.mod
1
go.mod
@ -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
|
||||
)
|
||||
|
@ -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)
|
||||
}
|
||||
|
169
smx509/x509.go
169
smx509/x509.go
@ -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,
|
||||
|
@ -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}
|
||||
|
Loading…
x
Reference in New Issue
Block a user