diff options
author | Megan Woods <megan@flygfisk.com> | 2019-01-14 17:07:22 +1100 |
---|---|---|
committer | Megan Woods <megan@flygfisk.com> | 2019-01-14 17:07:22 +1100 |
commit | ecc8edb622f0f42d43f72ae388fa4c4274e51c5f (patch) | |
tree | 9091e5bf1fe54dde31ee786956139b0fb54b0ba3 /crypto/src/asn1 | |
parent | minor tweaks (diff) | |
download | BouncyCastle.NET-ed25519-ecc8edb622f0f42d43f72ae388fa4c4274e51c5f.tar.xz |
Initial CMP
Diffstat (limited to 'crypto/src/asn1')
-rw-r--r-- | crypto/src/asn1/cmp/CertificateConfirmationContent.cs | 44 | ||||
-rw-r--r-- | crypto/src/asn1/cmp/CertificateConfirmationContentBuilder.cs | 71 | ||||
-rw-r--r-- | crypto/src/asn1/cmp/CertificateStatus.cs | 54 | ||||
-rw-r--r-- | crypto/src/asn1/cmp/CmpException.cs | 26 | ||||
-rw-r--r-- | crypto/src/asn1/cmp/GeneralPKIMessage.cs | 49 | ||||
-rw-r--r-- | crypto/src/asn1/cmp/ProtectedPkiMessage.cs | 107 | ||||
-rw-r--r-- | crypto/src/asn1/cmp/ProtectedPkiMessageBuilder.cs | 174 | ||||
-rw-r--r-- | crypto/src/asn1/crmf/AuthenticatorControl.cs | 33 | ||||
-rw-r--r-- | crypto/src/asn1/crmf/CertificateRequestMessage.cs | 182 | ||||
-rw-r--r-- | crypto/src/asn1/crmf/CertificateRequestMessageBuilder.cs | 261 | ||||
-rw-r--r-- | crypto/src/asn1/crmf/Controls.cs | 9 | ||||
-rw-r--r-- | crypto/src/asn1/crmf/CrmfException.cs | 26 | ||||
-rw-r--r-- | crypto/src/asn1/crmf/EncryptedValueBuilder.cs | 53 | ||||
-rw-r--r-- | crypto/src/asn1/crmf/OptionalValidity.cs | 6 | ||||
-rw-r--r-- | crypto/src/asn1/crmf/PkiArchiveControl.cs | 68 | ||||
-rw-r--r-- | crypto/src/asn1/crmf/ProofOfPossessionSigningKeyBuilder.cs | 90 | ||||
-rw-r--r-- | crypto/src/asn1/crmf/RegTokenControl.cs | 32 |
17 files changed, 1285 insertions, 0 deletions
diff --git a/crypto/src/asn1/cmp/CertificateConfirmationContent.cs b/crypto/src/asn1/cmp/CertificateConfirmationContent.cs new file mode 100644 index 000000000..9f2f3e038 --- /dev/null +++ b/crypto/src/asn1/cmp/CertificateConfirmationContent.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Org.BouncyCastle.Cms; + + +namespace Org.BouncyCastle.Asn1.Cmp +{ + public class CertificateConfirmationContent + { + private DefaultDigestAlgorithmIdentifierFinder digestAlgFinder; + private CertConfirmContent content; + + + public CertificateConfirmationContent(CertConfirmContent content) + { + this.content = content; + } + + public CertificateConfirmationContent(CertConfirmContent content, + DefaultDigestAlgorithmIdentifierFinder digestAlgFinder) + { + this.content = content; + this.digestAlgFinder = digestAlgFinder; + } + + public CertConfirmContent ToAsn1Structure() + { + return content; + } + + public CertificateStatus[] GetStatusMessages() + { + CertStatus[] statusArray = content.ToCertStatusArray(); + CertificateStatus[] ret = new CertificateStatus[statusArray.Length]; + for (int i = 0; i != ret.Length; i++) + { + ret[i] = new CertificateStatus(digestAlgFinder, statusArray[i]); + } + + return ret; + } + } +} diff --git a/crypto/src/asn1/cmp/CertificateConfirmationContentBuilder.cs b/crypto/src/asn1/cmp/CertificateConfirmationContentBuilder.cs new file mode 100644 index 000000000..b8c306f81 --- /dev/null +++ b/crypto/src/asn1/cmp/CertificateConfirmationContentBuilder.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Cms; +using Org.BouncyCastle.Crypto.IO; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Asn1.Cmp +{ + public class CertificateConfirmationContentBuilder + { + DefaultSignatureAlgorithmIdentifierFinder sigAlgFinder = new DefaultSignatureAlgorithmIdentifierFinder(); + private DefaultDigestAlgorithmIdentifierFinder digestAlgFinder; + private ArrayList acceptedCerts = new ArrayList(); + private ArrayList acceptedReqIds = new ArrayList(); + + public CertificateConfirmationContentBuilder() : this(new DefaultDigestAlgorithmIdentifierFinder()) + { + + } + + public CertificateConfirmationContentBuilder(DefaultDigestAlgorithmIdentifierFinder digestAlgFinder) + { + this.digestAlgFinder = digestAlgFinder; + } + + public CertificateConfirmationContentBuilder AddAcceptedCertificate(X509Certificate certHolder, + BigInteger certReqId) + { + acceptedCerts.Add(certHolder); + acceptedReqIds.Add(certReqId); + return this; + } + + public CertificateConfirmationContent Build() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + for (int i = 0; i != acceptedCerts.Count; i++) + { + X509Certificate cert = (X509Certificate) acceptedCerts[i]; + BigInteger reqId = (BigInteger) acceptedReqIds[i]; + + + + AlgorithmIdentifier algorithmIdentifier = sigAlgFinder.Find(cert.SigAlgName); + + AlgorithmIdentifier digAlg = digestAlgFinder.find(algorithmIdentifier); + if (digAlg == null) + { + throw new CmpException("cannot find algorithm for digest from signature"); + } + + DigestSink sink = new DigestSink(DigestUtilities.GetDigest(digAlg.Algorithm)); + + sink.Write(cert.GetEncoded()); + + byte[] dig = new byte[sink.Digest.GetDigestSize()]; + sink.Digest.DoFinal(dig, 0); + + v.Add(new CertStatus(dig,reqId)); + } + + return new CertificateConfirmationContent(CertConfirmContent.GetInstance(new DerSequence(v)), + digestAlgFinder); + } + } +} diff --git a/crypto/src/asn1/cmp/CertificateStatus.cs b/crypto/src/asn1/cmp/CertificateStatus.cs new file mode 100644 index 000000000..d16c8e006 --- /dev/null +++ b/crypto/src/asn1/cmp/CertificateStatus.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Cms; +using Org.BouncyCastle.Crypto.IO; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Asn1.Cmp +{ + public class CertificateStatus + { + private DefaultSignatureAlgorithmIdentifierFinder sigAlgFinder = new DefaultSignatureAlgorithmIdentifierFinder(); + private DefaultDigestAlgorithmIdentifierFinder digestAlgFinder; + private CertStatus certStatus; + + public CertificateStatus(DefaultDigestAlgorithmIdentifierFinder digestAlgFinder, CertStatus certStatus) + { + this.digestAlgFinder = digestAlgFinder; + this.certStatus = certStatus; + } + + public PkiStatusInfo PkiStatusInfo + { + get { return certStatus.StatusInfo; } + } + + public BigInteger CertRequestId + { + get { return certStatus.CertReqID.Value; } + } + + public bool IsVerified(X509Certificate cert) + { + + AlgorithmIdentifier digAlg = digestAlgFinder.find( sigAlgFinder.Find(cert.SigAlgName)); + if (digAlg == null) + { + throw new CmpException("cannot find algorithm for digest from signature "+cert.SigAlgName); + } + + DigestSink digestSink = new DigestSink(DigestUtilities.GetDigest(digAlg.Algorithm)); + + digestSink.Write(cert.GetEncoded()); + + byte[] digest = new byte[digestSink.Digest.GetDigestSize()]; + digestSink.Digest.DoFinal(digest, 0); + return Arrays.ConstantTimeAreEqual(certStatus.CertHash.GetOctets(), digest); + } + } +} diff --git a/crypto/src/asn1/cmp/CmpException.cs b/crypto/src/asn1/cmp/CmpException.cs new file mode 100644 index 000000000..0500b7d3e --- /dev/null +++ b/crypto/src/asn1/cmp/CmpException.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Text; + +namespace Org.BouncyCastle.Asn1.Cmp +{ + public class CmpException : Exception + { + public CmpException() + { + } + + public CmpException(string message) : base(message) + { + } + + public CmpException(string message, Exception innerException) : base(message, innerException) + { + } + + protected CmpException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } +} diff --git a/crypto/src/asn1/cmp/GeneralPKIMessage.cs b/crypto/src/asn1/cmp/GeneralPKIMessage.cs new file mode 100644 index 000000000..d91b8ef7e --- /dev/null +++ b/crypto/src/asn1/cmp/GeneralPKIMessage.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Org.BouncyCastle.Asn1.Cmp +{ + public class GeneralPKIMessage + { + private readonly PkiMessage pkiMessage; + + private static PkiMessage parseBytes(byte[] encoding) + { + return PkiMessage.GetInstance(Asn1Object.FromByteArray(encoding)); + } + + public GeneralPKIMessage(PkiMessage pkiMessage) + { + this.pkiMessage = pkiMessage; + } + + public GeneralPKIMessage(byte[] encoding) : this(parseBytes(encoding)) + { + } + + public PkiHeader Header { + get { + return pkiMessage.Header; + } + } + + public PkiBody Body + { + get + { + return pkiMessage.Body; + } + } + + public bool HasProtection + { + get { return pkiMessage.Protection != null; } + } + + public PkiMessage ToAsn1Structure() + { + return pkiMessage; + } + } +} diff --git a/crypto/src/asn1/cmp/ProtectedPkiMessage.cs b/crypto/src/asn1/cmp/ProtectedPkiMessage.cs new file mode 100644 index 000000000..c39f06ad0 --- /dev/null +++ b/crypto/src/asn1/cmp/ProtectedPkiMessage.cs @@ -0,0 +1,107 @@ +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.X509; +using System; +using System.Collections.Generic; +using System.Text; +using Org.BouncyCastle.Asn1.Crmf; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Operators; +using Org.BouncyCastle.Crypto.Paddings; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.Asn1.Cmp +{ + + public class ProtectedPkiMessage + { + private PkiMessage pkiMessage; + + + public ProtectedPkiMessage(GeneralPKIMessage pkiMessage) + { + + if (!pkiMessage.HasProtection) + { + throw new ArgumentException("pki message not protected"); + } + + this.pkiMessage = pkiMessage.ToAsn1Structure(); + } + + public ProtectedPkiMessage(PkiMessage pkiMessage) + { + if (pkiMessage.Header.ProtectionAlg == null) + { + throw new ArgumentException("pki message not protected"); + } + + this.pkiMessage = pkiMessage; + } + + public PkiHeader Header { get { return pkiMessage.Header; } } + public PkiBody Body { get { return pkiMessage.Body; } } + + public PkiMessage ToAsn1Message() { return pkiMessage; } + + public bool HasPasswordBasedMacProtected { get { return Header.ProtectionAlg.Algorithm.Equals(CmpObjectIdentifiers.passwordBasedMac); } } + + public X509Certificate[] GetCertificates() + { + CmpCertificate[] certs = pkiMessage.GetExtraCerts(); + + if (certs == null) + { + return new X509Certificate[0]; + } + + X509Certificate[] res = new X509Certificate[certs.Length]; + for (int t=0; t<certs.Length;t++) + { + res[t] = new X509Certificate(X509CertificateStructure.GetInstance(certs[t].GetEncoded())); + } + + return res; + } + + + + + public bool Verify(IVerifierFactory verifier) + { + Asn1EncodableVector avec = new Asn1EncodableVector(); + avec.Add(pkiMessage.Header); + avec.Add(pkiMessage.Body); + byte[] enc = new DerSequence(avec).GetDerEncoded(); + + IStreamCalculator streamCalculator = verifier.CreateCalculator(); + + streamCalculator.Stream.Write(enc,0,enc.Length); + streamCalculator.Stream.Flush(); + streamCalculator.Stream.Close(); + + IVerifier result = (IVerifier) streamCalculator.GetResult(); + return result.IsVerified(pkiMessage.Protection.GetBytes()); + } + + + public bool Verify(Asn1MacFactoryProvider asn1Factory, byte[] password) + { + if (!CmpObjectIdentifiers.passwordBasedMac.Equals(pkiMessage.Header.ProtectionAlg.Algorithm)) + { + throw new InvalidOperationException("protection algorithm is not mac based"); + } + + PbmParameter parameter = PbmParameter.GetInstance(pkiMessage.Header.ProtectionAlg.Parameters); + + PkMacFactory macFactory = (PkMacFactory)asn1Factory.CreateMacFactory(parameter); + + macFactory.Password = password; + MacVerifierFactory macVerifierFactory = new MacVerifierFactory(macFactory); + + return Verify(macVerifierFactory); + } + + } +} diff --git a/crypto/src/asn1/cmp/ProtectedPkiMessageBuilder.cs b/crypto/src/asn1/cmp/ProtectedPkiMessageBuilder.cs new file mode 100644 index 000000000..a6a98d753 --- /dev/null +++ b/crypto/src/asn1/cmp/ProtectedPkiMessageBuilder.cs @@ -0,0 +1,174 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Text; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.IO; +using Org.BouncyCastle.Crypto.Macs; +using Org.BouncyCastle.Crypto.Operators; +using Org.BouncyCastle.Crypto.Paddings; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.X509; + +namespace Org.BouncyCastle.Asn1.Cmp +{ + public class ProtectedPkiMessageBuilder + { + private PkiHeaderBuilder hdrBuilBuilder; + private PkiBody body; + private ArrayList generalInfos = new ArrayList(); + private ArrayList extraCerts = new ArrayList(); + + public ProtectedPkiMessageBuilder(GeneralName sender, GeneralName recipient) : this(PkiHeader.CMP_2000, sender, + recipient) + { + } + + + public ProtectedPkiMessageBuilder(int pvno, GeneralName sender, GeneralName recipient) + { + hdrBuilBuilder = new PkiHeaderBuilder(pvno, sender, recipient); + } + + public ProtectedPkiMessageBuilder SetTransactionId(byte[] tid) + { + hdrBuilBuilder.SetTransactionID(tid); + return this; + } + + public ProtectedPkiMessageBuilder SetFreeText(PkiFreeText freeText) + { + hdrBuilBuilder.SetFreeText(freeText); + return this; + } + + public ProtectedPkiMessageBuilder AddGeneralInfo(InfoTypeAndValue genInfo) + { + generalInfos.Add(genInfo); + return this; + } + + public ProtectedPkiMessageBuilder SetRecipKID(byte[] id) + { + hdrBuilBuilder.SetRecipKID(id); + return this; + } + + public ProtectedPkiMessageBuilder SetRecipNonce(byte[] nonce) + { + hdrBuilBuilder.SetRecipNonce(nonce); + return this; + } + + public ProtectedPkiMessageBuilder SetSenderKID(byte[] id) + { + hdrBuilBuilder.SetSenderKID(id); + return this; + } + + public ProtectedPkiMessageBuilder SetSenderNonce(byte[] nonce) + { + hdrBuilBuilder.SetSenderNonce(nonce); + return this; + } + + public ProtectedPkiMessageBuilder SetBody(PkiBody body) + { + this.body = body; + return this; + } + + public ProtectedPkiMessageBuilder AddCmpCertificate(X509Certificate certificate) + { + extraCerts.Add(certificate); + return this; + } + + public ProtectedPkiMessage Build(ISignatureFactory signatureFactory) + { + IStreamCalculator calculator = signatureFactory.CreateCalculator(); + + if (!(signatureFactory.AlgorithmDetails is AlgorithmIdentifier)) + { + throw new ArgumentException("AlgorithmDetails is not AlgorithmIdentifier"); + } + + FinalizeHeader((AlgorithmIdentifier) signatureFactory.AlgorithmDetails); + PkiHeader header = hdrBuilBuilder.Build(); + DerBitString protection = new DerBitString(CalculateSignature(calculator, header, body)); + return FinalizeMessage(header, protection); + } + + public ProtectedPkiMessage Build(IMacFactory factory) + { + IStreamCalculator calculator = factory.CreateCalculator(); + FinalizeHeader((AlgorithmIdentifier)factory.AlgorithmDetails); + PkiHeader header = hdrBuilBuilder.Build(); + DerBitString protection = new DerBitString(CalculateSignature(calculator, header, body)); + return FinalizeMessage(header, protection); + } + + + private void FinalizeHeader(AlgorithmIdentifier algorithmIdentifier) + { + hdrBuilBuilder.SetProtectionAlg(algorithmIdentifier); + if (generalInfos.Count > 0) + { + InfoTypeAndValue[] genInfos = new InfoTypeAndValue[generalInfos.Count]; + for (int t = 0; t < genInfos.Length; t++) + { + genInfos[t] = (InfoTypeAndValue) generalInfos[t]; + } + + hdrBuilBuilder.SetGeneralInfo(genInfos); + } + } + + private ProtectedPkiMessage FinalizeMessage(PkiHeader header, DerBitString protection) + { + if (extraCerts.Count > 0) + { + CmpCertificate[] cmpCertificates = new CmpCertificate[extraCerts.Count]; + for (int i = 0; i < cmpCertificates.Length; i++) + { + byte[] cert = ((X509Certificate) extraCerts[i]).GetEncoded(); + cmpCertificates[i] = CmpCertificate.GetInstance((Asn1Sequence.FromByteArray(cert))); + } + + return new ProtectedPkiMessage(new PkiMessage(header, body, protection, cmpCertificates)); + } + + return new ProtectedPkiMessage(new PkiMessage(header, body, protection)); + } + + private byte[] CalculateSignature(IStreamCalculator signer, PkiHeader header, PkiBody body) + { + Asn1EncodableVector avec = new Asn1EncodableVector(); + avec.Add(header); + avec.Add(body); + byte[] encoded = new DerSequence(avec).GetEncoded(); + signer.Stream.Write(encoded, 0, encoded.Length); + Object result = signer.GetResult(); + + + if (result is DefaultSignatureResult) + { + return ((DefaultSignatureResult) result).Collect(); + } + else if (result is DefaultMacAndDigestResult) + { + return ((DefaultMacAndDigestResult) result).MacResult; + } + else if (result is byte[]) + { + return (byte[]) result; + } + + throw new InvalidOperationException("result is not byte[] or DefaultSignatureResult"); + } + } +} \ No newline at end of file diff --git a/crypto/src/asn1/crmf/AuthenticatorControl.cs b/crypto/src/asn1/crmf/AuthenticatorControl.cs new file mode 100644 index 000000000..060088b1f --- /dev/null +++ b/crypto/src/asn1/crmf/AuthenticatorControl.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Org.BouncyCastle.Asn1.Crmf +{ + public class AuthenticatorControl:IControl + { + + private static readonly DerObjectIdentifier type = CrmfObjectIdentifiers.id_regCtrl_authenticator; + + private readonly DerUtf8String token; + + public AuthenticatorControl(DerUtf8String token) + { + this.token = token; + } + + public AuthenticatorControl(String token) + { + this.token = new DerUtf8String(token); + } + + public DerObjectIdentifier Type + { + get { return type; } + } + + public Asn1Encodable Value { + get { return token; } + } + } +} diff --git a/crypto/src/asn1/crmf/CertificateRequestMessage.cs b/crypto/src/asn1/crmf/CertificateRequestMessage.cs new file mode 100644 index 000000000..b80c2a3fd --- /dev/null +++ b/crypto/src/asn1/crmf/CertificateRequestMessage.cs @@ -0,0 +1,182 @@ +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Operators; + +namespace Org.BouncyCastle.Asn1.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; + + private readonly CertReqMsg certReqMsg; + private readonly Controls controls; + + private static CertReqMsg ParseBytes(byte[] encoding) + + { + return CertReqMsg.GetInstance(encoding); + } + + public CertificateRequestMessage(CertReqMsg certReqMsg) + { + this.certReqMsg = certReqMsg; + this.controls = certReqMsg.CertReq.Controls; + } + + public CertReqMsg ToAsn1Structure() + { + return certReqMsg; + } + + public CertTemplate GetCertTemplate() + { + return this.certReqMsg.CertReq.CertTemplate; + } + + public bool HasControls + { + get { return controls != null; } + } + + + public bool HasControl(DerObjectIdentifier objectIdentifier) + { + return findControl(objectIdentifier) != null; + } + + public IControl GetControl(DerObjectIdentifier type) + { + AttributeTypeAndValue found = findControl(type); + if (found != null) + { + if (found.Type.Equals(CrmfObjectIdentifiers.id_regCtrl_pkiArchiveOptions)) + { + return new PkiArchiveControl(PkiArchiveOptions.GetInstance(found.Value)); + } + + if (found.Type.Equals(CrmfObjectIdentifiers.id_regCtrl_regToken)) + { + return new RegTokenControl(DerUtf8String.GetInstance(found.Value)); + } + + if (found.Type.Equals(CrmfObjectIdentifiers.id_regCtrl_authenticator)) + { + return new AuthenticatorControl(DerUtf8String.GetInstance(found.Value)); + } + } + return null; + } + + + + + public AttributeTypeAndValue findControl(DerObjectIdentifier type) + { + if (controls == null) + { + return null; + } + + AttributeTypeAndValue[] tAndV = controls.ToAttributeTypeAndValueArray(); + AttributeTypeAndValue found = null; + + for (int i = 0; i < tAndV.Length; i++) + { + if (tAndV[i].Type.Equals(type)) + { + found = tAndV[i]; + break; + } + } + + return found; + } + + public bool HasProofOfPossession + { + get { return certReqMsg.Popo != null; } + } + + public int ProofOfPossession + { + get { return certReqMsg.Popo.Type; } + } + + public bool HasSigningKeyProofOfPossessionWithPkMac + { + get + { + ProofOfPossession pop = certReqMsg.Popo; + + if (pop.Type == popSigningKey) + { + PopoSigningKey popoSign = PopoSigningKey.GetInstance(pop.Object); + + return popoSign.PoposkInput.PublicKeyMac != null; + } + + return false; + + } + } + + public bool IsValidSigningKeyPop(IVerifierFactoryProvider verifierProvider) + { + ProofOfPossession pop = certReqMsg.Popo; + 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"); + } + return verifySignature(verifierProvider, popoSign); + } + + throw new InvalidOperationException("not Signing Key type of proof of possession"); + } + + + + private bool verifySignature(IVerifierFactoryProvider verifierFactoryProvider, PopoSigningKey signKey) + { + IVerifierFactory verifer; + IStreamCalculator calculator; + try + { + verifer = verifierFactoryProvider.CreateVerifierFactory(signKey.AlgorithmIdentifier); + calculator = verifer.CreateCalculator(); + } + catch (Exception ex) + { + throw new CrmfException("unable to create verifier: "+ex.Message, ex); + } + + if (signKey.PoposkInput != null) + { + byte[] b = signKey.GetDerEncoded(); + calculator.Stream.Write(b,0,b.Length); + } + else + { + byte[] b = certReqMsg.GetDerEncoded(); + calculator.Stream.Write(b,0,b.Length); + } + + DefaultVerifierResult result = (DefaultVerifierResult) calculator.GetResult(); + + return result.IsVerified(signKey.Signature.GetBytes()); + } + + public byte[] GetEncoded() + { + return certReqMsg.GetEncoded(); + } + } +} diff --git a/crypto/src/asn1/crmf/CertificateRequestMessageBuilder.cs b/crypto/src/asn1/crmf/CertificateRequestMessageBuilder.cs new file mode 100644 index 000000000..df604f4f5 --- /dev/null +++ b/crypto/src/asn1/crmf/CertificateRequestMessageBuilder.cs @@ -0,0 +1,261 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Operators; +using Org.BouncyCastle.Math; + +namespace Org.BouncyCastle.Asn1.Crmf +{ + public class CertificateRequestMessageBuilder + { + private readonly BigInteger _certReqId; + private X509ExtensionsGenerator _extGenerator; + private CertTemplateBuilder _templateBuilder; + private ArrayList _controls= new ArrayList(); + private ISignatureFactory _popSigner; + private PkMacFactory _pkMacBuilder; + private char[] _password; + private GeneralName _sender; + private int _popoType = ProofOfPossession.TYPE_KEY_ENCIPHERMENT; + private PopoPrivKey _popoPrivKey; + private Asn1Null _popRaVerified; + private PKMacValue _agreeMac; + + public CertificateRequestMessageBuilder(BigInteger certReqId) + { + this._certReqId = certReqId; + this._extGenerator = new X509ExtensionsGenerator(); + this._templateBuilder = new CertTemplateBuilder(); + } + + public CertificateRequestMessageBuilder SetPublicKey(SubjectPublicKeyInfo publicKeyInfo) + { + if (publicKeyInfo != null) + { + _templateBuilder.SetPublicKey(publicKeyInfo); + } + + return this; + } + + + public CertificateRequestMessageBuilder SetIssuer(X509Name issuer) + { + if (issuer != null) + { + _templateBuilder.SetIssuer(issuer); + } + + return this; + } + + public CertificateRequestMessageBuilder SetSubject(X509Name subject) + { + if (subject != null) + { + _templateBuilder.SetSubject(subject); + } + + return this; + } + + public CertificateRequestMessageBuilder SetSerialNumber(BigInteger serialNumber) + { + if (serialNumber != null) + { + _templateBuilder.SetSerialNumber(new DerInteger(serialNumber)); + } + + return this; + } + + public CertificateRequestMessageBuilder SetValidity(Time notBefore, Time notAfter) + { + _templateBuilder.SetValidity(new OptionalValidity(notBefore, notAfter)); + return this; + } + + public CertificateRequestMessageBuilder AddExtension(DerObjectIdentifier oid, bool critical, + Asn1Encodable value) + { + _extGenerator.AddExtension(oid,critical, value); + return this; + } + + public CertificateRequestMessageBuilder AddExtension(DerObjectIdentifier oid, bool critical, + byte[] value) + { + _extGenerator.AddExtension(oid, critical, value); + return this; + } + + public CertificateRequestMessageBuilder SetProofOfPossessionSignKeySigner(ISignatureFactory popoSignatureFactory) + { + if (_popoPrivKey != null || _popRaVerified != null || _agreeMac != null) + { + throw new InvalidOperationException("only one proof of possession is allowed."); + } + + this._popoType = ProofOfPossession.TYPE_KEY_ENCIPHERMENT; + return this; + } + + public CertificateRequestMessageBuilder SetProofOfPossessionSubsequentMessage(SubsequentMessage msg) + { + if (_popoPrivKey != null || _popRaVerified != null || _agreeMac != null) + { + throw new InvalidOperationException("only one proof of possession is allowed."); + } + + this._popoType = ProofOfPossession.TYPE_KEY_ENCIPHERMENT; + this._popoPrivKey = new PopoPrivKey(msg); + + + return this; + } + + + public CertificateRequestMessageBuilder SetProofOfPossessionSubsequentMessage(int type, SubsequentMessage msg) + { + if (_popoPrivKey != null || _popRaVerified != null || _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"); + } + + this._popoType = type; + this._popoPrivKey = new PopoPrivKey(msg); + return this; + } + + public CertificateRequestMessageBuilder SetProofOfPossessionAgreeMac(PKMacValue macValue) + { + if (_popSigner != null || _popRaVerified != null || _popoPrivKey != null) + { + throw new InvalidOperationException("only one proof of possession allowed"); + } + + this._agreeMac = macValue; + return this; + } + + public CertificateRequestMessageBuilder SetProofOfPossessionRaVerified() + { + if (_popSigner != null || _popoPrivKey != null) + { + throw new InvalidOperationException("only one proof of possession allowed"); + } + + this._popRaVerified = DerNull.Instance; + + return this; + } + + public CertificateRequestMessageBuilder SetAuthInfoPKMAC(PkMacFactory pkmacFactory, char[] password) + { + this._pkMacBuilder = pkmacFactory; + this._password = password; + + return this; + } + + public CertificateRequestMessageBuilder SetAuthInfoSender(X509Name sender) + { + return SetAuthInfoSender(new GeneralName(sender)); + } + + public CertificateRequestMessageBuilder SetAuthInfoSender(GeneralName sender) + { + this._sender = sender; + return this; + } + + public CertificateRequestMessage Build() + { + Asn1EncodableVector v = new Asn1EncodableVector(); + + v.Add(new DerInteger(this._certReqId)); + + if (!this._extGenerator.IsEmpty) + { + this._templateBuilder.SetExtensions(_extGenerator.Generate()); + } + + v.Add(_templateBuilder.Build()); + + if (_controls.Count>0) + { + Asn1EncodableVector controlV = new Asn1EncodableVector(); + + foreach (Object item in _controls) + { + IControl control = (IControl) item; + controlV.Add(new AttributeTypeAndValue(control.Type, control.Value)); + } + + v.Add(new DerSequence(controlV)); + } + + CertRequest request = CertRequest.GetInstance(new DerSequence(v)); + + v = new Asn1EncodableVector(); + + v.Add(request); + + if (_popSigner != null) + { + CertTemplate template = request.CertTemplate; + + if (template.Subject == null || template.PublicKey == null) + { + SubjectPublicKeyInfo pubKeyInfo = request.CertTemplate.PublicKey; + + ProofOfPossessionSigningKeyBuilder builder = new ProofOfPossessionSigningKeyBuilder(pubKeyInfo); + + if (_sender != null) + { + builder.setSender(_sender); + } + else + { + // PkMa pkmacGenerator = new PKMACValueGenerator(_pkmacBuilder); + + builder.setPublicKeyMac(_pkMacBuilder, _password); + } + + v.Add(new ProofOfPossession(builder.build(_popSigner))); + } + else + { + ProofOfPossessionSigningKeyBuilder builder = new ProofOfPossessionSigningKeyBuilder(request); + + v.Add(new ProofOfPossession(builder.build(_popSigner))); + } + } + else if (_popoPrivKey != null) + { + v.Add(new ProofOfPossession(_popoType, _popoPrivKey)); + } + else if (_agreeMac != null) + { + v.Add(new ProofOfPossession(ProofOfPossession.TYPE_KEY_AGREEMENT, + PopoPrivKey.GetInstance(new DerTaggedObject(false, PopoPrivKey.agreeMAC, _agreeMac),true ))); + + } + else if (_popRaVerified != null) + { + v.Add(new ProofOfPossession()); + } + + return new CertificateRequestMessage(CertReqMsg.GetInstance(new DerSequence(v))); + } + } +} diff --git a/crypto/src/asn1/crmf/Controls.cs b/crypto/src/asn1/crmf/Controls.cs index e8b9f3db0..8f986168c 100644 --- a/crypto/src/asn1/crmf/Controls.cs +++ b/crypto/src/asn1/crmf/Controls.cs @@ -4,6 +4,15 @@ using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Asn1.Crmf { + + public interface IControl + { + DerObjectIdentifier Type { get; } + + Asn1Encodable Value { get; } + } + + public class Controls : Asn1Encodable { diff --git a/crypto/src/asn1/crmf/CrmfException.cs b/crypto/src/asn1/crmf/CrmfException.cs new file mode 100644 index 000000000..7043ccd73 --- /dev/null +++ b/crypto/src/asn1/crmf/CrmfException.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Text; + +namespace Org.BouncyCastle.Asn1.Crmf +{ + public class CrmfException : Exception + { + public CrmfException() + { + } + + public CrmfException(string message) : base(message) + { + } + + public CrmfException(string message, Exception innerException) : base(message, innerException) + { + } + + protected CrmfException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } +} diff --git a/crypto/src/asn1/crmf/EncryptedValueBuilder.cs b/crypto/src/asn1/crmf/EncryptedValueBuilder.cs new file mode 100644 index 000000000..4b57156d4 --- /dev/null +++ b/crypto/src/asn1/crmf/EncryptedValueBuilder.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using Org.BouncyCastle.Asn1.Nist; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Engines; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Utilities; + +namespace Org.BouncyCastle.Asn1.Crmf +{ + +// public delegate IBlockCipher BlockCipherCreator(ICipherParameters); +// +// public class EncryptedValueBuilder +// { +// private readonly IBlockCipher _cipher; +// private static readonly IDictionary algToDelegate = Platform.CreateHashtable(); +// static EncryptedValueBuilder() +// { +// algToDelegate[NistObjectIdentifiers.IdAes128Cbc] = new CipherCreator() +// {Creator = delegate(ICipherParameters param) { return new AesEngine(); }}; +// +// } +// +// +// public EncryptedValueBuilder(DerObjectIdentifier alg) +// { +// +// } +// +// +// private static IBlockCipher AesCBC(ICipherParameters param) +// { +// if (param is ParametersWithIV ivParam) { +// return new +// } +// else +// { +// throw new ArgumentException("expecting param to be ParametersWithIv"); +// } +// } +// +// +// +// private class CipherCreator +// { +// public BlockCipherCreator Creator { get; set; } +// } +// +// } +} diff --git a/crypto/src/asn1/crmf/OptionalValidity.cs b/crypto/src/asn1/crmf/OptionalValidity.cs index d1a0f7ffb..46fd1f860 100644 --- a/crypto/src/asn1/crmf/OptionalValidity.cs +++ b/crypto/src/asn1/crmf/OptionalValidity.cs @@ -33,6 +33,12 @@ namespace Org.BouncyCastle.Asn1.Crmf return new OptionalValidity(Asn1Sequence.GetInstance(obj)); } + public OptionalValidity(Time notBefore, Time notAfter) + { + this.notBefore = notBefore; + this.notAfter = notAfter; + } + public virtual Time NotBefore { get { return notBefore; } diff --git a/crypto/src/asn1/crmf/PkiArchiveControl.cs b/crypto/src/asn1/crmf/PkiArchiveControl.cs new file mode 100644 index 000000000..0290fdfe6 --- /dev/null +++ b/crypto/src/asn1/crmf/PkiArchiveControl.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Org.BouncyCastle.Asn1.Cms; +using Org.BouncyCastle.Cms; + +namespace Org.BouncyCastle.Asn1.Crmf +{ + public class PkiArchiveControl:IControl + { + public static readonly int encryptedPrivKey = PkiArchiveOptions.encryptedPrivKey; + 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; + + public PkiArchiveControl(PkiArchiveOptions pkiArchiveOptions) + { + this.pkiArchiveOptions = pkiArchiveOptions; + } + + public DerObjectIdentifier Type + { + get { return type; } + } + + public Asn1Encodable Value + { + get { return pkiArchiveOptions; } + } + + public int ArchiveType + { + get { return pkiArchiveOptions.Type; } + } + + public bool EnvelopedData + { + get + { + EncryptedKey encKey = EncryptedKey.GetInstance(pkiArchiveOptions.Value); + return !encKey.IsEncryptedValue; + } + } + + public CmsEnvelopedData GetEnvelopedData() + { + try + { + EncryptedKey encKey = EncryptedKey.GetInstance(pkiArchiveOptions.Value); + EnvelopedData data = Org.BouncyCastle.Asn1.Cms.EnvelopedData.GetInstance(encKey.Value); + + return new CmsEnvelopedData(new ContentInfo(CmsObjectIdentifiers.EnvelopedData, data)); + } + catch (CmsException e) + { + throw new CrmfException("CMS parsing error: " + e.Message, e); + } + catch (Exception e) + { + throw new CrmfException("CRMF parsing error: "+e.Message, e); + } + } + + } +} diff --git a/crypto/src/asn1/crmf/ProofOfPossessionSigningKeyBuilder.cs b/crypto/src/asn1/crmf/ProofOfPossessionSigningKeyBuilder.cs new file mode 100644 index 000000000..cbaf834a1 --- /dev/null +++ b/crypto/src/asn1/crmf/ProofOfPossessionSigningKeyBuilder.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Operators; +using Org.BouncyCastle.Crypto.Paddings; + +namespace Org.BouncyCastle.Asn1.Crmf +{ + public class ProofOfPossessionSigningKeyBuilder + { + private CertRequest _certRequest; + private SubjectPublicKeyInfo _pubKeyInfo; + private GeneralName _name; + private PKMacValue _publicKeyMAC; + + public ProofOfPossessionSigningKeyBuilder(CertRequest certRequest) + { + this._certRequest = certRequest; + } + + + public ProofOfPossessionSigningKeyBuilder(SubjectPublicKeyInfo pubKeyInfo) + { + this._pubKeyInfo = pubKeyInfo; + } + + public ProofOfPossessionSigningKeyBuilder setSender(GeneralName name) + { + this._name = name; + + return this; + } + + public ProofOfPossessionSigningKeyBuilder setPublicKeyMac(PkMacFactory generator, char[] password) + { + IStreamCalculator calc = generator.CreateCalculator(); + byte[] d = _pubKeyInfo.GetDerEncoded(); + calc.Stream.Write(d, 0, d.Length); + calc.Stream.Flush(); + calc.Stream.Close(); + + + this._publicKeyMAC = new PKMacValue( + (AlgorithmIdentifier)generator.AlgorithmDetails, + new DerBitString(((DefaultMacAndDigestResult)calc.GetResult()).MacResult)); + + return this; + } + + public PopoSigningKey build(ISignatureFactory signer) + { + if (_name != null && _publicKeyMAC != null) + { + throw new InvalidOperationException("name and publicKeyMAC cannot both be set."); + } + + PopoSigningKeyInput popo; + byte[] b; + IStreamCalculator calc = signer.CreateCalculator(); + if (_certRequest != null) + { + popo = null; + b = _certRequest.GetDerEncoded(); + calc.Stream.Write(b, 0, b.Length); + + } + else if (_name != null) + { + popo = new PopoSigningKeyInput(_name, _pubKeyInfo); + b = popo.GetDerEncoded(); + calc.Stream.Write(b, 0, b.Length); + } + else + { + popo = new PopoSigningKeyInput(_publicKeyMAC, _pubKeyInfo); + b = popo.GetDerEncoded(); + calc.Stream.Write(b, 0, b.Length); + } + + calc.Stream.Flush(); + calc.Stream.Close(); + DefaultSignatureResult res = (DefaultSignatureResult)calc.GetResult(); + return new PopoSigningKey(popo, (AlgorithmIdentifier)signer.AlgorithmDetails, new DerBitString(res.Collect())); + } + + + } +} diff --git a/crypto/src/asn1/crmf/RegTokenControl.cs b/crypto/src/asn1/crmf/RegTokenControl.cs new file mode 100644 index 000000000..77bf32557 --- /dev/null +++ b/crypto/src/asn1/crmf/RegTokenControl.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Org.BouncyCastle.Asn1.Crmf +{ + public class RegTokenControl:IControl + { + private static readonly DerObjectIdentifier type = CrmfObjectIdentifiers.id_regCtrl_regToken; + + private readonly DerUtf8String token; + + public RegTokenControl(DerUtf8String token) + { + this.token = token; + } + + public RegTokenControl(String token) + { + this.token = new DerUtf8String(token); + } + + public DerObjectIdentifier Type + { + get { return type; } + } + public Asn1Encodable Value + { + get { return token; } + } + } +} |