Merge pull request #701 from nsacyber/v3_issue_693-unittest

Migrated 1 unit test to HIRS_AttestationCA
This commit is contained in:
D2B8CA1B27286366A8607B6858C0565962613D18D0546480078B520CD7AD705A 2024-02-09 11:20:32 -05:00 committed by GitHub
commit bb81f1050c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 721 additions and 0 deletions

View File

@ -52,6 +52,7 @@ dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter:5.9.3'
testImplementation 'org.junit.platform:junit-platform-launcher:1.9.3'
testImplementation 'org.mockito:mockito-core:4.2.0'
testImplementation 'org.springframework:spring-test:6.0.8'
// spring management
compileOnly libs.lombok

View File

@ -15,5 +15,9 @@
<Match>
<Bug pattern="EI_EXPOSE_REP2" />
</Match>
<Match>
<Class name="hirs.attestationca.persist.AttestationCertificateAuthorityTest"/>
<Bug pattern="NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE"/>
</Match>
</FindBugsFilter>

View File

@ -0,0 +1,716 @@
package hirs.attestationca.persist;
import com.google.protobuf.ByteString;
import hirs.attestationca.persist.entity.userdefined.certificate.EndorsementCredential;
import hirs.attestationca.persist.entity.userdefined.certificate.PlatformCredential;
import hirs.attestationca.persist.provision.AbstractProcessor;
import hirs.attestationca.persist.provision.helper.IssuedCertificateAttributeHelper;
import hirs.attestationca.persist.provision.helper.ProvisionUtils;
import hirs.structs.elements.aca.SymmetricAttestation;
import hirs.structs.elements.tpm.AsymmetricPublicKey;
import hirs.structs.elements.tpm.EncryptionScheme;
import hirs.structs.elements.tpm.IdentityProof;
import hirs.structs.elements.tpm.StorePubKey;
import hirs.structs.elements.tpm.SymmetricKey;
import hirs.utils.HexUtils;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.ArrayUtils;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.GeneralNames;
import org.bouncycastle.asn1.x509.TBSCertificate;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.jupiter.api.*;
import org.springframework.test.util.ReflectionTestUtils;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.OAEPParameterSpec;
import javax.crypto.spec.PSource;
import javax.crypto.spec.SecretKeySpec;
import javax.security.auth.x500.X500Principal;
import java.io.IOException;
import java.math.BigInteger;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.*;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.MGF1ParameterSpec;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
/**
* Test suite for {@link AttestationCertificateAuthority}.
*/
@TestInstance(TestInstance.Lifecycle.PER_CLASS) // needed to use non-static BeforeAll
public class AttestationCertificateAuthorityTest {
/**
* This internal class handles setup for testing the function
* generateCredential() from class AbstractProcessor. Because the
* function is Protected and in a different package than the test,
* it cannot be accessed directly.
*/
@Nested
public class AccessAbstractProcessor extends AbstractProcessor {
public AccessAbstractProcessor(final PrivateKey privateKey,
final int validDays) {
super(privateKey, validDays);
}
public X509Certificate accessGenerateCredential(final PublicKey publicKey,
final EndorsementCredential endorsementCredential,
final List<PlatformCredential> platformCredentials,
final String deviceName,
final X509Certificate acaCertificate) {
return generateCredential(publicKey,
endorsementCredential,
platformCredentials,
deviceName,
acaCertificate);
}
}
// object in test
private AttestationCertificateAuthority aca;
private AccessAbstractProcessor abstractProcessor;
// test key pair
private KeyPair keyPair;
private static final String EK_PUBLIC_PATH = "/tpm2/ek.pub";
private static final String AK_PUBLIC_PATH = "/tpm2/ak.pub";
private static final String AK_NAME_PATH = "/tpm2/ak.name";
private static final String TEST_NONCE_BLOB_PATH = "test/nonce.blob";
private static final String EK_MODULUS_HEX = "a3 b5 c2 1c 57 be 40 c4 3c 78 90 0d 00 81 01 78"
+ "13 ca 02 ec b6 75 89 60 ca 60 9b 10 b6 b4 d0 0b"
+ "4d e4 68 ad 01 a6 91 e2 56 20 5e cf 16 fe 77 ae"
+ "1f 13 d7 ac a1 91 0b 68 f6 07 cf c2 4b 5e c1 2c"
+ "4c fe 3a c9 62 7e 10 02 5b 33 c8 c2 1a cd 2e 7f"
+ "dd 7c 43 ac a9 5f b1 d6 07 56 4f 72 9b 0a 00 6c"
+ "f6 8d 23 a1 84 ca c1 7f 5a 8b ef 0e 23 11 90 00"
+ "30 f2 99 e9 94 59 c6 b0 fe b2 5c 0c c7 b4 76 69"
+ "6c f1 b7 d8 e5 60 d6 61 9f ab 7c 17 ce a4 74 6d"
+ "8c cd e6 9e 6e bb 64 52 a7 c3 bf ac 07 e8 5e 3e"
+ "ae eb dc c5 95 37 26 6a 5d a6 a2 12 52 fa 03 43"
+ "b2 62 2d 87 8c a7 06 8f d6 3f 63 b6 2d 73 c4 9d"
+ "9d d6 55 0e bb db b1 eb dd c5 4b 8f c3 17 cb 3b"
+ "c3 bf f6 7f 13 44 de 8e d7 b9 f1 a7 15 56 8f 6c"
+ "cd f2 4c 86 99 39 19 88 d3 4a 2f 38 c4 c4 37 39"
+ "85 6f 41 98 19 14 a4 1f 95 bc 04 ef 74 c2 0d f3";
private static final String AK_MODULUS_HEX = "d7 c9 f0 e3 ac 1b 4a 1e 3c 9d 2d 57 02 e9 2a 93"
+ "b0 c0 e1 50 af e4 61 11 31 73 a1 96 b8 d6 d2 1c"
+ "40 40 c8 a6 46 a4 10 4b d1 06 74 32 f6 e3 8a 55"
+ "1e 03 c0 3e cc 75 04 c6 44 88 b6 ad 18 c9 45 65"
+ "0d be c5 45 22 bd 24 ad 32 8c be 83 a8 9b 1b d9"
+ "e0 c8 d9 ec 14 67 55 1b fe 68 dd c7 f7 33 e4 cd"
+ "87 bd ba 9a 07 e7 74 eb 57 ef 80 9c 6d ee f9 35"
+ "52 67 36 e2 53 98 46 a5 4e 8f 17 41 8d ff eb bb"
+ "9c d2 b4 df 57 f8 7f 31 ef 2e 2d 6e 06 7f 05 ed"
+ "3f e9 6f aa b4 b7 5a f9 6d ba ff 2b 5e f7 c1 05"
+ "90 68 1f b6 4b 38 67 f7 92 d8 73 51 6e 08 19 ad"
+ "ca 35 48 a7 c1 fb cb 01 9a 28 03 c9 fe bb 49 2f"
+ "88 3f a1 e7 a8 69 f0 f8 e8 78 db d3 6d c5 80 8d"
+ "c2 e4 8a af 4b c2 ac 48 2a 44 63 6e 39 b0 8f dd"
+ "e4 b3 a3 f9 2a b1 c8 d9 3d 6b c4 08 b0 16 c4 e7"
+ "c7 2f f5 94 c6 43 3e ee 9b 8a da e7 31 d1 54 dd";
private static final String AK_NAME_HEX = "00 0b 6e 8f 79 1c 7e 16 96 1b 11 71 65 9c e0 cd"
+ "ae 0d 4d aa c5 41 be 58 89 74 67 55 96 c2 5e 38"
+ "e2 94";
/**
* Registers bouncy castle as a security provider. Normally the JEE container will handle this,
* but since the tests are not instantiating a container, have the unit test runner set up the
* provider.
*/
@BeforeAll
public void setupTests() throws Exception {
//BeforeSuite
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
keyPair = keyPairGenerator.generateKeyPair();
//BeforeTest
aca = new AttestationCertificateAuthority(null, keyPair.getPrivate(),
null, null, null, null, null, null, 1,
null, null, null, null) {
};
abstractProcessor = new AccessAbstractProcessor(keyPair.getPrivate(),1);
Security.addProvider(new BouncyCastleProvider());
}
/**
* Tests {@link AttestationCertificateAuthority#processIdentityClaimTpm2(byte[])}
* where the byte array is null. Expects an illegal argument exception to be thrown.
*/
@Test
public void testProcessIdentityClaimTpm2NullRequest() {
assertThrows(IllegalArgumentException.class, () ->
aca.processIdentityClaimTpm2(null));
}
/**
* Tests {@link AttestationCertificateAuthority#getPublicKey()}.
*/
@Test
public void testGetPublicKey() {
// encoded byte array to be returned by public key
byte[] encoded = new byte[]{0, 1, 0, 1, 0};
// create mocks for testing
X509Certificate acaCertificate = mock(X509Certificate.class);
PublicKey publicKey = mock(PublicKey.class);
// assign the aca certificate to the aca
ReflectionTestUtils.setField(aca, "acaCertificate", acaCertificate);
// return a mocked public key
when(acaCertificate.getPublicKey()).thenReturn(publicKey);
// return test byte array
when(publicKey.getEncoded()).thenReturn(encoded);
// assert what the ACA returns is as expected
assertArrayEquals(encoded, aca.getPublicKey());
// verify mock interactions
verify(acaCertificate).getPublicKey();
verify(publicKey).getEncoded();
// verify no other interactions with mocks
verifyNoMoreInteractions(acaCertificate, publicKey);
}
/**
* Tests {@link ProvisionUtils#decryptAsymmetricBlob(byte[],
* EncryptionScheme, PrivateKey)}.
*
* @throws Exception during aca processing
*/
@Test
public void testDecryptAsymmetricBlob() throws Exception {
// test encryption transformation
EncryptionScheme encryptionScheme = EncryptionScheme.PKCS1;
// test variables
byte[] expected = "test".getBytes(StandardCharsets.UTF_8);
// encrypt the expected value using same algorithm as the ACA.
byte[] encrypted = encryptBlob(expected, encryptionScheme.toString());
// perform the decryption and assert that the decrypted bytes equal the expected bytes
assertArrayEquals(expected, ProvisionUtils.decryptAsymmetricBlob(encrypted, encryptionScheme, keyPair.getPrivate()));
}
/**
* Tests {@link ProvisionUtils#decryptSymmetricBlob(
* byte[], byte[], byte[], String)}.
*
* @throws Exception during aca processing
*/
@Test
public void testDecryptSymmetricBlob() throws Exception {
// test encryption transformation
String transformation = "AES/CBC/PKCS5Padding";
// test variables
byte[] expected = "test".getBytes(StandardCharsets.UTF_8);
// create a key generator to generate a "shared" secret
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128);
// use some random bytes as the IV to encrypt and subsequently decrypt with
byte[] randomBytes = new byte[16];
// generate the random bytes
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
random.nextBytes(randomBytes);
// the shared secret
byte[] secretKey = keyGenerator.generateKey().getEncoded();
// encrypt the expected value with the private key being the shared secret
byte[] encrypted = encryptBlob(expected, secretKey, randomBytes, transformation);
// perform the decryption using the generated shared secret, random bytes as an IV, and the
// AES CBC transformation for the cipher. then assert the decrypted results are the same
// as our expected value.
assertArrayEquals(expected,
ProvisionUtils.decryptSymmetricBlob(encrypted, secretKey, randomBytes, transformation));
}
/**
* Tests {@link ProvisionUtils#generateSymmetricKey()}.
*/
@Test
public void testGenerateSymmetricKey() {
// perform the test
SymmetricKey symmetricKey = ProvisionUtils.generateSymmetricKey();
// assert the symmetric algorithm, scheme, and key size are all set appropriately
assertTrue(symmetricKey.getAlgorithmId() == 6);
assertTrue(symmetricKey.getEncryptionScheme() == 255);
assertTrue(symmetricKey.getKeySize() == symmetricKey.getKey().length);
}
/**
* Tests {@link ProvisionUtils#generateAsymmetricContents(
* byte[], byte[], PublicKey)}.
*
* @throws Exception during aca processing
*/
@Test
public void testGenerateAsymmetricContents() throws Exception {
// "encoded" identity proof (returned by struct converter)
byte[] identityProofEncoded = new byte[]{0, 0, 1, 1};
// generate a random session key to be used for encryption and decryption
byte[] sessionKey = new byte[16];
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
random.nextBytes(sessionKey);
// perform the test
byte[] result = ProvisionUtils.generateAsymmetricContents(identityProofEncoded,
sessionKey, keyPair.getPublic());
// decrypt the result
byte[] decryptedResult = decryptBlob(result);
// create a SHA1 digest of the identity key
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update(identityProofEncoded);
// generate the digest
byte[] identityDigest = md.digest();
// the decrypted asymmetric contents should be the session key and a SHA-1 hash of the
// encoded identity proof.
byte[] expected = ArrayUtils.addAll(sessionKey, identityDigest);
// compare the two byte arrays
assertArrayEquals(expected, decryptedResult);
}
/**
* Tests {@link ProvisionUtils#generateAttestation(X509Certificate,
* SymmetricKey)}.
*
* @throws Exception during aca processing
*/
@Test
public void testGenerateAttestation() throws Exception {
// create some mocks for the unit tests
X509Certificate certificate = mock(X509Certificate.class);
SymmetricKey symmetricKey = mock(SymmetricKey.class);
// create a key generator to generate a secret key
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128);
// obtain the key from the generator
byte[] secretKey = keyGenerator.generateKey().getEncoded();
// use our public key for encryption
when(symmetricKey.getKey()).thenReturn(secretKey);
// just use the existing public key for the credential
when(certificate.getEncoded()).thenReturn(keyPair.getPublic().getEncoded());
// perform the actual test
SymmetricAttestation attestation = ProvisionUtils.generateAttestation(certificate, symmetricKey);
// validate that the attestation is not null
assertNotNull(attestation);
// validate the attestation algorithm
assertNotNull(attestation.getAlgorithm());
assertTrue(attestation.getAlgorithm().getAlgorithmId() == 6);
assertTrue(attestation.getAlgorithm().getEncryptionScheme() == 0x1);
assertTrue(attestation.getAlgorithm().getSignatureScheme() == 0);
assertTrue(attestation.getAlgorithm().getParamsSize() == 0);
// validate the attestation credential
assertNotNull(attestation.getCredential());
// validate that the credential size is the size of the actual credential block
assertTrue(attestation.getCredential().length == attestation.getCredentialSize());
// create containers for the 2 parts of the credential
byte[] iv = new byte[16];
byte[] credential = new byte[attestation.getCredential().length - iv.length];
// siphon off the first 16 bytes for the IV
System.arraycopy(attestation.getCredential(), 0, iv, 0, iv.length);
// the rest is the actual encrypted credential
System.arraycopy(attestation.getCredential(), iv.length, credential, 0, credential.length);
// decrypt the credential
byte[] decrypted = decryptBlob(credential, secretKey, iv, "AES/CBC/PKCS5Padding");
// assert that the decrypted credential is our public key
assertArrayEquals(keyPair.getPublic().getEncoded(), decrypted);
// verify that the mocks were interacted with appropriately
verify(symmetricKey).getKey();
verify(certificate).getEncoded();
verifyNoMoreInteractions(certificate, symmetricKey);
}
/**
* Tests {@link AttestationCertificateAuthority#
* AttestationCertificateAuthority(SupplyChainValidationService, PrivateKey,
* X509Certificate, StructConverter, CertificateManager, DeviceRegister, int,
* DeviceManager, DBManager)}.
*
* @throws Exception during subject alternative name checking if cert formatting is bad
*/
@Test
public void testGenerateCredential() throws Exception {
// test variables
final String identityProofLabelString = "label";
byte[] identityProofLabel = identityProofLabelString.getBytes(StandardCharsets.UTF_8);
byte[] modulus = ((RSAPublicKey) keyPair.getPublic()).getModulus().toByteArray();
X500Principal principal = new X500Principal("CN=TEST, OU=TEST, O=TEST, C=TEST");
int validDays = 1;
// create mocks for testing
IdentityProof identityProof = mock(IdentityProof.class);
AsymmetricPublicKey asymmetricPublicKey = mock(AsymmetricPublicKey.class);
StorePubKey storePubKey = mock(StorePubKey.class);
X509Certificate acaCertificate = mock(X509Certificate.class);
// assign ACA fields
ReflectionTestUtils.setField(aca, "validDays", validDays);
ReflectionTestUtils.setField(aca, "acaCertificate", acaCertificate);
// prepare identity proof interactions
when(identityProof.getLabel()).thenReturn(identityProofLabel);
// prepare other mocks
when(acaCertificate.getSubjectX500Principal()).thenReturn(principal);
when(acaCertificate.getIssuerX500Principal()).thenReturn(principal);
// perform the test
X509Certificate certificate = abstractProcessor.accessGenerateCredential(keyPair.getPublic(),
null,
new LinkedList<PlatformCredential>(),
"exampleIdLabel",
acaCertificate);
// grab the modulus from the generate certificate
byte[] resultMod = ((RSAPublicKey) certificate.getPublicKey()).getModulus().toByteArray();
// today and tomorrow, when the certificate should be valid for
Calendar today = Calendar.getInstance();
Calendar tomorrow = Calendar.getInstance();
tomorrow.add(Calendar.DATE, 1);
// validate the certificate
assertTrue(certificate.getIssuerX500Principal().toString().contains("CN=TEST"));
assertTrue(certificate.getIssuerX500Principal().toString().contains("OU=TEST"));
assertTrue(certificate.getIssuerX500Principal().toString().contains("O=TEST"));
assertTrue(certificate.getIssuerX500Principal().toString().contains("C=TEST"));
// validate the format of the subject and subject alternative name
assertEquals("", certificate.getSubjectX500Principal().getName());
assertEquals("exampleIdLabel",
((X500Name) GeneralNames.fromExtensions(((TBSCertificate.getInstance(
certificate.getTBSCertificate()).getExtensions())), Extension.
subjectAlternativeName).getNames()[0].getName()).getRDNs(
IssuedCertificateAttributeHelper.TCPA_AT_TPM_ID_LABEL)[0].getFirst()
.getValue().toString());
assertArrayEquals(modulus, resultMod);
// obtain the expiration dates from the certificate
Calendar beforeDate = Calendar.getInstance();
Calendar afterDate = Calendar.getInstance();
beforeDate.setTime(certificate.getNotBefore());
afterDate.setTime(certificate.getNotAfter());
// assert the dates are set correctly
assertEquals(today.get(Calendar.DATE), beforeDate.get(Calendar.DATE));
assertEquals(tomorrow.get(Calendar.DATE), afterDate.get(Calendar.DATE));
// validate mock interactions
verify(acaCertificate).getSubjectX500Principal();
verifyNoMoreInteractions(identityProof, asymmetricPublicKey, storePubKey, acaCertificate);
}
/**
* Tests {@link ProvisionUtils#assemblePublicKey(byte[])}.
*/
@Test
public void testAssemblePublicKeyUsingByteArray() {
// obtain the expected modulus from the existing public key
final BigInteger modulus = ((RSAPublicKey) keyPair.getPublic()).getModulus();
// perform test
RSAPublicKey publicKey = (RSAPublicKey) ProvisionUtils.assemblePublicKey(modulus.toByteArray());
// assert that the exponent and the modulus are the same. the exponents should be the well
// known prime, 101
assertTrue(publicKey.getPublicExponent().equals(new BigInteger("010001", 16)));
assertTrue(publicKey.getModulus().equals(modulus));
}
/**
* Tests {@link ProvisionUtils#assemblePublicKey(String)}.
*/
@Test
public void testAssemblePublicKeyUsingHexEncodedString() {
// obtain the expected modulus from the existing public key
final BigInteger modulus = ((RSAPublicKey) keyPair.getPublic()).getModulus();
// encode our existing public key into hex
final String modulusString = Hex.encodeHexString(
((RSAPublicKey) keyPair.getPublic()).getModulus().toByteArray());
// perform test
RSAPublicKey publicKey = (RSAPublicKey) ProvisionUtils.assemblePublicKey(modulusString);
// assert that the exponent and the modulus are the same. the exponents should be the well
// known prime, 101.
assertTrue(publicKey.getPublicExponent().equals(new BigInteger("010001", 16)));
assertTrue(publicKey.getModulus().equals(modulus));
}
/**
* Tests parsing the EK from the TPM2 output file.
* @throws URISyntaxException incorrect resource path
* @throws IOException unable to read from file
*/
@Test
public void testParseEk() throws URISyntaxException, IOException {
Path ekPath = Paths.get(getClass().getResource(
EK_PUBLIC_PATH).toURI());
byte[] ekFile = Files.readAllBytes(ekPath);
RSAPublicKey ek = ProvisionUtils.parsePublicKey(ekFile);
assertTrue(ek.getPublicExponent().equals(new BigInteger("010001", 16)));
byte[] mod = ek.getModulus().toByteArray();
// big integer conversion is signed so it can add a 0 byte
if (mod[0] == 0) {
byte[] tmp = new byte[mod.length - 1];
System.arraycopy(mod, 1, tmp, 0, mod.length - 1);
mod = tmp;
}
String hex = HexUtils.byteArrayToHexString(mod);
String realMod = EK_MODULUS_HEX.replaceAll("\\s+", "");
assertEquals(realMod, hex);
}
/**
* Tests parsing the AK public key from the TPM2 output file.
* @throws URISyntaxException incorrect resource path
* @throws IOException unable to read from file
*/
@Test
public void testParseAk() throws URISyntaxException, IOException {
Path akPath = Paths.get(getClass().getResource(
AK_PUBLIC_PATH).toURI());
byte[] akFile = Files.readAllBytes(akPath);
RSAPublicKey ak = ProvisionUtils.parsePublicKey(akFile);
assertTrue(ak.getPublicExponent().equals(new BigInteger("010001", 16)));
byte[] mod = ak.getModulus().toByteArray();
// big integer conversion is signed so it can add a 0 byte
if (mod[0] == 0) {
byte[] tmp = new byte[mod.length - 1];
System.arraycopy(mod, 1, tmp, 0, mod.length - 1);
mod = tmp;
}
String hex = HexUtils.byteArrayToHexString(mod);
String realMod = AK_MODULUS_HEX.replaceAll("\\s+", "");
assertEquals(realMod, hex);
}
/**
* Tests parsing the AK name from the TPM2 output file.
* @throws URISyntaxException incorrect resource path
* @throws IOException unable to read from file
* @throws NoSuchAlgorithmException inavlid algorithm
*/
@Test
public void testGenerateAkName() throws URISyntaxException, IOException,
NoSuchAlgorithmException {
Path akNamePath = Paths.get(getClass().getResource(
AK_NAME_PATH).toURI());
byte[] akNameFileBytes = Files.readAllBytes(akNamePath);
String realHex = HexUtils.byteArrayToHexString(akNameFileBytes);
String realMod = AK_MODULUS_HEX.replaceAll("\\s+", "");
byte[] akName = ProvisionUtils.generateAkName(HexUtils.hexStringToByteArray(realMod));
String hex = HexUtils.byteArrayToHexString(akName);
String realName = AK_NAME_HEX.replaceAll("\\s+", "");
assertEquals(hex, realName);
assertEquals(hex, realHex);
}
/**
* Method to generate a make credential output file for use in manual testing. Feed to
* a TPM 2.0 or emulator using the activate credential command to ensure proper parsing.
* Must be performed manually. To use, copy the TPM's ek and ak into
* HIRS_AttestationCA/src/test/resources/tpm2/test/ and ensure the variables akPubPath
* and ekPubPath are correct. Your output file will be
* HIRS_AttestationCA/src/test/resources/tpm2/test/make.blob and the nonce used will be
* output as HIRS_AttestationCA/src/test/resources/tpm2/test/secret.blob
* @throws URISyntaxException invalid file path
* @throws IOException unable to read file
*/
@Disabled
@Test
public void testMakeCredential() throws URISyntaxException, IOException {
Path akPubPath = Paths.get(getClass().getResource(
AK_PUBLIC_PATH).toURI());
Path ekPubPath = Paths.get(getClass().getResource(
EK_PUBLIC_PATH).toURI());
byte[] ekPubFile = Files.readAllBytes(ekPubPath);
byte[] akPubFile = Files.readAllBytes(akPubPath);
RSAPublicKey ekPub = ProvisionUtils.parsePublicKey(ekPubFile);
RSAPublicKey akPub = ProvisionUtils.parsePublicKey(akPubFile);
// prepare the nonce and wrap it with keys
byte[] nonce = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
ByteString blob = ProvisionUtils.tpm20MakeCredential(ekPub, akPub, nonce);
Path resources = Objects.requireNonNull(Paths.get(Objects.requireNonNull(this.getClass().getResource(
"/").toURI()))
.getParent().getParent().getParent().getParent());
Path makeBlob = resources.resolve("src/test/resources/tpm2/test/make.blob");
Files.write(makeBlob, blob.toByteArray());
Path secretPath = resources.resolve("src/test/resources/tpm2/test/secret.blob");
Files.write(secretPath, nonce);
}
/**
* Test helper method that encrypts a blob using the specified transformation and the test key
* pair public key.
*
* @param blob to be encrypted
* @param transformation used by a cipher to encrypt
* @return encrypted blob
* @throws Exception during the encryption process
*/
private byte[] encryptBlob(byte[] blob, String transformation) throws Exception {
// initialize a cipher using the specified transformation
Cipher cipher = Cipher.getInstance(transformation);
// use our generated public key to encrypt
cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
// return the cipher text
return cipher.doFinal(blob);
}
/**
* Test helper method that encrypts a blob using a shared key and IV using the specified
* transformation.
*
* @param blob to be encrypted
* @param key shared key
* @param iv to encrypt with
* @param transformation of the encryption cipher
* @return encrypted blob
* @throws Exception
*/
private byte[] encryptBlob(byte[] blob, byte[] key, byte[] iv, String transformation)
throws Exception {
// initialize a cipher using the specified transformation
Cipher cipher = Cipher.getInstance(transformation);
// generate a secret key specification using the key and AES.
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
// create IV parameter for key specification
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
// encrypt using the key specification with the generated IV
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivParameterSpec);
// return the cipher text
return cipher.doFinal(blob);
}
/**
* Test helper method to decrypt blobs.
*
* @param blob to be decrypted
* @return decrypted blob
* @throws Exception
*/
private byte[] decryptBlob(byte[] blob) throws Exception {
// initialize a cipher using the specified transformation
Cipher cipher = Cipher.getInstance(EncryptionScheme.OAEP.toString());
OAEPParameterSpec spec = new OAEPParameterSpec("Sha1", "MGF1",
MGF1ParameterSpec.SHA1, new PSource.PSpecified("TCPA".getBytes(StandardCharsets.UTF_8)));
// use our generated public key to encrypt
cipher.init(Cipher.PRIVATE_KEY, keyPair.getPrivate(), spec);
// return the cipher text
return cipher.doFinal(blob);
}
/**
* Test helper method that decrypts a blob using a shared key and IV using the specified.
* transformation.
*
* @param blob to be decrypted
* @param key shared key
* @param iv to decrypt with
* @param transformation of the decryption cipher
* @return decrypted blob
* @throws Exception
*/
private byte[] decryptBlob(byte[] blob, byte[] key, byte[] iv, String transformation)
throws Exception {
// initialize a cipher using the specified transformation
Cipher cipher = Cipher.getInstance(transformation);
// generate a secret key specification using the key and AES.
SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
// create IV parameter for key specification
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
// encrypt using the key specification with the generated IV
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivParameterSpec);
// return the cipher text
return cipher.doFinal(blob);
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.