Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ public String getEventContentStr() {
case EvConstants.EV_EFI_SPDM_DEVICE_AUTHORITY:
try {
sb.append(new UefiVariable(eventContent));
} catch (CertificateException | NoSuchAlgorithmException | IOException exception) {
} catch (NoSuchAlgorithmException | IOException exception) {
log.error(exception);
sb.append(exception);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ public String getVendorTableReference() {
* published that represent standards that one can find further
* information on the configuration table being referenced.
* Refer to section 4.6 of UEFI spec v 2.8, page 101.
* defaultValue – the value to be returned if the requested member is missing
*
* @param lookupValue specific value to look up
* @return A String of major UUID parameters
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import hirs.utils.HexUtils;
import lombok.Getter;
import lombok.extern.log4j.Log4j2;

import java.io.ByteArrayInputStream;
import java.io.IOException;
Expand All @@ -11,14 +12,16 @@

/**
* Class for processing either
* 1) the contents of a Secure Boot PK, KEK, DB or DBX contents,
* used for EFIVariables associated with Secure Boot,
* as defined by Section 32.4.1 Signature Database from the UEFI 2.8 specification
* 2) the contents of an SPDM devdb,
* used for SPDM Device Policy or Device Authority, whose data is an EFIVariable
* EFIVariable data for SPDM Device Policy: UefiSignatureList
* EFIVariable data for SPDM Device: UefiSignatureData only
* as defined by PFP v1.06 Rev52, Section 10.4
* 1) the contents of a Secure Boot PK, KEK, DB or DBX contents,
* used for EFIVariables associated with Secure Boot,
* as defined by Section 32.4.1 Signature Database from the UEFI 2.8 specification
* EV_EFI_VARIABLE_DRIVER_CONFIG
* EV_EFI_VARIABLE_AUTHORITY
* 2) the contents of an SPDM devdb,
* used for SPDM Device Policy or Device Authority, whose data is an EFIVariable
* EFIVariable data for EV_EFI_SPDM_DEVICE_POLICY: UefiSignatureList
* EFIVariable data for EV_EFI_SPDM_DEVICE_AUTHORITY : UefiSignatureData only
* as defined by PFP v1.06 Rev52, Section 10.4
* <p>
* typedef struct _EFI_SIGNATURE_DATA {
* EFI_GUID SignatureOwner;
Expand All @@ -29,6 +32,7 @@
* will contain the "the SHA-256 hash of the binary".
* So the Signature Data depends upon the Signature Type from the EFI Signature List.
*/
@Log4j2
public class UefiSignatureData {
/**
* UEFI Certificate GUID.
Expand Down Expand Up @@ -63,10 +67,10 @@ public class UefiSignatureData {
*/
private final byte[] binaryHash = new byte[UefiConstants.SIZE_32];
/**
* UEFI Signature data status.
* UEFI Signature data error status.
*/
@Getter
private String status = "Signature Data contains a valid Certificate";
private String errorStatus = "";

/**
* UefiSignatureData constructor.
Expand All @@ -78,7 +82,7 @@ public class UefiSignatureData {
* @throws java.security.NoSuchAlgorithmException if there's a problem hashing the certificate.
*/
UefiSignatureData(final ByteArrayInputStream inputStream, final UefiGuid sigType)
throws IOException, CertificateException, NoSuchAlgorithmException {
throws IOException, NoSuchAlgorithmException {
signatureType = sigType;
// UEFI spec section 32.5.3.3 states that SignatureListType of EFI_CERT_SHA256_GUID
// only contains a hash, not a cert
Expand All @@ -90,28 +94,20 @@ public class UefiSignatureData {
} else if (sigType.getVendorTableReference().equals("EFI_CERT_X509_GUID")) {
inputStream.read(guid);
efiVarGuid = new UefiGuid(guid);
// Read in Type and Length separately so we calculate the rest of the cert size
byte[] certType = new byte[UefiConstants.SIZE_2];
inputStream.read(certType);
byte[] certLength = new byte[UefiConstants.SIZE_2];
inputStream.read(certLength);
int cLength = new BigInteger(certLength).intValue() + UefiConstants.SIZE_4;
byte[] certData = new byte[cLength];
inputStream.read(certData);
// put the cert back together
byte[] certBlob = new byte[cLength + UefiConstants.SIZE_4];
System.arraycopy(certType, 0, certBlob, 0, UefiConstants.SIZE_2);
System.arraycopy(certLength, 0, certBlob, UefiConstants.OFFSET_2, UefiConstants.SIZE_2);
System.arraycopy(certData, 0, certBlob, UefiConstants.OFFSET_4, cLength);
cert = new UefiX509Cert(certBlob);
} else if (sigType.isUnknownUUID()) {
//status = "Signature List Type has an unknown GUID: " + efiGuid.toString();
status = "Signature List Type has an unknown GUID";
return;
} else { // else process as a cert (RH SHIM does this)
processC509Cert(inputStream);
efiVarGuid = sigType;
} else {
errorStatus = "Signature List Type has either an unknown GUID or a type that hasn't been implemented yet";
return;
}
// else if (sigType.isUnknownUUID()) {
// //status = "Signature List Type has an unknown GUID: " + efiGuid.toString();
// status = "Signature List Type has an unknown GUID";
// return;
// } else { // else process as a cert (RH SHIM does this)
// processC509Cert(inputStream);
// efiVarGuid = sigType;
// }

valid = true;
}

Expand Down Expand Up @@ -140,20 +136,26 @@ public class UefiSignatureData {
* @throws java.security.NoSuchAlgorithmException if there's a problem creating a hash.
*/
private void processC509Cert(final ByteArrayInputStream inputStream)
throws IOException, CertificateException, NoSuchAlgorithmException {
throws IOException, NoSuchAlgorithmException {

// Read in Type and Length separately so we calculate the rest of the cert size
byte[] certType = new byte[UefiConstants.SIZE_2];
inputStream.read(certType);
byte[] certLength = new byte[UefiConstants.SIZE_2];
inputStream.read(certLength);
int cLength = new BigInteger(certLength).intValue() + UefiConstants.SIZE_4;
byte[] certData = new byte[cLength];
int certDataLength = new BigInteger(certLength).intValue();
byte[] certData = new byte[certDataLength];
inputStream.read(certData);
// put the cert back together
byte[] certBlob = new byte[cLength + UefiConstants.SIZE_4];
byte[] certBlob = new byte[certDataLength + UefiConstants.SIZE_4];
System.arraycopy(certType, 0, certBlob, 0, 2);
System.arraycopy(certLength, 0, certBlob, 2, 2);
System.arraycopy(certData, 0, certBlob, UefiConstants.OFFSET_4, cLength);
cert = new UefiX509Cert(certBlob);
System.arraycopy(certData, 0, certBlob, UefiConstants.OFFSET_4, certDataLength);
try {
cert = new UefiX509Cert(certBlob);
} catch (CertificateException e) {
errorStatus = "\n **** UefiSignatureData Certificate Issue ****: " + e.getMessage();
log.warn("UefiSignatureData Certificate Issue: {}", e.getMessage());
}
}

/**
Expand All @@ -164,14 +166,18 @@ private void processC509Cert(final ByteArrayInputStream inputStream)
public String toString() {
String sigInfo = "";
if (!valid) {
sigInfo = status;
sigInfo = errorStatus;
} else {
if (signatureType.getVendorTableReference().equals("EFI_CERT_SHA256_GUID")) {
sigInfo += " UEFI Signature Owner = " + efiVarGuid.toString() + "\n";
sigInfo += " Binary Hash = " + HexUtils.byteArrayToHexString(binaryHash) + "\n";
} else {
sigInfo += " UEFI Signature Owner = " + efiVarGuid.toString() + "\n";
sigInfo += cert.toString();
if (errorStatus.isEmpty()) {
sigInfo += cert.toString();
} else {
sigInfo += errorStatus;
}
}
}
return sigInfo;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,21 @@
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.ArrayList;

/**
* Class for processing either
* 1) the contents of a Secure Boot PK, KEK, DB or DBX contents,
* used for EFIVariables associated with Secure Boot,
* as defined by Section 32.4.1 Signature Database from the UEFI 2.8 specification
* 2) the contents of an SPDM devdb,
* used for SPDM Device Policy, whose data is an EFIVariable
* as defined by PFP v1.06 Rev52, Section 10.4
* 1) the contents of a Secure Boot PK, KEK, DB or DBX contents,
* used for EFIVariables associated with Secure Boot,
* as defined by Section 32.4.1 Signature Database from the UEFI 2.8 specification
* 2) the contents of an SPDM devdb,
* used for SPDM Device Policy, whose data is an EFIVariable
* as defined by PFP v1.06 Rev52, Section 10.4
* <p>
* An EFI Signature List is actually a list of Certificates used to verify a Signature.
* This is mainly found in PCR[7] UEFI variables for either the
* Secure Boot PK, KEK, Db and DBx variables
* or the SPDM devdb variable (under EV_EFI_SPDM_DEVICE_POLICY).
* - Secure Boot PK, KEK, Db and DBx variables
* - or the SPDM devdb variable (under EV_EFI_SPDM_DEVICE_POLICY).
* <p>
* typedef struct _EFI_SIGNATURE_LIST {
* EFI_GUID SignatureType;
Expand All @@ -32,18 +31,18 @@
* } EFI_SIGNATURE_LIST;
* <p>
* SignatureListHeader (contents common to any Signature Type)
* - SignatureType
* - SignatureListSize
* - SignatureHeaderSize
* - SignatureSize
* - SignatureType (SHA256, X509)
* - SignatureListSize
* - SignatureHeaderSize
* - SignatureSize
* SignatureHeader (contents depend on the SignatureType)
* - The format of this header is specified by the SignatureType (SHA256, X509).
* - The format of this header is specified by the SignatureType (SHA256, X509).
* Signatures[][] is an array of signatures.
* - Each signature is SignatureSize bytes in length.
* - The format of the signature is defined by SignatureType (SHA256, X509).
* - Each signature is SignatureSize bytes in length.
* - The format of the signature is defined by SignatureType (SHA256, X509).
* <p>
* / |-------------------------| ------- SignatureType
* / | Signature List Header | SignatureListSize
* / / |-------------------------| ------- SignatureType
* / / | Signature List Header | SignatureListSize
* |---------------------| / |-------------------------|\ SignatureHeaderSize
* | Signature List #0 | / | Signature Header | \ _____ SignatureSize
* | | / |-------------------------|
Expand All @@ -54,10 +53,10 @@
* | | | Signature #2 | (1 cert or hash)
* | | |-------------------------|
* |---------------------| | ... |
* \ | |
* \ |-------------------------|
* \ | Signature #n |
* \ |-------------------------|
* | | \ | |
* | | \ |-------------------------|
* | | \ | Signature #n |
* | | \ |-------------------------|
*/
public class UefiSignatureList {
/**
Expand Down Expand Up @@ -151,7 +150,7 @@ public class UefiSignatureList {
* @throws java.security.NoSuchAlgorithmException if there's a problem hashing the certificate.
*/
UefiSignatureList(final ByteArrayInputStream lists)
throws IOException, CertificateException, NoSuchAlgorithmException {
throws IOException, NoSuchAlgorithmException {
byte[] guid = new byte[UefiConstants.SIZE_16];
lists.read(guid);
signatureType = new UefiGuid(guid);
Expand Down Expand Up @@ -190,13 +189,13 @@ public class UefiSignatureList {
* @throws java.io.IOException If there's a problem parsing the signature data.
*/
private void processSignatureList(final byte[] efiSigData)
throws CertificateException, NoSuchAlgorithmException, IOException {
throws NoSuchAlgorithmException, IOException {
efiSigDataIS = new ByteArrayInputStream(efiSigData);
while (efiSigDataIS.available() > 0) {
UefiSignatureData tmpSigData = new UefiSignatureData(efiSigDataIS, signatureType);
if (!tmpSigData.isValid()) {
dataValid = false;
dataInvalidStatus = tmpSigData.getStatus();
dataInvalidStatus = tmpSigData.getErrorStatus();
break;
}
sigList.add(tmpSigData);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.List;

Expand Down Expand Up @@ -82,15 +81,13 @@ public class UefiVariable {
* the class used to parse the data within the "VariableData".
*
* @param variableData byte array holding the UEFI Variable.
* @throws java.security.cert.CertificateException If there a problem
* parsing the X509 certificate.
* @throws java.security.NoSuchAlgorithmException if there's a problem
* hashing the certificate.
* @throws java.io.IOException If there's a problem
* parsing the signature data.
*/
public UefiVariable(final byte[] variableData)
throws CertificateException, NoSuchAlgorithmException, IOException {
throws NoSuchAlgorithmException, IOException {
certSuperList = new ArrayList<>();
byte[] guid = new byte[UefiConstants.SIZE_16];
byte[] nameLength = new byte[UefiConstants.SIZE_8];
Expand Down Expand Up @@ -164,7 +161,7 @@ public UefiVariable(final byte[] variableData)
* parsing the signature data.
*/
private void processSigList(final byte[] data)
throws CertificateException, NoSuchAlgorithmException, IOException {
throws NoSuchAlgorithmException, IOException {
ByteArrayInputStream certData = new ByteArrayInputStream(data);
while (certData.available() > 0) {
UefiSignatureList list;
Expand Down Expand Up @@ -204,7 +201,7 @@ private void processSigList(final byte[] data)
* @throws java.io.IOException If there's a problem parsing the signature data.
*/
private void processSigDataX509(final byte[] efiSigData)
throws CertificateException, NoSuchAlgorithmException, IOException {
throws NoSuchAlgorithmException, IOException {

ByteArrayInputStream efiSigDataIS = new ByteArrayInputStream(efiSigData);
ArrayList<UefiSignatureData> sigList = new ArrayList<UefiSignatureData>();
Expand All @@ -222,7 +219,7 @@ private void processSigDataX509(final byte[] efiSigData)
UefiSignatureData tmpSigData = new UefiSignatureData(efiSigDataIS, signatureType);
if (!tmpSigData.isValid()) {
dataValid = false;
dataInvalidStatus = tmpSigData.getStatus();
dataInvalidStatus = tmpSigData.getErrorStatus();
break;
}
sigList.add(tmpSigData);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,14 @@ public class UefiX509Cert {
*/
public UefiX509Cert(final byte[] certData) throws CertificateException,
NoSuchAlgorithmException {
CertificateFactory cf;
cf = CertificateFactory.getInstance("X.509");
InputStream targetStream = new ByteArrayInputStream(certData);
cert = cf.generateCertificate(targetStream);
try {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream targetStream = new ByteArrayInputStream(certData);
cert = cf.generateCertificate(targetStream);
} catch (CertificateException e) {
throw new CertificateException("\n Error parsing UEFI X509 certificate: " + e.getMessage());
}

MessageDigest md = MessageDigest.getInstance("SHA1");
md.update(certData);
}
Expand Down
Loading