diff options
Diffstat (limited to 'pkix/src/main/java/org/spongycastle/cert/cmp/ProtectedPKIMessage.java')
-rw-r--r-- | pkix/src/main/java/org/spongycastle/cert/cmp/ProtectedPKIMessage.java | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/pkix/src/main/java/org/spongycastle/cert/cmp/ProtectedPKIMessage.java b/pkix/src/main/java/org/spongycastle/cert/cmp/ProtectedPKIMessage.java new file mode 100644 index 00000000..b5dbb980 --- /dev/null +++ b/pkix/src/main/java/org/spongycastle/cert/cmp/ProtectedPKIMessage.java @@ -0,0 +1,198 @@ +package org.spongycastle.cert.cmp; + +import java.io.IOException; +import java.io.OutputStream; + +import org.spongycastle.asn1.ASN1EncodableVector; +import org.spongycastle.asn1.ASN1Encoding; +import org.spongycastle.asn1.DERSequence; +import org.spongycastle.asn1.cmp.CMPCertificate; +import org.spongycastle.asn1.cmp.CMPObjectIdentifiers; +import org.spongycastle.asn1.cmp.PBMParameter; +import org.spongycastle.asn1.cmp.PKIBody; +import org.spongycastle.asn1.cmp.PKIHeader; +import org.spongycastle.asn1.cmp.PKIMessage; +import org.spongycastle.cert.X509CertificateHolder; +import org.spongycastle.cert.crmf.PKMACBuilder; +import org.spongycastle.operator.ContentVerifier; +import org.spongycastle.operator.ContentVerifierProvider; +import org.spongycastle.operator.MacCalculator; +import org.spongycastle.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); + } +} |