]> ruderich.org/simon Gitweb - nsscash/nsscash.git/commitdiff
nsscash: add "ca" option for files
authorSimon Ruderich <simon@ruderich.org>
Thu, 1 Aug 2019 21:21:58 +0000 (23:21 +0200)
committerSimon Ruderich <simon@ruderich.org>
Thu, 1 Aug 2019 21:21:58 +0000 (23:21 +0200)
Also run all main_test tests with HTTP and HTTPS.

14 files changed:
README
config.go
fetch.go
file.go
main_test.go
testdata/README [new file with mode: 0644]
testdata/ca.cfg [new file with mode: 0644]
testdata/ca.crt [new file with mode: 0644]
testdata/ca.key [new file with mode: 0644]
testdata/ca2.crt [new file with mode: 0644]
testdata/ca2.key [new file with mode: 0644]
testdata/server.cfg [new file with mode: 0644]
testdata/server.crt [new file with mode: 0644]
testdata/server.key [new file with mode: 0644]

diff --git a/README b/README
index 32e05470b47976961533918573e3b358ced38ff6..b5a60ab6bb068f9bb1036ea40b3d56f73730c88a 100644 (file)
--- a/README
+++ b/README
@@ -147,6 +147,10 @@ keys are available:
 
 - `url`: URL to fetch the file from; HTTP and HTTPS are supported
 
 
 - `url`: URL to fetch the file from; HTTP and HTTPS are supported
 
+- `ca`: Path to a custom CA in PEM format. Restricts HTTPS requests to accept
+  only certificates signed by this CA. Defaults to the system's certificate
+  store when omitted.
+
 - `path`: Path to store the retrieved file
 
 
 - `path`: Path to store the retrieved file
 
 
index 99b27cff35e423e607d541bbbea2fe1c9f1a0db2..8db49c1fe4875ebd959a084996280ea6f82cef09 100644 (file)
--- a/config.go
+++ b/config.go
@@ -32,6 +32,7 @@ type File struct {
        Type FileType
        Url  string
        Path string
        Type FileType
        Url  string
        Path string
+       CA   string
 
        body []byte // internally used by handleFiles()
 }
 
        body []byte // internally used by handleFiles()
 }
index 9834f3ead8d5beddc74134e722bd60797869f394..ba1bbc8f4bde2019503102a1100ea1cf01bcc0a0 100644 (file)
--- a/fetch.go
+++ b/fetch.go
 package main
 
 import (
 package main
 
 import (
+       "crypto/tls"
+       "crypto/x509"
+       "fmt"
        "io/ioutil"
        "net/http"
        "time"
        "io/ioutil"
        "net/http"
        "time"
+
+       "github.com/pkg/errors"
 )
 
 // Global variable to permit reuse of connections (keep-alive)
 )
 
 // Global variable to permit reuse of connections (keep-alive)
-var client *http.Client
+var clients map[string]*http.Client
 
 func init() {
 
 func init() {
-       client = &http.Client{}
+       clients = make(map[string]*http.Client)
+       clients[""] = &http.Client{}
 }
 
 }
 
-func fetchIfModified(url string, lastModified *time.Time) (int, []byte, error) {
+func fetchIfModified(url, ca string, lastModified *time.Time) (int, []byte, error) {
        req, err := http.NewRequest("GET", url, nil)
        if err != nil {
                return 0, nil, err
        req, err := http.NewRequest("GET", url, nil)
        if err != nil {
                return 0, nil, err
@@ -40,6 +46,29 @@ func fetchIfModified(url string, lastModified *time.Time) (int, []byte, error) {
                        lastModified.Format(http.TimeFormat))
        }
 
                        lastModified.Format(http.TimeFormat))
        }
 
+       client, ok := clients[ca]
+       if !ok {
+               pem, err := ioutil.ReadFile(ca)
+               if err != nil {
+                       return 0, nil, errors.Wrapf(err, "file.ca %q", ca)
+               }
+               pool := x509.NewCertPool()
+               ok := pool.AppendCertsFromPEM(pem)
+               if !ok {
+                       return 0, nil, fmt.Errorf(
+                               "file.ca %q: no PEM cert found", ca)
+               }
+
+               client = &http.Client{
+                       Transport: &http.Transport{
+                               TLSClientConfig: &tls.Config{
+                                       RootCAs: pool,
+                               },
+                       },
+               }
+               clients[ca] = client
+       }
+
        resp, err := client.Do(req)
        if err != nil {
                return 0, nil, err
        resp, err := client.Do(req)
        if err != nil {
                return 0, nil, err
diff --git a/file.go b/file.go
index 2ecab66ee85e1aeac6c4cf76c34eef3ecdefdf45..07ac987cbec6d9fb128cd746e467461750f44882 100644 (file)
--- a/file.go
+++ b/file.go
@@ -89,7 +89,7 @@ func fetchFile(file *File, state *State) error {
                t = zero // force download
        }
 
                t = zero // force download
        }
 
-       status, body, err := fetchIfModified(file.Url, &t)
+       status, body, err := fetchIfModified(file.Url, file.CA, &t)
        if err != nil {
                return err
        }
        if err != nil {
                return err
        }
index 2b48bcc7c9d37315910f8efdac80633ed269a6af..38499da197bb6fd0be3276e48d11527215a30a8c 100644 (file)
@@ -17,6 +17,7 @@ package main
 
 import (
        "crypto/sha1"
 
 import (
        "crypto/sha1"
+       "crypto/tls"
        "encoding/hex"
        "fmt"
        "io/ioutil"
        "encoding/hex"
        "fmt"
        "io/ioutil"
@@ -37,6 +38,10 @@ const (
        passwdPath = "testdata/passwd.nsscash"
        plainPath  = "testdata/plain"
        groupPath  = "testdata/group.nsscash"
        passwdPath = "testdata/passwd.nsscash"
        plainPath  = "testdata/plain"
        groupPath  = "testdata/group.nsscash"
+       tlsCAPath   = "testdata/ca.crt"
+       tlsCertPath = "testdata/server.crt"
+       tlsKeyPath  = "testdata/server.key"
+       tlsCA2Path  = "testdata/ca2.crt"
 )
 
 type args struct {
 )
 
 type args struct {
@@ -104,7 +109,8 @@ statepath = "%[1]s"
 type = "passwd"
 url = "%[2]s/passwd"
 path = "%[3]s"
 type = "passwd"
 url = "%[2]s/passwd"
 path = "%[3]s"
-`, statePath, url, passwdPath))
+ca = "%[4]s"
+`, statePath, url, passwdPath, tlsCAPath))
 }
 
 func mustWriteGroupConfig(t *testing.T, url string) {
 }
 
 func mustWriteGroupConfig(t *testing.T, url string) {
@@ -115,7 +121,8 @@ statepath = "%[1]s"
 type = "group"
 url = "%[2]s/group"
 path = "%[3]s"
 type = "group"
 url = "%[2]s/group"
 path = "%[3]s"
-`, statePath, url, groupPath))
+ca = "%[4]s"
+`, statePath, url, groupPath, tlsCAPath))
 }
 
 // mustCreate creates a file, truncating it if it exists. It then changes the
 }
 
 // mustCreate creates a file, truncating it if it exists. It then changes the
@@ -207,12 +214,30 @@ func TestMainFetch(t *testing.T) {
                fetchSecondFetchFails,
        }
 
                fetchSecondFetchFails,
        }
 
+       // HTTP tests
+
+       for _, f := range tests {
+               runMainTest(t, f, nil)
+       }
+
+       // HTTPS tests
+
+       tests = append(tests, fetchInvalidCA)
+
+       cert, err := tls.LoadX509KeyPair(tlsCertPath, tlsKeyPath)
+       if err != nil {
+               t.Fatal(err)
+       }
+       tls := &tls.Config{
+               Certificates: []tls.Certificate{cert},
+       }
+
        for _, f := range tests {
        for _, f := range tests {
-               runMainTest(t, f)
+               runMainTest(t, f, tls)
        }
 }
 
        }
 }
 
