package rotator import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/x509" "crypto/x509/pkix" "encoding/pem" "math/big" "net" "testing" "time" ) func TestGenerateRequest(t *testing.T) { addresses := []net.IP{net.ParseIP("10.0.0.1"), net.ParseIP("172.30.1.1")} privateKey, encoded, err := generateRequest(addresses) if err != nil { t.Fatal(err) } block, _ := pem.Decode(encoded) request, err := x509.ParseCertificateRequest(block.Bytes) if err != nil { t.Fatal(err) } if err := request.CheckSignature(); err != nil { t.Fatal(err) } if len(request.IPAddresses) != len(addresses) || !request.IPAddresses[0].Equal(addresses[0]) || !request.IPAddresses[1].Equal(addresses[1]) { t.Fatalf("unexpected IP SANs: %v", request.IPAddresses) } publicKey := request.PublicKey.(*ecdsa.PublicKey) if !publicKey.Equal(&privateKey.PublicKey) { t.Fatal("request does not contain the generated public key") } } func TestRequiredURL(t *testing.T) { t.Setenv("OPNSENSE_URL", "https://172.30.1.1:8443") if value, err := requiredURL("OPNSENSE_URL"); err != nil || value != "https://172.30.1.1:8443" { t.Fatalf("unexpected URL result: value=%q error=%v", value, err) } for _, value := range []string{"", "http://172.30.1.1:8443", "https://user@172.30.1.1:8443", "https://172.30.1.1:8443/api"} { t.Run(value, func(t *testing.T) { t.Setenv("OPNSENSE_URL", value) if _, err := requiredURL("OPNSENSE_URL"); err == nil { t.Fatalf("accepted invalid URL %q", value) } }) } } func TestVerifySignedCertificate(t *testing.T) { addresses := []net.IP{net.ParseIP("10.0.0.1"), net.ParseIP("172.30.1.1")} now := time.Now() rootKey, root := createCertificate(t, nil, nil, &x509.Certificate{ SerialNumber: big.NewInt(1), Subject: pkix.Name{CommonName: "root"}, NotBefore: now.Add(-time.Hour), NotAfter: now.Add(24 * time.Hour), IsCA: true, BasicConstraintsValid: true, KeyUsage: x509.KeyUsageCertSign, }) leafKey, leaf := createCertificate(t, root, rootKey, &x509.Certificate{ SerialNumber: big.NewInt(2), NotBefore: now.Add(-time.Hour), NotAfter: now.Add(12 * time.Hour), IPAddresses: addresses, KeyUsage: x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, }) rootPEM := string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: root.Raw})) trustedRoots := x509.NewCertPool() trustedRoots.AddCert(root) if err := verifySignedCertificate(leaf, []string{rootPEM}, trustedRoots, addresses, leafKey); err != nil { t.Fatal(err) } if err := verifySignedCertificate(leaf, []string{rootPEM}, trustedRoots, []net.IP{net.ParseIP("10.0.0.1"), net.ParseIP("172.30.1.2")}, leafKey); err == nil { t.Fatal("wrong IP SAN was accepted") } } func createCertificate(t *testing.T, parent *x509.Certificate, parentKey *ecdsa.PrivateKey, template *x509.Certificate) (*ecdsa.PrivateKey, *x509.Certificate) { t.Helper() key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { t.Fatal(err) } if parent == nil { parent = template parentKey = key } encoded, err := x509.CreateCertificate(rand.Reader, template, parent, &key.PublicKey, parentKey) if err != nil { t.Fatal(err) } certificate, err := x509.ParseCertificate(encoded) if err != nil { t.Fatal(err) } return key, certificate }