mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-10-03 14:18:54 -04:00
azure: allow a set of idkeydigest values (#991)
This commit is contained in:
parent
a3db3c8424
commit
632090c21b
26 changed files with 360 additions and 197 deletions
|
@ -9,6 +9,8 @@ package snp
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
|
||||
)
|
||||
|
||||
type signatureError struct {
|
||||
|
@ -48,7 +50,8 @@ func (e *vcekError) Error() string {
|
|||
}
|
||||
|
||||
type idKeyError struct {
|
||||
expectedValue []byte
|
||||
encounteredValue []byte
|
||||
expectedValues idkeydigest.IDKeyDigests
|
||||
}
|
||||
|
||||
func (e *idKeyError) Unwrap() error {
|
||||
|
@ -56,7 +59,7 @@ func (e *idKeyError) Unwrap() error {
|
|||
}
|
||||
|
||||
func (e *idKeyError) Error() string {
|
||||
return fmt.Sprintf("configured idkeydigest does not match reported idkeydigest: %x", e.expectedValue)
|
||||
return fmt.Sprintf("configured idkeydigests %x doesn't contain reported idkeydigest %x", e.expectedValues, e.encounteredValue)
|
||||
}
|
||||
|
||||
type versionError struct {
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
internalCrypto "github.com/edgelesssys/constellation/v2/internal/crypto"
|
||||
|
@ -42,11 +43,11 @@ type Validator struct {
|
|||
}
|
||||
|
||||
// NewValidator initializes a new Azure validator with the provided PCR values.
|
||||
func NewValidator(pcrs measurements.M, idKeyDigest []byte, enforceIDKeyDigest bool, log vtpm.AttestationLogger) *Validator {
|
||||
func NewValidator(pcrs measurements.M, idKeyDigests idkeydigest.IDKeyDigests, enforceIDKeyDigest bool, log vtpm.AttestationLogger) *Validator {
|
||||
return &Validator{
|
||||
Validator: vtpm.NewValidator(
|
||||
pcrs,
|
||||
getTrustedKey(&azureInstanceInfo{}, idKeyDigest, enforceIDKeyDigest, log),
|
||||
getTrustedKey(&azureInstanceInfo{}, idKeyDigests, enforceIDKeyDigest, log),
|
||||
validateCVM,
|
||||
vtpm.VerifyPKCS1v15,
|
||||
log,
|
||||
|
@ -77,7 +78,7 @@ func reverseEndian(b []byte) {
|
|||
// getTrustedKey establishes trust in the given public key.
|
||||
// It does so by verifying the SNP attestation statement in instanceInfo.
|
||||
func getTrustedKey(
|
||||
hclAk HCLAkValidator, idKeyDigest []byte, enforceIDKeyDigest bool, log vtpm.AttestationLogger,
|
||||
hclAk HCLAkValidator, idKeyDigest idkeydigest.IDKeyDigests, enforceIDKeyDigest bool, log vtpm.AttestationLogger,
|
||||
) func(akPub, instanceInfoRaw []byte) (crypto.PublicKey, error) {
|
||||
return func(akPub, instanceInfoRaw []byte) (crypto.PublicKey, error) {
|
||||
var instanceInfo azureInstanceInfo
|
||||
|
@ -95,7 +96,7 @@ func getTrustedKey(
|
|||
return nil, fmt.Errorf("validating VCEK: %w", err)
|
||||
}
|
||||
|
||||
if err = validateSNPReport(vcek, idKeyDigest, enforceIDKeyDigest, report, log); err != nil {
|
||||
if err := validateSNPReport(vcek, idKeyDigest, enforceIDKeyDigest, report, log); err != nil {
|
||||
return nil, fmt.Errorf("validating SNP report: %w", err)
|
||||
}
|
||||
|
||||
|
@ -143,7 +144,7 @@ func validateVCEK(vcekRaw []byte, certChain []byte) (*x509.Certificate, error) {
|
|||
}
|
||||
|
||||
func validateSNPReport(
|
||||
cert *x509.Certificate, expectedIDKeyDigest []byte, enforceIDKeyDigest bool,
|
||||
cert *x509.Certificate, expectedIDKeyDigests idkeydigest.IDKeyDigests, enforceIDKeyDigest bool,
|
||||
report snpAttestationReport, log vtpm.AttestationLogger,
|
||||
) error {
|
||||
if report.Policy.Debug() {
|
||||
|
@ -189,12 +190,20 @@ func validateSNPReport(
|
|||
return &signatureError{err}
|
||||
}
|
||||
|
||||
if !bytes.Equal(expectedIDKeyDigest, report.IDKeyDigest[:]) {
|
||||
hasExpectedIDKeyDigest := false
|
||||
for _, digest := range expectedIDKeyDigests {
|
||||
if bytes.Equal(digest, report.IDKeyDigest[:]) {
|
||||
hasExpectedIDKeyDigest = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !hasExpectedIDKeyDigest {
|
||||
if enforceIDKeyDigest {
|
||||
return &idKeyError{report.IDKeyDigest[:]}
|
||||
return &idKeyError{report.IDKeyDigest[:], expectedIDKeyDigests}
|
||||
}
|
||||
if log != nil {
|
||||
log.Warnf("Encountered different than configured IDKeyDigest value: %x", report.IDKeyDigest[:])
|
||||
log.Warnf("configured idkeydigests %x doesn't contain reported idkeydigest %x", expectedIDKeyDigests, report.IDKeyDigest[:])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import (
|
|||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/simulator"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
|
||||
"github.com/google/go-tpm-tools/client"
|
||||
|
@ -41,14 +42,16 @@ func TestTrustedKeyFromSNP(t *testing.T) {
|
|||
defaultRuntimeData := "7b226b657973223a5b7b226b6964223a2248434c416b507562222c226b65795f6f7073223a5b22656e6372797074225d2c226b7479223a22525341222c2265223a2241514142222c226e223a22747946717641414166324746656c6b5737566352684a6e4132597659364c6a427a65554e3276614d5a6e5a74685f74466e574d6b4b35415874757379434e656c337569703356475a7a54617a3558327447566a4772732d4d56486361703951647771555856573367394f515f74456269786378372d78626c554a516b474551666e626253646e5049326c764c7a4f73315a5f30766a65444178765351726d616773366e592d634a4157482d706744564a79487470735553735f5142576b6c617a44736f3557486d6e4d743973394d75696c57586f7830525379586e55656151796859316a753752545363526e5658754e7936377a5f454a6e774d393264727746623841556430534a5f396f687645596c34615a52444543476f3056726a635348552d4a474a6575574335566844425235454f6f4356424267716539653833765f6c4a784933574c65326f7653495a49497a416d625351227d5d2c22766d2d636f6e66696775726174696f6e223a7b22636f6e736f6c652d656e61626c6564223a747275652c2263757272656e742d74696d65223a313636313435353339312c227365637572652d626f6f74223a66616c73652c2274706d2d656e61626c6564223a747275652c22766d556e697175654964223a2242364339384333422d344543372d344441362d424432462d374439384432304437423735227d7d"
|
||||
defaultVCEK := "-----BEGIN CERTIFICATE-----\nMIIFTDCCAvugAwIBAgIBADBGBgkqhkiG9w0BAQowOaAPMA0GCWCGSAFlAwQCAgUA\noRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAgUAogMCATCjAwIBATB7MRQwEgYD\nVQQLDAtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxFDASBgNVBAcMC1NhbnRhIENs\nYXJhMQswCQYDVQQIDAJDQTEfMB0GA1UECgwWQWR2YW5jZWQgTWljcm8gRGV2aWNl\nczESMBAGA1UEAwwJU0VWLU1pbGFuMB4XDTIyMDYyOTE2MzEzMFoXDTI5MDYyOTE2\nMzEzMFowejEUMBIGA1UECwwLRW5naW5lZXJpbmcxCzAJBgNVBAYTAlVTMRQwEgYD\nVQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExHzAdBgNVBAoMFkFkdmFuY2Vk\nIE1pY3JvIERldmljZXMxETAPBgNVBAMMCFNFVi1WQ0VLMHYwEAYHKoZIzj0CAQYF\nK4EEACIDYgAEhPX8Cl9uA7PxqNGzeqamJNYJLx/VFE/s3+8qOWtaztKNcn1PaAI4\nndE+yaVfMHsiA8CLTylumpWXcVBHPYV9kPEVrtozhvrrT5Oii9OpZPYHJ7/WPVmM\nJ3K8/Iz3AshTo4IBFjCCARIwEAYJKwYBBAGceAEBBAMCAQAwFwYJKwYBBAGceAEC\nBAoWCE1pbGFuLUIwMBEGCisGAQQBnHgBAwEEAwIBAjARBgorBgEEAZx4AQMCBAMC\nAQAwEQYKKwYBBAGceAEDBAQDAgEAMBEGCisGAQQBnHgBAwUEAwIBADARBgorBgEE\nAZx4AQMGBAMCAQAwEQYKKwYBBAGceAEDBwQDAgEAMBEGCisGAQQBnHgBAwMEAwIB\nBjARBgorBgEEAZx4AQMIBAMCAV0wTQYJKwYBBAGceAEEBECeRKrvAs/Kb926ymac\nbP0p4auNl+vJOYVxKKy7E7h0DfMUNtNOhuX4rgzf6zoOGF20beysF2zHfXYcIqG5\n3PJbMEYGCSqGSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG9w0B\nAQgwDQYJYIZIAWUDBAICBQCiAwIBMKMDAgEBA4ICAQBXXzX8w+z06JNKLVAa9vyE\njC69c7uvfTPScqLzOCV+S8yZ7Ibpn6gdRcgn5s3F7uerVs9/8mq+rDpMzLTVxLei\nYAW9jDS9VdEgfUp3GzzL1g3zsWNZPpWuAu0Cw1V7KnQ9kiGsJMRKerx8QLrm+aAH\nOiob4XHl2naUx9aILzCLbNgLBdh6Tw2XkGj8NB9O7kNQoINEz6U+cAJL5LWzuoYt\nW1IJkYUEMydvLImFHeFIFtB2wI4mTSuCjtb/pBUeRdvDm5dmY/VPvh+CkvCeXNze\nHPZ8vcQ+ZZNS44O9rMnSUOtRFZb3ow3atXsx53Gy9rp41Bd0OZgSMrnHH74lDQX0\nkkNP+UrRYs66q0gJaSZglzkWfHLtAGfuRh9XyBh4kBgHcjF1Qh6frTpotX9t+0V/\nQZv3KjPVMsGaUN407WHEoAl6qX6TSS/An2EdXgqbhXS5O81gzatWDTcT2D3VJG1N\nHYtkh1J5WmrFTphc7OhxmVk7l3UkWPyS8Oi8be2y8Q4x0wgviZn5eOa/djpHoarW\nLS91KKPZXGyXlj49TlCjbl4RfyKYOd/HqgAYYdtqBe84AyJQRvuD5gWmdBzagncb\nyKjs6tYr74aAGnAqulp+yqvrzb7teUQmCMkROfzFjYZmLByqw6UGRdHgCf8hOzmO\nch4hf9cHRLAUJpqynRmb+g==\n-----END CERTIFICATE-----\n"
|
||||
defaultCertChain := "-----BEGIN CERTIFICATE-----\n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\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIGYzCCBBKgAwIBAgIDAQAAMEYGCSqGSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAIC\nBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWUDBAICBQCiAwIBMKMDAgEBMHsxFDAS\nBgNVBAsMC0VuZ2luZWVyaW5nMQswCQYDVQQGEwJVUzEUMBIGA1UEBwwLU2FudGEg\nQ2xhcmExCzAJBgNVBAgMAkNBMR8wHQYDVQQKDBZBZHZhbmNlZCBNaWNybyBEZXZp\nY2VzMRIwEAYDVQQDDAlBUkstTWlsYW4wHhcNMjAxMDIyMTcyMzA1WhcNNDUxMDIy\nMTcyMzA1WjB7MRQwEgYDVQQLDAtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxFDAS\nBgNVBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTEfMB0GA1UECgwWQWR2YW5j\nZWQgTWljcm8gRGV2aWNlczESMBAGA1UEAwwJQVJLLU1pbGFuMIICIjANBgkqhkiG\n9w0BAQEFAAOCAg8AMIICCgKCAgEA0Ld52RJOdeiJlqK2JdsVmD7FktuotWwX1fNg\nW41XY9Xz1HEhSUmhLz9Cu9DHRlvgJSNxbeYYsnJfvyjx1MfU0V5tkKiU1EesNFta\n1kTA0szNisdYc9isqk7mXT5+KfGRbfc4V/9zRIcE8jlHN61S1ju8X93+6dxDUrG2\nSzxqJ4BhqyYmUDruPXJSX4vUc01P7j98MpqOS95rORdGHeI52Naz5m2B+O+vjsC0\n60d37jY9LFeuOP4Meri8qgfi2S5kKqg/aF6aPtuAZQVR7u3KFYXP59XmJgtcog05\ngmI0T/OitLhuzVvpZcLph0odh/1IPXqx3+MnjD97A7fXpqGd/y8KxX7jksTEzAOg\nbKAeam3lm+3yKIcTYMlsRMXPcjNbIvmsBykD//xSniusuHBkgnlENEWx1UcbQQrs\n+gVDkuVPhsnzIRNgYvM48Y+7LGiJYnrmE8xcrexekBxrva2V9TJQqnN3Q53kt5vi\nQi3+gCfmkwC0F0tirIZbLkXPrPwzZ0M9eNxhIySb2npJfgnqz55I0u33wh4r0ZNQ\neTGfw03MBUtyuzGesGkcw+loqMaq1qR4tjGbPYxCvpCq7+OgpCCoMNit2uLo9M18\nfHz10lOMT8nWAUvRZFzteXCm+7PHdYPlmQwUw3LvenJ/ILXoQPHfbkH0CyPfhl1j\nWhJFZasCAwEAAaN+MHwwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSFrBrRQ/fI\nrFXUxR1BSKvVeErUUzAPBgNVHRMBAf8EBTADAQH/MDoGA1UdHwQzMDEwL6AtoCuG\nKWh0dHBzOi8va2RzaW50Zi5hbWQuY29tL3ZjZWsvdjEvTWlsYW4vY3JsMEYGCSqG\nSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZI\nAWUDBAICBQCiAwIBMKMDAgEBA4ICAQC6m0kDp6zv4Ojfgy+zleehsx6ol0ocgVel\nETobpx+EuCsqVFRPK1jZ1sp/lyd9+0fQ0r66n7kagRk4Ca39g66WGTJMeJdqYriw\nSTjjDCKVPSesWXYPVAyDhmP5n2v+BYipZWhpvqpaiO+EGK5IBP+578QeW/sSokrK\ndHaLAxG2LhZxj9aF73fqC7OAJZ5aPonw4RE299FVarh1Tx2eT3wSgkDgutCTB1Yq\nzT5DuwvAe+co2CIVIzMDamYuSFjPN0BCgojl7V+bTou7dMsqIu/TW/rPCX9/EUcp\nKGKqPQ3P+N9r1hjEFY1plBg93t53OOo49GNI+V1zvXPLI6xIFVsh+mto2RtgEX/e\npmMKTNN6psW88qg7c1hTWtN6MbRuQ0vm+O+/2tKBF2h8THb94OvvHHoFDpbCELlq\nHnIYhxy0YKXGyaW1NjfULxrrmxVW4wcn5E8GddmvNa6yYm8scJagEi13mhGu4Jqh\n3QU3sf8iUSUr09xQDwHtOQUVIqx4maBZPBtSMf+qUDtjXSSq8lfWcd8bLr9mdsUn\nJZJ0+tuPMKmBnSH860llKk+VpVQsgqbzDIvOLvD6W1Umq25boxCYJ+TuBoa4s+HH\nCViAvgT9kf/rBq1d+ivj6skkHxuzcxbk1xv6ZGxrteJxVH7KlX7YRdZ6eARKwLe4\nAFZEAwoKCQ==\n-----END CERTIFICATE-----\n"
|
||||
defaultIDKeyDigest := "57e229e0ffe5fa92d0faddff6cae0e61c926fc9ef9afd20a8b8cfcf7129db9338cbe5bf3f6987733a2bf65d06dc38fc1"
|
||||
defaultIDKeyDigestOld, err := hex.DecodeString("57e229e0ffe5fa92d0faddff6cae0e61c926fc9ef9afd20a8b8cfcf7129db9338cbe5bf3f6987733a2bf65d06dc38fc1")
|
||||
require.NoError(err)
|
||||
defaultIDKeyDigest := idkeydigest.NewIDKeyDigests([][]byte{defaultIDKeyDigestOld})
|
||||
|
||||
testCases := map[string]struct {
|
||||
report string
|
||||
runtimeData string
|
||||
vcek string
|
||||
certChain string
|
||||
idkeydigest string
|
||||
idkeydigest idkeydigest.IDKeyDigests
|
||||
enforceIDKeyDigest bool
|
||||
wantErr bool
|
||||
assertCorrectError func(error)
|
||||
|
@ -118,7 +121,7 @@ func TestTrustedKeyFromSNP(t *testing.T) {
|
|||
runtimeData: defaultRuntimeData,
|
||||
vcek: defaultVCEK,
|
||||
certChain: defaultCertChain,
|
||||
idkeydigest: "67e229e0ffe5fa92d0faddff6cae0e61c926fc9ef9afd20a8b8cfcf7129db9338cbe5bf3f6987733a2bf65d06dc38fc1",
|
||||
idkeydigest: idkeydigest.IDKeyDigests{[]byte{0x00}},
|
||||
enforceIDKeyDigest: true,
|
||||
wantErr: true,
|
||||
assertCorrectError: func(err error) {
|
||||
|
@ -131,7 +134,7 @@ func TestTrustedKeyFromSNP(t *testing.T) {
|
|||
runtimeData: defaultRuntimeData,
|
||||
vcek: defaultVCEK,
|
||||
certChain: defaultCertChain,
|
||||
idkeydigest: "",
|
||||
idkeydigest: idkeydigest.IDKeyDigests{[]byte{0x00}},
|
||||
},
|
||||
"unsupported microcode version": {
|
||||
report: "02000000020000001f0003000000000001000000000000000000000000000000020000000000000000000000000000000000000001000000020000000000065d010000000000000000000000000000000ccc0895ef2f2c3b8c8568f5a2bb65ff5bf9387a09359742ad41e686cacfd38b00000000000000000000000000000000000000000000000000000000000000005677f1de87289e7ad2c7e99c805d0468b1a9ccd83f0d245afa5242d405da4d5725852f8c6550564870e5f3206dfb1841000000000000000000000000000000000000000000000000000000000000000057e229e0ffe5fa92d0faddff6cae0e61c926fc9ef9afd20a8b8cfcf7129db9338cbe5bf3f6987733a2bf65d06dc38fc100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005f7240b24a1babe2ece844c4f792bcd9844bf6907d14aeea00156310b9538daffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff020000000000065d0000000000000000000000000000000000000000000000009e44aaef02cfca6fddbaca669c6cfd29e1ab8d97ebc939857128acbb13b8740df31436d34e86e5f8ae0cdfeb3a0e185db46decac176cc77d761c22a1b9dcf25b020000000000065c0133010001330100020000000000065d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bcb7dc15abff884802e774b39adba8e6ff7efcf05e115c91588e657065151056a320f70c788d0e3619391052922e422b000000000000000000000000000000000000000000000000e8dbf581140443bbc681c50eca8639a76ef6cab34e0780cbca977e2e2a03f8b864fd4e9774b0f8055511567e031e59bf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005c02000001000000020000000100000048020000",
|
||||
|
@ -198,10 +201,7 @@ func TestTrustedKeyFromSNP(t *testing.T) {
|
|||
assert.Error(err)
|
||||
}
|
||||
|
||||
idkeydigest, err := hex.DecodeString(tc.idkeydigest)
|
||||
assert.NoError(err)
|
||||
|
||||
key, err := getTrustedKey(&instanceInfo, idkeydigest, tc.enforceIDKeyDigest, nil)(akPub, statement)
|
||||
key, err := getTrustedKey(&instanceInfo, tc.idkeydigest, tc.enforceIDKeyDigest, nil)(akPub, statement)
|
||||
if tc.wantErr {
|
||||
tc.assertCorrectError(err)
|
||||
} else {
|
||||
|
|
117
internal/attestation/idkeydigest/idkeydigest.go
Normal file
117
internal/attestation/idkeydigest/idkeydigest.go
Normal file
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package idkeydigest
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"go.uber.org/multierr"
|
||||
)
|
||||
|
||||
// IDKeyDigests is a list of trusted digest values for the ID key.
|
||||
type IDKeyDigests [][]byte
|
||||
|
||||
type encodedIDKeyDigests []string
|
||||
|
||||
// encodedDigestLength is the length of a digest in hex encoding.
|
||||
const encodedDigestLength = 2 * 48
|
||||
|
||||
// NewIDKeyDigests creates a new IDKeyDigests from a list of digests.
|
||||
func NewIDKeyDigests(digests [][]byte) IDKeyDigests {
|
||||
idKeyDigests := make(IDKeyDigests, len(digests))
|
||||
copy(idKeyDigests, digests)
|
||||
return idKeyDigests
|
||||
}
|
||||
|
||||
// DefaultsFor returns the default IDKeyDigests for the given cloud provider.
|
||||
func DefaultsFor(csp cloudprovider.Provider) IDKeyDigests {
|
||||
switch csp {
|
||||
case cloudprovider.Azure:
|
||||
return IDKeyDigests{
|
||||
{0x57, 0x48, 0x6a, 0x44, 0x7e, 0xc0, 0xf1, 0x95, 0x80, 0x02, 0xa2, 0x2a, 0x06, 0xb7, 0x67, 0x3b, 0x9f, 0xd2, 0x7d, 0x11, 0xe1, 0xc6, 0x52, 0x74, 0x98, 0x05, 0x60, 0x54, 0xc5, 0xfa, 0x92, 0xd2, 0x3c, 0x50, 0xf9, 0xde, 0x44, 0x07, 0x27, 0x60, 0xfe, 0x2b, 0x6f, 0xb8, 0x97, 0x40, 0xb6, 0x96},
|
||||
{0x03, 0x56, 0x21, 0x58, 0x82, 0xa8, 0x25, 0x27, 0x9a, 0x85, 0xb3, 0x00, 0xb0, 0xb7, 0x42, 0x93, 0x1d, 0x11, 0x3b, 0xf7, 0xe3, 0x2d, 0xde, 0x2e, 0x50, 0xff, 0xde, 0x7e, 0xc7, 0x43, 0xca, 0x49, 0x1e, 0xcd, 0xd7, 0xf3, 0x36, 0xdc, 0x28, 0xa6, 0xe0, 0xb2, 0xbb, 0x57, 0xaf, 0x7a, 0x44, 0xa3},
|
||||
}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// MarshalYAML implements the yaml.Marshaler interface.
|
||||
func (d IDKeyDigests) MarshalYAML() (any, error) {
|
||||
encodedIDKeyDigests := []string{}
|
||||
for _, digest := range d {
|
||||
encodedIDKeyDigests = append(encodedIDKeyDigests, hex.EncodeToString(digest))
|
||||
}
|
||||
return encodedIDKeyDigests, nil
|
||||
}
|
||||
|
||||
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||
func (d *IDKeyDigests) UnmarshalYAML(unmarshal func(any) error) error {
|
||||
var encodedDigests encodedIDKeyDigests
|
||||
if err := unmarshal(&encodedDigests); err != nil {
|
||||
// Unmarshalling failed, IDKeyDigests might be a simple string instead of IDKeyDigests struct.
|
||||
var unmarshalledString string
|
||||
if legacyErr := unmarshal(&unmarshalledString); legacyErr != nil {
|
||||
return multierr.Append(
|
||||
err,
|
||||
fmt.Errorf("trying legacy format: %w", legacyErr),
|
||||
)
|
||||
}
|
||||
encodedDigests = append(encodedDigests, unmarshalledString)
|
||||
}
|
||||
if err := d.unmarshal(encodedDigests); err != nil {
|
||||
return fmt.Errorf("unmarshalling yaml: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalJSON implements the json.Marshaler interface.
|
||||
func (d IDKeyDigests) MarshalJSON() ([]byte, error) {
|
||||
encodedIDKeyDigests := []string{}
|
||||
for _, digest := range d {
|
||||
encodedIDKeyDigests = append(encodedIDKeyDigests, hex.EncodeToString(digest))
|
||||
}
|
||||
return json.Marshal(encodedIDKeyDigests)
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the json.Unmarshaler interface.
|
||||
func (d *IDKeyDigests) UnmarshalJSON(b []byte) error {
|
||||
var encodedDigests encodedIDKeyDigests
|
||||
if err := json.Unmarshal(b, &encodedDigests); err != nil {
|
||||
// Unmarshalling failed, IDKeyDigests might be a simple string instead of IDKeyDigests struct.
|
||||
var unmarshalledString string
|
||||
if legacyErr := json.Unmarshal(b, &unmarshalledString); legacyErr != nil {
|
||||
return multierr.Append(
|
||||
err,
|
||||
fmt.Errorf("trying legacy format: %w", legacyErr),
|
||||
)
|
||||
}
|
||||
encodedDigests = []string{unmarshalledString}
|
||||
}
|
||||
if err := d.unmarshal(encodedDigests); err != nil {
|
||||
return fmt.Errorf("unmarshalling json: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// unmarshal is a helper function for unmarshalling encodedIDKeyDigests into IDKeyDigests.
|
||||
func (d *IDKeyDigests) unmarshal(encodedDigests encodedIDKeyDigests) error {
|
||||
for _, encodedDigest := range encodedDigests {
|
||||
if len(encodedDigest) != encodedDigestLength {
|
||||
return fmt.Errorf("invalid digest length: %d", len(encodedDigest))
|
||||
}
|
||||
digest, err := hex.DecodeString(encodedDigest)
|
||||
if err != nil {
|
||||
return fmt.Errorf("decoding digest: %w", err)
|
||||
}
|
||||
*d = append(*d, digest)
|
||||
}
|
||||
return nil
|
||||
}
|
119
internal/attestation/idkeydigest/idkeydigest_test.go
Normal file
119
internal/attestation/idkeydigest/idkeydigest_test.go
Normal file
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package idkeydigest
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func TestMarshal(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
dgst IDKeyDigests
|
||||
wantYAML string
|
||||
wantJSON string
|
||||
}{
|
||||
"digest": {
|
||||
dgst: IDKeyDigests{{0x01, 0x02, 0x03, 0x04}, {0xff, 0xff, 0xff, 0xff}},
|
||||
wantJSON: `["01020304","ffffffff"]`,
|
||||
wantYAML: `
|
||||
- "01020304"
|
||||
- "ffffffff"`,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
{
|
||||
// YAML
|
||||
yaml, err := yaml.Marshal(tc.dgst)
|
||||
require.NoError(err)
|
||||
|
||||
assert.YAMLEq(tc.wantYAML, string(yaml))
|
||||
}
|
||||
|
||||
{
|
||||
// JSON
|
||||
json, err := json.Marshal(tc.dgst)
|
||||
require.NoError(err)
|
||||
|
||||
assert.JSONEq(tc.wantJSON, string(json))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshal(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
yaml string
|
||||
json string
|
||||
wantDgst IDKeyDigests
|
||||
wantErr bool
|
||||
}{
|
||||
"digest struct": {
|
||||
json: `["57486a447ec0f1958002a22a06b7673b9fd27d11e1c6527498056054c5fa92d23c50f9de44072760fe2b6fb89740b696","0356215882a825279a85b300b0b742931d113bf7e32dde2e50ffde7ec743ca491ecdd7f336dc28a6e0b2bb57af7a44a3"]`,
|
||||
yaml: `
|
||||
- "57486a447ec0f1958002a22a06b7673b9fd27d11e1c6527498056054c5fa92d23c50f9de44072760fe2b6fb89740b696"
|
||||
- "0356215882a825279a85b300b0b742931d113bf7e32dde2e50ffde7ec743ca491ecdd7f336dc28a6e0b2bb57af7a44a3"`,
|
||||
wantDgst: IDKeyDigests{
|
||||
{0x57, 0x48, 0x6a, 0x44, 0x7e, 0xc0, 0xf1, 0x95, 0x80, 0x02, 0xa2, 0x2a, 0x06, 0xb7, 0x67, 0x3b, 0x9f, 0xd2, 0x7d, 0x11, 0xe1, 0xc6, 0x52, 0x74, 0x98, 0x05, 0x60, 0x54, 0xc5, 0xfa, 0x92, 0xd2, 0x3c, 0x50, 0xf9, 0xde, 0x44, 0x07, 0x27, 0x60, 0xfe, 0x2b, 0x6f, 0xb8, 0x97, 0x40, 0xb6, 0x96},
|
||||
{0x03, 0x56, 0x21, 0x58, 0x82, 0xa8, 0x25, 0x27, 0x9a, 0x85, 0xb3, 0x00, 0xb0, 0xb7, 0x42, 0x93, 0x1d, 0x11, 0x3b, 0xf7, 0xe3, 0x2d, 0xde, 0x2e, 0x50, 0xff, 0xde, 0x7e, 0xc7, 0x43, 0xca, 0x49, 0x1e, 0xcd, 0xd7, 0xf3, 0x36, 0xdc, 0x28, 0xa6, 0xe0, 0xb2, 0xbb, 0x57, 0xaf, 0x7a, 0x44, 0xa3},
|
||||
},
|
||||
},
|
||||
"legacy digest as string": {
|
||||
json: `"57486a447ec0f1958002a22a06b7673b9fd27d11e1c6527498056054c5fa92d23c50f9de44072760fe2b6fb89740b696"`,
|
||||
yaml: `"57486a447ec0f1958002a22a06b7673b9fd27d11e1c6527498056054c5fa92d23c50f9de44072760fe2b6fb89740b696"`,
|
||||
wantDgst: IDKeyDigests{{0x57, 0x48, 0x6a, 0x44, 0x7e, 0xc0, 0xf1, 0x95, 0x80, 0x02, 0xa2, 0x2a, 0x06, 0xb7, 0x67, 0x3b, 0x9f, 0xd2, 0x7d, 0x11, 0xe1, 0xc6, 0x52, 0x74, 0x98, 0x05, 0x60, 0x54, 0xc5, 0xfa, 0x92, 0xd2, 0x3c, 0x50, 0xf9, 0xde, 0x44, 0x07, 0x27, 0x60, 0xfe, 0x2b, 0x6f, 0xb8, 0x97, 0x40, 0xb6, 0x96}},
|
||||
},
|
||||
"invalid length": {
|
||||
json: `"010203"`,
|
||||
yaml: `"010203"`,
|
||||
wantDgst: IDKeyDigests{{}},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
require := require.New(t)
|
||||
|
||||
{
|
||||
// YAML
|
||||
var dgst IDKeyDigests
|
||||
err := yaml.Unmarshal([]byte(tc.yaml), &dgst)
|
||||
if tc.wantErr {
|
||||
require.Error(err)
|
||||
} else {
|
||||
require.NoError(err)
|
||||
|
||||
assert.Equal(tc.wantDgst, dgst)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// JSON
|
||||
var dgst IDKeyDigests
|
||||
err := json.Unmarshal([]byte(tc.json), &dgst)
|
||||
if tc.wantErr {
|
||||
require.Error(err)
|
||||
} else {
|
||||
require.NoError(err)
|
||||
|
||||
assert.Equal(tc.wantDgst, dgst)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue