From 9b38f5a034486c27eaf81062ecdd86a72667e2b0 Mon Sep 17 00:00:00 2001 From: Rasmus Dahlberg Date: Fri, 23 Oct 2020 18:01:10 +0200 Subject: added basic trust-anchor code path Pretty much the bare minimum to load trust anchors from file and check that the submitter's certificate chains back to something valid. --- handler.go | 4 ++-- instance.go | 5 ++++- reqres.go | 20 ++++++++++++++--- server/main.go | 22 +++++++++++++----- server/testdata/anchors.pem | 32 ++++++++++++++++++++++++++ server/testdata/end-entity.key | 51 ++++++++++++++++++++++++++++++++++++++++++ server/testdata/end-entity.pem | 30 +++++++++++++++++++++++++ server/testdata/root.key | 51 ++++++++++++++++++++++++++++++++++++++++++ server/testdata/root.pem | 32 ++++++++++++++++++++++++++ 9 files changed, 235 insertions(+), 12 deletions(-) create mode 100644 server/testdata/anchors.pem create mode 100644 server/testdata/end-entity.key create mode 100644 server/testdata/end-entity.pem create mode 100644 server/testdata/root.key create mode 100644 server/testdata/root.pem diff --git a/handler.go b/handler.go index 80d7726..27b2fd9 100644 --- a/handler.go +++ b/handler.go @@ -50,7 +50,7 @@ func addEntry(ctx context.Context, i *instance, w http.ResponseWriter, r *http.R return http.StatusBadRequest, err } // request can be decoded - leaf, err := VerifyAddEntryRequest(request) + leaf, err := VerifyAddEntryRequest(i.anchors, request) if err != nil { return http.StatusBadRequest, err } // leaf is valid, e.g., signed by a trust anchor @@ -65,7 +65,7 @@ func addEntry(ctx context.Context, i *instance, w http.ResponseWriter, r *http.R trillianResponse, err := i.client.QueueLeaf(ctx, &trillianRequest) if err != nil { return http.StatusInternalServerError, fmt.Errorf("backend QueueLeaf request failed: %v", err) - } // note: more detail could be provided here, see addChainInternal in ctfe + } // note: more detail could be provided here, see addChainInternal in ctfe glog.Infof("Queued leaf: %v", trillianResponse.QueuedLeaf.Leaf.LeafValue) // TODO: respond with an SDI diff --git a/instance.go b/instance.go index 5fa1b6c..3f53e5f 100644 --- a/instance.go +++ b/instance.go @@ -8,6 +8,7 @@ import ( "github.com/golang/glog" "github.com/google/trillian" + "github.com/google/certificate-transparency-go/trillian/ctfe" ctutil "github.com/google/certificate-transparency-go/trillian/util" ) @@ -17,17 +18,19 @@ type instance struct { logID int64 client trillian.TrillianLogClient deadline time.Duration + anchors ctfe.CertValidationOpts timesource ctutil.TimeSource } // NewInstance returns a new STFE instance -func NewInstance(prefix string, id int64, client trillian.TrillianLogClient, deadline time.Duration, timesource ctutil.TimeSource) *instance { +func NewInstance(prefix string, id int64, client trillian.TrillianLogClient, deadline time.Duration, timesource ctutil.TimeSource, anchors ctfe.CertValidationOpts) *instance { return &instance{ prefix: prefix, logID: id, client: client, deadline: deadline, timesource: timesource, + anchors: anchors, } } diff --git a/reqres.go b/reqres.go index d2d40ec..c384d02 100644 --- a/reqres.go +++ b/reqres.go @@ -10,6 +10,7 @@ import ( "net/http" "github.com/google/certificate-transparency-go/tls" + "github.com/google/certificate-transparency-go/trillian/ctfe" "github.com/google/trillian" ) @@ -143,10 +144,23 @@ func NewGetProofByHashResponse(treeSize uint64, inclusionProof *trillian.Proof) // VerifyAddEntryRequest determines whether a well-formed AddEntryRequest should // be inserted into the log. If so, the serialized leaf value is returned. -func VerifyAddEntryRequest(r AddEntryRequest) ([]byte, error) { +func VerifyAddEntryRequest(a ctfe.CertValidationOpts, r AddEntryRequest) ([]byte, error) { item, _ := StItemFromB64(r.Item) // r.Item is a well-formed ChecksumV1 - // TODO: verify r.Signature and r.Certificate - leaf, _ := tls.Marshal(item) // again, r.Item is well-formed + leaf, _ := tls.Marshal(item) // again, r.Item is well-formed + + chainBytes, err := base64.StdEncoding.DecodeString(r.Certificate) + if err != nil { + return nil, fmt.Errorf("failed decoding certificate: %v", err) + } + + chain := make([][]byte, 0, 1) + chain = append(chain, chainBytes) + _, err = ctfe.ValidateChain(chain, a) + if err != nil { + return nil, fmt.Errorf("chain verification failed: %v", err) + } + + // TODO: verify signature return leaf, nil } diff --git a/server/main.go b/server/main.go index 53ac8e6..f52433b 100644 --- a/server/main.go +++ b/server/main.go @@ -12,15 +12,18 @@ import ( "github.com/system-transparency/stfe" "google.golang.org/grpc" + "github.com/google/certificate-transparency-go/trillian/ctfe" ctutil "github.com/google/certificate-transparency-go/trillian/util" + "github.com/google/certificate-transparency-go/x509" ) var ( - httpEndpoint = flag.String("http_endpoint", "localhost:6965", "host:port specification of where stfe serves clients") - rpcBackend = flag.String("log_rpc_server", "localhost:6962", "host:port specification of where Trillian serves clients") - prefix = flag.String("prefix", "/st/v1", "a prefix that proceeds each endpoint path") - trillianID = flag.Int64("trillianID", 5991359069696313945, "log identifier in the Trillian database") - rpcDeadline = flag.Duration("rpc_deadline", time.Second*10, "deadline for backend RPC requests") + httpEndpoint = flag.String("http_endpoint", "localhost:6965", "host:port specification of where stfe serves clients") + rpcBackend = flag.String("log_rpc_server", "localhost:6962", "host:port specification of where Trillian serves clients") + prefix = flag.String("prefix", "/st/v1", "a prefix that proceeds each endpoint path") + trillianID = flag.Int64("trillian_id", 5991359069696313945, "log identifier in the Trillian database") + rpcDeadline = flag.Duration("rpc_deadline", time.Second*10, "deadline for backend RPC requests") + anchorsPemFile = flag.String("anchors_file", "testdata/anchors.pem", "path to a file containing PEM-encoded X.509 root certificates") ) func main() { @@ -37,8 +40,15 @@ func main() { mux := http.NewServeMux() http.Handle("/", mux) + // TODO: proper setup + glog.Info("Loading trust anchors") + cert_pool := ctfe.NewPEMCertPool() + cert_pool.AppendCertsFromPEMFile(*anchorsPemFile) + anchors := ctfe.NewCertValidationOpts(cert_pool, time.Now(), true, false, nil, nil, false, []x509.ExtKeyUsage{}) + glog.Infof("%v", cert_pool.Subjects()) + glog.Info("Creating STFE server instance") - stfe_server := stfe.NewInstance(*prefix, *trillianID, trillian.NewTrillianLogClient(conn), *rpcDeadline, new(ctutil.SystemTimeSource)) + stfe_server := stfe.NewInstance(*prefix, *trillianID, trillian.NewTrillianLogClient(conn), *rpcDeadline, new(ctutil.SystemTimeSource), anchors) stfe_server.AddEndpoints(mux) glog.Infof("Serving on %v%v", *httpEndpoint, *prefix) diff --git a/server/testdata/anchors.pem b/server/testdata/anchors.pem new file mode 100644 index 0000000..6a96054 --- /dev/null +++ b/server/testdata/anchors.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFiTCCA3GgAwIBAgIUCpdSpYgFV7bmPzdIAcesg5ZJxe4wDQYJKoZIhvcNAQEL +BQAwVDELMAkGA1UEBhMCU0UxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDENMAsGA1UEAwwEcmdkZDAeFw0yMDEw +MjMxNDI4MzFaFw0yMzA4MTMxNDI4MzFaMFQxCzAJBgNVBAYTAlNFMRMwEQYDVQQI +DApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQx +DTALBgNVBAMMBHJnZGQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2 +zbx/W/DBBUOtd94vzI0Qqx/909oJAMyqxF5evFmeoyORI/rIeXzvCu2YOQa7Y1Ku +wKuY65oafIDLY+FMxHKBhJ7vaY3wQJQxj4e0nXjcnFHCIBWwcrP2bb1aGwog2WyI +kKjEUdFshFcUuGNFrEzlLyW0wOh3Enm7mt30U+a7LsUUBfhrgK/CMnrthc35rFVJ +DiIBcEzl2F+n4k7BY+d4MqgCqPJmA9+f30F19JMTPcrjSEevNUNoH7+Vrzl8bgWr +5i2VezE/gMVeFjHFebzBjGKxxRtSPt2In/I2vALvPUuZ5Lw29Ire0Wy/AhYB1ngx +/L3nSHvMzlmlGC5H7FHMqg8T9g9VOaUWyiO8Ck73dF8JHxIOKwCJWZgIr4qAwSvK +O8PpHIoFOhpLFLhP+zH3B2w4QFbk/HfuQ2Ww78+AXEHoP2JTiAyH89xD/g+6366W +5dcutQw+rb1S9DGc4yXIPTew/24Hzmu1YkhcRemwebZ6s6y7H9muz0T4Ax2eYb0Z +NtaTR7+1TEcC/3R2YWuK1H8kY2kwEl0ize77QRZPii4cLCvIT9Ug7xpzVLYlJvly +WswZed1R8rncUE4fqWYOu0V0LzC/PBUv2cmFk0i6UjpCbFH70hK58AvZccpH+onF +RZNdqM5q+jjaySLzZFiqezgGX1k25p8H76EqaC59xQIDAQABo1MwUTAdBgNVHQ4E +FgQUrcBnUTJSmhmdJdn+HA/aBSQ1VYQwHwYDVR0jBBgwFoAUrcBnUTJSmhmdJdn+ +HA/aBSQ1VYQwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAVivn +9T+M8rsWaP9PPsBTJbcgbfL1gmKMDh7xki14don5b3aJytzsrFowDDCQodtq6kPw +r3iv5M55pftQxwT3s+buFSX0ck57PSif1u/TfVMT1tq+YQuFeQLoo7Kr8bk5kUCG +GVqHBwllPaRbQQ4y2Lx4/i8J4hj8//IYR0lEnDNEpOkMM1pZYU5bsB7aUfJOaHVD +QnUyAiudZtSTWNT0rB2vYYef8yBFQoSi2Uj5CCdoM4ubi/pEvnbtT8rKseaycjBA +2lw+fO4B6s3haRWY+U8BAEqTUq9GesH++SM9t1VDAlcoRZx2s6JeZrvSYMs6NyVQ +JilrhOmRg6Dghkt9UJQWpCkslxsEze1Crz1KQgFyRwtqkaeDGlwRGhySlHCMg4vu +aXGDdSTUv2m9Ss31ktwEmMNcPI7vyehHyhFnt6wi3FzCnQu/I5D4MtOerrUljLiU +qXQkFGditrKuZQnRwx6mOAy5hIrtJVqlBi+bzmNAoUHdkcID8YEpbx47eBEIwyct +Wi2x19FOI+aECutO/OjzkfOkig3cZg0qwAm/JJsve4nc8d5D2HewH99EFGtuz1jn +4mimMAjebW17Uf484w4wI3IeQ/F+nDvk14xkD+Hc90tq6KH7z0DplhXVIvx8SPs3 +9109jghVzFwjxF+FS9QkvUQaqdoyVCw5SI0c3hA= +-----END CERTIFICATE----- diff --git a/server/testdata/end-entity.key b/server/testdata/end-entity.key new file mode 100644 index 0000000..f232f2e --- /dev/null +++ b/server/testdata/end-entity.key @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- diff --git a/server/testdata/end-entity.pem b/server/testdata/end-entity.pem new file mode 100644 index 0000000..ab5154f --- /dev/null +++ b/server/testdata/end-entity.pem @@ -0,0 +1,30 @@ +-----BEGIN CERTIFICATE----- +MIIFMjCCAxoCFFdE6AyXlAd3tmoTZXRkLElTp6d1MA0GCSqGSIb3DQEBCwUAMFQx +CzAJBgNVBAYTAlNFMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl +cm5ldCBXaWRnaXRzIFB0eSBMdGQxDTALBgNVBAMMBHJnZGQwHhcNMjAxMDIzMTQz +NTQ2WhcNMjIwMzE5MTQzNTQ2WjBXMQswCQYDVQQGEwJTRTETMBEGA1UECAwKU29t +ZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRAwDgYD +VQQDDAdyZ2RkLWVlMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAx42J ++xiAYTGGJL0w6KHXV6in9IuHOBiyKvavVog8qWh1dh3I3nIUA3i0CdbeuLRubovC +pOIFk2HjKo1qxpdh/Iab3RtTBEYghz8bkdIi3PhNdsgKUh2Pi7GCE/+0NdzMKUxL +LSqJAIF+WymbfnnRYsxPjPBusnNdTunLWuvjS2AcpaLFcF+LojdlaFBUDvDYGWpP +h60/z9IjUE7JbxluAl4GZYIx2bSlhQZ96bse/HoEjeJumv74JZ4GI1SH/TjFJCQS +KRMPimm7PXsTDoaZrw/8Bc+FfVbLyp7u3ML28WGfABzPjvzXScKPTRjjoVdX2BWp +kOV7T5zVYsJAs6cGbIgJ6UWPsOafSrIPTSCz17sNDCaN1PtkNKemosMFt8aZvnYX +eypvMC0SPFKQr3+uFuxRIjRIrRrVfLfIb9iHBo20vSbunnRt9jwmHq5UvXxLSMoB +dFKMp8RmnV22e40gpWppZ3C4e8HaDrGsGV0LB04PFkFaa/iqyAh8NxG7c4AFzkD7 +efDg+XQ1ujSLtnX0Mr+C/HGVpoJVRdMxnRGnUIdGt6tXrCMGGWkxjVObMaxdPe/7 +PccjxoN5wKa6Nxcv0T0dZFntKkizBJGw2VuBEAFfQCvz7a18YvQV70mr4FU5gQ4Q +4M6pshrerM+4laIVheEJWvWi5Nh8l2NI9R0x3R0CAwEAATANBgkqhkiG9w0BAQsF +AAOCAgEAEr0mnYtQx1WBSEVsRd4q0F8dmwEFaaIoC25RaOlbUiWUSp1S7vZpa/KJ +ds7dh5xSNgssjoCuTFAWezgCQmEmI4JBuki4Bc5iJvVctRa/b4p0Dm6YxEYz2c2j +0IaD32N4xZXQb+1Rf0RxEmExADZbAdmso7B0W/aCIMKwJID0FRt443ZWmu7fsLH1 +0xCr4ZQusX8eQ29jKNaMAS67uNz71z1FqffzwdtzGziE25sHgLqiyMGZzoJm1hw+ +mS5E21XAdgPu9JWoYzS+G/uqw7ZjjHEv+GPyjKhgXzgu3AxMZbQx0wTnSWHTsj57 +qgUGI1sOaxhRWkPouXztvSMOkW3zYSrNc740YxoDvYYYPveAnQ15ThqgPCon9/SE +mqwjQzjoRVTfQz4AQgj3v2RBRYgHHu51L6VMkpanNRuUnPXvs9MqNgIhAoFENd+C +5c/K92ntTXgYTGigPbW+a4IUVj0Ry8ctg45JZ40YBGSrReDcap9lct8X/pREY1Af +jBpd5QPBszBaozcuTAVmakiD+YL3/JOCKNbdAYQeSXYi1A0v8n+pNvgEJRQIbbyX +0mQugmo6EEwzRGXcc8NnBgA3knkpT/PyDgzS1uTGoDYh1iPSkkVtXNxrNgmA7jem +Kls6XILMjQzGWAo2R/8aVnlTCF0rDBV3I12wcSQ/MsjMVXwag1k= +-----END CERTIFICATE----- diff --git a/server/testdata/root.key b/server/testdata/root.key new file mode 100644 index 0000000..97effe3 --- /dev/null +++ b/server/testdata/root.key @@ -0,0 +1,51 @@ +-----BEGIN RSA PRIVATE KEY----- +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 +-----END RSA PRIVATE KEY----- diff --git a/server/testdata/root.pem b/server/testdata/root.pem new file mode 100644 index 0000000..6a96054 --- /dev/null +++ b/server/testdata/root.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFiTCCA3GgAwIBAgIUCpdSpYgFV7bmPzdIAcesg5ZJxe4wDQYJKoZIhvcNAQEL +BQAwVDELMAkGA1UEBhMCU0UxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDENMAsGA1UEAwwEcmdkZDAeFw0yMDEw +MjMxNDI4MzFaFw0yMzA4MTMxNDI4MzFaMFQxCzAJBgNVBAYTAlNFMRMwEQYDVQQI +DApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQx +DTALBgNVBAMMBHJnZGQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2 +zbx/W/DBBUOtd94vzI0Qqx/909oJAMyqxF5evFmeoyORI/rIeXzvCu2YOQa7Y1Ku +wKuY65oafIDLY+FMxHKBhJ7vaY3wQJQxj4e0nXjcnFHCIBWwcrP2bb1aGwog2WyI +kKjEUdFshFcUuGNFrEzlLyW0wOh3Enm7mt30U+a7LsUUBfhrgK/CMnrthc35rFVJ +DiIBcEzl2F+n4k7BY+d4MqgCqPJmA9+f30F19JMTPcrjSEevNUNoH7+Vrzl8bgWr +5i2VezE/gMVeFjHFebzBjGKxxRtSPt2In/I2vALvPUuZ5Lw29Ire0Wy/AhYB1ngx +/L3nSHvMzlmlGC5H7FHMqg8T9g9VOaUWyiO8Ck73dF8JHxIOKwCJWZgIr4qAwSvK +O8PpHIoFOhpLFLhP+zH3B2w4QFbk/HfuQ2Ww78+AXEHoP2JTiAyH89xD/g+6366W +5dcutQw+rb1S9DGc4yXIPTew/24Hzmu1YkhcRemwebZ6s6y7H9muz0T4Ax2eYb0Z +NtaTR7+1TEcC/3R2YWuK1H8kY2kwEl0ize77QRZPii4cLCvIT9Ug7xpzVLYlJvly +WswZed1R8rncUE4fqWYOu0V0LzC/PBUv2cmFk0i6UjpCbFH70hK58AvZccpH+onF +RZNdqM5q+jjaySLzZFiqezgGX1k25p8H76EqaC59xQIDAQABo1MwUTAdBgNVHQ4E +FgQUrcBnUTJSmhmdJdn+HA/aBSQ1VYQwHwYDVR0jBBgwFoAUrcBnUTJSmhmdJdn+ +HA/aBSQ1VYQwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAVivn +9T+M8rsWaP9PPsBTJbcgbfL1gmKMDh7xki14don5b3aJytzsrFowDDCQodtq6kPw +r3iv5M55pftQxwT3s+buFSX0ck57PSif1u/TfVMT1tq+YQuFeQLoo7Kr8bk5kUCG +GVqHBwllPaRbQQ4y2Lx4/i8J4hj8//IYR0lEnDNEpOkMM1pZYU5bsB7aUfJOaHVD +QnUyAiudZtSTWNT0rB2vYYef8yBFQoSi2Uj5CCdoM4ubi/pEvnbtT8rKseaycjBA +2lw+fO4B6s3haRWY+U8BAEqTUq9GesH++SM9t1VDAlcoRZx2s6JeZrvSYMs6NyVQ +JilrhOmRg6Dghkt9UJQWpCkslxsEze1Crz1KQgFyRwtqkaeDGlwRGhySlHCMg4vu +aXGDdSTUv2m9Ss31ktwEmMNcPI7vyehHyhFnt6wi3FzCnQu/I5D4MtOerrUljLiU +qXQkFGditrKuZQnRwx6mOAy5hIrtJVqlBi+bzmNAoUHdkcID8YEpbx47eBEIwyct +Wi2x19FOI+aECutO/OjzkfOkig3cZg0qwAm/JJsve4nc8d5D2HewH99EFGtuz1jn +4mimMAjebW17Uf484w4wI3IeQ/F+nDvk14xkD+Hc90tq6KH7z0DplhXVIvx8SPs3 +9109jghVzFwjxF+FS9QkvUQaqdoyVCw5SI0c3hA= +-----END CERTIFICATE----- -- cgit v1.2.3