import (
"crypto"
+ "crypto/dsa"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
t.Fatalf("unexpected error, got %q, want %q", err, expectedErr)
}
}
+
+func TestCertificateChainSignedByECDSA(t *testing.T) {
+ caKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+ root := &Certificate{
+ SerialNumber: big.NewInt(1),
+ Subject: pkix.Name{CommonName: "X"},
+ NotBefore: time.Now().Add(-time.Hour),
+ NotAfter: time.Now().Add(365 * 24 * time.Hour),
+ IsCA: true,
+ KeyUsage: KeyUsageCertSign | KeyUsageCRLSign,
+ BasicConstraintsValid: true,
+ }
+ caDER, err := CreateCertificate(rand.Reader, root, root, &caKey.PublicKey, caKey)
+ if err != nil {
+ t.Fatal(err)
+ }
+ root, err = ParseCertificate(caDER)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ leafKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ leaf := &Certificate{
+ SerialNumber: big.NewInt(42),
+ Subject: pkix.Name{CommonName: "leaf"},
+ NotBefore: time.Now().Add(-10 * time.Minute),
+ NotAfter: time.Now().Add(24 * time.Hour),
+ KeyUsage: KeyUsageDigitalSignature,
+ ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth},
+ BasicConstraintsValid: true,
+ }
+ leafDER, err := CreateCertificate(rand.Reader, leaf, root, &leafKey.PublicKey, caKey)
+ if err != nil {
+ t.Fatal(err)
+ }
+ leaf, err = ParseCertificate(leafDER)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ inter, err := ParseCertificate(dsaSelfSignedCNX(t))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ inters := NewCertPool()
+ inters.AddCert(root)
+ inters.AddCert(inter)
+
+ wantErr := "certificate signed by unknown authority"
+ _, err = leaf.Verify(VerifyOptions{Intermediates: inters, Roots: NewCertPool()})
+ if !strings.Contains(err.Error(), wantErr) {
+ t.Errorf("got %v, want %q", err, wantErr)
+ }
+}
+
+// dsaSelfSignedCNX produces DER-encoded
+// certificate with the properties:
+//
+// Subject=Issuer=CN=X
+// DSA SPKI
+// Matching inner/outer signature OIDs
+// Dummy ECDSA signature
+func dsaSelfSignedCNX(t *testing.T) []byte {
+ t.Helper()
+ var params dsa.Parameters
+ if err := dsa.GenerateParameters(¶ms, rand.Reader, dsa.L1024N160); err != nil {
+ t.Fatal(err)
+ }
+
+ var dsaPriv dsa.PrivateKey
+ dsaPriv.Parameters = params
+ if err := dsa.GenerateKey(&dsaPriv, rand.Reader); err != nil {
+ t.Fatal(err)
+ }
+ dsaPub := &dsaPriv.PublicKey
+
+ type dsaParams struct{ P, Q, G *big.Int }
+ paramDER, err := asn1.Marshal(dsaParams{dsaPub.P, dsaPub.Q, dsaPub.G})
+ if err != nil {
+ t.Fatal(err)
+ }
+ yDER, err := asn1.Marshal(dsaPub.Y)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ spki := publicKeyInfo{
+ Algorithm: pkix.AlgorithmIdentifier{
+ Algorithm: oidPublicKeyDSA,
+ Parameters: asn1.RawValue{FullBytes: paramDER},
+ },
+ PublicKey: asn1.BitString{Bytes: yDER, BitLength: 8 * len(yDER)},
+ }
+
+ rdn := pkix.Name{CommonName: "X"}.ToRDNSequence()
+ b, err := asn1.Marshal(rdn)
+ if err != nil {
+ t.Fatal(err)
+ }
+ rawName := asn1.RawValue{FullBytes: b}
+
+ algoIdent := pkix.AlgorithmIdentifier{Algorithm: oidSignatureDSAWithSHA256}
+ tbs := tbsCertificate{
+ Version: 0,
+ SerialNumber: big.NewInt(1002),
+ SignatureAlgorithm: algoIdent,
+ Issuer: rawName,
+ Validity: validity{NotBefore: time.Now().Add(-time.Hour), NotAfter: time.Now().Add(24 * time.Hour)},
+ Subject: rawName,
+ PublicKey: spki,
+ }
+ c := certificate{
+ TBSCertificate: tbs,
+ SignatureAlgorithm: algoIdent,
+ SignatureValue: asn1.BitString{Bytes: []byte{0}, BitLength: 8},
+ }
+ dsaDER, err := asn1.Marshal(c)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return dsaDER
+}