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.X509; namespace Org.BouncyCastle.Cmp { /// /// Wrapper for a PKIMessage with protection attached to it. /// public class ProtectedPkiMessage { private readonly PkiMessage m_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("GeneralPkiMessage not protected"); m_pkiMessage = pkiMessage.ToAsn1Structure(); } // TODO[cmp] Make internal? (Has test that uses it) /// /// 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("PkiMessage not protected"); m_pkiMessage = pkiMessage; } /// Message header public virtual PkiHeader Header => m_pkiMessage.Header; /// Message body public virtual PkiBody Body => m_pkiMessage.Body; /// /// Return the underlying ASN.1 structure contained in this object. /// /// PkiMessage structure public virtual PkiMessage ToAsn1Message() => m_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 virtual bool HasPasswordBasedMacProtected { get { return CmpObjectIdentifiers.passwordBasedMac.Equals(Header.ProtectionAlg.Algorithm); } } /** * Return the message's protection algorithm. * * @return the algorithm ID for the message's protection algorithm. */ public virtual AlgorithmIdentifier ProtectionAlgorithm => m_pkiMessage.Header.ProtectionAlg; /// /// Return the extra certificates associated with this message. /// /// an array of extra certificates, zero length if none present. public virtual X509Certificate[] GetCertificates() { CmpCertificate[] certs = m_pkiMessage.GetExtraCerts(); if (null == certs) return new X509Certificate[0]; return Array.ConvertAll(certs, cmpCertificate => new X509Certificate(cmpCertificate.X509v3PKCert)); } /// /// 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 virtual bool Verify(IVerifierFactory verifierFactory) => X509Utilities.VerifySignature(verifierFactory, CreateProtected(), m_pkiMessage.Protection); /// /// 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 virtual bool Verify(PKMacBuilder pkMacBuilder, char[] password) { var protectionAlgorithm = m_pkiMessage.Header.ProtectionAlg; if (!CmpObjectIdentifiers.passwordBasedMac.Equals(protectionAlgorithm.Algorithm)) throw new InvalidOperationException("protection algorithm is not mac based"); PbmParameter parameter = PbmParameter.GetInstance(protectionAlgorithm.Parameters); pkMacBuilder.SetParameters(parameter); var macFactory = pkMacBuilder.Build(password); return X509Utilities.VerifyMac(macFactory, CreateProtected(), m_pkiMessage.Protection); } #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER public virtual bool Verify(PKMacBuilder pkMacBuilder, ReadOnlySpan password) { var protectionAlgorithm = m_pkiMessage.Header.ProtectionAlg; if (!CmpObjectIdentifiers.passwordBasedMac.Equals(protectionAlgorithm.Algorithm)) throw new InvalidOperationException("protection algorithm is not mac based"); PbmParameter parameter = PbmParameter.GetInstance(protectionAlgorithm.Parameters); pkMacBuilder.SetParameters(parameter); var macFactory = pkMacBuilder.Build(password); return X509Utilities.VerifyMac(macFactory, CreateProtected(), m_pkiMessage.Protection); } #endif private DerSequence CreateProtected() => new DerSequence(m_pkiMessage.Header, m_pkiMessage.Body); } }