Improve output for ACA-signed certificates (#859)

This commit is contained in:
CAFB385655BEB1060E85B6C080B432F8EB2A2AF78459BD6532124977B933154A 2024-10-24 20:14:10 +00:00 committed by GitHub
parent b163691d49
commit 9662c08e76
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 49 additions and 26 deletions

View File

@ -116,7 +116,7 @@ public class AbstractProcessor {
+ "Unable to issue certificates"); + "Unable to issue certificates");
} }
ContentSigner signer = new JcaContentSignerBuilder("SHA1WithRSA") ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSA")
.setProvider("BC").build(getPrivateKey()); .setProvider("BC").build(getPrivateKey());
X509CertificateHolder holder = builder.build(signer); X509CertificateHolder holder = builder.build(signer);
return new JcaX509CertificateConverter() return new JcaX509CertificateConverter()

View File

@ -160,16 +160,14 @@ public class CertificateRequestProcessor extends AbstractProcessor {
attestationCertificate); attestationCertificate);
byte[] derEncodedLdevidCertificate = ProvisionUtils.getDerEncodedCertificate( byte[] derEncodedLdevidCertificate = ProvisionUtils.getDerEncodedCertificate(
ldevidCertificate); ldevidCertificate);
String pemEncodedAttestationCertificate = ProvisionUtils.getPemEncodedCertificate(
attestationCertificate);
String pemEncodedLdevidCertificate = ProvisionUtils.getPemEncodedCertificate(
ldevidCertificate);
// We validated the nonce and made use of the identity claim so state can be deleted // We validated the nonce and made use of the identity claim so state can be deleted
tpm2ProvisionerStateRepository.delete(tpm2ProvisionerState); tpm2ProvisionerStateRepository.delete(tpm2ProvisionerState);
// Package the signed certificates into a response
ByteString certificateBytes = ByteString
.copyFrom(derEncodedAttestationCertificate);
ByteString ldevidCertificateBytes = ByteString
.copyFrom(derEncodedLdevidCertificate);
boolean generateAtt = saveAttestationCertificate(certificateRepository, derEncodedAttestationCertificate, boolean generateAtt = saveAttestationCertificate(certificateRepository, derEncodedAttestationCertificate,
endorsementCredential, platformCredentials, device, false); endorsementCredential, platformCredentials, device, false);
boolean generateLDevID = saveAttestationCertificate(certificateRepository, derEncodedLdevidCertificate, boolean generateLDevID = saveAttestationCertificate(certificateRepository, derEncodedLdevidCertificate,
@ -178,10 +176,10 @@ public class CertificateRequestProcessor extends AbstractProcessor {
ProvisionerTpm2.CertificateResponse.Builder builder = ProvisionerTpm2.CertificateResponse. ProvisionerTpm2.CertificateResponse.Builder builder = ProvisionerTpm2.CertificateResponse.
newBuilder().setStatus(ProvisionerTpm2.ResponseStatus.PASS); newBuilder().setStatus(ProvisionerTpm2.ResponseStatus.PASS);
if (generateAtt) { if (generateAtt) {
builder = builder.setCertificate(certificateBytes); builder = builder.setCertificate(pemEncodedAttestationCertificate);
} }
if (generateLDevID) { if (generateLDevID) {
builder = builder.setLdevidCertificate(ldevidCertificateBytes); builder = builder.setLdevidCertificate(pemEncodedLdevidCertificate);
} }
ProvisionerTpm2.CertificateResponse response = builder.build(); ProvisionerTpm2.CertificateResponse response = builder.build();
@ -190,20 +188,19 @@ public class CertificateRequestProcessor extends AbstractProcessor {
else { else {
byte[] derEncodedAttestationCertificate = ProvisionUtils.getDerEncodedCertificate( byte[] derEncodedAttestationCertificate = ProvisionUtils.getDerEncodedCertificate(
attestationCertificate); attestationCertificate);
String pemEncodedAttestationCertificate = ProvisionUtils.getPemEncodedCertificate(
attestationCertificate);
// We validated the nonce and made use of the identity claim so state can be deleted // We validated the nonce and made use of the identity claim so state can be deleted
tpm2ProvisionerStateRepository.delete(tpm2ProvisionerState); tpm2ProvisionerStateRepository.delete(tpm2ProvisionerState);
// Package the signed certificates into a response
ByteString certificateBytes = ByteString
.copyFrom(derEncodedAttestationCertificate);
ProvisionerTpm2.CertificateResponse.Builder builder = ProvisionerTpm2.CertificateResponse. ProvisionerTpm2.CertificateResponse.Builder builder = ProvisionerTpm2.CertificateResponse.
newBuilder().setStatus(ProvisionerTpm2.ResponseStatus.PASS); newBuilder().setStatus(ProvisionerTpm2.ResponseStatus.PASS);
boolean generateAtt = saveAttestationCertificate(certificateRepository, derEncodedAttestationCertificate, boolean generateAtt = saveAttestationCertificate(certificateRepository, derEncodedAttestationCertificate,
endorsementCredential, platformCredentials, device, false); endorsementCredential, platformCredentials, device, false);
if (generateAtt) { if (generateAtt) {
builder = builder.setCertificate(certificateBytes); builder = builder.setCertificate(pemEncodedAttestationCertificate);
} }
ProvisionerTpm2.CertificateResponse response = builder.build(); ProvisionerTpm2.CertificateResponse response = builder.build();

View File

@ -18,6 +18,7 @@ import hirs.utils.enums.DeviceInfoEnums;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import org.apache.commons.codec.binary.Hex; import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ArrayUtils;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import javax.crypto.BadPaddingException; import javax.crypto.BadPaddingException;
import javax.crypto.Cipher; import javax.crypto.Cipher;
@ -28,6 +29,8 @@ import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.OAEPParameterSpec; import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource; import javax.crypto.spec.PSource;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.StringWriter;
import java.math.BigInteger; import java.math.BigInteger;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@ -107,6 +110,29 @@ public final class ProvisionUtils {
} }
} }
/**
* Helper method to extract a PEM encoded certificate from an X509 certificate.
*
* @param certificate the X509 certificate to be converted to PEM encoding
* @throws {@link UnexpectedServerException} if error occurs during encoding retrieval
* @return the string representing the PEM encoded certificate
*/
public static String getPemEncodedCertificate(final X509Certificate certificate) {
try {
final StringWriter stringWriter = new StringWriter();
final JcaPEMWriter pemWriter = new JcaPEMWriter(stringWriter);
pemWriter.writeObject(certificate);
pemWriter.flush();
pemWriter.close();
return stringWriter.toString();
} catch (IOException ioEx) {
log.error("Error converting certificate to PEM Encoding.", ioEx);
throw new UnexpectedServerException(
"Encountered error while converting X509 Certificate to PEM Encoding: "
+ ioEx.getMessage(), ioEx);
}
}
/** /**
* Parse public key from public data segment generated by TPM 2.0. * Parse public key from public data segment generated by TPM 2.0.
* @param publicArea the public area segment to parse * @param publicArea the public area segment to parse

View File

@ -95,8 +95,8 @@ message CertificateRequest {
} }
message CertificateResponse { message CertificateResponse {
optional bytes certificate = 1; optional string certificate = 1;
optional ResponseStatus status = 2 [default = FAIL]; optional ResponseStatus status = 2 [default = FAIL];
optional bytes ldevidCertificate = 3; optional string ldevidCertificate = 3;
} }

View File

@ -297,7 +297,7 @@ namespace hirs {
tpm.GetQuote(CommandTpm.DefaultAkHandle, Tpm2Lib.TpmAlgId.Sha256, recoveredSecret, out CommandTpmQuoteResponse ctqr, selectPcrs); tpm.GetQuote(CommandTpm.DefaultAkHandle, Tpm2Lib.TpmAlgId.Sha256, recoveredSecret, out CommandTpmQuoteResponse ctqr, selectPcrs);
Log.Information("----> Nonce successfully decrypted. Sending attestation certificate request"); Log.Information("----> Nonce successfully decrypted. Sending attestation certificate request");
CertificateRequest akCertReq = acaClient.CreateAkCertificateRequest(recoveredSecret, ctqr); CertificateRequest akCertReq = acaClient.CreateAkCertificateRequest(recoveredSecret, ctqr);
byte[] certificate; string certificate;
Log.Debug("Communicate certificate request to the ACA."); Log.Debug("Communicate certificate request to the ACA.");
CertificateResponse cr = await acaClient.PostCertificateRequest(akCertReq); CertificateResponse cr = await acaClient.PostCertificateRequest(akCertReq);
Log.Debug("Response received from the ACA regarding the certificate request."); Log.Debug("Response received from the ACA regarding the certificate request.");
@ -311,34 +311,34 @@ namespace hirs {
} }
} }
if (cr.HasCertificate) { if (cr.HasCertificate) {
certificate = cr.Certificate.ToByteArray(); // contains certificate certificate = cr.Certificate.ToString(); // contains certificate
String certificateDirPath = settings.certificate_output_directory; String certificateDirPath = settings.certificate_output_directory;
if (certificateDirPath != null) { if (certificateDirPath != null) {
String certificateFilePath = FormatCertificatePath(dv, certificateDirPath, DefaultAKCertFileName); String certificateFilePath = FormatCertificatePath(dv, certificateDirPath, DefaultAKCertFileName);
try { try {
File.WriteAllBytes(certificateFilePath, certificate); File.WriteAllText(certificateFilePath, certificate);
Log.Debug("Attestation key certificate written to local file system: {0}", certificateFilePath); Log.Debug("Attestation key certificate written to local file system: {0}", certificateFilePath);
} }
catch (Exception) { catch (Exception) {
Log.Debug("Failed to write attestation key 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)); Log.Debug("Printing attestation key certificate: " + certificate);
} }
if (cr.HasLdevidCertificate) { if (cr.HasLdevidCertificate) {
certificate = cr.LdevidCertificate.ToByteArray(); // contains certificate certificate = cr.LdevidCertificate.ToString(); // contains certificate
String certificateDirPath = settings.certificate_output_directory; String certificateDirPath = settings.certificate_output_directory;
if (certificateDirPath != null) { if (certificateDirPath != null) {
String certificateFilePath = FormatCertificatePath(dv, certificateDirPath, DefaultLDevIDCertFileName); String certificateFilePath = FormatCertificatePath(dv, certificateDirPath, DefaultLDevIDCertFileName);
try { try {
File.WriteAllBytes(certificateFilePath, certificate); File.WriteAllText(certificateFilePath, certificate);
Log.Debug("LDevID certificate written to local file system: {0}", certificateFilePath); Log.Debug("LDevID certificate written to local file system: {0}", certificateFilePath);
} }
catch (Exception) { catch (Exception) {
Log.Debug("Failed to write LDevID certificate to local file system."); Log.Debug("Failed to write LDevID certificate to local file system.");
} }
} }
Log.Debug("Printing LDevID certificate: " + BitConverter.ToString(certificate)); Log.Debug("Printing LDevID certificate: " + certificate);
} }
} else { } else {
result = ClientExitCodes.MAKE_CREDENTIAL_BLOB_MALFORMED; result = ClientExitCodes.MAKE_CREDENTIAL_BLOB_MALFORMED;

View File

@ -14,7 +14,7 @@ namespace hirsTest {
const string address = "https://127.0.0.1:8443/"; const string address = "https://127.0.0.1:8443/";
byte[] ekCert = Encoding.UTF8.GetBytes("EK CERTIFICATE"); byte[] ekCert = Encoding.UTF8.GetBytes("EK CERTIFICATE");
byte[] secret = Encoding.UTF8.GetBytes("AuthCredential Secret"); byte[] secret = Encoding.UTF8.GetBytes("AuthCredential Secret");
byte[] acaIssuedCert = Encoding.UTF8.GetBytes("ACA ISSUED CERTIFICATE"); string acaIssuedCert = "ACA ISSUED CERTIFICATE";
byte[] integrityHMAC = Convert.FromBase64String("VAtedc1RlNA1w0XfrtwmhE0ILBlILP6163Tur5HRIo0="); byte[] integrityHMAC = Convert.FromBase64String("VAtedc1RlNA1w0XfrtwmhE0ILBlILP6163Tur5HRIo0=");
byte[] encIdentity = Convert.FromBase64String("6e2oGBsK3H9Vzbj667ZsjnVOtvpSpQ=="); byte[] encIdentity = Convert.FromBase64String("6e2oGBsK3H9Vzbj667ZsjnVOtvpSpQ==");
byte[] encryptedSecret = Convert.FromBase64String("NekvnOX8RPRdyd0/cxBI4FTCuNkiu0KAnS28yT7yYJUL5Lwfcv5ctEK6zQA0fq0IsX5TlAYSidGKxrAilOSwALJmJ+m7sMiXwMKrZn1cd4gzXObZEQimQoWgSEQbPO7rfpUn1UfI8K5SzmUFUTxc5X3D8zFonaEBp6QCjtdLegKGgioCDcQFdz20Y0PFAa1Itug7YbZdCFpfit570eQQinmqdVryiNyn6CLQdMgIejuBxoEpoTSWszB5eFKEdn5g/+8wcvhp6RpNBQ0hikF+6688TOVK/j8n3JDwKVltJ/WNHjVO+lxa2aLIMJRgs5ZRuzuz6OSMf10KqJjSWZE04w=="); byte[] encryptedSecret = Convert.FromBase64String("NekvnOX8RPRdyd0/cxBI4FTCuNkiu0KAnS28yT7yYJUL5Lwfcv5ctEK6zQA0fq0IsX5TlAYSidGKxrAilOSwALJmJ+m7sMiXwMKrZn1cd4gzXObZEQimQoWgSEQbPO7rfpUn1UfI8K5SzmUFUTxc5X3D8zFonaEBp6QCjtdLegKGgioCDcQFdz20Y0PFAa1Itug7YbZdCFpfit570eQQinmqdVryiNyn6CLQdMgIejuBxoEpoTSWszB5eFKEdn5g/+8wcvhp6RpNBQ0hikF+6688TOVK/j8n3JDwKVltJ/WNHjVO+lxa2aLIMJRgs5ZRuzuz6OSMf10KqJjSWZE04w==");
@ -34,7 +34,7 @@ namespace hirsTest {
idClaimResp.CredentialBlob = Google.Protobuf.ByteString.CopyFrom(credentialBlob); idClaimResp.CredentialBlob = Google.Protobuf.ByteString.CopyFrom(credentialBlob);
CertificateResponse certResp = new(); CertificateResponse certResp = new();
certResp.Status = ResponseStatus.Pass; certResp.Status = ResponseStatus.Pass;
certResp.Certificate = Google.Protobuf.ByteString.CopyFrom(acaIssuedCert); certResp.Certificate = acaIssuedCert;
IHirsAcaTpm tpm = A.Fake<IHirsAcaTpm>(); IHirsAcaTpm tpm = A.Fake<IHirsAcaTpm>();
byte[] name = null, qualifiedName = null; byte[] name = null, qualifiedName = null;

View File

@ -95,8 +95,8 @@ message CertificateRequest {
} }
message CertificateResponse { message CertificateResponse {
optional bytes certificate = 1; optional string certificate = 1;
optional ResponseStatus status = 2 [default = FAIL]; optional ResponseStatus status = 2 [default = FAIL];
optional bytes ldevidCertificate = 3; optional string ldevidCertificate = 3;
} }