From e2735bf36a604db1995464a408fae20dab3b5152 Mon Sep 17 00:00:00 2001 From: Simon Ott Date: Fri, 16 Feb 2024 12:05:16 +0000 Subject: [PATCH] testtool: refactored publishing method Introduced callbacks for attested HTTPS and attested TLS verification results so that testtool can further process them. Signed-off-by: Simon Ott --- attestedhttp/client.go | 6 ++--- attestedhttp/server.go | 9 +++----- attestedtls/attestation.go | 3 +-- attestedtls/coap.go | 15 ++++++++----- attestedtls/config.go | 9 ++++---- attestedtls/grpc.go | 15 ++++++++----- attestedtls/libapi.go | 7 ++++-- attestedtls/listener.go | 5 ++++- attestedtls/socket.go | 15 ++++++++----- testtool/config.go | 1 + testtool/http.go | 19 ++++++++++++++++ testtool/publish.go | 4 ++++ testtool/tls.go | 45 +++++++++++++++----------------------- 13 files changed, 91 insertions(+), 62 deletions(-) diff --git a/attestedhttp/client.go b/attestedhttp/client.go index a80555e9..93d41747 100644 --- a/attestedhttp/client.go +++ b/attestedhttp/client.go @@ -66,6 +66,7 @@ type Transport struct { CmcPolicies []byte Ca []byte ReadTimeout time.Duration + ResultCb func(result *ar.VerificationResult) } // Wrapper for net/http Client @@ -187,18 +188,15 @@ func prepareClient(c *Client) error { log.Debugf("Dialing TLS address: %v", addr) - verificationResult := new(ar.VerificationResult) - conn, err := atls.Dial("tcp", addr, c.Transport.TLSClientConfig, atls.WithCmcConfig(&cmcConfig), - atls.WithResult(verificationResult)) + atls.WithResultCb(c.Transport.ResultCb)) if err != nil { return nil, fmt.Errorf("failed to dial server: %w", err) } if c.Transport.ReadTimeout != 0 { _ = conn.SetReadDeadline(time.Now().Add(c.Transport.ReadTimeout)) } - // TODO store verification result for retrieval log.Debugf("aHTTPS connection established") diff --git a/attestedhttp/server.go b/attestedhttp/server.go index a874d458..6b8d3777 100644 --- a/attestedhttp/server.go +++ b/attestedhttp/server.go @@ -27,7 +27,7 @@ import ( // Wrapper for http.Server type Server struct { - Server *http.Server + *http.Server // Additional aTLS parameters Attest string @@ -38,6 +38,7 @@ type Server struct { Cmc *cmc.Cmc CmcPolicies []byte Ca []byte + ResultCb func(result *ar.VerificationResult) } func (s *Server) ListenAndServe() error { @@ -46,8 +47,6 @@ func (s *Server) ListenAndServe() error { return errors.New("failed to listen: no TLS config provided") } - verificationResult := new(ar.VerificationResult) - // Listen: TLS connection ln, err := atls.Listen("tcp", s.Server.Addr, s.Server.TLSConfig, atls.WithCmcAddr(s.CmcAddr), @@ -57,15 +56,13 @@ func (s *Server) ListenAndServe() error { atls.WithMtls(s.MutualTls), atls.WithAttest(s.Attest), atls.WithCmcNetwork(s.CmcNetwork), - atls.WithResult(verificationResult), + atls.WithResultCb(s.ResultCb), atls.WithCmc(s.Cmc)) if err != nil { log.Fatalf("Failed to listen for connections: %v", err) } defer ln.Close() - // TODO store verification result - log.Infof("Serving HTTPS under %v", s.Server.Addr) err = s.Server.Serve(ln) diff --git a/attestedtls/attestation.go b/attestedtls/attestation.go index 68308bbf..509e3de3 100644 --- a/attestedtls/attestation.go +++ b/attestedtls/attestation.go @@ -102,14 +102,13 @@ func attestListener(conn *tls.Conn, chbindings []byte, cc CmcConfig) error { log.Debug("Skipping server-side attestation") } - readValue, err := readValue(conn, cc.Attest, false) + report, err := readValue(conn, cc.Attest, false) if err != nil { return err } // optional: Wait for attestation report from client if cc.Attest == Attest_Mutual || cc.Attest == Attest_Client { - report := readValue // Verify AR from dialer with own channel bindings log.Trace("Verifying attestation report from dialer...") err = cc.CmcApi.verifyAR(chbindings, report, cc) diff --git a/attestedtls/coap.go b/attestedtls/coap.go index adb18fec..d37521bb 100644 --- a/attestedtls/coap.go +++ b/attestedtls/coap.go @@ -134,16 +134,21 @@ func (a CoapApi) verifyAR(chbindings, report []byte, cc CmcConfig) error { } // Parse VerificationResult - if cc.Result == nil { - cc.Result = new(ar.VerificationResult) - } - err = json.Unmarshal(verifyResp.VerificationResult, cc.Result) + result := new(ar.VerificationResult) + err = json.Unmarshal(verifyResp.VerificationResult, result) if err != nil { return fmt.Errorf("could not parse verification result: %w", err) } + // Return attestation result via callback if specified + if cc.ResultCb != nil { + cc.ResultCb(result) + } else { + log.Tracef("Will not return attestation result: no callback specified") + } + // check results - if !cc.Result.Success { + if !result.Success { return errors.New("attestation report verification failed") } diff --git a/attestedtls/config.go b/attestedtls/config.go index 790dc539..794fd87d 100644 --- a/attestedtls/config.go +++ b/attestedtls/config.go @@ -54,7 +54,7 @@ type CmcConfig struct { Policies []byte Mtls bool Attest AttestSelect - Result *ar.VerificationResult + ResultCb func(result *ar.VerificationResult) Cmc *cmc.Cmc } @@ -124,11 +124,10 @@ func WithAttest(mAttest string) ConnectionOption[CmcConfig] { } } -// WithResult takes an attestation result by reference as input parameter -// and writes the attestation result -func WithResult(result *ar.VerificationResult) ConnectionOption[CmcConfig] { +// WithResultCb is a callback for further processing of attestation results +func WithResultCb(cb func(result *ar.VerificationResult)) ConnectionOption[CmcConfig] { return func(c *CmcConfig) { - c.Result = result + c.ResultCb = cb } } diff --git a/attestedtls/grpc.go b/attestedtls/grpc.go index 8d1819e9..9e1f2e0c 100644 --- a/attestedtls/grpc.go +++ b/attestedtls/grpc.go @@ -111,16 +111,21 @@ func (a GrpcApi) verifyAR(chbindings, report []byte, cc CmcConfig) error { } // Parse VerificationResult - if cc.Result == nil { - cc.Result = new(ar.VerificationResult) - } - err = json.Unmarshal(resp.GetVerificationResult(), cc.Result) + result := new(ar.VerificationResult) + err = json.Unmarshal(resp.GetVerificationResult(), result) if err != nil { return fmt.Errorf("could not parse verification result: %w", err) } + // Return attestation result via callback if specified + if cc.ResultCb != nil { + cc.ResultCb(result) + } else { + log.Tracef("Will not return attestation result: no callback specified") + } + // check results - if !cc.Result.Success { + if !result.Success { return errors.New("attestation report verification failed") } return nil diff --git a/attestedtls/libapi.go b/attestedtls/libapi.go index 8ad8f678..959a4e0b 100644 --- a/attestedtls/libapi.go +++ b/attestedtls/libapi.go @@ -68,8 +68,11 @@ func (a LibApi) verifyAR(chbindings, report []byte, cc CmcConfig) error { log.Debug("Verifier: Verifying Attestation Report") result := ar.Verify(report, chbindings, cc.Ca, nil, cc.Cmc.PolicyEngineSelect, cc.Cmc.IntelStorage) - if cc.Result != nil { - *cc.Result = result + // Return attestation result via callback if specified + if cc.ResultCb != nil { + cc.ResultCb(&result) + } else { + log.Tracef("Will not return attestation result: no callback specified") } if !result.Success { diff --git a/attestedtls/listener.go b/attestedtls/listener.go index c82df5d4..1cd9c5e8 100644 --- a/attestedtls/listener.go +++ b/attestedtls/listener.go @@ -66,7 +66,10 @@ func (ln Listener) Accept() (net.Conn, error) { } cs := tlsConn.ConnectionState() - log.Tracef("TLS Handshake Complete: %v, generating channel bindings", cs.HandshakeComplete) + if !cs.HandshakeComplete { + return nil, errors.New("internal error: handshake not complete") + } + log.Trace("TLS handshake complete, generating channel bindings") chbindings, err := cs.ExportKeyingMaterial("EXPORTER-Channel-Binding", nil, 32) if err != nil { return nil, fmt.Errorf("failed to export keying material for channel binding: %w", err) diff --git a/attestedtls/socket.go b/attestedtls/socket.go index 25304eb7..d571a5be 100644 --- a/attestedtls/socket.go +++ b/attestedtls/socket.go @@ -123,16 +123,21 @@ func (a SocketApi) verifyAR(chbindings, report []byte, cc CmcConfig) error { } // Parse VerificationResult - if cc.Result == nil { - cc.Result = new(ar.VerificationResult) - } - err = json.Unmarshal(verifyResp.VerificationResult, cc.Result) + result := new(ar.VerificationResult) + err = json.Unmarshal(verifyResp.VerificationResult, result) if err != nil { return fmt.Errorf("could not parse verification result: %w", err) } + // Return attestation result via callback if specified + if cc.ResultCb != nil { + cc.ResultCb(result) + } else { + log.Tracef("Will not return attestation result: no callback specified") + } + // Check results - if !cc.Result.Success { + if !result.Success { return errors.New("attestation report verification failed") } return nil diff --git a/testtool/config.go b/testtool/config.go index cf797020..fdf228b4 100644 --- a/testtool/config.go +++ b/testtool/config.go @@ -178,6 +178,7 @@ func getConfig() *config { Api: "grpc", LogLevel: "info", IntervalStr: "0s", + Attest: "mutual", Method: "GET", } diff --git a/testtool/http.go b/testtool/http.go index d15575ed..d19c34df 100644 --- a/testtool/http.go +++ b/testtool/http.go @@ -24,10 +24,12 @@ import ( "io" "net/http" "strings" + "sync" "time" // local modules + ar "github.com/Fraunhofer-AISEC/cmc/attestationreport" ahttp "github.com/Fraunhofer-AISEC/cmc/attestedhttp" atls "github.com/Fraunhofer-AISEC/cmc/attestedtls" "github.com/Fraunhofer-AISEC/cmc/cmc" @@ -101,6 +103,16 @@ func requestInternal(c *config, api atls.CmcApiSelect, cmc *cmc.Cmc) error { Cmc: cmc, Ca: c.ca, CmcPolicies: c.policies, + ResultCb: func(result *ar.VerificationResult) { + // Publish the attestation result asynchronously if publishing address was specified and + // and attestation was performed + if c.Publish != "" && (c.Attest == "mutual" || c.Attest == "server") { + wg := new(sync.WaitGroup) + wg.Add(1) + defer wg.Wait() + go publishResultAsync(c.Publish, result, wg) + } + }, } // Create an attested HTTPS Client @@ -214,6 +226,13 @@ func serveInternal(c *config, api atls.CmcApiSelect, cmc *cmc.Cmc) { Cmc: cmc, Ca: c.ca, CmcPolicies: c.policies, + ResultCb: func(result *ar.VerificationResult) { + if c.Publish != "" && (c.Attest == "mutual" || c.Attest == "client") { + // Publish the attestation result if publishing address was specified + // and result is not empty + go publishResult(c.Publish, result) + } + }, } // Use the golang net/http module functions to configure the server diff --git a/testtool/publish.go b/testtool/publish.go index 65a00b3b..2065c16b 100644 --- a/testtool/publish.go +++ b/testtool/publish.go @@ -38,6 +38,10 @@ func publishResultAsync(addr string, result *ar.VerificationResult, wg *sync.Wai func publishResult(addr string, result *ar.VerificationResult) { + if result == nil { + log.Trace("Will not publish result: not present") + return + } if result.Prover == "" { log.Trace("Will not publish result: prover is empty (this happens if connection could not be established)") return diff --git a/testtool/tls.go b/testtool/tls.go index 76080079..b3c32922 100644 --- a/testtool/tls.go +++ b/testtool/tls.go @@ -35,7 +35,6 @@ import ( // Creates TLS connection between this client and a server and performs a remote // attestation of the server before exchanging few a exemplary messages with it func dialInternalAddr(c *config, api atls.CmcApiSelect, addr string, tlsConf *tls.Config, cmc *cmc.Cmc) error { - verificationResult := new(ar.VerificationResult) conn, err := atls.Dial("tcp", addr, tlsConf, atls.WithCmcAddr(c.CmcAddr), @@ -45,16 +44,17 @@ func dialInternalAddr(c *config, api atls.CmcApiSelect, addr string, tlsConf *tl atls.WithMtls(c.Mtls), atls.WithAttest(c.Attest), atls.WithCmcNetwork(c.Network), - atls.WithResult(verificationResult), + atls.WithResultCb(func(result *ar.VerificationResult) { + // Publish the attestation result asynchronously if publishing address was specified and + // and attestation was performed + if c.Publish != "" && (c.Attest == "mutual" || c.Attest == "server") { + wg := new(sync.WaitGroup) + wg.Add(1) + defer wg.Wait() + go publishResultAsync(c.Publish, result, wg) + } + }), atls.WithCmc(cmc)) - // Publish the attestation result asynchronously if publishing address was specified and - // and attestation was performed - if c.Publish != "" && (c.Attest == "mutual" || c.Attest == "server") { - wg := new(sync.WaitGroup) - wg.Add(1) - defer wg.Wait() - go publishResultAsync(c.Publish, verificationResult, wg) - } if err != nil { return fmt.Errorf("failed to dial server: %v", err) } @@ -181,12 +181,8 @@ func listenInternal(c *config, api atls.CmcApiSelect, cmc *cmc.Cmc) { Renegotiation: tls.RenegotiateNever, } - atls.WithAttest(c.Attest) - internal.PrintTlsConfig(tlsConf, c.ca) - verificationResult := new(ar.VerificationResult) - addr := "" if len(c.Addr) > 0 { addr = c.Addr[0] @@ -201,7 +197,13 @@ func listenInternal(c *config, api atls.CmcApiSelect, cmc *cmc.Cmc) { atls.WithMtls(c.Mtls), atls.WithAttest(c.Attest), atls.WithCmcNetwork(c.Network), - atls.WithResult(verificationResult), + atls.WithResultCb(func(result *ar.VerificationResult) { + if c.Publish != "" && (c.Attest == "mutual" || c.Attest == "client") { + // Publish the attestation result if publishing address was specified + // and result is not empty + go publishResult(c.Publish, result) + } + }), atls.WithCmc(cmc)) if err != nil { log.Fatalf("Failed to listen for connections: %v", err) @@ -213,23 +215,12 @@ func listenInternal(c *config, api atls.CmcApiSelect, cmc *cmc.Cmc) { // Accept connection and perform remote attestation conn, err := ln.Accept() if err != nil { - log.Errorf("Failed to establish connection: %v", err) - if c.Mtls { - // Publish the attestation result if publishing address was specified - // and result is not empty - go publishResult(c.Publish, verificationResult) - } + log.Warnf("Failed to establish connection: %v", err) continue } // Handle established connections go handleConnection(conn) - - if c.Publish != "" && (c.Attest == "mutual" || c.Attest == "client") { - // Publish the attestation result if publishing address was specified - // and result is not empty - go publishResult(c.Publish, verificationResult) - } } }