using System; 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.Utilities; using Org.BouncyCastle.X509; namespace Org.BouncyCastle.Cmp { /// /// Wrapper for a PKIMessage with protection attached to it. /// public class ProtectedPkiMessage { private readonly PkiMessage pkiMessage; /// /// Wrap a general message. /// /// If the general message does not have protection. /// The General message public ProtectedPkiMessage(GeneralPkiMessage pkiMessage) { if (!pkiMessage.HasProtection) throw new ArgumentException("pki message not protected"); this.pkiMessage = pkiMessage.ToAsn1Structure(); } /// /// Wrap a PKI message. /// /// If the PKI message does not have protection. /// The PKI message public ProtectedPkiMessage(PkiMessage pkiMessage) { if (null == pkiMessage.Header.ProtectionAlg) throw new ArgumentException("pki message not protected"); this.pkiMessage = pkiMessage; } /// /// Message header /// public PkiHeader Header { get { return pkiMessage.Header; } } /// /// Message Body /// public PkiBody Body { get { return pkiMessage.Body; } } /// /// Return the underlying ASN.1 structure contained in this object. /// /// PKI Message structure public PkiMessage ToAsn1Message() { return pkiMessage; } /// /// Determine whether the message is protected by a password based MAC. Use verify(PKMACBuilder, char[]) /// to verify the message if this method returns true. /// /// true if protection MAC PBE based, false otherwise. public bool HasPasswordBasedMacProtected { get { return Header.ProtectionAlg.Algorithm.Equals(CmpObjectIdentifiers.passwordBasedMac); } } /// /// Return the extra certificates associated with this message. /// /// an array of extra certificates, zero length if none present. public X509Certificate[] GetCertificates() { CmpCertificate[] certs = pkiMessage.GetExtraCerts(); if (null == certs) 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; } /// /// Verify a message with a public key based signature attached. /// /// a factory of signature verifiers. /// true if the provider is able to create a verifier that validates the signature, false otherwise. public bool Verify(IVerifierFactory verifierFactory) { IStreamCalculator streamCalculator = verifierFactory.CreateCalculator(); IVerifier result = (IVerifier)Process(streamCalculator); return result.IsVerified(pkiMessage.Protection.GetBytes()); } private object Process(IStreamCalculator streamCalculator) { Asn1EncodableVector avec = new Asn1EncodableVector(); avec.Add(pkiMessage.Header); avec.Add(pkiMessage.Body); byte[] enc = new DerSequence(avec).GetDerEncoded(); streamCalculator.Stream.Write(enc, 0, enc.Length); streamCalculator.Stream.Flush(); Platform.Dispose(streamCalculator.Stream); return streamCalculator.GetResult(); } /// /// Verify a message with password based MAC protection. /// /// MAC builder that can be used to construct the appropriate MacCalculator /// the MAC password /// true if the passed in password and MAC builder verify the message, false otherwise. /// if algorithm not MAC based, or an exception is thrown verifying the MAC. public bool Verify(PKMacBuilder pkMacBuilder, char[] 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); pkMacBuilder.SetParameters(parameter); IBlockResult result = (IBlockResult)Process(pkMacBuilder.Build(password).CreateCalculator()); return Arrays.ConstantTimeAreEqual(result.Collect(), this.pkiMessage.Protection.GetBytes()); } } }