Skip to content

Commit

Permalink
Derive marble private secrets using marble type in addition to UUID (#…
Browse files Browse the repository at this point in the history
…730)

Signed-off-by: Daniel Weiße <[email protected]>
  • Loading branch information
daniel-weisse authored Sep 20, 2024
1 parent a8d6d6a commit 961b68b
Show file tree
Hide file tree
Showing 10 changed files with 188 additions and 54 deletions.
8 changes: 4 additions & 4 deletions coordinator/clientapi/clientapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ type core interface {
}) error
GetState(context.Context) (state.State, string, error)
GenerateSecrets(
map[string]manifest.Secret, uuid.UUID, *x509.Certificate, *ecdsa.PrivateKey, *ecdsa.PrivateKey,
map[string]manifest.Secret, uuid.UUID, string, *x509.Certificate, *ecdsa.PrivateKey, *ecdsa.PrivateKey,
) (map[string]manifest.Secret, error)
GetQuote(reportData []byte) ([]byte, error)
GenerateQuote([]byte) error
Expand Down Expand Up @@ -387,13 +387,13 @@ func (a *ClientAPI) SetManifest(ctx context.Context, rawManifest []byte) (recove
}

// Generate shared secrets specified in manifest
secrets, err := a.core.GenerateSecrets(mnf.Secrets, uuid.Nil, marbleRootCert, intermediatePrivK, rootPrivK)
secrets, err := a.core.GenerateSecrets(mnf.Secrets, uuid.Nil, "", marbleRootCert, intermediatePrivK, rootPrivK)
if err != nil {
a.log.Error("Could not generate specified secrets for the given manifest.", zap.Error(err))
return nil, fmt.Errorf("generating secrets from manifest: %w", err)
}
// generate placeholders for private secrets specified in manifest
privSecrets, err := a.core.GenerateSecrets(mnf.Secrets, uuid.New(), marbleRootCert, intermediatePrivK, rootPrivK)
privSecrets, err := a.core.GenerateSecrets(mnf.Secrets, uuid.New(), "", marbleRootCert, intermediatePrivK, rootPrivK)
if err != nil {
a.log.Error("Could not generate specified secrets for the given manifest.", zap.Error(err))
return nil, fmt.Errorf("generating placeholder secrets from manifest: %w", err)
Expand Down Expand Up @@ -604,7 +604,7 @@ func (a *ClientAPI) UpdateManifest(ctx context.Context, rawUpdateManifest []byte
}

// Regenerate shared secrets specified in manifest
regeneratedSecrets, err := a.core.GenerateSecrets(secretsToRegenerate, uuid.Nil, marbleRootCert, intermediatePrivK, rootPrivK)
regeneratedSecrets, err := a.core.GenerateSecrets(secretsToRegenerate, uuid.Nil, "", marbleRootCert, intermediatePrivK, rootPrivK)
if err != nil {
a.log.Error("Could not generate specified secrets for the given manifest.", zap.Error(err))
return fmt.Errorf("regenerating shared secrets for updated manifest: %w", err)
Expand Down
2 changes: 1 addition & 1 deletion coordinator/clientapi/clientapi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -924,7 +924,7 @@ func (c *fakeCore) GetState(_ context.Context) (state.State, string, error) {
}

func (c *fakeCore) GenerateSecrets(
newSecrets map[string]manifest.Secret, _ uuid.UUID, rootCert *x509.Certificate, privK *ecdsa.PrivateKey, _ *ecdsa.PrivateKey,
newSecrets map[string]manifest.Secret, _ uuid.UUID, _ string, rootCert *x509.Certificate, privK *ecdsa.PrivateKey, _ *ecdsa.PrivateKey,
) (map[string]manifest.Secret, error) {
if c.generateSecretsErr != nil || c.generatedSecrets != nil {
return c.generatedSecrets, c.generateSecretsErr
Expand Down
6 changes: 4 additions & 2 deletions coordinator/core/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ func (c *Core) GetState(ctx context.Context) (state.State, string, error) {

// GenerateSecrets generates secrets for the given manifest and parent certificate.
func (c *Core) GenerateSecrets(
secrets map[string]manifest.Secret, id uuid.UUID,
secrets map[string]manifest.Secret, id uuid.UUID, marbleName string,
parentCertificate *x509.Certificate, parentPrivKey *ecdsa.PrivateKey, rootPrivK *ecdsa.PrivateKey,
) (map[string]manifest.Secret, error) {
// Create a new map so we do not overwrite the entries in the manifest
Expand Down Expand Up @@ -395,7 +395,9 @@ func (c *Core) GenerateSecrets(
salt := id.String() + name
secretKeyDerive := rootPrivK.D.Bytes()
var err error
generatedValue, err = util.DeriveKey(secretKeyDerive, []byte(salt), secret.Size/8)

// Derive key using the uuid and secret name as salt, and the marble's name as info
generatedValue, err = util.DeriveKey(secretKeyDerive, []byte(salt), []byte(marbleName), secret.Size/8)
if err != nil {
return nil, err
}
Expand Down
16 changes: 8 additions & 8 deletions coordinator/core/core_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ func TestGenerateSecrets(t *testing.T) {
rootPrivK := testutil.GetPrivateKey(t, c.txHandle, constants.SKCoordinatorRootKey)

// This should return valid secrets
generatedSecrets, err := c.GenerateSecrets(secretsToGenerate, uuid.Nil, rootCert, rootPrivK, rootPrivK)
generatedSecrets, err := c.GenerateSecrets(secretsToGenerate, uuid.Nil, "", rootCert, rootPrivK, rootPrivK)
require.NoError(err)
// Check if rawTest1 has 128 Bits/16 Bytes and rawTest2 256 Bits/8 Bytes
assert.Len(generatedSecrets["rawTest1"].Public, 16)
Expand All @@ -222,7 +222,7 @@ func TestGenerateSecrets(t *testing.T) {

// Make sure a certificate gets a new serial number if its regenerated
firstSerial := generatedSecrets["cert-rsa-test"].Cert.SerialNumber
secondGeneration, err := c.GenerateSecrets(generatedSecrets, uuid.Nil, rootCert, rootPrivK, rootPrivK)
secondGeneration, err := c.GenerateSecrets(generatedSecrets, uuid.Nil, "", rootCert, rootPrivK, rootPrivK)
assert.NoError(err)
assert.NotEqualValues(*firstSerial, *secondGeneration["cert-rsa-test"].Cert.SerialNumber)

Expand Down Expand Up @@ -264,31 +264,31 @@ func TestGenerateSecrets(t *testing.T) {
assert.NoError(err)

// Check if we get an empty secret map as output for an empty map as input
generatedSecrets, err = c.GenerateSecrets(secretsEmptyMap, uuid.Nil, rootCert, rootPrivK, rootPrivK)
generatedSecrets, err = c.GenerateSecrets(secretsEmptyMap, uuid.Nil, "", rootCert, rootPrivK, rootPrivK)
require.NoError(err)
assert.IsType(map[string]manifest.Secret{}, generatedSecrets)
assert.Len(generatedSecrets, 0)

// Check if we get an empty secret map as output for nil
generatedSecrets, err = c.GenerateSecrets(nil, uuid.Nil, rootCert, rootPrivK, rootPrivK)
generatedSecrets, err = c.GenerateSecrets(nil, uuid.Nil, "", rootCert, rootPrivK, rootPrivK)
require.NoError(err)
assert.IsType(map[string]manifest.Secret{}, generatedSecrets)
assert.Len(generatedSecrets, 0)

// If no size is specified, the function should fail
_, err = c.GenerateSecrets(secretsNoSize, uuid.Nil, rootCert, rootPrivK, rootPrivK)
_, err = c.GenerateSecrets(secretsNoSize, uuid.Nil, "", rootCert, rootPrivK, rootPrivK)
assert.Error(err)

// Also, it should fail if we try to generate a secret with an unknown type
_, err = c.GenerateSecrets(secretsInvalidType, uuid.Nil, rootCert, rootPrivK, rootPrivK)
_, err = c.GenerateSecrets(secretsInvalidType, uuid.Nil, "", rootCert, rootPrivK, rootPrivK)
assert.Error(err)

// If Ed25519 key size is specified, we should fail
_, err = c.GenerateSecrets(secretsEd25519WrongKeySize, uuid.Nil, rootCert, rootPrivK, rootPrivK)
_, err = c.GenerateSecrets(secretsEd25519WrongKeySize, uuid.Nil, "", rootCert, rootPrivK, rootPrivK)
assert.Error(err)

// However, for ECDSA we fail as we can have multiple curves
_, err = c.GenerateSecrets(secretsECDSAWrongKeySize, uuid.Nil, rootCert, rootPrivK, rootPrivK)
_, err = c.GenerateSecrets(secretsECDSAWrongKeySize, uuid.Nil, "", rootCert, rootPrivK, rootPrivK)
assert.Error(err)
}

Expand Down
36 changes: 21 additions & 15 deletions coordinator/core/marbleapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ func (c *Core) Activate(ctx context.Context, req *rpc.ActivationReq) (res *rpc.A
}
defer rollback()

if err := c.verifyManifestRequirement(txdata, tlsCert, req.GetQuote(), req.GetMarbleType()); err != nil {
marbleName, err := c.verifyManifestRequirement(txdata, tlsCert, req.GetQuote(), req.GetMarbleType())
if err != nil {
c.log.Error("Marble verification failed", zap.Error(err))
return nil, status.Errorf(codes.PermissionDenied, "marble verification failed: %s", err)
}
Expand Down Expand Up @@ -127,7 +128,7 @@ func (c *Core) Activate(ctx context.Context, req *rpc.ActivationReq) (res *rpc.A
}

// Generate unique (= per marble) secrets
privateSecrets, err := c.GenerateSecrets(secrets, marbleUUID, marbleRootCert, intermediatePrivK, rootPrivK)
privateSecrets, err := c.GenerateSecrets(secrets, marbleUUID, marbleName, marbleRootCert, intermediatePrivK, rootPrivK)
if err != nil {
c.log.Error("Couldn't generate specified secrets for the given manifest", zap.Error(err))
return nil, status.Errorf(codes.Internal, "generating secrets for marble: %s", err)
Expand Down Expand Up @@ -184,64 +185,69 @@ func (c *Core) Activate(ctx context.Context, req *rpc.ActivationReq) (res *rpc.A
}

// verifyManifestRequirement verifies marble attempting to register with respect to manifest.
func (c *Core) verifyManifestRequirement(txdata storeGetter, tlsCert *x509.Certificate, certQuote []byte, marbleType string) error {
func (c *Core) verifyManifestRequirement(txdata storeGetter, tlsCert *x509.Certificate, certQuote []byte, marbleType string) (string, error) {
marble, err := txdata.GetMarble(marbleType)
if err != nil {
if errors.Is(err, store.ErrValueUnset) {
return fmt.Errorf("unknown marble type requested")
return "", fmt.Errorf("unknown marble type requested")
}
return fmt.Errorf("loading marble data: %w", err)
return "", fmt.Errorf("loading marble data: %w", err)
}

pkg, err := txdata.GetPackage(marble.Package)
if err != nil {
if errors.Is(err, store.ErrValueUnset) {
return fmt.Errorf("undefined package %q", marble.Package)
return "", fmt.Errorf("undefined package %q", marble.Package)
}
return fmt.Errorf("loading package data: %w", err)
return "", fmt.Errorf("loading package data: %w", err)
}

infraIter, err := txdata.GetIterator(request.Infrastructure)
if err != nil {
return fmt.Errorf("getting infrastructure iterator: %w", err)
return "", fmt.Errorf("getting infrastructure iterator: %w", err)
}

if !c.inSimulationMode() {
if !infraIter.HasNext() {
if err := c.qv.Validate(certQuote, tlsCert.Raw, pkg, quote.InfrastructureProperties{}); err != nil {
return fmt.Errorf("invalid quote: %w", err)
return "", fmt.Errorf("invalid quote: %w", err)
}
} else {
infraMatch := false
for infraIter.HasNext() {
infraName, err := infraIter.GetNext()
if err != nil {
return err
return "", err
}
infra, err := txdata.GetInfrastructure(infraName)
if err != nil {
return fmt.Errorf("loading infrastructure: %w", err)
return "", fmt.Errorf("loading infrastructure: %w", err)
}
if c.qv.Validate(certQuote, tlsCert.Raw, pkg, infra) == nil {
infraMatch = true
break
}
}
if !infraMatch {
return fmt.Errorf("invalid infrastructure")
return "", fmt.Errorf("invalid infrastructure")
}
}
}

// check activation budget (MaxActivations == 0 means infinite budget)
activations, err := txdata.GetActivations(marbleType)
if err != nil {
return fmt.Errorf("could not retrieve activations for marble type %q: %w", marbleType, err)
return "", fmt.Errorf("could not retrieve activations for marble type %q: %w", marbleType, err)
}
if marble.MaxActivations > 0 && activations >= marble.MaxActivations {
return fmt.Errorf("reached max activations count (%d) for marble type %q", marble.MaxActivations, marbleType)
return "", fmt.Errorf("reached max activations count (%d) for marble type %q", marble.MaxActivations, marbleType)
}
return nil

marbleName := marbleType
if marble.DisableSecretBinding {
marbleName = ""
}
return marbleName, nil
}

// generateCertFromCSR signs the CSR from marble attempting to register.
Expand Down
Loading

0 comments on commit 961b68b

Please sign in to comment.