From b152a3421cf1e67c113f3be8d650b10b62d57b89 Mon Sep 17 00:00:00 2001 From: iadgovuser59 <133057011+iadgovuser59@users.noreply.github.com> Date: Mon, 5 Aug 2024 10:58:27 -0400 Subject: [PATCH] Saving LDevID to local key files --- .../persist/provision/AbstractProcessor.java | 7 +- .../CertificateRequestProcessor.java | 81 +++++++++++++------ HIRS_Provisioner.NET/hirs/appsettings.json | 1 + .../hirs/src/client/Client.cs | 4 +- .../hirs/src/config/Settings.cs | 31 ++++++- .../hirs/src/provisioner/Provisioner.cs | 11 ++- .../hirs/src/tpm/CommandTpm.cs | 50 +++++------- .../hirs/src/tpm/IHirsAcaTpm.cs | 3 +- .../src/provisioner/ProvisionerTests.cs | 6 +- 9 files changed, 124 insertions(+), 70 deletions(-) diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/AbstractProcessor.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/AbstractProcessor.java index ff718f3e..0f59637a 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/AbstractProcessor.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/AbstractProcessor.java @@ -236,10 +236,11 @@ public class AbstractProcessor { * @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 + * @return whether the certificate was saved successfully * @throws {@link CertificateProcessingException} if error occurs in persisting the Attestation * Certificate */ - public void saveAttestationCertificate(final CertificateRepository certificateRepository, + public boolean saveAttestationCertificate(final CertificateRepository certificateRepository, final byte[] derEncodedAttestationCertificate, final EndorsementCredential endorsementCredential, final List platformCredentials, @@ -264,7 +265,7 @@ public class AbstractProcessor { generateCertificate = isLDevID ? policySettings.isIssueDevIdCertificate() : policySettings.isIssueAttestationCertificate(); - if (issuedAc != null && (isLDevID ? policySettings.isDevIdExpirationFlag() + if (issuedAc != null && issuedAc.size() > 0 && (isLDevID ? policySettings.isDevIdExpirationFlag() : policySettings.isGenerateOnExpiration())) { if (issuedAc.get(0).getEndValidity().after(currentDate)) { // so the issued AC is not expired @@ -291,6 +292,8 @@ public class AbstractProcessor { "Encountered error while storing Attestation Certificate: " + e.getMessage(), e); } + + return generateCertificate; } private List getPlatformCredentials(final CertificateRepository certificateRepository, diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/CertificateRequestProcessor.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/CertificateRequestProcessor.java index fb9cd00e..571e8ae0 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/CertificateRequestProcessor.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/persist/provision/CertificateRequestProcessor.java @@ -112,7 +112,10 @@ public class CertificateRequestProcessor extends AbstractProcessor { endorsementCredential, certificateRepository); // Get LDevID public key if it exists - RSAPublicKey ldevidPub = ProvisionUtils.parsePublicKey(claim.getLdevidPublicArea().toByteArray()); + RSAPublicKey ldevidPub = null; + if (claim.hasLdevidPublicArea()) { + ldevidPub = ProvisionUtils.parsePublicKey(claim.getLdevidPublicArea().toByteArray()); + } // Get device name and device String deviceName = claim.getDv().getNw().getHostname(); @@ -149,33 +152,63 @@ 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); + if (ldevidPub != null) { + // Create signed LDevID certificate + 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); + // We validated the nonce and made use of the identity claim so state can be deleted + tpm2ProvisionerStateRepository.delete(tpm2ProvisionerState); - // 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(); + // Package the signed certificates into a response + ByteString certificateBytes = ByteString + .copyFrom(derEncodedAttestationCertificate); + ByteString ldevidCertificateBytes = ByteString + .copyFrom(derEncodedLdevidCertificate); - saveAttestationCertificate(certificateRepository, derEncodedAttestationCertificate, - endorsementCredential, platformCredentials, device, false); - saveAttestationCertificate(certificateRepository, derEncodedLdevidCertificate, - endorsementCredential, platformCredentials, device, true); + boolean generateAtt = saveAttestationCertificate(certificateRepository, derEncodedAttestationCertificate, + endorsementCredential, platformCredentials, device, false); + boolean generateLDevID = saveAttestationCertificate(certificateRepository, derEncodedLdevidCertificate, + endorsementCredential, platformCredentials, device, true); - return response.toByteArray(); + ProvisionerTpm2.CertificateResponse.Builder builder = ProvisionerTpm2.CertificateResponse. + newBuilder().setStatus(ProvisionerTpm2.ResponseStatus.PASS); + if (generateAtt) { + builder = builder.setCertificate(certificateBytes); + } + if (generateLDevID) { + builder = builder.setLdevidCertificate(ldevidCertificateBytes); + } + ProvisionerTpm2.CertificateResponse response = builder.build(); + + return response.toByteArray(); + } + else { + byte[] derEncodedAttestationCertificate = ProvisionUtils.getDerEncodedCertificate( + attestationCertificate); + + // We validated the nonce and made use of the identity claim so state can be deleted + tpm2ProvisionerStateRepository.delete(tpm2ProvisionerState); + + // Package the signed certificates into a response + ByteString certificateBytes = ByteString + .copyFrom(derEncodedAttestationCertificate); + ProvisionerTpm2.CertificateResponse.Builder builder = ProvisionerTpm2.CertificateResponse. + newBuilder().setStatus(ProvisionerTpm2.ResponseStatus.PASS); + + boolean generateAtt = saveAttestationCertificate(certificateRepository, derEncodedAttestationCertificate, + endorsementCredential, platformCredentials, device, false); + if (generateAtt) { + builder = builder.setCertificate(certificateBytes); + } + ProvisionerTpm2.CertificateResponse response = builder.build(); + + return response.toByteArray(); + } } else { log.error("Supply chain validation did not succeed. " + "Firmware Quote Validation failed. Result is: " diff --git a/HIRS_Provisioner.NET/hirs/appsettings.json b/HIRS_Provisioner.NET/hirs/appsettings.json index 854d682e..61accf75 100644 --- a/HIRS_Provisioner.NET/hirs/appsettings.json +++ b/HIRS_Provisioner.NET/hirs/appsettings.json @@ -2,6 +2,7 @@ "auto_detect_tpm": "TRUE", "aca_address_port": "https://127.0.0.1:8443", "efi_prefix": "", + "ldevid_prefix": "", "paccor_output_file": "", "event_log_file": "", "hardware_manifest_collectors": "paccor_scripts", diff --git a/HIRS_Provisioner.NET/hirs/src/client/Client.cs b/HIRS_Provisioner.NET/hirs/src/client/Client.cs index 8f60cb0e..9536b72b 100644 --- a/HIRS_Provisioner.NET/hirs/src/client/Client.cs +++ b/HIRS_Provisioner.NET/hirs/src/client/Client.cs @@ -69,7 +69,7 @@ namespace hirs { public IdentityClaim CreateIdentityClaim(DeviceInfo dv, byte[] akPublicArea, byte[] ekPublicArea, byte[] endorsementCredential, List platformCredentials, - string paccoroutput, byte[] ldevidPublicArea) { + string paccoroutput, byte[] ldevidPublicArea = null) { IdentityClaim identityClaim = new(); identityClaim.Dv = dv; identityClaim.AkPublicArea = ByteString.CopyFrom(akPublicArea); @@ -81,7 +81,7 @@ namespace hirs { } } identityClaim.PaccorOutput = paccoroutput; - identityClaim.LdevidPublicArea = ByteString.CopyFrom(ldevidPublicArea); + if (ldevidPublicArea != null) identityClaim.LdevidPublicArea = ByteString.CopyFrom(ldevidPublicArea); return identityClaim; } diff --git a/HIRS_Provisioner.NET/hirs/src/config/Settings.cs b/HIRS_Provisioner.NET/hirs/src/config/Settings.cs index 3b7ece22..95e12225 100644 --- a/HIRS_Provisioner.NET/hirs/src/config/Settings.cs +++ b/HIRS_Provisioner.NET/hirs/src/config/Settings.cs @@ -24,7 +24,8 @@ namespace hirs { linux_sys_vendor_file, linux_product_name_file, linux_product_version_file, - linux_product_serial_file + linux_product_serial_file, + ldevid_prefix } private static readonly string DEFAULT_SETTINGS_FILE = "appsettings.json"; @@ -72,6 +73,9 @@ namespace hirs { public virtual string linux_product_serial { get; private set; } + public virtual string ldevid_prefix { + get; private set; + } private List hardwareManifests = new(); private Dictionary hardware_manifest_collectors_with_args = new(); private bool hardware_manifest_collection_swid_enforced = false; @@ -126,6 +130,8 @@ namespace hirs { CheckEfiPrefix(); + CheckLDevIDPrefix(); + IngestEventLogFromFile(); StoreCustomDeviceInfoCollectorOptions(); @@ -268,9 +274,30 @@ namespace hirs { } #endregion + #region + private void CheckLDevIDPrefix() { + if (!string.IsNullOrWhiteSpace(configFromSettingsFile[Options.ldevid_prefix.ToString()])) { + Log.Debug("Checking LDevID Prefix setting."); + ldevid_prefix = $"{ configFromSettingsFile[Options.ldevid_prefix.ToString()] }"; + if (!string.IsNullOrWhiteSpace(ldevid_prefix)) { + if (!Directory.Exists(ldevid_prefix)) { + Log.Debug(Options.ldevid_prefix.ToString() + ": " + ldevid_prefix + " did not exist."); + ldevid_prefix = null; + } + } + } + if (ldevid_prefix == null) { + Log.Warning(Options.ldevid_prefix.ToString() + " not set in the settings file. Defaulting to the current working directory."); + ldevid_prefix = ""; + } else { + Log.Debug(" Will scan for LDevID keys in " + ldevid_prefix); + } + } + #endregion + #region EFI private void CheckEfiPrefix() { - if (configFromSettingsFile[Options.efi_prefix.ToString()] != null) { + if (!string.IsNullOrWhiteSpace(configFromSettingsFile[Options.efi_prefix.ToString()])) { 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 diff --git a/HIRS_Provisioner.NET/hirs/src/provisioner/Provisioner.cs b/HIRS_Provisioner.NET/hirs/src/provisioner/Provisioner.cs index 8c11fc39..d8a856a2 100644 --- a/HIRS_Provisioner.NET/hirs/src/provisioner/Provisioner.cs +++ b/HIRS_Provisioner.NET/hirs/src/provisioner/Provisioner.cs @@ -15,6 +15,9 @@ namespace hirs { private IHirsDeviceInfoCollector deviceInfoCollector = null; private IHirsAcaClient acaClient = null; + private const string DefaultLDevIDPubKeyFileName = "ldevid.pub"; + private const string DefaultLDevIDPrivKeyFileName = "ldevid.priv"; + private const string DefaultCertFileName = "attestationkey.pem"; private const string DefaultLDevIDCertFileName = "ldevid.pem"; @@ -146,10 +149,12 @@ namespace hirs { 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); + string ldevidPubPath = settings.ldevid_prefix + DefaultLDevIDPubKeyFileName; + string ldevidPrivPath = settings.ldevid_prefix + DefaultLDevIDPrivKeyFileName; + tpm.CreateLDevIDKey(CommandTpm.DefaultSrkHandle, ldevidPubPath, ldevidPrivPath, cli.ReplaceLDevID); Log.Debug("Gathering LDevID PUBLIC."); - byte[] ldevidPublicArea = tpm.ReadPublicArea(CommandTpm.DefaultLDevIDHandle, out name, out qualifiedName); + byte[] ldevidPublicArea = tpm.ConvertLDevIDPublic(ldevidPubPath); List pcs = null, baseRims = null, supportRimELs = null, supportRimPCRs = null; if (settings.HasEfiPrefix()) { @@ -281,7 +286,7 @@ namespace hirs { Log.Debug("Communicate certificate request to the ACA."); CertificateResponse cr = await acaClient.PostCertificateRequest(akCertReq); Log.Debug("Response received from the ACA regarding the certificate request."); - if (cr.HasStatus) { + if (cr.HasStatus) { if (cr.Status == ResponseStatus.Pass) { Log.Debug("ACA returned a positive response to the Certificate Request."); } else { diff --git a/HIRS_Provisioner.NET/hirs/src/tpm/CommandTpm.cs b/HIRS_Provisioner.NET/hirs/src/tpm/CommandTpm.cs index 344a7e4c..b8d5679c 100644 --- a/HIRS_Provisioner.NET/hirs/src/tpm/CommandTpm.cs +++ b/HIRS_Provisioner.NET/hirs/src/tpm/CommandTpm.cs @@ -27,7 +27,6 @@ namespace hirs { public const uint DefaultEkHandle = 0x81010001; public const uint DefaultAkHandle = 0x81010002; public const uint DefaultSrkHandle = 0x81000001; - public const uint DefaultLDevIDHandle = 0x81000002; private readonly Tpm2 tpm; @@ -266,7 +265,7 @@ namespace hirs { private static RsaParms LDevIDRSAParms() { TpmAlgId digestAlg = TpmAlgId.Sha256; - RsaParms parms = new(new SymDefObject(TpmAlgId.Null, 0, TpmAlgId.Null), new SchemeRsassa(digestAlg), 2048, 0); + RsaParms parms = new(new SymDefObject(TpmAlgId.Null, 0, TpmAlgId.Null), null, 2048, 0); return parms; } @@ -365,37 +364,21 @@ namespace hirs { Log.Debug("Flushed the context for the transient SRK."); } - public void CreateLDevIDKey(uint srkHandleInt, uint ldevidHandleInt, bool replace) { + public void CreateLDevIDKey(uint srkHandleInt, string pubPath, string privPath, 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) { + if (!replace && File.Exists(privPath) && File.Exists(pubPath)) { // Do Nothing - Log.Debug("LDevID exists at expected handle. Flag to not replace the LDevID is set in the settings file."); + Log.Debug("LDevID exists at local file system path. 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 + // Create a new transient key 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); @@ -403,17 +386,20 @@ namespace hirs { Log.Debug("New LDevID PUB 2BREP: " + BitConverter.ToString(outPublic.GetTpm2BRepresentation())); Log.Debug("New LDevID PUB unique: " + BitConverter.ToString((Tpm2bPublicKeyRsa)(outPublic.unique))); - /*tpm.FlushContext(sessSRK); + Tpm2bPublic ldevidPublic = new Tpm2bPublic(outPublic); - sessSRK = tpm.StartAuthSessionEx(TpmSe.Policy, nameAlg); - sessSRK.RunPolicy(tpm, policySRK);*/ + File.WriteAllBytes(pubPath, ldevidPublic); + File.WriteAllBytes(privPath, kLDevID); + Log.Debug("Created new LDevID at local file system paths."); + Log.Debug(" LDevID Pub Path: {0}", pubPath); + Log.Debug(" LDevID Priv Path: {0}", privPath); + } - 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 byte[] ConvertLDevIDPublic(string ldevidPubPath) { + byte[] ldevidPubBytes = File.ReadAllBytes(ldevidPubPath); + var marshaller = new Marshaller(ldevidPubBytes, DataRepresentation.Tpm); + Tpm2bPublic ldevidPublic = marshaller.Get(); + return ldevidPublic.publicArea; } public Tpm2bDigest[] GetPcrList(TpmAlgId pcrBankDigestAlg, uint[] pcrs = null) { diff --git a/HIRS_Provisioner.NET/hirs/src/tpm/IHirsAcaTpm.cs b/HIRS_Provisioner.NET/hirs/src/tpm/IHirsAcaTpm.cs index 62444263..bc532397 100644 --- a/HIRS_Provisioner.NET/hirs/src/tpm/IHirsAcaTpm.cs +++ b/HIRS_Provisioner.NET/hirs/src/tpm/IHirsAcaTpm.cs @@ -10,7 +10,8 @@ namespace hirs { void CreateEndorsementKey(uint ekHandleInt); void CreateAttestationKey(uint ekHandleInt, uint akHandleInt, bool replace); void CreateStorageRootKey(uint srkHandleInt); - void CreateLDevIDKey(uint srkHandleInt, uint ldevidHandleInt, bool replace); + void CreateLDevIDKey(uint srkHandleInt, string pubPath, string privPath, bool replace); + byte[] ConvertLDevIDPublic(string ldevidPubPath); 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); diff --git a/HIRS_Provisioner.NET/hirsTest/src/provisioner/ProvisionerTests.cs b/HIRS_Provisioner.NET/hirsTest/src/provisioner/ProvisionerTests.cs index b60e777c..ca44e6b5 100644 --- a/HIRS_Provisioner.NET/hirsTest/src/provisioner/ProvisionerTests.cs +++ b/HIRS_Provisioner.NET/hirsTest/src/provisioner/ProvisionerTests.cs @@ -45,8 +45,7 @@ namespace hirsTest { 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.CreateLDevIDKey(CommandTpm.DefaultSrkHandle, "", "", false)).DoesNothing(); //A.CallTo(() => tpm.getPcrList(TpmAlgId.Sha1, A.Ignored)).Returns(sha1Values); //A.CallTo(() => tpm.getPcrList(TpmAlgId.Sha256, A.Ignored)).Returns(sha256Values); A.CallTo(() => tpm.GetQuote(CommandTpm.DefaultAkHandle, TpmAlgId.Sha256, secret, out ctqr, A.Ignored)).DoesNothing(); @@ -103,8 +102,7 @@ namespace hirsTest { 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.CreateLDevIDKey(CommandTpm.DefaultSrkHandle, "", "", false)).DoesNothing(); A.CallTo(() => tpm.GetPcrList(TpmAlgId.Sha1, A.Ignored)).Returns(sha1Values); A.CallTo(() => tpm.GetPcrList(TpmAlgId.Sha256, A.Ignored)).Returns(sha256Values);