golang version 1.4 is no longer supported

This commit is contained in:
Emman 2021-12-02 17:14:50 +08:00
parent db223b3c7f
commit aff4830dd8
3 changed files with 465 additions and 117 deletions

2
go.mod
View File

@ -1,6 +1,6 @@
module github.com/emmansun/gmsm module github.com/emmansun/gmsm
go 1.14 go 1.15
require ( require (
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871

View File

@ -238,6 +238,19 @@ var signatureAlgorithmDetails = []struct {
{SM2WithSM3, "SM2-SM3", oidSignatureSM2WithSM3, x509.ECDSA, crypto.Hash(0) /* no pre-hashing */}, {SM2WithSM3, "SM2-SM3", oidSignatureSM2WithSM3, x509.ECDSA, crypto.Hash(0) /* no pre-hashing */},
} }
// hashToPSSParameters contains the DER encoded RSA PSS parameters for the
// SHA256, SHA384, and SHA512 hashes as defined in RFC 3447, Appendix A.2.3.
// The parameters contain the following values:
// * hashAlgorithm contains the associated hash identifier with NULL parameters
// * maskGenAlgorithm always contains the default mgf1SHA1 identifier
// * saltLength contains the length of the associated hash
// * trailerField always contains the default trailerFieldBC value
var hashToPSSParameters = map[crypto.Hash]asn1.RawValue{
crypto.SHA256: asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 162, 3, 2, 1, 32}},
crypto.SHA384: asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 162, 3, 2, 1, 48}},
crypto.SHA512: asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 162, 3, 2, 1, 64}},
}
// pssParameters reflects the parameters in an AlgorithmIdentifier that // pssParameters reflects the parameters in an AlgorithmIdentifier that
// specifies RSA PSS. See RFC 3447, Appendix A.2.3. // specifies RSA PSS. See RFC 3447, Appendix A.2.3.
type pssParameters struct { type pssParameters struct {
@ -250,51 +263,6 @@ type pssParameters struct {
TrailerField int `asn1:"optional,explicit,tag:3,default:1"` TrailerField int `asn1:"optional,explicit,tag:3,default:1"`
} }
// rsaPSSParameters returns an asn1.RawValue suitable for use as the Parameters
// in an AlgorithmIdentifier that specifies RSA PSS.
func rsaPSSParameters(hashFunc crypto.Hash) asn1.RawValue {
var hashOID asn1.ObjectIdentifier
switch hashFunc {
case crypto.SHA256:
hashOID = oidSHA256
case crypto.SHA384:
hashOID = oidSHA384
case crypto.SHA512:
hashOID = oidSHA512
}
params := pssParameters{
Hash: pkix.AlgorithmIdentifier{
Algorithm: hashOID,
Parameters: asn1.NullRawValue,
},
MGF: pkix.AlgorithmIdentifier{
Algorithm: oidMGF1,
},
SaltLength: hashFunc.Size(),
TrailerField: 1,
}
mgf1Params := pkix.AlgorithmIdentifier{
Algorithm: hashOID,
Parameters: asn1.NullRawValue,
}
var err error
params.MGF.Parameters.FullBytes, err = asn1.Marshal(mgf1Params)
if err != nil {
panic(err)
}
serialized, err := asn1.Marshal(params)
if err != nil {
panic(err)
}
return asn1.RawValue{FullBytes: serialized}
}
func getSignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) x509.SignatureAlgorithm { func getSignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) x509.SignatureAlgorithm {
if ai.Algorithm.Equal(oidSignatureEd25519) { if ai.Algorithm.Equal(oidSignatureEd25519) {
// RFC 8410, Section 3 // RFC 8410, Section 3
@ -654,7 +622,7 @@ func checkSignature(algo x509.SignatureAlgorithm, signed, signature []byte, publ
if !sm2.VerifyASN1WithSM2(pub, nil, signed, signature) { if !sm2.VerifyASN1WithSM2(pub, nil, signed, signature) {
return errors.New("x509: ECDSA verification failure") return errors.New("x509: ECDSA verification failure")
} }
} else if !verifyECDSAASN1(pub, signed, signature) { } else if !ecdsa.VerifyASN1(pub, signed, signature) {
return errors.New("x509: ECDSA verification failure") return errors.New("x509: ECDSA verification failure")
} }
return return
@ -1415,9 +1383,15 @@ func oidInExtensions(oid asn1.ObjectIdentifier, extensions []pkix.Extension) boo
func marshalSANs(dnsNames, emailAddresses []string, ipAddresses []net.IP, uris []*url.URL) (derBytes []byte, err error) { func marshalSANs(dnsNames, emailAddresses []string, ipAddresses []net.IP, uris []*url.URL) (derBytes []byte, err error) {
var rawValues []asn1.RawValue var rawValues []asn1.RawValue
for _, name := range dnsNames { for _, name := range dnsNames {
if err := isIA5String(name); err != nil {
return nil, err
}
rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeDNS, Class: 2, Bytes: []byte(name)}) rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeDNS, Class: 2, Bytes: []byte(name)})
} }
for _, email := range emailAddresses { for _, email := range emailAddresses {
if err := isIA5String(email); err != nil {
return nil, err
}
rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeEmail, Class: 2, Bytes: []byte(email)}) rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeEmail, Class: 2, Bytes: []byte(email)})
} }
for _, rawIP := range ipAddresses { for _, rawIP := range ipAddresses {
@ -1429,6 +1403,10 @@ func marshalSANs(dnsNames, emailAddresses []string, ipAddresses []net.IP, uris [
rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeIP, Class: 2, Bytes: ip}) rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeIP, Class: 2, Bytes: ip})
} }
for _, uri := range uris { for _, uri := range uris {
uriStr := uri.String()
if err := isIA5String(uriStr); err != nil {
return nil, err
}
rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeURI, Class: 2, Bytes: []byte(uri.String())}) rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeURI, Class: 2, Bytes: []byte(uri.String())})
} }
return asn1.Marshal(rawValues) return asn1.Marshal(rawValues)
@ -1444,67 +1422,32 @@ func isIA5String(s string) error {
return nil return nil
} }
func buildExtensions(template *x509.Certificate, subjectIsEmpty bool, authorityKeyId []byte) (ret []pkix.Extension, err error) { func buildCertExtensions(template *x509.Certificate, subjectIsEmpty bool, authorityKeyId []byte) (ret []pkix.Extension, err error) {
ret = make([]pkix.Extension, 10 /* maximum number of elements. */) ret = make([]pkix.Extension, 10 /* maximum number of elements. */)
n := 0 n := 0
if template.KeyUsage != 0 && if template.KeyUsage != 0 &&
!oidInExtensions(oidExtensionKeyUsage, template.ExtraExtensions) { !oidInExtensions(oidExtensionKeyUsage, template.ExtraExtensions) {
ret[n].Id = oidExtensionKeyUsage ret[n], err = marshalKeyUsage(template.KeyUsage)
ret[n].Critical = true
var a [2]byte
a[0] = reverseBitsInAByte(byte(template.KeyUsage))
a[1] = reverseBitsInAByte(byte(template.KeyUsage >> 8))
l := 1
if a[1] != 0 {
l = 2
}
bitString := a[:l]
ret[n].Value, err = asn1.Marshal(asn1.BitString{Bytes: bitString, BitLength: asn1BitLength(bitString)})
if err != nil { if err != nil {
return return nil, err
} }
n++ n++
} }
if (len(template.ExtKeyUsage) > 0 || len(template.UnknownExtKeyUsage) > 0) && if (len(template.ExtKeyUsage) > 0 || len(template.UnknownExtKeyUsage) > 0) &&
!oidInExtensions(oidExtensionExtendedKeyUsage, template.ExtraExtensions) { !oidInExtensions(oidExtensionExtendedKeyUsage, template.ExtraExtensions) {
ret[n].Id = oidExtensionExtendedKeyUsage ret[n], err = marshalExtKeyUsage(template.ExtKeyUsage, template.UnknownExtKeyUsage)
var oids []asn1.ObjectIdentifier
for _, u := range template.ExtKeyUsage {
if oid, ok := oidFromExtKeyUsage(u); ok {
oids = append(oids, oid)
} else {
panic("internal error")
}
}
oids = append(oids, template.UnknownExtKeyUsage...)
ret[n].Value, err = asn1.Marshal(oids)
if err != nil { if err != nil {
return return nil, err
} }
n++ n++
} }
if template.BasicConstraintsValid && !oidInExtensions(oidExtensionBasicConstraints, template.ExtraExtensions) { if template.BasicConstraintsValid && !oidInExtensions(oidExtensionBasicConstraints, template.ExtraExtensions) {
// Leaving MaxPathLen as zero indicates that no maximum path ret[n], err = marshalBasicConstraints(template.IsCA, template.MaxPathLen, template.MaxPathLenZero)
// length is desired, unless MaxPathLenZero is set. A value of
// -1 causes encoding/asn1 to omit the value as desired.
maxPathLen := template.MaxPathLen
if maxPathLen == 0 && !template.MaxPathLenZero {
maxPathLen = -1
}
ret[n].Id = oidExtensionBasicConstraints
ret[n].Value, err = asn1.Marshal(basicConstraints{template.IsCA, maxPathLen})
ret[n].Critical = true
if err != nil { if err != nil {
return return nil, err
} }
n++ n++
} }
@ -1566,14 +1509,9 @@ func buildExtensions(template *x509.Certificate, subjectIsEmpty bool, authorityK
if len(template.PolicyIdentifiers) > 0 && if len(template.PolicyIdentifiers) > 0 &&
!oidInExtensions(oidExtensionCertificatePolicies, template.ExtraExtensions) { !oidInExtensions(oidExtensionCertificatePolicies, template.ExtraExtensions) {
ret[n].Id = oidExtensionCertificatePolicies ret[n], err = marshalCertificatePolicies(template.PolicyIdentifiers)
policies := make([]policyInformation, len(template.PolicyIdentifiers))
for i, policy := range template.PolicyIdentifiers {
policies[i].Policy = policy
}
ret[n].Value, err = asn1.Marshal(policies)
if err != nil { if err != nil {
return return nil, err
} }
n++ n++
} }
@ -1706,6 +1644,98 @@ func buildExtensions(template *x509.Certificate, subjectIsEmpty bool, authorityK
return append(ret[:n], template.ExtraExtensions...), nil return append(ret[:n], template.ExtraExtensions...), nil
} }
func marshalKeyUsage(ku x509.KeyUsage) (pkix.Extension, error) {
ext := pkix.Extension{Id: oidExtensionKeyUsage, Critical: true}
var a [2]byte
a[0] = reverseBitsInAByte(byte(ku))
a[1] = reverseBitsInAByte(byte(ku >> 8))
l := 1
if a[1] != 0 {
l = 2
}
bitString := a[:l]
var err error
ext.Value, err = asn1.Marshal(asn1.BitString{Bytes: bitString, BitLength: asn1BitLength(bitString)})
if err != nil {
return ext, err
}
return ext, nil
}
func marshalExtKeyUsage(extUsages []x509.ExtKeyUsage, unknownUsages []asn1.ObjectIdentifier) (pkix.Extension, error) {
ext := pkix.Extension{Id: oidExtensionExtendedKeyUsage}
oids := make([]asn1.ObjectIdentifier, len(extUsages)+len(unknownUsages))
for i, u := range extUsages {
if oid, ok := oidFromExtKeyUsage(u); ok {
oids[i] = oid
} else {
return ext, errors.New("x509: unknown extended key usage")
}
}
copy(oids[len(extUsages):], unknownUsages)
var err error
ext.Value, err = asn1.Marshal(oids)
if err != nil {
return ext, err
}
return ext, nil
}
func marshalBasicConstraints(isCA bool, maxPathLen int, maxPathLenZero bool) (pkix.Extension, error) {
ext := pkix.Extension{Id: oidExtensionBasicConstraints, Critical: true}
// Leaving MaxPathLen as zero indicates that no maximum path
// length is desired, unless MaxPathLenZero is set. A value of
// -1 causes encoding/asn1 to omit the value as desired.
if maxPathLen == 0 && !maxPathLenZero {
maxPathLen = -1
}
var err error
ext.Value, err = asn1.Marshal(basicConstraints{isCA, maxPathLen})
if err != nil {
return ext, nil
}
return ext, nil
}
func marshalCertificatePolicies(policyIdentifiers []asn1.ObjectIdentifier) (pkix.Extension, error) {
ext := pkix.Extension{Id: oidExtensionCertificatePolicies}
policies := make([]policyInformation, len(policyIdentifiers))
for i, policy := range policyIdentifiers {
policies[i].Policy = policy
}
var err error
ext.Value, err = asn1.Marshal(policies)
if err != nil {
return ext, err
}
return ext, nil
}
func buildCSRExtensions(template *x509.CertificateRequest) ([]pkix.Extension, error) {
var ret []pkix.Extension
if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0 || len(template.URIs) > 0) &&
!oidInExtensions(oidExtensionSubjectAltName, template.ExtraExtensions) {
sanBytes, err := marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses, template.URIs)
if err != nil {
return nil, err
}
ret = append(ret, pkix.Extension{
Id: oidExtensionSubjectAltName,
Value: sanBytes,
})
}
return append(ret, template.ExtraExtensions...), nil
}
func subjectBytes(cert *x509.Certificate) ([]byte, error) { func subjectBytes(cert *x509.Certificate) ([]byte, error) {
if len(cert.RawSubject) > 0 { if len(cert.RawSubject) > 0 {
return cert.RawSubject, nil return cert.RawSubject, nil
@ -1759,7 +1789,7 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo x509.SignatureA
return return
} }
if requestedSigAlgo == 0 || sigAlgo.Algorithm.Equal(oidSignatureSM2WithSM3) { if requestedSigAlgo == 0 {
return return
} }
@ -1771,12 +1801,12 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo x509.SignatureA
return return
} }
sigAlgo.Algorithm, hashFunc = details.oid, details.hash sigAlgo.Algorithm, hashFunc = details.oid, details.hash
if hashFunc == 0 && pubType != x509.Ed25519 { if hashFunc == 0 && pubType != x509.Ed25519 && !sigAlgo.Algorithm.Equal(oidSignatureSM2WithSM3) {
err = errors.New("x509: cannot sign with hash function requested") err = errors.New("x509: cannot sign with hash function requested")
return return
} }
if isRSAPSS(requestedSigAlgo) { if isRSAPSS(requestedSigAlgo) {
sigAlgo.Parameters = rsaPSSParameters(hashFunc) sigAlgo.Parameters = hashToPSSParameters[hashFunc]
} }
found = true found = true
break break
@ -1902,7 +1932,7 @@ func CreateCertificate(rand io.Reader, template, parent *x509.Certificate, pub,
return nil, errors.New("x509: provided PrivateKey doesn't match parent's PublicKey") return nil, errors.New("x509: provided PrivateKey doesn't match parent's PublicKey")
} }
extensions, err := buildExtensions(template, bytes.Equal(asn1Subject, emptyASN1Subject), authorityKeyId) extensions, err := buildCertExtensions(template, bytes.Equal(asn1Subject, emptyASN1Subject), authorityKeyId)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -2171,23 +2201,11 @@ func CreateCertificateRequest(rand io.Reader, template *x509.CertificateRequest,
return nil, err return nil, err
} }
var extensions []pkix.Extension extensions, err := buildCSRExtensions(template)
if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0 || len(template.URIs) > 0) &&
!oidInExtensions(oidExtensionSubjectAltName, template.ExtraExtensions) {
sanBytes, err := marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses, template.URIs)
if err != nil { if err != nil {
return nil, err return nil, err
} }
extensions = append(extensions, pkix.Extension{
Id: oidExtensionSubjectAltName,
Value: sanBytes,
})
}
extensions = append(extensions, template.ExtraExtensions...)
// Make a copy of template.Attributes because we may alter it below. // Make a copy of template.Attributes because we may alter it below.
attributes := make([]pkix.AttributeTypeAndValueSET, 0, len(template.Attributes)) attributes := make([]pkix.AttributeTypeAndValueSET, 0, len(template.Attributes))
for _, attr := range template.Attributes { for _, attr := range template.Attributes {
@ -2422,7 +2440,6 @@ func (c *CertificateRequest) CheckSignature() error {
// The issuer distinguished name CRL field and authority key identifier // The issuer distinguished name CRL field and authority key identifier
// extension are populated using the issuer certificate. issuer must have // extension are populated using the issuer certificate. issuer must have
// SubjectKeyId set. // SubjectKeyId set.
/*
func CreateRevocationList(rand io.Reader, template *x509.RevocationList, issuer *Certificate, priv crypto.Signer) ([]byte, error) { func CreateRevocationList(rand io.Reader, template *x509.RevocationList, issuer *Certificate, priv crypto.Signer) ([]byte, error) {
if template == nil { if template == nil {
return nil, errors.New("x509: template can not be nil") return nil, errors.New("x509: template can not be nil")
@ -2521,4 +2538,3 @@ func CreateRevocationList(rand io.Reader, template *x509.RevocationList, issuer
SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
}) })
} }
*/

View File

@ -2,6 +2,7 @@ package smx509
import ( import (
"bytes" "bytes"
"crypto"
"crypto/ecdsa" "crypto/ecdsa"
"crypto/ed25519" "crypto/ed25519"
"crypto/elliptic" "crypto/elliptic"
@ -31,6 +32,17 @@ MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAELfjZP28bYfGSvbODYlXiB5bcoXE+
2LRjjpIH3DcCCct9FuVhi9cm60nDFrbW49k2D3GJco2iWPlr0+5LV+t4AQ== 2LRjjpIH3DcCCct9FuVhi9cm60nDFrbW49k2D3GJco2iWPlr0+5LV+t4AQ==
-----END PUBLIC KEY----- -----END PUBLIC KEY-----
` `
const publicKeyPemFromHuaweiKms = `-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEP3JLMIBPGUx88KChOY3WhjNVKOsk
RzYP5lpimwVS9CAK6MzL4kqudI7Pqi6hcir35zH8/BHMXzQ4fM2Ojp+59w==
-----END PUBLIC KEY-----
`
const publicKeyPemFromHuaweiKmsForSign = `-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAENpoOih+9ASfmKYx5lK5mLsrUK3Am
B6kLUsqHlVyglXgoMEwo8Sr8xb/Q3gDMNnd7Wyp2bJE9ksb60ansO4QaKg==
-----END PUBLIC KEY-----
`
const publicKeyPemFromAliKmsForSign = `-----BEGIN PUBLIC KEY----- const publicKeyPemFromAliKmsForSign = `-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAERrsLH25zLm2LIo6tivZM9afLprSX MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAERrsLH25zLm2LIo6tivZM9afLprSX
@ -40,6 +52,8 @@ MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAERrsLH25zLm2LIo6tivZM9afLprSX
const hashBase64 = `Zsfw9GLu7dnR8tRr3BDk4kFnxIdc8veiKX2gK49LqOA=` const hashBase64 = `Zsfw9GLu7dnR8tRr3BDk4kFnxIdc8veiKX2gK49LqOA=`
const signature = `MEUCIHV5hOCgYzlO4HkrUhct1Cc8BeKmbXNP+ASje5rGOcCYAiEA2XOajXo3/IihtCEJmNpImtWw3uHIy5CX5TIxit7V0gQ=` const signature = `MEUCIHV5hOCgYzlO4HkrUhct1Cc8BeKmbXNP+ASje5rGOcCYAiEA2XOajXo3/IihtCEJmNpImtWw3uHIy5CX5TIxit7V0gQ=`
const signatureFromHuawei = `MEQCIGK8rWDJw5K7a6RZP5pDii8iqY3yLmavaXpkl7aDLORqAiAlMiiSvp7OJYBCJmzmwadBiBhdBnCCfIdjiWhXHX9xcw==`
const csrFromAli = `-----BEGIN CERTIFICATE REQUEST----- const csrFromAli = `-----BEGIN CERTIFICATE REQUEST-----
MIIBYjCCAQkCAQAwRzELMAkGA1UEBhMCQ04xEzARBgNVBAMMCkNhcmdvU21hcnQx MIIBYjCCAQkCAQAwRzELMAkGA1UEBhMCQ04xEzARBgNVBAMMCkNhcmdvU21hcnQx
DzANBgNVBAcMBlpodWhhaTESMBAGA1UECAwJR3Vhbmdkb25nMFkwEwYHKoZIzj0C DzANBgNVBAcMBlpodWhhaTESMBAGA1UECAwJR3Vhbmdkb25nMFkwEwYHKoZIzj0C
@ -236,6 +250,20 @@ func TestSignByAliVerifyAtLocal(t *testing.T) {
} }
} }
func TestSignByHuaweiVerifyAtLocal(t *testing.T) {
dig, err := base64.StdEncoding.DecodeString(signatureFromHuawei)
if err != nil {
t.Fatal(err)
}
pub, err := getPublicKey([]byte(publicKeyPemFromHuaweiKmsForSign))
pub1 := pub.(*ecdsa.PublicKey)
hashValue, _ := base64.StdEncoding.DecodeString(hashBase64)
result := sm2.VerifyASN1(pub1, hashValue, dig)
if !result {
t.Error("Verify fail")
}
}
func TestParsePKIXPublicKey(t *testing.T) { func TestParsePKIXPublicKey(t *testing.T) {
pub, err := getPublicKey([]byte(publicKeyPemFromAliKms)) pub, err := getPublicKey([]byte(publicKeyPemFromAliKms))
if err != nil { if err != nil {
@ -249,6 +277,19 @@ func TestParsePKIXPublicKey(t *testing.T) {
fmt.Printf("encrypted=%s\n", base64.StdEncoding.EncodeToString(encrypted)) fmt.Printf("encrypted=%s\n", base64.StdEncoding.EncodeToString(encrypted))
} }
func TestParsePKIXPublicKeyFromHuawei(t *testing.T) {
pub, err := getPublicKey([]byte(publicKeyPemFromHuaweiKms))
if err != nil {
t.Fatal(err)
}
pub1 := pub.(*ecdsa.PublicKey)
encrypted, err := sm2.Encrypt(rand.Reader, pub1, []byte("encryption standard"), sm2.NewASN1EncrypterOpts())
if err != nil {
t.Fatal(err)
}
fmt.Printf("encrypted=%s\n", base64.RawURLEncoding.EncodeToString(encrypted))
}
func TestMarshalPKIXPublicKey(t *testing.T) { func TestMarshalPKIXPublicKey(t *testing.T) {
pub, err := getPublicKey([]byte(publicKeyPemFromAliKms)) pub, err := getPublicKey([]byte(publicKeyPemFromAliKms))
if err != nil { if err != nil {
@ -681,3 +722,294 @@ func TestCRLCreation(t *testing.T) {
} }
} }
} }
func TestCreateRevocationList(t *testing.T) {
sm2Priv, err := sm2.GenerateKey(rand.Reader)
if err != nil {
t.Fatalf("Failed to generate SM2 key: %s", err)
}
_, ed25519Priv, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
t.Fatalf("Failed to generate Ed25519 key: %s", err)
}
tests := []struct {
name string
key crypto.Signer
issuer *x509.Certificate
template *x509.RevocationList
expectedError string
}{
{
name: "nil template",
key: sm2Priv,
issuer: nil,
template: nil,
expectedError: "x509: template can not be nil",
},
{
name: "nil issuer",
key: sm2Priv,
issuer: nil,
template: &x509.RevocationList{},
expectedError: "x509: issuer can not be nil",
},
{
name: "issuer doesn't have crlSign key usage bit set",
key: sm2Priv,
issuer: &x509.Certificate{
KeyUsage: x509.KeyUsageCertSign,
},
template: &x509.RevocationList{},
expectedError: "x509: issuer must have the crlSign key usage bit set",
},
{
name: "issuer missing SubjectKeyId",
key: sm2Priv,
issuer: &x509.Certificate{
KeyUsage: x509.KeyUsageCRLSign,
},
template: &x509.RevocationList{},
expectedError: "x509: issuer certificate doesn't contain a subject key identifier",
},
{
name: "nextUpdate before thisUpdate",
key: sm2Priv,
issuer: &x509.Certificate{
KeyUsage: x509.KeyUsageCRLSign,
Subject: pkix.Name{
CommonName: "testing",
},
SubjectKeyId: []byte{1, 2, 3},
},
template: &x509.RevocationList{
ThisUpdate: time.Time{}.Add(time.Hour),
NextUpdate: time.Time{},
},
expectedError: "x509: template.ThisUpdate is after template.NextUpdate",
},
{
name: "nil Number",
key: sm2Priv,
issuer: &x509.Certificate{
KeyUsage: x509.KeyUsageCRLSign,
Subject: pkix.Name{
CommonName: "testing",
},
SubjectKeyId: []byte{1, 2, 3},
},
template: &x509.RevocationList{
ThisUpdate: time.Time{}.Add(time.Hour * 24),
NextUpdate: time.Time{}.Add(time.Hour * 48),
},
expectedError: "x509: template contains nil Number field",
},
{
name: "invalid signature algorithm",
key: sm2Priv,
issuer: &x509.Certificate{
KeyUsage: x509.KeyUsageCRLSign,
Subject: pkix.Name{
CommonName: "testing",
},
SubjectKeyId: []byte{1, 2, 3},
},
template: &x509.RevocationList{
SignatureAlgorithm: x509.SHA256WithRSA,
RevokedCertificates: []pkix.RevokedCertificate{
{
SerialNumber: big.NewInt(2),
RevocationTime: time.Time{}.Add(time.Hour),
},
},
Number: big.NewInt(5),
ThisUpdate: time.Time{}.Add(time.Hour * 24),
NextUpdate: time.Time{}.Add(time.Hour * 48),
},
expectedError: "x509: requested SignatureAlgorithm does not match private key type",
},
{
name: "valid",
key: sm2Priv,
issuer: &x509.Certificate{
KeyUsage: x509.KeyUsageCRLSign,
Subject: pkix.Name{
CommonName: "testing",
},
SubjectKeyId: []byte{1, 2, 3},
},
template: &x509.RevocationList{
RevokedCertificates: []pkix.RevokedCertificate{
{
SerialNumber: big.NewInt(2),
RevocationTime: time.Time{}.Add(time.Hour),
},
},
Number: big.NewInt(5),
ThisUpdate: time.Time{}.Add(time.Hour * 24),
NextUpdate: time.Time{}.Add(time.Hour * 48),
},
},
{
name: "valid, Ed25519 key",
key: ed25519Priv,
issuer: &x509.Certificate{
KeyUsage: x509.KeyUsageCRLSign,
Subject: pkix.Name{
CommonName: "testing",
},
SubjectKeyId: []byte{1, 2, 3},
},
template: &x509.RevocationList{
RevokedCertificates: []pkix.RevokedCertificate{
{
SerialNumber: big.NewInt(2),
RevocationTime: time.Time{}.Add(time.Hour),
},
},
Number: big.NewInt(5),
ThisUpdate: time.Time{}.Add(time.Hour * 24),
NextUpdate: time.Time{}.Add(time.Hour * 48),
},
},
{
name: "valid, non-default signature algorithm",
key: sm2Priv,
issuer: &x509.Certificate{
KeyUsage: x509.KeyUsageCRLSign,
Subject: pkix.Name{
CommonName: "testing",
},
SubjectKeyId: []byte{1, 2, 3},
},
template: &x509.RevocationList{
SignatureAlgorithm: x509.ECDSAWithSHA512,
RevokedCertificates: []pkix.RevokedCertificate{
{
SerialNumber: big.NewInt(2),
RevocationTime: time.Time{}.Add(time.Hour),
},
},
Number: big.NewInt(5),
ThisUpdate: time.Time{}.Add(time.Hour * 24),
NextUpdate: time.Time{}.Add(time.Hour * 48),
},
},
{
name: "valid, extra extension",
key: sm2Priv,
issuer: &x509.Certificate{
KeyUsage: x509.KeyUsageCRLSign,
Subject: pkix.Name{
CommonName: "testing",
},
SubjectKeyId: []byte{1, 2, 3},
},
template: &x509.RevocationList{
RevokedCertificates: []pkix.RevokedCertificate{
{
SerialNumber: big.NewInt(2),
RevocationTime: time.Time{}.Add(time.Hour),
},
},
Number: big.NewInt(5),
ThisUpdate: time.Time{}.Add(time.Hour * 24),
NextUpdate: time.Time{}.Add(time.Hour * 48),
ExtraExtensions: []pkix.Extension{
{
Id: []int{2, 5, 29, 99},
Value: []byte{5, 0},
},
},
},
},
{
name: "valid, empty list",
key: sm2Priv,
issuer: &x509.Certificate{
KeyUsage: x509.KeyUsageCRLSign,
Subject: pkix.Name{
CommonName: "testing",
},
SubjectKeyId: []byte{1, 2, 3},
},
template: &x509.RevocationList{
Number: big.NewInt(5),
ThisUpdate: time.Time{}.Add(time.Hour * 24),
NextUpdate: time.Time{}.Add(time.Hour * 48),
},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
var issuer *Certificate
if tc.issuer != nil {
issuer = &Certificate{*tc.issuer}
}
crl, err := CreateRevocationList(rand.Reader, tc.template, issuer, tc.key)
if err != nil && tc.expectedError == "" {
t.Fatalf("CreateRevocationList failed unexpectedly: %s", err)
} else if err != nil && tc.expectedError != err.Error() {
t.Fatalf("CreateRevocationList failed unexpectedly, wanted: %s, got: %s", tc.expectedError, err)
} else if err == nil && tc.expectedError != "" {
t.Fatalf("CreateRevocationList didn't fail, expected: %s", tc.expectedError)
}
if tc.expectedError != "" {
return
}
parsedCRL, err := ParseDERCRL(crl)
if err != nil {
t.Fatalf("Failed to parse generated CRL: %s", err)
}
if tc.template.SignatureAlgorithm != x509.UnknownSignatureAlgorithm &&
parsedCRL.SignatureAlgorithm.Algorithm.Equal(signatureAlgorithmDetails[tc.template.SignatureAlgorithm].oid) {
t.Fatalf("SignatureAlgorithm mismatch: got %v; want %v.", parsedCRL.SignatureAlgorithm,
tc.template.SignatureAlgorithm)
}
if !reflect.DeepEqual(parsedCRL.TBSCertList.RevokedCertificates, tc.template.RevokedCertificates) {
t.Fatalf("RevokedCertificates mismatch: got %v; want %v.",
parsedCRL.TBSCertList.RevokedCertificates, tc.template.RevokedCertificates)
}
if len(parsedCRL.TBSCertList.Extensions) != 2+len(tc.template.ExtraExtensions) {
t.Fatalf("Generated CRL has wrong number of extensions, wanted: %d, got: %d", 2+len(tc.template.ExtraExtensions), len(parsedCRL.TBSCertList.Extensions))
}
expectedAKI, err := asn1.Marshal(authKeyId{Id: tc.issuer.SubjectKeyId})
if err != nil {
t.Fatalf("asn1.Marshal failed: %s", err)
}
akiExt := pkix.Extension{
Id: oidExtensionAuthorityKeyId,
Value: expectedAKI,
}
if !reflect.DeepEqual(parsedCRL.TBSCertList.Extensions[0], akiExt) {
t.Fatalf("Unexpected first extension: got %v, want %v",
parsedCRL.TBSCertList.Extensions[0], akiExt)
}
expectedNum, err := asn1.Marshal(tc.template.Number)
if err != nil {
t.Fatalf("asn1.Marshal failed: %s", err)
}
crlExt := pkix.Extension{
Id: oidExtensionCRLNumber,
Value: expectedNum,
}
if !reflect.DeepEqual(parsedCRL.TBSCertList.Extensions[1], crlExt) {
t.Fatalf("Unexpected second extension: got %v, want %v",
parsedCRL.TBSCertList.Extensions[1], crlExt)
}
if len(parsedCRL.TBSCertList.Extensions[2:]) == 0 && len(tc.template.ExtraExtensions) == 0 {
// If we don't have anything to check return early so we don't
// hit a [] != nil false positive below.
return
}
if !reflect.DeepEqual(parsedCRL.TBSCertList.Extensions[2:], tc.template.ExtraExtensions) {
t.Fatalf("Extensions mismatch: got %v; want %v.",
parsedCRL.TBSCertList.Extensions[2:], tc.template.ExtraExtensions)
}
})
}
}