Implementing LDevID generation

This commit is contained in:
iadgovuser59 2024-07-19 18:31:56 -04:00
parent 19d3bdd1ac
commit 69c673adb7
21 changed files with 253 additions and 34 deletions

View File

@ -114,7 +114,7 @@ public abstract class AttestationCertificateAuthority {
this.certificateRequestHandler = new CertificateRequestProcessor(supplyChainValidationService,
certificateRepository, deviceRepository,
privateKey, acaCertificate, validDays, tpm2ProvisionerStateRepository);
privateKey, acaCertificate, validDays, tpm2ProvisionerStateRepository, policyRepository);
this.identityClaimHandler = new IdentityClaimProcessor(supplyChainValidationService,
certificateRepository, componentResultRepository, componentInfoRepository,
referenceManifestRepository, referenceDigestValueRepository,

View File

@ -4,6 +4,7 @@ import hirs.attestationca.persist.entity.userdefined.Certificate;
import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.IssuedAttestationCertificate;
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
@ -35,5 +36,6 @@ public interface CertificateRepository extends JpaRepository<Certificate, UUID>
Certificate findByCertificateHash(int certificateHash, String dType);
EndorsementCredential findByPublicKeyModulusHexValue(String publicKeyModulusHexValue);
IssuedAttestationCertificate findByDeviceId(UUID deviceId);
List<IssuedAttestationCertificate> findByDeviceIdAndIsLDevID(UUID deviceId, boolean isLDevID, Sort sort);
Certificate findByCertificateHash(int certificateHash);
}

View File