-func runMainTest(t *testing.T, f func(args)) {
+func runMainTest(t *testing.T, f func(args), tls *tls.Config) {
        cleanup := []string{
                configPath,
                statePath,
        cleanup := []string{
                configPath,
                statePath,
@@ -226,6 +251,9 @@ func runMainTest(t *testing.T, f func(args)) {
        fn := runtime.FuncForPC(reflect.ValueOf(f).Pointer())
        name := fn.Name()
        name = name[strings.LastIndex(name, ".")+1:]
        fn := runtime.FuncForPC(reflect.ValueOf(f).Pointer())
        name := fn.Name()
        name = name[strings.LastIndex(name, ".")+1:]
+       if tls != nil {
+               name = "tls" + name
+       }
 
        t.Run(name, func(t *testing.T) {
                // Preparation & cleanup
 
        t.Run(name, func(t *testing.T) {
                // Preparation & cleanup
@@ -240,10 +268,16 @@ func runMainTest(t *testing.T, f func(args)) {
                }
 
                var handler func(http.ResponseWriter, *http.Request)
                }
 
                var handler func(http.ResponseWriter, *http.Request)
-               ts := httptest.NewServer(http.HandlerFunc(
+               ts := httptest.NewUnstartedServer(http.HandlerFunc(
                        func(w http.ResponseWriter, r *http.Request) {
                                handler(w, r)
                        }))
                        func(w http.ResponseWriter, r *http.Request) {
                                handler(w, r)
                        }))
+               if tls == nil {
+                       ts.Start()
+               } else {
+                       ts.TLS = tls
+                       ts.StartTLS()
+               }
                defer ts.Close()
 
                f(args{
                defer ts.Close()
 
                f(args{
@@ -464,7 +498,8 @@ statepath = "%[1]s"
 type = "plain"
 url = "%[2]s/plain"
 path = "%[3]s"
 type = "plain"
 url = "%[2]s/plain"
 path = "%[3]s"
-`, statePath, a.url, plainPath))
+ca = "%[4]s"
+`, statePath, a.url, plainPath, tlsCAPath))
        mustCreate(t, plainPath)
 
        *a.handler = func(w http.ResponseWriter, r *http.Request) {
        mustCreate(t, plainPath)
 
        *a.handler = func(w http.ResponseWriter, r *http.Request) {
@@ -488,7 +523,8 @@ statepath = "%[1]s"
 type = "plain"
 url = "%[2]s/plain"
 path = "%[3]s"
 type = "plain"
 url = "%[2]s/plain"
 path = "%[3]s"
-`, statePath, a.url, plainPath))
+ca = "%[4]s"
+`, statePath, a.url, plainPath, tlsCAPath))
        mustCreate(t, plainPath)
        mustHaveHash(t, plainPath, "da39a3ee5e6b4b0d3255bfef95601890afd80709")
 
        mustCreate(t, plainPath)
        mustHaveHash(t, plainPath, "da39a3ee5e6b4b0d3255bfef95601890afd80709")
 
@@ -707,12 +743,14 @@ statepath = "%[1]s"
 type = "passwd"
 url = "%[2]s/passwd"
 path = "%[3]s"
 type = "passwd"
 url = "%[2]s/passwd"
 path = "%[3]s"
+ca = "%[5]s"
 
 [[file]]
 type = "group"
 url = "%[2]s/group"
 path = "%[4]s"
 
 [[file]]
 type = "group"
 url = "%[2]s/group"
 path = "%[4]s"
-`, statePath, a.url, passwdPath, groupPath))
+ca = "%[5]s"
+`, statePath, a.url, passwdPath, groupPath, tlsCAPath))
        mustCreate(t, passwdPath)
        mustCreate(t, groupPath)
        mustHaveHash(t, passwdPath, "da39a3ee5e6b4b0d3255bfef95601890afd80709")
        mustCreate(t, passwdPath)
        mustCreate(t, groupPath)
        mustHaveHash(t, passwdPath, "da39a3ee5e6b4b0d3255bfef95601890afd80709")
@@ -736,3 +774,60 @@ path = "%[4]s"
        // because the second fetch failed
        mustBeOld(t, passwdPath, groupPath)
 }
        // because the second fetch failed
        mustBeOld(t, passwdPath, groupPath)
 }
+
+func fetchInvalidCA(a args) {
+       t := a.t
+
+       // System CA
+
+       mustWriteConfig(t, fmt.Sprintf(`
+statepath = "%[1]s"
+
+[[file]]
+type = "passwd"
+url = "%[2]s/passwd"
+path = "%[3]s"
+`, statePath, a.url, passwdPath))
+       mustCreate(t, passwdPath)
+       mustHaveHash(t, passwdPath, "da39a3ee5e6b4b0d3255bfef95601890afd80709")
+
+       *a.handler = func(w http.ResponseWriter, r *http.Request) {
+               if r.URL.Path == "/passwd" {
+                       fmt.Fprintln(w, "root:x:0:0:root:/root:/bin/bash")
+               }
+       }
+
+       err := mainFetch(configPath)
+       mustBeErrorWithSubstring(t, err,
+               "x509: certificate signed by unknown authority")
+
+       mustNotExist(t, statePath, plainPath, groupPath)
+       mustBeOld(t, passwdPath)
+
+       // Invalid CA
+
+       mustWriteConfig(t, fmt.Sprintf(`
+statepath = "%[1]s"
+
+[[file]]
+type = "passwd"
+url = "%[2]s/passwd"
+path = "%[3]s"
+ca = "%[4]s"
+`, statePath, a.url, passwdPath, tlsCA2Path))
+       mustCreate(t, passwdPath)
+       mustHaveHash(t, passwdPath, "da39a3ee5e6b4b0d3255bfef95601890afd80709")
+
+       *a.handler = func(w http.ResponseWriter, r *http.Request) {
+               if r.URL.Path == "/passwd" {
+                       fmt.Fprintln(w, "root:x:0:0:root:/root:/bin/bash")
+               }
+       }
+
+       err = mainFetch(configPath)
+       mustBeErrorWithSubstring(t, err,
+               "x509: certificate signed by unknown authority")
+
+       mustNotExist(t, statePath, plainPath, groupPath)
+       mustBeOld(t, passwdPath)
+}
diff --git a/testdata/README b/testdata/README
new file mode 100644 (file)
index 0000000..06c7cd5
--- /dev/null
@@ -0,0 +1,12 @@
+= README
+
+To re-generate the test CA and test certificates run the following commands:
+
+    certtool --generate-privkey > ca.key
+    certtool --generate-self-signed --load-privkey ca.key --template ca.cfg > ca.crt
+
+    certtool --generate-privkey > server.key
+    certtool --generate-certificate --load-privkey server.key --load-ca-certificate ca.crt --load-ca-privkey ca.key --template server.cfg > server.crt
+
+    certtool --generate-privkey > ca2.key
+    certtool --generate-self-signed --load-privkey ca2.key --template ca.cfg > ca2.crt
diff --git a/testdata/ca.cfg b/testdata/ca.cfg
new file mode 100644 (file)
index 0000000..60f3e89
--- /dev/null
@@ -0,0 +1,3 @@
+cn = Test CA
+ca
+expiration_days = -1
diff --git a/testdata/ca.crt b/testdata/ca.crt
new file mode 100644 (file)
index 0000000..bdeac4f
--- /dev/null
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIID5jCCAk6gAwIBAgIUIEI3z2UX3k3ctBLclMAoYyEIchswDQYJKoZIhvcNAQEL
+BQAwEjEQMA4GA1UEAxMHVGVzdCBDQTAgFw0xOTA4MDEwNzQwMTlaGA85OTk5MTIz
+MTIzNTk1OVowEjEQMA4GA1UEAxMHVGVzdCBDQTCCAaIwDQYJKoZIhvcNAQEBBQAD
+ggGPADCCAYoCggGBAN3CjhEiN5QNHJIYk0dOgYD317wyD3Nno8zncslAEisT5GfI
+PSZJyDaD9JpEbv0axj6Dr9qOkl+hBnl4TImh6hIGDlVC0DkXSASZsSiX3+fN4ill
+Z3pj/vTmnZAwjLd/vv/30rRSPViebidxERTi+svWOcA2t1YLXPlMTu7vK2N+INrl
+IwhZJwShnwCyR+cNvR9LoY8yiXXyrz5kCznS0f0eu93JFM3RYcS3i6nVuVd5nkzZ
+KHzVDYa4L14JDAnGL4YxejFMIUY2fns0V+Vb9sRwEctPCUv8VzSJXz26ECIZ+9Yk
+q+WDEvV91I0lyZaPH86Uw1IQUhNPyRtE465mrpRw5Z33NDjC4DqxyzxdgwR01wBP
+gApPOUwJ9uT0yrVC2sddcD1LFVm8RhOmi6SETZehwKcz5eC/b6geQu1bVvJNF6dt
+jmeIlHJSVQSO9FdwyfyXmRDE/z9I/DcmryzcLkUAi48hAW63D8X5DTQduQli7KAZ
+zP/p8SkLCturcwSxFQIDAQABozIwMDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
+BBTxc+gg5oElW6nJqfCDUpcd4uh52DANBgkqhkiG9w0BAQsFAAOCAYEARIFXNC3G
+gU4c0oYWrka6cki8f2Dd9PXflAEw8f8nzD0cZn6Lgl70LfvA/0ndd0hyBaImYh40
+Kt3f75CvWinZL86HV29QRDBFkhtQRHPImBrsh1X9vaM066fNQuIiTiZpo82h3+b5
+UAmqeCn0ntc2cvMQY1an7TstWcK8I6rJ+ZJMpGmlaPQlw1Xo8t9Re6NgNSKG797d
+CYBErwAO56AyfPamzIpQkW/UVN2vNcTkxZmikBFKB3QLaPW6SH/aU8lX3XLhxgNM
+wDD/it17YC6PJzIpUK98/f++BV8E2dWwHXmyjy4Y7ZCNm5tG7CeIflUhuJ+RQzmy
+NmpBcjojzeHly0a0nVswvR+XRIZ+zn74KztsB8R+5poH1519FerWJjK/cEx6q4PC
+94oWrNmjJsDhuk8ywRBXOvUshTaFi6FWgCUYqs+DwzpLpDBRQpyxBOJWrCatMvs4
+WP4+1DoIfreiEDPpnf6Oh0mX804X/cOvO0bBXIlJ9yRUhppRXUKWvtMz
+-----END CERTIFICATE-----
diff --git a/testdata/ca.key b/testdata/ca.key
new file mode 100644 (file)
index 0000000..72142ed
--- /dev/null
@@ -0,0 +1,182 @@
+Public Key Info:
+       Public Key Algorithm: RSA
+       Key Security Level: High (3072 bits)
+
+modulus:
+       00:dd:c2:8e:11:22:37:94:0d:1c:92:18:93:47:4e:81
+       80:f7:d7:bc:32:0f:73:67:a3:cc:e7:72:c9:40:12:2b
+       13:e4:67:c8:3d:26:49:c8:36:83:f4:9a:44:6e:fd:1a
+       c6:3e:83:af:da:8e:92:5f:a1:06:79:78:4c:89:a1:ea
+       12:06:0e:55:42:d0:39:17:48:04:99:b1:28:97:df:e7
+       cd:e2:29:65:67:7a:63:fe:f4:e6:9d:90:30:8c:b7:7f
+       be:ff:f7:d2:b4:52:3d:58:9e:6e:27:71:11:14:e2:fa
+       cb:d6:39:c0:36:b7:56:0b:5c:f9:4c:4e:ee:ef:2b:63
+       7e:20:da:e5:23:08:59:27:04:a1:9f:00:b2:47:e7:0d
+       bd:1f:4b:a1:8f:32:89:75:f2:af:3e:64:0b:39:d2:d1
+       fd:1e:bb:dd:c9:14:cd:d1:61:c4:b7:8b:a9:d5:b9:57
+       79:9e:4c:d9:28:7c:d5:0d:86:b8:2f:5e:09:0c:09:c6
+       2f:86:31:7a:31:4c:21:46:36:7e:7b:34:57:e5:5b:f6
+       c4:70:11:cb:4f:09:4b:fc:57:34:89:5f:3d:ba:10:22
+       19:fb:d6:24:ab:e5:83:12:f5:7d:d4:8d:25:c9:96:8f
+       1f:ce:94:c3:52:10:52:13:4f:c9:1b:44:e3:ae:66:ae
+       94:70:e5:9d:f7:34:38:c2:e0:3a:b1:cb:3c:5d:83:04
+       74:d7:00:4f:80:0a:4f:39:4c:09:f6:e4:f4:ca:b5:42
+       da:c7:5d:70:3d:4b:15:59:bc:46:13:a6:8b:a4:84:4d
+       97:a1:c0:a7:33:e5:e0:bf:6f:a8:1e:42:ed:5b:56:f2
+       4d:17:a7:6d:8e:67:88:94:72:52:55:04:8e:f4:57:70
+       c9:fc:97:99:10:c4:ff:3f:48:fc:37:26:af:2c:dc:2e
+       45:00:8b:8f:21:01:6e:b7:0f:c5:f9:0d:34:1d:b9:09
+       62:ec:a0:19:cc:ff:e9:f1:29:0b:0a:db:ab:73:04:b1
+       15:
+
+public exponent:
+       01:00:01:
+
+private exponent:
+       00:d9:5d:50:3f:7f:18:97:27:da:ef:60:e3:4b:ab:a9
+       c8:ae:26:6a:33:6f:6d:a1:12:af:4f:d5:f5:69:b5:e5
+       3f:94:4c:1d:bb:c2:81:e3:9b:7b:f0:10:1e:2f:e4:2b
+       90:51:ca:66:5e:86:0c:f7:6b:30:9b:73:cd:21:c2:f1
+       5a:45:51:5b:45:28:30:2d:9f:cb:d2:92:11:c5:fc:14
+       8c:7b:b8:33:cb:1f:ee:50:03:e0:e0:64:6b:12:22:f3
+       36:56:53:a5:d6:56:1e:07:75:13:67:d9:ad:f2:99:21
+       57:17:5e:78:07:a9:e0:cf:36:8c:ad:bd:58:fa:59:bf
+       25:ec:32:63:12:d9:a5:f9:56:d2:cc:b5:b4:0a:42:71
+       f7:04:6b:ef:aa:1a:d1:1e:29:88:98:51:1b:a7:cb:fb
+       44:6e:11:9b:2c:f4:15:61:bc:c1:43:5f:c4:52:d7:5e
+       e4:b8:c3:7e:bf:ee:cc:2e:7b:f4:a1:89:3c:b8:ee:03
+       b0:d2:62:71:11:93:a1:c6:0e:15:ee:1c:07:0b:a2:e6
+       67:f2:a3:55:2f:6b:80:b2:aa:b3:41:d3:9b:5c:a7:e2
+       86:0b:20:e2:68:a5:4d:d9:1e:ed:7e:c1:a0:60:a1:3a
+       ff:31:da:57:d1:3d:a3:8a:42:06:46:7b:57:5e:dd:69
+       ff:14:fd:c0:9f:e4:a1:ab:53:3f:2c:c8:9b:e9:6f:a2
+       88:29:d5:f7:7e:77:b9:36:f9:51:a5:21:9a:10:3c:44
+       0a:08:c7:6a:29:77:e3:d3:32:dd:41:a4:6c:2c:5e:36
+       00:f3:9c:86:2b:05:ad:03:57:73:3e:a4:ed:d6:2d:79
+       43:ed:88:88:0e:3f:c2:06:c1:1b:58:2b:f7:b3:fc:9b
+       06:6a:2d:57:b3:55:61:fc:16:bd:04:02:2f:6e:b9:c7
+       63:42:7f:3b:17:c6:ab:3f:55:e3:f0:ec:f3:f8:78:3a
+       f9:7e:1d:f0:aa:cc:2d:99:d6:6c:1b:b0:b8:46:d4:a6
+       c1:
+
+prime1:
+       00:ea:68:a1:bc:fd:de:fb:11:72:69:7b:84:5a:8b:d0
+       1b:29:d1:2e:9e:64:1d:c1:a7:53:51:f0:2f:d8:e1:7f
+       36:11:f2:a4:f4:e7:39:ff:bd:86:96:5d:74:bc:dd:d2
+       ad:bf:43:2f:a8:0c:c1:3e:9b:2b:c5:96:a7:c9:4e:4e
+       40:2f:b3:4c:be:50:d8:a6:44:c2:04:76:96:78:5a:e9
+       bc:42:90:cc:28:f6:fa:56:37:2a:03:1a:9a:9a:36:e1
+       24:fc:f7:9d:85:3d:d9:90:43:d9:90:b4:6f:61:3d:5c
+       0e:16:bd:05:e3:7d:b9:97:20:4d:62:92:5a:49:bc:74
+       42:c8:28:0c:a6:f4:b2:69:fa:a0:51:b2:3b:59:56:95
+       3c:57:3b:9f:4c:cc:7a:14:27:04:cb:41:ad:46:cd:ce
+       fb:b3:7d:15:53:4e:6a:80:7b:e1:39:f2:5b:c9:56:e6
+       92:a7:09:2d:9b:e9:23:4f:d1:f1:70:b4:66:50:3a:77
+       d9:
+
+prime2:
+       00:f2:2f:aa:54:6b:e5:35:7d:64:03:6e:69:13:54:63
+       18:da:f5:51:18:9b:9d:9d:46:5a:3c:83:f4:ab:17:20
+       82:ec:77:a5:54:2d:8c:37:37:b7:5c:9a:cc:fe:25:38
+       e0:8a:a5:58:bb:a1:6e:7a:a2:5c:3f:28:6b:90:97:20
+       20:3a:6b:1d:97:75:a0:14:ff:fb:ce:29:53:8b:92:55
+       5e:23:80:c7:8e:85:3c:bd:f6:21:73:70:52:83:be:26
+       c4:a2:d9:dc:1e:d6:56:26:0b:1b:cb:2c:a7:47:57:29
+       65:9b:30:29:52:76:bd:13:6d:00:77:ec:d0:03:81:b4
+       ed:33:18:eb:d3:09:87:f5:6b:98:91:05:7a:14:1e:a5
+       94:f9:4f:e2:95:c3:25:39:30:84:16:5e:28:bc:0e:34
+       52:6b:67:dd:71:e7:d4:fb:17:22:e9:7c:d8:52:ee:93
+       71:9e:94:b4:28:3d:0e:52:d5:04:16:f7:47:d8:fd:19
+       9d:
+
+coefficient:
+       00:d1:0f:b9:20:d5:5e:74:11:2e:bb:67:66:c9:0f:52
+       2b:62:6c:b2:8a:60:bc:aa:61:23:bb:a4:83:cf:77:3b
+       af:25:b2:18:fa:d1:8a:c0:19:cf:a8:20:45:92:ec:a8
+       60:99:26:b4:71:f7:58:17:dc:bc:2d:8d:9c:ca:d9:ce
+       93:d7:21:3b:be:2f:e4:fa:ca:bc:d4:8d:dc:c5:5a:d4
+       87:6d:62:1e:0f:b4:86:c9:a6:6c:06:d6:5e:3d:58:70
+       15:76:e6:b6:63:31:f9:c4:f1:87:27:6b:90:c9:74:48
+       b3:7c:52:16:77:9c:10:ce:4b:97:0e:e5:c5:74:fd:9e
+       00:b1:63:9e:78:4a:53:e4:6e:f0:9f:8a:a8:37:9c:50
+       f5:45:b4:7c:3a:6d:9b:32:9d:c5:3b:0c:84:f1:14:65
+       e6:7c:41:c5:6d:99:40:b9:a0:fc:c7:9b:4b:23:cb:c1
+       7d:30:8c:11:8d:cd:31:60:a1:69:65:5c:58:71:53:e5
+       a6:
+
+exp1:
+       51:70:52:a8:e7:86:bd:b1:9d:0f:5a:b3:6c:05:e1:22
+       5e:cf:e7:23:6e:63:0c:31:c6:f7:d3:bb:bb:dc:f4:26
+       63:eb:ea:35:8f:d4:0d:ae:da:00:89:ad:92:24:7b:1a
+       94:35:92:6c:0f:2a:60:46:e6:d9:39:f3:47:34:26:69
+       94:68:f5:c3:b5:30:df:eb:49:80:e5:76:77:90:16:5e
+       aa:bd:c5:c0:81:b6:0d:98:12:c7:8b:49:a5:44:65:ca
+       44:fc:fe:44:19:6d:e9:fa:38:af:56:90:cf:b6:d2:b1
+       ae:62:b3:96:0a:cb:1c:df:43:23:78:f7:57:60:da:ff
+       8c:ac:a5:60:a7:e9:08:7a:e3:92:1e:9b:11:f9:cb:d5
+       6f:f5:2d:ee:2f:a8:46:32:1c:2f:45:bd:1e:b9:48:2d
+       18:79:df:9b:d6:c5:97:a7:f2:63:00:79:b5:24:b4:ec
+       c4:8d:a2:c3:e5:26:b8:87:97:1b:72:01:8d:e4:12:59
+       
+
+exp2:
+       1d:a5:03:fe:6d:6e:93:0b:94:30:6f:55:61:4e:55:0a
+       f7:d2:4b:68:ed:b3:6f:4a:eb:44:b9:0a:3b:df:0a:d5
+       bb:c8:31:6e:8a:5c:bd:6d:8e:7e:41:5c:92:47:50:1c
+       fc:1b:9d:2e:ea:65:b1:91:2a:25:78:f7:21:ad:bd:fa
+       f3:eb:a4:a5:a3:7a:42:d7:ca:a4:c3:9e:3c:59:5f:25
+       b4:c6:d0:a6:7b:5c:a2:0b:fc:b0:3a:b1:7e:fa:c9:98
+       0c:2f:0a:a8:a3:a7:cb:e4:54:34:9c:74:a5:60:df:ea
+       56:02:a1:2c:3c:e8:8b:f6:2d:b6:80:40:3e:0d:a4:6d
+       dc:71:52:7c:74:90:35:d4:43:ca:8c:97:12:db:65:7d
+       44:bf:28:87:18:69:f8:04:1e:46:f6:a3:99:d1:4b:4a
+       43:67:65:4d:ca:08:e1:eb:45:14:bb:79:67:3d:58:c2
+       f1:9c:56:29:0e:c0:30:17:6e:f6:b8:b2:0c:b7:7e:69
+       
+
+
+Public Key PIN:
+       pin-sha256:Jfh1923uFu2xFgdj8fN5FzXVs2xd9OhbzCcEWinpgtk=
+Public Key ID:
+       sha256:25f875f76dee16edb1160763f1f3791735d5b36c5df4e85bcc27045a29e982d9
+       sha1:f173e820e681255ba9c9a9f08352971de2e879d8
+
+-----BEGIN RSA PRIVATE KEY-----
+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
+-----END RSA PRIVATE KEY-----
diff --git a/testdata/ca2.crt b/testdata/ca2.crt
new file mode 100644 (file)
index 0000000..d7c1c3d
--- /dev/null
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIID5jCCAk6gAwIBAgIUax20T9SptmHBg8oPVBeMs+odInAwDQYJKoZIhvcNAQEL
+BQAwEjEQMA4GA1UEAxMHVGVzdCBDQTAgFw0xOTA4MDEyMDM2NDdaGA85OTk5MTIz
+MTIzNTk1OVowEjEQMA4GA1UEAxMHVGVzdCBDQTCCAaIwDQYJKoZIhvcNAQEBBQAD
+ggGPADCCAYoCggGBAMsvbj50om+iACUe8zuMoyW1lusjKPzxHXp95/RuwU4s/mDb
+meWnEazDy+NjPZJflCrYcy/fjwui4/Lva5FIPMkYlVYOnwbZlxnYk9eAwTId7C3z
+4nBTqRFmBhIUlql6wzhAlyXDmWNM2V+/0U8CbTsWMK1c5VxMQ/WG5QACAkAOd1gk
+ol9g6tNwnaSeMDHJYdppt9C0JOz1ysVVyru1TTEwdE+MbUvNy9z2viY/2pcbzYHL
+Vf5ADKDfyb53YbFINvmiZ+Sfpi6fJOGGpcvr5ZFMURbgTpaViqMsl6jBNcuD/mEX
+/MecHKcBiPn5kqKK8wZtIvU5wHXZPOGw1LaDSExXUPcqd6nRYgS9BEq4VQxXJYW7
+l0wWpJcXv1/ghsI6kmUFw/LLaZWopSWs35xM/6CUspNIegl47cDDhBZlcxJTTfyq
+Fvq7j0I/AYWy58djsz4DcwuBuEKPBtW9yRkjziTIPBWnThu2JTStin19+RFcc1Yw
+JvhLGiqH/p9kNuhDyQIDAQABozIwMDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
+BBRzA2i6X9jSvZG7J2LM/IGHHJAjTzANBgkqhkiG9w0BAQsFAAOCAYEAFQz3HP6g
+lC//48ndvkck36hQ8R9QIncphW9o5ED7fPTEfVf9NcbKGdho4BkNwNdXcUv9O4yn
+fBVYxCfAHupWrkWbC2GlN2ZKSHUczY79+Qy/PObfDjYxFiPUmSXzsj7b73p8cJAT
+tu96yBl2TE+6cQ8g+X5Y2YzHhXeJ7ILZsJ28lYCi2PHKgG7E0VtemsrnNuyibxo5
+qAnUQxjk78RfChBq8hMtjTlutR79tv77252B2uvi/WN4bg7SlV37Vs8KF4wdk8rV
+KGXBmGVWhZfAT51GEDDiv9CJI3KEBfg5VP5Bwjb79Yuot8OFskbhG+BcHoT8YDIM
+2JFusSSXYviuZUPopPstAXi+XcSLzHSRr6Uob1c2owUywOcQjERFH2QI4y/CyMi7
+L2pfaKAjXdpFPphMtnrYbj4LZd0hLG+b1BjrkovmdM6cPilPE6DD39c2q4v+OA04
++383IN2CAf+qzadKN13trlGzGYBOgAIArAQI5VXzhqkdUip2eEKxCNbb
+-----END CERTIFICATE-----
diff --git a/testdata/ca2.key b/testdata/ca2.key
new file mode 100644 (file)
index 0000000..30fe838
--- /dev/null
@@ -0,0 +1,182 @@
+Public Key Info:
+       Public Key Algorithm: RSA
+       Key Security Level: High (3072 bits)
+
+modulus:
+       00:cb:2f:6e:3e:74:a2:6f:a2:00:25:1e:f3:3b:8c:a3
+       25:b5:96:eb:23:28:fc:f1:1d:7a:7d:e7:f4:6e:c1:4e
+       2c:fe:60:db:99:e5:a7:11:ac:c3:cb:e3:63:3d:92:5f
+       94:2a:d8:73:2f:df:8f:0b:a2:e3:f2:ef:6b:91:48:3c
+       c9:18:95:56:0e:9f:06:d9:97:19:d8:93:d7:80:c1:32
+       1d:ec:2d:f3:e2:70:53:a9:11:66:06:12:14:96:a9:7a
+       c3:38:40:97:25:c3:99:63:4c:d9:5f:bf:d1:4f:02:6d
+       3b:16:30:ad:5c:e5:5c:4c:43:f5:86:e5:00:02:02:40
+       0e:77:58:24:a2:5f:60:ea:d3:70:9d:a4:9e:30:31:c9
+       61:da:69:b7:d0:b4:24:ec:f5:ca:c5:55:ca:bb:b5:4d
+       31:30:74:4f:8c:6d:4b:cd:cb:dc:f6:be:26:3f:da:97
+       1b:cd:81:cb:55:fe:40:0c:a0:df:c9:be:77:61:b1:48
+       36:f9:a2:67:e4:9f:a6:2e:9f:24:e1:86:a5:cb:eb:e5
+       91:4c:51:16:e0:4e:96:95:8a:a3:2c:97:a8:c1:35:cb
+       83:fe:61:17:fc:c7:9c:1c:a7:01:88:f9:f9:92:a2:8a
+       f3:06:6d:22:f5:39:c0:75:d9:3c:e1:b0:d4:b6:83:48
+       4c:57:50:f7:2a:77:a9:d1:62:04:bd:04:4a:b8:55:0c
+       57:25:85:bb:97:4c:16:a4:97:17:bf:5f:e0:86:c2:3a
+       92:65:05:c3:f2:cb:69:95:a8:a5:25:ac:df:9c:4c:ff
+       a0:94:b2:93:48:7a:09:78:ed:c0:c3:84:16:65:73:12
+       53:4d:fc:aa:16:fa:bb:8f:42:3f:01:85:b2:e7:c7:63
+       b3:3e:03:73:0b:81:b8:42:8f:06:d5:bd:c9:19:23:ce
+       24:c8:3c:15:a7:4e:1b:b6:25:34:ad:8a:7d:7d:f9:11
+       5c:73:56:30:26:f8:4b:1a:2a:87:fe:9f:64:36:e8:43
+       c9:
+
+public exponent:
+       01:00:01:
+
+private exponent:
+       4c:42:f3:27:f1:f2:fd:df:5a:1a:94:b1:4a:8a:90:b9
+       98:9c:9a:88:c9:db:96:4c:30:2b:8d:a2:0a:e7:f7:05
+       a0:3c:8e:70:06:e8:5c:13:f2:31:56:99:6b:04:c3:67
+       03:65:d6:66:03:8c:d7:1b:3e:5f:72:49:77:70:1b:90
+       86:ef:96:2b:4a:b8:f1:76:6b:37:04:d6:7f:f7:03:6e
+       83:b5:03:b2:db:e2:2a:b4:e3:0c:28:41:1e:03:62:96
+       5f:48:ae:f2:77:a5:dc:c5:7d:59:18:cf:e0:cd:d2:5d
+       b9:08:70:29:4b:d5:06:b3:03:36:ac:41:02:80:01:b6
+       ec:48:63:07:a6:b0:e3:b2:94:b4:36:93:41:17:8e:b4
+       71:9b:f8:68:17:15:3c:f3:4c:36:20:eb:44:e4:d9:a2
+       3a:c3:8d:0f:f1:fd:df:b2:42:af:41:d3:6d:68:08:0b
+       61:68:f3:fe:c4:bd:19:80:50:3e:92:84:90:60:4f:ef
+       d7:23:df:4a:86:1d:51:20:54:31:d1:a6:67:b4:b5:46
+       35:ff:a3:2b:07:6c:ef:b1:97:47:e9:6e:a6:35:75:9a
+       d0:f7:43:a4:8c:47:93:ec:81:c3:f4:41:58:e1:cb:6b
+       e0:05:9e:1b:b0:f0:e2:5e:71:e6:d6:0f:56:7b:87:56
+       06:a5:d7:89:83:db:a5:a4:08:2a:aa:a5:02:3d:69:1a
+       04:89:0a:5d:48:4f:c9:3d:d0:ec:c7:e1:fe:ff:06:0e
+       9b:87:04:9a:fd:dc:3a:b3:97:11:1b:a4:42:a7:65:b1
+       ff:85:6a:9a:30:5f:41:e4:88:db:b1:9b:9a:ce:6f:af
+       3d:46:1b:f7:1f:df:7e:64:f8:0d:2c:6b:2e:3d:11:e7
+       a9:95:35:b5:ff:6a:e0:3b:f4:93:63:cd:63:e5:ef:d7
+       a1:1c:86:ad:f5:6f:2b:ab:5e:1f:c6:8a:73:dc:fc:78
+       a0:62:26:85:07:0b:53:b9:c0:36:87:3a:28:67:af:61
+       
+
+prime1:
+       00:e9:f3:84:12:16:36:d3:9a:00:e8:66:45:a6:4d:97
+       be:97:ea:c0:2c:cb:23:fa:eb:a2:f3:4a:18:71:f1:40
+       ab:0d:45:bc:c6:6a:6b:d2:23:b1:7d:50:a4:3b:62:71
+       d4:a8:75:9f:7e:b5:4d:01:23:b8:21:fa:fb:42:0d:83
+       a9:30:40:c5:6a:59:fd:90:0d:37:9c:ba:d3:5e:08:cd
+       9f:87:0a:a5:17:ec:10:02:e6:72:bc:db:6b:ff:45:52
+       ab:0c:db:c0:29:f3:c5:fc:e2:4f:33:16:bf:f1:e8:6d
+       95:37:08:31:ad:10:54:fb:33:3a:a2:25:d7:1a:3e:57
+       b4:d8:85:55:92:31:04:94:86:22:51:a0:e9:ef:60:34
+       1b:ae:c3:6c:2b:5e:25:ac:0b:06:60:f0:55:39:cf:32
+       0d:50:33:1a:a4:0d:f7:41:08:d8:ce:a1:c7:8e:93:78
+       b6:62:f4:06:96:87:3c:8f:48:06:83:ef:95:d0:7b:05
+       7d:
+
+prime2:
+       00:de:55:a1:cb:47:59:97:5d:96:d9:12:cd:53:a6:1e
+       c0:5f:df:72:80:b2:d7:d5:c5:5f:7f:76:40:27:ed:44
+       ad:9e:d8:a8:df:bb:ea:3f:5a:fa:1e:1f:b6:bd:e5:87
+       bb:3b:80:c3:a9:a5:ef:94:c5:4b:14:2d:42:f5:80:8d
+       51:04:98:72:08:6e:b6:95:a2:56:89:99:d5:cc:f6:2e
+       dc:c6:ee:fe:de:98:66:dc:d4:27:18:72:9b:e1:75:91
+       71:79:9e:03:83:8b:9c:6e:40:8f:e3:72:5e:e0:73:c2
+       f7:19:bb:82:af:8d:28:82:6f:55:5b:ef:95:31:15:45
+       da:15:3f:1e:18:a2:ee:38:07:7f:8e:30:96:a7:83:b8
+       ab:86:b4:fd:f4:4b:f1:ac:52:1f:0f:88:fc:26:3b:7d
+       35:09:61:ec:85:47:5f:c9:e7:7d:de:bc:4f:80:75:d9
+       5d:99:60:b2:28:aa:00:8c:0a:08:95:a5:c9:88:85:d9
+       3d:
+
+coefficient:
+       1f:33:b9:5d:14:f5:f2:3a:f3:91:e2:ca:8a:bb:e8:1e
+       fd:4d:d6:70:89:db:45:4c:89:2c:da:74:cf:8a:95:d2
+       46:c2:45:fb:7a:fd:14:3b:e0:7e:40:76:18:51:0f:84
+       be:be:d0:10:e4:d1:93:ac:65:e4:49:58:6b:4c:f2:dd
+       eb:c9:e5:4f:79:87:b1:6a:cd:0d:c4:6b:86:4f:68:ce
+       01:4a:63:68:68:e7:11:72:5b:f6:2c:e2:5c:49:2d:09
+       bd:b5:0f:4e:f9:67:86:55:ba:ea:4b:88:e8:da:f8:12
+       84:e2:99:df:02:5b:16:ee:b4:c1:4d:6f:bd:6a:35:28
+       31:05:de:64:a3:1a:e8:6e:ed:83:8d:88:0b:bc:b7:41
+       33:b9:ca:f6:1c:8d:a1:09:b7:c9:b5:e0:f0:7a:3c:fb
+       5a:7d:f4:2b:7d:20:66:ac:b2:0a:d1:9e:f9:f3:24:77
+       37:54:b6:29:ee:fe:03:84:33:73:3d:3a:97:af:0d:59
+       
+
+exp1:
+       59:0b:46:89:5b:cb:22:5e:cb:59:a9:13:79:68:af:08
+       eb:e9:7d:9b:8e:f5:f2:db:1c:fa:5c:89:51:54:f1:b8
+       29:25:11:e4:b3:3c:b6:8e:bf:4f:63:12:1f:48:28:eb
+       37:f3:0c:f1:bd:2f:c1:ef:46:76:28:80:d9:73:2b:59
+       89:f4:1d:2f:8d:70:e5:13:22:c7:94:94:3e:86:3b:3d
+       2c:b8:f0:7d:5a:6b:fd:ae:98:9d:29:26:c1:d2:30:d4
+       c9:e0:1a:13:dd:a4:cd:cb:95:39:6c:bf:41:e3:a5:51
+       d5:d0:58:97:f6:4f:62:0c:ed:94:29:b2:e5:5a:35:27
+       b0:01:8f:c0:44:c7:e9:7f:e4:30:0d:7e:fc:8d:31:48
+       18:0c:69:6f:58:36:1e:75:53:c8:31:b1:3e:7f:8e:1d
+       63:19:10:5a:c0:b6:0b:1a:c2:ea:62:c9:01:8b:3f:b6
+       ab:93:15:ae:d5:6a:47:5e:b2:9c:24:e4:70:a5:62:41
+       
+
+exp2:
+       75:b4:d0:1b:56:82:cf:e7:f4:5c:a7:df:9c:51:6e:26
+       5a:9b:69:7b:49:33:8b:31:1b:05:d8:0c:cf:16:86:2d
+       84:d3:1f:54:93:9f:c8:3a:d9:ff:e8:ba:4e:7e:9e:05
+       39:d3:49:c3:1e:de:5f:dc:b3:8a:d3:0b:87:fd:ae:d3
+       1d:a3:b7:7b:4f:61:ca:86:4f:5a:39:df:3e:cb:76:b3
+       db:7d:db:e0:ec:be:48:5a:e8:f7:c0:75:56:3f:6f:e8
+       ab:82:44:49:f8:37:b1:06:ed:26:74:fe:55:c5:f3:89
+       ee:4d:9f:3a:61:78:f8:d5:08:53:cb:db:28:49:22:d9
+       fa:35:98:31:62:d0:cb:48:ec:f6:d2:32:70:2d:04:2f
+       8a:f9:77:19:46:bb:83:87:56:7a:5b:03:63:1a:4b:87
+       30:98:6f:27:80:49:ee:12:68:48:eb:59:0b:a1:58:9a
+       7d:00:fc:51:1a:ef:7f:34:30:a7:49:46:10:c9:0b:e1
+       
+
+
+Public Key PIN:
+       pin-sha256:AAGX7OpdsnOKVlAlz3DfSavqKkLyFKNj4Lw7rsP1EFs=
+Public Key ID:
+       sha256:000197ecea5db2738a565025cf70df49abea2a42f214a363e0bc3baec3f5105b
+       sha1:730368ba5fd8d2bd91bb2762ccfc81871c90234f
+
+-----BEGIN RSA PRIVATE KEY-----
+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
+-----END RSA PRIVATE KEY-----
diff --git a/testdata/server.cfg b/testdata/server.cfg
new file mode 100644 (file)
index 0000000..4c771f2
--- /dev/null
@@ -0,0 +1,6 @@
+cn = Test server certificate
+expiration_days = -1
+tls_www_server
+uri = "https://localhost"
+ip_address = "127.0.0.1"
+ip_address = "::1"
diff --git a/testdata/server.crt b/testdata/server.crt
new file mode 100644 (file)
index 0000000..a7ad1a9
--- /dev/null
@@ -0,0 +1,26 @@
+-----BEGIN CERTIFICATE-----
+MIIEYTCCAsmgAwIBAgIUIdHSGULF1m+RwYrzZzuMxymHnCUwDQYJKoZIhvcNAQEL
+BQAwEjEQMA4GA1UEAxMHVGVzdCBDQTAgFw0xOTA4MDEyMDMzMTdaGA85OTk5MTIz
+MTIzNTk1OVowIjEgMB4GA1UEAxMXVGVzdCBzZXJ2ZXIgY2VydGlmaWNhdGUwggGi
+MA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQCtO6NfDlcwu90r4OR/l9ehb3xi
+1TdwVH0xS2uABllRkuWcYm4RPx/K5FmfaETH9sw8ijpXVXFGIOx162f6t1p/fHEy
+Amq9fBa/MyKZrEY4vfzOsc9KaX4s8vJH+69z2ZifUSfQcZKhpdg5oBVjt+HfZeLS
+Bf45nvWWg7HJHEhHbavkGQmfcOMS+WTJueRO6CiaWjcRXLEvTxbH8XdtCoQsto+l
+3mTKPXt46PYD24Hho2ibmsdIsYHai9atdrZEmCfYYMUY1PO9yp8unykQt+DoKdhG
+CsKEDBGWMn0kcDEjtoX/cCTSWV+5eVj840hOW0w35zTFxlr8ZkvM34PULY4cLPEm
+pjJAlEYzjC0CwCNRW6THCmylxMMduejz1dPlDIkW7CpHRNhIVv8qDRIHCWptKvpE
+R9QNcc2pxGZUiMst8OJtOqGa7lVjBtk7n7mFEWdfiVyew+5cf2u1wAn2l9RET/JQ
+W0/2IoYHtLbcdpkp25SkzUSCGTwqpBbMWJgAZ1cCAwEAAaOBnDCBmTAMBgNVHRMB
+Af8EAjAAMDQGA1UdEQQtMCuGEWh0dHBzOi8vbG9jYWxob3N0hwR/AAABhxAAAAAA
+AAAAAAAAAAAAAAABMBMGA1UdJQQMMAoGCCsGAQUFBwMBMB0GA1UdDgQWBBSQri6H
+p7BuDS/Lkq84xtR2YSnwMzAfBgNVHSMEGDAWgBTxc+gg5oElW6nJqfCDUpcd4uh5
+2DANBgkqhkiG9w0BAQsFAAOCAYEAE4qQ2IhXfuQhkBF4LluoQyqtCFZiN9YbrzrG
+khC7R0vYwjl+g6PL4JkPebFQeCVda2dHhwFyeRtJq1Rk6l3l05YYRDnWyFu4qpJ6
+KUgvtNdLxMGrYeG2nsxxfvvdOyGPMqFQFgvD51HBlCbGbfz/vkPMyyE69VxlT1nu
+Sawyvye2mILgkVEL62zbu7pepGF9FY2OTHNgTFGaPssnei+K29eRIeOdSG/Ld6qa
+oxBWT4mhSYweqLQFb1mjUxkO+V/NLh+N4WU1kcxdo95zp6M+3Cn2T6DHhOk+/7qL
+Wt9tC6s1VTV43DcDMjvcaehMSX9G1Ig3ROsGXo60YdkZBcJBvkuFNDhiD7JX/92P
+LjCTDjIa1vPrG3k1UADXbOjtCqRADdd+5AK8PAIm1dJWMnYamDQuBnkCAgr8uBZs
+1Y2wBBJdtKBTa+a5kR/E9SZW1pN7VQ+niiCPKxPhx6nQKRXk7BbznYetsKh1bD03
+MXT5UDJuuEsjMPLhp5/r0VwG9aZE
+-----END CERTIFICATE-----
diff --git a/testdata/server.key b/testdata/server.key
new file mode 100644 (file)
index 0000000..1dc2fac
--- /dev/null
@@ -0,0 +1,182 @@
+Public Key Info:
+       Public Key Algorithm: RSA
+       Key Security Level: High (3072 bits)
+
+modulus:
+       00:ad:3b:a3:5f:0e:57:30:bb:dd:2b:e0:e4:7f:97:d7
+       a1:6f:7c:62:d5:37:70:54:7d:31:4b:6b:80:06:59:51
+       92:e5:9c:62:6e:11:3f:1f:ca:e4:59:9f:68:44:c7:f6
+       cc:3c:8a:3a:57:55:71:46:20:ec:75:eb:67:fa:b7:5a
+       7f:7c:71:32:02:6a:bd:7c:16:bf:33:22:99:ac:46:38
+       bd:fc:ce:b1:cf:4a:69:7e:2c:f2:f2:47:fb:af:73:d9
+       98:9f:51:27:d0:71:92:a1:a5:d8:39:a0:15:63:b7:e1
+       df:65:e2:d2:05:fe:39:9e:f5:96:83:b1:c9:1c:48:47
+       6d:ab:e4:19:09:9f:70:e3:12:f9:64:c9:b9:e4:4e:e8
+       28:9a:5a:37:11:5c:b1:2f:4f:16:c7:f1:77:6d:0a:84
+       2c:b6:8f:a5:de:64:ca:3d:7b:78:e8:f6:03:db:81:e1
+       a3:68:9b:9a:c7:48:b1:81:da:8b:d6:ad:76:b6:44:98
+       27:d8:60:c5:18:d4:f3:bd:ca:9f:2e:9f:29:10:b7:e0
+       e8:29:d8:46:0a:c2:84:0c:11:96:32:7d:24:70:31:23
+       b6:85:ff:70:24:d2:59:5f:b9:79:58:fc:e3:48:4e:5b
+       4c:37:e7:34:c5:c6:5a:fc:66:4b:cc:df:83:d4:2d:8e
+       1c:2c:f1:26:a6:32:40:94:46:33:8c:2d:02:c0:23:51
+       5b:a4:c7:0a:6c:a5:c4:c3:1d:b9:e8:f3:d5:d3:e5:0c
+       89:16:ec:2a:47:44:d8:48:56:ff:2a:0d:12:07:09:6a
+       6d:2a:fa:44:47:d4:0d:71:cd:a9:c4:66:54:88:cb:2d
+       f0:e2:6d:3a:a1:9a:ee:55:63:06:d9:3b:9f:b9:85:11
+       67:5f:89:5c:9e:c3:ee:5c:7f:6b:b5:c0:09:f6:97:d4
+       44:4f:f2:50:5b:4f:f6:22:86:07:b4:b6:dc:76:99:29
+       db:94:a4:cd:44:82:19:3c:2a:a4:16:cc:58:98:00:67
+       57:
+
+public exponent:
+       01:00:01:
+
+private exponent:
+       3e:6f:e1:59:50:6c:e2:96:c3:87:9e:1e:1d:52:d8:18
+       4a:7b:75:8f:cd:d4:81:cf:41:a6:22:4f:d9:79:f5:e9
+       d1:32:45:53:d0:89:84:e6:f6:d8:ca:98:a5:39:c1:5d
+       29:70:d4:c8:47:76:75:45:46:94:d5:cc:fb:53:7c:9d
+       b8:77:80:03:d8:ff:04:ab:9a:2c:4f:0b:3e:49:6d:08
+       25:07:46:95:25:07:d2:bf:56:ad:36:7e:a3:65:49:07
+       36:5c:e4:d1:bf:2d:8f:6f:9b:f8:61:17:74:82:81:39
+       a8:9a:51:02:71:f7:c8:b0:51:98:93:ca:9d:93:fb:92
+       ae:c2:9e:b7:96:2c:f4:db:10:e2:5f:c6:cd:60:17:53
+       13:16:f3:04:21:f9:86:c8:a5:b8:58:f2:a7:6d:83:e8
+       2d:c0:a6:92:fa:96:de:04:13:b7:3b:7c:76:70:60:a8
+       29:fa:f3:95:62:41:00:41:89:e7:4d:4c:1d:33:a9:f7
+       12:b2:f8:c6:2c:79:ab:6f:dd:eb:af:f8:e9:7c:30:f7
+       38:9d:d2:2f:f2:be:5c:e3:0a:57:bb:16:0e:1f:ba:66
+       35:ab:df:55:2a:bb:ac:ec:43:f4:e9:66:86:46:19:a1
+       8a:e6:9c:8a:d8:a5:5e:a1:00:29:c6:a9:99:20:6f:46
+       09:e3:56:5f:b2:2d:ed:ca:f9:37:7e:8c:2c:6c:9b:7b
+       2f:93:b4:fe:fc:b7:3c:8e:e7:b2:d3:88:9d:e7:f3:f4
+       2b:aa:80:9e:8b:d8:65:7d:c3:cf:bc:4e:d4:ce:64:fc
+       e5:19:2c:92:08:3d:d3:f0:26:f2:4a:17:5b:89:22:ba
+       73:66:58:3d:b2:45:4b:e3:5a:32:ff:b7:8d:d6:83:96
+       73:8d:81:92:ca:3e:2e:96:44:7d:ea:ab:e0:58:2c:63
+       8e:b9:f7:6b:2c:3e:1f:c8:a1:e1:e0:ec:17:46:bb:61
+       82:5e:d4:f9:a9:5e:0a:b5:49:03:32:f7:9c:7e:e1:91
+       
+
+prime1:
+       00:ce:4e:ea:4b:1c:c7:cc:4a:0f:51:f8:1d:79:dc:9e
+       48:15:02:86:8a:88:b6:c6:75:bb:16:2d:71:de:e6:27
+       19:94:5d:2d:4d:8e:fa:85:bc:ff:d2:7e:8f:01:79:c6
+       ad:f0:f6:df:5e:93:28:85:ae:0e:4d:c1:b2:07:42:5b
+       57:ed:65:b8:c3:bc:50:af:01:bb:6f:0c:cf:48:0a:73
+       90:c9:41:f2:8b:4b:cd:5d:1a:88:6f:29:94:9d:dc:f8
+       ed:a4:66:11:d6:b5:d8:cc:84:9d:08:fc:60:61:01:95
+       81:56:b6:21:7d:4a:77:b9:53:32:38:34:e4:c6:5d:4f
+       ee:54:22:96:df:97:83:a4:cd:6d:3e:13:94:47:31:68
+       a5:f3:df:d5:a2:a0:c6:2b:d7:e5:27:4e:f6:8d:c6:cd
+       ab:3f:86:98:2c:25:2e:98:a0:f8:ad:44:28:47:95:e2
+       f3:42:ae:db:6b:a1:6b:6e:02:1e:6f:30:a1:23:7d:21
+       19:
+
+prime2:
+       00:d6:f5:47:f5:e1:b4:2f:bc:e9:f3:5e:a7:2c:06:eb
+       c1:7a:2b:05:a8:13:c1:fb:a0:22:64:b4:09:4c:e0:4b
+       2d:53:10:9c:96:a0:2f:f0:37:19:06:07:6c:3e:1c:2a
+       53:2a:50:80:e9:77:ed:9e:75:3b:76:22:42:4c:9c:08
+       da:05:06:f7:75:9f:12:16:d4:70:48:a7:2a:fe:88:20
+       de:b0:a8:52:20:41:d9:8f:1b:a1:37:6d:77:a7:cc:fd
+       87:7c:fc:60:53:8d:33:14:30:5a:ce:e7:06:f9:32:91
+       44:b8:50:8f:43:bd:1e:c3:48:ad:e7:c2:ea:96:a6:5f
+       6a:ff:9a:66:27:c0:d1:87:30:0f:41:f0:c1:49:ca:e9
+       f4:ca:4f:2e:91:1a:e6:1d:1e:aa:33:32:45:de:c0:c8
+       64:4b:27:f2:f4:c9:97:f3:14:10:e0:77:70:b7:52:68
+       56:ec:38:f3:80:00:fd:5a:a2:6d:c8:db:e0:e7:9d:a9
+       ef:
+
+coefficient:
+       41:01:01:08:2b:f6:b0:8c:1c:80:ca:d3:a2:ab:1d:b2
+       f2:0e:59:f1:88:ae:2b:69:66:87:76:4f:1f:f9:2c:90
+       4e:36:db:a4:ac:56:b4:76:dc:cb:dc:5a:3e:48:b7:0e
+       bb:33:ee:8c:ce:b4:a3:4d:63:68:14:8c:6f:a5:ae:b2
+       d7:1b:44:74:8f:6b:32:ea:6d:88:70:e1:a8:b9:a3:67
+       d5:d2:48:d7:95:09:2b:41:07:dc:da:fe:11:7a:08:69
+       8d:bc:ab:5c:2a:64:05:d9:ca:ec:2c:28:60:5e:d4:7d
+       3b:ff:e5:ae:5e:3b:49:f0:dc:c3:fc:7a:85:a3:19:39
+       86:c9:5f:57:19:ae:be:3f:6f:05:d4:c1:79:84:fd:7a
+       d4:ad:70:7e:e4:0c:ca:93:7c:ce:e2:8f:bc:ac:45:66
+       e4:cc:54:1e:07:39:34:f8:cd:83:21:2e:20:e7:db:39
+       3c:90:e3:2f:d0:3b:5a:17:a2:3c:ed:08:15:39:9e:89
+       
+
+exp1:
+       71:52:d9:d1:be:92:65:3d:fd:22:5a:76:de:7c:78:19
+       42:29:2b:fc:26:d2:b7:3a:ee:34:65:6c:1a:33:34:21
+       11:e5:08:c0:84:9c:4a:20:22:29:de:c8:f0:d7:92:71
+       f3:5d:b8:1e:bc:18:d3:2d:63:c0:04:78:a5:12:27:18
+       aa:57:68:e1:63:ac:b2:24:f2:6f:32:8b:1d:98:58:18
+       9c:e4:73:b5:5e:43:05:34:50:e3:36:e4:e2:be:01:a2
+       8f:de:5d:48:22:85:5e:fa:2d:44:45:55:2f:93:ee:2a
+       a8:95:cc:d9:84:b1:35:04:65:1e:88:b7:6d:da:cd:d0
+       2d:38:fe:c4:fc:f6:1b:ed:97:67:34:dc:0b:2b:31:bf
+       8e:b1:52:29:4d:c4:ed:4a:5f:1e:73:7a:6d:30:59:c3
+       0a:57:05:79:a2:46:f1:21:e2:d7:52:0c:0a:1e:64:16
+       99:77:71:21:b2:fe:4e:e4:2d:11:88:95:ca:e7:ad:e9
+       
+
+exp2:
+       00:a2:99:ab:b3:5c:e5:d5:ee:8a:f1:a3:39:c5:5d:fe
+       db:bd:b3:e9:75:78:6c:96:10:4d:b3:eb:53:d5:a9:1c
+       74:ce:8e:94:44:84:2b:7f:03:ce:93:f6:ed:74:16:0e
+       16:16:be:0a:a5:90:28:58:62:c9:75:d4:f8:5d:c6:f2
+       13:29:16:59:fd:c9:33:ff:bc:f6:aa:9e:79:31:4c:7b
+       c0:b7:d4:bb:3a:d7:54:e0:a1:bf:d3:93:a4:9d:73:bc
+       9b:ce:79:81:cb:f1:d5:1f:82:6c:4e:72:07:9e:5d:17
+       f1:e9:92:56:ac:a0:d4:32:58:39:e4:44:56:fb:5a:22
+       77:67:9d:bd:84:78:a0:86:28:5e:82:3c:c1:99:36:3a
+       bf:06:81:da:f1:bc:6d:30:bd:cf:75:26:a4:1f:99:a8
+       7b:e5:35:f4:dc:21:da:24:ef:9a:cc:90:cc:dc:7f:23
+       9a:0c:da:0f:a7:56:18:4f:84:ea:92:b3:70:6f:03:9e
+       55:
+
+
+Public Key PIN:
+       pin-sha256:fFKn4o/MFily5Ps0NYnZ303CvcgCroJxNxM3QgSzVy0=
+Public Key ID:
+       sha256:7c52a7e28fcc162972e4fb343589d9df4dc2bdc802ae82713713374204b3572d
+       sha1:90ae2e87a7b06e0d2fcb92af38c6d4766129f033
+
+-----BEGIN RSA PRIVATE KEY-----
+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
+-----END RSA PRIVATE KEY-----