org.bouncycastle.cert.cmp.ProtectedPKIMessage Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bcpkix-jdk15on Show documentation
Show all versions of bcpkix-jdk15on Show documentation
The Bouncy Castle Java APIs for CMS, PKCS, EAC, TSP, CMP, CRMF, OCSP, and certificate generation. This jar contains APIs for JDK 1.5 to JDK 1.8. The APIs can be used in conjunction with a JCE/JCA provider such as the one provided with the Bouncy Castle Cryptography APIs.
package org.bouncycastle.cert.cmp;
import java.io.IOException;
import java.io.OutputStream;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.cmp.CMPCertificate;
import org.bouncycastle.asn1.cmp.CMPObjectIdentifiers;
import org.bouncycastle.asn1.cmp.PBMParameter;
import org.bouncycastle.asn1.cmp.PKIBody;
import org.bouncycastle.asn1.cmp.PKIHeader;
import org.bouncycastle.asn1.cmp.PKIMessage;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.crmf.PKMACBuilder;
import org.bouncycastle.operator.ContentVerifier;
import org.bouncycastle.operator.ContentVerifierProvider;
import org.bouncycastle.operator.MacCalculator;
import org.bouncycastle.util.Arrays;
/**
* Wrapper for a PKIMessage with protection attached to it.
*/
public class ProtectedPKIMessage
{
private PKIMessage pkiMessage;
/**
* Base constructor.
*
* @param pkiMessage a GeneralPKIMessage with
*/
public ProtectedPKIMessage(GeneralPKIMessage pkiMessage)
{
if (!pkiMessage.hasProtection())
{
throw new IllegalArgumentException("PKIMessage not protected");
}
this.pkiMessage = pkiMessage.toASN1Structure();
}
ProtectedPKIMessage(PKIMessage pkiMessage)
{
if (pkiMessage.getHeader().getProtectionAlg() == null)
{
throw new IllegalArgumentException("PKIMessage not protected");
}
this.pkiMessage = pkiMessage;
}
/**
* Return the message header.
*
* @return the message's PKIHeader structure.
*/
public PKIHeader getHeader()
{
return pkiMessage.getHeader();
}
/**
* Return the message body.
*
* @return the message's PKIBody structure.
*/
public PKIBody getBody()
{
return pkiMessage.getBody();
}
/**
* Return the underlying ASN.1 structure contained in this object.
*
* @return a PKIMessage structure.
*/
public PKIMessage toASN1Structure()
{
return pkiMessage;
}
/**
* Determine whether the message is protected by a password based MAC. Use verify(PKMACBuilder, char[])
* to verify the message if this method returns true.
*
* @return true if protection MAC PBE based, false otherwise.
*/
public boolean hasPasswordBasedMacProtection()
{
return pkiMessage.getHeader().getProtectionAlg().getAlgorithm().equals(CMPObjectIdentifiers.passwordBasedMac);
}
/**
* Return the extra certificates associated with this message.
*
* @return an array of extra certificates, zero length if none present.
*/
public X509CertificateHolder[] getCertificates()
{
CMPCertificate[] certs = pkiMessage.getExtraCerts();
if (certs == null)
{
return new X509CertificateHolder[0];
}
X509CertificateHolder[] res = new X509CertificateHolder[certs.length];
for (int i = 0; i != certs.length; i++)
{
res[i] = new X509CertificateHolder(certs[i].getX509v3PKCert());
}
return res;
}
/**
* Verify a message with a public key based signature attached.
*
* @param verifierProvider a provider of signature verifiers.
* @return true if the provider is able to create a verifier that validates
* the signature, false otherwise.
* @throws CMPException if an exception is thrown trying to verify the signature.
*/
public boolean verify(ContentVerifierProvider verifierProvider)
throws CMPException
{
ContentVerifier verifier;
try
{
verifier = verifierProvider.get(pkiMessage.getHeader().getProtectionAlg());
return verifySignature(pkiMessage.getProtection().getBytes(), verifier);
}
catch (Exception e)
{
throw new CMPException("unable to verify signature: " + e.getMessage(), e);
}
}
/**
* Verify a message with password based MAC protection.
*
* @param pkMacBuilder MAC builder that can be used to construct the appropriate MacCalculator
* @param password the MAC password
* @return true if the passed in password and MAC builder verify the message, false otherwise.
* @throws CMPException if algorithm not MAC based, or an exception is thrown verifying the MAC.
*/
public boolean verify(PKMACBuilder pkMacBuilder, char[] password)
throws CMPException
{
if (!CMPObjectIdentifiers.passwordBasedMac.equals(pkiMessage.getHeader().getProtectionAlg().getAlgorithm()))
{
throw new CMPException("protection algorithm not mac based");
}
try
{
pkMacBuilder.setParameters(PBMParameter.getInstance(pkiMessage.getHeader().getProtectionAlg().getParameters()));
MacCalculator calculator = pkMacBuilder.build(password);
OutputStream macOut = calculator.getOutputStream();
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(pkiMessage.getHeader());
v.add(pkiMessage.getBody());
macOut.write(new DERSequence(v).getEncoded(ASN1Encoding.DER));
macOut.close();
return Arrays.areEqual(calculator.getMac(), pkiMessage.getProtection().getBytes());
}
catch (Exception e)
{
throw new CMPException("unable to verify MAC: " + e.getMessage(), e);
}
}
private boolean verifySignature(byte[] signature, ContentVerifier verifier)
throws IOException
{
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(pkiMessage.getHeader());
v.add(pkiMessage.getBody());
OutputStream sOut = verifier.getOutputStream();
sOut.write(new DERSequence(v).getEncoded(ASN1Encoding.DER));
sOut.close();
return verifier.verify(signature);
}
}