package de.persosim.simulator.crypto.certificates;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.List;
import de.persosim.simulator.exception.CarParameterInvalidException;
import de.persosim.simulator.exception.CertificateNotParseableException;
import de.persosim.simulator.protocols.Tr03110Utils;
import de.persosim.simulator.tlv.ConstructedTlvDataObject;
import de.persosim.simulator.tlv.TlvConstants;
import de.persosim.simulator.tlv.TlvDataObject;
import de.persosim.simulator.utils.Utils;
/**
* This class implements the body of a card verifiable certificate as described
* in TR-03110 v2.10 Part 3 Appendix C.
*
* @author mboonk, cstroh
*
*/
public class ReducedCertificateBody implements Body {
protected int certificateProfileIdentifier;
protected PublicKeyReference certificationAuthorityReference;
protected CvPublicKey publicKey;
protected PublicKeyReference certificateHolderReference;
protected List<CertificateExtension> certificateExtensions;
public ReducedCertificateBody(
int certificateProfileIdentifier,
PublicKeyReference certificationAuthorityReference,
CvPublicKey publicKey,
PublicKeyReference certificateHolderReference,
List<CertificateExtension> certificateExtensions) {
if(certificateHolderReference.equals(certificationAuthorityReference)) {
if(!publicKey.isComplete()) {
throw new IllegalArgumentException("Certificate seems to be a self-signed CVCA root certificate, but domain parameters are missing.");
}
}
this.certificateProfileIdentifier = certificateProfileIdentifier;
this.certificationAuthorityReference = certificationAuthorityReference;
this.publicKey = publicKey;
this.certificateHolderReference = certificateHolderReference;
this.certificateExtensions = certificateExtensions;
}
/**
* Create a certificate object from the TLV-encoding using the domain
* parameters from the certificate.
* @param certificateData as described in TR-03110 V2.10 part 3, C
* @throws CertificateNotParseableException
*/
public ReducedCertificateBody(ConstructedTlvDataObject certificateData) throws CertificateNotParseableException {
this(certificateData, null);
}
/**
* Create a certificate object from the TLV-encoding using the domain
* parameters from the given public key if the certificate does not contain
* them.
*
* @param certificateBodyData as described in TR-03110 V2.10 part 3, C
* @param currentPublicKey the public key to be used
* @throws CertificateNotParseableException
*/
public ReducedCertificateBody(ConstructedTlvDataObject certificateBodyData, PublicKey currentPublicKey) throws CertificateNotParseableException {
//Certificate Profile Identifier (CPI)
certificateProfileIdentifier = Utils.getIntFromUnsignedByteArray(certificateBodyData.getTlvDataObject(TlvConstants.TAG_5F29).getValueField());
//Certification Authority Reference (CAR)
try {
certificationAuthorityReference = new PublicKeyReference(certificateBodyData.getTlvDataObject(TlvConstants.TAG_42));
} catch (CarParameterInvalidException e) {
throw new CertificateNotParseableException("The certificate authority reference could not be parsed");
}
//Public Key (PK)
ConstructedTlvDataObject publicKeyData = (ConstructedTlvDataObject) certificateBodyData.getTlvDataObject(TlvConstants.TAG_7F49);
publicKey = Tr03110Utils.parseCvPublicKey(publicKeyData);
if(currentPublicKey != null) {
publicKey.updateKey(currentPublicKey);
}
//Certificate Holder Reference (CHR)
try {
certificateHolderReference = new PublicKeyReference(certificateBodyData.getTlvDataObject(TlvConstants.TAG_5F20));
} catch (CarParameterInvalidException e) {
throw new CertificateNotParseableException("The certificate holder reference could not be parsed");
}
//Certificate Extensions (CE)
certificateExtensions = parseExtensions((ConstructedTlvDataObject) certificateBodyData.getTlvDataObject(TlvConstants.TAG_65));
if(certificateHolderReference.equals(certificationAuthorityReference)) {
if(!publicKey.isComplete()) {
throw new IllegalArgumentException("Certificate seems to be a self-signed CVCA root certificate, but domain parameters are missing.");
}
}
}
/**
* Create a list of all certificate extensions
* see {@link #parseCertificateExtensions(ConstructedTlvDataObject)} for details
*/
protected List<CertificateExtension> parseExtensions(ConstructedTlvDataObject extensionsData) {
return parseCertificateExtensions(extensionsData);
}
/**
* Create a list of all certificate extensions
* @param extensionsData as described in TR03110 v2.10 part 3, C
* @return all parsed extensions
*/
public static List<CertificateExtension> parseCertificateExtensions(ConstructedTlvDataObject extensionsData) {
List<CertificateExtension> result = new ArrayList<>();
if (extensionsData != null){
for (TlvDataObject ddt : extensionsData.getTlvDataObjectContainer()){
if (ddt instanceof ConstructedTlvDataObject){
result.add(new GenericExtension((ConstructedTlvDataObject) ddt));
}
}
}
return result;
}
@Override
public int getCertificateProfileIdentifier() {
return certificateProfileIdentifier;
}
@Override
public PublicKeyReference getCertificationAuthorityReference() {
return certificationAuthorityReference;
}
@Override
public PublicKeyReference getCertificateHolderReference() {
return certificateHolderReference;
}
@Override
public CvPublicKey getPublicKey() {
return publicKey;
}
@Override
public List<CertificateExtension> getCertificateExtensions() {
return certificateExtensions;
}
@Override
public byte[] getEncoded() {
return getTlvEncoding(true).toByteArray();
}
@Override
public String toString() {
return "CardVerifiableCertificate [certificateAuthorityReference="
+ certificationAuthorityReference
+ ", certificateHolderReference=" + certificateHolderReference
+ "]";
}
@Override
public ConstructedTlvDataObject getTlvEncoding(boolean withParams) {
ConstructedTlvDataObject encoding = CertificateUtils.encodeReducedCertificateBody(
certificateProfileIdentifier,
certificationAuthorityReference,
publicKey.toTlvDataObject(withParams),
certificateHolderReference,
getExtensionRepresentation());
return encoding;
}
@Override
public ConstructedTlvDataObject getExtensionRepresentation() {
if((certificateExtensions != null) && (!certificateExtensions.isEmpty())) {
ConstructedTlvDataObject extensionRepresentation = new ConstructedTlvDataObject(TlvConstants.TAG_65);
for(CertificateExtension extension : certificateExtensions) {
extensionRepresentation.addTlvDataObject(extension.toTlv());
}
return extensionRepresentation;
} else{
return null;
}
}
}