org.spongycastle.cert.crmf.CertificateRequestMessage Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pkix Show documentation
Show all versions of pkix Show documentation
Spongy Castle is a package-rename (org.bouncycastle.* to org.spongycastle.*) of Bouncy Castle
intended for the Android platform. Android unfortunately ships with a stripped-down version of
Bouncy Castle, which prevents easy upgrades - Spongy Castle overcomes this and provides a full,
up-to-date version of the Bouncy Castle cryptographic libs.
package org.spongycastle.cert.crmf;
import java.io.IOException;
import org.spongycastle.asn1.ASN1ObjectIdentifier;
import org.spongycastle.asn1.ASN1Primitive;
import org.spongycastle.asn1.DERUTF8String;
import org.spongycastle.asn1.crmf.AttributeTypeAndValue;
import org.spongycastle.asn1.crmf.CRMFObjectIdentifiers;
import org.spongycastle.asn1.crmf.CertReqMsg;
import org.spongycastle.asn1.crmf.CertTemplate;
import org.spongycastle.asn1.crmf.Controls;
import org.spongycastle.asn1.crmf.PKIArchiveOptions;
import org.spongycastle.asn1.crmf.PKMACValue;
import org.spongycastle.asn1.crmf.POPOSigningKey;
import org.spongycastle.asn1.crmf.ProofOfPossession;
import org.spongycastle.cert.CertIOException;
import org.spongycastle.operator.ContentVerifier;
import org.spongycastle.operator.ContentVerifierProvider;
import org.spongycastle.operator.OperatorCreationException;
import org.spongycastle.util.Encodable;
/**
* Carrier for a CRMF CertReqMsg.
*/
public class CertificateRequestMessage
implements Encodable
{
public static final int popRaVerified = ProofOfPossession.TYPE_RA_VERIFIED;
public static final int popSigningKey = ProofOfPossession.TYPE_SIGNING_KEY;
public static final int popKeyEncipherment = ProofOfPossession.TYPE_KEY_ENCIPHERMENT;
public static final int popKeyAgreement = ProofOfPossession.TYPE_KEY_AGREEMENT;
private final CertReqMsg certReqMsg;
private final Controls controls;
private static CertReqMsg parseBytes(byte[] encoding)
throws IOException
{
try
{
return CertReqMsg.getInstance(ASN1Primitive.fromByteArray(encoding));
}
catch (ClassCastException e)
{
throw new CertIOException("malformed data: " + e.getMessage(), e);
}
catch (IllegalArgumentException e)
{
throw new CertIOException("malformed data: " + e.getMessage(), e);
}
}
/**
* Create a CertificateRequestMessage from the passed in bytes.
*
* @param certReqMsg BER/DER encoding of the CertReqMsg structure.
* @throws IOException in the event of corrupted data, or an incorrect structure.
*/
public CertificateRequestMessage(byte[] certReqMsg)
throws IOException
{
this(parseBytes(certReqMsg));
}
public CertificateRequestMessage(CertReqMsg certReqMsg)
{
this.certReqMsg = certReqMsg;
this.controls = certReqMsg.getCertReq().getControls();
}
/**
* Return the underlying ASN.1 object defining this CertificateRequestMessage object.
*
* @return a CertReqMsg.
*/
public CertReqMsg toASN1Structure()
{
return certReqMsg;
}
/**
* Return the certificate template contained in this message.
*
* @return a CertTemplate structure.
*/
public CertTemplate getCertTemplate()
{
return this.certReqMsg.getCertReq().getCertTemplate();
}
/**
* Return whether or not this request has control values associated with it.
*
* @return true if there are control values present, false otherwise.
*/
public boolean hasControls()
{
return controls != null;
}
/**
* Return whether or not this request has a specific type of control value.
*
* @param type the type OID for the control value we are checking for.
* @return true if a control value of type is present, false otherwise.
*/
public boolean hasControl(ASN1ObjectIdentifier type)
{
return findControl(type) != null;
}
/**
* Return a control value of the specified type.
*
* @param type the type OID for the control value we are checking for.
* @return the control value if present, null otherwise.
*/
public Control getControl(ASN1ObjectIdentifier type)
{
AttributeTypeAndValue found = findControl(type);
if (found != null)
{
if (found.getType().equals(CRMFObjectIdentifiers.id_regCtrl_pkiArchiveOptions))
{
return new PKIArchiveControl(PKIArchiveOptions.getInstance(found.getValue()));
}
if (found.getType().equals(CRMFObjectIdentifiers.id_regCtrl_regToken))
{
return new RegTokenControl(DERUTF8String.getInstance(found.getValue()));
}
if (found.getType().equals(CRMFObjectIdentifiers.id_regCtrl_authenticator))
{
return new AuthenticatorControl(DERUTF8String.getInstance(found.getValue()));
}
}
return null;
}
private AttributeTypeAndValue findControl(ASN1ObjectIdentifier type)
{
if (controls == null)
{
return null;
}
AttributeTypeAndValue[] tAndVs = controls.toAttributeTypeAndValueArray();
AttributeTypeAndValue found = null;
for (int i = 0; i != tAndVs.length; i++)
{
if (tAndVs[i].getType().equals(type))
{
found = tAndVs[i];
break;
}
}
return found;
}
/**
* Return whether or not this request message has a proof-of-possession field in it.
*
* @return true if proof-of-possession is present, false otherwise.
*/
public boolean hasProofOfPossession()
{
return this.certReqMsg.getPopo() != null;
}
/**
* Return the type of the proof-of-possession this request message provides.
*
* @return one of: popRaVerified, popSigningKey, popKeyEncipherment, popKeyAgreement
*/
public int getProofOfPossessionType()
{
return this.certReqMsg.getPopo().getType();
}
/**
* Return whether or not the proof-of-possession (POP) is of the type popSigningKey and
* it has a public key MAC associated with it.
*
* @return true if POP is popSigningKey and a PKMAC is present, false otherwise.
*/
public boolean hasSigningKeyProofOfPossessionWithPKMAC()
{
ProofOfPossession pop = certReqMsg.getPopo();
if (pop.getType() == popSigningKey)
{
POPOSigningKey popoSign = POPOSigningKey.getInstance(pop.getObject());
return popoSign.getPoposkInput().getPublicKeyMAC() != null;
}
return false;
}
/**
* Return whether or not a signing key proof-of-possession (POP) is valid.
*
* @param verifierProvider a provider that can produce content verifiers for the signature contained in this POP.
* @return true if the POP is valid, false otherwise.
* @throws CRMFException if there is a problem in verification or content verifier creation.
* @throws IllegalStateException if POP not appropriate.
*/
public boolean isValidSigningKeyPOP(ContentVerifierProvider verifierProvider)
throws CRMFException, IllegalStateException
{
ProofOfPossession pop = certReqMsg.getPopo();
if (pop.getType() == popSigningKey)
{
POPOSigningKey popoSign = POPOSigningKey.getInstance(pop.getObject());
if (popoSign.getPoposkInput() != null && popoSign.getPoposkInput().getPublicKeyMAC() != null)
{
throw new IllegalStateException("verification requires password check");
}
return verifySignature(verifierProvider, popoSign);
}
else
{
throw new IllegalStateException("not Signing Key type of proof of possession");
}
}
/**
* Return whether or not a signing key proof-of-possession (POP), with an associated PKMAC, is valid.
*
* @param verifierProvider a provider that can produce content verifiers for the signature contained in this POP.
* @param macBuilder a suitable PKMACBuilder to create the MAC verifier.
* @param password the password used to key the MAC calculation.
* @return true if the POP is valid, false otherwise.
* @throws CRMFException if there is a problem in verification or content verifier creation.
* @throws IllegalStateException if POP not appropriate.
*/
public boolean isValidSigningKeyPOP(ContentVerifierProvider verifierProvider, PKMACBuilder macBuilder, char[] password)
throws CRMFException, IllegalStateException
{
ProofOfPossession pop = certReqMsg.getPopo();
if (pop.getType() == popSigningKey)
{
POPOSigningKey popoSign = POPOSigningKey.getInstance(pop.getObject());
if (popoSign.getPoposkInput() == null || popoSign.getPoposkInput().getSender() != null)
{
throw new IllegalStateException("no PKMAC present in proof of possession");
}
PKMACValue pkMAC = popoSign.getPoposkInput().getPublicKeyMAC();
PKMACValueVerifier macVerifier = new PKMACValueVerifier(macBuilder);
if (macVerifier.isValid(pkMAC, password, this.getCertTemplate().getPublicKey()))
{
return verifySignature(verifierProvider, popoSign);
}
return false;
}
else
{
throw new IllegalStateException("not Signing Key type of proof of possession");
}
}
private boolean verifySignature(ContentVerifierProvider verifierProvider, POPOSigningKey popoSign)
throws CRMFException
{
ContentVerifier verifier;
try
{
verifier = verifierProvider.get(popoSign.getAlgorithmIdentifier());
}
catch (OperatorCreationException e)
{
throw new CRMFException("unable to create verifier: " + e.getMessage(), e);
}
if (popoSign.getPoposkInput() != null)
{
CRMFUtil.derEncodeToStream(popoSign.getPoposkInput(), verifier.getOutputStream());
}
else
{
CRMFUtil.derEncodeToStream(certReqMsg.getCertReq(), verifier.getOutputStream());
}
return verifier.verify(popoSign.getSignature().getBytes());
}
/**
* Return the ASN.1 encoding of the certReqMsg we wrap.
*
* @return a byte array containing the binary encoding of the certReqMsg.
* @throws IOException if there is an exception creating the encoding.
*/
public byte[] getEncoded()
throws IOException
{
return certReqMsg.getEncoded();
}
}