smx509: change CreateCertificate's template and parent parameter type to any

This commit is contained in:
Sun Yimin 2023-02-03 10:25:03 +08:00 committed by GitHub
parent cb1e23a776
commit cf0c739dcf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 99 additions and 26 deletions

View File

@ -1624,7 +1624,7 @@ func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.
if parent == nil { if parent == nil {
parent = template parent = template
} }
derBytes, err := CreateCertificate(rand.Reader, template.asX509(), parent.asX509(), &key.PublicKey, parentKey) derBytes, err := CreateCertificate(rand.Reader, template, parent, &key.PublicKey, parentKey)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -1952,7 +1952,7 @@ func genCertEdge(t *testing.T, subject string, key crypto.Signer, mutateTmpl fun
signer = key signer = key
} }
d, err := CreateCertificate(rand.Reader, tmpl.asX509(), issuer.asX509(), key.Public(), signer) d, err := CreateCertificate(rand.Reader, tmpl, issuer, key.Public(), signer)
if err != nil { if err != nil {
t.Fatalf("failed to generate test cert: %s", err) t.Fatalf("failed to generate test cert: %s", err)
} }
@ -2598,7 +2598,7 @@ func TestVerifyEKURootAsLeaf(t *testing.T) {
DNSNames: []string{"localhost"}, DNSNames: []string{"localhost"},
ExtKeyUsage: tc.rootEKUs, ExtKeyUsage: tc.rootEKUs,
} }
rootDER, err := CreateCertificate(rand.Reader, tmpl.asX509(), tmpl.asX509(), k.Public(), k) rootDER, err := CreateCertificate(rand.Reader, tmpl, tmpl, k.Public(), k)
if err != nil { if err != nil {
t.Fatalf("failed to create certificate: %s", err) t.Fatalf("failed to create certificate: %s", err)
} }

View File

