diff --git a/internal/ostree/ostree.go b/internal/ostree/ostree.go index 35f0af4d6..e5a7cdfd9 100644 --- a/internal/ostree/ostree.go +++ b/internal/ostree/ostree.go @@ -1,6 +1,8 @@ package ostree import ( + "crypto/tls" + "crypto/x509" "encoding/hex" "io/ioutil" "net/http" @@ -8,14 +10,20 @@ import ( "path" "regexp" "strings" + "time" + + "github.com/osbuild/osbuild-composer/internal/rhsm" ) var ostreeRefRE = regexp.MustCompile(`^(?:[\w\d][-._\w\d]*\/)*[\w\d][-._\w\d]*$`) +// RequestParams serves as input for ResolveParams, and contains all necessary variables to resolve +// a ref, which can then be turned into a CommitSpec. type RequestParams struct { URL string `json:"url"` Ref string `json:"ref"` Parent string `json:"parent"` + RHSM bool `json:"rhsm"` } // CommitSpec specifies an ostree commit using any combination of Ref (branch), URL (source), and Checksum (commit ID). @@ -50,13 +58,56 @@ func VerifyRef(ref string) bool { // ResolveRef resolves the URL path specified by the location and ref // (location+"refs/heads/"+ref) and returns the commit ID for the named ref. If // there is an error, it will be of type ResolveRefError. -func ResolveRef(location, ref string) (string, error) { +func ResolveRef(location, ref string, consumerCerts bool, subs *rhsm.Subscriptions) (string, error) { u, err := url.Parse(location) if err != nil { return "", NewResolveRefError(err.Error()) } u.Path = path.Join(u.Path, "refs/heads/", ref) - resp, err := http.Get(u.String()) + + var client *http.Client + if consumerCerts { + if subs == nil { + subs, err = rhsm.LoadSystemSubscriptions() + if subs.Consumer == nil || err != nil { + return "", NewResolveRefError("error adding rhsm certificates when resolving ref") + } + } + caCertPEM, err := ioutil.ReadFile(subs.Consumer.CACert) + if err != nil { + return "", NewResolveRefError("error adding rhsm certificates when resolving ref") + } + + roots := x509.NewCertPool() + ok := roots.AppendCertsFromPEM(caCertPEM) + if !ok { + return "", NewResolveRefError("error adding rhsm certificates when resolving ref") + } + + cert, err := tls.LoadX509KeyPair(subs.Consumer.ConsumerCert, subs.Consumer.ConsumerKey) + if err != nil { + return "", NewResolveRefError("error adding rhsm certificates when resolving ref") + } + client = &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + Certificates: []tls.Certificate{cert}, + RootCAs: roots, + MinVersion: tls.VersionTLS12, + }, + }, + Timeout: 300 * time.Second, + } + } else { + client = &http.Client{} + } + + req, err := http.NewRequest(http.MethodGet, u.String(), nil) + if err != nil { + return "", NewResolveRefError("error adding rhsm certificates when resolving ref") + } + + resp, err := client.Do(req) if err != nil { return "", NewResolveRefError(err.Error()) } @@ -114,7 +165,7 @@ func ResolveParams(params RequestParams) (ref, checksum string, err error) { // Resolve parent checksum if params.URL != "" { // If a URL is specified, we need to fetch the commit at the URL. - parent, err := ResolveRef(params.URL, parentRef) + parent, err := ResolveRef(params.URL, parentRef, params.RHSM, nil) if err != nil { return "", "", err // ResolveRefError } diff --git a/internal/ostree/ostree_test.go b/internal/ostree/ostree_test.go index 2ca929c62..493bead62 100644 --- a/internal/ostree/ostree_test.go +++ b/internal/ostree/ostree_test.go @@ -7,6 +7,10 @@ import ( "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/osbuild/osbuild-composer/internal/ostree/test_mtls_server" + "github.com/osbuild/osbuild-composer/internal/rhsm" ) func TestOstreeResolveRef(t *testing.T) { @@ -34,30 +38,63 @@ func TestOstreeResolveRef(t *testing.T) { srv := httptest.NewServer(handler) defer srv.Close() + mTLSSrv, err := test_mtls_server.NewMTLSServer(handler) + srv2 := mTLSSrv.Server + require.NoError(t, err) + defer srv2.Close() + subs := &rhsm.Subscriptions{ + Consumer: &rhsm.ConsumerSecrets{ + CACert: mTLSSrv.CAPath, + ConsumerKey: mTLSSrv.ClientKeyPath, + ConsumerCert: mTLSSrv.ClientCrtPath, + }, + } + + type srvConfig struct { + Srv *httptest.Server + RHSM bool + Subs *rhsm.Subscriptions + } + srvConfs := []srvConfig{ + srvConfig{ + Srv: srv, + RHSM: false, + Subs: nil, + }, + srvConfig{ + Srv: srv2, + RHSM: true, + Subs: subs, + }, + } + type input struct { location string ref string } - validCases := map[input]string{ - {srv.URL, "test_redir"}: goodRef, - {srv.URL, "valid/ostree/ref"}: goodRef, - } - for in, expOut := range validCases { - out, err := ResolveRef(in.location, in.ref) - assert.NoError(t, err) - assert.Equal(t, expOut, out) - } - errCases := map[input]string{ - {"not-a-url", "a-bad-ref"}: "Get \"not-a-url/refs/heads/a-bad-ref\": unsupported protocol scheme \"\"", - {"http://0.0.0.0:10/repo", "whatever"}: "Get \"http://0.0.0.0:10/repo/refs/heads/whatever\": dial tcp 0.0.0.0:10: connect: connection refused", - {srv.URL, "rhel/8/x86_64/edge"}: fmt.Sprintf("ostree repository \"%s/refs/heads/rhel/8/x86_64/edge\" returned status: 404 Not Found", srv.URL), - {srv.URL, "test_forbidden"}: fmt.Sprintf("ostree repository \"%s/refs/heads/test_forbidden\" returned status: 403 Forbidden", srv.URL), - {srv.URL, "get_bad_ref"}: fmt.Sprintf("ostree repository \"%s/refs/heads/get_bad_ref\" returned invalid reference", srv.URL), - } - for in, expMsg := range errCases { - _, err := ResolveRef(in.location, in.ref) - assert.EqualError(t, err, expMsg) + for _, srvConf := range srvConfs { + validCases := map[input]string{ + {srvConf.Srv.URL, "test_redir"}: goodRef, + {srvConf.Srv.URL, "valid/ostree/ref"}: goodRef, + } + for in, expOut := range validCases { + out, err := ResolveRef(in.location, in.ref, srvConf.RHSM, srvConf.Subs) + assert.NoError(t, err) + assert.Equal(t, expOut, out) + } + + errCases := map[input]string{ + {"not-a-url", "a-bad-ref"}: "Get \"not-a-url/refs/heads/a-bad-ref\": unsupported protocol scheme \"\"", + {"http://0.0.0.0:10/repo", "whatever"}: "Get \"http://0.0.0.0:10/repo/refs/heads/whatever\": dial tcp 0.0.0.0:10: connect: connection refused", + {srvConf.Srv.URL, "rhel/8/x86_64/edge"}: fmt.Sprintf("ostree repository \"%s/refs/heads/rhel/8/x86_64/edge\" returned status: 404 Not Found", srvConf.Srv.URL), + {srvConf.Srv.URL, "test_forbidden"}: fmt.Sprintf("ostree repository \"%s/refs/heads/test_forbidden\" returned status: 403 Forbidden", srvConf.Srv.URL), + {srvConf.Srv.URL, "get_bad_ref"}: fmt.Sprintf("ostree repository \"%s/refs/heads/get_bad_ref\" returned invalid reference", srvConf.Srv.URL), + } + for in, expMsg := range errCases { + _, err := ResolveRef(in.location, in.ref, srvConf.RHSM, srvConf.Subs) + assert.EqualError(t, err, expMsg) + } } } diff --git a/internal/ostree/test_mtls_server/ca.crt b/internal/ostree/test_mtls_server/ca.crt new file mode 100644 index 000000000..f4c00ef9c --- /dev/null +++ b/internal/ostree/test_mtls_server/ca.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDUzCCAjugAwIBAgIUQ2t8FSMBRHm94ydwULyQrxnKWi8wDQYJKoZIhvcNAQEL +BQAwFjEUMBIGA1UEAwwLb3NidWlsZC5vcmcwIBcNMjIxMDIxMTExNjI0WhgPMjEy +MjA5MjcxMTE2MjRaMBYxFDASBgNVBAMMC29zYnVpbGQub3JnMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoeBKaPFnQg7EOLWGyHuqYDQHgFpYxFLwgiiT +PMVDobebOnvR1NdSs7mFs339sXb+ld80KYUrgVTiqXIglWwLvWjbMqRGotN3iIc0 +C70o45VgAT0s5vUyvpw/OqSQ6i4fluGDnzhhmDGWfGMRK/NirvFTGMaxa81BopCH +HB13Vmcsfqgjukol1B3PN5lnjwXVtnYyy75VMZAazkpwF9SAycIKdoqcygUcEipQ +qSJOQ0m0bX4ridhnh4t7zHVeLDEhvK8BnBDRkCiy/mUo3U5MAC4KcYiU9wdjkuvw +eipDNLW8959RJmRmz0Y4BeWbxITo9DkBBG6n3cAePYKEZjRYWQIDAQABo4GWMIGT +MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFDoE7SvomYFOMNT0Rmjk8aB4JEoS +MFEGA1UdIwRKMEiAFDoE7SvomYFOMNT0Rmjk8aB4JEoSoRqkGDAWMRQwEgYDVQQD +DAtvc2J1aWxkLm9yZ4IUQ2t8FSMBRHm94ydwULyQrxnKWi8wDgYDVR0PAQH/BAQD +AgGGMA0GCSqGSIb3DQEBCwUAA4IBAQAldZN2HiEhwgxvlIijOKTYpRaKJOjvpw5m +kltTQmkt9QVDgrAXQxI1APBM3HPYrwoLRmLE7rluQf46UBvrSi8l0KJWLw262UJF +m7oWPDq+cA1CgSO//bP+CDrYfNb4oxi/3ojLlkQy60lmdH0Gh4AuLNYBjNpoqleP +9VDRibR1hRU8XDwzcmDbEQvF6ql062XO8FM4R6Vv8dPpGaAReBPJekSHmzpsn5fi +k/B5yjYJBxK6++3lqPilX1BPhTH+5HfV+xIxNRhNbiizMmhBdfkpFLdSd+IYZfvn +040Z0QnwM43aWjza82TaX4reWgNUlZugehAcqxZPCS4IYS+BDfeo +-----END CERTIFICATE----- diff --git a/internal/ostree/test_mtls_server/client.crt b/internal/ostree/test_mtls_server/client.crt new file mode 100644 index 000000000..749802ace --- /dev/null +++ b/internal/ostree/test_mtls_server/client.crt @@ -0,0 +1,85 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 12:8c:b9:0c:03:44:59:6b:01:ab:68:77:0e:02:9f:17:b9:b8:69:b9 + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN=osbuild.org + Validity + Not Before: Oct 21 11:16:24 2022 GMT + Not After : Sep 27 11:16:24 2122 GMT + Subject: CN=client.osbuild.org/emailAddress=osbuild@example.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:d8:9b:ae:30:a2:5b:7c:e2:08:64:9b:25:e2:61: + fd:69:bb:25:7d:c2:ee:ca:c2:88:e0:96:5d:e7:d0: + 20:f3:a8:cd:8b:31:07:21:01:de:a2:92:c1:b0:f3: + 77:64:82:b3:e1:d0:2d:f4:ca:db:ea:d3:50:a2:f5: + 1e:e4:ea:49:ea:d3:68:46:09:3d:16:0a:20:54:64: + 20:35:2d:89:8d:55:48:75:63:0b:4a:1d:dd:8a:02: + 68:3d:8c:81:fd:60:be:cd:ac:e5:91:da:fd:bf:36: + 77:95:d8:4f:83:14:c2:c6:3f:9e:40:7d:2a:bd:4c: + a6:0d:75:41:30:5d:11:14:ad:11:56:79:58:c3:7b: + 94:b2:db:d1:c9:e3:84:0d:d5:7d:da:92:98:6f:ce: + db:37:2c:da:3a:3e:c9:35:38:67:8a:3b:36:d0:73: + 50:47:75:6e:53:94:55:6b:e4:c1:a4:bd:22:4d:b2: + bf:57:72:aa:a0:73:7e:b6:77:07:85:72:c0:1a:5f: + c1:cb:d9:57:38:54:0c:ed:73:ce:ba:83:5b:00:c4: + 09:62:5e:12:89:0f:a9:05:4e:1d:98:2e:c4:14:63: + 74:5e:16:0b:5f:ac:83:c0:e0:5b:0e:93:35:80:b7: + 8e:85:da:cd:fe:3f:83:c5:35:38:34:e0:de:3d:3e: + 2f:a7 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Subject Key Identifier: + 8F:ED:C1:36:46:5D:80:B7:A9:3A:B9:A5:65:FD:9C:F1:07:F9:3B:A0 + X509v3 Authority Key Identifier: + keyid:3A:04:ED:2B:E8:99:81:4E:30:D4:F4:46:68:E4:F1:A0:78:24:4A:12 + + X509v3 Key Usage: critical + Digital Signature, Non Repudiation, Key Encipherment + X509v3 Extended Key Usage: + TLS Web Client Authentication + X509v3 Subject Alternative Name: + DNS:client.osbuild.org, IP Address:127.0.0.1 + Signature Algorithm: sha256WithRSAEncryption + 8d:4f:f2:ab:1a:08:8f:04:f8:ac:b5:7d:0d:14:7a:38:0f:d6: + 63:72:b0:df:7f:22:d4:a9:bd:5a:f3:53:f2:d6:e4:f2:29:01: + fc:72:7e:df:e7:2a:be:9c:d5:90:2f:9a:60:d3:63:64:49:81: + 58:06:f5:6b:2f:92:80:44:28:2b:e2:95:e3:a0:8e:eb:ef:5c: + 83:e9:d0:02:35:79:8d:21:a5:8b:32:d0:e8:88:7f:c5:72:8c: + 49:5f:6d:d9:20:dc:de:9f:e7:58:bb:bb:7b:10:1a:f9:00:fa: + 8d:c5:ec:05:7d:1b:c5:ac:f5:4a:6b:d3:b7:19:99:bc:a0:dd: + d7:75:4a:06:69:9d:d5:87:9a:f6:50:30:b1:d3:96:4b:a8:67: + 19:55:1d:ab:c2:77:ff:23:85:a4:2d:40:de:cd:d6:50:8c:ee: + de:d8:92:77:4a:6a:06:ee:92:52:04:1e:e6:3f:ff:2d:d0:44: + 75:e8:e5:f1:a2:c5:f8:6b:28:92:67:f6:25:52:52:ae:0a:65: + a9:3f:2a:1e:70:a8:45:d5:5d:14:40:50:05:0d:af:91:8a:68: + 0d:2d:27:ed:32:2b:f4:9e:ac:35:00:ec:f4:07:e1:80:92:59: + a1:aa:3c:60:11:e1:b8:b5:df:14:b5:20:94:9b:cd:2d:a6:ab: + 74:f5:39:17 +-----BEGIN CERTIFICATE----- +MIIDgDCCAmigAwIBAgIUEoy5DANEWWsBq2h3DgKfF7m4abkwDQYJKoZIhvcNAQEL +BQAwFjEUMBIGA1UEAwwLb3NidWlsZC5vcmcwIBcNMjIxMDIxMTExNjI0WhgPMjEy +MjA5MjcxMTE2MjRaMEExGzAZBgNVBAMMEmNsaWVudC5vc2J1aWxkLm9yZzEiMCAG +CSqGSIb3DQEJARYTb3NidWlsZEBleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBANibrjCiW3ziCGSbJeJh/Wm7JX3C7srCiOCWXefQIPOo +zYsxByEB3qKSwbDzd2SCs+HQLfTK2+rTUKL1HuTqSerTaEYJPRYKIFRkIDUtiY1V +SHVjC0od3YoCaD2Mgf1gvs2s5ZHa/b82d5XYT4MUwsY/nkB9Kr1Mpg11QTBdERSt +EVZ5WMN7lLLb0cnjhA3VfdqSmG/O2zcs2jo+yTU4Z4o7NtBzUEd1blOUVWvkwaS9 +Ik2yv1dyqqBzfrZ3B4VywBpfwcvZVzhUDO1zzrqDWwDECWJeEokPqQVOHZguxBRj +dF4WC1+sg8DgWw6TNYC3joXazf4/g8U1ODTg3j0+L6cCAwEAAaOBmDCBlTAJBgNV +HRMEAjAAMB0GA1UdDgQWBBSP7cE2Rl2At6k6uaVl/ZzxB/k7oDAfBgNVHSMEGDAW +gBQ6BO0r6JmBTjDU9EZo5PGgeCRKEjAOBgNVHQ8BAf8EBAMCBeAwEwYDVR0lBAww +CgYIKwYBBQUHAwIwIwYDVR0RBBwwGoISY2xpZW50Lm9zYnVpbGQub3JnhwR/AAAB +MA0GCSqGSIb3DQEBCwUAA4IBAQCNT/KrGgiPBPistX0NFHo4D9ZjcrDffyLUqb1a +81Py1uTyKQH8cn7f5yq+nNWQL5pg02NkSYFYBvVrL5KARCgr4pXjoI7r71yD6dAC +NXmNIaWLMtDoiH/FcoxJX23ZINzen+dYu7t7EBr5APqNxewFfRvFrPVKa9O3GZm8 +oN3XdUoGaZ3Vh5r2UDCx05ZLqGcZVR2rwnf/I4WkLUDezdZQjO7e2JJ3SmoG7pJS +BB7mP/8t0ER16OXxosX4ayiSZ/YlUlKuCmWpPyoecKhF1V0UQFAFDa+RimgNLSft +Miv0nqw1AOz0B+GAklmhqjxgEeG4td8UtSCUm80tpqt09TkX +-----END CERTIFICATE----- diff --git a/internal/ostree/test_mtls_server/client.key b/internal/ostree/test_mtls_server/client.key new file mode 100644 index 000000000..20384d6a3 --- /dev/null +++ b/internal/ostree/test_mtls_server/client.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDYm64wolt84ghk +myXiYf1puyV9wu7Kwojgll3n0CDzqM2LMQchAd6iksGw83dkgrPh0C30ytvq01Ci +9R7k6knq02hGCT0WCiBUZCA1LYmNVUh1YwtKHd2KAmg9jIH9YL7NrOWR2v2/NneV +2E+DFMLGP55AfSq9TKYNdUEwXREUrRFWeVjDe5Sy29HJ44QN1X3akphvzts3LNo6 +Psk1OGeKOzbQc1BHdW5TlFVr5MGkvSJNsr9Xcqqgc362dweFcsAaX8HL2Vc4VAzt +c866g1sAxAliXhKJD6kFTh2YLsQUY3ReFgtfrIPA4FsOkzWAt46F2s3+P4PFNTg0 +4N49Pi+nAgMBAAECggEBANR/Hcq+bGw+PqecAPVu1jF0lFok8yhc4fUZ7rPs3XbM +QiDsDydVczkgKf5TSuyCwL+mAH+mx0o+1luXhyBhq/RAQ4p5o8DMXF0OAP7KVqgd +Y0Et0jR6ygyLQgInppqQ335cwLZvFQISCA0rsQ1SP6ZHYRO490XQPRL01egBVTFm +rYXR2ntCFDuqwjy/XN/xzDQPSlgLNfE2MiCt8LaU+1DagdRLfSlFFMjOGIuOgxrU +sT6OyTv0l4EthuKBCyS8olX7Z+ChQ/q7YNqnHxZdKLYBNhG8MWBmSlHh5EOQs8oe +8elBXBMRRcylUCfuyePBy2FwGfbFdijeYuxZ708D9bECgYEA7z54QWrteDtyWDvp +bgh1pBN1XR4vJ9RXJ9YGCvexgemOnhJwqTpoVmpMuF9t0ytNP9t9iqpgTF1qJL7G +KtlfHZTGOW+3bqWzWxSmlmJ4l97akU1mroJLqYjKx3tAopcc4lVLg5jOhcJsj6iw +4qRU57QlOGejRoyU3H21pZRcEe8CgYEA58dcJixwWHLonfxcdAR2wdoV2hUpk9tS +lW/BrsDOoQW6cESwQopD0pfSNqqzLlpArCI+7A/ArzAz311dnM82dYmQCF+p6VJD +01Zh///67zS+/scHtij4aUHokoPAaSRcG5NrXV+M/tmxMbh2VbOiGLyZm1etPdhT +OWbSPPG8lckCgYEAjrh9lMjtESSlee2Du5hgVZkmEn7HMsOBmsoaoMBSrGVgJvxp +KQsm4yZWzkZfhfH3C3ks02QAPo4bnAASx80U6Nivx+PVUbSX4mXXWy8zMaZITRYX +g1NHP8PS9F2amWP8Xyjy+3ZU/YaWrLy9iPbvj6nv6k4pIRUMWNzFWBnBMxECgYEA +oXepIo7i1Tt4AlfEsK5LbVDY2EzV4kNwjNqGO4/mYxbygzPW9wQLq7JIp/zTRv9o +/oH9A8cVnPYfrQQGKy/P6KIkzTCX1guRZLFRJF7YGbzNMgDFxolURT+9HhTa/mRu +JmfU6/+c4g4V+2VeSuYRjtoUyLuT3PnPQLX40Kw3jMECgYBnjh8gKEyoySChHdiu +F3dGr1Q/d/XDdrtQ/oCyYKnCDixFLMJX0KEkLqJkCnXHMV9Mn0SPqJUq9elskYE8 +hQKo65nko0dH0faleM17Ox8j7fpjp0MEjzuO6T7LwibOk8dJnCG0mAoRQNRZW6GB +dLi37U3h2YWvQ8wnre5eBwgZpA== +-----END PRIVATE KEY----- diff --git a/internal/ostree/test_mtls_server/http_mtls_server.go b/internal/ostree/test_mtls_server/http_mtls_server.go new file mode 100644 index 000000000..66290d636 --- /dev/null +++ b/internal/ostree/test_mtls_server/http_mtls_server.go @@ -0,0 +1,76 @@ +package test_mtls_server + +import ( + "crypto/tls" + "crypto/x509" + "errors" + "fmt" + "io/ioutil" + "net/http" + "net/http/httptest" + "path/filepath" +) + +type MTLSServer struct { + Server *httptest.Server + CAPath string + ClientKeyPath string + ClientCrtPath string +} + +func NewMTLSServer(handler http.Handler) (*MTLSServer, error) { + certsPath, err := filepath.Abs("test_mtls_server") + if err != nil { + return nil, err + } + + caPath := filepath.Join(certsPath, "ca.crt") + serverKeyPath := filepath.Join(certsPath, "server.key") + serverCrtPath := filepath.Join(certsPath, "server.crt") + clientKeyPath := filepath.Join(certsPath, "client.key") + clientCrtPath := filepath.Join(certsPath, "client.crt") + + caCertPem, err := ioutil.ReadFile(caPath) + if err != nil { + return nil, err + } + + caPool := x509.NewCertPool() + ok := caPool.AppendCertsFromPEM(caCertPem) + if !ok { + return nil, fmt.Errorf("Unable to append ca cert (%s) to ca pool", caPath) + } + + serverCrt, err := tls.LoadX509KeyPair(serverCrtPath, serverKeyPath) + if err != nil { + return nil, err + } + + server := httptest.NewUnstartedServer(handler) + + server.TLS = &tls.Config{ + Certificates: []tls.Certificate{serverCrt}, + ClientAuth: tls.RequireAndVerifyClientCert, + ClientCAs: caPool, + MinVersion: tls.VersionTLS12, + VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { + for _, chain := range verifiedChains { + for _, domain := range []string{"127.0.0.1", "localhost", "osbuild.org"} { + if chain[0].VerifyHostname(domain) == nil { + return nil + } + } + } + + return errors.New("domain not in allowlist") + }, + } + server.StartTLS() + + return &MTLSServer{ + Server: server, + CAPath: caPath, + ClientKeyPath: clientKeyPath, + ClientCrtPath: clientCrtPath, + }, nil +} diff --git a/internal/ostree/test_mtls_server/server.crt b/internal/ostree/test_mtls_server/server.crt new file mode 100644 index 000000000..d8811f8f5 --- /dev/null +++ b/internal/ostree/test_mtls_server/server.crt @@ -0,0 +1,88 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: + 03:98:ce:0d:99:59:1a:59:c5:51:23:64:c1:86:80:47:82:2a:2f:0e + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN=osbuild.org + Validity + Not Before: Oct 21 11:16:24 2022 GMT + Not After : Sep 27 11:16:24 2122 GMT + Subject: CN=localhost/emailAddress=osbuild@example.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public-Key: (2048 bit) + Modulus: + 00:bb:8a:35:4b:56:c5:25:3d:85:ac:56:77:f0:a2: + f7:75:1a:4f:2e:10:d2:a5:15:07:83:9d:96:61:05: + 4d:09:fe:0f:bc:6f:3d:be:d9:8b:90:c2:9c:05:9f: + 92:4d:50:d2:63:da:e5:5e:95:e0:e4:96:db:d0:78: + d8:bb:e9:62:7d:80:6d:b5:42:be:24:8e:f3:15:f7: + ce:de:eb:1a:af:ee:5c:d7:e4:94:cf:f7:e2:e6:fc: + 65:a9:e0:d6:8b:f5:71:6a:af:dd:24:c5:0f:4a:a2: + 09:54:52:fe:05:ac:da:14:40:09:4a:f8:6a:fd:84: + 07:46:c2:5d:b1:ca:ee:8e:62:33:2b:a5:0c:9b:3a: + 34:aa:70:cc:77:1c:e6:0b:e8:7c:60:6f:a2:52:ac: + 15:5f:00:a5:6f:c2:22:8c:bf:59:f3:ee:89:4a:c9: + c3:a6:d3:c3:53:2e:eb:6d:c7:ee:fa:1a:83:06:17: + 00:08:dc:a5:2c:69:1c:4f:26:15:57:72:a1:42:97: + 41:98:9c:6c:db:43:0c:55:e4:41:86:bb:25:0e:37: + 04:17:04:03:fa:45:66:80:8a:e2:9f:66:8d:00:66: + ad:e1:a3:d0:63:0f:6d:a9:01:70:ab:5d:74:7f:73: + 62:17:6d:4d:b3:52:b2:78:34:b7:61:23:7e:fa:85: + e6:5f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: critical + CA:FALSE + X509v3 Subject Key Identifier: + C0:2F:23:10:5D:C6:BC:97:76:50:71:FC:93:C1:47:59:02:FD:BC:23 + X509v3 Authority Key Identifier: + keyid:3A:04:ED:2B:E8:99:81:4E:30:D4:F4:46:68:E4:F1:A0:78:24:4A:12 + DirName:/CN=osbuild.org + serial:43:6B:7C:15:23:01:44:79:BD:E3:27:70:50:BC:90:AF:19:CA:5A:2F + + X509v3 Key Usage: critical + Digital Signature, Key Encipherment + X509v3 Extended Key Usage: + TLS Web Server Authentication + X509v3 Subject Alternative Name: + DNS:localhost, DNS:composer, IP Address:127.0.0.1 + Signature Algorithm: sha256WithRSAEncryption + 72:f9:19:12:a1:d3:f6:62:66:5b:42:cf:da:c6:62:93:c9:29: + 28:0e:4d:f0:c3:00:f2:c1:a5:10:7b:17:3b:21:2c:3c:96:6f: + b3:0b:e7:fb:69:56:21:fe:dd:ed:25:64:97:0a:5c:8a:ec:c0: + dc:49:b4:9f:14:19:cc:0b:dc:20:a1:09:25:3c:4d:65:8d:56: + c9:16:c0:e5:2c:8b:3f:5d:27:4d:81:0e:1f:77:5e:e6:7d:d7: + e7:96:4c:27:b6:25:e7:42:d1:70:85:7f:08:4c:46:1e:59:21: + 94:6a:f1:dc:2a:38:9e:14:1e:99:07:e3:9e:cc:81:37:55:62: + fb:98:33:4e:2c:fa:eb:9c:9c:3e:76:64:7d:73:62:9f:d0:08: + 5d:ee:34:f3:8d:53:28:6c:20:f8:8c:3b:c8:32:d3:82:2f:3f: + a1:da:f4:ae:48:96:6b:2c:4c:60:b6:d5:19:d1:63:3d:9b:bd: + c2:89:fa:c3:0c:57:80:51:ea:79:1c:2b:ad:29:a5:01:93:6a: + 4e:36:28:60:e6:f3:fd:09:a8:4e:8a:5c:51:31:30:f3:d1:c1: + 2d:e0:7c:23:25:91:6f:bb:a6:f8:5a:01:18:34:51:ed:f9:ab: + c8:ab:6b:29:0e:19:44:25:09:60:e0:7c:a0:0c:45:37:7b:2d: + 62:1d:b6:61 +-----BEGIN CERTIFICATE----- +MIIDrTCCApWgAwIBAgIUA5jODZlZGlnFUSNkwYaAR4IqLw4wDQYJKoZIhvcNAQEL +BQAwFjEUMBIGA1UEAwwLb3NidWlsZC5vcmcwIBcNMjIxMDIxMTExNjI0WhgPMjEy +MjA5MjcxMTE2MjRaMDgxEjAQBgNVBAMMCWxvY2FsaG9zdDEiMCAGCSqGSIb3DQEJ +ARYTb3NidWlsZEBleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBALuKNUtWxSU9haxWd/Ci93UaTy4Q0qUVB4OdlmEFTQn+D7xvPb7Zi5DC +nAWfkk1Q0mPa5V6V4OSW29B42LvpYn2AbbVCviSO8xX3zt7rGq/uXNfklM/34ub8 +Zang1ov1cWqv3STFD0qiCVRS/gWs2hRACUr4av2EB0bCXbHK7o5iMyulDJs6NKpw +zHcc5gvofGBvolKsFV8ApW/CIoy/WfPuiUrJw6bTw1Mu623H7voagwYXAAjcpSxp +HE8mFVdyoUKXQZicbNtDDFXkQYa7JQ43BBcEA/pFZoCK4p9mjQBmreGj0GMPbakB +cKtddH9zYhdtTbNSsng0t2EjfvqF5l8CAwEAAaOBzjCByzAMBgNVHRMBAf8EAjAA +MB0GA1UdDgQWBBTALyMQXca8l3ZQcfyTwUdZAv28IzBRBgNVHSMESjBIgBQ6BO0r +6JmBTjDU9EZo5PGgeCRKEqEapBgwFjEUMBIGA1UEAwwLb3NidWlsZC5vcmeCFENr +fBUjAUR5veMncFC8kK8ZylovMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggr +BgEFBQcDATAkBgNVHREEHTAbgglsb2NhbGhvc3SCCGNvbXBvc2VyhwR/AAABMA0G +CSqGSIb3DQEBCwUAA4IBAQBy+RkSodP2YmZbQs/axmKTySkoDk3wwwDywaUQexc7 +ISw8lm+zC+f7aVYh/t3tJWSXClyK7MDcSbSfFBnMC9wgoQklPE1ljVbJFsDlLIs/ +XSdNgQ4fd17mfdfnlkwntiXnQtFwhX8ITEYeWSGUavHcKjieFB6ZB+OezIE3VWL7 +mDNOLPrrnJw+dmR9c2Kf0Ahd7jTzjVMobCD4jDvIMtOCLz+h2vSuSJZrLExgttUZ +0WM9m73CifrDDFeAUep5HCutKaUBk2pONihg5vP9CahOilxRMTDz0cEt4HwjJZFv +u6b4WgEYNFHt+avIq2spDhlEJQlg4HygDEU3ey1iHbZh +-----END CERTIFICATE----- diff --git a/internal/ostree/test_mtls_server/server.key b/internal/ostree/test_mtls_server/server.key new file mode 100644 index 000000000..970d6c66e --- /dev/null +++ b/internal/ostree/test_mtls_server/server.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC7ijVLVsUlPYWs +Vnfwovd1Gk8uENKlFQeDnZZhBU0J/g+8bz2+2YuQwpwFn5JNUNJj2uVeleDkltvQ +eNi76WJ9gG21Qr4kjvMV987e6xqv7lzX5JTP9+Lm/GWp4NaL9XFqr90kxQ9KoglU +Uv4FrNoUQAlK+Gr9hAdGwl2xyu6OYjMrpQybOjSqcMx3HOYL6Hxgb6JSrBVfAKVv +wiKMv1nz7olKycOm08NTLuttx+76GoMGFwAI3KUsaRxPJhVXcqFCl0GYnGzbQwxV +5EGGuyUONwQXBAP6RWaAiuKfZo0AZq3ho9BjD22pAXCrXXR/c2IXbU2zUrJ4NLdh +I376heZfAgMBAAECggEBAKwBGtg6gR6iypNBy0e9cFDLDIwnics2+mlQg7gAcKQV +jME7FdqRFFx04TyXGkwnMI+9GFokBNwjMQCHleDjMR4CSJzS1ioZogIoAmiaISPy +7txkHciQhl9sZqHkQWKkfp1nJuCujFPbQctBQxJZcrrX8K3+IcLa8QGJCv4iLaIQ +BMMBsqNlpok4qQavW2Bp79WbRSeGXEb4ce4bCjdZob8Qrhx+fCIflQoV2V5IGFTL +R163GGvzyoYxRQz7/35eMoWcCJAPNEN+nbx2V4HGPfnYq0LJGLLt5+wGa62IbHpU +nigDHfXXNPu1lpRjxMenSUJxQf1X/erYmphoWpfEF2ECgYEA41ZYVngSTClGBxKU +mYlYK5L+Lued6R3kqgMcxLd1zO4QdThvNASRe9oTee5JEOheQC0VoVwqEZ+mwoz8 +NueJc017w1HREgOG2WtZfnslKbVhg64XiaM3cK6WuEuWyYXy76cg+BFt025fheLw +4IC4+SNg1prXZQY2uI3kjLdEbcUCgYEA0y9Xa4yOcI8SZmcabMb1Ku708KNPcEpb +Vc56xnDpbdgU2BmXbZOGIxxz/7JtTyrh14Mq34n6L2ddtIREbQ1vgS3cR8uF2Lou +taviH2WdGpuR3SxXmjs5QOxzqf7Riza2Wg3fEctU3DsqrCITGZxhCQQnbm4lsyNc +O4DLzePtidMCgYBhazrnswSERpuPpFKxiL2TzqXGC9MLdpfqkvLdCZEdhFbhJJHi +xKJjZIw8D/SXnjvlXGyMfSY57yRS8n+SN54bHvUOOh1RjtlWij4LiVHfka578zp6 +7MpxKx/DUgEH0rLMJ95k73MUy5N7mEiIrCCYAqUY0bnDvOnuJD/wXQih0QKBgBY4 +tQosEBDn/RepYa5wgPuziTKI/KLkMBgnUePvnaBhTFAw4S42h7bKF6qgK8BY0srK +kohTDHBQgBuuj0SqVUFSggtL7xmO/btACtsi5hUWqZKMR+uCr9OVDdalaYcsiqOP +Mhm9O4Cw+RyDuV7Iha1dMoj8LhtbbSkVtFxFz4jhAoGAE83WDaeRwgYEO2l1P3vy +Rl9Ti2URwadhfid+c/Qmjmu8KMstPp+gPQvnpqkfANaTPE6d+1BjbmHnr5e7u2gY +Al4/pMR/bOD1SYdNECu11nYlFmSZniv95NZuoSvAiYm+SEAVM1vOCFLtB1lPWYkq +lH67FGOJr3Pe2R/oVa9Wcug= +-----END PRIVATE KEY-----