aboutsummaryrefslogtreecommitdiffstats
path: root/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/ProtectedPKIMessageBuilder.java
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/ProtectedPKIMessageBuilder.java')
-rw-r--r--libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/ProtectedPKIMessageBuilder.java306
1 files changed, 306 insertions, 0 deletions
diff --git a/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/ProtectedPKIMessageBuilder.java b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/ProtectedPKIMessageBuilder.java
new file mode 100644
index 000000000..8d5228d17
--- /dev/null
+++ b/libraries/spongycastle/pkix/src/main/java/org/spongycastle/cert/cmp/ProtectedPKIMessageBuilder.java
@@ -0,0 +1,306 @@
+package org.spongycastle.cert.cmp;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.spongycastle.asn1.ASN1EncodableVector;
+import org.spongycastle.asn1.ASN1Encoding;
+import org.spongycastle.asn1.ASN1GeneralizedTime;
+import org.spongycastle.asn1.DERBitString;
+import org.spongycastle.asn1.DERSequence;
+import org.spongycastle.asn1.cmp.CMPCertificate;
+import org.spongycastle.asn1.cmp.InfoTypeAndValue;
+import org.spongycastle.asn1.cmp.PKIBody;
+import org.spongycastle.asn1.cmp.PKIFreeText;
+import org.spongycastle.asn1.cmp.PKIHeader;
+import org.spongycastle.asn1.cmp.PKIHeaderBuilder;
+import org.spongycastle.asn1.cmp.PKIMessage;
+import org.spongycastle.asn1.x509.AlgorithmIdentifier;
+import org.spongycastle.asn1.x509.GeneralName;
+import org.spongycastle.cert.X509CertificateHolder;
+import org.spongycastle.operator.ContentSigner;
+import org.spongycastle.operator.MacCalculator;
+
+/**
+ * Builder for creating a protected PKI message.
+ */
+public class ProtectedPKIMessageBuilder
+{
+ private PKIHeaderBuilder hdrBuilder;
+ private PKIBody body;
+ private List generalInfos = new ArrayList();
+ private List extraCerts = new ArrayList();
+
+ /**
+ * Commence a message with the header version CMP_2000.
+ *
+ * @param sender message sender.
+ * @param recipient intended recipient.
+ */
+ public ProtectedPKIMessageBuilder(GeneralName sender, GeneralName recipient)
+ {
+ this(PKIHeader.CMP_2000, sender, recipient);
+ }
+
+ /**
+ * Commence a message with a specific header type.
+ *
+ * @param pvno the version CMP_1999 or CMP_2000.
+ * @param sender message sender.
+ * @param recipient intended recipient.
+ */
+ public ProtectedPKIMessageBuilder(int pvno, GeneralName sender, GeneralName recipient)
+ {
+ hdrBuilder = new PKIHeaderBuilder(pvno, sender, recipient);
+ }
+
+ /**
+ * Set the identifier for the transaction the new message will belong to.
+ *
+ * @param tid the transaction ID.
+ * @return the current builder instance.
+ */
+ public ProtectedPKIMessageBuilder setTransactionID(byte[] tid)
+ {
+ hdrBuilder.setTransactionID(tid);
+
+ return this;
+ }
+
+ /**
+ * Include a human-readable message in the new message.
+ *
+ * @param freeText the contents of the human readable message,
+ * @return the current builder instance.
+ */
+ public ProtectedPKIMessageBuilder setFreeText(PKIFreeText freeText)
+ {
+ hdrBuilder.setFreeText(freeText);
+
+ return this;
+ }
+
+ /**
+ * Add a generalInfo data record to the header of the new message.
+ *
+ * @param genInfo the generalInfo data to be added.
+ * @return the current builder instance.
+ */
+ public ProtectedPKIMessageBuilder addGeneralInfo(InfoTypeAndValue genInfo)
+ {
+ generalInfos.add(genInfo);
+
+ return this;
+ }
+
+ /**
+ * Set the creation time for the new message.
+ *
+ * @param time the message creation time.
+ * @return the current builder instance.
+ */
+ public ProtectedPKIMessageBuilder setMessageTime(Date time)
+ {
+ hdrBuilder.setMessageTime(new ASN1GeneralizedTime(time));
+
+ return this;
+ }
+
+ /**
+ * Set the recipient key identifier for the key to be used to verify the new message.
+ *
+ * @param kid a key identifier.
+ * @return the current builder instance.
+ */
+ public ProtectedPKIMessageBuilder setRecipKID(byte[] kid)
+ {
+ hdrBuilder.setRecipKID(kid);
+
+ return this;
+ }
+
+ /**
+ * Set the recipient nonce field on the new message.
+ *
+ * @param nonce a NONCE, typically copied from the sender nonce of the previous message.
+ * @return the current builder instance.
+ */
+ public ProtectedPKIMessageBuilder setRecipNonce(byte[] nonce)
+ {
+ hdrBuilder.setRecipNonce(nonce);
+
+ return this;
+ }
+
+ /**
+ * Set the sender key identifier for the key used to protect the new message.
+ *
+ * @param kid a key identifier.
+ * @return the current builder instance.
+ */
+ public ProtectedPKIMessageBuilder setSenderKID(byte[] kid)
+ {
+ hdrBuilder.setSenderKID(kid);
+
+ return this;
+ }
+
+ /**
+ * Set the sender nonce field on the new message.
+ *
+ * @param nonce a NONCE, typically 128 bits of random data.
+ * @return the current builder instance.
+ */
+ public ProtectedPKIMessageBuilder setSenderNonce(byte[] nonce)
+ {
+ hdrBuilder.setSenderNonce(nonce);
+
+ return this;
+ }
+
+ /**
+ * Set the body for the new message
+ *
+ * @param body the message body.
+ * @return the current builder instance.
+ */
+ public ProtectedPKIMessageBuilder setBody(PKIBody body)
+ {
+ this.body = body;
+
+ return this;
+ }
+
+ /**
+ * Add an "extra certificate" to the message.
+ *
+ * @param extraCert the extra certificate to add.
+ * @return the current builder instance.
+ */
+ public ProtectedPKIMessageBuilder addCMPCertificate(X509CertificateHolder extraCert)
+ {
+ extraCerts.add(extraCert);
+
+ return this;
+ }
+
+ /**
+ * Build a protected PKI message which has MAC based integrity protection.
+ *
+ * @param macCalculator MAC calculator.
+ * @return the resulting protected PKI message.
+ * @throws CMPException if the protection MAC cannot be calculated.
+ */
+ public ProtectedPKIMessage build(MacCalculator macCalculator)
+ throws CMPException
+ {
+ finaliseHeader(macCalculator.getAlgorithmIdentifier());
+
+ PKIHeader header = hdrBuilder.build();
+
+ try
+ {
+ DERBitString protection = new DERBitString(calculateMac(macCalculator, header, body));
+
+ return finaliseMessage(header, protection);
+ }
+ catch (IOException e)
+ {
+ throw new CMPException("unable to encode MAC input: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Build a protected PKI message which has MAC based integrity protection.
+ *
+ * @param signer the ContentSigner to be used to calculate the signature.
+ * @return the resulting protected PKI message.
+ * @throws CMPException if the protection signature cannot be calculated.
+ */
+ public ProtectedPKIMessage build(ContentSigner signer)
+ throws CMPException
+ {
+ finaliseHeader(signer.getAlgorithmIdentifier());
+
+ PKIHeader header = hdrBuilder.build();
+
+ try
+ {
+ DERBitString protection = new DERBitString(calculateSignature(signer, header, body));
+
+ return finaliseMessage(header, protection);
+ }
+ catch (IOException e)
+ {
+ throw new CMPException("unable to encode signature input: " + e.getMessage(), e);
+ }
+ }
+
+ private void finaliseHeader(AlgorithmIdentifier algorithmIdentifier)
+ {
+ hdrBuilder.setProtectionAlg(algorithmIdentifier);
+
+ if (!generalInfos.isEmpty())
+ {
+ InfoTypeAndValue[] genInfos = new InfoTypeAndValue[generalInfos.size()];
+
+ hdrBuilder.setGeneralInfo((InfoTypeAndValue[])generalInfos.toArray(genInfos));
+ }
+ }
+
+ private ProtectedPKIMessage finaliseMessage(PKIHeader header, DERBitString protection)
+ {
+ if (!extraCerts.isEmpty())
+ {
+ CMPCertificate[] cmpCerts = new CMPCertificate[extraCerts.size()];
+
+ for (int i = 0; i != cmpCerts.length; i++)
+ {
+ cmpCerts[i] = new CMPCertificate(((X509CertificateHolder)extraCerts.get(i)).toASN1Structure());
+ }
+
+ return new ProtectedPKIMessage(new PKIMessage(header, body, protection, cmpCerts));
+ }
+ else
+ {
+ return new ProtectedPKIMessage(new PKIMessage(header, body, protection));
+ }
+ }
+
+ private byte[] calculateSignature(ContentSigner signer, PKIHeader header, PKIBody body)
+ throws IOException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(header);
+ v.add(body);
+
+ OutputStream sOut = signer.getOutputStream();
+
+ sOut.write(new DERSequence(v).getEncoded(ASN1Encoding.DER));
+
+ sOut.close();
+
+ return signer.getSignature();
+ }
+
+ private byte[] calculateMac(MacCalculator macCalculator, PKIHeader header, PKIBody body)
+ throws IOException
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ v.add(header);
+ v.add(body);
+
+ OutputStream sOut = macCalculator.getOutputStream();
+
+ sOut.write(new DERSequence(v).getEncoded(ASN1Encoding.DER));
+
+ sOut.close();
+
+ return macCalculator.getMac();
+ }
+}