mirror of
https://github.com/emmansun/gmsm.git
synced 2025-04-21 17:56:19 +08:00
golang version 1.4 is no longer supported
This commit is contained in:
parent
db223b3c7f
commit
aff4830dd8
2
go.mod
2
go.mod
@ -1,6 +1,6 @@
|
||||
module github.com/emmansun/gmsm
|
||||
|
||||
go 1.14
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871
|
||||
|
244
smx509/x509.go
244
smx509/x509.go
@ -238,6 +238,19 @@ var signatureAlgorithmDetails = []struct {
|
||||
{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
|
||||
// specifies RSA PSS. See RFC 3447, Appendix A.2.3.
|
||||
type pssParameters struct {
|
||||
@ -250,51 +263,6 @@ type pssParameters struct {
|
||||
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 {
|
||||
if ai.Algorithm.Equal(oidSignatureEd25519) {
|
||||
// RFC 8410, Section 3
|
||||
@ -654,7 +622,7 @@ func checkSignature(algo x509.SignatureAlgorithm, signed, signature []byte, publ
|
||||
if !sm2.VerifyASN1WithSM2(pub, nil, signed, signature) {
|
||||
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
|
||||
@ -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) {
|
||||
var rawValues []asn1.RawValue
|
||||
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)})
|
||||
}
|
||||
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)})
|
||||
}
|
||||
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})
|
||||
}
|
||||
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())})
|
||||
}
|
||||
return asn1.Marshal(rawValues)
|
||||
@ -1444,67 +1422,32 @@ func isIA5String(s string) error {
|
||||
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. */)
|
||||
n := 0
|
||||
|
||||
if template.KeyUsage != 0 &&
|
||||
!oidInExtensions(oidExtensionKeyUsage, template.ExtraExtensions) {
|
||||
ret[n].Id = oidExtensionKeyUsage
|
||||
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)})
|
||||
ret[n], err = marshalKeyUsage(template.KeyUsage)
|
||||
if err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
n++
|
||||
}
|
||||
|
||||
if (len(template.ExtKeyUsage) > 0 || len(template.UnknownExtKeyUsage) > 0) &&
|
||||
!oidInExtensions(oidExtensionExtendedKeyUsage, template.ExtraExtensions) {
|
||||
ret[n].Id = oidExtensionExtendedKeyUsage
|
||||
|
||||
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)
|
||||
ret[n], err = marshalExtKeyUsage(template.ExtKeyUsage, template.UnknownExtKeyUsage)
|
||||
if err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
n++
|
||||
}
|
||||
|
||||
if template.BasicConstraintsValid && !oidInExtensions(oidExtensionBasicConstraints, template.ExtraExtensions) {
|
||||
// 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.
|
||||
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
|
||||
ret[n], err = marshalBasicConstraints(template.IsCA, template.MaxPathLen, template.MaxPathLenZero)
|
||||
if err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
n++
|
||||
}
|
||||
@ -1566,14 +1509,9 @@ func buildExtensions(template *x509.Certificate, subjectIsEmpty bool, authorityK
|
||||
|
||||
if len(template.PolicyIdentifiers) > 0 &&
|
||||
!oidInExtensions(oidExtensionCertificatePolicies, template.ExtraExtensions) {
|
||||
ret[n].Id = oidExtensionCertificatePolicies
|
||||
policies := make([]policyInformation, len(template.PolicyIdentifiers))
|
||||
for i, policy := range template.PolicyIdentifiers {
|
||||
policies[i].Policy = policy
|
||||
}
|
||||
ret[n].Value, err = asn1.Marshal(policies)
|
||||
ret[n], err = marshalCertificatePolicies(template.PolicyIdentifiers)
|
||||
if err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
n++
|
||||
}
|
||||
@ -1706,6 +1644,98 @@ func buildExtensions(template *x509.Certificate, subjectIsEmpty bool, authorityK
|
||||
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) {
|
||||
if len(cert.RawSubject) > 0 {
|
||||
return cert.RawSubject, nil
|
||||
@ -1759,7 +1789,7 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo x509.SignatureA
|
||||
return
|
||||
}
|
||||
|
||||
if requestedSigAlgo == 0 || sigAlgo.Algorithm.Equal(oidSignatureSM2WithSM3) {
|
||||
if requestedSigAlgo == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
@ -1771,12 +1801,12 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo x509.SignatureA
|
||||
return
|
||||
}
|
||||
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")
|
||||
return
|
||||
}
|
||||
if isRSAPSS(requestedSigAlgo) {
|
||||
sigAlgo.Parameters = rsaPSSParameters(hashFunc)
|
||||
sigAlgo.Parameters = hashToPSSParameters[hashFunc]
|
||||
}
|
||||
found = true
|
||||
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")
|
||||
}
|
||||
|
||||
extensions, err := buildExtensions(template, bytes.Equal(asn1Subject, emptyASN1Subject), authorityKeyId)
|
||||
extensions, err := buildCertExtensions(template, bytes.Equal(asn1Subject, emptyASN1Subject), authorityKeyId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -2171,23 +2201,11 @@ func CreateCertificateRequest(rand io.Reader, template *x509.CertificateRequest,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var extensions []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)
|
||||
extensions, err := buildCSRExtensions(template)
|
||||
if err != nil {
|
||||
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.
|
||||
attributes := make([]pkix.AttributeTypeAndValueSET, 0, len(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
|
||||
// extension are populated using the issuer certificate. issuer must have
|
||||
// SubjectKeyId set.
|
||||
/*
|
||||
func CreateRevocationList(rand io.Reader, template *x509.RevocationList, issuer *Certificate, priv crypto.Signer) ([]byte, error) {
|
||||
if template == 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},
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
@ -2,6 +2,7 @@ package smx509
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/ed25519"
|
||||
"crypto/elliptic"
|
||||
@ -31,6 +32,17 @@ MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAELfjZP28bYfGSvbODYlXiB5bcoXE+
|
||||
2LRjjpIH3DcCCct9FuVhi9cm60nDFrbW49k2D3GJco2iWPlr0+5LV+t4AQ==
|
||||
-----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-----
|
||||
MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAERrsLH25zLm2LIo6tivZM9afLprSX
|
||||
@ -40,6 +52,8 @@ MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAERrsLH25zLm2LIo6tivZM9afLprSX
|
||||
|
||||
const hashBase64 = `Zsfw9GLu7dnR8tRr3BDk4kFnxIdc8veiKX2gK49LqOA=`
|
||||
const signature = `MEUCIHV5hOCgYzlO4HkrUhct1Cc8BeKmbXNP+ASje5rGOcCYAiEA2XOajXo3/IihtCEJmNpImtWw3uHIy5CX5TIxit7V0gQ=`
|
||||
const signatureFromHuawei = `MEQCIGK8rWDJw5K7a6RZP5pDii8iqY3yLmavaXpkl7aDLORqAiAlMiiSvp7OJYBCJmzmwadBiBhdBnCCfIdjiWhXHX9xcw==`
|
||||
|
||||
const csrFromAli = `-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIIBYjCCAQkCAQAwRzELMAkGA1UEBhMCQ04xEzARBgNVBAMMCkNhcmdvU21hcnQx
|
||||
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) {
|
||||
pub, err := getPublicKey([]byte(publicKeyPemFromAliKms))
|
||||
if err != nil {
|
||||
@ -249,6 +277,19 @@ func TestParsePKIXPublicKey(t *testing.T) {
|
||||
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) {
|
||||
pub, err := getPublicKey([]byte(publicKeyPemFromAliKms))
|
||||
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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user