diff --git a/lib/http/auth.go b/lib/http/auth.go index 0e7fd6d29..d08dec55d 100644 --- a/lib/http/auth.go +++ b/lib/http/auth.go @@ -19,6 +19,10 @@ By default this will serve files without needing a login. You can either use an htpasswd file which can take lots of users, or set a single username and password with the ` + "`--{{ .Prefix }}user` and `--{{ .Prefix }}pass`" + ` flags. +If no static users are configured by either of the above methods, and client +certificates are required by the ` + "`--client-ca`" + ` flag passed to the server, the +client certificate common name will be considered as the username. + Use ` + "`--{{ .Prefix }}htpasswd /path/to/htpasswd`" + ` to provide an htpasswd file. This is in standard apache format and supports MD5, SHA1 and BCrypt for basic authentication. Bcrypt is recommended. diff --git a/lib/http/middleware.go b/lib/http/middleware.go index cef2485d6..2aa319c81 100644 --- a/lib/http/middleware.go +++ b/lib/http/middleware.go @@ -74,6 +74,24 @@ func basicAuth(authenticator *LoggedBasicAuth) func(next http.Handler) http.Hand } } +// MiddlewareAuthCertificateUser instantiates middleware that extracts the authenticated user via client certificate common name +func MiddlewareAuthCertificateUser() Middleware { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + for _, cert := range r.TLS.PeerCertificates { + if cert.Subject.CommonName != "" { + r = r.WithContext(context.WithValue(r.Context(), ctxKeyUser, cert.Subject.CommonName)) + next.ServeHTTP(w, r) + return + } + } + code := http.StatusUnauthorized + w.Header().Set("Content-Type", "text/plain") + http.Error(w, http.StatusText(code), code) + }) + } +} + // MiddlewareAuthHtpasswd instantiates middleware that authenticates against the passed htpasswd file func MiddlewareAuthHtpasswd(path, realm string) Middleware { fs.Infof(nil, "Using %q as htpasswd storage", path) @@ -97,7 +115,7 @@ func MiddlewareAuthBasic(user, pass, realm, salt string) Middleware { } // MiddlewareAuthCustom instantiates middleware that authenticates using a custom function -func MiddlewareAuthCustom(fn CustomAuthFn, realm string) Middleware { +func MiddlewareAuthCustom(fn CustomAuthFn, realm string, userFromContext bool) Middleware { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // skip auth for unix socket @@ -107,6 +125,10 @@ func MiddlewareAuthCustom(fn CustomAuthFn, realm string) Middleware { } user, pass, ok := parseAuthorization(r) + if !ok && userFromContext { + user, ok = CtxGetUser(r.Context()) + } + if !ok { code := http.StatusUnauthorized w.Header().Set("Content-Type", "text/plain") diff --git a/lib/http/middleware_test.go b/lib/http/middleware_test.go index 8932ca4fd..24cc97afb 100644 --- a/lib/http/middleware_test.go +++ b/lib/http/middleware_test.go @@ -2,6 +2,7 @@ package http import ( "context" + "crypto/tls" "errors" "fmt" "net/http" @@ -159,6 +160,167 @@ func TestMiddlewareAuth(t *testing.T) { } } +func TestMiddlewareAuthCertificateUser(t *testing.T) { + serverCertBytes := testReadTestdataFile(t, "local.crt") + serverKeyBytes := testReadTestdataFile(t, "local.key") + clientCertBytes := testReadTestdataFile(t, "client.crt") + clientKeyBytes := testReadTestdataFile(t, "client.key") + clientCert, err := tls.X509KeyPair(clientCertBytes, clientKeyBytes) + require.NoError(t, err) + emptyCertBytes := testReadTestdataFile(t, "emptyclient.crt") + emptyKeyBytes := testReadTestdataFile(t, "emptyclient.key") + emptyCert, err := tls.X509KeyPair(emptyCertBytes, emptyKeyBytes) + require.NoError(t, err) + invalidCert, err := tls.X509KeyPair(serverCertBytes, serverKeyBytes) + require.NoError(t, err) + + servers := []struct { + name string + wantErr bool + status int + result string + http Config + auth AuthConfig + clientCerts []tls.Certificate + }{ + { + name: "Missing", + wantErr: true, + http: Config{ + ListenAddr: []string{"127.0.0.1:0"}, + TLSCertBody: serverCertBytes, + TLSKeyBody: serverKeyBytes, + MinTLSVersion: "tls1.0", + ClientCA: "./testdata/client-ca.crt", + }, + }, + { + name: "Invalid", + wantErr: true, + clientCerts: []tls.Certificate{invalidCert}, + http: Config{ + ListenAddr: []string{"127.0.0.1:0"}, + TLSCertBody: serverCertBytes, + TLSKeyBody: serverKeyBytes, + MinTLSVersion: "tls1.0", + ClientCA: "./testdata/client-ca.crt", + }, + }, + { + name: "EmptyCommonName", + status: http.StatusUnauthorized, + result: fmt.Sprintf("%s\n", http.StatusText(http.StatusUnauthorized)), + clientCerts: []tls.Certificate{emptyCert}, + http: Config{ + ListenAddr: []string{"127.0.0.1:0"}, + TLSCertBody: serverCertBytes, + TLSKeyBody: serverKeyBytes, + MinTLSVersion: "tls1.0", + ClientCA: "./testdata/client-ca.crt", + }, + }, + { + name: "Valid", + status: http.StatusOK, + result: "rclone-dev-client", + clientCerts: []tls.Certificate{clientCert}, + http: Config{ + ListenAddr: []string{"127.0.0.1:0"}, + TLSCertBody: serverCertBytes, + TLSKeyBody: serverKeyBytes, + MinTLSVersion: "tls1.0", + ClientCA: "./testdata/client-ca.crt", + }, + }, + { + name: "CustomAuth/Invalid", + status: http.StatusUnauthorized, + result: fmt.Sprintf("%d %s\n", http.StatusUnauthorized, http.StatusText(http.StatusUnauthorized)), + clientCerts: []tls.Certificate{clientCert}, + http: Config{ + ListenAddr: []string{"127.0.0.1:0"}, + TLSCertBody: serverCertBytes, + TLSKeyBody: serverKeyBytes, + MinTLSVersion: "tls1.0", + ClientCA: "./testdata/client-ca.crt", + }, + auth: AuthConfig{ + Realm: "test", + CustomAuthFn: func(user, pass string) (value interface{}, err error) { + if user == "custom" && pass == "custom" { + return true, nil + } + return nil, errors.New("invalid credentials") + }, + }, + }, + { + name: "CustomAuth/Valid", + status: http.StatusOK, + result: "rclone-dev-client", + clientCerts: []tls.Certificate{clientCert}, + http: Config{ + ListenAddr: []string{"127.0.0.1:0"}, + TLSCertBody: serverCertBytes, + TLSKeyBody: serverKeyBytes, + MinTLSVersion: "tls1.0", + ClientCA: "./testdata/client-ca.crt", + }, + auth: AuthConfig{ + Realm: "test", + CustomAuthFn: func(user, pass string) (value interface{}, err error) { + fmt.Println("CUSTOMAUTH", user, pass) + if user == "rclone-dev-client" && pass == "" { + return true, nil + } + return nil, errors.New("invalid credentials") + }, + }, + }, + } + + for _, ss := range servers { + t.Run(ss.name, func(t *testing.T) { + s, err := NewServer(context.Background(), WithConfig(ss.http), WithAuth(ss.auth)) + require.NoError(t, err) + defer func() { + require.NoError(t, s.Shutdown()) + }() + + s.Router().Mount("/", testAuthUserHandler()) + s.Serve() + + url := testGetServerURL(t, s) + client := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + Certificates: ss.clientCerts, + InsecureSkipVerify: true, + }, + }, + } + req, err := http.NewRequest("GET", url, nil) + require.NoError(t, err) + + resp, err := client.Do(req) + if ss.wantErr { + require.Error(t, err) + return + } + require.NoError(t, err) + + defer func() { + _ = resp.Body.Close() + }() + + require.Equal(t, ss.status, resp.StatusCode, fmt.Sprintf("should return status %d", ss.status)) + + testExpectRespBody(t, resp, []byte(ss.result)) + }) + } + +} + var _testCORSHeaderKeys = []string{ "Access-Control-Allow-Origin", "Access-Control-Request-Method", diff --git a/lib/http/server.go b/lib/http/server.go index 89e6666c7..3c26d5cd5 100644 --- a/lib/http/server.go +++ b/lib/http/server.go @@ -226,8 +226,6 @@ func NewServer(ctx context.Context, options ...Option) (*Server, error) { s.mux.Use(MiddlewareStripPrefix(s.cfg.BaseURL)) } - s.initAuth() - err := s.initTemplate() if err != nil { return nil, err @@ -238,6 +236,8 @@ func NewServer(ctx context.Context, options ...Option) (*Server, error) { return nil, err } + s.initAuth() + for _, addr := range s.cfg.ListenAddr { var url string var network = "tcp" @@ -293,9 +293,17 @@ func NewServer(ctx context.Context, options ...Option) (*Server, error) { } func (s *Server) initAuth() { + s.usingAuth = false + + authCertificateUserEnabled := s.tlsConfig != nil && s.tlsConfig.ClientAuth != tls.NoClientCert && s.auth.HtPasswd == "" && s.auth.BasicUser == "" + if authCertificateUserEnabled { + s.usingAuth = true + s.mux.Use(MiddlewareAuthCertificateUser()) + } + if s.auth.CustomAuthFn != nil { s.usingAuth = true - s.mux.Use(MiddlewareAuthCustom(s.auth.CustomAuthFn, s.auth.Realm)) + s.mux.Use(MiddlewareAuthCustom(s.auth.CustomAuthFn, s.auth.Realm, authCertificateUserEnabled)) return } @@ -310,7 +318,6 @@ func (s *Server) initAuth() { s.mux.Use(MiddlewareAuthBasic(s.auth.BasicUser, s.auth.BasicPass, s.auth.Realm, s.auth.Salt)) return } - s.usingAuth = false } func (s *Server) initTemplate() error { diff --git a/lib/http/server_test.go b/lib/http/server_test.go index 4cb303685..d3bf997d4 100644 --- a/lib/http/server_test.go +++ b/lib/http/server_test.go @@ -20,6 +20,16 @@ func testEchoHandler(data []byte) http.Handler { }) } +func testAuthUserHandler() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + userID, ok := CtxGetUser(r.Context()) + if !ok { + http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) + } + _, _ = w.Write([]byte(userID)) + }) +} + func testExpectRespBody(t *testing.T, resp *http.Response, expected []byte) { body, err := io.ReadAll(resp.Body) require.NoError(t, err) @@ -234,19 +244,22 @@ func TestNewServerBaseURL(t *testing.T) { } func TestNewServerTLS(t *testing.T) { - certBytes := testReadTestdataFile(t, "local.crt") - keyBytes := testReadTestdataFile(t, "local.key") + serverCertBytes := testReadTestdataFile(t, "local.crt") + serverKeyBytes := testReadTestdataFile(t, "local.key") + clientCertBytes := testReadTestdataFile(t, "client.crt") + clientKeyBytes := testReadTestdataFile(t, "client.key") + clientCert, err := tls.X509KeyPair(clientCertBytes, clientKeyBytes) + require.NoError(t, err) // TODO: generate a proper cert with SAN - // TODO: generate CA, test mTLS - // clientCert, err := tls.X509KeyPair(certBytes, keyBytes) - // require.NoError(t, err, "should be testing with a valid self signed certificate") servers := []struct { - name string - wantErr bool - err error - http Config + name string + clientCerts []tls.Certificate + wantErr bool + wantClientErr bool + err error + http Config }{ { name: "FromFile/Valid", @@ -303,8 +316,8 @@ func TestNewServerTLS(t *testing.T) { name: "FromBody/Valid", http: Config{ ListenAddr: []string{"127.0.0.1:0"}, - TLSCertBody: certBytes, - TLSKeyBody: keyBytes, + TLSCertBody: serverCertBytes, + TLSKeyBody: serverKeyBytes, MinTLSVersion: "tls1.0", }, }, @@ -315,7 +328,7 @@ func TestNewServerTLS(t *testing.T) { http: Config{ ListenAddr: []string{"127.0.0.1:0"}, TLSCertBody: nil, - TLSKeyBody: keyBytes, + TLSKeyBody: serverKeyBytes, MinTLSVersion: "tls1.0", }, }, @@ -325,7 +338,7 @@ func TestNewServerTLS(t *testing.T) { http: Config{ ListenAddr: []string{"127.0.0.1:0"}, TLSCertBody: []byte("JUNK DATA"), - TLSKeyBody: keyBytes, + TLSKeyBody: serverKeyBytes, MinTLSVersion: "tls1.0", }, }, @@ -335,7 +348,7 @@ func TestNewServerTLS(t *testing.T) { err: ErrTLSBodyMismatch, http: Config{ ListenAddr: []string{"127.0.0.1:0"}, - TLSCertBody: certBytes, + TLSCertBody: serverCertBytes, TLSKeyBody: nil, MinTLSVersion: "tls1.0", }, @@ -345,7 +358,7 @@ func TestNewServerTLS(t *testing.T) { wantErr: true, http: Config{ ListenAddr: []string{"127.0.0.1:0"}, - TLSCertBody: certBytes, + TLSCertBody: serverCertBytes, TLSKeyBody: []byte("JUNK DATA"), MinTLSVersion: "tls1.0", }, @@ -354,8 +367,8 @@ func TestNewServerTLS(t *testing.T) { name: "MinTLSVersion/Valid/1.1", http: Config{ ListenAddr: []string{"127.0.0.1:0"}, - TLSCertBody: certBytes, - TLSKeyBody: keyBytes, + TLSCertBody: serverCertBytes, + TLSKeyBody: serverKeyBytes, MinTLSVersion: "tls1.1", }, }, @@ -363,8 +376,8 @@ func TestNewServerTLS(t *testing.T) { name: "MinTLSVersion/Valid/1.2", http: Config{ ListenAddr: []string{"127.0.0.1:0"}, - TLSCertBody: certBytes, - TLSKeyBody: keyBytes, + TLSCertBody: serverCertBytes, + TLSKeyBody: serverKeyBytes, MinTLSVersion: "tls1.2", }, }, @@ -372,8 +385,8 @@ func TestNewServerTLS(t *testing.T) { name: "MinTLSVersion/Valid/1.3", http: Config{ ListenAddr: []string{"127.0.0.1:0"}, - TLSCertBody: certBytes, - TLSKeyBody: keyBytes, + TLSCertBody: serverCertBytes, + TLSKeyBody: serverKeyBytes, MinTLSVersion: "tls1.3", }, }, @@ -383,11 +396,46 @@ func TestNewServerTLS(t *testing.T) { err: ErrInvalidMinTLSVersion, http: Config{ ListenAddr: []string{"127.0.0.1:0"}, - TLSCertBody: certBytes, - TLSKeyBody: keyBytes, + TLSCertBody: serverCertBytes, + TLSKeyBody: serverKeyBytes, MinTLSVersion: "tls0.9", }, }, + { + name: "MutualTLS/InvalidCA", + clientCerts: []tls.Certificate{clientCert}, + wantErr: true, + http: Config{ + ListenAddr: []string{"127.0.0.1:0"}, + TLSCertBody: serverCertBytes, + TLSKeyBody: serverKeyBytes, + MinTLSVersion: "tls1.0", + ClientCA: "./testdata/client-ca.crt.invalid", + }, + }, + { + name: "MutualTLS/InvalidClient", + clientCerts: []tls.Certificate{}, + wantClientErr: true, + http: Config{ + ListenAddr: []string{"127.0.0.1:0"}, + TLSCertBody: serverCertBytes, + TLSKeyBody: serverKeyBytes, + MinTLSVersion: "tls1.0", + ClientCA: "./testdata/client-ca.crt", + }, + }, + { + name: "MutualTLS/Valid", + clientCerts: []tls.Certificate{clientCert}, + http: Config{ + ListenAddr: []string{"127.0.0.1:0"}, + TLSCertBody: serverCertBytes, + TLSKeyBody: serverKeyBytes, + MinTLSVersion: "tls1.0", + ClientCA: "./testdata/client-ca.crt", + }, + }, } for _, ss := range servers { @@ -422,7 +470,7 @@ func TestNewServerTLS(t *testing.T) { return net.Dial("tcp", dest) }, TLSClientConfig: &tls.Config{ - // Certificates: []tls.Certificate{clientCert}, + Certificates: ss.clientCerts, InsecureSkipVerify: true, }, }, @@ -431,6 +479,12 @@ func TestNewServerTLS(t *testing.T) { require.NoError(t, err) resp, err := client.Do(req) + + if ss.wantClientErr { + require.Error(t, err, "new server client should return error") + return + } + require.NoError(t, err) defer func() { _ = resp.Body.Close() diff --git a/lib/http/testdata/client-ca.crt b/lib/http/testdata/client-ca.crt new file mode 100644 index 000000000..64642c06c --- /dev/null +++ b/lib/http/testdata/client-ca.crt @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIURSp4/DIspJDvwXq6udbAqg2Yk9IwDQYJKoZIhvcNAQEL +BQAwZzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xDzANBgNVBAoM +BnJjbG9uZTETMBEGA1UECwwKcmNsb25lLWRldjEdMBsGA1UEAwwUcmNsb25lLWRl +di1jbGllbnQtY2EwHhcNMjMwNTI1MjM1NzE3WhcNMzMwNTIyMjM1NzE3WjBnMQsw +CQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjEPMA0GA1UECgwGcmNsb25l +MRMwEQYDVQQLDApyY2xvbmUtZGV2MR0wGwYDVQQDDBRyY2xvbmUtZGV2LWNsaWVu +dC1jYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxufFA5IrPWTnk+ +EEUttdGNystKNkJyuRV2Mgso9VX5HrwIGyNCOVeRX2Uds2Piaz8uSET8/fWMg3h4 +ZNTImoomMUcaqL7lmBsPxXZUguo9M5ZlrlLW9VrwuSIZs9+W26Gy44WliivZl3f5 +RNYzk+0UyZ0hp7h81LufUiVQhT8MX3XoVdDFAgoDipEI07ROipB2KXPa1lr1Mdhu +kAEKu0gLb7RoGrIEADyCKMr4waE5SovXWfC0jTVbMdB9DLCYmR5/zmR9ykUzWaWJ +ug7iIv6a/q+r+sB/Xh+PHY0CTieYGkd4rweFQk5ImwspOIx0RdtWj4pyxDoKiIuK +vhLyzl0CAwEAAaNTMFEwHQYDVR0OBBYEFDcCPxWKtwaU8DCpAdGuZ8X07x67MB8G +A1UdIwQYMBaAFDcCPxWKtwaU8DCpAdGuZ8X07x67MA8GA1UdEwEB/wQFMAMBAf8w +DQYJKoZIhvcNAQELBQADggEBACgU9YDjoqrOAhfhYz8MNkb8yWofCGse8fDrhXft +ZdJjlVBd343Ja97o6P5IaS9H8mM2ZRVtw0p/JoBvnsF74GMbSAR/M1VovxPa/Ze9 +SjGKdJAwxjhx3+YCU61psR0DZO1By1+mjKfvbOMOHD+HVvvG7x1/iv3buPId935+ +53dt36d1OYx7Z6BbYYjL8/CXtkaOhgdKbCtng2frU3OvOtSs1OBLBimtc9ja+evk +Nn/NiG14F962ZWRPXEKQAH1tpqzWJ6okjY3F58hPb5c//p/kgOiWefCZ+XF/75HL +vZAQjtmpn0pv4ObCHWp/6ZFWdmnxGDuOigcC09R74P+HNuU= +-----END CERTIFICATE----- diff --git a/lib/http/testdata/client-ca.key b/lib/http/testdata/client-ca.key new file mode 100644 index 000000000..f06e77696 --- /dev/null +++ b/lib/http/testdata/client-ca.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDcbnxQOSKz1k55 +PhBFLbXRjcrLSjZCcrkVdjILKPVV+R68CBsjQjlXkV9lHbNj4ms/LkhE/P31jIN4 +eGTUyJqKJjFHGqi+5ZgbD8V2VILqPTOWZa5S1vVa8LkiGbPfltuhsuOFpYor2Zd3 ++UTWM5PtFMmdIae4fNS7n1IlUIU/DF916FXQxQIKA4qRCNO0ToqQdilz2tZa9THY +bpABCrtIC2+0aBqyBAA8gijK+MGhOUqL11nwtI01WzHQfQywmJkef85kfcpFM1ml +iboO4iL+mv6vq/rAf14fjx2NAk4nmBpHeK8HhUJOSJsLKTiMdEXbVo+KcsQ6CoiL +ir4S8s5dAgMBAAECggEATNrw2P+yy8USw08SWSxg0ll/tXWAiZZ6VbNKK33yXDFp +t+GTpK14VMHI4vaCD3doMTUv2W3kFfMR+7TuYwo2Z6h9Ue9HmpduezD6hhFdO9Ju +5Cc7qoJsNXLs+ajAgFqW5T/7+CMJk9Rf7WKpz41YLDctPG35jmdnvKsF9yCl9J70 +Fd8ZGq7l6WDbTpAlb+cbEEb/dXuBgesgp0qlnzBd8E4Ib5IhAuex1c+lY7gHZBn4 +9f8fEowusjidFtvKZxK5cXhumZ6qQdXwk2rBPOcND73k8ftYjX6uFMvhCpoDkrGA +uIAPHOq3/DpgH1fOXe/KxZCvFNyX8OgW8QwI+ASU+QKBgQDxTb0+52m+mGvcx3ZF +6D9PQAOoMgxMPP0e6rKHDxBPdroJE1PevbfEvU6mdrqzvNhGbOsxlQpDqDWqgNKK +asBiPw0Tm4+Tcnytol86OCd0Nhgkat/QwGx5PpwOQwNkeCJv3igazaGrsUxfGkEK +h3NjL8G1vgCTLJdSZPjgM/1/swKBgQDp21JKczoMs0f969x/O2TQzFt5NSLS1ZCd +SYV8bskLwFVywX7ij6j3eYm9fZy7283hO8Jmw+kxNnvqT624qte87oeLgWplJ7k4 +wglOqMTsU47sGyl7tY6Eqz2FH0D3euzx2Em0Uw3Qv7CP0Eh9AdHj17T5pOEB9Wgw +YRu8nkvxrwKBgD4uQi4Lg/xRWroxzBCHoIjTfh3Bh9m9fZyR7h9Pimxvs9DS4jHr +wYc5ISNURRg7+Z9sQc8tENAOcIXXXGm+yISIqt36oCzmu6oixVdDUSdpKR95SuOI +Mmur7preOemR643YOY1un9KWhY+cPFZyQRG2JLyokY1bWEMrMdbUjuZxAoGAA+Zx +f+ZeEHoo+DYnzkNqUgUmfWYCd6uyJr1kKYgbeEOz6R8LA7JLqhzvzCY9J/DphRkf +C+G2kOiMtoKvrgXDZVZBEnWNFbTM5QJvb01nQ129Y3isf3CuuM22T/MOfVIig4IM +8KH1+AZKZoudud/+5SLi1MsIKaUzIKNt9/5X2+cCgYAitKJmHLgLnXlRbswioHy1 +l9Anqrh+sDjLzfcuSKaNucivqNProC/K45o33p61BTVrKr8aFWHfmPyLrXAbKWOI +c+5YcUBh6dqsk96nbNsKH+pqvWYTdEsbfaqOjVv5R7Y8/rGt3TEeBfIYvht6ILkQ ++waZBbneFx9gdQ2Q/x0yhg== +-----END PRIVATE KEY----- diff --git a/lib/http/testdata/client-ca.srl b/lib/http/testdata/client-ca.srl new file mode 100644 index 000000000..c46e043cb --- /dev/null +++ b/lib/http/testdata/client-ca.srl @@ -0,0 +1 @@ +607C74360F5500750AA949B367AC937975C32987 diff --git a/lib/http/testdata/client.crt b/lib/http/testdata/client.crt new file mode 100644 index 000000000..6a1b3f4e6 --- /dev/null +++ b/lib/http/testdata/client.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDUjCCAjoCFGB8dDYPVQB1CqlJs2esk3l1wymGMA0GCSqGSIb3DQEBCwUAMGcx +CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMQ8wDQYDVQQKDAZyY2xv +bmUxEzARBgNVBAsMCnJjbG9uZS1kZXYxHTAbBgNVBAMMFHJjbG9uZS1kZXYtY2xp +ZW50LWNhMB4XDTIzMDUyNTIzNTgzMloXDTMzMDUyMjIzNTgzMlowZDELMAkGA1UE +BhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xDzANBgNVBAoMBnJjbG9uZTETMBEG +A1UECwwKcmNsb25lLWRldjEaMBgGA1UEAwwRcmNsb25lLWRldi1jbGllbnQwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0hCo8Q7MsmdZMh+5t4+NtiU2D +h/QQYlQsXybJYtjuO4KMWvx4rqIrJkP5P/RBBQKbVcv2KvjfIDddHfHxdkFBT5bN +l/RHg6dzrvv18cFwk4Ho9e+LZ5Uq7aLCUkYxdrBwCvrd7+RfzGSlcpdupLtlWDX2 +5QvC0G3B2Cb0jCUl18vxO6u9XRcKJREjcjZ0kmORLX4kKWQQDtOc3Lb51q0zpRjf +Ev4otSugyo3B4VNpOnJdXxVTDQXDDkmvErxMrylKe4KMm3v608obODLFd49CCXI8 +g9TSHQGeMQBtyq7u/7B6Z11/iEyrGxxqUpe/bTK7vtUXG1xXF8CF4f2oJ9CJAgMB +AAEwDQYJKoZIhvcNAQELBQADggEBADML6IM1HPaQM7xF2tIrEyVzzLf1wlPS914a +CUI2Ck8q9wIwZ02P605dzgzwvAXyq5SZx+A0tYKeyai01lgL5dGF1Bo38E4yGwbW +2Zk00yGB2fdiCXKjj4yWhVnbCH7/GNIrFlCb7KZOWhkf1Ia66iDuZW6RZID37ai2 +qZxvDk7oW316pAVfl5hEPsKJcQXQJBX/+jJzjN/VSpGv6vuk1VzCHNROg6M5aEdh +D7r/kX/yEF5eVaPlE42S7YpzfgQpT3HKU/PLdq51MrRZ2B4Jm3daaGwty1bvymFv +zcEADCCnFdKlg0QfLkF/gsonMqlohaL0KKP6/7xO/YMD0Sb9Fe8= +-----END CERTIFICATE----- diff --git a/lib/http/testdata/client.csr b/lib/http/testdata/client.csr new file mode 100644 index 000000000..ab6db60d8 --- /dev/null +++ b/lib/http/testdata/client.csr @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICqTCCAZECAQAwZDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24x +DzANBgNVBAoMBnJjbG9uZTETMBEGA1UECwwKcmNsb25lLWRldjEaMBgGA1UEAwwR +cmNsb25lLWRldi1jbGllbnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQC0hCo8Q7MsmdZMh+5t4+NtiU2Dh/QQYlQsXybJYtjuO4KMWvx4rqIrJkP5P/RB +BQKbVcv2KvjfIDddHfHxdkFBT5bNl/RHg6dzrvv18cFwk4Ho9e+LZ5Uq7aLCUkYx +drBwCvrd7+RfzGSlcpdupLtlWDX25QvC0G3B2Cb0jCUl18vxO6u9XRcKJREjcjZ0 +kmORLX4kKWQQDtOc3Lb51q0zpRjfEv4otSugyo3B4VNpOnJdXxVTDQXDDkmvErxM +rylKe4KMm3v608obODLFd49CCXI8g9TSHQGeMQBtyq7u/7B6Z11/iEyrGxxqUpe/ +bTK7vtUXG1xXF8CF4f2oJ9CJAgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAZy97 +RGpwNyBJVLM10lgZjUMPlUOC3smGBfiJ75W0lQ/YlRhRMr2IeO15c7rD5Z4t4G06 +HI+1X8KObH61RvIRdDp+ypaqMGhu5UdHH8khyqsmB98e4gI1nhRKfWoAay+vrV3y +vwK/qgpsgst98HHzkEYIlSZtdHzpY5APjEqoTwWlAoRcwGbFj7Cnme5ga5NIn0W8 +jZ8S4ue0BompGNGwlE8T8swd14/IDNI9VLL1iHcOiClKX15ldHKlZPM1u1RXciQJ +1btA6JElqdLvuIA8DqwKiMniQotSz/X4xigEm7CLJQqVwj8brHJCNDDbx2qcGr1S +wiU3dzpA4NOuC635DA== +-----END CERTIFICATE REQUEST----- diff --git a/lib/http/testdata/client.key b/lib/http/testdata/client.key new file mode 100644 index 000000000..6b77c22a1 --- /dev/null +++ b/lib/http/testdata/client.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEuwIBADANBgkqhkiG9w0BAQEFAASCBKUwggShAgEAAoIBAQC0hCo8Q7MsmdZM +h+5t4+NtiU2Dh/QQYlQsXybJYtjuO4KMWvx4rqIrJkP5P/RBBQKbVcv2KvjfIDdd +HfHxdkFBT5bNl/RHg6dzrvv18cFwk4Ho9e+LZ5Uq7aLCUkYxdrBwCvrd7+RfzGSl +cpdupLtlWDX25QvC0G3B2Cb0jCUl18vxO6u9XRcKJREjcjZ0kmORLX4kKWQQDtOc +3Lb51q0zpRjfEv4otSugyo3B4VNpOnJdXxVTDQXDDkmvErxMrylKe4KMm3v608ob +ODLFd49CCXI8g9TSHQGeMQBtyq7u/7B6Z11/iEyrGxxqUpe/bTK7vtUXG1xXF8CF +4f2oJ9CJAgMBAAECgf985XTTfYPauBWtnd856RLSFs2q08XqEB5tFOihLeMp8cLB +mbJVTX6mnDMroTQ+SFklYJdeGx1WQ9QKeU2M42UC6y5L0XcSg+S4BboO0NYmLekU +ZhT3PxPWP9T83i/yyUwKOY6ZQAGixqhcUIy14QRHemDcEl2wzMUj+Yn6aXzKUPqw +3BQgtTVBItoBMOPz2OaK22JzSxI7TXLi8E6+Rqb+uXDE2flgcjSSO4VwVrhUzL4r +kxnTWhmwEn3p9GlSSRqL1vJIU7pQu1h+/d5PjYRAy1hFZikALe/U//V9uLetzMP/ +98ybqcCD/wUXu5ae5IYBpZ/E7D3t1Va1oskhilECgYEAytmZ78+5mxAlN50v8jM/ +1lHj1dd3VQGuEjvwdoyxcPX6sOooEXHz8+BchDomLO3aDpaaazGi5mom6VUNhvBE +GaWhK7VgFQGcfn13GIE+p5GFsZ3zs1eakNGSf7qN9yrDQLa/0MShUoflwxC2+fxl +2nIONerrSO7bXlc60JQ2d/ECgYEA49CApQCOOQFFQHrQx+6YrkmTHL6eJ5ckVW4X +31Ppli5OiqdaOSp+nXCqm0IyhRWiZ8teMqz0b92fZLUm4jfR939bV+3H8YRimjyc +n7Nxs8IhsPzgzlZtku2XZctdqI3U0OOn1w2zVDYAAIQPVydTA+IaqcWvEOlNKNmY +6R/BuhkCgYAHnTtmAQoag/ShrcjK8pmG1fQTZs8X5cQ+8vkHuig+8TzDv0ZZwUlC +8j0GyZf9P8Bbo9OQCoDu3TUwtPyZABPOUqVGGrzMjQ7uwI7j4JYVfCTkkeU/6h3n +KbayDLKfgH9rwnBYyci0bF13gP0dTRgVpwpZg8PpLO4XEHcotSeGQQKBgQDeu3z7 +Vea3bzmRCELWJr3aMQ8HHIsudARPDjuC2tzXO2EJCQQaPiTas0vqTjdsjLFjP59S +dmzqbkknwkFJDYBYtYjOGCnTRTbOS5JqRZxWPuiHzUXSFwg8jdTm7oUchcbbkKkJ +hlidbcpktrj04fq1IjwlXqSCKUeKN+zbiHP1CQKBgB6jZ7Vk6CGBSZTS5fJB8kgD +3IEX3K7mZF/4B2C48gvfysASR2hdDFfLzg2WTZhiavjWM91UDcvfPsIMAnFSA29I +oVYaZdBlkFJCGwImVOynn0GZQL5oTCN4He5k20Y0mSOX995ngXHSYsCNSbyyNwSQ +uOlbvNTIooMkhu2Tpr52 +-----END PRIVATE KEY----- diff --git a/lib/http/testdata/emptyclient.crt b/lib/http/testdata/emptyclient.crt new file mode 100644 index 000000000..586cbe3e9 --- /dev/null +++ b/lib/http/testdata/emptyclient.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDNjCCAh4CFGB8dDYPVQB1CqlJs2esk3l1wymHMA0GCSqGSIb3DQEBCwUAMGcx +CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMQ8wDQYDVQQKDAZyY2xv +bmUxEzARBgNVBAsMCnJjbG9uZS1kZXYxHTAbBgNVBAMMFHJjbG9uZS1kZXYtY2xp +ZW50LWNhMB4XDTIzMDUyNjAzNTIzMVoXDTMzMDUyMzAzNTIzMVowSDELMAkGA1UE +BhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xDzANBgNVBAoMBnJjbG9uZTETMBEG +A1UECwwKcmNsb25lLWRldjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AJqTaR9wVpkpalY972W102Fj5LL+cSvqte4kSzp2RTlRW5CXa5AJat+IXSeUln/6 +TJdwnpnRyHP12XSWWlqTeBG1Q6cDBMt7GRrIqK5qEitDNihlSVElJkeFHDStT79a +YJbyZ86IJXGKXP42TZGv56NkC/UCLbpRV7lq7zNgrCptZH+ZClRcNq7UGGsxEgzy +iISQ2ALf9MFtVxq85J76pi5nJ1WYc6d3usSBPk9uLWQvTPNNoVf35SRCWUPNHM0O +cOXIMicUIlpm6Ksh7KfiEEuuHlNH6F9YnlmEQkXzR+90KfSwwBH+jlBAUuuSkI4s +a5lES42sOEdjgno8lThXPgcCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAikhwkc1d +O+9fO9fMqi7iqdMBzF8c5F004IH1JRVHnkaMEOo2I+dUgVwwGj3iVQA7PdJce3Ij +GPwef1Wc5RdyhuwigjPO8Z4zRMBAASFnwerVS31HhO42ZS9sdfJwldBnBX4h/uKy +4ib3XVj+VfCBKDuKbV4Z6cjp9r81vO96xE5PVbNqK+DH1qNUIS+jDPJDK8nAyL7z +YjyluIR8ECbJje2WGIaNK/kNlz/8sRO64z8FZZbI67sL1fsauNcq8EFURq55tcfA +llwvwVB9Guns70pEsgvZLO5Vy+Gzq+veFdbmJ+aa2ayCor6hdZ8N7r8/Mj6KeEXZ +Eq03flwdARJKJQ== +-----END CERTIFICATE----- diff --git a/lib/http/testdata/emptyclient.csr b/lib/http/testdata/emptyclient.csr new file mode 100644 index 000000000..e266d36f0 --- /dev/null +++ b/lib/http/testdata/emptyclient.csr @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICjTCCAXUCAQAwSDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24x +DzANBgNVBAoMBnJjbG9uZTETMBEGA1UECwwKcmNsb25lLWRldjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAJqTaR9wVpkpalY972W102Fj5LL+cSvqte4k +Szp2RTlRW5CXa5AJat+IXSeUln/6TJdwnpnRyHP12XSWWlqTeBG1Q6cDBMt7GRrI +qK5qEitDNihlSVElJkeFHDStT79aYJbyZ86IJXGKXP42TZGv56NkC/UCLbpRV7lq +7zNgrCptZH+ZClRcNq7UGGsxEgzyiISQ2ALf9MFtVxq85J76pi5nJ1WYc6d3usSB +Pk9uLWQvTPNNoVf35SRCWUPNHM0OcOXIMicUIlpm6Ksh7KfiEEuuHlNH6F9YnlmE +QkXzR+90KfSwwBH+jlBAUuuSkI4sa5lES42sOEdjgno8lThXPgcCAwEAAaAAMA0G +CSqGSIb3DQEBCwUAA4IBAQBtGAtDmIdSZOpKLNHMqruN2J/ZP/W7N00wEViu3Etu +3GS5UofXoqVfeRVp6phbp8KdXBiU/VkMAWIAC8ZDqvQGArD/pr4mrIaqiWrzBQDG +NxuyXz3aRjkR9CVjRNyWiodQPY2lSkKlgVg0Erbb5TaWWzt9AHbDO1pUhg748CkY +AGZoLZvxWIR0XivCyFqYbhFOW6yzgXgqxrCr5wd2OGyrzaZBQUoydp1EVGZHkgGp +d8ZUH7cb497SAPcGImCgB1RQdFAHmUI6DjPJmsTe+4dcATDBL+IayUOGedWLu3yZ +PZc1O8/f50YjdLIeHuNqiIBb4hlKCoikZ1cdp/7J2hrq +-----END CERTIFICATE REQUEST----- diff --git a/lib/http/testdata/emptyclient.key b/lib/http/testdata/emptyclient.key new file mode 100644 index 000000000..59482a616 --- /dev/null +++ b/lib/http/testdata/emptyclient.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCak2kfcFaZKWpW +Pe9ltdNhY+Sy/nEr6rXuJEs6dkU5UVuQl2uQCWrfiF0nlJZ/+kyXcJ6Z0chz9dl0 +llpak3gRtUOnAwTLexkayKiuahIrQzYoZUlRJSZHhRw0rU+/WmCW8mfOiCVxilz+ +Nk2Rr+ejZAv1Ai26UVe5au8zYKwqbWR/mQpUXDau1BhrMRIM8oiEkNgC3/TBbVca +vOSe+qYuZydVmHOnd7rEgT5Pbi1kL0zzTaFX9+UkQllDzRzNDnDlyDInFCJaZuir +Ieyn4hBLrh5TR+hfWJ5ZhEJF80fvdCn0sMAR/o5QQFLrkpCOLGuZREuNrDhHY4J6 +PJU4Vz4HAgMBAAECggEAL+ExUretW0vk0Enm+Y5Up3oVwQvnaj8Nk3JSiw1Pa+2z +exosCzWfkRXgJP51j7asOsx7lBHTEXg5n09jNWMwceu/xN++gHjk0dMNzNi2QAhV +ojWdfDERpl2o2vhEF3WbLaZwWRz63CyLmYKgjFv8WDQJMB84otnHXnutFDEBozI7 +0+QQLacPVCuqid48x/ydDAzUdggmSkaB4WoIzYzEHHa1abC+giZZSxy9tMKAHHJH +rKuAANGC18cGeeQcGYxDz5FDYQiEZu/NEEv1gGbbOaMBu5pCZ6+43jzydv7BYiXJ +fzrCryeFihVzEG2Ri28JYYKi01YkOE3k2zsLSQUF4QKBgQDTcFsA8cveO03mZDFh +m6lf3K9EuDkJmGiusG/tYb+zfTkBwLNRQysQynjgq/5nxAVz/XawuvMSX+DBxvUR +IEWX2TCt62gb6eQW3q6S4RIBbp8qwQ75tZXXOfc/G3ho5zmJDikWMfor1kUnZwKI ++y8RmlCIc4MubVuIOj9sVTjr+wKBgQC7JydjAE9PyOMT8Zncc5atXSagOC6bbd0B +5xk7vxojjmOkvoi4OPUzxP22P5tLKZdor8jBv1oGwgmKKLjlnqfkJhpHa35bFx9y +NQ6koUdCqaDkWtXv5lEFZWRYniGU62LJMSHlLBu7L6PwX+Hfz+r62lSCGzUZnA9g +yX+s5YksZQKBgAmgjAQ2/jlYKevblAQFumiK+8/9M1ukfN+3WOFOGhRqFzZlN8Tz +cfqJvYc9TZAb9MObPtQ9LuQfSXSJQo9NEN4hHX5NwafDtob0DK7TYKaACu8/axcj +lXb/RKqy7YCZRp1e76/7BpEIaI2quwrRpQsAI7qSx95NTGWfgVPFbZoRAoGBALFZ +cSGH8aCRpV4I3NzjTC4Mz8WUd9YiTgS3klnjxklbbWF4jObGUtY0HpjNvcOELk6u +BXhUdGNjDNc3r78okcDJuq1jV+HKD6qSTMYFbxnk1OqQiZtEjhKm+mhfsUMFrB8r +yAr7uWuwwZHPyqPky6/bpamFTtRt5sS5LZwSB+NhAoGBALah1gCxay3pZLHg2Yhx +r5r4cUTaQmSs8NBqYeXHNx388ObQP01XxrD22XnyBKOqev4k9jSzz+RNRxl6kI8w +7IQhx2/dk5f032xmzIy/6nNrYI3qq0hwHkoPkG1g4VRDGBVscSQ5/IeZ6ysZbo5s +fOG8ouxBmrh03LCmnvYVGluA +-----END PRIVATE KEY-----