@ -1,5 +1,6 @@
package hirs.attestationca.persist.entity.userdefined.certificate;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.JoinColumn;
@ -35,6 +36,9 @@ public class IssuedAttestationCertificate extends DeviceAssociatedCertificate {
@JoinColumn(name = "pc_id")
private List<PlatformCredential> platformCredentials;
@Column
public boolean isLDevID;
/**
* Constructor.
* @param certificateBytes the issued certificate bytes
@ -44,11 +48,12 @@ public class IssuedAttestationCertificate extends DeviceAssociatedCertificate {
*/
public IssuedAttestationCertificate(final byte[] certificateBytes,
final EndorsementCredential endorsementCredential,
final List<PlatformCredential> platformCredentials)
final List<PlatformCredential> platformCredentials, boolean isLDevID)
throws IOException {
super(certificateBytes);
this.endorsementCredential = endorsementCredential;
this.platformCredentials = new ArrayList<>(platformCredentials);
this.isLDevID = isLDevID;
}
/**
@ -60,9 +65,10 @@ public class IssuedAttestationCertificate extends DeviceAssociatedCertificate {
*/
public IssuedAttestationCertificate(final Path certificatePath,
final EndorsementCredential endorsementCredential,
final List<PlatformCredential> platformCredentials)
final List<PlatformCredential> platformCredentials,
final boolean isLDevID)
throws IOException {
this(readBytes(certificatePath), endorsementCredential, platformCredentials);
this(readBytes(certificatePath), endorsementCredential, platformCredentials, isLDevID);
}
public List<PlatformCredential> getPlatformCredentials() {

View File

@ -9,6 +9,7 @@ import hirs.attestationca.persist.entity.userdefined.Device;
import hirs.attestationca.persist.entity.userdefined.PolicySettings;
import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.IssuedAttestationCertificate;
import hirs.attestationca.persist.entity.userdefined.certificate.IssuedLDevIDCertificate;
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
import hirs.attestationca.persist.exceptions.CertificateProcessingException;
import hirs.attestationca.persist.provision.helper.CredentialManagementHelper;
@ -27,6 +28,7 @@ import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.springframework.data.domain.Sort;
import java.io.IOException;
import java.math.BigInteger;
@ -234,6 +236,7 @@ public class AbstractProcessor {
* @param endorsementCredential the endorsement credential used to generate the AC
* @param platformCredentials the platform credentials used to generate the AC
* @param device the device to which the attestation certificate is tied
* @param isLDevID whether the certificate is a ldevid
* @throws {@link CertificateProcessingException} if error occurs in persisting the Attestation
* Certificate
*/
@ -241,8 +244,8 @@ public class AbstractProcessor {
final byte[] derEncodedAttestationCertificate,
final EndorsementCredential endorsementCredential,
final List<PlatformCredential> platformCredentials,
final Device device) {
IssuedAttestationCertificate issuedAc;
final Device device, boolean isLDevID) {
List<IssuedAttestationCertificate> issuedAc;
boolean generateCertificate = true;
PolicyRepository scp = getPolicyRepository();
PolicySettings policySettings;
@ -251,19 +254,25 @@ public class AbstractProcessor {
try {
// save issued certificate
IssuedAttestationCertificate attCert = new IssuedAttestationCertificate(
derEncodedAttestationCertificate, endorsementCredential, platformCredentials);
derEncodedAttestationCertificate, endorsementCredential, platformCredentials, isLDevID);
if (scp != null) {
policySettings = scp.findByName("Default");
issuedAc = certificateRepository.findByDeviceId(device.getId());
generateCertificate = policySettings.isIssueAttestationCertificate();
if (issuedAc != null && policySettings.isGenerateOnExpiration()) {
if (issuedAc.getEndValidity().after(currentDate)) {
Sort sortCriteria = Sort.by(Sort.Direction.DESC, "endValidity");
issuedAc = certificateRepository.findByDeviceIdAndIsLDevID(device.getId(), isLDevID, sortCriteria);
generateCertificate = isLDevID ? policySettings.isIssueDevIdCertificate()
: policySettings.isIssueAttestationCertificate();
if (issuedAc != null && (isLDevID ? policySettings.isDevIdExpirationFlag()
: policySettings.isGenerateOnExpiration())) {
if (issuedAc.get(0).getEndValidity().after(currentDate)) {
// so the issued AC is not expired
// however are we within the threshold
days = ProvisionUtils.daysBetween(currentDate, issuedAc.getEndValidity());
if (days < Integer.parseInt(policySettings.getReissueThreshold())) {
days = ProvisionUtils.daysBetween(currentDate, issuedAc.get(0).getEndValidity());
if (days < Integer.parseInt(isLDevID ? policySettings.getDevIdReissueThreshold()
: policySettings.getReissueThreshold())) {
generateCertificate = true;
} else {
generateCertificate = false;
@ -271,6 +280,7 @@ public class AbstractProcessor {
}
}
}
if (generateCertificate) {
attCert.setDeviceId(device.getId());
attCert.setDeviceName(device.getName());

View File

@ -5,6 +5,7 @@ import com.google.protobuf.InvalidProtocolBufferException;
import hirs.attestationca.configuration.provisionerTpm2.ProvisionerTpm2;
import hirs.attestationca.persist.entity.manager.CertificateRepository;
import hirs.attestationca.persist.entity.manager.DeviceRepository;
import hirs.attestationca.persist.entity.manager.PolicyRepository;
import hirs.attestationca.persist.entity.manager.TPM2ProvisionerStateRepository;
import hirs.attestationca.persist.entity.tpm.TPM2ProvisionerState;
import hirs.attestationca.persist.entity.userdefined.Device;
@ -44,6 +45,7 @@ public class CertificateRequestProcessor extends AbstractProcessor {
* @param acaCertificate object used to create credential
* @param validDays int for the time in which a certificate is valid.
* @param tpm2ProvisionerStateRepository db connector for provisioner state.
* @param policyRepository db connector for policies.
*/
public CertificateRequestProcessor(final SupplyChainValidationService supplyChainValidationService,
final CertificateRepository certificateRepository,
@ -51,13 +53,15 @@ public class CertificateRequestProcessor extends AbstractProcessor {
final PrivateKey privateKey,
final X509Certificate acaCertificate,
final int validDays,
final TPM2ProvisionerStateRepository tpm2ProvisionerStateRepository) {
final TPM2ProvisionerStateRepository tpm2ProvisionerStateRepository,
final PolicyRepository policyRepository) {
super(privateKey, validDays);
this.supplyChainValidationService = supplyChainValidationService;
this.certificateRepository = certificateRepository;
this.deviceRepository = deviceRepository;
this.acaCertificate = acaCertificate;
this.tpm2ProvisionerStateRepository = tpm2ProvisionerStateRepository;
setPolicyRepository(policyRepository);
}
/**
@ -107,6 +111,9 @@ public class CertificateRequestProcessor extends AbstractProcessor {
List<PlatformCredential> platformCredentials = parsePcsFromIdentityClaim(claim,
endorsementCredential, certificateRepository);
// Get LDevID public key if it exists
RSAPublicKey ldevidPub = ProvisionUtils.parsePublicKey(claim.getLdevidPublicArea().toByteArray());
// Get device name and device
String deviceName = claim.getDv().getNw().getHostname();
Device device = deviceRepository.findByName(deviceName);
@ -142,22 +149,31 @@ public class CertificateRequestProcessor extends AbstractProcessor {
// Create signed, attestation certificate
X509Certificate attestationCertificate = generateCredential(akPub,
endorsementCredential, platformCredentials, deviceName, acaCertificate);
X509Certificate ldevidCertificate = generateCredential(ldevidPub,
endorsementCredential, platformCredentials, deviceName, acaCertificate);
byte[] derEncodedAttestationCertificate = ProvisionUtils.getDerEncodedCertificate(
attestationCertificate);
byte[] derEncodedLdevidCertificate = ProvisionUtils.getDerEncodedCertificate(
ldevidCertificate);
// We validated the nonce and made use of the identity claim so state can be deleted
tpm2ProvisionerStateRepository.delete(tpm2ProvisionerState);
// Package the signed certificate into a response
// Package the signed certificates into a response
ByteString certificateBytes = ByteString
.copyFrom(derEncodedAttestationCertificate);
ByteString ldevidCertificateBytes = ByteString
.copyFrom(derEncodedLdevidCertificate);
ProvisionerTpm2.CertificateResponse response = ProvisionerTpm2.CertificateResponse
.newBuilder().setCertificate(certificateBytes)
.setLdevidCertificate(ldevidCertificateBytes)
.setStatus(ProvisionerTpm2.ResponseStatus.PASS)
.build();
saveAttestationCertificate(certificateRepository, derEncodedAttestationCertificate,
endorsementCredential, platformCredentials, device);
endorsementCredential, platformCredentials, device, false);
saveAttestationCertificate(certificateRepository, derEncodedLdevidCertificate,
endorsementCredential, platformCredentials, device, true);
return response.toByteArray();
} else {

View File

@ -160,7 +160,7 @@ public class AbstractUserdefinedEntityTest {
return new PlatformCredential(certPath);
case "IssuedAttestationCertificate":
return new IssuedAttestationCertificate(certPath,
endorsementCredential, platformCredentials);
endorsementCredential, platformCredentials, false);
default:
throw new IllegalArgumentException(
String.format("Unknown certificate class %s", certificateClass.getName())

View File

@ -26,6 +26,7 @@
<thead>
<tr>
<th rowspan="2">Hostname</th>
<th rowspan="2">Type</th>
<th rowspan="2">Issuer</th>
<th rowspan="2">Valid (begin)</th>
<th rowspan="2">Valid (end)</th>
@ -51,6 +52,16 @@
return full.deviceName;
}
},
{
data: 'isLDevID',
searchable:false,
render: function (data, type, full, meta) {
if (data === true) {
return "LDevID";
}
return "AK";
}
},
{data: 'issuer'},
{
data: 'beginValidity',

View File

@ -189,7 +189,7 @@
<br />
<%-- Generate LDevID Certificate--%>
<div class="aca-input-box" style="display: none">
<div class="aca-input-box">
<form:form method="POST" modelAttribute="initialData" action="policy/update-issue-devid">
<li>Generate LDevID Certificate: ${initialData.issueDevIdCertificate ? 'Enabled' : 'Disabled'}
<my:editor id="issuedDevIdCertificatePolicyEditor" label="Edit Settings">

View File

@ -169,7 +169,7 @@ public abstract class PageControllerTest {
return new CertificateAuthorityCredential(fPath);
case "IssuedAttestationCertificate":
return new IssuedAttestationCertificate(fPath,
endorsementCredential, platformCredentials);
endorsementCredential, platformCredentials, false);
default:
throw new IllegalArgumentException(
String.format("Unknown certificate class %s", certificateClass.getName())

View File

@ -71,6 +71,7 @@ message IdentityClaim {
repeated bytes platform_credential = 5;
optional string client_version = 6;
optional string paccorOutput = 7;
optional bytes ldevid_public_area = 8;
}
message TpmQuote {
@ -96,5 +97,6 @@ message CertificateRequest {
message CertificateResponse {
optional bytes certificate = 1;
optional ResponseStatus status = 2 [default = FAIL];
optional bytes ldevidCertificate = 3;
}

View File

@ -69,7 +69,7 @@ namespace hirs {
public IdentityClaim CreateIdentityClaim(DeviceInfo dv, byte[] akPublicArea, byte[] ekPublicArea,
byte[] endorsementCredential, List<byte[]> platformCredentials,
string paccoroutput) {
string paccoroutput, byte[] ldevidPublicArea) {
IdentityClaim identityClaim = new();
identityClaim.Dv = dv;
identityClaim.AkPublicArea = ByteString.CopyFrom(akPublicArea);
@ -81,6 +81,7 @@ namespace hirs {
}
}
identityClaim.PaccorOutput = paccoroutput;
identityClaim.LdevidPublicArea = ByteString.CopyFrom(ldevidPublicArea);
return identityClaim;
}

View File

@ -36,10 +36,12 @@ namespace hirs {
/// <param name="platformCredentials">Any platform certificates relevant to the Device,
/// encoded in DER or PEM.</param>
/// <param name="paccoroutput">Platform Manifest in a JSON format.</param>
/// <param name="ldevidPublicArea">The public LDevID retrieved as a TPM2B_PUBLIC.</param>
/// <returns>An <see cref="IdentityClaim"/> object that can be sent to the ACA.</returns>
IdentityClaim CreateIdentityClaim(DeviceInfo dv, byte[] akPublicArea, byte[] ekPublicArea,
byte[] endorsementCredential,
List<byte[]> platformCredentials, string paccoroutput);
List<byte[]> platformCredentials, string paccoroutput,
byte[] ldevidPublicArea);
/// <summary>
/// Collect answers to verification requirements regarding a Device into an object that
/// can be interpreted by the ACA.

View File

@ -32,6 +32,11 @@ namespace hirs {
get; set;
}
[Option("replaceLDevID", Default = false, HelpText = "Clear any existing hirs LDevID and create a new one.")]
public bool ReplaceLDevID {
get; set;
}
public static string[] SplitArgs(string argString) {
return argString.SplitArgs(true);
}

View File

@ -270,7 +270,7 @@ namespace hirs {
#region EFI
private void CheckEfiPrefix() {
if (!string.IsNullOrWhiteSpace(configFromSettingsFile[Options.efi_prefix.ToString()])) {
if (configFromSettingsFile[Options.efi_prefix.ToString()] != null) {
Log.Debug("Checking EFI Prefix setting.");
efi_prefix = $"{ configFromSettingsFile[Options.efi_prefix.ToString()] }";
if (string.IsNullOrWhiteSpace(efi_prefix)) { // If not explicitly set in appsettings, try to use default EFI location on Linux

View File

@ -16,7 +16,7 @@ namespace hirs {
private IHirsAcaClient acaClient = null;
private const string DefaultCertFileName = "attestationkey.pem";
private const string DefaultLDevIDCertFileName = "ldevid.pem";
public Provisioner() {
}
@ -141,6 +141,16 @@ namespace hirs {
Log.Debug("Gathering AK PUBLIC.");
byte[] akPublicArea = tpm.ReadPublicArea(CommandTpm.DefaultAkHandle, out name, out qualifiedName);
Log.Debug("Checking SRK PUBLIC");
tpm.CreateStorageRootKey(CommandTpm.DefaultSrkHandle); // Will not create key if obj already exists at handle
byte[] srkPublicArea = tpm.ReadPublicArea(CommandTpm.DefaultSrkHandle, out byte[] name2, out byte[] qualifiedName2);
Log.Information("----> " + (cli.ReplaceLDevID ? "Creating new" : "Verifying existence of") + " LDevID Key.");
tpm.CreateLDevIDKey(CommandTpm.DefaultSrkHandle, CommandTpm.DefaultLDevIDHandle, cli.ReplaceLDevID);
Log.Debug("Gathering LDevID PUBLIC.");
byte[] ldevidPublicArea = tpm.ReadPublicArea(CommandTpm.DefaultLDevIDHandle, out name, out qualifiedName);
List<byte[]> pcs = null, baseRims = null, supportRimELs = null, supportRimPCRs = null;
if (settings.HasEfiPrefix()) {
Log.Information("----> Gathering artifacts from EFI.");
@ -210,7 +220,7 @@ namespace hirs {
dv.Pcrslist = ByteString.CopyFromUtf8(pcrsList);
Log.Debug("Create identity claim");
IdentityClaim idClaim = acaClient.CreateIdentityClaim(dv, akPublicArea, ekPublicArea, ekc, pcs, manifest);
IdentityClaim idClaim = acaClient.CreateIdentityClaim(dv, akPublicArea, ekPublicArea, ekc, pcs, manifest, ldevidPublicArea);
Log.Information("----> Sending identity claim to Attestation CA");
IdentityClaimResponse icr = await acaClient.PostIdentityClaim(idClaim);
@ -284,20 +294,38 @@ namespace hirs {
certificate = cr.Certificate.ToByteArray(); // contains certificate
String certificateDirPath = settings.efi_prefix;
if (certificateDirPath != null) {
String certificateFilePath = certificateFilePath = certificateDirPath + DefaultCertFileName;
String certificateFilePath = certificateDirPath + DefaultCertFileName;
try {
if (!Directory.Exists(certificateDirPath)) {
Directory.CreateDirectory(certificateDirPath);
}
File.WriteAllBytes(certificateFilePath, certificate);
Log.Debug("Certificate written to local file system: ", certificateFilePath);
Log.Debug("Attestation key certificate written to local file system: {0}", certificateFilePath);
}
catch (Exception) {
Log.Debug("Failed to write certificate to local file system.");
Log.Debug("Failed to write attestation key certificate to local file system.");
}
}
Log.Debug("Printing attestation key certificate: " + BitConverter.ToString(certificate));
}
if (cr.HasLdevidCertificate) {
certificate = cr.LdevidCertificate.ToByteArray(); // contains certificate
String certificateDirPath = settings.efi_prefix;
if (certificateDirPath != null) {
String certificateFilePath = certificateDirPath + DefaultLDevIDCertFileName;
try {
if (!Directory.Exists(certificateDirPath)) {
Directory.CreateDirectory(certificateDirPath);
}
File.WriteAllBytes(certificateFilePath, certificate);
Log.Debug("LDevID certificate written to local file system: {0}", certificateFilePath);
}
catch (Exception) {
Log.Debug("Failed to write LDevID certificate to local file system.");
}
}
Log.Debug("Printing LDevID certificate: " + BitConverter.ToString(certificate));
}
} else {
result = ClientExitCodes.MAKE_CREDENTIAL_BLOB_MALFORMED;
Log.Error("Credential elements could not be extracted from the ACA's response.");

View File

@ -1,4 +1,5 @@
using Serilog;
using Newtonsoft.Json.Converters;
using Serilog;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@ -25,6 +26,8 @@ namespace hirs {
public const uint DefaultEkcNvIndex = 0x1c00002;
public const uint DefaultEkHandle = 0x81010001;
public const uint DefaultAkHandle = 0x81010002;
public const uint DefaultSrkHandle = 0x81000001;
public const uint DefaultLDevIDHandle = 0x81000002;
private readonly Tpm2 tpm;
@ -197,6 +200,20 @@ namespace hirs {
return inPublic;
}
public static TpmPublic GenerateSRKTemplateL1() {
TpmAlgId nameAlg = TpmAlgId.Sha256;
ObjectAttr attributes = ObjectAttr.FixedTPM | ObjectAttr.FixedParent | ObjectAttr.SensitiveDataOrigin | ObjectAttr.UserWithAuth | ObjectAttr.Restricted | ObjectAttr.Decrypt | ObjectAttr.NoDA;
byte[] auth_policy = null;
// ASYM: RSA 2048 with NULL scheme, SYM: AES-128 with CFB mode
RsaParms rsa = new(new SymDefObject(TpmAlgId.Aes, 128, TpmAlgId.Cfb), new NullAsymScheme(), 2048, 0);
// unique buffer must be filled with 0 for the EK Template L-1.
byte[] zero256 = new byte[256];
Array.Fill<byte>(zero256, 0x00);
Tpm2bPublicKeyRsa unique = new(zero256);
TpmPublic inPublic = new(nameAlg, attributes, auth_policy, rsa, unique);
return inPublic;
}
public void CreateEndorsementKey(uint ekHandleInt) {
TpmHandle ekHandle = new(ekHandleInt);
@ -247,6 +264,25 @@ namespace hirs {
return inPublic;
}
private static RsaParms LDevIDRSAParms() {
TpmAlgId digestAlg = TpmAlgId.Sha256;
RsaParms parms = new(new SymDefObject(TpmAlgId.Null, 0, TpmAlgId.Null), new SchemeRsassa(digestAlg), 2048, 0);
return parms;
}
private static ObjectAttr LDevIDAttributes() {
ObjectAttr attrib = ObjectAttr.Sign | ObjectAttr.FixedParent | ObjectAttr.FixedTPM
| ObjectAttr.SensitiveDataOrigin | ObjectAttr.UserWithAuth;
return attrib;
}
private static TpmPublic GenerateLDevIDTemplate(TpmAlgId nameAlg) {
RsaParms rsa = LDevIDRSAParms();
ObjectAttr attributes = LDevIDAttributes();
TpmPublic inPublic = new(nameAlg, attributes, null, rsa, new Tpm2bPublicKeyRsa());
return inPublic;
}
public void CreateAttestationKey(uint ekHandleInt, uint akHandleInt, bool replace) {
TpmHandle ekHandle = new(ekHandleInt);
TpmHandle akHandle = new(akHandleInt);
@ -298,6 +334,88 @@ namespace hirs {
tpm.FlushContext(sessEK);
}
public void CreateStorageRootKey(uint srkHandleInt) {
TpmHandle srkHandle = new(srkHandleInt);
TpmPublic existingObject;
try {
existingObject = tpm.ReadPublic(srkHandle, out byte[] name, out byte[] qualifiedName);
Log.Debug("SRK already exists.");
return;
} catch (TpmException) {
Log.Debug("Verified SRK does not exist at expected handle. Creating SRK.");
}
SensitiveCreate inSens = new(); // key password (no params = no key password)
TpmPublic inPublic = CommandTpm.GenerateSRKTemplateL1();
TpmHandle newTransientSrkHandle = tpm.CreatePrimary(TpmRh.Owner, inSens, inPublic,
new byte[] { }, new PcrSelection[] { }, out TpmPublic outPublic,
out CreationData creationData, out byte[] creationHash, out TkCreation ticket);
Log.Debug("New SRK Handle: " + BitConverter.ToString(newTransientSrkHandle));
Log.Debug("New SRK PUB Name: " + BitConverter.ToString(outPublic.GetName()));
Log.Debug("New SRK PUB 2BREP: " + BitConverter.ToString(outPublic.GetTpm2BRepresentation()));
// Make the object persistent
tpm.EvictControl(TpmRh.Owner, newTransientSrkHandle, srkHandle);
Log.Debug("Successfully made the new SRK persistent at handle " + BitConverter.ToString(srkHandle) + ".");
tpm.FlushContext(newTransientSrkHandle);
Log.Debug("Flushed the context for the transient SRK.");
}
public void CreateLDevIDKey(uint srkHandleInt, uint ldevidHandleInt, bool replace) {
TpmHandle srkHandle = new(srkHandleInt);
TpmHandle ldevidHandle = new(ldevidHandleInt);
TpmPublic existingObject = null;
try {
existingObject = tpm.ReadPublic(ldevidHandle, out byte[] name, out byte[] qualifiedName);
} catch { }
if (!replace && existingObject != null) {
// Do Nothing
Log.Debug("LDevID exists at expected handle. Flag to not replace the LDevID is set in the settings file.");
return;
} else if (replace && existingObject != null) {
// Clear the object and continue
tpm.EvictControl(TpmRh.Owner, ldevidHandle, ldevidHandle);
Log.Debug("Removed previous LDevID.");
}
// Create a new key and make it persistent at ldevidHandle
TpmAlgId nameAlg = TpmAlgId.Sha256;
SensitiveCreate inSens = new();
TpmPublic inPublic = GenerateLDevIDTemplate(nameAlg);
/*var policySRK = new PolicyTree(nameAlg);
policySRK.SetPolicyRoot(new TpmPolicySecret(TpmRh.Owner, false, 0, null, null));
AuthSession sessSRK = tpm.StartAuthSessionEx(TpmSe.Policy, nameAlg);
sessSRK.RunPolicy(tpm, policySRK);*/
TpmPrivate kLDevID = tpm.Create(srkHandle, inSens, inPublic, null, null, out TpmPublic outPublic,
out CreationData creationData, out byte[] creationHash, out TkCreation ticket);
Log.Debug("New LDevID PUB Name: " + BitConverter.ToString(outPublic.GetName()));
Log.Debug("New LDevID PUB 2BREP: " + BitConverter.ToString(outPublic.GetTpm2BRepresentation()));
Log.Debug("New LDevID PUB unique: " + BitConverter.ToString((Tpm2bPublicKeyRsa)(outPublic.unique)));
/*tpm.FlushContext(sessSRK);
sessSRK = tpm.StartAuthSessionEx(TpmSe.Policy, nameAlg);
sessSRK.RunPolicy(tpm, policySRK);*/
TpmHandle hLDevID = tpm.Load(srkHandle, kLDevID, outPublic);
tpm.EvictControl(TpmRh.Owner, hLDevID, ldevidHandle);
Log.Debug("Created and persisted new LDevID at handle 0x" + ldevidHandle.handle.ToString("X") + ".");
//tpm.FlushContext(sessSRK);
}
public Tpm2bDigest[] GetPcrList(TpmAlgId pcrBankDigestAlg, uint[] pcrs = null) {
if (pcrs == null) {
pcrs = new uint[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 };

View File

@ -9,6 +9,8 @@ namespace hirs {
TpmPublic ReadPublicArea(uint handleInt, out byte[] name, out byte[] qualifiedName);
void CreateEndorsementKey(uint ekHandleInt);
void CreateAttestationKey(uint ekHandleInt, uint akHandleInt, bool replace);
void CreateStorageRootKey(uint srkHandleInt);
void CreateLDevIDKey(uint srkHandleInt, uint ldevidHandleInt, bool replace);
Tpm2bDigest[] GetPcrList(TpmAlgId pcrBankDigestAlg, uint[] pcrs = null);
void GetQuote(uint akHandleInt, TpmAlgId pcrBankDigestAlg, byte[] nonce, out CommandTpmQuoteResponse ctqr, uint[] pcrs = null);
byte[] ActivateCredential(uint akHandleInt, uint ekHandleInt, byte[] integrityHMAC, byte[] encIdentity, byte[] encryptedSecret);

View File

@ -16,12 +16,13 @@ namespace hirsTest {
DeviceInfo dv = new DeviceInfo();
byte[] akPub = new byte[] { };
byte[] ekPub = new byte[] { };
byte[] ldevidPub = new byte[] { };
byte[] ekc = new byte[] { };
List<byte[]> pcs = new List<byte[]>();
pcs.Add(new byte[] { });
string componentList= "";
IdentityClaim obj = client.CreateIdentityClaim(dv, akPub, ekPub, ekc, pcs, componentList);
IdentityClaim obj = client.CreateIdentityClaim(dv, akPub, ekPub, ekc, pcs, componentList, ldevidPub);
Assert.Multiple(() => {
Assert.That(obj.Dv, Is.Not.Null);
Assert.That(obj.HasAkPublicArea, Is.True);
@ -29,6 +30,7 @@ namespace hirsTest {
Assert.That(obj.HasEndorsementCredential, Is.True);
Assert.That(obj.PlatformCredential, Has.Count.EqualTo(1));
Assert.That(obj.HasPaccorOutput, Is.True);
Assert.That(obj.HasLdevidPublicArea, Is.True);
});
}

View File

@ -21,6 +21,8 @@ namespace hirsTest {
byte[] credentialBlob = Convert.FromBase64String("OAAAIFQLXnXNUZTQNcNF367cJoRNCCwZSCz+tet07q+R0SKN6e2oGBsK3H9Vzbj667ZsjnVOtvpSpQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATXpL5zl/ET0XcndP3MQSOBUwrjZIrtCgJ0tvMk+8mCVC+S8H3L+XLRCus0ANH6tCLF+U5QGEonRisawIpTksACyZifpu7DIl8DCq2Z9XHeIM1zm2REIpkKFoEhEGzzu636VJ9VHyPCuUs5lBVE8XOV9w/MxaJ2hAaekAo7XS3oChoIqAg3EBXc9tGNDxQGtSLboO2G2XQhaX4ree9HkEIp5qnVa8ojcp+gi0HTICHo7gcaBKaE0lrMweXhShHZ+YP/vMHL4aekaTQUNIYpBfuuvPEzlSv4/J9yQ8ClZbSf1jR41TvpcWtmiyDCUYLOWUbs7s+jkjH9dCqiY0lmRNOM=");
TpmPublic ekPublic = CommandTpm.GenerateEKTemplateL1();
TpmPublic akPublic = new(TpmAlgId.Sha256, ObjectAttr.None, System.Text.Encoding.UTF8.GetBytes("AK PUBLIC AUTH POLICY"), new RsaParms(new SymDefObject(TpmAlgId.Null, 0, TpmAlgId.Null), new SchemeRsassa(TpmAlgId.Sha256), 2048, 0), new Tpm2bPublicKeyRsa());
TpmPublic srkPublic = CommandTpm.GenerateSRKTemplateL1();
TpmPublic ldevidPublic = new(TpmAlgId.Sha256, ObjectAttr.None, System.Text.Encoding.UTF8.GetBytes("LDEVID PUBLIC AUTH POLICY"), new RsaParms(new SymDefObject(TpmAlgId.Null, 0, TpmAlgId.Null), new SchemeRsassa(TpmAlgId.Sha256), 2048, 0), new Tpm2bPublicKeyRsa());
Tpm2bDigest[] sha1Values = new Tpm2bDigest[] { new Tpm2bDigest(System.Text.Encoding.UTF8.GetBytes("SHA1 DIGEST1")) };
Tpm2bDigest[] sha256Values = new Tpm2bDigest[] { new Tpm2bDigest(System.Text.Encoding.UTF8.GetBytes("SHA256 DIGEST1")) };
DeviceInfo dv = new();
@ -41,6 +43,10 @@ namespace hirsTest {
A.CallTo(() => tpm.ReadPublicArea(CommandTpm.DefaultEkHandle, out name, out qualifiedName)).Returns(ekPublic);
A.CallTo(() => tpm.CreateAttestationKey(CommandTpm.DefaultEkHandle, CommandTpm.DefaultAkHandle, false)).DoesNothing();
A.CallTo(() => tpm.ReadPublicArea(CommandTpm.DefaultAkHandle, out name, out qualifiedName)).Returns(akPublic);
A.CallTo(() => tpm.CreateStorageRootKey(CommandTpm.DefaultSrkHandle)).DoesNothing();
A.CallTo(() => tpm.ReadPublicArea(CommandTpm.DefaultSrkHandle, out name, out qualifiedName)).Returns(srkPublic);
A.CallTo(() => tpm.CreateLDevIDKey(CommandTpm.DefaultSrkHandle, CommandTpm.DefaultLDevIDHandle, false)).DoesNothing();
A.CallTo(() => tpm.ReadPublicArea(CommandTpm.DefaultLDevIDHandle, out name, out qualifiedName)).Returns(ldevidPublic);
//A.CallTo(() => tpm.getPcrList(TpmAlgId.Sha1, A<uint[]>.Ignored)).Returns(sha1Values);
//A.CallTo(() => tpm.getPcrList(TpmAlgId.Sha256, A<uint[]>.Ignored)).Returns(sha256Values);
A.CallTo(() => tpm.GetQuote(CommandTpm.DefaultAkHandle, TpmAlgId.Sha256, secret, out ctqr, A<uint[]>.Ignored)).DoesNothing();
@ -49,7 +55,7 @@ namespace hirsTest {
A.CallTo(() => collector.CollectDeviceInfo(address)).Returns(dv);
IHirsAcaClient client = A.Fake<IHirsAcaClient>();
IdentityClaim idClaim = client.CreateIdentityClaim(dv, akPublic, ekPublic, ekCert, null, paccorOutput);
IdentityClaim idClaim = client.CreateIdentityClaim(dv, akPublic, ekPublic, ekCert, null, paccorOutput, ldevidPublic);
CertificateRequest certReq = client.CreateAkCertificateRequest(secret, ctqr);
A.CallTo(() => client.PostIdentityClaim(idClaim)).Returns(Task.FromResult<IdentityClaimResponse>(idClaimResp));
A.CallTo(() => client.PostCertificateRequest(certReq)).Returns(Task.FromResult<CertificateResponse>(certResp));
@ -79,6 +85,8 @@ namespace hirsTest {
byte[] acaIssuedCert = Encoding.UTF8.GetBytes("ACA ISSUED CERTIFICATE");
TpmPublic ekPublic = CommandTpm.GenerateEKTemplateL1();
TpmPublic akPublic = new(TpmAlgId.Sha256, ObjectAttr.None, System.Text.Encoding.UTF8.GetBytes("AK PUBLIC AUTH POLICY"), new RsaParms(new SymDefObject(TpmAlgId.Null, 0, TpmAlgId.Null), new SchemeRsassa(TpmAlgId.Sha256), 2048, 0), new Tpm2bPublicKeyRsa());
TpmPublic srkPublic = CommandTpm.GenerateSRKTemplateL1();
TpmPublic ldevidPublic = new(TpmAlgId.Sha256, ObjectAttr.None, System.Text.Encoding.UTF8.GetBytes("LDEVID PUBLIC AUTH POLICY"), new RsaParms(new SymDefObject(TpmAlgId.Null, 0, TpmAlgId.Null), new SchemeRsassa(TpmAlgId.Sha256), 2048, 0), new Tpm2bPublicKeyRsa());
Tpm2bDigest[] sha1Values = new Tpm2bDigest[] { new Tpm2bDigest(System.Text.Encoding.UTF8.GetBytes("SHA1 DIGEST1")) };
Tpm2bDigest[] sha256Values = new Tpm2bDigest[] { new Tpm2bDigest(System.Text.Encoding.UTF8.GetBytes("SHA256 DIGEST1")) };
DeviceInfo dv = new();
@ -93,6 +101,10 @@ namespace hirsTest {
A.CallTo(() => tpm.ReadPublicArea(CommandTpm.DefaultEkHandle, out name, out qualifiedName)).Returns(ekPublic);
A.CallTo(() => tpm.CreateAttestationKey(CommandTpm.DefaultEkHandle, CommandTpm.DefaultAkHandle, false)).DoesNothing();
A.CallTo(() => tpm.ReadPublicArea(CommandTpm.DefaultAkHandle, out name, out qualifiedName)).Returns(ekPublic);
A.CallTo(() => tpm.CreateStorageRootKey(CommandTpm.DefaultSrkHandle)).DoesNothing();
A.CallTo(() => tpm.ReadPublicArea(CommandTpm.DefaultSrkHandle, out name, out qualifiedName)).Returns(srkPublic);
A.CallTo(() => tpm.CreateLDevIDKey(CommandTpm.DefaultSrkHandle, CommandTpm.DefaultLDevIDHandle, false)).DoesNothing();
A.CallTo(() => tpm.ReadPublicArea(CommandTpm.DefaultLDevIDHandle, out name, out qualifiedName)).Returns(ldevidPublic);
A.CallTo(() => tpm.GetPcrList(TpmAlgId.Sha1, A<uint[]>.Ignored)).Returns(sha1Values);
A.CallTo(() => tpm.GetPcrList(TpmAlgId.Sha256, A<uint[]>.Ignored)).Returns(sha256Values);
@ -100,7 +112,7 @@ namespace hirsTest {
A.CallTo(() => collector.CollectDeviceInfo(address)).Returns(dv);
IHirsAcaClient client = A.Fake<IHirsAcaClient>();
IdentityClaim idClaim = client.CreateIdentityClaim(dv, akPublic, ekPublic, ekCert, null, paccorOutput);
IdentityClaim idClaim = client.CreateIdentityClaim(dv, akPublic, ekPublic, ekCert, null, paccorOutput, ldevidPublic);
A.CallTo(() => client.PostIdentityClaim(idClaim)).WithAnyArguments().Returns(Task.FromResult<IdentityClaimResponse>(idClaimResp));
Settings settings = Settings.LoadSettingsFromFile("./Resources/test/settings_test/appsettings.json");

View File

@ -71,6 +71,7 @@ message IdentityClaim {
repeated bytes platform_credential = 5;
optional string client_version = 6;
optional string paccorOutput = 7;
optional bytes ldevid_public_area = 8;
}
message TpmQuote {
@ -96,5 +97,6 @@ message CertificateRequest {
message CertificateResponse {
optional bytes certificate = 1;
optional ResponseStatus status = 2 [default = FAIL];
optional bytes ldevidCertificate = 3;
}