diff --git a/coordinator/core/marbleapi_test.go b/coordinator/core/marbleapi_test.go index 46c6907bd..88607ec3e 100644 --- a/coordinator/core/marbleapi_test.go +++ b/coordinator/core/marbleapi_test.go @@ -424,6 +424,10 @@ func TestParseSecrets(t *testing.T) { _, err = parseSecrets("{{ hex .Secrets.emptysecret }}", manifest.ManifestFileTemplateFuncMap, testWrappedSecrets) assert.Error(err) + // Test if we can encode as jks + parsedSecret, err = parseSecrets("{{ jks \"password\" .Secrets.testcertificate }}", manifest.ManifestFileTemplateFuncMap, testWrappedSecrets) + require.NoError(err) + testWrappedSecrets.Secrets = map[string]manifest.Secret{ "plainSecret": {Type: "plain", Public: []byte{1, 2, 3}}, "nullSecret": {Type: "plain", Public: []byte{0, 1, 2}}, @@ -441,6 +445,10 @@ func TestParseSecrets(t *testing.T) { // non plain secrets always result in an error _, err = parseSecrets("{{ string .Secrets.otherSecret }}", manifest.ManifestEnvTemplateFuncMap, testWrappedSecrets) assert.Error(err) + + // jks must fail encoding a symmetric key + _, err = parseSecrets("{{ jks \"password\" .Secrets.otherSecret }}", manifest.ManifestEnvTemplateFuncMap, testWrappedSecrets) + assert.Error(err) } func TestSecurityLevelUpdate(t *testing.T) { diff --git a/coordinator/manifest/manifest.go b/coordinator/manifest/manifest.go index 18644f9f6..355b35d5e 100644 --- a/coordinator/manifest/manifest.go +++ b/coordinator/manifest/manifest.go @@ -7,6 +7,7 @@ package manifest import ( + "bytes" "context" "crypto/x509" "encoding/base64" @@ -15,8 +16,10 @@ import ( "encoding/pem" "errors" "fmt" + "github.com/pavlo-v-chernykh/keystore-go/v4" "strings" "text/template" + "time" "github.com/edgelesssys/marblerun/coordinator/quote" "github.com/edgelesssys/marblerun/coordinator/user" @@ -477,12 +480,64 @@ func EncodeSecretDataToString(data interface{}) (string, error) { } } +// EncodeSecretsToJavaKeyStore encodes secrets as java keystore +func EncodeSecretsToJavaKeyStore(password string, secrets...Secret) (string, error) { + ks := keystore.New() + + for i, secret := range secrets { + if secret.Type != "cert-rsa" && secret.Type != "cert-ed25519" && secret.Type != "cert-ecdsa" { + return "", errors.New("only RSA, ED25519 and ECDSA certificates can be encoded as Java keystore") + } + + if len(secret.Cert.Raw) == 0 { + return "", errors.New("certificate is empty") + } + + var alias = fmt.Sprintf("a%d", i) + + err := ks.SetTrustedCertificateEntry(alias, keystore.TrustedCertificateEntry{ + Certificate: keystore.Certificate{ + Type: "X509", + Content: secret.Cert.Raw, + }, + }) + if err != nil { + return "", err + } + + if secret.Private != nil { + pkeIn := keystore.PrivateKeyEntry{ + CreationTime: time.Now(), + PrivateKey: secret.Private, + CertificateChain: []keystore.Certificate{ + { + Type: "X509", + Content: secret.Cert.Raw, + }, + }, + } + + if err := ks.SetPrivateKeyEntry(alias, pkeIn, []byte(password)); err != nil { + return "", err + } + } + } + + var f bytes.Buffer + err := ks.Store(&f, []byte(password)) + if err != nil { + return "", err + } + return f.String(), nil +} + // ManifestTemplateFuncMap defines the functions which can be specified for secret injections into files in the in Go template format. var ManifestFileTemplateFuncMap = template.FuncMap{ "pem": EncodeSecretDataToPem, "hex": EncodeSecretDataToHex, "raw": EncodeSecretDataToRaw, "base64": EncodeSecretDataToBase64, + "jks": EncodeSecretsToJavaKeyStore, } // ManifestEnvTemplateFuncMap defines the functions which can be specified for secret injections into Env variables in the Go template format. diff --git a/go.mod b/go.mod index d24e2dd4f..92fbe0928 100644 --- a/go.mod +++ b/go.mod @@ -109,6 +109,7 @@ require ( github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect + github.com/pavlo-v-chernykh/keystore-go/v4 v4.4.0 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/go.sum b/go.sum index fac2ed4ca..1ff4622a7 100644 --- a/go.sum +++ b/go.sum @@ -921,6 +921,8 @@ github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xA github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/pavlo-v-chernykh/keystore-go/v4 v4.4.0 h1:y9azNmMzvkNBPyczpNRwaV4bm0U6e7Oyrj7gi2/SNFI= +github.com/pavlo-v-chernykh/keystore-go/v4 v4.4.0/go.mod h1:lAVhWwbNaveeJmxrxuSTxMgKpF6DjnuVpn6T8WiBwYQ= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=