TlsDHKeyExchange.cs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.Collections;
  5. using System.IO;
  6. using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.X509;
  7. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
  8. using BestHTTP.SecureProtocol.Org.BouncyCastle.Security;
  9. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Tls
  10. {
  11. /// <summary>(D)TLS DH key exchange.</summary>
  12. public class TlsDHKeyExchange
  13. : AbstractTlsKeyExchange
  14. {
  15. protected TlsSigner mTlsSigner;
  16. protected TlsDHVerifier mDHVerifier;
  17. protected DHParameters mDHParameters;
  18. protected AsymmetricKeyParameter mServerPublicKey;
  19. protected TlsAgreementCredentials mAgreementCredentials;
  20. protected DHPrivateKeyParameters mDHAgreePrivateKey;
  21. protected DHPublicKeyParameters mDHAgreePublicKey;
  22. [Obsolete("Use constructor that takes a TlsDHVerifier")]
  23. public TlsDHKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, DHParameters dhParameters)
  24. : this(keyExchange, supportedSignatureAlgorithms, new DefaultTlsDHVerifier(), dhParameters)
  25. {
  26. }
  27. public TlsDHKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, TlsDHVerifier dhVerifier, DHParameters dhParameters)
  28. : base(keyExchange, supportedSignatureAlgorithms)
  29. {
  30. switch (keyExchange)
  31. {
  32. case KeyExchangeAlgorithm.DH_anon:
  33. case KeyExchangeAlgorithm.DH_RSA:
  34. case KeyExchangeAlgorithm.DH_DSS:
  35. this.mTlsSigner = null;
  36. break;
  37. case KeyExchangeAlgorithm.DHE_RSA:
  38. this.mTlsSigner = new TlsRsaSigner();
  39. break;
  40. case KeyExchangeAlgorithm.DHE_DSS:
  41. this.mTlsSigner = new TlsDssSigner();
  42. break;
  43. default:
  44. throw new InvalidOperationException("unsupported key exchange algorithm");
  45. }
  46. this.mDHVerifier = dhVerifier;
  47. this.mDHParameters = dhParameters;
  48. }
  49. public override void Init(TlsContext context)
  50. {
  51. base.Init(context);
  52. if (this.mTlsSigner != null)
  53. {
  54. this.mTlsSigner.Init(context);
  55. }
  56. }
  57. public override void SkipServerCredentials()
  58. {
  59. if (mKeyExchange != KeyExchangeAlgorithm.DH_anon)
  60. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  61. }
  62. public override void ProcessServerCertificate(Certificate serverCertificate)
  63. {
  64. if (mKeyExchange == KeyExchangeAlgorithm.DH_anon)
  65. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  66. if (serverCertificate.IsEmpty)
  67. throw new TlsFatalAlert(AlertDescription.bad_certificate);
  68. X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0);
  69. SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
  70. try
  71. {
  72. this.mServerPublicKey = PublicKeyFactory.CreateKey(keyInfo);
  73. }
  74. catch (Exception e)
  75. {
  76. throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e);
  77. }
  78. if (mTlsSigner == null)
  79. {
  80. try
  81. {
  82. this.mDHAgreePublicKey = (DHPublicKeyParameters)this.mServerPublicKey;
  83. this.mDHParameters = mDHAgreePublicKey.Parameters;
  84. }
  85. catch (InvalidCastException e)
  86. {
  87. throw new TlsFatalAlert(AlertDescription.certificate_unknown, e);
  88. }
  89. TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyAgreement);
  90. }
  91. else
  92. {
  93. if (!mTlsSigner.IsValidPublicKey(this.mServerPublicKey))
  94. {
  95. throw new TlsFatalAlert(AlertDescription.certificate_unknown);
  96. }
  97. TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
  98. }
  99. base.ProcessServerCertificate(serverCertificate);
  100. }
  101. public override bool RequiresServerKeyExchange
  102. {
  103. get
  104. {
  105. switch (mKeyExchange)
  106. {
  107. case KeyExchangeAlgorithm.DH_anon:
  108. case KeyExchangeAlgorithm.DHE_DSS:
  109. case KeyExchangeAlgorithm.DHE_RSA:
  110. return true;
  111. default:
  112. return false;
  113. }
  114. }
  115. }
  116. public override byte[] GenerateServerKeyExchange()
  117. {
  118. if (!RequiresServerKeyExchange)
  119. return null;
  120. // DH_anon is handled here, DHE_* in a subclass
  121. MemoryStream buf = new MemoryStream();
  122. this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom,
  123. this.mDHParameters, buf);
  124. return buf.ToArray();
  125. }
  126. public override void ProcessServerKeyExchange(Stream input)
  127. {
  128. if (!RequiresServerKeyExchange)
  129. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  130. // DH_anon is handled here, DHE_* in a subclass
  131. this.mDHParameters = TlsDHUtilities.ReceiveDHParameters(mDHVerifier, input);
  132. this.mDHAgreePublicKey = new DHPublicKeyParameters(TlsDHUtilities.ReadDHParameter(input), mDHParameters);
  133. }
  134. public override void ValidateCertificateRequest(CertificateRequest certificateRequest)
  135. {
  136. if (mKeyExchange == KeyExchangeAlgorithm.DH_anon)
  137. throw new TlsFatalAlert(AlertDescription.handshake_failure);
  138. byte[] types = certificateRequest.CertificateTypes;
  139. for (int i = 0; i < types.Length; ++i)
  140. {
  141. switch (types[i])
  142. {
  143. case ClientCertificateType.rsa_sign:
  144. case ClientCertificateType.dss_sign:
  145. case ClientCertificateType.rsa_fixed_dh:
  146. case ClientCertificateType.dss_fixed_dh:
  147. case ClientCertificateType.ecdsa_sign:
  148. break;
  149. default:
  150. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  151. }
  152. }
  153. }
  154. public override void ProcessClientCredentials(TlsCredentials clientCredentials)
  155. {
  156. if (mKeyExchange == KeyExchangeAlgorithm.DH_anon)
  157. throw new TlsFatalAlert(AlertDescription.internal_error);
  158. if (clientCredentials is TlsAgreementCredentials)
  159. {
  160. // TODO Validate client cert has matching parameters (see 'areCompatibleParameters')?
  161. this.mAgreementCredentials = (TlsAgreementCredentials)clientCredentials;
  162. }
  163. else if (clientCredentials is TlsSignerCredentials)
  164. {
  165. // OK
  166. }
  167. else
  168. {
  169. throw new TlsFatalAlert(AlertDescription.internal_error);
  170. }
  171. }
  172. public override void GenerateClientKeyExchange(Stream output)
  173. {
  174. /*
  175. * RFC 2246 7.4.7.2 If the client certificate already contains a suitable Diffie-Hellman
  176. * key, then Yc is implicit and does not need to be sent again. In this case, the Client Key
  177. * Exchange message will be sent, but will be empty.
  178. */
  179. if (mAgreementCredentials == null)
  180. {
  181. this.mDHAgreePrivateKey = TlsDHUtilities.GenerateEphemeralClientKeyExchange(mContext.SecureRandom,
  182. mDHParameters, output);
  183. }
  184. }
  185. public override void ProcessClientCertificate(Certificate clientCertificate)
  186. {
  187. if (mKeyExchange == KeyExchangeAlgorithm.DH_anon)
  188. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  189. // TODO Extract the public key
  190. // TODO If the certificate is 'fixed', take the public key as dhAgreePublicKey
  191. }
  192. public override void ProcessClientKeyExchange(Stream input)
  193. {
  194. if (mDHAgreePublicKey != null)
  195. {
  196. // For dss_fixed_dh and rsa_fixed_dh, the key arrived in the client certificate
  197. return;
  198. }
  199. this.mDHAgreePublicKey = new DHPublicKeyParameters(TlsDHUtilities.ReadDHParameter(input), mDHParameters);
  200. }
  201. public override byte[] GeneratePremasterSecret()
  202. {
  203. if (mAgreementCredentials != null)
  204. {
  205. return mAgreementCredentials.GenerateAgreement(mDHAgreePublicKey);
  206. }
  207. if (mDHAgreePrivateKey != null)
  208. {
  209. return TlsDHUtilities.CalculateDHBasicAgreement(mDHAgreePublicKey, mDHAgreePrivateKey);
  210. }
  211. throw new TlsFatalAlert(AlertDescription.internal_error);
  212. }
  213. }
  214. }
  215. #pragma warning restore
  216. #endif