diff --git a/HIRS_AttestationCA/build.gradle b/HIRS_AttestationCA/build.gradle index 893997d90..30f6e4158 100644 --- a/HIRS_AttestationCA/build.gradle +++ b/HIRS_AttestationCA/build.gradle @@ -46,10 +46,10 @@ dependencies { implementation 'org.apache.logging.log4j:log4j-core:2.19.0' implementation 'org.apache.logging.log4j:log4j-api:2.19.0' + testImplementation 'org.apache.directory.studio:org.apache.commons.io:2.4' + testImplementation 'org.hamcrest:hamcrest:2.2' testImplementation 'org.junit.jupiter:junit-jupiter:5.9.3' testImplementation 'org.junit.platform:junit-platform-launcher:1.9.3' - testImplementation 'org.hamcrest:hamcrest:2.2' - testImplementation 'org.mockito:mockito-core:4.2.0' // spring management diff --git a/HIRS_AttestationCA/src/test/java/hirs/attestationca/persist/provision/helper/CredentialManagementHelperTest.java b/HIRS_AttestationCA/src/test/java/hirs/attestationca/persist/provision/helper/CredentialManagementHelperTest.java new file mode 100644 index 000000000..07c99470f --- /dev/null +++ b/HIRS_AttestationCA/src/test/java/hirs/attestationca/persist/provision/helper/CredentialManagementHelperTest.java @@ -0,0 +1,117 @@ +package hirs.attestationca.persist.provision.helper; + +import hirs.attestationca.persist.entity.manager.CertificateRepository; +import hirs.attestationca.persist.entity.userdefined.Certificate; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.FileInputStream; +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; + +/** + * Unit tests for {@see CredentialManagementHelper}. + */ +public class CredentialManagementHelperTest { + + @Mock + private CertificateRepository certificateRepository; + + private static final String EK_HEADER_TRUNCATED + = "/certificates/nuc-1/ek_cert_7_byte_header_removed.cer"; + private static final String EK_UNTOUCHED + = "/certificates/nuc-1/ek_cert_untouched.cer"; + + /** + * Setup mocks. + */ + @BeforeEach + public void setUp() { + //certificateRepository = mock(CertificateRepository.class); + MockitoAnnotations.initMocks(this); + } + + /** + * Tests exception generated if providing a null cert repository. + * @throws IOException if an IO error occurs + */ + @Test + public void processNullCertRep() throws IOException { + // use valid EK byte array + String path = CredentialManagementHelperTest.class.getResource(EK_UNTOUCHED).getPath(); + byte[] ekBytes = IOUtils.toByteArray(new FileInputStream(path)); + assertThrows(IllegalArgumentException.class, () -> + CredentialManagementHelper.storeEndorsementCredential(null, ekBytes, "testName")); + } + + /** + * Tests exception generated when providing a null EK byte array. + */ + @Test + public void processNullEndorsementCredential() { + assertThrows(IllegalArgumentException.class, () -> + CredentialManagementHelper.storeEndorsementCredential(certificateRepository, null, "testName")); + } + + /** + * Tests exception generated when providing an empty array of bytes as the EK. + */ + @Test + public void processEmptyEndorsementCredential() { + assertThrows(IllegalArgumentException.class, () -> + CredentialManagementHelper.storeEndorsementCredential(certificateRepository, new byte[0], "testName")); + } + + /** + * Tests processing an invalid EK (too small of an array). + */ + @Test + public void processInvalidEndorsementCredentialCase1() { + byte[] ekBytes = new byte[] {1}; + assertThrows(IllegalArgumentException.class, () -> + CredentialManagementHelper.storeEndorsementCredential(certificateRepository, ekBytes, "testName")); + } + + /** + * Tests processing an invalid EK (garbage bytes of a reasonable length). + */ + @Test + public void processInvalidEndorsementCredentialCase2() { + byte[] ekBytes = new byte[] {1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0}; + assertThrows(IllegalArgumentException.class, () -> + CredentialManagementHelper.storeEndorsementCredential(certificateRepository, ekBytes, "testName")); + } + + /** + * Tests processing a valid EK with the 7 byte header in tact. + * @throws IOException if an IO error occurs + */ + @Test + public void parseUntouchedEndorsementCredential() throws IOException { + String path = CredentialManagementHelperTest.class.getResource(EK_UNTOUCHED).getPath(); + byte[] ekBytes = IOUtils.toByteArray(new FileInputStream(path)); + + CredentialManagementHelper.storeEndorsementCredential(certificateRepository, ekBytes, "testName"); + verify(certificateRepository).save(any(Certificate.class)); + } + + /** + * Tests processing a valid EK with the 7 byte header already stripped. + * @throws IOException if an IO error occurs + */ + @Test + public void parseHeaderTruncatedEndorsementCredential() throws IOException { + String path = CredentialManagementHelperTest.class.getResource(EK_HEADER_TRUNCATED) + .getPath(); + byte[] ekBytes = IOUtils.toByteArray(new FileInputStream(path)); + + CredentialManagementHelper.storeEndorsementCredential(certificateRepository, ekBytes, "testName"); + verify(certificateRepository).save(any(Certificate.class)); + } +} diff --git a/HIRS_AttestationCA/src/test/java/hirs/attestationca/persist/provision/helper/IssuedCertificateAttributeHelperTest.java b/HIRS_AttestationCA/src/test/java/hirs/attestationca/persist/provision/helper/IssuedCertificateAttributeHelperTest.java new file mode 100644 index 000000000..eb4710a95 --- /dev/null +++ b/HIRS_AttestationCA/src/test/java/hirs/attestationca/persist/provision/helper/IssuedCertificateAttributeHelperTest.java @@ -0,0 +1,206 @@ +package hirs.attestationca.persist.provision.helper; + +import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential; +import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1Set; +import org.bouncycastle.asn1.ASN1TaggedObject; +import org.bouncycastle.asn1.DLSequence; +import org.bouncycastle.asn1.x509.Extension; +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +/** + * Tests for {@see IssuedCertificateAttributeHelper}. + */ +public class IssuedCertificateAttributeHelperTest { + + private static final String NUC1_EC = "/certificates/nuc-1/tpmcert.pem"; + + private static final String INTEL_PC = "/certificates/platform_certs_2/" + + "Intel_pc.pem"; + + private static final String TEST_HOSTNAME = "box1"; + + private static final String TPM_MANUFACTURER = "2.23.133.2.1"; + + private static final String TPM_MODEL = "2.23.133.2.2"; + + private static final String TPM_VERSION = "2.23.133.2.3"; + + private static final String TPM_ID_LABEL_OID = "2.23.133.2.15"; + + private static final String PLATFORM_MANUFACTURER = "2.23.133.2.4"; + + private static final String PLATFORM_MODEL = "2.23.133.2.5"; + + private static final String PLATFORM_VERSION = "2.23.133.2.6"; + + /** + * Test that provide a null host name and is rejected. + * @throws IOException an IO error occurs + */ + @Test + public void rejectNullHostName() throws IOException { + assertThrows(IllegalArgumentException.class, () -> + IssuedCertificateAttributeHelper.buildSubjectAlternativeNameFromCerts(null, null, "")); + } + + /** + * Test that subject alt name can be built without an EC or PC. + * @throws IOException an IO error occurs + */ + @Test + public void buildAttributesNoEndorsementNoPlatform() throws IOException { + Extension subjectAlternativeName = + IssuedCertificateAttributeHelper.buildSubjectAlternativeNameFromCerts( + null, new ArrayList(), TEST_HOSTNAME); + + Map subjectAlternativeNameAttrMap = getSubjectAlternativeNameAttributes( + subjectAlternativeName); + + assertNull(subjectAlternativeNameAttrMap.get(TPM_MANUFACTURER)); + assertNull(subjectAlternativeNameAttrMap.get(TPM_MODEL)); + assertNull(subjectAlternativeNameAttrMap.get(TPM_VERSION)); + assertNull(subjectAlternativeNameAttrMap.get(PLATFORM_MANUFACTURER)); + assertNull(subjectAlternativeNameAttrMap.get(PLATFORM_MODEL)); + assertNull(subjectAlternativeNameAttrMap.get(PLATFORM_VERSION)); + assertEquals(TEST_HOSTNAME, subjectAlternativeNameAttrMap.get(TPM_ID_LABEL_OID)); + } + + /** + * Test that subject alt name can be built with an EC but no PC. + * @throws IOException an IO error occurs + * @throws URISyntaxException unrecognized URI for EC Path + */ + @Test + public void buildAttributesEndorsementNoPlatform() throws IOException, URISyntaxException { + Path endorsementCredentialPath = Paths.get(getClass().getResource( + NUC1_EC).toURI()); + EndorsementCredential endorsementCredential = new EndorsementCredential( + endorsementCredentialPath); + Extension subjectAlternativeName = + IssuedCertificateAttributeHelper.buildSubjectAlternativeNameFromCerts( + endorsementCredential, new ArrayList(), TEST_HOSTNAME); + + Map subjectAlternativeNameAttrMap = getSubjectAlternativeNameAttributes( + subjectAlternativeName); + + assertEquals(endorsementCredential.getManufacturer(), + subjectAlternativeNameAttrMap.get(TPM_MANUFACTURER)); + assertEquals(endorsementCredential.getModel(), + subjectAlternativeNameAttrMap.get(TPM_MODEL)); + assertEquals(endorsementCredential.getVersion(), + subjectAlternativeNameAttrMap.get(TPM_VERSION)); + assertNull(subjectAlternativeNameAttrMap.get(PLATFORM_MANUFACTURER)); + assertNull(subjectAlternativeNameAttrMap.get(PLATFORM_MODEL)); + assertNull(subjectAlternativeNameAttrMap.get(PLATFORM_VERSION)); + assertEquals(subjectAlternativeNameAttrMap.get(TPM_ID_LABEL_OID), + TEST_HOSTNAME); + } + + /** + * Test that subject alt name can be built with an PC but no EC. + * @throws IOException an IO error occurs + * @throws URISyntaxException unrecognized URI for PC Path + */ + @Test + public void buildAttributesPlatformNoEndorsement() throws IOException, URISyntaxException { + Path platformCredentialPath = Paths.get(getClass().getResource( + INTEL_PC).toURI()); + PlatformCredential platformCredential = new PlatformCredential( + platformCredentialPath); + List platformCredentialList = new ArrayList<>(); + platformCredentialList.add(platformCredential); + Extension subjectAlternativeName = + IssuedCertificateAttributeHelper.buildSubjectAlternativeNameFromCerts( + null, platformCredentialList, TEST_HOSTNAME); + + Map subjectAlternativeNameAttrMap = getSubjectAlternativeNameAttributes( + subjectAlternativeName); + + assertNull(subjectAlternativeNameAttrMap.get(TPM_MANUFACTURER)); + assertNull(subjectAlternativeNameAttrMap.get(TPM_MODEL)); + assertNull(subjectAlternativeNameAttrMap.get(TPM_VERSION)); + assertEquals(platformCredential.getManufacturer(), + subjectAlternativeNameAttrMap.get(PLATFORM_MANUFACTURER)); + assertEquals(platformCredential.getModel(), + subjectAlternativeNameAttrMap.get(PLATFORM_MODEL)); + assertEquals(platformCredential.getVersion(), + subjectAlternativeNameAttrMap.get(PLATFORM_VERSION)); + assertEquals(TEST_HOSTNAME, + subjectAlternativeNameAttrMap.get(TPM_ID_LABEL_OID)); + } + + /** + * Test that subject alt name can be built with a PC and an EC. + * @throws IOException an IO error occurs + * @throws URISyntaxException unrecognized URI for EC or PC Path + */ + @Test + public void buildAttributesPlatformAndEndorsement() throws IOException, URISyntaxException { + Path endorsementCredentialPath = Paths.get(getClass().getResource( + NUC1_EC).toURI()); + Path platformCredentialPath = Paths.get(getClass().getResource( + INTEL_PC).toURI()); + EndorsementCredential endorsementCredential = new EndorsementCredential( + endorsementCredentialPath); + PlatformCredential platformCredential = new PlatformCredential( + platformCredentialPath); + List platformCredentialList = new ArrayList<>(); + platformCredentialList.add(platformCredential); + Extension subjectAlternativeName = + IssuedCertificateAttributeHelper.buildSubjectAlternativeNameFromCerts( + endorsementCredential, platformCredentialList, TEST_HOSTNAME); + + Map subjectAlternativeNameAttrMap = getSubjectAlternativeNameAttributes( + subjectAlternativeName); + + assertEquals(endorsementCredential.getManufacturer(), + subjectAlternativeNameAttrMap.get(TPM_MANUFACTURER)); + assertEquals(endorsementCredential.getModel(), + subjectAlternativeNameAttrMap.get(TPM_MODEL)); + assertEquals(endorsementCredential.getVersion(), + subjectAlternativeNameAttrMap.get(TPM_VERSION)); + assertEquals(platformCredential.getManufacturer(), + subjectAlternativeNameAttrMap.get(PLATFORM_MANUFACTURER)); + assertEquals(platformCredential.getModel(), + subjectAlternativeNameAttrMap.get(PLATFORM_MODEL)); + assertEquals(platformCredential.getVersion(), + subjectAlternativeNameAttrMap.get(PLATFORM_VERSION)); + assertEquals(TEST_HOSTNAME, + subjectAlternativeNameAttrMap.get(TPM_ID_LABEL_OID)); + } + + private Map getSubjectAlternativeNameAttributes( + Extension subjectAlternativeName) { + Map subjectAlternativeNameAttrMap = new HashMap<>(); + + DLSequence dlSequence = (DLSequence) subjectAlternativeName.getParsedValue(); + ASN1TaggedObject asn1TaggedObject = (ASN1TaggedObject) dlSequence.getObjectAt(0); + ASN1Sequence asn1Sequence = (ASN1Sequence) asn1TaggedObject.getObject(); + + Enumeration enumeration = asn1Sequence.getObjects(); + while (enumeration.hasMoreElements()) { + ASN1Set set = (ASN1Set) enumeration.nextElement(); + ASN1Sequence innerAsn1Sequence = (ASN1Sequence) set.getObjectAt(0); + + subjectAlternativeNameAttrMap.put(innerAsn1Sequence.getObjectAt(0).toString(), + innerAsn1Sequence.getObjectAt(1).toString()); + } + return subjectAlternativeNameAttrMap; + } +} diff --git a/HIRS_AttestationCA/src/test/resources/certificates/nuc-1/ek_cert_7_byte_header_removed.cer b/HIRS_AttestationCA/src/test/resources/certificates/nuc-1/ek_cert_7_byte_header_removed.cer new file mode 100644 index 000000000..f14093b1f Binary files /dev/null and b/HIRS_AttestationCA/src/test/resources/certificates/nuc-1/ek_cert_7_byte_header_removed.cer differ diff --git a/HIRS_AttestationCA/src/test/resources/certificates/nuc-1/ek_cert_untouched.cer b/HIRS_AttestationCA/src/test/resources/certificates/nuc-1/ek_cert_untouched.cer new file mode 100644 index 000000000..fbcbe8fba Binary files /dev/null and b/HIRS_AttestationCA/src/test/resources/certificates/nuc-1/ek_cert_untouched.cer differ diff --git a/HIRS_AttestationCA/src/test/resources/certificates/platform_certs_2/Intel_pc.pem b/HIRS_AttestationCA/src/test/resources/certificates/platform_certs_2/Intel_pc.pem new file mode 100644 index 000000000..9ea77f12c Binary files /dev/null and b/HIRS_AttestationCA/src/test/resources/certificates/platform_certs_2/Intel_pc.pem differ