diff --git a/pom.xml b/pom.xml
index eeb5e064..200c8aad 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
com.uid2
uid2-shared
- 8.0.32
+ 8.0.34-alpha-191-SNAPSHOT
${project.groupId}:${project.artifactId}
Library for all the shared uid2 operations
https://github.com/IABTechLab/uid2docs
diff --git a/src/main/java/com/uid2/shared/secure/AzureCCCoreAttestationService.java b/src/main/java/com/uid2/shared/secure/AzureCCCoreAttestationService.java
index ae44ef79..417f5e32 100644
--- a/src/main/java/com/uid2/shared/secure/AzureCCCoreAttestationService.java
+++ b/src/main/java/com/uid2/shared/secure/AzureCCCoreAttestationService.java
@@ -25,14 +25,17 @@ public class AzureCCCoreAttestationService implements ICoreAttestationService {
private final IPolicyValidator policyValidator;
- public AzureCCCoreAttestationService(String maaServerBaseUrl, String attestationUrl) {
- this(new MaaTokenSignatureValidator(maaServerBaseUrl), new PolicyValidator(attestationUrl));
+ private final String azureCcProtocol;
+
+ public AzureCCCoreAttestationService(String maaServerBaseUrl, String attestationUrl, String azureCcProtocol) {
+ this(new MaaTokenSignatureValidator(maaServerBaseUrl), new PolicyValidator(attestationUrl), azureCcProtocol);
}
// used in UT
- protected AzureCCCoreAttestationService(IMaaTokenSignatureValidator tokenSignatureValidator, IPolicyValidator policyValidator) {
+ protected AzureCCCoreAttestationService(IMaaTokenSignatureValidator tokenSignatureValidator, IPolicyValidator policyValidator, String azureCcProtocol) {
this.tokenSignatureValidator = tokenSignatureValidator;
this.policyValidator = policyValidator;
+ this.azureCcProtocol = azureCcProtocol;
}
@Override
@@ -40,8 +43,9 @@ public void attest(byte[] attestationRequest, byte[] publicKey, Handler {
assertTrue(ar.succeeded());
@@ -69,11 +75,12 @@ public void testHappyPath() throws AttestationException {
});
}
- @Test
- public void testSignatureCheckFailed_ClientError() throws AttestationException {
+ @ParameterizedTest
+ @MethodSource("argumentProvider")
+ public void testSignatureCheckFailed_ClientError(String azureProtocol) throws AttestationException {
var errorStr = "token signature validation failed";
- when(alwaysFailTokenValidator.validate(any())).thenThrow(new AttestationClientException(errorStr, AttestationFailure.BAD_PAYLOAD));
- var provider = new AzureCCCoreAttestationService(alwaysFailTokenValidator, alwaysPassPolicyValidator);
+ when(alwaysFailTokenValidator.validate(any(), any())).thenThrow(new AttestationClientException(errorStr, AttestationFailure.BAD_PAYLOAD));
+ var provider = new AzureCCCoreAttestationService(alwaysFailTokenValidator, alwaysPassPolicyValidator, azureProtocol);
provider.registerEnclave(ENCLAVE_ID);
attest(provider, ar -> {
assertTrue(ar.succeeded());
@@ -82,10 +89,11 @@ public void testSignatureCheckFailed_ClientError() throws AttestationException {
});
}
- @Test
- public void testSignatureCheckFailed_ServerError() throws AttestationException {
- when(alwaysFailTokenValidator.validate(any())).thenThrow(new AttestationException("unknown server error"));
- var provider = new AzureCCCoreAttestationService(alwaysFailTokenValidator, alwaysPassPolicyValidator);
+ @ParameterizedTest
+ @MethodSource("argumentProvider")
+ public void testSignatureCheckFailed_ServerError(String azureProtocol) throws AttestationException {
+ when(alwaysFailTokenValidator.validate(any(), any())).thenThrow(new AttestationException("unknown server error"));
+ var provider = new AzureCCCoreAttestationService(alwaysFailTokenValidator, alwaysPassPolicyValidator, azureProtocol);
provider.registerEnclave(ENCLAVE_ID);
attest(provider, ar -> {
assertFalse(ar.succeeded());
@@ -93,11 +101,12 @@ public void testSignatureCheckFailed_ServerError() throws AttestationException {
});
}
- @Test
- public void testPolicyCheckSuccess_ClientError() throws AttestationException {
+ @ParameterizedTest
+ @MethodSource("argumentProvider")
+ public void testPolicyCheckSuccess_ClientError(String azureProtocol) throws AttestationException {
var errorStr = "policy validation failed";
when(alwaysFailPolicyValidator.validate(any(), any())).thenThrow(new AttestationClientException(errorStr, AttestationFailure.BAD_PAYLOAD));
- var provider = new AzureCCCoreAttestationService(alwaysFailTokenValidator, alwaysFailPolicyValidator);
+ var provider = new AzureCCCoreAttestationService(alwaysFailTokenValidator, alwaysFailPolicyValidator, azureProtocol);
provider.registerEnclave(ENCLAVE_ID);
attest(provider, ar -> {
assertTrue(ar.succeeded());
@@ -106,10 +115,11 @@ public void testPolicyCheckSuccess_ClientError() throws AttestationException {
});
}
- @Test
- public void testPolicyCheckFailed_ServerError() throws AttestationException {
+ @ParameterizedTest
+ @MethodSource("argumentProvider")
+ public void testPolicyCheckFailed_ServerError(String azureProtocol) throws AttestationException {
when(alwaysFailPolicyValidator.validate(any(), any())).thenThrow(new AttestationException("unknown server error"));
- var provider = new AzureCCCoreAttestationService(alwaysFailTokenValidator, alwaysFailPolicyValidator);
+ var provider = new AzureCCCoreAttestationService(alwaysFailTokenValidator, alwaysFailPolicyValidator, azureProtocol);
provider.registerEnclave(ENCLAVE_ID);
attest(provider, ar -> {
assertFalse(ar.succeeded());
@@ -117,9 +127,10 @@ public void testPolicyCheckFailed_ServerError() throws AttestationException {
});
}
- @Test
- public void testEnclaveNotRegistered() throws AttestationException {
- var provider = new AzureCCCoreAttestationService(alwaysFailTokenValidator, alwaysPassPolicyValidator);
+ @ParameterizedTest
+ @MethodSource("argumentProvider")
+ public void testEnclaveNotRegistered(String azureProtocol) throws AttestationException {
+ var provider = new AzureCCCoreAttestationService(alwaysFailTokenValidator, alwaysPassPolicyValidator, azureProtocol);
attest(provider, ar -> {
assertTrue(ar.succeeded());
assertFalse(ar.result().isSuccess());
@@ -133,4 +144,11 @@ private static void attest(ICoreAttestationService provider, Handler argumentProvider() {
+ return Stream.of(
+ Arguments.of(MaaTokenPayload.AZURE_CC_ACI_PROTOCOL),
+ Arguments.of(MaaTokenPayload.AZURE_CC_AKS_PROTOCOL)
+ );
+ }
}
diff --git a/src/test/java/com/uid2/shared/secure/azurecc/MaaTokenSignatureValidatorTest.java b/src/test/java/com/uid2/shared/secure/azurecc/MaaTokenSignatureValidatorTest.java
index a5d9257f..e932d1f5 100644
--- a/src/test/java/com/uid2/shared/secure/azurecc/MaaTokenSignatureValidatorTest.java
+++ b/src/test/java/com/uid2/shared/secure/azurecc/MaaTokenSignatureValidatorTest.java
@@ -3,17 +3,21 @@
import com.uid2.shared.secure.AttestationException;
import com.uid2.shared.secure.TestClock;
import org.junit.jupiter.api.Disabled;
-import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.stream.Stream;
import static com.uid2.shared.secure.TestUtils.loadFromJson;
import static com.uid2.shared.secure.azurecc.MaaTokenUtils.validateAndParseToken;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class MaaTokenSignatureValidatorTest {
- @Test
- public void testPayload() throws Exception {
+ @ParameterizedTest
+ @MethodSource("argumentProvider")
+ public void testPayload(String payloadPath, String protocol) throws Exception {
// expire at 1695313895
- var payloadPath = "/com.uid2.shared/test/secure/azurecc/jwt_payload.json";
var payload = loadFromJson(payloadPath);
var clock = new TestClock();
clock.setCurrentTimeMs(1695313893000L);
@@ -22,7 +26,7 @@ public void testPayload() throws Exception {
var expectedLocation = "East US";
var expectedPublicKey = "abc";
- var tokenPayload = validateAndParseToken(payload, clock);
+ var tokenPayload = validateAndParseToken(payload, clock, protocol);
assertEquals(true, tokenPayload.isSevSnpVM());
assertEquals(true, tokenPayload.isUtilityVMCompliant());
assertEquals(false, tokenPayload.isVmDebuggable());
@@ -37,6 +41,13 @@ public void testE2E() throws AttestationException {
var maaToken = "";
var maaServerUrl = "https://sharedeus.eus.attest.azure.net";
var validator = new MaaTokenSignatureValidator(maaServerUrl);
- var token = validator.validate(maaToken);
+ var token = validator.validate(maaToken, MaaTokenPayload.AZURE_CC_ACI_PROTOCOL);
+ }
+
+ static Stream argumentProvider() {
+ return Stream.of(
+ Arguments.of("/com.uid2.shared/test/secure/azurecc/jwt_payload_aci.json", MaaTokenPayload.AZURE_CC_ACI_PROTOCOL),
+ Arguments.of("/com.uid2.shared/test/secure/azurecc/jwt_payload_aks.json", MaaTokenPayload.AZURE_CC_AKS_PROTOCOL)
+ );
}
}
diff --git a/src/test/java/com/uid2/shared/secure/azurecc/MaaTokenUtils.java b/src/test/java/com/uid2/shared/secure/azurecc/MaaTokenUtils.java
index 48d1335e..82714b1e 100644
--- a/src/test/java/com/uid2/shared/secure/azurecc/MaaTokenUtils.java
+++ b/src/test/java/com/uid2/shared/secure/azurecc/MaaTokenUtils.java
@@ -14,7 +14,7 @@
public class MaaTokenUtils {
public static final String MAA_BASE_URL = "https://sharedeus.eus.attest.azure.net";
- public static MaaTokenPayload validateAndParseToken(JsonObject payload, Clock clock) throws Exception{
+ public static MaaTokenPayload validateAndParseToken(JsonObject payload, Clock clock, String protocol) throws Exception{
var gen = KeyPairGenerator.getInstance(Const.Name.AsymetricEncryptionKeyClass);
gen.initialize(2048, new SecureRandom());
var keyPair = gen.generateKeyPair();
@@ -30,7 +30,7 @@ public static MaaTokenPayload validateAndParseToken(JsonObject payload, Clock cl
var tokenVerifier = new MaaTokenSignatureValidator(MAA_BASE_URL, keyProvider, clock);
// validate token
- return tokenVerifier.validate(token);
+ return tokenVerifier.validate(token, protocol);
}
private static class MockKeyProvider implements IPublicKeyProvider {
diff --git a/src/test/java/com/uid2/shared/secure/azurecc/PolicyValidatorTest.java b/src/test/java/com/uid2/shared/secure/azurecc/PolicyValidatorTest.java
index 59c3630b..9e4cde11 100644
--- a/src/test/java/com/uid2/shared/secure/azurecc/PolicyValidatorTest.java
+++ b/src/test/java/com/uid2/shared/secure/azurecc/PolicyValidatorTest.java
@@ -97,6 +97,7 @@ private MaaTokenPayload generateBasicPayload() {
.vmDebuggable(false)
.runtimeData(generateBasicRuntimeData())
.ccePolicyDigest(CCE_POLICY_DIGEST)
+ .azureProtocol(MaaTokenPayload.AZURE_CC_ACI_PROTOCOL)
.build();
}
@@ -125,4 +126,53 @@ public void testValidationFailure_DifferentAttestationUrl() {
assertEquals(AttestationFailure.UNKNOWN_ATTESTATION_URL, ((AttestationClientException)t).getAttestationFailure());
}
+
+ @Test
+ public void testValidationFailure_AzureCcWithOtherUvm() {
+ var validator = new PolicyValidator(ATTESTATION_URL);
+ var aksPayload = generateBasicPayload()
+ .toBuilder()
+ .complianceStatus("fake-compliance")
+ .build();
+ Throwable t = assertThrows(AttestationException.class, ()-> validator.validate(aksPayload, PUBLIC_KEY));
+ assertEquals("Not run in Azure Compliance Utility VM", t.getMessage());
+ assertEquals(AttestationFailure.BAD_FORMAT, ((AttestationClientException)t).getAttestationFailure());
+ }
+
+ @Test
+ public void testValidationSuccess_AksWithAzureSignedKataccUvm() throws AttestationClientException {
+ var validator = new PolicyValidator(ATTESTATION_URL);
+ var aksPayload = generateBasicPayload()
+ .toBuilder()
+ .complianceStatus("azure-signed-katacc-uvm")
+ .azureProtocol(MaaTokenPayload.AZURE_CC_AKS_PROTOCOL)
+ .build();
+ var enclaveId = validator.validate(aksPayload, PUBLIC_KEY);
+ assertEquals(CCE_POLICY_DIGEST, enclaveId);
+ }
+
+ @Test
+ public void testValidationFailure_AksWithOtherUvm() {
+ var validator = new PolicyValidator(ATTESTATION_URL);
+ var aksPayload = generateBasicPayload()
+ .toBuilder()
+ .complianceStatus("fake-compliance")
+ .azureProtocol(MaaTokenPayload.AZURE_CC_AKS_PROTOCOL)
+ .build();
+ Throwable t = assertThrows(AttestationException.class, ()-> validator.validate(aksPayload, PUBLIC_KEY));
+ assertEquals("Not run in Azure Compliance Utility VM", t.getMessage());
+ assertEquals(AttestationFailure.BAD_FORMAT, ((AttestationClientException)t).getAttestationFailure());
+ }
+
+ @Test
+ public void testValidationFailure_InvalidProtocol() {
+ var validator = new PolicyValidator(ATTESTATION_URL);
+ var aksPayload = generateBasicPayload()
+ .toBuilder()
+ .azureProtocol("fake-protocol")
+ .build();
+ Throwable t = assertThrows(AttestationException.class, ()-> validator.validate(aksPayload, PUBLIC_KEY));
+ assertEquals("Azure protocol: fake-protocol not supported", t.getMessage());
+ assertEquals(AttestationFailure.INVALID_PROTOCOL, ((AttestationClientException)t).getAttestationFailure());
+ }
}
diff --git a/src/test/resources/com.uid2.shared/test/secure/azurecc/jwt_payload.json b/src/test/resources/com.uid2.shared/test/secure/azurecc/jwt_payload_aci.json
similarity index 100%
rename from src/test/resources/com.uid2.shared/test/secure/azurecc/jwt_payload.json
rename to src/test/resources/com.uid2.shared/test/secure/azurecc/jwt_payload_aci.json
diff --git a/src/test/resources/com.uid2.shared/test/secure/azurecc/jwt_payload_aks.json b/src/test/resources/com.uid2.shared/test/secure/azurecc/jwt_payload_aks.json
new file mode 100644
index 00000000..4a744ee3
--- /dev/null
+++ b/src/test/resources/com.uid2.shared/test/secure/azurecc/jwt_payload_aks.json
@@ -0,0 +1,41 @@
+{
+ "exp": 1695313895,
+ "iat": 1695285095,
+ "iss": "https://sharedeus.eus.attest.azure.net",
+ "jti": "3b16f2ab4492417aae4cc9a5e6506ca2519659c0d8fdc2bf442fe01aa9b8e46c",
+ "nbf": 1695285095,
+ "nonce": "7394904505194784658",
+ "x-ms-attestation-type": "sevsnpvm",
+ "x-ms-compliance-status": "azure-signed-katacc-uvm",
+ "x-ms-policy-hash": "9NY0VnTQ-IiBriBplVUpFbczcDaEBUwsiFYAzHu_gco",
+ "x-ms-runtime": {
+ "location": "East US",
+ "publicKey": "abc"
+ },
+ "x-ms-sevsnpvm-authorkeydigest": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "x-ms-sevsnpvm-bootloader-svn": 3,
+ "x-ms-sevsnpvm-familyId": "01000000000000000000000000000000",
+ "x-ms-sevsnpvm-guestsvn": 2,
+ "x-ms-sevsnpvm-hostdata": "fef932e0103f6132437e8a1223f32efc4bea63342f893b5124645224ef29ba73",
+ "x-ms-sevsnpvm-idkeydigest": "ebeeeabce075eeaba3d9ea24d8495137a2877c0d20ac6ea73fc6d2f8aeb50de132150e0a0752664919bcebbf2e8c5807",
+ "x-ms-sevsnpvm-imageId": "02000000000000000000000000000000",
+ "x-ms-sevsnpvm-is-debuggable": false,
+ "x-ms-sevsnpvm-launchmeasurement": "03fea02823189b25d0623a5c81f97c8ba4d2fbc48c914a55ce525f90454ddcec303743dac2fc013f0846912d1412f6df",
+ "x-ms-sevsnpvm-microcode-svn": 115,
+ "x-ms-sevsnpvm-migration-allowed": false,
+ "x-ms-sevsnpvm-reportdata": "4e7d4a413745ddea79f05d20d9ac7add3659ac783ef24684127bbbb3e50fc63c0000000000000000000000000000000000000000000000000000000000000000",
+ "x-ms-sevsnpvm-reportid": "d137a83c2d42d81dd42d39ad95ef9023de63216ddaaf2c368a8c41a636ddb2a9",
+ "x-ms-sevsnpvm-smt-allowed": true,
+ "x-ms-sevsnpvm-snpfw-svn": 8,
+ "x-ms-sevsnpvm-tee-svn": 0,
+ "x-ms-sevsnpvm-uvm-endorsement": {
+ "x-ms-sevsnpvm-guestsvn": "100",
+ "x-ms-sevsnpvm-launchmeasurement": "03fea02823189b25d0623a5c81f97c8ba4d2fbc48c914a55ce525f90454ddcec303743dac2fc013f0846912d1412f6df"
+ },
+ "x-ms-sevsnpvm-uvm-endorsement-headers": {
+ "feed": "ContainerPlat-AMD-UVM",
+ "iss": "did:x509:0:sha256:I__iuL25oXEVFdTP_aBLx_eT1RPHbCQ_ECBQfYZpt9s::eku:1.3.6.1.4.1.311.76.59.1.2"
+ },
+ "x-ms-sevsnpvm-vmpl": 0,
+ "x-ms-ver": "1.0"
+}