diff --git a/bindings/jsons.go b/bindings/jsons.go index 5405baf8bd9f74c63d236e913043be576479adf8..53f15435c6e8750a5d08e18c18d23b81c4304f5d 100644 --- a/bindings/jsons.go +++ b/bindings/jsons.go @@ -12,7 +12,8 @@ import ( "net/http" ) -// Returns a []byte containing the JSON data describing client errors. +// DownloadErrorDB returns a []byte containing the JSON data +// describing client errors. // See https://git.xx.network/elixxir/client-error-database/ func DownloadErrorDB() ([]byte, error) { // Build a request for the file @@ -32,7 +33,8 @@ func DownloadErrorDB() ([]byte, error) { return content, nil } -// Returns a []byte containing the JSON data describing registered dApps. +// DownloadDAppRegistrationDB returns a []byte containing +// the JSON data describing registered dApps. // See https://git.xx.network/elixxir/registered-dapps func DownloadDAppRegistrationDB() ([]byte, error) { // Build a request for the file diff --git a/bindings/ndf.go b/bindings/ndf.go new file mode 100644 index 0000000000000000000000000000000000000000..5d0795b7312e8b2632b8070de8b9c0351cc90f8c --- /dev/null +++ b/bindings/ndf.go @@ -0,0 +1,117 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright © 2021 xx network SEZC // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file // +/////////////////////////////////////////////////////////////////////////////// + +package bindings + +import ( + "encoding/base64" + "github.com/pkg/errors" + pb "gitlab.com/elixxir/comms/mixmessages" + "gitlab.com/xx_network/comms/signature" + "gitlab.com/xx_network/crypto/tls" + "google.golang.org/protobuf/proto" + "io/ioutil" + "net/http" +) + +// todo: populate with actual URL +// ndfUrl is a hardcoded url to a bucket containing the signed NDF message. +const ndfUrl = `elixxir.io` + + +// DownloadSignedNdf retrieves the NDF from a hardcoded bucket URL. +// The NDF returned requires further processing and verification +// before being used. Use VerifySignedNdf to properly process +// the downloaded data returned. +// DO NOT USE THE RETURNED DATA TO START A CLIENT. +func DownloadSignedNdf() ([]byte, error) { + // Build a request for the file + resp, err := http.Get(ndfUrl) + if err != nil { + return nil, errors.WithMessagef(err, "Failed to retrieve " + + "NDF from %s", ndfUrl) + } + defer resp.Body.Close() + + // Download contents of the file + signedNdfEncoded, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, errors.WithMessage(err, "Failed to read signed " + + "NDF response request") + } + + return signedNdfEncoded, nil +} + +// DownloadSignedNdfWithUrl retrieves the NDF from a specified URL. +// The NDF returned requires further processing and verification +// before being used. Use VerifySignedNdf to properly process +// the downloaded data returned. +// DO NOT USE THE RETURNED DATA TO START A CLIENT. +func DownloadSignedNdfWithUrl(url, cert string) ([]byte, error) { + // Build a reqeust for the file + resp, err := http.Get(url) + if err != nil { + return nil, errors.WithMessagef(err, "Failed to retrieve " + + "NDF from %s", url) + } + defer resp.Body.Close() + + // Download contents of the file + signedNdfEncoded, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, errors.WithMessage(err, "Failed to read signed " + + "NDF response request") + } + + return signedNdfEncoded, nil +} + +// VerifySignedNdf takes the downloaded NDF from either +// DownloadSignedNdf or DownloadSignedNdfWithUrl (signedNdfEncoded) +// an the scheduling certificate (cert). The downloaded NDF is parsed +// into a protobuf containing a signature. The signature is verified using the +// passed in cert. Upon successful parsing and verification, the NDF is +// returned. This may be used to start a client. +func VerifySignedNdf(signedNdfEncoded []byte, cert string) ([]byte, error) { + // Base64 decode the signed NDF + signedNdfMarshaled, err := base64.StdEncoding.DecodeString( + string(signedNdfEncoded)) + if err != nil { + return nil, errors.WithMessage(err, "Failed to decode signed NDF") + } + + // Unmarshal the signed NDF + signedNdfMsg := &pb.NDF{} + err = proto.Unmarshal(signedNdfMarshaled, signedNdfMsg) + if err != nil { + return nil, errors.WithMessage(err, "Failed to unmarshal " + + "signed NDF into protobuf") + } + + + // Load the certificate from it's PEM contents + schedulingCert, err := tls.LoadCertificate(cert) + if err != nil { + return nil, errors.WithMessagef(err, "Failed to parse scheduling cert (%s)", cert) + } + + // Extract the public key from the cert + schedulingPubKey, err := tls.ExtractPublicKey(schedulingCert) + if err != nil { + return nil, errors.WithMessage(err, "Failed to extract public key from cert") + } + + // Verify signed NDF message + err = signature.VerifyRsa(signedNdfMsg, schedulingPubKey) + if err != nil { + return nil, errors.WithMessage(err, "Failed to verify signed NDF message") + } + + return signedNdfMsg.Ndf, nil +} + diff --git a/bindings/ndf_test.go b/bindings/ndf_test.go new file mode 100644 index 0000000000000000000000000000000000000000..b77b41b44499adda3a996ec9bef9e13004d8e853 --- /dev/null +++ b/bindings/ndf_test.go @@ -0,0 +1,38 @@ +/////////////////////////////////////////////////////////////////////////////// +// Copyright © 2021 xx network SEZC // +// // +// Use of this source code is governed by a license that can be found in the // +// LICENSE file // +/////////////////////////////////////////////////////////////////////////////// + +package bindings + +import "testing" + +func TestDownloadSignedNdf(t *testing.T) { + // Todo: test once a proper URL is hardcoded + //content, err := DownloadSignedNdf() + //if err != nil { + // t.Errorf("Failed to download signed NDF: %v") + //} + //fmt.Printf("content: %s\n", string(content)) + +} + +func TestDownloadSignedNdfWithUrl(t *testing.T) { + // todo: write test once a proper URL can be passed in + //content, err := DownloadSignedNdfWithUrl(exampleURL) + //if err != nil { + // t.Errorf("Failed to download signed NDF: %v") + //} + //fmt.Printf("content: %s\n", string(content)) +} + +// Tests +func TestVerifySignedNdf(t *testing.T) { + // todo write test once example data is collected + //ndf, err := VerifySignedNdf(testSignedNdf, testCert) + //if err != nil { + // + //} +}