ProtectedPkiMessage.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Asn1;
  5. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Asn1.Cmp;
  6. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Asn1.X509;
  7. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crmf;
  8. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto;
  9. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  10. using Best.HTTP.SecureProtocol.Org.BouncyCastle.X509;
  11. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Cmp
  12. {
  13. /// <summary>
  14. /// Wrapper for a PKIMessage with protection attached to it.
  15. /// </summary>
  16. public class ProtectedPkiMessage
  17. {
  18. private readonly PkiMessage m_pkiMessage;
  19. /// <summary>
  20. /// Wrap a general message.
  21. /// </summary>
  22. /// <exception cref="ArgumentException">If the general message does not have protection.</exception>
  23. /// <param name="pkiMessage">The General message</param>
  24. public ProtectedPkiMessage(GeneralPkiMessage pkiMessage)
  25. {
  26. if (!pkiMessage.HasProtection)
  27. throw new ArgumentException("GeneralPkiMessage not protected");
  28. this.m_pkiMessage = pkiMessage.ToAsn1Structure();
  29. }
  30. // TODO[cmp] Make internal? (Has test that uses it)
  31. /// <summary>
  32. /// Wrap a PKI message.
  33. /// </summary>
  34. /// <exception cref="ArgumentException">If the PKI message does not have protection.</exception>
  35. /// <param name="pkiMessage">The PKI message</param>
  36. public ProtectedPkiMessage(PkiMessage pkiMessage)
  37. {
  38. if (null == pkiMessage.Header.ProtectionAlg)
  39. throw new ArgumentException("PkiMessage not protected");
  40. this.m_pkiMessage = pkiMessage;
  41. }
  42. /// <summary>Message header</summary>
  43. public virtual PkiHeader Header => m_pkiMessage.Header;
  44. /// <summary>Message body</summary>
  45. public virtual PkiBody Body => m_pkiMessage.Body;
  46. /// <summary>
  47. /// Return the underlying ASN.1 structure contained in this object.
  48. /// </summary>
  49. /// <returns>PkiMessage structure</returns>
  50. public virtual PkiMessage ToAsn1Message() => m_pkiMessage;
  51. /// <summary>
  52. /// Determine whether the message is protected by a password based MAC. Use verify(PKMACBuilder, char[])
  53. /// to verify the message if this method returns true.
  54. /// </summary>
  55. /// <returns>true if protection MAC PBE based, false otherwise.</returns>
  56. public virtual bool HasPasswordBasedMacProtected
  57. {
  58. get { return CmpObjectIdentifiers.passwordBasedMac.Equals(Header.ProtectionAlg.Algorithm); }
  59. }
  60. /// <summary>
  61. /// Return the extra certificates associated with this message.
  62. /// </summary>
  63. /// <returns>an array of extra certificates, zero length if none present.</returns>
  64. public virtual X509Certificate[] GetCertificates()
  65. {
  66. CmpCertificate[] certs = m_pkiMessage.GetExtraCerts();
  67. if (null == certs)
  68. return new X509Certificate[0];
  69. X509Certificate[] result = new X509Certificate[certs.Length];
  70. for (int t = 0; t < certs.Length; t++)
  71. {
  72. result[t] = new X509Certificate(certs[t].X509v3PKCert);
  73. }
  74. return result;
  75. }
  76. /// <summary>
  77. /// Verify a message with a public key based signature attached.
  78. /// </summary>
  79. /// <param name="verifierFactory">a factory of signature verifiers.</param>
  80. /// <returns>true if the provider is able to create a verifier that validates the signature, false otherwise.</returns>
  81. public virtual bool Verify(IVerifierFactory verifierFactory)
  82. {
  83. IStreamCalculator<IVerifier> streamCalculator = verifierFactory.CreateCalculator();
  84. IVerifier result = Process(streamCalculator);
  85. return result.IsVerified(m_pkiMessage.Protection.GetBytes());
  86. }
  87. /// <summary>
  88. /// Verify a message with password based MAC protection.
  89. /// </summary>
  90. /// <param name="pkMacBuilder">MAC builder that can be used to construct the appropriate MacCalculator</param>
  91. /// <param name="password">the MAC password</param>
  92. /// <returns>true if the passed in password and MAC builder verify the message, false otherwise.</returns>
  93. /// <exception cref="InvalidOperationException">if algorithm not MAC based, or an exception is thrown verifying the MAC.</exception>
  94. public virtual bool Verify(PKMacBuilder pkMacBuilder, char[] password)
  95. {
  96. if (!CmpObjectIdentifiers.passwordBasedMac.Equals(m_pkiMessage.Header.ProtectionAlg.Algorithm))
  97. throw new InvalidOperationException("protection algorithm is not mac based");
  98. PbmParameter parameter = PbmParameter.GetInstance(m_pkiMessage.Header.ProtectionAlg.Parameters);
  99. pkMacBuilder.SetParameters(parameter);
  100. IBlockResult result = Process(pkMacBuilder.Build(password).CreateCalculator());
  101. return Arrays.ConstantTimeAreEqual(result.Collect(), m_pkiMessage.Protection.GetBytes());
  102. }
  103. private TResult Process<TResult>(IStreamCalculator<TResult> streamCalculator)
  104. {
  105. Asn1EncodableVector avec = new Asn1EncodableVector();
  106. avec.Add(m_pkiMessage.Header);
  107. avec.Add(m_pkiMessage.Body);
  108. byte[] enc = new DerSequence(avec).GetDerEncoded();
  109. using (var stream = streamCalculator.Stream)
  110. {
  111. stream.Write(enc, 0, enc.Length);
  112. }
  113. return streamCalculator.GetResult();
  114. }
  115. }
  116. }
  117. #pragma warning restore
  118. #endif