Skip to content

Commit

Permalink
[#25] Make ACA exception handling more descriptive
Browse files Browse the repository at this point in the history
  • Loading branch information
apldev3 committed Oct 29, 2018
1 parent f192ce5 commit 5ddb978
Show file tree
Hide file tree
Showing 14 changed files with 306 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import com.google.protobuf.ByteString;

import com.google.protobuf.InvalidProtocolBufferException;
import hirs.attestationca.exceptions.CertificateProcessingException;
import hirs.attestationca.exceptions.IdentityProcessingException;
import hirs.attestationca.exceptions.UnexpectedServerException;
import hirs.data.persist.AppraisalStatus;
import hirs.data.persist.BIOSComponentInfo;
import hirs.data.persist.BaseboardComponentInfo;
Expand Down Expand Up @@ -238,7 +241,8 @@ public byte[] processIdentityRequest(final byte[] identityRequest) {
if (publicKeyModulus != null) {
ekPublicKey = assemblePublicKey(publicKeyModulus.toByteArray());
} else {
throw new IllegalArgumentException("TPM 1.2 Provisioning requires RSA EKC");
throw new IdentityProcessingException("TPM 1.2 Provisioning requires EK "
+ "Credentials to be created with RSA");
}
} catch (IOException e) {
LOG.error("Could not retrieve the public key modulus from the EK cert");
Expand Down Expand Up @@ -277,7 +281,7 @@ public byte[] processIdentityRequest(final byte[] identityRequest) {

if (deviceInfoReport == null) {
LOG.error("Failed to deserialize Device Info Report");
throw new IllegalArgumentException("Device Info Report failed to deserialize "
throw new IdentityProcessingException("Device Info Report failed to deserialize "
+ "from Identity Request");
}

Expand Down Expand Up @@ -382,17 +386,21 @@ public byte[] processIdentityClaimTpm2(final byte[] identityClaim) {
LOG.info("Got identity claim");

if (ArrayUtils.isEmpty(identityClaim)) {
throw new IllegalArgumentException("identityClaim cannot be null or empty");
LOG.error("Identity claim empty throwing exception.");
throw new CertificateProcessingException("identityClaim cannot be null or empty");
}

// attempt to deserialize Protobuf IdentityClaim
ProvisionerTpm2.IdentityClaim claim = parseIdentityClaim(identityClaim);

AppraisalStatus.Status validationResult = doSupplyChainValidation(claim);
// parse the EK Public key from the IdentityClaim once for use in supply chain validation
// and later tpm20MakeCredential function
RSAPublicKey ekPub = parsePublicKey(claim.getEkPublicArea().toByteArray());

AppraisalStatus.Status validationResult = doSupplyChainValidation(claim, ekPub);

if (validationResult == AppraisalStatus.Status.PASS) {

RSAPublicKey ekPub = parsePublicKey(claim.getEkPublicArea().toByteArray());
RSAPublicKey akPub = parsePublicKey(claim.getAkPublicArea().toByteArray());
byte[] nonce = generateRandomBytes(NONCE_LENGTH);
ByteString blobStr = tpm20MakeCredential(ekPub, akPub, nonce);
Expand Down Expand Up @@ -420,12 +428,13 @@ public byte[] processIdentityClaimTpm2(final byte[] identityClaim) {
* Performs supply chain validation.
*
* @param claim the identity claim
* @param ekPub the public endorsement key
* @return the {@link AppraisalStatus} of the supply chain validation
*/
private AppraisalStatus.Status doSupplyChainValidation(
final ProvisionerTpm2.IdentityClaim claim) {
final ProvisionerTpm2.IdentityClaim claim, PublicKey ekPub) {
// attempt to find an endorsement credential to validate
EndorsementCredential endorsementCredential = parseEcFromIdentityClaim(claim);
EndorsementCredential endorsementCredential = parseEcFromIdentityClaim(claim, ekPub);

// attempt to find platform credentials to validate
Set<PlatformCredential> platformCredentials = parsePcsFromIdentityClaim(claim,
Expand Down Expand Up @@ -466,7 +475,7 @@ public byte[] processCertificateRequest(final byte[] certificateRequest) {
try {
request = ProvisionerTpm2.CertificateRequest.parseFrom(certificateRequest);
} catch (InvalidProtocolBufferException ipbe) {
throw new IdentityProcessingException(
throw new CertificateProcessingException(
"Could not deserialize certificate request", ipbe);
}

Expand All @@ -477,13 +486,16 @@ public byte[] processCertificateRequest(final byte[] certificateRequest) {
byte[] identityClaim = tpm2ProvisionerState.getIdentityClaim();
ProvisionerTpm2.IdentityClaim claim = parseIdentityClaim(identityClaim);

// Get endorsement public key
RSAPublicKey ekPub = parsePublicKey(claim.getEkPublicArea().toByteArray());

// Get attestation public key
RSAPublicKey akPub = parsePublicKey(claim.getAkPublicArea().toByteArray());

// Get Endorsement Credential if it exists
EndorsementCredential endorsementCredential = parseEcFromIdentityClaim(claim);
// Get Endorsement Credential if it exists or was uploaded
EndorsementCredential endorsementCredential = parseEcFromIdentityClaim(claim, ekPub);

// Get Platform Credentials if they exist
// Get Platform Credentials if they exist or were uploaded
Set<PlatformCredential> platformCredentials = parsePcsFromIdentityClaim(claim,
endorsementCredential);

Expand Down Expand Up @@ -512,7 +524,7 @@ public byte[] processCertificateRequest(final byte[] certificateRequest) {
} else {
LOG.error("Could not process credential request. Invalid nonce provided: "
+ request.getNonce().toString());
throw new IdentityProcessingException("Invalid nonce given in request");
throw new CertificateProcessingException("Invalid nonce given in request");
}
}

Expand All @@ -524,7 +536,7 @@ public byte[] processCertificateRequest(final byte[] certificateRequest) {
RSAPublicKey parsePublicKey(final byte[] publicArea) {
int pubLen = publicArea.length;
if (pubLen < RSA_MODULUS_LENGTH) {
throw new IdentityProcessingException(
throw new IllegalArgumentException(
"EK or AK public data segment is not long enough");
}
// public data ends with 256 byte modulus
Expand Down Expand Up @@ -661,7 +673,7 @@ private Device processDeviceInfo(final ProvisionerTpm2.IdentityClaim claim) {

if (deviceInfoReport == null) {
LOG.error("Failed to deserialize Device Info Report");
throw new IllegalArgumentException("Device Info Report failed to deserialize "
throw new IdentityProcessingException("Device Info Report failed to deserialize "
+ "from Identity Claim");
}

Expand Down Expand Up @@ -882,7 +894,7 @@ private PublicKey assemblePublicKey(final BigInteger modulus) {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(keySpec);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
throw new IdentityProcessingException(
throw new UnexpectedServerException(
"Encountered unexpected error creating public key: " + e.getMessage(), e);
}
}
Expand Down Expand Up @@ -948,7 +960,7 @@ byte[] generateAsymmetricContents(final IdentityProof proof, final SymmetricKey
} catch (NoSuchAlgorithmException | IllegalBlockSizeException | NoSuchPaddingException
| InvalidKeyException | BadPaddingException
| InvalidAlgorithmParameterException e) {
throw new IdentityProcessingException(
throw new CertificateProcessingException(
"Encountered error while generating ACA session key: " + e.getMessage(), e);
}
}
Expand Down Expand Up @@ -1004,7 +1016,7 @@ SymmetricAttestation generateAttestation(final X509Certificate credential,
} catch (BadPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException
| InvalidKeyException | InvalidAlgorithmParameterException | NoSuchPaddingException
| CertificateEncodingException e) {
throw new IdentityProcessingException(
throw new CertificateProcessingException(
"Encountered error while generating Identity Response: " + e.getMessage(), e);
}
}
Expand Down Expand Up @@ -1066,7 +1078,7 @@ X509Certificate generateCredential(final PublicKey publicKey,
.setProvider("BC").getCertificate(holder);
return certificate;
} catch (IOException | OperatorCreationException | CertificateException e) {
throw new IdentityProcessingException("Encountered error while generating "
throw new CertificateProcessingException("Encountered error while generating "
+ "identity credential: " + e.getMessage(), e);
}
}
Expand Down Expand Up @@ -1159,7 +1171,8 @@ protected ByteString tpm20MakeCredential(final RSAPublicKey ek, final RSAPublicK
| InvalidKeyException | InvalidAlgorithmParameterException
| NoSuchPaddingException e) {
throw new IdentityProcessingException(
"Encountered error while making credential: " + e.getMessage(), e);
"Encountered error while making the identity claim challenge: "
+ e.getMessage(), e);
}
}

Expand Down Expand Up @@ -1366,21 +1379,29 @@ private ProvisionerTpm2.IdentityClaim parseIdentityClaim(final byte[] identityCl

/**
* Helper method to parse an Endorsement Credential from a Protobuf generated
* IdentityClaim. Persists the Endorsement Credential if it does not already exist.
* IdentityClaim. Will also check if the Endorsement Credential was already uploaded.
* Persists the Endorsement Credential if it does not already exist.
*
* @param identityClaim a Protobuf generated Identity Claim object
* @param ekPub the endorsement public key from the Identity Claim object
* @return the Endorsement Credential, if one exists, null otherwise
*/
private EndorsementCredential parseEcFromIdentityClaim(
final ProvisionerTpm2.IdentityClaim identityClaim) {
final ProvisionerTpm2.IdentityClaim identityClaim,
final PublicKey ekPub) {
EndorsementCredential endorsementCredential = null;
if (identityClaim.hasEndorsementCredential()) {
return CredentialManagementHelper.storeEndorsementCredential(
endorsementCredential = CredentialManagementHelper.storeEndorsementCredential(
this.certificateManager,
identityClaim.getEndorsementCredential().toByteArray());
} else if (ekPub != null) {
LOG.warn("Endorement Cred was not in the identity claim from the client."
+ " Checking for uploads.");
endorsementCredential = getEndorsementCredential(ekPub);
} else {
LOG.warn("No endorsement credential received in identity claim.");
}
return null;
return endorsementCredential;
}

/**
Expand Down Expand Up @@ -1418,15 +1439,15 @@ private Set<PlatformCredential> parsePcsFromIdentityClaim(
* Helper method to extract a DER encoded ASN.1 certificate from an X509 certificate.
*
* @param certificate the X509 certificate to be converted to DER encoding
* @throws {@link IdentityProcessingException} if error occurs during encoding retrieval
* @throws {@link UnexpectedServerException} if error occurs during encoding retrieval
* @return the byte array representing the DER encoded certificate
*/
private byte[] getDerEncodedCertificate(final X509Certificate certificate) {
try {
return certificate.getEncoded();
} catch (CertificateEncodingException e) {
LOG.error("Error converting certificate to ASN.1 DER Encoding.", e);
throw new IdentityProcessingException(
throw new UnexpectedServerException(
"Encountered error while converting X509 Certificate: "
+ e.getMessage(), e);
}
Expand All @@ -1441,7 +1462,7 @@ private byte[] getDerEncodedCertificate(final X509Certificate certificate) {
* @param endorsementCredential the endorsement credential used to generate the AC
* @param platformCredentials the platform credentials used to generate the AC
* @param device the device to which the attestation certificate is tied
* @throws {@link IdentityProcessingException} if error occurs in persisting the Attestation
* @throws {@link CertificateProcessingException} if error occurs in persisting the Attestation
* Certificate
*/
private void saveAttestationCertificate(final byte[] derEncodedAttestationCertificate,
Expand All @@ -1456,7 +1477,7 @@ private void saveAttestationCertificate(final byte[] derEncodedAttestationCertif
certificateManager.save(attCert);
} catch (Exception e) {
LOG.error("Error saving generated Attestation Certificate to database.", e);
throw new IdentityProcessingException(
throw new CertificateProcessingException(
"Encountered error while storing Attestation Certificate: "
+ e.getMessage(), e);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package hirs.attestationca;

public class AcaRestError {

private String error;

// Don't remove this constructor as it's required for JSON mapping
public AcaRestError() { }

public AcaRestError(String error) {
this.error = error;
}

public String getError() {
return error;
}

public void setError(final String error) {
this.error = error;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
import org.springframework.context.annotation.Scope;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.Environment;
import org.springframework.http.MediaType;
import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
Expand Down Expand Up @@ -54,8 +56,8 @@
@PropertySource(value = "file:/etc/hirs/aca/aca.properties",
ignoreResourceNotFound = true)
})
@ComponentScan({ "hirs.attestationca", "hirs.attestationca.service", "hirs.validation",
"hirs.data.service" })
@ComponentScan({ "hirs.attestationca", "hirs.attestationca.service", "hirs.attestationca.rest",
"hirs.validation", "hirs.data.service" })
@Import(HibernateConfiguration.class)
@EnableWebMvc
public class AttestationCertificateAuthorityConfiguration extends WebMvcConfigurerAdapter {
Expand Down Expand Up @@ -248,4 +250,13 @@ public void configureDefaultServletHandling(final DefaultServletHandlerConfigure
configurer.enable();
}

@Override
public void configureContentNegotiation(final ContentNegotiationConfigurer configurer) {
// TODO: Confirm those lines are unnecessary
// configurer.favorPathExtension(false)
// .ignoreAcceptHeader(false)
// .defaultContentType(MediaType.APPLICATION_JSON)
// .useJaf(false);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package hirs.attestationca.exceptions;

/**
* Generic exception thrown while a {@link hirs.attestationca.AttestationCertificateAuthority}
* is processing a newly created Attestation Certificate for a validated identity.
*/
public class CertificateProcessingException extends RuntimeException {
/**
* Constructs a generic instance of this exception using the specified reason.
*
* @param reason for the exception
*/
public CertificateProcessingException(final String reason) {
super(reason);
}

/**
* Constructs a instance of this exception with the specified reason and backing root
* exception.
*
* @param reason for this exception
* @param rootException causing this exception
*/
public CertificateProcessingException(final String reason, final Throwable rootException) {
super(reason, rootException);
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package hirs.attestationca;
package hirs.attestationca.exceptions;

/**
* Generic exception thrown while a {@link AttestationCertificateAuthority} is processing a newly
* submitted Identity.
* Generic exception thrown while a {@link hirs.attestationca.AttestationCertificateAuthority}
* is processing a newly submitted Identity.
*/
public class IdentityProcessingException extends RuntimeException {
/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package hirs.attestationca.exceptions;

/**
* Generic exception thrown when a {@link hirs.attestationca.AttestationCertificateAuthority}
* encounters an unexpected condition that can't be handled.
*/
public class UnexpectedServerException extends RuntimeException {
/**
* Constructs a generic instance of this exception using the specified reason.
*
* @param reason for the exception
*/
public UnexpectedServerException(final String reason) {
super(reason);
}

/**
* Constructs a instance of this exception with the specified reason and backing root
* exception.
*
* @param reason for this exception
* @param rootException causing this exception
*/
public UnexpectedServerException(final String reason, final Throwable rootException) {
super(reason, rootException);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/**
* Custom exceptions of the {@link hirs.attestationca.AttestationCertificateAuthority}.
*/
package hirs.attestationca.exceptions;
Loading

0 comments on commit 5ddb978

Please sign in to comment.