diff --git a/crypto/src/cmp/CertificateConfirmationContent.cs b/crypto/src/cmp/CertificateConfirmationContent.cs
index 262a28531..edd4a28ed 100644
--- a/crypto/src/cmp/CertificateConfirmationContent.cs
+++ b/crypto/src/cmp/CertificateConfirmationContent.cs
@@ -14,7 +14,7 @@ namespace Org.BouncyCastle.Cmp
IDigestAlgorithmFinder digestAlgorithmFinder)
{
if (!IsCertificateConfirmationContent(pkiBody.Type))
- throw new ArgumentException("content of PkiBody wrong type: " + pkiBody.Type);
+ throw new ArgumentException("content of PKIBody wrong type: " + pkiBody.Type);
var content = CertConfirmContent.GetInstance(pkiBody.Content);
diff --git a/crypto/src/cmp/ProtectedPkiMessage.cs b/crypto/src/cmp/ProtectedPkiMessage.cs
index a7fdd35a9..9e442c426 100644
--- a/crypto/src/cmp/ProtectedPkiMessage.cs
+++ b/crypto/src/cmp/ProtectedPkiMessage.cs
@@ -102,6 +102,9 @@ namespace Org.BouncyCastle.Cmp
/// <exception cref="InvalidOperationException">if algorithm not MAC based, or an exception is thrown verifying the MAC.</exception>
public virtual bool Verify(PKMacBuilder pkMacBuilder, char[] password)
{
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return Verify(pkMacBuilder, password.AsSpan());
+#else
var protectionAlgorithm = m_pkiMessage.Header.ProtectionAlg;
if (!CmpObjectIdentifiers.passwordBasedMac.Equals(protectionAlgorithm.Algorithm))
@@ -113,6 +116,7 @@ namespace Org.BouncyCastle.Cmp
var macFactory = pkMacBuilder.Build(password);
return X509Utilities.VerifyMac(macFactory, CreateProtected(), m_pkiMessage.Protection);
+#endif
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
diff --git a/crypto/src/cmp/ProtectedPkiMessageBuilder.cs b/crypto/src/cmp/ProtectedPkiMessageBuilder.cs
index ff4af5573..27d2cd0a1 100644
--- a/crypto/src/cmp/ProtectedPkiMessageBuilder.cs
+++ b/crypto/src/cmp/ProtectedPkiMessageBuilder.cs
@@ -4,6 +4,7 @@ using System.Collections.Generic;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Cmp;
using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Crmf;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.X509;
@@ -86,25 +87,23 @@ namespace Org.BouncyCastle.Cmp
return this;
}
- // TODO[crmf] Add CertificateReqMessages
- //public ProtectedPkiMessageBuilder SetBody(int bodyType, CertificateReqMessages certificateReqMessages)
- //{
- // if (!CertificateReqMessages.IsCertificateRequestMessages(bodyType))
- // throw new ArgumentException("body type " + bodyType + " does not match CMP type CertReqMessages");
+ public ProtectedPkiMessageBuilder SetBody(int bodyType, CertificateReqMessages certificateReqMessages)
+ {
+ if (!CertificateReqMessages.IsCertificateRequestMessages(bodyType))
+ throw new ArgumentException("body type " + bodyType + " does not match CMP type CertReqMessages");
- // m_body = new PkiBody(bodyType, certificateReqMessages.ToAsn1Structure());
- // return this;
- //}
+ m_body = new PkiBody(bodyType, certificateReqMessages.ToAsn1Structure());
+ return this;
+ }
- // TODO[crmf] Add CertificateRepMessage
- //public ProtectedPkiMessageBuilder SetBody(int bodyType, CertificateRepMessage certificateRepMessage)
- //{
- // if (!CertificateRepMessage.IsCertificateRepMessage(bodyType))
- // throw new ArgumentException("body type " + bodyType + " does not match CMP type CertRepMessage");
+ public ProtectedPkiMessageBuilder SetBody(int bodyType, CertificateRepMessage certificateRepMessage)
+ {
+ if (!CertificateRepMessage.IsCertificateRepMessage(bodyType))
+ throw new ArgumentException("body type " + bodyType + " does not match CMP type CertRepMessage");
- // m_body = new PkiBody(bodyType, certificateRepMessage.ToAsn1Structure());
- // return this;
- //}
+ m_body = new PkiBody(bodyType, certificateRepMessage.ToAsn1Structure());
+ return this;
+ }
public ProtectedPkiMessageBuilder SetBody(int bodyType,
CertificateConfirmationContent certificateConfirmationContent)
diff --git a/crypto/src/crmf/AuthenticatorControl.cs b/crypto/src/crmf/AuthenticatorControl.cs
index fc546ede5..4a15db6cb 100644
--- a/crypto/src/crmf/AuthenticatorControl.cs
+++ b/crypto/src/crmf/AuthenticatorControl.cs
@@ -11,9 +11,7 @@ namespace Org.BouncyCastle.Crmf
public class AuthenticatorControl
: IControl
{
- private static readonly DerObjectIdentifier type = CrmfObjectIdentifiers.id_regCtrl_authenticator;
-
- private readonly DerUtf8String token;
+ private readonly DerUtf8String m_token;
/// <summary>
/// Basic constructor - build from a UTF-8 string representing the token.
@@ -21,7 +19,7 @@ namespace Org.BouncyCastle.Crmf
/// <param name="token">UTF-8 string representing the token.</param>
public AuthenticatorControl(DerUtf8String token)
{
- this.token = token;
+ m_token = token;
}
/// <summary>
@@ -30,23 +28,17 @@ namespace Org.BouncyCastle.Crmf
/// <param name="token">string representing the token.</param>
public AuthenticatorControl(string token)
{
- this.token = new DerUtf8String(token);
+ m_token = new DerUtf8String(token);
}
/// <summary>
/// Return the type of this control.
/// </summary>
- public DerObjectIdentifier Type
- {
- get { return type; }
- }
+ public DerObjectIdentifier Type => CrmfObjectIdentifiers.id_regCtrl_authenticator;
/// <summary>
/// Return the token associated with this control (a UTF8String).
/// </summary>
- public Asn1Encodable Value
- {
- get { return token; }
- }
+ public Asn1Encodable Value => m_token;
}
}
diff --git a/crypto/src/crmf/CertificateRepMessage.cs b/crypto/src/crmf/CertificateRepMessage.cs
new file mode 100644
index 000000000..756021981
--- /dev/null
+++ b/crypto/src/crmf/CertificateRepMessage.cs
@@ -0,0 +1,85 @@
+using System;
+using System.Collections.Generic;
+
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Crmf
+{
+ public class CertificateRepMessage
+ {
+ public static CertificateRepMessage FromPkiBody(PkiBody pkiBody)
+ {
+ if (!IsCertificateRepMessage(pkiBody.Type))
+ throw new ArgumentException("content of PKIBody wrong type: " + pkiBody.Type);
+
+ return new CertificateRepMessage(CertRepMessage.GetInstance(pkiBody.Content));
+ }
+
+ public static bool IsCertificateRepMessage(int bodyType)
+ {
+ switch (bodyType)
+ {
+ case PkiBody.TYPE_INIT_REP:
+ case PkiBody.TYPE_CERT_REP:
+ case PkiBody.TYPE_KEY_UPDATE_REP:
+ case PkiBody.TYPE_CROSS_CERT_REP:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private readonly CertResponse[] m_resps;
+ private readonly CmpCertificate[] m_caCerts;
+
+ public CertificateRepMessage(CertRepMessage repMessage)
+ {
+ m_resps = repMessage.GetResponse();
+ m_caCerts = repMessage.GetCAPubs();
+ }
+
+ public virtual CertificateResponse[] GetResponses() => Array.ConvertAll(m_resps, resp => new CertificateResponse(resp));
+
+ public virtual X509Certificate[] GetX509Certificates()
+ {
+ List<X509Certificate> certs = new List<X509Certificate>();
+
+ foreach (var caCert in m_caCerts)
+ {
+ if (caCert.IsX509v3PKCert)
+ {
+ certs.Add(new X509Certificate(caCert.X509v3PKCert));
+ }
+ }
+
+ return certs.ToArray();
+ }
+
+ /**
+ * Return true if the message only contains X.509 public key certificates.
+ *
+ * @return true if only X.509 PK, false otherwise.
+ */
+ public virtual bool IsOnlyX509PKCertificates()
+ {
+ bool isOnlyX509 = true;
+
+ foreach (var caCert in m_caCerts)
+ {
+ isOnlyX509 &= caCert.IsX509v3PKCert;
+ }
+
+ return isOnlyX509;
+ }
+
+ /**
+ * Return the actual CMP certificates - useful if the array also contains non-X509 PK certificates.
+ *
+ * @return CMPCertificate array
+ */
+ public virtual CmpCertificate[] GetCmpCertificates() => (CmpCertificate[])m_caCerts.Clone();
+
+ public virtual CertRepMessage ToAsn1Structure() => new CertRepMessage(m_caCerts, m_resps);
+ }
+}
diff --git a/crypto/src/crmf/CertificateRepMessageBuilder.cs b/crypto/src/crmf/CertificateRepMessageBuilder.cs
new file mode 100644
index 000000000..439d98b93
--- /dev/null
+++ b/crypto/src/crmf/CertificateRepMessageBuilder.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Crmf
+{
+ /// <summary>Builder for a CertificateRepMessage.</summary>
+ public class CertificateRepMessageBuilder
+ {
+ private readonly List<CertResponse> m_responses = new List<CertResponse>();
+ private readonly CmpCertificate[] m_caCerts;
+
+ /**
+ * Base constructor which can accept 0 or more certificates representing the CA plus its chain.
+ *
+ * @param caCerts the CA public key and it's support certificates (optional)
+ */
+ public CertificateRepMessageBuilder(params X509Certificate[] caCerts)
+ {
+ m_caCerts = Array.ConvertAll(caCerts, caCert => new CmpCertificate(caCert.CertificateStructure));
+ }
+
+ public virtual CertificateRepMessageBuilder AddCertificateResponse(CertificateResponse response)
+ {
+ m_responses.Add(response.ToAsn1Structure());
+ return this;
+ }
+
+ public virtual CertificateRepMessage Build()
+ {
+ var caPubs = m_caCerts;
+ if (caPubs.Length < 1)
+ {
+ // older versions of CertRepMessage need null if no caCerts.
+ caPubs = null;
+ }
+
+ CertRepMessage repMessage = new CertRepMessage(caPubs, m_responses.ToArray());
+
+ m_responses.Clear();
+
+ return new CertificateRepMessage(repMessage);
+ }
+ }
+}
diff --git a/crypto/src/crmf/CertificateReqMessages.cs b/crypto/src/crmf/CertificateReqMessages.cs
new file mode 100644
index 000000000..db465a352
--- /dev/null
+++ b/crypto/src/crmf/CertificateReqMessages.cs
@@ -0,0 +1,45 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.Crmf;
+
+namespace Org.BouncyCastle.Crmf
+{
+ public class CertificateReqMessages
+ {
+ public static CertificateReqMessages FromPkiBody(PkiBody pkiBody)
+ {
+ if (!IsCertificateRequestMessages(pkiBody.Type))
+ throw new ArgumentException("content of PKIBody wrong type: " + pkiBody.Type);
+
+ return new CertificateReqMessages(CertReqMessages.GetInstance(pkiBody.Content));
+ }
+
+ public static bool IsCertificateRequestMessages(int bodyType)
+ {
+ switch (bodyType)
+ {
+ case PkiBody.TYPE_INIT_REQ:
+ case PkiBody.TYPE_CERT_REQ:
+ case PkiBody.TYPE_KEY_UPDATE_REQ:
+ case PkiBody.TYPE_KEY_RECOVERY_REQ:
+ case PkiBody.TYPE_CROSS_CERT_REQ:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private readonly CertReqMsg[] m_reqs;
+
+ public CertificateReqMessages(CertReqMessages certReqMessages)
+ {
+ m_reqs = certReqMessages.ToCertReqMsgArray();
+ }
+
+ public virtual CertificateRequestMessage[] GetRequests() =>
+ Array.ConvertAll(m_reqs, req => new CertificateRequestMessage(req));
+
+ public virtual CertReqMessages ToAsn1Structure() => new CertReqMessages(m_reqs);
+ }
+}
diff --git a/crypto/src/crmf/CertificateReqMessagesBuilder.cs b/crypto/src/crmf/CertificateReqMessagesBuilder.cs
new file mode 100644
index 000000000..813f1d9e3
--- /dev/null
+++ b/crypto/src/crmf/CertificateReqMessagesBuilder.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+
+using Org.BouncyCastle.Asn1.Crmf;
+
+namespace Org.BouncyCastle.Crmf
+{
+ public class CertificateReqMessagesBuilder
+ {
+ private readonly List<CertReqMsg> m_requests = new List<CertReqMsg>();
+
+ public CertificateReqMessagesBuilder()
+ {
+ }
+
+ public virtual void AddRequest(CertificateRequestMessage request) => m_requests.Add(request.ToAsn1Structure());
+
+ public virtual CertificateReqMessages Build()
+ {
+ CertificateReqMessages certificateReqMessages = new CertificateReqMessages(
+ new CertReqMessages(m_requests.ToArray()));
+
+ m_requests.Clear();
+
+ return certificateReqMessages;
+ }
+ }
+}
diff --git a/crypto/src/crmf/CertificateRequestMessage.cs b/crypto/src/crmf/CertificateRequestMessage.cs
index d71e85e1f..8b8feb3f4 100644
--- a/crypto/src/crmf/CertificateRequestMessage.cs
+++ b/crypto/src/crmf/CertificateRequestMessage.cs
@@ -9,70 +9,61 @@ namespace Org.BouncyCastle.Crmf
{
public class CertificateRequestMessage
{
- public static readonly int popRaVerified = Org.BouncyCastle.Asn1.Crmf.ProofOfPossession.TYPE_RA_VERIFIED;
- public static readonly int popSigningKey = Org.BouncyCastle.Asn1.Crmf.ProofOfPossession.TYPE_SIGNING_KEY;
- public static readonly int popKeyEncipherment = Org.BouncyCastle.Asn1.Crmf.ProofOfPossession.TYPE_KEY_ENCIPHERMENT;
- public static readonly int popKeyAgreement = Org.BouncyCastle.Asn1.Crmf.ProofOfPossession.TYPE_KEY_AGREEMENT;
+ public static readonly int popRaVerified = Asn1.Crmf.ProofOfPossession.TYPE_RA_VERIFIED;
+ public static readonly int popSigningKey = Asn1.Crmf.ProofOfPossession.TYPE_SIGNING_KEY;
+ public static readonly int popKeyEncipherment = Asn1.Crmf.ProofOfPossession.TYPE_KEY_ENCIPHERMENT;
+ public static readonly int popKeyAgreement = Asn1.Crmf.ProofOfPossession.TYPE_KEY_AGREEMENT;
- private readonly CertReqMsg certReqMsg;
- private readonly Controls controls;
+ private readonly CertReqMsg m_certReqMsg;
+ private readonly Controls m_controls;
- private static CertReqMsg ParseBytes(byte[] encoding)
- {
- return CertReqMsg.GetInstance(encoding);
- }
+ private static CertReqMsg ParseBytes(byte[] encoding) => CertReqMsg.GetInstance(encoding);
/// <summary>
/// Create a CertificateRequestMessage from the passed in bytes.
/// </summary>
/// <param name="encoded">BER/DER encoding of the CertReqMsg structure.</param>
public CertificateRequestMessage(byte[] encoded)
- : this(CertReqMsg.GetInstance(encoded))
+ : this(ParseBytes(encoded))
{
}
public CertificateRequestMessage(CertReqMsg certReqMsg)
{
- this.certReqMsg = certReqMsg;
- this.controls = certReqMsg.CertReq.Controls;
+ m_certReqMsg = certReqMsg;
+ m_controls = certReqMsg.CertReq.Controls;
}
/// <summary>
/// Return the underlying ASN.1 object defining this CertificateRequestMessage object.
/// </summary>
/// <returns>A CertReqMsg</returns>
- public CertReqMsg ToAsn1Structure()
- {
- return certReqMsg;
- }
+ public CertReqMsg ToAsn1Structure() => m_certReqMsg;
+
+ /// <summary>
+ /// Return the certificate request ID for this message.
+ /// </summary>
+ /// <returns>the certificate request ID.</returns>
+ public DerInteger GetCertReqID() => m_certReqMsg.CertReq.CertReqID;
/// <summary>
/// Return the certificate template contained in this message.
/// </summary>
/// <returns>a CertTemplate structure.</returns>
- public CertTemplate GetCertTemplate()
- {
- return this.certReqMsg.CertReq.CertTemplate;
- }
+ public CertTemplate GetCertTemplate() => m_certReqMsg.CertReq.CertTemplate;
/// <summary>
/// Return whether or not this request has control values associated with it.
/// </summary>
/// <returns>true if there are control values present, false otherwise.</returns>
- public bool HasControls
- {
- get { return controls != null; }
- }
+ public bool HasControls => m_controls != null;
/// <summary>
/// Return whether or not this request has a specific type of control value.
/// </summary>
/// <param name="objectIdentifier">the type OID for the control value we are checking for.</param>
/// <returns>true if a control value of type is present, false otherwise.</returns>
- public bool HasControl(DerObjectIdentifier objectIdentifier)
- {
- return FindControl(objectIdentifier) != null;
- }
+ public bool HasControl(DerObjectIdentifier objectIdentifier) => FindControl(objectIdentifier) != null;
/// <summary>
/// Return a control value of the specified type.
@@ -84,32 +75,26 @@ namespace Org.BouncyCastle.Crmf
AttributeTypeAndValue found = FindControl(type);
if (found != null)
{
- if (found.Type.Equals(CrmfObjectIdentifiers.id_regCtrl_pkiArchiveOptions))
- {
+ var oid = found.Type;
+
+ if (CrmfObjectIdentifiers.id_regCtrl_pkiArchiveOptions.Equals(oid))
return new PkiArchiveControl(PkiArchiveOptions.GetInstance(found.Value));
- }
- if (found.Type.Equals(CrmfObjectIdentifiers.id_regCtrl_regToken))
- {
+ if (CrmfObjectIdentifiers.id_regCtrl_regToken.Equals(oid))
return new RegTokenControl(DerUtf8String.GetInstance(found.Value));
- }
- if (found.Type.Equals(CrmfObjectIdentifiers.id_regCtrl_authenticator))
- {
+ if (CrmfObjectIdentifiers.id_regCtrl_authenticator.Equals(oid))
return new AuthenticatorControl(DerUtf8String.GetInstance(found.Value));
- }
}
return null;
}
public AttributeTypeAndValue FindControl(DerObjectIdentifier type)
{
- if (controls == null)
- {
+ if (m_controls == null)
return null;
- }
- AttributeTypeAndValue[] tAndV = controls.ToAttributeTypeAndValueArray();
+ AttributeTypeAndValue[] tAndV = m_controls.ToAttributeTypeAndValueArray();
AttributeTypeAndValue found = null;
for (int i = 0; i < tAndV.Length; i++)
@@ -128,19 +113,13 @@ namespace Org.BouncyCastle.Crmf
/// Return whether or not this request message has a proof-of-possession field in it.
/// </summary>
/// <returns>true if proof-of-possession is present, false otherwise.</returns>
- public bool HasProofOfPossession
- {
- get { return certReqMsg.Pop != null; }
- }
+ public bool HasProofOfPossession => m_certReqMsg.Pop != null;
/// <summary>
/// Return the type of the proof-of-possession this request message provides.
/// </summary>
/// <returns>one of: popRaVerified, popSigningKey, popKeyEncipherment, popKeyAgreement</returns>
- public int ProofOfPossession
- {
- get { return certReqMsg.Pop.Type; }
- }
+ public int ProofOfPossession => m_certReqMsg.Pop.Type;
/// <summary>
/// Return whether or not the proof-of-possession (POP) is of the type popSigningKey and
@@ -151,16 +130,14 @@ namespace Org.BouncyCastle.Crmf
{
get
{
- ProofOfPossession pop = certReqMsg.Pop;
+ ProofOfPossession pop = m_certReqMsg.Pop;
- if (pop.Type == popSigningKey)
- {
- PopoSigningKey popoSign = PopoSigningKey.GetInstance(pop.Object);
+ if (pop.Type != popSigningKey)
+ return false;
- return popoSign.PoposkInput.PublicKeyMac != null;
- }
+ PopoSigningKey popoSign = PopoSigningKey.GetInstance(pop.Object);
- return false;
+ return popoSign.PoposkInput.PublicKeyMac != null;
}
}
@@ -173,19 +150,77 @@ namespace Org.BouncyCastle.Crmf
/// <exception cref="InvalidOperationException">if POP not appropriate.</exception>
public bool IsValidSigningKeyPop(IVerifierFactoryProvider verifierProvider)
{
- ProofOfPossession pop = certReqMsg.Pop;
- if (pop.Type == popSigningKey)
- {
- PopoSigningKey popoSign = PopoSigningKey.GetInstance(pop.Object);
- if (popoSign.PoposkInput != null && popoSign.PoposkInput.PublicKeyMac != null)
- throw new InvalidOperationException("verification requires password check");
+ ProofOfPossession pop = m_certReqMsg.Pop;
+ if (pop.Type != popSigningKey)
+ throw new InvalidOperationException("not Signing Key type of proof of possession");
- return VerifySignature(verifierProvider, popoSign);
- }
+ PopoSigningKey popoSign = PopoSigningKey.GetInstance(pop.Object);
+ if (popoSign.PoposkInput != null && popoSign.PoposkInput.PublicKeyMac != null)
+ throw new InvalidOperationException("verification requires password check");
- throw new InvalidOperationException("not Signing Key type of proof of possession");
+ return VerifySignature(verifierProvider, popoSign);
+ }
+
+ /// <summary>
+ /// Return whether or not a signing key proof-of-possession (POP), with an associated PKMAC, is valid.
+ /// </summary>
+ /// <param name="verifierProvider">a provider that can produce content verifiers for the signature contained in this POP.</param>
+ /// <param name="macBuilder">a suitable PKMacBuilder to create the MAC verifier.</param>
+ /// <param name="password">the password used to key the MAC calculation.</param>
+ /// <returns>true if the POP is valid, false otherwise.</returns>
+ /// <exception cref="InvalidOperationException">if there is a problem in verification or content verifier creation.</exception>
+ /// <exception cref="InvalidOperationException">if POP not appropriate.</exception>
+ public bool IsValidSigningKeyPop(IVerifierFactoryProvider verifierProvider, PKMacBuilder macBuilder,
+ char[] password)
+ {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return IsValidSigningKeyPop(verifierProvider, macBuilder, password.AsSpan());
+#else
+ ProofOfPossession pop = m_certReqMsg.Pop;
+ if (pop.Type != popSigningKey)
+ throw new InvalidOperationException("not Signing Key type of proof of possession");
+
+ PopoSigningKey popoSign = PopoSigningKey.GetInstance(pop.Object);
+ if (popoSign.PoposkInput == null || popoSign.PoposkInput.Sender != null)
+ throw new InvalidOperationException("no PKMAC present in proof of possession");
+
+ PKMacValue mac = popoSign.PoposkInput.PublicKeyMac;
+ PKMacValueVerifier macVerifier = new PKMacValueVerifier(macBuilder);
+
+ return macVerifier.IsValid(mac, password, GetCertTemplate().PublicKey)
+ && VerifySignature(verifierProvider, popoSign);
+#endif
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ /// <summary>
+ /// Return whether or not a signing key proof-of-possession (POP), with an associated PKMAC, is valid.
+ /// </summary>
+ /// <param name="verifierProvider">a provider that can produce content verifiers for the signature contained in this POP.</param>
+ /// <param name="macBuilder">a suitable PKMacBuilder to create the MAC verifier.</param>
+ /// <param name="password">the password used to key the MAC calculation.</param>
+ /// <returns>true if the POP is valid, false otherwise.</returns>
+ /// <exception cref="InvalidOperationException">if there is a problem in verification or content verifier creation.</exception>
+ /// <exception cref="InvalidOperationException">if POP not appropriate.</exception>
+ public bool IsValidSigningKeyPop(IVerifierFactoryProvider verifierProvider, PKMacBuilder macBuilder,
+ ReadOnlySpan<char> password)
+ {
+ ProofOfPossession pop = m_certReqMsg.Pop;
+ if (pop.Type != popSigningKey)
+ throw new InvalidOperationException("not Signing Key type of proof of possession");
+
+ PopoSigningKey popoSign = PopoSigningKey.GetInstance(pop.Object);
+ if (popoSign.PoposkInput == null || popoSign.PoposkInput.Sender != null)
+ throw new InvalidOperationException("no PKMAC present in proof of possession");
+
+ PKMacValue mac = popoSign.PoposkInput.PublicKeyMac;
+ PKMacValueVerifier macVerifier = new PKMacValueVerifier(macBuilder);
+
+ return macVerifier.IsValid(mac, password, GetCertTemplate().PublicKey)
+ && VerifySignature(verifierProvider, popoSign);
+ }
+#endif
+
private bool VerifySignature(IVerifierFactoryProvider verifierFactoryProvider, PopoSigningKey signKey)
{
var verifierFactory = verifierFactoryProvider.CreateVerifierFactory(signKey.AlgorithmIdentifier);
@@ -193,7 +228,7 @@ namespace Org.BouncyCastle.Crmf
Asn1Encodable asn1Encodable = signKey.PoposkInput;
if (asn1Encodable == null)
{
- asn1Encodable = certReqMsg.CertReq;
+ asn1Encodable = m_certReqMsg.CertReq;
}
return X509.X509Utilities.VerifySignature(verifierFactory, asn1Encodable, signKey.Signature);
@@ -203,9 +238,6 @@ namespace Org.BouncyCastle.Crmf
/// Return the ASN.1 encoding of the certReqMsg we wrap.
/// </summary>
/// <returns>a byte array containing the binary encoding of the certReqMsg.</returns>
- public byte[] GetEncoded()
- {
- return certReqMsg.GetEncoded();
- }
+ public byte[] GetEncoded() => m_certReqMsg.GetEncoded();
}
}
diff --git a/crypto/src/crmf/CertificateRequestMessageBuilder.cs b/crypto/src/crmf/CertificateRequestMessageBuilder.cs
index dc5bc6224..84c9b7966 100644
--- a/crypto/src/crmf/CertificateRequestMessageBuilder.cs
+++ b/crypto/src/crmf/CertificateRequestMessageBuilder.cs
@@ -11,31 +11,38 @@ namespace Org.BouncyCastle.Crmf
{
public class CertificateRequestMessageBuilder
{
- private readonly BigInteger _certReqId;
- private X509ExtensionsGenerator _extGenerator;
- private CertTemplateBuilder _templateBuilder;
- private IList<IControl> m_controls = new List<IControl>();
- private ISignatureFactory _popSigner;
- private PKMacBuilder _pkMacBuilder;
- private char[] _password;
- private GeneralName _sender;
- private int _popoType = ProofOfPossession.TYPE_KEY_ENCIPHERMENT;
- private PopoPrivKey _popoPrivKey;
- private Asn1Null _popRaVerified;
- private PKMacValue _agreeMac;
+ private readonly List<IControl> m_controls = new List<IControl>();
+ private readonly X509ExtensionsGenerator m_extGenerator = new X509ExtensionsGenerator();
+ private readonly CertTemplateBuilder m_templateBuilder = new CertTemplateBuilder();
+
+ private readonly BigInteger m_certReqID;
+
+ private ISignatureFactory m_popSigner = null;
+ private PKMacBuilder m_pkMacBuilder = null;
+ private char[] m_password = null;
+ private GeneralName m_sender = null;
+ private int m_popoType = ProofOfPossession.TYPE_KEY_ENCIPHERMENT;
+ private PopoPrivKey m_popoPrivKey = null;
+ private Asn1Null m_popRaVerified = null;
+ private PKMacValue m_agreeMac = null;
+ private AttributeTypeAndValue[] m_regInfo = null;
public CertificateRequestMessageBuilder(BigInteger certReqId)
{
- this._certReqId = certReqId;
- this._extGenerator = new X509ExtensionsGenerator();
- this._templateBuilder = new CertTemplateBuilder();
+ m_certReqID = certReqId;
+ }
+
+ public CertificateRequestMessageBuilder SetRegInfo(AttributeTypeAndValue[] regInfo)
+ {
+ m_regInfo = regInfo;
+ return this;
}
public CertificateRequestMessageBuilder SetPublicKey(SubjectPublicKeyInfo publicKeyInfo)
{
if (publicKeyInfo != null)
{
- _templateBuilder.SetPublicKey(publicKeyInfo);
+ m_templateBuilder.SetPublicKey(publicKeyInfo);
}
return this;
@@ -45,7 +52,7 @@ namespace Org.BouncyCastle.Crmf
{
if (issuer != null)
{
- _templateBuilder.SetIssuer(issuer);
+ m_templateBuilder.SetIssuer(issuer);
}
return this;
@@ -55,7 +62,7 @@ namespace Org.BouncyCastle.Crmf
{
if (subject != null)
{
- _templateBuilder.SetSubject(subject);
+ m_templateBuilder.SetSubject(subject);
}
return this;
@@ -65,7 +72,17 @@ namespace Org.BouncyCastle.Crmf
{
if (serialNumber != null)
{
- _templateBuilder.SetSerialNumber(new DerInteger(serialNumber));
+ m_templateBuilder.SetSerialNumber(new DerInteger(serialNumber));
+ }
+
+ return this;
+ }
+
+ public CertificateRequestMessageBuilder SetSerialNumber(DerInteger serialNumber)
+ {
+ if (serialNumber != null)
+ {
+ m_templateBuilder.SetSerialNumber(serialNumber);
}
return this;
@@ -73,21 +90,21 @@ namespace Org.BouncyCastle.Crmf
public CertificateRequestMessageBuilder SetValidity(DateTime? notBefore, DateTime? notAfter)
{
- _templateBuilder.SetValidity(new OptionalValidity(CreateTime(notBefore), CreateTime(notAfter)));
+ m_templateBuilder.SetValidity(new OptionalValidity(CreateTime(notBefore), CreateTime(notAfter)));
return this;
}
public CertificateRequestMessageBuilder AddExtension(DerObjectIdentifier oid, bool critical,
Asn1Encodable value)
{
- _extGenerator.AddExtension(oid, critical, value);
+ m_extGenerator.AddExtension(oid, critical, value);
return this;
}
public CertificateRequestMessageBuilder AddExtension(DerObjectIdentifier oid, bool critical,
byte[] value)
{
- _extGenerator.AddExtension(oid, critical, value);
+ m_extGenerator.AddExtension(oid, critical, value);
return this;
}
@@ -97,69 +114,53 @@ namespace Org.BouncyCastle.Crmf
return this;
}
- public CertificateRequestMessageBuilder SetProofOfPossessionSignKeySigner(ISignatureFactory popoSignatureFactory)
+ public CertificateRequestMessageBuilder SetProofOfPossessionSignKeySigner(
+ ISignatureFactory popoSignatureFactory)
{
- if (_popoPrivKey != null || _popRaVerified != null || _agreeMac != null)
- {
+ if (m_popoPrivKey != null || m_popRaVerified != null || m_agreeMac != null)
throw new InvalidOperationException("only one proof of possession is allowed.");
- }
-
- this._popSigner = popoSignatureFactory;
+ m_popSigner = popoSignatureFactory;
return this;
}
public CertificateRequestMessageBuilder SetProofOfPossessionSubsequentMessage(SubsequentMessage msg)
{
- if (_popoPrivKey != null || _popRaVerified != null || _agreeMac != null)
- {
+ if (m_popoPrivKey != null || m_popRaVerified != null || m_agreeMac != null)
throw new InvalidOperationException("only one proof of possession is allowed.");
- }
-
- this._popoType = ProofOfPossession.TYPE_KEY_ENCIPHERMENT;
- this._popoPrivKey = new PopoPrivKey(msg);
+ m_popoType = ProofOfPossession.TYPE_KEY_ENCIPHERMENT;
+ m_popoPrivKey = new PopoPrivKey(msg);
return this;
}
-
public CertificateRequestMessageBuilder SetProofOfPossessionSubsequentMessage(int type, SubsequentMessage msg)
{
- if (_popoPrivKey != null || _popRaVerified != null || _agreeMac != null)
- {
+ if (m_popoPrivKey != null || m_popRaVerified != null || m_agreeMac != null)
throw new InvalidOperationException("only one proof of possession is allowed.");
- }
-
if (type != ProofOfPossession.TYPE_KEY_ENCIPHERMENT && type != ProofOfPossession.TYPE_KEY_AGREEMENT)
- {
- throw new ArgumentException("type must be ProofOfPossession.TYPE_KEY_ENCIPHERMENT || ProofOfPossession.TYPE_KEY_AGREEMENT");
- }
+ throw new ArgumentException("type must be ProofOfPossession.TYPE_KEY_ENCIPHERMENT or ProofOfPossession.TYPE_KEY_AGREEMENT");
- this._popoType = type;
- this._popoPrivKey = new PopoPrivKey(msg);
+ m_popoType = type;
+ m_popoPrivKey = new PopoPrivKey(msg);
return this;
}
public CertificateRequestMessageBuilder SetProofOfPossessionAgreeMac(PKMacValue macValue)
{
- if (_popSigner != null || _popRaVerified != null || _popoPrivKey != null)
- {
+ if (m_popSigner != null || m_popRaVerified != null || m_popoPrivKey != null)
throw new InvalidOperationException("only one proof of possession allowed");
- }
- this._agreeMac = macValue;
+ m_agreeMac = macValue;
return this;
}
public CertificateRequestMessageBuilder SetProofOfPossessionRaVerified()
{
- if (_popSigner != null || _popoPrivKey != null)
- {
+ if (m_popSigner != null || m_popoPrivKey != null)
throw new InvalidOperationException("only one proof of possession allowed");
- }
-
- this._popRaVerified = DerNull.Instance;
+ m_popRaVerified = DerNull.Instance;
return this;
}
@@ -171,11 +172,20 @@ namespace Org.BouncyCastle.Crmf
public CertificateRequestMessageBuilder SetAuthInfoPKMacBuilder(PKMacBuilder pkmacFactory, char[] password)
{
- this._pkMacBuilder = pkmacFactory;
- this._password = password;
+ m_pkMacBuilder = pkmacFactory;
+ m_password = password;
+ return this;
+ }
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public CertificateRequestMessageBuilder SetAuthInfoPKMacBuilder(PKMacBuilder pkmacFactory,
+ ReadOnlySpan<char> password)
+ {
+ m_pkMacBuilder = pkmacFactory;
+ m_password = password.ToArray();
return this;
}
+#endif
public CertificateRequestMessageBuilder SetAuthInfoSender(X509Name sender)
{
@@ -184,20 +194,21 @@ namespace Org.BouncyCastle.Crmf
public CertificateRequestMessageBuilder SetAuthInfoSender(GeneralName sender)
{
- this._sender = sender;
+ m_sender = sender;
return this;
}
public CertificateRequestMessage Build()
{
- Asn1EncodableVector v = new Asn1EncodableVector(new DerInteger(this._certReqId));
+ Asn1EncodableVector v = new Asn1EncodableVector(3);
+ v.Add(new DerInteger(m_certReqID));
- if (!this._extGenerator.IsEmpty)
+ if (!m_extGenerator.IsEmpty)
{
- this._templateBuilder.SetExtensions(_extGenerator.Generate());
+ m_templateBuilder.SetExtensions(m_extGenerator.Generate());
}
- v.Add(_templateBuilder.Build());
+ v.Add(m_templateBuilder.Build());
if (m_controls.Count > 0)
{
@@ -213,52 +224,54 @@ namespace Org.BouncyCastle.Crmf
CertRequest request = CertRequest.GetInstance(new DerSequence(v));
- v = new Asn1EncodableVector(request);
-
- if (_popSigner != null)
+ ProofOfPossession proofOfPossession;
+ if (m_popSigner != null)
{
CertTemplate template = request.CertTemplate;
+ ProofOfPossessionSigningKeyBuilder builder;
if (template.Subject == null || template.PublicKey == null)
{
SubjectPublicKeyInfo pubKeyInfo = request.CertTemplate.PublicKey;
- ProofOfPossessionSigningKeyBuilder builder = new ProofOfPossessionSigningKeyBuilder(pubKeyInfo);
+ builder = new ProofOfPossessionSigningKeyBuilder(pubKeyInfo);
- if (_sender != null)
+ if (m_sender != null)
{
- builder.SetSender(_sender);
+ builder.SetSender(m_sender);
}
else
{
- //PKMACValueGenerator pkmacGenerator = new PKMACValueGenerator(_pkmacBuilder);
-
- builder.SetPublicKeyMac(_pkMacBuilder, _password);
+ builder.SetPublicKeyMac(m_pkMacBuilder, m_password);
}
-
- v.Add(new ProofOfPossession(builder.Build(_popSigner)));
}
else
{
- ProofOfPossessionSigningKeyBuilder builder = new ProofOfPossessionSigningKeyBuilder(request);
-
- v.Add(new ProofOfPossession(builder.Build(_popSigner)));
+ builder = new ProofOfPossessionSigningKeyBuilder(request);
}
+
+ proofOfPossession = new ProofOfPossession(builder.Build(m_popSigner));
}
- else if (_popoPrivKey != null)
+ else if (m_popoPrivKey != null)
{
- v.Add(new ProofOfPossession(_popoType, _popoPrivKey));
+ proofOfPossession = new ProofOfPossession(m_popoType, m_popoPrivKey);
}
- else if (_agreeMac != null)
+ else if (m_agreeMac != null)
{
- v.Add(new ProofOfPossession(ProofOfPossession.TYPE_KEY_AGREEMENT, new PopoPrivKey(_agreeMac)));
+ proofOfPossession = new ProofOfPossession(ProofOfPossession.TYPE_KEY_AGREEMENT, new PopoPrivKey(m_agreeMac));
}
- else if (_popRaVerified != null)
+ else if (m_popRaVerified != null)
{
- v.Add(new ProofOfPossession());
+ proofOfPossession = new ProofOfPossession();
}
+ else
+ {
+ proofOfPossession = new ProofOfPossession();
+ }
+
+ CertReqMsg certReqMsg = new CertReqMsg(request, proofOfPossession, m_regInfo);
- return new CertificateRequestMessage(CertReqMsg.GetInstance(new DerSequence(v)));
+ return new CertificateRequestMessage(certReqMsg);
}
private static Time CreateTime(DateTime? dateTime)
diff --git a/crypto/src/crmf/CertificateResponse.cs b/crypto/src/crmf/CertificateResponse.cs
new file mode 100644
index 000000000..3a3f0d7c6
--- /dev/null
+++ b/crypto/src/crmf/CertificateResponse.cs
@@ -0,0 +1,94 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Cms;
+
+namespace Org.BouncyCastle.Crmf
+{
+ /// <summary>High level wrapper for the CertResponse CRMF structure.</summary>
+ public class CertificateResponse
+ {
+ private readonly CertResponse m_certResponse;
+
+ public CertificateResponse(CertResponse certResponse)
+ {
+ m_certResponse = certResponse;
+ }
+
+ /**
+ * Return true if the response contains an encrypted certificate.
+ *
+ * @return true if certificate in response encrypted, false otherwise.
+ */
+ public virtual bool HasEncryptedCertificate =>
+ m_certResponse.CertifiedKeyPair.CertOrEncCert.HasEncryptedCertificate;
+
+ /**
+ * Return a CMSEnvelopedData representing the encrypted certificate contained in the response.
+ *
+ * @return a CMEEnvelopedData if an encrypted certificate is present.
+ * @throws IllegalStateException if no encrypted certificate is present, or there is an issue with the enveloped data.
+ */
+ public virtual CmsEnvelopedData GetEncryptedCertificate()
+ {
+ if (!HasEncryptedCertificate)
+ throw new InvalidOperationException("encrypted certificate asked for, none found");
+
+ CertifiedKeyPair receivedKeyPair = m_certResponse.CertifiedKeyPair;
+
+ var contentInfo = new Asn1.Cms.ContentInfo(PkcsObjectIdentifiers.EnvelopedData,
+ receivedKeyPair.CertOrEncCert.EncryptedCert.Value);
+
+ CmsEnvelopedData envelopedData = new CmsEnvelopedData(contentInfo);
+
+ if (envelopedData.GetRecipientInfos().Count != 1)
+ throw new InvalidOperationException("data encrypted for more than one recipient");
+
+ return envelopedData;
+ }
+
+ // TODO[crmf]
+#if false
+ /**
+ * Return the CMPCertificate representing the plaintext certificate in the response.
+ *
+ * @return a CMPCertificate if a plaintext certificate is present.
+ * @throws IllegalStateException if no plaintext certificate is present.
+ */
+ public virtual CmpCertificate GetCertificate(Recipient recipient)
+ {
+ CmsEnvelopedData encryptedCert = GetEncryptedCertificate();
+
+ RecipientInformationStore recipients = encryptedCert.GetRecipientInfos();
+
+ var c = recipients.GetRecipients();
+
+ RecipientInformation recInfo = c[0];
+
+ return CmpCertificate.GetInstance(recInfo.GetContent(recipient));
+ }
+#endif
+
+ /**
+ * Return the CMPCertificate representing the plaintext certificate in the response.
+ *
+ * @return a CMPCertificate if a plaintext certificate is present.
+ * @throws IllegalStateException if no plaintext certificate is present.
+ */
+ public virtual CmpCertificate GetCertificate()
+ {
+ if (HasEncryptedCertificate)
+ throw new InvalidOperationException("plaintext certificate asked for, none found");
+
+ return m_certResponse.CertifiedKeyPair.CertOrEncCert.Certificate;
+ }
+
+ /**
+ * Return this object's underlying ASN.1 structure.
+ *
+ * @return a CertResponse
+ */
+ public virtual CertResponse ToAsn1Structure() => m_certResponse;
+ }
+}
diff --git a/crypto/src/crmf/CertificateResponseBuilder.cs b/crypto/src/crmf/CertificateResponseBuilder.cs
new file mode 100644
index 000000000..d1e85ea23
--- /dev/null
+++ b/crypto/src/crmf/CertificateResponseBuilder.cs
@@ -0,0 +1,104 @@
+using System;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.Cms;
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Cms;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Crmf
+{
+ /// <summary>Builder for CertificateResponse objects (the CertResponse CRMF equivalent).</summary>
+ public class CertificateResponseBuilder
+ {
+ private readonly DerInteger m_certReqID;
+ private readonly PkiStatusInfo m_statusInfo;
+
+ private CertifiedKeyPair m_certKeyPair;
+ private Asn1OctetString m_rspInfo;
+
+ /**
+ * Base constructor.
+ *
+ * @param certReqId the request ID for the response.
+ * @param statusInfo the status info to associate with the response.
+ */
+ public CertificateResponseBuilder(DerInteger certReqID, PkiStatusInfo statusInfo)
+ {
+ m_certReqID = certReqID;
+ m_statusInfo = statusInfo;
+ }
+
+ /**
+ * Specify the certificate to assign to this response (in plaintext).
+ *
+ * @param certificate the X.509 PK certificate to include.
+ * @return the current builder.
+ */
+ public virtual CertificateResponseBuilder WithCertificate(X509Certificate certificate)
+ {
+ if (m_certKeyPair != null)
+ throw new InvalidOperationException("certificate in response already set");
+
+ var cmpCertificate = new CmpCertificate(certificate.CertificateStructure);
+
+ m_certKeyPair = new CertifiedKeyPair(new CertOrEncCert(cmpCertificate));
+
+ return this;
+ }
+
+ /**
+ * Specify the certificate to assign to this response (in plaintext).
+ *
+ * @param cmpCertificate the X.509 PK certificate to include.
+ * @return the current builder.
+ */
+ public virtual CertificateResponseBuilder WithCertificate(CmpCertificate cmpCertificate)
+ {
+ if (m_certKeyPair != null)
+ throw new InvalidOperationException("certificate in response already set");
+
+ m_certKeyPair = new CertifiedKeyPair(new CertOrEncCert(cmpCertificate));
+
+ return this;
+ }
+
+ /**
+ * Specify the encrypted certificate to assign to this response (in plaintext).
+ *
+ * @param encryptedCertificate an encrypted
+ * @return the current builder.
+ */
+ public virtual CertificateResponseBuilder WithCertificate(CmsEnvelopedData encryptedCertificate)
+ {
+ if (m_certKeyPair != null)
+ throw new InvalidOperationException("certificate in response already set");
+
+ var encryptedKey = new EncryptedKey(EnvelopedData.GetInstance(encryptedCertificate.ContentInfo.Content));
+
+ m_certKeyPair = new CertifiedKeyPair(new CertOrEncCert(encryptedKey));
+
+ return this;
+ }
+
+ /**
+ * Specify the response info field on the response.
+ *
+ * @param responseInfo a response info string.
+ * @return the current builder.
+ */
+ public virtual CertificateResponseBuilder WithResponseInfo(byte[] responseInfo)
+ {
+ if (m_rspInfo != null)
+ throw new InvalidOperationException("response info already set");
+
+ m_rspInfo = new DerOctetString(responseInfo);
+
+ return this;
+ }
+
+ public virtual CertificateResponse Build() =>
+ new CertificateResponse(new CertResponse(m_certReqID, m_statusInfo, m_certKeyPair, m_rspInfo));
+ }
+}
diff --git a/crypto/src/crmf/EncryptedValueBuilder.cs b/crypto/src/crmf/EncryptedValueBuilder.cs
index 3dca9e72c..a056aadf6 100644
--- a/crypto/src/crmf/EncryptedValueBuilder.cs
+++ b/crypto/src/crmf/EncryptedValueBuilder.cs
@@ -146,14 +146,6 @@ namespace Org.BouncyCastle.Crmf
return new EncryptedValue(intendedAlg, symmAlg, encSymmKey, keyAlg, valueHint, encValue);
}
- private byte[] PadData(byte[] data)
- {
- if (padder != null)
- {
- return padder.GetPaddedData(data);
- }
-
- return data;
- }
+ private byte[] PadData(byte[] data) => padder?.GetPaddedData(data) ?? data;
}
}
diff --git a/crypto/src/crmf/EncryptedValueParser.cs b/crypto/src/crmf/EncryptedValueParser.cs
new file mode 100644
index 000000000..6be4cbadf
--- /dev/null
+++ b/crypto/src/crmf/EncryptedValueParser.cs
@@ -0,0 +1,97 @@
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Crmf
+{
+ /// <summary>Parser for EncryptedValue structures.</summary>
+ public class EncryptedValueParser
+ {
+ private readonly EncryptedValue m_value;
+ private readonly IEncryptedValuePadder m_padder;
+
+ /**
+ * Basic constructor - create a parser to read the passed in value.
+ *
+ * @param value the value to be parsed.
+ */
+ public EncryptedValueParser(EncryptedValue value)
+ : this(value, null)
+ {
+ }
+
+ /**
+ * Create a parser to read the passed in value, assuming the padder was
+ * applied to the data prior to encryption.
+ *
+ * @param value the value to be parsed.
+ * @param padder the padder to be used to remove padding from the decrypted value..
+ */
+ public EncryptedValueParser(EncryptedValue value, IEncryptedValuePadder padder)
+ {
+ m_value = value;
+ m_padder = padder;
+ }
+
+ public virtual AlgorithmIdentifier IntendedAlg => m_value.IntendedAlg;
+
+ // TODO[crmf]
+#if false
+ private virtual byte[] DecryptValue(ValueDecryptorGenerator decGen)
+ {
+ if (m_value.ValueHint != null)
+ throw new NotSupportedException();
+
+ InputDecryptor decryptor = decGen.getValueDecryptor(value.getKeyAlg(),
+ value.getSymmAlg(), value.getEncSymmKey().getBytes());
+ InputStream dataIn = decryptor.getInputStream(new ByteArrayInputStream(
+ value.getEncValue().getBytes()));
+ try
+ {
+ return UnpadData(Streams.readAll(dataIn));
+ }
+ catch (IOException e)
+ {
+ throw new CRMFException("Cannot parse decrypted data: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Read a X.509 certificate.
+ *
+ * @param decGen the decryptor generator to decrypt the encrypted value.
+ * @return an X509CertificateHolder containing the certificate read.
+ * @throws CRMFException if the decrypted data cannot be parsed, or a decryptor cannot be generated.
+ */
+ public virtual X509Certificate ReadCertificate(ValueDecryptorGenerator decGen)
+ {
+ return new X509Certificate(X509CertificateStructure.GetInstance(DecryptValue(decGen)));
+ }
+
+ /**
+ * Read a PKCS#8 PrivateKeyInfo.
+ *
+ * @param decGen the decryptor generator to decrypt the encrypted value.
+ * @return an PrivateKeyInfo containing the private key that was read.
+ * @throws CRMFException if the decrypted data cannot be parsed, or a decryptor cannot be generated.
+ */
+ public virtual PrivateKeyInfo ReadPrivateKeyInfo(ValueDecryptorGenerator decGen)
+ {
+ return PrivateKeyInfo.GetInstance(DecryptValue(decGen));
+ }
+
+ /**
+ * Read a pass phrase.
+ *
+ * @param decGen the decryptor generator to decrypt the encrypted value.
+ * @return a pass phrase as recovered from the encrypted value.
+ * @throws CRMFException if the decrypted data cannot be parsed, or a decryptor cannot be generated.
+ */
+ public virtual char[] ReadPassphrase(ValueDecryptorGenerator decGen)
+ {
+ return Strings.FromUtf8ByteArray(DecryptValue(decGen)).ToCharArray();
+ }
+#endif
+
+ private byte[] UnpadData(byte[] data) => m_padder?.GetUnpaddedData(data) ?? data;
+ }
+}
diff --git a/crypto/src/crmf/PKMacBuilder.cs b/crypto/src/crmf/PKMacBuilder.cs
index f59ba8f35..ac9e7ca18 100644
--- a/crypto/src/crmf/PKMacBuilder.cs
+++ b/crypto/src/crmf/PKMacBuilder.cs
@@ -52,8 +52,10 @@ namespace Org.BouncyCastle.Crmf
/// <summary>
/// Default, IterationCount = 1000, OIW=IdSha1, Mac=HmacSHA1
/// </summary>
- public PKMacBuilder() :
- this(new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1), 1000, new AlgorithmIdentifier(IanaObjectIdentifiers.HmacSha1, DerNull.Instance), new DefaultPKMacPrimitivesProvider())
+ public PKMacBuilder()
+ : this(new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1), 1000,
+ new AlgorithmIdentifier(IanaObjectIdentifiers.HmacSha1, DerNull.Instance),
+ new DefaultPKMacPrimitivesProvider())
{
}
@@ -61,8 +63,9 @@ namespace Org.BouncyCastle.Crmf
/// Defaults with IPKMacPrimitivesProvider
/// </summary>
/// <param name="provider"></param>
- public PKMacBuilder(IPKMacPrimitivesProvider provider) :
- this(new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1), 1000, new AlgorithmIdentifier(IanaObjectIdentifiers.HmacSha1, DerNull.Instance), provider)
+ public PKMacBuilder(IPKMacPrimitivesProvider provider)
+ : this(new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1), 1000,
+ new AlgorithmIdentifier(IanaObjectIdentifiers.HmacSha1, DerNull.Instance), provider)
{
}
@@ -72,8 +75,9 @@ namespace Org.BouncyCastle.Crmf
/// <param name="provider">The Mac provider</param>
/// <param name="digestAlgorithmIdentifier">Digest Algorithm Id</param>
/// <param name="macAlgorithmIdentifier">Mac Algorithm Id</param>
- public PKMacBuilder(IPKMacPrimitivesProvider provider, AlgorithmIdentifier digestAlgorithmIdentifier, AlgorithmIdentifier macAlgorithmIdentifier) :
- this(digestAlgorithmIdentifier, 1000, macAlgorithmIdentifier, provider)
+ public PKMacBuilder(IPKMacPrimitivesProvider provider, AlgorithmIdentifier digestAlgorithmIdentifier,
+ AlgorithmIdentifier macAlgorithmIdentifier)
+ : this(digestAlgorithmIdentifier, 1000, macAlgorithmIdentifier, provider)
{
}
@@ -88,7 +92,8 @@ namespace Org.BouncyCastle.Crmf
this.maxIterations = maxIterations;
}
- private PKMacBuilder(AlgorithmIdentifier digestAlgorithmIdentifier, int iterationCount, AlgorithmIdentifier macAlgorithmIdentifier, IPKMacPrimitivesProvider provider)
+ private PKMacBuilder(AlgorithmIdentifier digestAlgorithmIdentifier, int iterationCount,
+ AlgorithmIdentifier macAlgorithmIdentifier, IPKMacPrimitivesProvider provider)
{
this.iterationCount = iterationCount;
this.mac = macAlgorithmIdentifier;
@@ -131,6 +136,18 @@ namespace Org.BouncyCastle.Crmf
}
/// <summary>
+ /// The Secure random
+ /// </summary>
+ /// <param name="random">The random.</param>
+ /// <returns>this</returns>
+ public PKMacBuilder SetSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ /// <summary>
/// Set PbmParameters
/// </summary>
/// <param name="parameters">The parameters.</param>
@@ -144,18 +161,32 @@ namespace Org.BouncyCastle.Crmf
return this;
}
- /// <summary>
- /// The Secure random
- /// </summary>
- /// <param name="random">The random.</param>
- /// <returns>this</returns>
- public PKMacBuilder SetSecureRandom(SecureRandom random)
+ public IMacFactory Get(AlgorithmIdentifier algorithm, char[] password)
{
- this.random = random;
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ return Get(algorithm, password.AsSpan());
+#else
+ if (!CmpObjectIdentifiers.passwordBasedMac.Equals(algorithm.Algorithm))
+ throw new ArgumentException("protection algorithm not mac based", nameof(algorithm));
- return this;
+ SetParameters(PbmParameter.GetInstance(algorithm.Parameters));
+
+ return Build(password);
+#endif
}
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ public IMacFactory Get(AlgorithmIdentifier algorithm, ReadOnlySpan<char> password)
+ {
+ if (!CmpObjectIdentifiers.passwordBasedMac.Equals(algorithm.Algorithm))
+ throw new ArgumentException("protection algorithm not mac based", nameof(algorithm));
+
+ SetParameters(PbmParameter.GetInstance(algorithm.Parameters));
+
+ return Build(password);
+ }
+#endif
+
/// <summary>
/// Build an IMacFactory.
/// </summary>
diff --git a/crypto/src/crmf/PKMacValueGenerator.cs b/crypto/src/crmf/PKMacValueGenerator.cs
new file mode 100644
index 000000000..0809de348
--- /dev/null
+++ b/crypto/src/crmf/PKMacValueGenerator.cs
@@ -0,0 +1,28 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Crmf
+{
+ internal static class PKMacValueGenerator
+ {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal static PKMacValue Generate(PKMacBuilder builder, ReadOnlySpan<char> password,
+ SubjectPublicKeyInfo keyInfo)
+ {
+ var macFactory = builder.Build(password);
+ var macValue = X509Utilities.GenerateMac(macFactory, keyInfo);
+ return new PKMacValue((AlgorithmIdentifier)macFactory.AlgorithmDetails, macValue);
+ }
+#else
+ internal static PKMacValue Generate(PKMacBuilder builder, char[] password, SubjectPublicKeyInfo keyInfo)
+ {
+ var macFactory = builder.Build(password);
+ var macValue = X509Utilities.GenerateMac(macFactory, keyInfo);
+ return new PKMacValue((AlgorithmIdentifier)macFactory.AlgorithmDetails, macValue);
+ }
+#endif
+ }
+}
diff --git a/crypto/src/crmf/PKMacValueVerifier.cs b/crypto/src/crmf/PKMacValueVerifier.cs
new file mode 100644
index 000000000..0f84e64e1
--- /dev/null
+++ b/crypto/src/crmf/PKMacValueVerifier.cs
@@ -0,0 +1,39 @@
+using System;
+
+using Org.BouncyCastle.Asn1.Cmp;
+using Org.BouncyCastle.Asn1.Crmf;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.X509;
+
+namespace Org.BouncyCastle.Crmf
+{
+ internal class PKMacValueVerifier
+ {
+ private readonly PKMacBuilder m_builder;
+
+ internal PKMacValueVerifier(PKMacBuilder builder)
+ {
+ m_builder = builder;
+ }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+ internal virtual bool IsValid(PKMacValue value, ReadOnlySpan<char> password, SubjectPublicKeyInfo keyInfo)
+ {
+ m_builder.SetParameters(PbmParameter.GetInstance(value.AlgID.Parameters));
+
+ var macFactory = m_builder.Build(password);
+
+ return X509Utilities.VerifyMac(macFactory, keyInfo, value.MacValue);
+ }
+#else
+ internal virtual bool IsValid(PKMacValue value, char[] password, SubjectPublicKeyInfo keyInfo)
+ {
+ m_builder.SetParameters(PbmParameter.GetInstance(value.AlgID.Parameters));
+
+ var macFactory = m_builder.Build(password);
+
+ return X509Utilities.VerifyMac(macFactory, keyInfo, value.MacValue);
+ }
+#endif
+ }
+}
diff --git a/crypto/src/crmf/PkiArchiveControl.cs b/crypto/src/crmf/PkiArchiveControl.cs
index 251b8db96..122c043cb 100644
--- a/crypto/src/crmf/PkiArchiveControl.cs
+++ b/crypto/src/crmf/PkiArchiveControl.cs
@@ -14,9 +14,7 @@ namespace Org.BouncyCastle.Crmf
public static readonly int keyGenParameters = PkiArchiveOptions.keyGenParameters;
public static readonly int archiveRemGenPrivKey = PkiArchiveOptions.archiveRemGenPrivKey;
- private static readonly DerObjectIdentifier type = CrmfObjectIdentifiers.id_regCtrl_pkiArchiveOptions;
-
- private readonly PkiArchiveOptions pkiArchiveOptions;
+ private readonly PkiArchiveOptions m_pkiArchiveOptions;
/// <summary>
/// Basic constructor - build from an PKIArchiveOptions structure.
@@ -24,48 +22,42 @@ namespace Org.BouncyCastle.Crmf
/// <param name="pkiArchiveOptions">the ASN.1 structure that will underlie this control.</param>
public PkiArchiveControl(PkiArchiveOptions pkiArchiveOptions)
{
- this.pkiArchiveOptions = pkiArchiveOptions;
+ m_pkiArchiveOptions = pkiArchiveOptions;
}
/// <summary>
/// Return the type of this control.
/// </summary>
/// <returns>CRMFObjectIdentifiers.id_regCtrl_pkiArchiveOptions</returns>
- public DerObjectIdentifier Type
- {
-
- get { return type; }
- }
+ public DerObjectIdentifier Type => CrmfObjectIdentifiers.id_regCtrl_pkiArchiveOptions;
/// <summary>
/// Return the underlying ASN.1 object.
/// </summary>
/// <returns>a PKIArchiveOptions structure.</returns>
- public Asn1Encodable Value
- {
- get { return pkiArchiveOptions; }
- }
+ public Asn1Encodable Value => m_pkiArchiveOptions;
/// <summary>
/// Return the archive control type, one of: encryptedPrivKey,keyGenParameters,or archiveRemGenPrivKey.
/// </summary>
/// <returns>the archive control type.</returns>
- public int ArchiveType
- {
- get { return pkiArchiveOptions.Type; }
- }
+ public int ArchiveType => m_pkiArchiveOptions.Type;
/// <summary>
/// Return whether this control contains enveloped data.
/// </summary>
/// <returns>true if the control contains enveloped data, false otherwise.</returns>
- public bool EnvelopedData
+ [Obsolete("Use 'IsEnvelopedData' instead")]
+ public bool EnvelopedData => IsEnvelopedData();
+
+ /// <summary>
+ /// Return whether this control contains enveloped data.
+ /// </summary>
+ /// <returns>true if the control contains enveloped data, false otherwise.</returns>
+ public bool IsEnvelopedData()
{
- get
- {
- EncryptedKey encKey = EncryptedKey.GetInstance(pkiArchiveOptions.Value);
- return !encKey.IsEncryptedValue;
- }
+ EncryptedKey encKey = EncryptedKey.GetInstance(m_pkiArchiveOptions.Value);
+ return !encKey.IsEncryptedValue;
}
/// <summary>
@@ -76,8 +68,8 @@ namespace Org.BouncyCastle.Crmf
{
try
{
- EncryptedKey encKey = EncryptedKey.GetInstance(pkiArchiveOptions.Value);
- EnvelopedData data = Org.BouncyCastle.Asn1.Cms.EnvelopedData.GetInstance(encKey.Value);
+ EncryptedKey encKey = EncryptedKey.GetInstance(m_pkiArchiveOptions.Value);
+ EnvelopedData data = Asn1.Cms.EnvelopedData.GetInstance(encKey.Value);
return new CmsEnvelopedData(new ContentInfo(CmsObjectIdentifiers.EnvelopedData, data));
}
diff --git a/crypto/src/crmf/PkiArchiveControlBuilder.cs b/crypto/src/crmf/PkiArchiveControlBuilder.cs
index d79f3b5ed..8cfa4ef19 100644
--- a/crypto/src/crmf/PkiArchiveControlBuilder.cs
+++ b/crypto/src/crmf/PkiArchiveControlBuilder.cs
@@ -12,8 +12,8 @@ namespace Org.BouncyCastle.Crmf
{
public class PkiArchiveControlBuilder
{
- private CmsEnvelopedDataGenerator envGen;
- private CmsProcessableByteArray keyContent;
+ private readonly CmsEnvelopedDataGenerator m_envGen;
+ private readonly CmsProcessableByteArray m_keyContent;
/// <summary>
///Basic constructor - specify the contents of the PKIArchiveControl structure.
@@ -27,14 +27,14 @@ namespace Org.BouncyCastle.Crmf
try
{
- this.keyContent = new CmsProcessableByteArray(CrmfObjectIdentifiers.id_ct_encKeyWithID, encKeyWithID.GetEncoded());
+ m_keyContent = new CmsProcessableByteArray(CrmfObjectIdentifiers.id_ct_encKeyWithID, encKeyWithID.GetEncoded());
}
catch (IOException e)
{
throw new InvalidOperationException("unable to encode key and general name info", e);
}
- this.envGen = new CmsEnvelopedDataGenerator();
+ m_envGen = new CmsEnvelopedDataGenerator();
}
///<summary>Add a recipient generator to this control.</summary>
@@ -42,7 +42,7 @@ namespace Org.BouncyCastle.Crmf
///<returns>this builder object.</returns>
public PkiArchiveControlBuilder AddRecipientGenerator(RecipientInfoGenerator recipientGen)
{
- envGen.AddRecipientInfoGenerator(recipientGen);
+ m_envGen.AddRecipientInfoGenerator(recipientGen);
return this;
}
@@ -51,9 +51,26 @@ namespace Org.BouncyCastle.Crmf
/// <returns>a PKIArchiveControl object.</returns>
public PkiArchiveControl Build(ICipherBuilderWithKey contentEncryptor)
{
- CmsEnvelopedData envContent = envGen.Generate(keyContent, contentEncryptor);
+ CmsEnvelopedData envContent = m_envGen.Generate(m_keyContent, contentEncryptor);
EnvelopedData envD = EnvelopedData.GetInstance(envContent.ContentInfo.Content);
return new PkiArchiveControl(new PkiArchiveOptions(new EncryptedKey(envD)));
}
+
+ // TODO[crmf]
+#if false
+ /**
+ * Build the PKIArchiveControl using the passed in encryptor to encrypt its contents.
+ *
+ * @param contentEncryptor a suitable content encryptor.
+ * @return a PKIArchiveControl object.
+ * @throws CMSException in the event the build fails.
+ */
+ public PkiArchiveControl Build(OutputEncryptor contentEncryptor)
+ {
+ CmsEnvelopedData envContent = m_envGen.Generate(m_keyContent, contentEncryptor);
+ EnvelopedData envD = EnvelopedData.GetInstance(envContent.ContentInfo.Content);
+ return new PkiArchiveControl(new PkiArchiveOptions(new EncryptedKey(envD)));
+ }
+#endif
}
}
diff --git a/crypto/src/crmf/ProofOfPossessionSigningKeyBuilder.cs b/crypto/src/crmf/ProofOfPossessionSigningKeyBuilder.cs
index 02af74924..bace00334 100644
--- a/crypto/src/crmf/ProofOfPossessionSigningKeyBuilder.cs
+++ b/crypto/src/crmf/ProofOfPossessionSigningKeyBuilder.cs
@@ -1,6 +1,4 @@
using System;
-using System.IO;
-using System.Net.Security;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Crmf;
@@ -11,64 +9,65 @@ namespace Org.BouncyCastle.Crmf
{
public class ProofOfPossessionSigningKeyBuilder
{
- private CertRequest _certRequest;
- private SubjectPublicKeyInfo _pubKeyInfo;
- private GeneralName _name;
- private PKMacValue _publicKeyMAC;
+ private readonly CertRequest m_certRequest;
+ private readonly SubjectPublicKeyInfo m_pubKeyInfo;
+
+ private GeneralName m_name = null;
+ private PKMacValue m_publicKeyMac = null;
public ProofOfPossessionSigningKeyBuilder(CertRequest certRequest)
{
- this._certRequest = certRequest;
+ m_certRequest = certRequest;
+ m_pubKeyInfo = null;
}
public ProofOfPossessionSigningKeyBuilder(SubjectPublicKeyInfo pubKeyInfo)
{
- this._pubKeyInfo = pubKeyInfo;
+ m_certRequest = null;
+ m_pubKeyInfo = pubKeyInfo;
}
public ProofOfPossessionSigningKeyBuilder SetSender(GeneralName name)
{
- this._name = name;
+ m_name = name;
return this;
}
public ProofOfPossessionSigningKeyBuilder SetPublicKeyMac(PKMacBuilder generator, char[] password)
{
- IMacFactory fact = generator.Build(password);
-
- return ImplSetPublicKeyMac(fact);
+ m_publicKeyMac = PKMacValueGenerator.Generate(generator, password, m_pubKeyInfo);
+ return this;
}
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
public ProofOfPossessionSigningKeyBuilder SetPublicKeyMac(PKMacBuilder generator, ReadOnlySpan<char> password)
{
- IMacFactory fact = generator.Build(password);
-
- return ImplSetPublicKeyMac(fact);
+ m_publicKeyMac = PKMacValueGenerator.Generate(generator, password, m_pubKeyInfo);
+ return this;
}
#endif
public PopoSigningKey Build(ISignatureFactory signer)
{
- if (_name != null && _publicKeyMAC != null)
+ if (m_name != null && m_publicKeyMac != null)
throw new InvalidOperationException("name and publicKeyMAC cannot both be set.");
PopoSigningKeyInput popo;
Asn1Encodable asn1Encodable;
- if (_certRequest != null)
+ if (m_certRequest != null)
{
popo = null;
- asn1Encodable = _certRequest;
+ asn1Encodable = m_certRequest;
}
- else if (_name != null)
+ else if (m_name != null)
{
- popo = new PopoSigningKeyInput(_name, _pubKeyInfo);
+ popo = new PopoSigningKeyInput(m_name, m_pubKeyInfo);
asn1Encodable = popo;
}
else
{
- popo = new PopoSigningKeyInput(_publicKeyMAC, _pubKeyInfo);
+ popo = new PopoSigningKeyInput(m_publicKeyMac, m_pubKeyInfo);
asn1Encodable = popo;
}
@@ -76,12 +75,5 @@ namespace Org.BouncyCastle.Crmf
return new PopoSigningKey(popo, (AlgorithmIdentifier)signer.AlgorithmDetails, signature);
}
-
- private ProofOfPossessionSigningKeyBuilder ImplSetPublicKeyMac(IMacFactory macFactory)
- {
- var macValue = X509.X509Utilities.GenerateMac(macFactory, _pubKeyInfo);
- this._publicKeyMAC = new PKMacValue((AlgorithmIdentifier)macFactory.AlgorithmDetails, macValue);
- return this;
- }
}
}
diff --git a/crypto/src/crmf/RegTokenControl.cs b/crypto/src/crmf/RegTokenControl.cs
index 43484097c..a890c289c 100644
--- a/crypto/src/crmf/RegTokenControl.cs
+++ b/crypto/src/crmf/RegTokenControl.cs
@@ -1,6 +1,4 @@
-using System;
-
-using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Crmf;
namespace Org.BouncyCastle.Crmf
@@ -8,9 +6,7 @@ namespace Org.BouncyCastle.Crmf
public class RegTokenControl
: IControl
{
- private static readonly DerObjectIdentifier type = CrmfObjectIdentifiers.id_regCtrl_regToken;
-
- private readonly DerUtf8String token;
+ private readonly DerUtf8String m_token;
/// <summary>
/// Basic constructor - build from a UTF-8 string representing the token.
@@ -18,7 +14,7 @@ namespace Org.BouncyCastle.Crmf
/// <param name="token">UTF-8 string representing the token.</param>
public RegTokenControl(DerUtf8String token)
{
- this.token = token;
+ m_token = token;
}
/// <summary>
@@ -27,25 +23,19 @@ namespace Org.BouncyCastle.Crmf
/// <param name="token">string representing the token.</param>
public RegTokenControl(string token)
{
- this.token = new DerUtf8String(token);
+ m_token = new DerUtf8String(token);
}
/// <summary>
/// Return the type of this control.
/// </summary>
/// <returns>CRMFObjectIdentifiers.id_regCtrl_regToken</returns>
- public DerObjectIdentifier Type
- {
- get { return type; }
- }
+ public DerObjectIdentifier Type => CrmfObjectIdentifiers.id_regCtrl_regToken;
/// <summary>
/// Return the token associated with this control (a UTF8String).
/// </summary>
/// <returns>a UTF8String.</returns>
- public Asn1Encodable Value
- {
- get { return token; }
- }
+ public Asn1Encodable Value => m_token;
}
}
|