All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.uid2.shared.secure.GcpVmidCoreAttestationService Maven / Gradle / Ivy

package com.uid2.shared.secure;

import com.google.auth.oauth2.GoogleCredentials;
import com.uid2.shared.Utils;
import com.uid2.shared.secure.gcp.VmConfigId;
import com.uid2.shared.secure.gcp.VmConfigVerifier;
import com.uid2.shared.secure.gcp.InstanceDocument;
import com.uid2.shared.secure.gcp.InstanceDocumentVerifier;
import io.grpc.LoadBalancerRegistry;
import io.grpc.internal.PickFirstLoadBalancerProvider;
import io.vertx.core.AsyncResult;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.nio.charset.StandardCharsets;
import java.util.*;

public class GcpVmidCoreAttestationService implements ICoreAttestationService {
    private static final Logger LOGGER = LoggerFactory.getLogger(GcpVmidCoreAttestationService.class);

    private final InstanceDocumentVerifier idVerifier = new InstanceDocumentVerifier();
    private final VmConfigVerifier vmConfigVerifier;
    private final Set allowedVmConfigIds = new HashSet<>();

    public GcpVmidCoreAttestationService(GoogleCredentials credentials, Set enclaveParams) throws Exception {
        LoadBalancerRegistry.getDefaultRegistry().register(new PickFirstLoadBalancerProvider());
        this.vmConfigVerifier = new VmConfigVerifier(credentials, enclaveParams);
        LOGGER.info("Using Google Service Account: " + credentials.toString());
    }

    @Override
    public void attest(byte[] attestationRequest, byte[] publicKey, Handler> handler) {
        // check instance document
        final InstanceDocument vmid;
        try {
            String request = new String(attestationRequest, StandardCharsets.US_ASCII);
            vmid = idVerifier.verify(request);
        }
        catch (Exception ex) {
            handler.handle(Future.failedFuture(new AttestationException(ex)));
            return;
        }

        LOGGER.debug("Validating Instance Confidentiality...");
        if (!vmid.getInstanceConfidentiality()) {
            // return attestation failure for non-confidential-vm
            handler.handle(Future.failedFuture(new AttestationException("not on confidential vm")));
            return;
        }

        LOGGER.debug("Validating client public key...");
        // check client public key matches audience in instance document
        try {
            byte[] signedPubKey = Utils.decodeBase64String(vmid.getAudience());
            if (!Arrays.equals(signedPubKey, publicKey)) {
                handler.handle(Future.failedFuture(new AttestationException("Invalid or mismatched client public key")));
                return;
            }
        }
        catch (Exception ex) {
            handler.handle(Future.failedFuture(new AttestationException(ex)));
            return;
        }

        // extract vmConfigId using information from instance document
        LOGGER.debug("Validating VmConfig...");
        final VmConfigId vmConfigId;
        try {
            vmConfigId = vmConfigVerifier.getVmConfigId(vmid);
        }
        catch (Exception ex) {
            handler.handle(Future.failedFuture(new AttestationException(ex)));
            return;
        }

        // check if vmConfigId is approved/allowed
        if (!vmConfigId.isValid()) {
            final String errorMessage = vmConfigId.getProjectId() == null ?
                    vmConfigId.getFailedReason() :
                    vmConfigId.getProjectId() + " @ " + vmConfigId.getFailedReason();
            handler.handle(Future.failedFuture(new AttestationException(errorMessage)));
            return;
        }

        LOGGER.debug("VmConfigId = " + vmConfigId + ", validating against " + allowedVmConfigIds.size() + " registered enclaves");
        if (VmConfigVerifier.VALIDATE_VMCONFIG && !allowedVmConfigIds.contains(vmConfigId.getValue())) {
            handler.handle(Future.failedFuture(new AttestationException("unauthorized vmConfigId")));
            return;
        } else if (!VmConfigVerifier.VALIDATE_VMCONFIG) {
            LOGGER.error("Skip VmConfig validation (VALIDATE_VMCONFIG off)...");
        }

        LOGGER.debug("Successfully attested VmConfigId against registered enclaves");

        // return successful attestation with public key if all above checks pass
        AttestationResult result = new AttestationResult(publicKey, vmConfigId.getValue());
        handler.handle(Future.succeededFuture(result));
    }

    @Override
    public void registerEnclave(String vmConfigId) throws AttestationException {
        try {
            allowedVmConfigIds.add(vmConfigId);
        } catch (Exception e) {
            LOGGER.error("registerEnclave", e);
            throw new AttestationException(e);
        }
    }

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

    @Override
    public Collection getEnclaveAllowlist() {
        return allowedVmConfigIds;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy