Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>com.uid2</groupId>
<artifactId>uid2-shared</artifactId>
<version>8.0.32</version>
<version>8.0.33-alpha-190-SNAPSHOT</version>
<name>${project.groupId}:${project.artifactId}</name>
<description>Library for all the shared uid2 operations</description>
<url>https://github.com/IABTechLab/uid2docs</url>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.uid2.shared.secure;

import com.uid2.shared.Utils;
import com.uid2.shared.secure.azurecc.IMaaTokenSignatureValidator;
import com.uid2.shared.secure.azurecc.IPolicyValidator;
import com.uid2.shared.secure.azurecc.MaaTokenSignatureValidator;
import com.uid2.shared.secure.azurecc.PolicyValidator;
import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

// CC stands for Confidential Container
@Slf4j
public class AzureCCAksCoreAttestationService extends AzureCCCoreAttestationServiceBase {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we actually need child classes for these? Could they just be one class that takes in the AZURE_CC_PROTOCOL?

private static final String AZURE_CC_PROTOCOL = "azure-cc-aks";

public AzureCCAksCoreAttestationService(String maaServerBaseUrl, String attestationUrl) {
super(new MaaTokenSignatureValidator(maaServerBaseUrl), new PolicyValidator(attestationUrl), AZURE_CC_PROTOCOL);
}

// used in UT
protected AzureCCAksCoreAttestationService(IMaaTokenSignatureValidator tokenSignatureValidator, IPolicyValidator policyValidator) {
super(tokenSignatureValidator, policyValidator, AZURE_CC_PROTOCOL);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,74 +17,15 @@

// CC stands for Confidential Container
@Slf4j
public class AzureCCCoreAttestationService implements ICoreAttestationService {

private final Set<String> allowedEnclaveIds = new HashSet<>();

private final IMaaTokenSignatureValidator tokenSignatureValidator;

private final IPolicyValidator policyValidator;
public class AzureCCCoreAttestationService extends AzureCCCoreAttestationServiceBase {
private static final String AZURE_CC_PROTOCOL = "azure-cc";

public AzureCCCoreAttestationService(String maaServerBaseUrl, String attestationUrl) {
this(new MaaTokenSignatureValidator(maaServerBaseUrl), new PolicyValidator(attestationUrl));
super(new MaaTokenSignatureValidator(maaServerBaseUrl), new PolicyValidator(attestationUrl), AZURE_CC_PROTOCOL);
}

// used in UT
protected AzureCCCoreAttestationService(IMaaTokenSignatureValidator tokenSignatureValidator, IPolicyValidator policyValidator) {
this.tokenSignatureValidator = tokenSignatureValidator;
this.policyValidator = policyValidator;
}

@Override
public void attest(byte[] attestationRequest, byte[] publicKey, Handler<AsyncResult<AttestationResult>> handler) {
try {
var tokenString = new String(attestationRequest, StandardCharsets.US_ASCII);

log.debug("Validating signature...");
var tokenPayload = tokenSignatureValidator.validate(tokenString);

log.debug("Validating policy...");
var encodedPublicKey = Utils.toBase64String(publicKey);

var enclaveId = policyValidator.validate(tokenPayload, encodedPublicKey);

if (allowedEnclaveIds.contains(enclaveId)) {
log.info("Successfully attested azure-cc against registered enclaves, enclave id: " + enclaveId);
handler.handle(Future.succeededFuture(new AttestationResult(publicKey, enclaveId)));
} else {
log.warn("Got unsupported azure-cc enclave id: " + enclaveId);
handler.handle(Future.succeededFuture(new AttestationResult(AttestationFailure.FORBIDDEN_ENCLAVE)));
}
}
catch (AttestationClientException ace){
handler.handle(Future.succeededFuture(new AttestationResult(ace)));
} catch (AttestationException ae) {
handler.handle(Future.failedFuture(ae));
} catch (Exception ex) {
handler.handle(Future.failedFuture(new AttestationException(ex)));
}
}

@Override
public void registerEnclave(String encodedIdentifier) throws AttestationException {
try {
allowedEnclaveIds.add(encodedIdentifier);
} catch (Exception e) {
throw new AttestationException(e);
}
}

@Override
public void unregisterEnclave(String encodedIdentifier) throws AttestationException {
try {
allowedEnclaveIds.remove(encodedIdentifier);
} catch (Exception e) {
throw new AttestationException(e);
}
}

@Override
public Collection<String> getEnclaveAllowlist() {
return allowedEnclaveIds;
super(tokenSignatureValidator, policyValidator, AZURE_CC_PROTOCOL);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.uid2.shared.secure;

import com.uid2.shared.Utils;
import com.uid2.shared.secure.azurecc.IMaaTokenSignatureValidator;
import com.uid2.shared.secure.azurecc.IPolicyValidator;
import com.uid2.shared.secure.azurecc.MaaTokenSignatureValidator;
import com.uid2.shared.secure.azurecc.PolicyValidator;
import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

// CC stands for Confidential Container
@Slf4j
public abstract class AzureCCCoreAttestationServiceBase implements ICoreAttestationService {

protected final Set<String> allowedEnclaveIds = new HashSet<>();

protected final IMaaTokenSignatureValidator tokenSignatureValidator;

protected final IPolicyValidator policyValidator;

protected final String azureCcProtocol;

protected AzureCCCoreAttestationServiceBase(IMaaTokenSignatureValidator tokenSignatureValidator, IPolicyValidator policyValidator, String azureCcProtocol) {
this.tokenSignatureValidator = tokenSignatureValidator;
this.policyValidator = policyValidator;
this.azureCcProtocol = azureCcProtocol;
}

public void attest(byte[] attestationRequest, byte[] publicKey, Handler<AsyncResult<AttestationResult>> handler) {
try {
var tokenString = new String(attestationRequest, StandardCharsets.US_ASCII);

log.debug("Validating signature...");
var tokenPayload = tokenSignatureValidator.validate(tokenString, azureCcProtocol);

log.debug("Validating policy...");
var encodedPublicKey = Utils.toBase64String(publicKey);

var enclaveId = policyValidator.validate(tokenPayload, encodedPublicKey);

if (allowedEnclaveIds.contains(enclaveId)) {
log.info("Successfully attested " + azureCcProtocol + " against registered enclaves, enclave id: " + enclaveId);
handler.handle(Future.succeededFuture(new AttestationResult(publicKey, enclaveId)));
} else {
log.warn("Got unsupported " + azureCcProtocol + " enclave id: " + enclaveId);
handler.handle(Future.succeededFuture(new AttestationResult(AttestationFailure.FORBIDDEN_ENCLAVE)));
}
}
catch (AttestationClientException ace){
handler.handle(Future.succeededFuture(new AttestationResult(ace)));
} catch (AttestationException ae) {
handler.handle(Future.failedFuture(ae));
} catch (Exception ex) {
handler.handle(Future.failedFuture(new AttestationException(ex)));
}
};

public void registerEnclave(String encodedIdentifier) throws AttestationException {
try {
allowedEnclaveIds.add(encodedIdentifier);
} catch (Exception e) {
throw new AttestationException(e);
}
}

public void unregisterEnclave(String encodedIdentifier) throws AttestationException {
try {
allowedEnclaveIds.remove(encodedIdentifier);
} catch (Exception e) {
throw new AttestationException(e);
}
}

public Collection<String> getEnclaveAllowlist() {
return allowedEnclaveIds;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ public interface IMaaTokenSignatureValidator {
* @return Parsed token payload.
* @throws AttestationException
*/
MaaTokenPayload validate(String tokenString) throws AttestationException;
MaaTokenPayload validate(String tokenString, String protocol) throws AttestationException;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we introduce an enum for the protocols instead of using a String?

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,14 @@
@Builder(toBuilder = true)
public class MaaTokenPayload {
public static final String SEV_SNP_VM_TYPE = "sevsnpvm";
public static final String AZURE_CC_PROTOCOL = "azure-cc";
public static final String AZURE_CC_AKS_PROTOCOL = "azure-cc-aks";
// the `x-ms-compliance-status` value for ACI CC
public static final String AZURE_COMPLIANT_UVM = "azure-compliant-uvm";
// the `x-ms-compliance-status` value for AKS CC
public static final String AZURE_COMPLIANT_UVM_AKS = "azure-signed-katacc-uvm";

private String azureProtocol;
private String attestationType;
private String complianceStatus;
private boolean vmDebuggable;
Expand All @@ -21,6 +27,11 @@ public boolean isSevSnpVM(){
}

public boolean isUtilityVMCompliant(){
return AZURE_COMPLIANT_UVM.equalsIgnoreCase(complianceStatus);
if (azureProtocol == AZURE_CC_PROTOCOL) {
return AZURE_COMPLIANT_UVM.equalsIgnoreCase(complianceStatus);
} else if (azureProtocol == AZURE_CC_AKS_PROTOCOL) {
return AZURE_COMPLIANT_UVM_AKS.equalsIgnoreCase(complianceStatus);
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
import static com.uid2.shared.secure.JwtUtils.tryGetField;

public class MaaTokenSignatureValidator implements IMaaTokenSignatureValidator {

// set to true to facilitate local test.
public static final boolean BYPASS_SIGNATURE_CHECK = false;

Expand Down Expand Up @@ -52,7 +51,7 @@ private TokenVerifier buildTokenVerifier(String kid) throws AttestationException
}

@Override
public MaaTokenPayload validate(String tokenString) throws AttestationException {
public MaaTokenPayload validate(String tokenString, String protocol) throws AttestationException {
if (Strings.isNullOrEmpty(tokenString)) {
throw new IllegalArgumentException("tokenString can not be null or empty");
}
Expand All @@ -77,6 +76,7 @@ public MaaTokenPayload validate(String tokenString) throws AttestationException

var tokenPayloadBuilder = MaaTokenPayload.builder();

tokenPayloadBuilder.azureProtocol(protocol);
tokenPayloadBuilder.attestationType(tryGetField(rawPayload, "x-ms-attestation-type", String.class));
tokenPayloadBuilder.complianceStatus(tryGetField(rawPayload, "x-ms-compliance-status", String.class));
tokenPayloadBuilder.vmDebuggable(tryGetField(rawPayload, "x-ms-sevsnpvm-is-debuggable", Boolean.class));
Expand Down
Loading