using System; using Org.BouncyCastle.Asn1; using Org.BouncyCastle.Asn1.Crmf; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Operators; 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; private readonly CertReqMsg certReqMsg; private readonly Controls controls; private static CertReqMsg ParseBytes(byte[] encoding) { return CertReqMsg.GetInstance(encoding); } /// /// Create a CertificateRequestMessage from the passed in bytes. /// /// BER/DER encoding of the CertReqMsg structure. public CertificateRequestMessage(byte[] encoded) : this(CertReqMsg.GetInstance(encoded)) { } public CertificateRequestMessage(CertReqMsg certReqMsg) { this.certReqMsg = certReqMsg; this.controls = certReqMsg.CertReq.Controls; } /// /// Return the underlying ASN.1 object defining this CertificateRequestMessage object. /// /// A CertReqMsg public CertReqMsg ToAsn1Structure() { return certReqMsg; } /// /// Return the certificate template contained in this message. /// /// a CertTemplate structure. public CertTemplate GetCertTemplate() { return this.certReqMsg.CertReq.CertTemplate; } /// /// Return whether or not this request has control values associated with it. /// /// true if there are control values present, false otherwise. public bool HasControls { get { return controls != null; } } /// /// Return whether or not this request has a specific type of control value. /// /// the type OID for the control value we are checking for. /// true if a control value of type is present, false otherwise. public bool HasControl(DerObjectIdentifier objectIdentifier) { return FindControl(objectIdentifier) != null; } /// /// Return a control value of the specified type. /// /// the type OID for the control value we are checking for. /// the control value if present, null otherwise. 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; } /// /// Return whether or not this request message has a proof-of-possession field in it. /// /// true if proof-of-possession is present, false otherwise. public bool HasProofOfPossession { get { return certReqMsg.Popo != null; } } /// /// Return the type of the proof-of-possession this request message provides. /// /// one of: popRaVerified, popSigningKey, popKeyEncipherment, popKeyAgreement public int ProofOfPossession { get { return certReqMsg.Popo.Type; } } /// /// Return whether or not the proof-of-possession (POP) is of the type popSigningKey and /// it has a public key MAC associated with it. /// /// true if POP is popSigningKey and a PKMAC is present, false otherwise. 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; } } /// /// Return whether or not a signing key proof-of-possession (POP) is valid. /// /// a provider that can produce content verifiers for the signature contained in this POP. /// true if the POP is valid, false otherwise. /// if there is a problem in verification or content verifier creation. /// if POP not appropriate. 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.CertReq.GetDerEncoded(); calculator.Stream.Write(b, 0, b.Length); } IVerifier result = calculator.GetResult(); return result.IsVerified(signKey.Signature.GetBytes()); } /// /// Return the ASN.1 encoding of the certReqMsg we wrap. /// /// a byte array containing the binary encoding of the certReqMsg. public byte[] GetEncoded() { return certReqMsg.GetEncoded(); } } }