mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-10-01 01:36:09 -04:00
c7d12055d1
* config: move AMD root key to global constant * attestation: add SNP based attestation for aws * Always enable SNP, regardless of attestation type. * Make AWSNitroTPM default again There exists a bug in AWS SNP implementation where sometimes a host might not be able to produce valid SNP reports. Since we have to wait for AWS to fix this we are merging SNP attestation as opt-in feature.
502 lines
59 KiB
Go
502 lines
59 KiB
Go
/*
|
|
Copyright (c) Edgeless Systems GmbH
|
|
|
|
SPDX-License-Identifier: AGPL-3.0-only
|
|
*/
|
|
|
|
package vtpm
|
|
|
|
import (
|
|
"context"
|
|
"crypto"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"testing"
|
|
|
|
"github.com/google/go-sev-guest/proto/sevsnp"
|
|
tpmclient "github.com/google/go-tpm-tools/client"
|
|
"github.com/google/go-tpm-tools/proto/attest"
|
|
"github.com/google/go-tpm-tools/proto/tpm"
|
|
"github.com/google/go-tpm/tpm2"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/edgelesssys/constellation/v2/internal/attestation/initialize"
|
|
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
|
"github.com/edgelesssys/constellation/v2/internal/attestation/simulator"
|
|
tpmsim "github.com/edgelesssys/constellation/v2/internal/attestation/simulator"
|
|
"github.com/edgelesssys/constellation/v2/internal/logger"
|
|
)
|
|
|
|
// attDocRaw is a valid attestation document used for smoke-testing the SNP report unmarshalling.
|
|
const attDocRaw = `{"Attestation":{"akPub":"AAEACwAFAHIAAAAQABQACwgAAAAAAAEArxfXJUX03DMFeQYwO8DS5fYFTdOdUOC8lapZGkl+G9MMjSPCXQJEFas3qOiSohK9nwwVFtVPFuaI16Mwc5naVCWBD1eFAz5p4m3I6C2M5TK64QHIMUT42fc+YB8xy5f6e52P6nP7OQlWJyZL1g8ItfeHMhLxPppJdqrVfCwpZwEaaLxkGPnhoeSFq17SzuuX388LqDq+z/zEdkb5eq060KsVRXZiAKSHZ2b1X9TU24TRD9gbHzeqTgmsSv+ejdBDkIvUCGffSOPWboQHIFbaTB/utrDx9Qanv+SvLN8TNccs1cjPVlm7ibAgHbnmj323SQZgl3P0hVg+aB9C/gwfjQ==","quotes":[{"quote":"/1RDR4AYACIACzusvJ74XCdH29qji0/iiqhEcwGq5LcXk9NZA/Lt+/7mACCzxSSaIYIUEzJi9alDVwiQ7KmfDyz27KA29yoPJhiWlgAAAAAAB+nEkSsHaXVdPBEBwZB6wPh6pj0AAAABAAsD////ACB1BKHP6t92CX0ty/1MPNBlWYyp3bzhx9l9/BaqBpgpzg==","rawSig":"ABQACwEAoiod+IlGvq2n1AFwII9qGtLtV94MO/U2aJgrrTUAh3CNqeesJVLLEu+lDGdOxxvIVEhwxREGqsk4iP1cQNaoeDgtN9pfg8sgTqb2lyRcGbPD7fEbg8RyMCpNuRLVh8mOe53xGVJsFsK2p7kw7DfhQmxiWU1XCCdnhwYEaY8FeHhdwanc6o2ACkcKxDy/kDaf9bfAXb9/mcU95VKOpHI/ZBvqJtCO9KgwoAZQTumSOQ4MnuneksIZq8+eTR36l176WNdV+jD1GvWi+nu7JB4SMQnh+nDH02T91uZbIqaJyOiqo95jdYBnaOSWrWtTPR6RN3uUK1bERSDXVPQzDGhBdg==","pcrs":{"hash":"SHA256","pcrs":{"0":"ewaMDDrCmv4mQTRTa5vibx1MzVdbiNPDzqvzasmcAng=","1":"lBcKsylvKkzBRRjDZ5PtEKssNkrIE01ryiBYZfNwWpM=","2":"PUWM/lXMA+ofRD8VYr7sjfUcdeFKn8+acjShPxmOeWk=","3":"PUWM/lXMA+ofRD8VYr7sjfUcdeFKn8+acjShPxmOeWk=","4":"m4kxK6nKfuCQwYbM+5DvQRkoItFxOyQMQtPt+9boeOY=","5":"n53xb43ld0aeGQTkItQbwd8MF6x3sI3SUR/nnS7LBPs=","6":"PUWM/lXMA+ofRD8VYr7sjfUcdeFKn8+acjShPxmOeWk=","7":"+3Hl5Vzvup4rOW0XYE3g/m4YQadnWIVqEggz460cQKM=","8":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=","9":"3YJHcjoTpTj4YP1iU5Y9WudkwroKc+kUoM7XgESB11c=","10":"hVfaAbz7VHG2kLTWyrspqJbK8IIJK8wGVVmgD1atCbM=","11":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=","12":"nmfmHDL9KBUCtI3c4X7+39YfHGRd3MNegdXKW068gTk=","13":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=","14":"18TMf/eTMCLwE+A73uh1uRcgtbhs8XU8rYMPleeRkm8=","15":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=","16":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=","17":"//////////////////////////////////////////8=","18":"//////////////////////////////////////////8=","19":"//////////////////////////////////////////8=","20":"//////////////////////////////////////////8=","21":"//////////////////////////////////////////8=","22":"//////////////////////////////////////////8=","23":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="}}},{"quote":"/1RDR4AYACIACzusvJ74XCdH29qji0/iiqhEcwGq5LcXk9NZA/Lt+/7mACCzxSSaIYIUEzJi9alDVwiQ7KmfDyz27KA29yoPJhiWlgAAAAAAB+q6kSsHaXVdPBEBwZB6wPh6pj0AAAABAAwD////ACBDyU6rmoq/MGRuXOZtSN0zMwVt54NMGEZzpEiKvu8UFQ==","rawSig":"ABQACwEALEJYI9+t9DxhC8OpjDsN3z7lko27sMOZiLBzUN2nad7GVpwAZRf77Hq7T5NuuXXVCbXeIXPPFAutTsjipXjK4a92Ogr/NSQz+Xy0Az991BMiv2WlPMB+0bs/UsPBIEWJaL2CgnBf3Uaq2esfRJBkBRnigCe+dLX9w6GgAOasEWhKXy8oyDn5e/XItbOg+Ug2ufLlxWHOShzXdX66XNx7NldxnB0CPhJY24xKyMmgJRQHB367wtj1byx6WE3BK3HfcFMUTndRgtY9XTdteynd81pUBgxfdu0/KDR8OlEDzM6wDwXENTBdGYJjerPou1IGAfvdP3g+mnOQlCUhWEMDlw==","pcrs":{"hash":"SHA384","pcrs":{"0":"3EZiPRyTft1GbeUgzqE6DytXO5QIT22qUhbtcNw/B19go7VVM4Ga69lMORmD7A2y","1":"7ojUJQGNzJJCSgCIqACM0HMZA+E+P6pfC6givgi+juXWdCNtMx13lRLnibuk7HGy","2":"UYkjsPlV0I2gd8lqq6Uiud7O3mHFmc6mxBiJz76krk1QUp2W/k0a/a+2Xn+VvyPE","3":"UYkjsPlV0I2gd8lqq6Uiud7O3mHFmc6mxBiJz76krk1QUp2W/k0a/a+2Xn+VvyPE","4":"aJMP6E2BOfqfg0kIzsPPHgnbUjHGW1BWrsKvt9iRkEpQFc3xVmJNLa1j2X/emu5v","5":"auzDenRwYRJhPgsawrCdR629m7E5UD6Aln/3GH/dbjAGIOKrM0k7srscgA6IAPRf","6":"UYkjsPlV0I2gd8lqq6Uiud7O3mHFmc6mxBiJz76krk1QUp2W/k0a/a+2Xn+VvyPE","7":"mjLHXDKNMkEb8nU7Fw55cJAQ2kFBNf0rh+8DVn8lZK3qaBUpkOnCDVTbNHEZcrIx","8":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA","9":"HXzMvbSpA6bsC+1L1KpXtdZl4Qf7h+PYjsoD3fCx2ncJLhIZgL9iWxrNNJ+7UVGK","10":"lYr8xNLTD0ckvTl6J/W3NIp/A3LPOfTpnW8J2JWsmpbk8th874Pl4/xxFmmmdUnk","11":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA","12":"JJkqFH7ieQaqyzLKE8XXXm0oIx8qqKHHHJtYGhN4SJmBrQkAhOx0kTKVhIMXPCIN","13":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA","14":"AT/OjGKKHa+3e6+vrBwwt+DVtZc9J2z3C352VGKrMlBG1wpZD2uTMDUnWvmLO8xH","15":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA","16":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA","17":"////////////////////////////////////////////////////////////////","18":"////////////////////////////////////////////////////////////////","19":"////////////////////////////////////////////////////////////////","20":"////////////////////////////////////////////////////////////////","21":"////////////////////////////////////////////////////////////////","22":"////////////////////////////////////////////////////////////////","23":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"}}},{"quote":"/1RDR4AYACIACzusvJ74XCdH29qji0/iiqhEcwGq5LcXk9NZA/Lt+/7mACCzxSSaIYIUEzJi9alDVwiQ7KmfDyz27KA29yoPJhiWlgAAAAAAB+vdkSsHaXVdPBEBwZB6wPh6pj0AAAABAA0D////ACACIRaJ7z1XVZ0G/fpsOTnrQhBiEIDU/JPK8hVE2ou6YA==","rawSig":"ABQACwEAQ+fnBPHTkwwEDI6miPtEQXLMn271zNdeGTcWDBQIets1NJaSYhgGInwTpdEDa7dTqXViHjHCLq0tctOMBTkYRLl23Q9Tpq/ZMsDllF/121KmFypUl4kiS4aDQOQodtuLcnYER+a/aXtuGVVMgojcIYKGhU3SnGDBQY3PwmNAFZVbNO0Qoa1pT2Nc+KTID9MQQxikESAWslMvpK/RJmbyvyb8dYIzhOJcTV/jEzwUVBbEb8Sfaic7vLWFS+ZRLbpft/CQh4iNLgpDHcd8Q4Fe4gykctaIWYsjpjRvXKY06UsTZuK8OJ/IUK5sUAlFBfAgiHh43AO/9nyOMUREporZlg==","pcrs":{"hash":"SHA512","pcrs":{"0":"ZAHmBFpxeI+azyLt0KcsjO9Zgw3YlHjC6iWTNyGm17jIFtZc/cQRv42HxdTB/W0Q/eMjhC6DIx4asXvfmO6gcA==","1":"ox5+tdL16TO8mB60KNMmTW3uCYp1ya0zzbYFf2uc9m5zt7NLuAXMJcH4ExXtwplTX+HfXF+ZHYlicAN39hy4Hg==","2":"J+wJFTPEue6jjdFMOj7N7wqZweVky+Zt/gCCUBVOeDmwt1Io/o3rzEyjMOauvBq8dAcLycnB4muTnJ2RbkXhPA==","3":"J+wJFTPEue6jjdFMOj7N7wqZweVky+Zt/gCCUBVOeDmwt1Io/o3rzEyjMOauvBq8dAcLycnB4muTnJ2RbkXhPA==","4":"AzJEYS/PR0PlAxObuY7LO49YiE7ZzmQEkeYH2q5zuo6jibYQEj8eMOt5OUJ7S9Tm8FA2ISt4A896mQ0AzbnzkQ==","5":"nDoRoI0yqV9IjNB2uo350iYi6n5Lt4pHCXTULT+xK3JKt5vqWIBfXxQ6GOG/UXgO0TqdsXa6LafHXpk7nXKO1A==","6":"J+wJFTPEue6jjdFMOj7N7wqZweVky+Zt/gCCUBVOeDmwt1Io/o3rzEyjMOauvBq8dAcLycnB4muTnJ2RbkXhPA==","7":"EwEiYgkAsHRj8E/HibHPs+70skpm/DW2qndLIIOrkCyJI6hQ/qU7DT2Z3y2K53wQY6cMi7mghOmdd+zEzdQqaA==","8":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==","9":"q+0IQZ+v0CXBRtp/713PV0tfmugaqp5d54cFAh1/U00jd6XRARPTH3HIzLdaRoS/8VMbLroajxG2rbjillZx7Q==","10":"PGsjFalFg+t3V9gqkRdoHWEi3ozyFDbmZ5MXde3yAayDCSAXJOKeHAs0nFo1hw4CZTihAqwv8T0UqHpj2bouNg==","11":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==","12":"3ltx4yZdd8DxyUHWWoFbnslWbDOMeC+PzycaZDaGfY5BiJCswjtTCepibUoTmNUgotrOvkUjpJVHI0ql0UDkAQ==","13":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==","14":"hq9AIsVNou36QDe1Sj/m4/xe4tQKngqZiNkq1tB1hnf7gr2NyjHjuVnzzpNd1StUCqW269zXIBUdYI7EeR31zQ==","15":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==","16":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==","17":"/////////////////////////////////////////////////////////////////////////////////////w==","18":"/////////////////////////////////////////////////////////////////////////////////////w==","19":"/////////////////////////////////////////////////////////////////////////////////////w==","20":"/////////////////////////////////////////////////////////////////////////////////////w==","21":"/////////////////////////////////////////////////////////////////////////////////////w==","22":"/////////////////////////////////////////////////////////////////////////////////////w==","23":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="}}}],"eventLog":"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","sevSnpAttestation":{"report":{"version":2,"policy":"196608","familyId":"AAAAAAAAAAAAAAAAAAAAAA==","imageId":"AAAAAAAAAAAAAAAAAAAAAA==","signatureAlgo":1,"currentTcb":"14846679121580261379","platformInfo":"3","authorKeyEn":4,"reportData":"s8UkmiGCFBMyYvWpQ1cIkOypnw8s9uygNvcqDyYYlpYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==","measurement":"JayBD1xHUIkPsaFY8JeWLgTU1/tkDR0IqZgpz0pwVDpHzG+xkrvpCqcTFCNhpmFV","hostData":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=","idKeyDigest":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA","authorKeyDigest":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA","reportId":"c+5Bu3zXghGxmkiPmIrRvLRgxIKIbjC74IEjzlpWXx0=","reportIdMa":"//////////////////////////////////////////8=","reportedTcb":"8289438064128819203","chipId":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==","committedTcb":"8289438064128819203","currentBuild":1,"currentMinor":54,"currentMajor":1,"committedBuild":1,"committedMinor":54,"committedMajor":1,"launchTcb":"8289438064128819203","signature":"+I+FKD+izQwR2/MY/8m1WuHsdyJfPI1bs8+82/bNJeyVZcm70kCedk4bIgtg6MznAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ9O0Imt5m+9P2nYGiS+C4ysSgzxuxF8tIU0gLBI059s39Pu4GuQWz14M+b3wEOYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="},"certificateChain":{}}},"InstanceInfo":"eyJSZXBvcnQiOiJBZ0FBQUFBQUFBQUFBQU1BQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRUFBQUFEQUFBQUFBQUt6Z01BQUFBQUFBQUFCQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFKYXlCRDF4SFVJa1BzYUZZOEplV0xnVFUxL3RrRFIwSXFaZ3B6MHB3VkRwSHpHK3hrcnZwQ3FjVEZDTmhwbUZWQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCejdrRzdmTmVDRWJHYVNJK1lpdEc4dEdERWdvaHVNTHZnZ1NQT1dsWmZIZi8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL0F3QUFBQUFBQ25NQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQXdBQUFBQUFDbk1CTmdFQUFUWUJBQU1BQUFBQUFBcHpBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQVpGdWMzRXRUY3Zjd3FaZzBmekc4R1dpWThGZTJZTDBnZ2pIYWJEckY5M1RjZm8vMGVkeXVadmEyQzN3WVFlM3pBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUdUSFUzYUh1RGlmQTRkbjd1QWVTWE5KMWRUbmErOENHTzRKbGZuTXJCNGdSUk9KV01hZEJrRWptbFJGY2IxRnBBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBPSIsIkNlcnRzIjoicUFkTHdxSmFTRDZxNWpuQVJhQzRvVEFBQUFBckJRQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQU1JSUZKekNDQXRhZ0F3SUJBZ0lCQURCR0Jna3Foa2lHOXcwQkFRb3dPYUFQTUEwR0NXQ0dTQUZsQXdRQ0FnVUFvUnd3R2dZSktvWklodmNOQVFFSU1BMEdDV0NHU0FGbEF3UUNBZ1VBb2dNQ0FUQ2pBd0lCQVRDQmdERVVNQklHQTFVRUN3d0xSVzVuYVc1bFpYSnBibWN4Q3pBSkJnTlZCQVlUQWxWVE1SUXdFZ1lEVlFRSERBdFRZVzUwWVNCRGJHRnlZVEVMTUFrR0ExVUVDQXdDUTBFeEh6QWRCZ05WQkFvTUZrRmtkbUZ1WTJWa0lFMXBZM0p2SUVSbGRtbGpaWE14RnpBVkJnTlZCQU1NRGxORlZpMVdURVZMTFUxcGJHRnVNQjRYRFRJek1EUXlNREU0TXpBeE5sb1hEVEkwTURReU1ERTRNekF4Tmxvd2VqRVVNQklHQTFVRUN3d0xSVzVuYVc1bFpYSnBibWN4Q3pBSkJnTlZCQVlUQWxWVE1SUXdFZ1lEVlFRSERBdFRZVzUwWVNCRGJHRnlZVEVMTUFrR0ExVUVDQXdDUTBFeEh6QWRCZ05WQkFvTUZrRmtkbUZ1WTJWa0lFMXBZM0p2SUVSbGRtbGpaWE14RVRBUEJnTlZCQU1NQ0ZORlZpMVdURVZMTUhZd0VBWUhLb1pJemowQ0FRWUZLNEVFQUNJRFlnQUVuQnFmMVNiazhLdjdPM0M4VXhOdTUxd3ZiL3c0L3VSM2tPVGo4ZkU3Q0FDZHNUOEliSlQzU3hQNG5IQ3p1ZG5MS1c4WU5CRkpCSFZLUFlSS1BYM2FzWENBQ1JMWDJFQitGVnM0bTFnT281OFFqT2FMVnRNeUc5L0RRVU1rcUZMdW80SHNNSUhwTUJBR0NTc0dBUVFCbkhnQkFRUURBZ0VBTUJRR0NTc0dBUVFCbkhnQkFnUUhGZ1ZOYVd4aGJqQVJCZ29yQmdFRUFaeDRBUU1CQkFNQ0FRTXdFUVlLS3dZQkJBR2NlQUVEQWdRREFnRUFNQkVHQ2lzR0FRUUJuSGdCQXdRRUF3SUJBREFSQmdvckJnRUVBWng0QVFNRkJBTUNBUUF3RVFZS0t3WUJCQUdjZUFFREJnUURBZ0VBTUJFR0Npc0dBUVFCbkhnQkF3Y0VBd0lCQURBUkJnb3JCZ0VFQVp4NEFRTURCQU1DQVFvd0VRWUtLd1lCQkFHY2VBRURDQVFEQWdGek1DY0dDU3NHQVFRQm5IZ0JCUVFhRmhoRFRqMWpZeTEwWlhOMExtRnRZWHB2Ym1GM2N5NWpiMjB3UmdZSktvWklodmNOQVFFS01EbWdEekFOQmdsZ2hrZ0JaUU1FQWdJRkFLRWNNQm9HQ1NxR1NJYjNEUUVCQ0RBTkJnbGdoa2dCWlFNRUFnSUZBS0lEQWdFd293TUNBUUVEZ2dJQkFDOWR3YkxBUUNPNUR2SU8wdGVSY0ZRSDlzdnN0YnFhTDZRMVR4djdTQWJudi9sMnBmYWlSMHdwcU9CS2lZcHFhWjI2RXJDK2lMdTB0eE5wYXg1VXhzMlViUmZaaVE2OURzYUxORWI1OEpNVW5odFh4RWNPY092YmtSdTFIWXB2Um5qbkVNcVRMNmp0YzJvZ25VUmxiL3E2UkVmdUxrSzVHbmg4WUVtNVRid3JNZjVYOTRMQWFKVEp3ck0wQnVrUE1wMENMRTcxN1VjR0g0bFcwRXdvdjBlbm5iMjM4STQxcEhoWW5icGM3YjFtMHlXZStHcnM3RktPcElpWWNQR0wrUUJIY1VZempVSjBuNzhLYnlSVEpwbUhaczhiMkVTZlEwb0FGUnVqeEtvU2dTQXl0OFc2d3F5UWpObTVBR2RKSlhwalExYktrc0trZnQ5eWlYa1hUcC9nbHUxbEUzOEdtOGlHWlpGVGV5L3crS1pTZVdQZjJEb1k2b0h1RTZNWFN1akYwZ0M5M0l6U2dUUXc2WkJJRjEvOEM1WVVOazlOREJKNFFTOUg2TjdEZ0JsdnhyN2llOGdEZS94a0x1U3hBUEVmYk9KWnRZKzVDTnNxUFBaUGhHQzdnM3FnOU1xdXUzdnRJdXFGMlpoTks1ekt5bk50cEwzaXk3RW5QbENHOWpReUlHSjA2SHJjcUFNS2FtRmtEVGx0THpBYlRpbHpIYUxDcmp1WW1ieFJYbjBTRStjRE82N0kya1p0ZXhWSWwwWXhEZmh5ZTFYKzJqM2tFN1phR3JZell4THN0WkNJbFZVejB3VEtvUmk5MGt6OThjR3hYOC9hUXN0TUhZWUpIaGxKcHJlYlhvcGxxcDdOdzZYTkttbi9HWEF4ZkJId2RQeUYvV01OZXpUc0FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUE9PSJ9","UserData":"BWmTa8zt+6Y1nbl1twWt8tRpMz9TQkmUjUPTq8oOW30="}`
|
|
|
|
type simTPMWithEventLog struct {
|
|
io.ReadWriteCloser
|
|
}
|
|
|
|
func newSimTPMWithEventLog() (io.ReadWriteCloser, error) {
|
|
tpmSim, err := simulator.OpenSimulatedTPM()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &simTPMWithEventLog{tpmSim}, nil
|
|
}
|
|
|
|
// EventLog overrides the default event log getter.
|
|
func (s simTPMWithEventLog) EventLog() ([]byte, error) {
|
|
// event log header for successful parsing of event log
|
|
header := []byte{
|
|
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x53, 0x70, 0x65,
|
|
0x63, 0x20, 0x49, 0x44, 0x20, 0x45, 0x76, 0x65, 0x6E, 0x74, 0x30, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x02, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x14, 0x00, 0x0B, 0x00, 0x20, 0x00, 0x00,
|
|
}
|
|
return header, nil
|
|
}
|
|
|
|
func fakeGetInstanceInfo(_ context.Context, _ io.ReadWriteCloser, _ []byte) ([]byte, error) {
|
|
return []byte("unit-test"), nil
|
|
}
|
|
|
|
func TestValidate(t *testing.T) {
|
|
require := require.New(t)
|
|
|
|
fakeValidateCVM := func(AttestationDocument, *attest.MachineState) error { return nil }
|
|
fakeGetTrustedKey := func(_ context.Context, attDoc AttestationDocument, _ []byte) (crypto.PublicKey, error) {
|
|
pubArea, err := tpm2.DecodePublic(attDoc.Attestation.AkPub)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return pubArea.Key()
|
|
}
|
|
|
|
testExpectedPCRs := measurements.M{
|
|
0: measurements.WithAllBytes(0x00, measurements.Enforce, measurements.PCRMeasurementLength),
|
|
1: measurements.WithAllBytes(0x00, measurements.Enforce, measurements.PCRMeasurementLength),
|
|
uint32(measurements.PCRIndexClusterID): measurements.WithAllBytes(0x00, measurements.Enforce, measurements.PCRMeasurementLength),
|
|
}
|
|
warnLog := &testAttestationLogger{}
|
|
|
|
tpmOpen, tpmCloser := tpmsim.NewSimulatedTPMOpenFunc()
|
|
defer tpmCloser.Close()
|
|
|
|
issuer := NewIssuer(tpmOpen, tpmclient.AttestationKeyRSA, fakeGetInstanceInfo, logger.NewTest(t))
|
|
validator := NewValidator(testExpectedPCRs, fakeGetTrustedKey, fakeValidateCVM, nil)
|
|
|
|
nonce := []byte{1, 2, 3, 4}
|
|
challenge := []byte("Constellation")
|
|
|
|
ctx := context.Background()
|
|
|
|
attDocRaw, err := issuer.Issue(ctx, challenge, nonce)
|
|
require.NoError(err)
|
|
|
|
var attDoc AttestationDocument
|
|
err = json.Unmarshal(attDocRaw, &attDoc)
|
|
require.NoError(err)
|
|
require.Equal(challenge, attDoc.UserData)
|
|
|
|
// valid test
|
|
out, err := validator.Validate(ctx, attDocRaw, nonce)
|
|
require.NoError(err)
|
|
require.Equal(challenge, out)
|
|
|
|
// validation must fail after bootstrapping (change of enforced PCR)
|
|
require.NoError(initialize.MarkNodeAsBootstrapped(tpmOpen, []byte{2}))
|
|
attDocBootstrappedRaw, err := issuer.Issue(ctx, challenge, nonce)
|
|
require.NoError(err)
|
|
_, err = validator.Validate(ctx, attDocBootstrappedRaw, nonce)
|
|
require.Error(err)
|
|
|
|
// userData must be bound to PCR state
|
|
attDocBootstrappedRaw, err = issuer.Issue(ctx, []byte{2, 3}, nonce)
|
|
require.NoError(err)
|
|
var attDocBootstrapped AttestationDocument
|
|
require.NoError(json.Unmarshal(attDocBootstrappedRaw, &attDocBootstrapped))
|
|
attDocBootstrapped.Attestation = attDoc.Attestation
|
|
attDocBootstrappedRaw, err = json.Marshal(attDocBootstrapped)
|
|
require.NoError(err)
|
|
_, err = validator.Validate(ctx, attDocBootstrappedRaw, nonce)
|
|
require.Error(err)
|
|
|
|
expectedPCRs := measurements.M{
|
|
0: measurements.WithAllBytes(0x00, measurements.WarnOnly, measurements.PCRMeasurementLength),
|
|
1: measurements.WithAllBytes(0x00, measurements.WarnOnly, measurements.PCRMeasurementLength),
|
|
2: measurements.Measurement{
|
|
Expected: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20},
|
|
ValidationOpt: measurements.WarnOnly,
|
|
},
|
|
3: measurements.Measurement{
|
|
Expected: []byte{0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40},
|
|
ValidationOpt: measurements.WarnOnly,
|
|
},
|
|
4: measurements.Measurement{
|
|
Expected: []byte{0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60},
|
|
ValidationOpt: measurements.WarnOnly,
|
|
},
|
|
5: measurements.Measurement{
|
|
Expected: []byte{0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80},
|
|
ValidationOpt: measurements.WarnOnly,
|
|
},
|
|
}
|
|
warningValidator := NewValidator(
|
|
expectedPCRs,
|
|
fakeGetTrustedKey,
|
|
fakeValidateCVM,
|
|
warnLog,
|
|
)
|
|
out, err = warningValidator.Validate(ctx, attDocRaw, nonce)
|
|
require.NoError(err)
|
|
assert.Equal(t, challenge, out)
|
|
assert.Len(t, warnLog.warnings, 4)
|
|
|
|
testCases := map[string]struct {
|
|
validator *Validator
|
|
attDoc []byte
|
|
nonce []byte
|
|
wantErr bool
|
|
}{
|
|
"valid": {
|
|
validator: NewValidator(testExpectedPCRs, fakeGetTrustedKey, fakeValidateCVM, warnLog),
|
|
attDoc: mustMarshalAttestation(attDoc, require),
|
|
nonce: nonce,
|
|
},
|
|
"invalid nonce": {
|
|
validator: NewValidator(testExpectedPCRs, fakeGetTrustedKey, fakeValidateCVM, warnLog),
|
|
attDoc: mustMarshalAttestation(attDoc, require),
|
|
nonce: []byte{4, 3, 2, 1},
|
|
wantErr: true,
|
|
},
|
|
"invalid signature": {
|
|
validator: NewValidator(testExpectedPCRs, fakeGetTrustedKey, fakeValidateCVM, warnLog),
|
|
attDoc: mustMarshalAttestation(AttestationDocument{
|
|
Attestation: attDoc.Attestation,
|
|
InstanceInfo: attDoc.InstanceInfo,
|
|
UserData: []byte("wrong data"),
|
|
}, require),
|
|
nonce: nonce,
|
|
wantErr: true,
|
|
},
|
|
"untrusted attestation public key": {
|
|
validator: NewValidator(
|
|
testExpectedPCRs,
|
|
func(context.Context, AttestationDocument, []byte) (crypto.PublicKey, error) {
|
|
return nil, errors.New("untrusted")
|
|
},
|
|
fakeValidateCVM, warnLog),
|
|
attDoc: mustMarshalAttestation(attDoc, require),
|
|
nonce: nonce,
|
|
wantErr: true,
|
|
},
|
|
"not a CVM": {
|
|
validator: NewValidator(
|
|
testExpectedPCRs,
|
|
fakeGetTrustedKey,
|
|
func(AttestationDocument, *attest.MachineState) error {
|
|
return errors.New("untrusted")
|
|
},
|
|
warnLog),
|
|
attDoc: mustMarshalAttestation(attDoc, require),
|
|
nonce: nonce,
|
|
wantErr: true,
|
|
},
|
|
"untrusted PCRs": {
|
|
validator: NewValidator(
|
|
measurements.M{
|
|
0: measurements.Measurement{
|
|
Expected: []byte{0xFF},
|
|
ValidationOpt: measurements.Enforce,
|
|
},
|
|
},
|
|
fakeGetTrustedKey,
|
|
fakeValidateCVM,
|
|
warnLog),
|
|
attDoc: mustMarshalAttestation(attDoc, require),
|
|
nonce: nonce,
|
|
wantErr: true,
|
|
},
|
|
"no sha256 quote": {
|
|
validator: NewValidator(testExpectedPCRs, fakeGetTrustedKey, fakeValidateCVM, warnLog),
|
|
attDoc: mustMarshalAttestation(AttestationDocument{
|
|
Attestation: &attest.Attestation{
|
|
AkPub: attDoc.Attestation.AkPub,
|
|
Quotes: []*tpm.Quote{
|
|
attDoc.Attestation.Quotes[2],
|
|
},
|
|
EventLog: attDoc.Attestation.EventLog,
|
|
InstanceInfo: attDoc.Attestation.InstanceInfo,
|
|
},
|
|
InstanceInfo: attDoc.InstanceInfo,
|
|
UserData: attDoc.UserData,
|
|
}, require),
|
|
nonce: nonce,
|
|
wantErr: true,
|
|
},
|
|
"invalid attestation document": {
|
|
validator: NewValidator(testExpectedPCRs, fakeGetTrustedKey, fakeValidateCVM, warnLog),
|
|
attDoc: []byte("invalid attestation"),
|
|
nonce: nonce,
|
|
wantErr: true,
|
|
},
|
|
}
|
|
|
|
for name, tc := range testCases {
|
|
t.Run(name, func(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
_, err = tc.validator.Validate(ctx, tc.attDoc, tc.nonce)
|
|
if tc.wantErr {
|
|
assert.Error(err)
|
|
} else {
|
|
assert.NoError(err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func mustMarshalAttestation(attDoc AttestationDocument, require *require.Assertions) []byte {
|
|
out, err := json.Marshal(attDoc)
|
|
require.NoError(err)
|
|
return out
|
|
}
|
|
|
|
func TestFailIssuer(t *testing.T) {
|
|
testCases := map[string]struct {
|
|
issuer *Issuer
|
|
userData []byte
|
|
nonce []byte
|
|
}{
|
|
"fail openTPM": {
|
|
issuer: NewIssuer(
|
|
func() (io.ReadWriteCloser, error) {
|
|
return nil, errors.New("failure")
|
|
},
|
|
tpmclient.AttestationKeyRSA,
|
|
fakeGetInstanceInfo,
|
|
nil,
|
|
),
|
|
userData: []byte("Constellation"),
|
|
nonce: []byte{1, 2, 3, 4},
|
|
},
|
|
"fail getAttestationKey": {
|
|
issuer: NewIssuer(
|
|
newSimTPMWithEventLog,
|
|
func(tpm io.ReadWriter) (*tpmclient.Key, error) {
|
|
return nil, errors.New("failure")
|
|
},
|
|
fakeGetInstanceInfo,
|
|
nil,
|
|
),
|
|
userData: []byte("Constellation"),
|
|
nonce: []byte{1, 2, 3, 4},
|
|
},
|
|
"fail Attest": {
|
|
issuer: NewIssuer(
|
|
newSimTPMWithEventLog,
|
|
func(tpm io.ReadWriter) (*tpmclient.Key, error) {
|
|
return &tpmclient.Key{}, nil
|
|
},
|
|
fakeGetInstanceInfo,
|
|
nil,
|
|
),
|
|
userData: []byte("Constellation"),
|
|
nonce: []byte{1, 2, 3, 4},
|
|
},
|
|
"fail getInstanceInfo": {
|
|
issuer: NewIssuer(
|
|
newSimTPMWithEventLog,
|
|
tpmclient.AttestationKeyRSA,
|
|
func(context.Context, io.ReadWriteCloser, []byte) ([]byte, error) { return nil, errors.New("failure") },
|
|
nil,
|
|
),
|
|
userData: []byte("Constellation"),
|
|
nonce: []byte{1, 2, 3, 4},
|
|
},
|
|
}
|
|
|
|
for name, tc := range testCases {
|
|
t.Run(name, func(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
tc.issuer.log = logger.NewTest(t)
|
|
|
|
_, err := tc.issuer.Issue(context.Background(), tc.userData, tc.nonce)
|
|
assert.Error(err)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetSHA256QuoteIndex(t *testing.T) {
|
|
testCases := map[string]struct {
|
|
quotes []*tpm.Quote
|
|
wantIdx int
|
|
wantErr bool
|
|
}{
|
|
"idx 0 is valid": {
|
|
quotes: []*tpm.Quote{
|
|
{
|
|
Pcrs: &tpm.PCRs{
|
|
Hash: tpm.HashAlgo_SHA256,
|
|
},
|
|
},
|
|
},
|
|
wantIdx: 0,
|
|
wantErr: false,
|
|
},
|
|
"idx 1 is valid": {
|
|
quotes: []*tpm.Quote{
|
|
{
|
|
Pcrs: &tpm.PCRs{
|
|
Hash: tpm.HashAlgo_SHA1,
|
|
},
|
|
},
|
|
{
|
|
Pcrs: &tpm.PCRs{
|
|
Hash: tpm.HashAlgo_SHA256,
|
|
},
|
|
},
|
|
},
|
|
wantIdx: 1,
|
|
wantErr: false,
|
|
},
|
|
"no quotes": {
|
|
quotes: nil,
|
|
wantErr: true,
|
|
},
|
|
"quotes is nil": {
|
|
quotes: make([]*tpm.Quote, 2),
|
|
wantErr: true,
|
|
},
|
|
"pcrs is nil": {
|
|
quotes: []*tpm.Quote{
|
|
{
|
|
Pcrs: &tpm.PCRs{
|
|
Hash: tpm.HashAlgo_SHA1,
|
|
},
|
|
},
|
|
{
|
|
Pcrs: nil,
|
|
},
|
|
},
|
|
wantErr: true,
|
|
},
|
|
}
|
|
|
|
for name, tc := range testCases {
|
|
t.Run(name, func(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
idx, err := GetSHA256QuoteIndex(tc.quotes)
|
|
if tc.wantErr {
|
|
assert.Error(err)
|
|
assert.Equal(0, idx)
|
|
} else {
|
|
assert.NoError(err)
|
|
assert.Equal(tc.wantIdx, idx)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetSelectedMeasurements(t *testing.T) {
|
|
testCases := map[string]struct {
|
|
openFunc TPMOpenFunc
|
|
pcrSelection tpm2.PCRSelection
|
|
wantErr bool
|
|
}{
|
|
"error": {
|
|
openFunc: func() (io.ReadWriteCloser, error) { return nil, errors.New("error") },
|
|
pcrSelection: tpm2.PCRSelection{
|
|
Hash: tpm2.AlgSHA256,
|
|
PCRs: []int{0, 1, 2},
|
|
},
|
|
wantErr: true,
|
|
},
|
|
"3 PCRs": {
|
|
openFunc: simulator.OpenSimulatedTPM,
|
|
pcrSelection: tpm2.PCRSelection{
|
|
Hash: tpm2.AlgSHA256,
|
|
PCRs: []int{0, 1, 2},
|
|
},
|
|
},
|
|
"Azure PCRS": {
|
|
openFunc: simulator.OpenSimulatedTPM,
|
|
pcrSelection: AzurePCRSelection,
|
|
},
|
|
"GCP PCRs": {
|
|
openFunc: simulator.OpenSimulatedTPM,
|
|
pcrSelection: GCPPCRSelection,
|
|
},
|
|
}
|
|
|
|
for name, tc := range testCases {
|
|
t.Run(name, func(t *testing.T) {
|
|
require := require.New(t)
|
|
assert := assert.New(t)
|
|
|
|
pcrs, err := GetSelectedMeasurements(tc.openFunc, tc.pcrSelection)
|
|
if tc.wantErr {
|
|
assert.Error(err)
|
|
return
|
|
}
|
|
require.NoError(err)
|
|
assert.Len(pcrs, len(tc.pcrSelection.PCRs))
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestUnmarshal verifies that an actual attestation document can be unmarshalled.
|
|
func TestUnmarshal(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
attestation := &AttestationDocument{}
|
|
err := json.Unmarshal([]byte(attDocRaw), attestation)
|
|
assert.NoError(err)
|
|
}
|
|
|
|
// TestMarshalUnmarshal verifies that the AttestationDocument can be marshalled and unmarshalled.
|
|
func TestMarshalUnmarshal(t *testing.T) {
|
|
testCases := map[string]struct {
|
|
obj AttestationDocument
|
|
}{
|
|
"snp tee": {
|
|
obj: AttestationDocument{&attest.Attestation{TeeAttestation: &attest.Attestation_SevSnpAttestation{SevSnpAttestation: &sevsnp.Attestation{Report: &sevsnp.Report{Version: 1}}}}, nil, nil},
|
|
},
|
|
"no tee": {
|
|
obj: AttestationDocument{&attest.Attestation{}, nil, nil},
|
|
},
|
|
}
|
|
|
|
for name, tc := range testCases {
|
|
t.Run(name, func(t *testing.T) {
|
|
assert := assert.New(t)
|
|
|
|
data, err := json.Marshal(&tc.obj)
|
|
assert.NoError(err)
|
|
assert.NotNil(data)
|
|
|
|
attestation := &AttestationDocument{}
|
|
err = json.Unmarshal(data, attestation)
|
|
assert.NoError(err)
|
|
assert.NotNil(attestation)
|
|
assert.Equal(tc.obj, *attestation)
|
|
})
|
|
}
|
|
}
|
|
|
|
type testAttestationLogger struct {
|
|
infos []string
|
|
warnings []string
|
|
}
|
|
|
|
func (w *testAttestationLogger) Infof(format string, args ...any) {
|
|
w.infos = append(w.infos, fmt.Sprintf(format, args...))
|
|
}
|
|
|
|
func (w *testAttestationLogger) Warnf(format string, args ...any) {
|
|
w.warnings = append(w.warnings, fmt.Sprintf(format, args...))
|
|
}
|