Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 26 additions & 30 deletions kms/cloudkms/attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (
"regexp"
"slices"
"strconv"
"time"

"cloud.google.com/go/kms/apiv1/kmspb"

Expand Down Expand Up @@ -48,29 +47,31 @@ x2JBsjEjmWpHuBDAXPCesD5cu9UzzDgcpdwmi7Xidl74kj3f/HgrOeimRdOb8lG5
/A==
-----END CERTIFICATE-----`

// Marvell (Cavium) certificate, expires on Nov 16 13:55:25 2025 UTC
// https://www.marvell.com/content/dam/marvell/en/public-collateral/security-solutions/liquid_security_certificate.zip
// Marvell (Cavium) certificate, expires on Jul 23 20:29:20 2034 UTC
// https://www.marvell.com/products/security-solutions/nitrox-hs-adapters/liquidsecurity-certificate-cnxxxxx-nfbe-x0-g-v3.html
// https://www.marvell.com/content/dam/marvell/en/public-collateral/security-solutions/liquidsecurity-certificate-cnxxxxx-nfbe-x.0-g-v3.zip
const caviumRoot = `-----BEGIN CERTIFICATE-----
MIIDoDCCAogCCQDA6q30NN7cFzANBgkqhkiG9w0BAQsFADCBkTELMAkGA1UEBhMC
VVMxEzARBgNVBAgMCkNhbGlmb3JuaWExETAPBgNVBAcMCFNhbiBKb3NlMRUwEwYD
VQQKDAxDYXZpdW0sIEluYy4xFzAVBgNVBAsMDkxpcXVpZFNlY3VyaXR5MSowKAYD
VQQDDCFsb2NhbGNhLmxpcXVpZHNlY3VyaXR5LmNhdml1bS5jb20wHhcNMTUxMTE5
MTM1NTI1WhcNMjUxMTE2MTM1NTI1WjCBkTELMAkGA1UEBhMCVVMxEzARBgNVBAgM
CkNhbGlmb3JuaWExETAPBgNVBAcMCFNhbiBKb3NlMRUwEwYDVQQKDAxDYXZpdW0s
IEluYy4xFzAVBgNVBAsMDkxpcXVpZFNlY3VyaXR5MSowKAYDVQQDDCFsb2NhbGNh
LmxpcXVpZHNlY3VyaXR5LmNhdml1bS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQDckvqQM4cvZjdyqOLGMTjKJwvfxJOhVqw6pojgUMz10VU7z3Ct
JrwHcESwEDUxUkMxzof55kForURLaVVCjedYauEisnZwwSWkAemp9GREm8iX6BXt
oZ8VDWoO2H0AJiHCM62qJeZVXhm8A/zWG0PyLrCINH0yz9ah6BcwdsZGLvQvkpUN
JhwVMrb9nI9BlRmTWhoot1YSTf7jfibEkc/pN+0Ez30RFaL3MhyIaNJS22+10tny
4sOUTsPEtXKah5mPlHpnrGcB18z5Yxgr0vDNYx+FCPGo95XGrq9NYfNMlwsSeFSr
8D1VQ7HZmipeTB1hQTUQw/K/Rmtw5NiljkYTAgMBAAEwDQYJKoZIhvcNAQELBQAD
ggEBAJjqbFaa3FOXEXcXPX2lCHdcyl8TwOR9f3Rq87MEfb3oeK9FarNkUCdvuGs3
OkAWoFib/9l2F7ZgaNlJqVrwBaOvYuGguQoUpDybqttYUJVLcu9vA9eZA+UCJdhd
P7fCyGMO+G96cnG3GTS1/SrIDU+YCnVElQ0P/73/de+ImoeMkwcqiUi2lsf3vGGR
YXMt/DxUwjXwjIpWCs+37cwbNHAv0VKDOR/jmNf5EZf+sy4x2rJZ1NS6eDZ9RBug
CLaN6ntybV4YlE7jDI9XIOm/tPJULZGLpLolngWVB6qtzn1RjBw1HIqpoXg+9s1g
pLFFinSrEL1fkQR0YZQrJckktPs=
MIIDvzCCAqegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBkTELMAkGA1UEBhMCVVMx
EzARBgNVBAgMCkNhbGlmb3JuaWExETAPBgNVBAcMCFNhbiBKb3NlMRUwEwYDVQQK
DAxDYXZpdW0sIEluYy4xFzAVBgNVBAsMDkxpcXVpZFNlY3VyaXR5MSowKAYDVQQD
DCFsb2NhbGNhLmxpcXVpZHNlY3VyaXR5LmNhdml1bS5jb20wHhcNMjQwNzI1MjAy
OTIwWhcNMzQwNzIzMjAyOTIwWjCBkTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNh
bGlmb3JuaWExETAPBgNVBAcMCFNhbiBKb3NlMRUwEwYDVQQKDAxDYXZpdW0sIElu
Yy4xFzAVBgNVBAsMDkxpcXVpZFNlY3VyaXR5MSowKAYDVQQDDCFsb2NhbGNhLmxp
cXVpZHNlY3VyaXR5LmNhdml1bS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQDckvqQM4cvZjdyqOLGMTjKJwvfxJOhVqw6pojgUMz10VU7z3CtJrwH
cESwEDUxUkMxzof55kForURLaVVCjedYauEisnZwwSWkAemp9GREm8iX6BXtoZ8V
DWoO2H0AJiHCM62qJeZVXhm8A/zWG0PyLrCINH0yz9ah6BcwdsZGLvQvkpUNJhwV
Mrb9nI9BlRmTWhoot1YSTf7jfibEkc/pN+0Ez30RFaL3MhyIaNJS22+10tny4sOU
TsPEtXKah5mPlHpnrGcB18z5Yxgr0vDNYx+FCPGo95XGrq9NYfNMlwsSeFSr8D1V
Q7HZmipeTB1hQTUQw/K/Rmtw5NiljkYTAgMBAAGjIDAeMA4GA1UdDwEB/wQEAwIC
hDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCYlr7aeTnbRfPJGc5Q
5LEVreY91mp0e5KN331iG3DXQ6x07RMY4PPN+MvVgIPD21Ix6Xtp6Vj9VcsBpV7h
+6X69s79Ix8j0XV+6+AnrLuftjUjNw7iI9shOYa9aSTg/R6YpwwpXH+L3SZZ+VEF
yBg5gM7az0aJvuF48fSxNNwel11VC6xkrUFTuzI13GqYe+2rWhc/4TWvs1PpSzA0
K0W7KYFX2jhGi7H1uOrVneJiaVgD9bgIao/UaQabjlLT62wE9DegpdKPOHbIiQp5
XOV1rIP/pAWSSiyY7BB7c1acC/3ucDoSjTNUEsVIk3Zsm2jiUy0XC/rZTxaZkHaH
Bux7
-----END CERTIFICATE-----`

type Attestation struct {
Expand Down Expand Up @@ -111,10 +112,6 @@ const attestationSignatureSize = 256
// cryptoKeyVersionRx is the regular used to validate the key names.
var cryptoKeyVersionRx = regexp.MustCompile("^projects/([^/]+)/locations/([a-zA-Z0-9_-]{1,63})/keyRings/([a-zA-Z0-9_-]{1,63})/cryptoKeys/([a-zA-Z0-9_-]{1,63})/cryptoKeyVersions/([a-zA-Z0-9_-]{1,63})$")

// currentTime is the time used to validate certificates. The zero value will
// use the current time, but we can it for testing purposes.
var currentTime time.Time

// VerifyAttestation obtains and validates the attestation from an object in
// Cloud HSM.
//
Expand Down Expand Up @@ -317,9 +314,8 @@ func getIssuedCertificate(issuer *x509.Certificate, certs []*x509.Certificate, v
continue
}
if _, err := crt.Verify(x509.VerifyOptions{
Roots: roots,
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
CurrentTime: currentTime,
Roots: roots,
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
}); err == nil {
for _, fn := range validators {
if !fn(crt) {
Expand Down
25 changes: 3 additions & 22 deletions kms/cloudkms/attestation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,6 @@ import (
"go.step.sm/crypto/randutil"
)

func mustTime(t *testing.T) {
t.Helper()

currentTime = time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC)
t.Cleanup(func() {
currentTime = time.Time{}
})
}

func mustContent(t *testing.T, filename string) ([]byte, []AttestationAttribute, []AttestationAttribute) {
t.Helper()

Expand Down Expand Up @@ -210,8 +201,6 @@ func mustAsymmetricContentV1(t *testing.T, pub, priv []AttestationAttribute, key
}

func TestCloudKMS_VerifyAttestation(t *testing.T) {
mustTime(t)

ecContent, ecPub, ecPriv := mustContent(t, "testdata/ec.dat")
rsaContent, rsaPub, rsaPriv := mustContent(t, "testdata/rsa.dat")
aesContent, aesSym, _ := mustContent(t, "testdata/aes.dat")
Expand Down Expand Up @@ -313,8 +302,6 @@ func TestCloudKMS_VerifyAttestation(t *testing.T) {
}

func TestCloudKMS_verifyAttestation(t *testing.T) {
mustTime(t)

ca, err := minica.New()
require.NoError(t, err)
caRoot := string(pem.EncodeToMemory(&pem.Block{
Expand Down Expand Up @@ -743,18 +730,12 @@ func Test_getKeyType(t *testing.T) {

// TestValidateCaviumRoot validates that the current root certificate for the
// hard-coded root for Marvell's LiquidSecurity HSM adapters matches the one in
// this package. The current certificate expires on November 16, 2025. We will
// need to change it once Marvell changes it.
// this package.
func TestValidateCaviumRoot(t *testing.T) {
d := time.Date(2026, 3, 19, 7, 0, 0, 0, time.UTC)
if !time.Now().After(d) {
t.Skipf("skipping expired Cavium root test until %s", d.Format(time.RFC1123))
}

root, err := pemutil.ParseCertificate([]byte(caviumRoot))
require.NoError(t, err)

resp, err := http.Get("https://www.marvell.com/content/dam/marvell/en/public-collateral/security-solutions/liquid_security_certificate.zip")
resp, err := http.Get("https://www.marvell.com/content/dam/marvell/en/public-collateral/security-solutions/liquidsecurity-certificate-cnxxxxx-nfbe-x.0-g-v3.zip")
require.NoError(t, err)
t.Cleanup(func() {
assert.NoError(t, resp.Body.Close())
Expand All @@ -767,7 +748,7 @@ func TestValidateCaviumRoot(t *testing.T) {
require.NoError(t, err)

for _, f := range r.File {
if f.Name != "liquid_security_certificate.crt" {
if f.Name != "cavium_cert.crt" {
continue
}
rc, err := f.Open()
Expand Down