@ -658,6 +658,7 @@ func (c *Certificate) asX509() *x509.Certificate {
return (*x509.Certificate)(c) return (*x509.Certificate)(c)
} }
// ToX509 convert smx509.Certificate reference to x509.Certificate
func (c *Certificate) ToX509() *x509.Certificate { func (c *Certificate) ToX509() *x509.Certificate {
return c.asX509() return c.asX509()
} }
@ -1374,8 +1375,9 @@ var emptyASN1Subject = []byte{0x30, 0}
// - UnknownExtKeyUsage // - UnknownExtKeyUsage
// //
// The certificate is signed by parent. If parent is equal to template then the // The certificate is signed by parent. If parent is equal to template then the
// certificate is self-signed. The parameter pub is the public key of the // certificate is self-signed, both parent and template should be *x509.Certificate or
// certificate to be generated and priv is the private key of the signer. // *smx509.Certificate type. The parameter pub is the public key of the certificate to
// be generated and priv is the private key of the signer.
// //
// The returned slice is the certificate in DER encoding. // The returned slice is the certificate in DER encoding.
// //
@ -1389,13 +1391,23 @@ var emptyASN1Subject = []byte{0x30, 0}
// //
// If SubjectKeyId from template is empty and the template is a CA, SubjectKeyId // If SubjectKeyId from template is empty and the template is a CA, SubjectKeyId
// will be generated from the hash of the public key. // will be generated from the hash of the public key.
func CreateCertificate(rand io.Reader, template, parent *x509.Certificate, pub, priv interface{}) ([]byte, error) { func CreateCertificate(rand io.Reader, template, parent, pub, priv interface{}) ([]byte, error) {
realTemplate, err := toCertificate(template)
if err != nil {
return nil, fmt.Errorf("x509: unsupported template parameter type: %T", template)
}
realParent, err := toCertificate(parent)
if err != nil {
return nil, fmt.Errorf("x509: unsupported parent parameter type: %T", parent)
}
key, ok := priv.(crypto.Signer) key, ok := priv.(crypto.Signer)
if !ok { if !ok {
return nil, errors.New("x509: certificate private key does not implement crypto.Signer") return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
} }
if template.SerialNumber == nil { if realTemplate.SerialNumber == nil {
return nil, errors.New("x509: no SerialNumber given") return nil, errors.New("x509: no SerialNumber given")
} }
@ -1404,15 +1416,15 @@ func CreateCertificate(rand io.Reader, template, parent *x509.Certificate, pub,
// We _should_ also restrict serials to <= 20 octets, but it turns out a lot of people // We _should_ also restrict serials to <= 20 octets, but it turns out a lot of people
// get this wrong, in part because the encoding can itself alter the length of the // get this wrong, in part because the encoding can itself alter the length of the
// serial. For now we accept these non-conformant serials. // serial. For now we accept these non-conformant serials.
if template.SerialNumber.Sign() == -1 { if realTemplate.SerialNumber.Sign() == -1 {
return nil, errors.New("x509: serial number must be positive") return nil, errors.New("x509: serial number must be positive")
} }
if template.BasicConstraintsValid && !template.IsCA && template.MaxPathLen != -1 && (template.MaxPathLen != 0 || template.MaxPathLenZero) { if realTemplate.BasicConstraintsValid && !realTemplate.IsCA && realTemplate.MaxPathLen != -1 && (realTemplate.MaxPathLen != 0 || realTemplate.MaxPathLenZero) {
return nil, errors.New("x509: only CAs are allowed to specify MaxPathLen") return nil, errors.New("x509: only CAs are allowed to specify MaxPathLen")
} }
hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm) hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), realTemplate.SignatureAlgorithm)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1426,23 +1438,23 @@ func CreateCertificate(rand io.Reader, template, parent *x509.Certificate, pub,
return nil, fmt.Errorf("x509: unsupported public key type: %T", pub) return nil, fmt.Errorf("x509: unsupported public key type: %T", pub)
} }
asn1Issuer, err := subjectBytes(parent) asn1Issuer, err := subjectBytes(realParent)
if err != nil { if err != nil {
return nil, err return nil, err
} }
asn1Subject, err := subjectBytes(template) asn1Subject, err := subjectBytes(realTemplate)
if err != nil { if err != nil {
return nil, err return nil, err
} }
authorityKeyId := template.AuthorityKeyId authorityKeyId := realTemplate.AuthorityKeyId
if !bytes.Equal(asn1Issuer, asn1Subject) && len(parent.SubjectKeyId) > 0 { if !bytes.Equal(asn1Issuer, asn1Subject) && len(realParent.SubjectKeyId) > 0 {
authorityKeyId = parent.SubjectKeyId authorityKeyId = realParent.SubjectKeyId
} }
subjectKeyId := template.SubjectKeyId subjectKeyId := realTemplate.SubjectKeyId
if len(subjectKeyId) == 0 && template.IsCA { if len(subjectKeyId) == 0 && realTemplate.IsCA {
// SubjectKeyId generated using method 1 in RFC 5280, Section 4.2.1.2: // 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 // (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the
// value of the BIT STRING subjectPublicKey (excluding the tag, // value of the BIT STRING subjectPublicKey (excluding the tag,
@ -1458,11 +1470,11 @@ func CreateCertificate(rand io.Reader, template, parent *x509.Certificate, pub,
if privPub, ok := key.Public().(privateKey); !ok { if privPub, ok := key.Public().(privateKey); !ok {
return nil, errors.New("x509: internal error: supported public key does not implement Equal") return nil, errors.New("x509: internal error: supported public key does not implement Equal")
} else if parent.PublicKey != nil && !privPub.Equal(parent.PublicKey) { } else if realParent.PublicKey != nil && !privPub.Equal(realParent.PublicKey) {
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 := buildCertExtensions(template, bytes.Equal(asn1Subject, emptyASN1Subject), authorityKeyId, subjectKeyId) extensions, err := buildCertExtensions(realTemplate, bytes.Equal(asn1Subject, emptyASN1Subject), authorityKeyId, subjectKeyId)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1470,10 +1482,10 @@ func CreateCertificate(rand io.Reader, template, parent *x509.Certificate, pub,
encodedPublicKey := asn1.BitString{BitLength: len(publicKeyBytes) * 8, Bytes: publicKeyBytes} encodedPublicKey := asn1.BitString{BitLength: len(publicKeyBytes) * 8, Bytes: publicKeyBytes}
c := tbsCertificate{ c := tbsCertificate{
Version: 2, Version: 2,
SerialNumber: template.SerialNumber, SerialNumber: realTemplate.SerialNumber,
SignatureAlgorithm: signatureAlgorithm, SignatureAlgorithm: signatureAlgorithm,
Issuer: asn1.RawValue{FullBytes: asn1Issuer}, Issuer: asn1.RawValue{FullBytes: asn1Issuer},
Validity: validity{template.NotBefore.UTC(), template.NotAfter.UTC()}, Validity: validity{realTemplate.NotBefore.UTC(), realTemplate.NotAfter.UTC()},
Subject: asn1.RawValue{FullBytes: asn1Subject}, Subject: asn1.RawValue{FullBytes: asn1Subject},
PublicKey: publicKeyInfo{nil, publicKeyAlgorithm, encodedPublicKey}, PublicKey: publicKeyInfo{nil, publicKeyAlgorithm, encodedPublicKey},
Extensions: extensions, Extensions: extensions,
@ -1495,7 +1507,7 @@ func CreateCertificate(rand io.Reader, template, parent *x509.Certificate, pub,
} }
var signerOpts crypto.SignerOpts = hashFunc var signerOpts crypto.SignerOpts = hashFunc
if template.SignatureAlgorithm != 0 && isRSAPSS(template.SignatureAlgorithm) { if realTemplate.SignatureAlgorithm != 0 && isRSAPSS(realTemplate.SignatureAlgorithm) {
signerOpts = &rsa.PSSOptions{ signerOpts = &rsa.PSSOptions{
SaltLength: rsa.PSSSaltLengthEqualsHash, SaltLength: rsa.PSSSaltLengthEqualsHash,
Hash: hashFunc, Hash: hashFunc,
@ -1525,6 +1537,17 @@ func CreateCertificate(rand io.Reader, template, parent *x509.Certificate, pub,
return signedCert, nil return signedCert, nil
} }
func toCertificate(in interface{}) (*x509.Certificate, error) {
switch c := in.(type) {
case *x509.Certificate:
return c, nil
case *Certificate:
return c.asX509(), nil
default:
return nil, fmt.Errorf("unsupported certificate of type %T", in)
}
}
// ParseCRL parses a CRL from the given bytes. It's often the case that PEM // ParseCRL parses a CRL from the given bytes. It's often the case that PEM
// encoded CRLs will appear where they should be DER encoded, so this function // encoded CRLs will appear where they should be DER encoded, so this function
// will transparently handle PEM encoding as long as there isn't any leading // will transparently handle PEM encoding as long as there isn't any leading
@ -1615,6 +1638,7 @@ func (c *CertificateRequest) asX509() *x509.CertificateRequest {
return (*x509.CertificateRequest)(c) return (*x509.CertificateRequest)(c)
} }
// ToX509 convert smx509.CertificateRequest reference to x509.CertificateRequest
func (c *CertificateRequest) ToX509() *x509.CertificateRequest { func (c *CertificateRequest) ToX509() *x509.CertificateRequest {
return c.asX509() return c.asX509()
} }

View File

@ -213,3 +213,52 @@ func TestMarshalECDHPKIXPublicKey(t *testing.T) {
t.Fatal("should be same") t.Fatal("should be same")
} }
} }
func TestToCertificate(t *testing.T) {
x509Cert := new(x509.Certificate)
c, err := toCertificate(x509Cert)
if err != nil || c != x509Cert {
t.Fatal("should be no error")
}
smX509Cert := new(Certificate)
_, err = toCertificate(smX509Cert)
if err != nil {
t.Fatal("should be no error")
}
_, err = toCertificate("test")
if err == nil {
t.Fatal("should be error")
}
_, err = toCertificate(nil)
if err == nil {
t.Fatal("should be error")
}
}
func TestInvalidParentTemplate(t *testing.T) {
random := rand.Reader
sm2Priv, err := sm2.GenerateKey(rand.Reader)
if err != nil {
t.Fatalf("Failed to generate SM2 key: %s", err)
}
_, err = CreateCertificate(random, nil, nil, sm2Priv.PublicKey, sm2Priv)
if err == nil {
t.Fatal("should be error")
}
if err.Error() != "x509: unsupported template parameter type: <nil>" {
t.Fatalf("unexpected error message: %v", err.Error())
}
_, err = CreateCertificate(random, new(x509.Certificate), nil, sm2Priv.PublicKey, sm2Priv)
if err == nil {
t.Fatal("should be error")
}
if err.Error() != "x509: unsupported parent parameter type: <nil>" {
t.Fatalf("unexpected error message: %v", err.Error())
}
}

View File

@ -2747,7 +2747,7 @@ func TestCreateCertificateLegacy(t *testing.T) {
DNSNames: []string{"example.com"}, DNSNames: []string{"example.com"},
SignatureAlgorithm: sigAlg, SignatureAlgorithm: sigAlg,
} }
_, err := CreateCertificate(rand.Reader, template.asX509(), template.asX509(), testPrivateKey.Public(), &brokenSigner{testPrivateKey.Public()}) _, err := CreateCertificate(rand.Reader, template, template, testPrivateKey.Public(), &brokenSigner{testPrivateKey.Public()})
if err == nil { if err == nil {
t.Fatal("CreateCertificate didn't fail when SignatureAlgorithm = MD5WithRSA") t.Fatal("CreateCertificate didn't fail when SignatureAlgorithm = MD5WithRSA")
} }
@ -3085,7 +3085,7 @@ func TestDisableSHA1ForCertOnly(t *testing.T) {
IsCA: true, IsCA: true,
KeyUsage: KeyUsageCertSign | KeyUsageCRLSign, KeyUsage: KeyUsageCertSign | KeyUsageCRLSign,
} }
certDER, err := CreateCertificate(rand.Reader, tmpl.asX509(), tmpl.asX509(), rsaPrivateKey.Public(), rsaPrivateKey) certDER, err := CreateCertificate(rand.Reader, tmpl, tmpl, rsaPrivateKey.Public(), rsaPrivateKey)
if err != nil { if err != nil {
t.Fatalf("failed to generate test cert: %s", err) t.Fatalf("failed to generate test cert: %s", err)
} }
@ -3148,7 +3148,7 @@ func TestOmitEmptyExtensions(t *testing.T) {
NotAfter: time.Now().Add(time.Hour), NotAfter: time.Now().Add(time.Hour),
NotBefore: time.Now().Add(-time.Hour), NotBefore: time.Now().Add(-time.Hour),
} }
der, err := CreateCertificate(rand.Reader, tmpl.asX509(), tmpl.asX509(), k.Public(), k) der, err := CreateCertificate(rand.Reader, tmpl, tmpl, k.Public(), k)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -3190,7 +3190,7 @@ func TestCreateNegativeSerial(t *testing.T) {
NotBefore: time.Now().Add(-time.Hour), NotBefore: time.Now().Add(-time.Hour),
} }
expectedErr := "x509: serial number must be positive" expectedErr := "x509: serial number must be positive"
_, err = CreateCertificate(rand.Reader, tmpl.asX509(), tmpl.asX509(), k.Public(), k) _, err = CreateCertificate(rand.Reader, tmpl, tmpl, k.Public(), k)
if err == nil || err.Error() != expectedErr { if err == nil || err.Error() != expectedErr {
t.Errorf("CreateCertificate returned unexpected error: want %q, got %q", expectedErr, err) t.Errorf("CreateCertificate returned unexpected error: want %q, got %q", expectedErr, err)
} }