TlsECDHKeyExchange.cs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  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 ECDH key exchange (see RFC 4492).</summary>
  12. public class TlsECDHKeyExchange
  13. : AbstractTlsKeyExchange
  14. {
  15. protected TlsSigner mTlsSigner;
  16. protected int[] mNamedCurves;
  17. protected byte[] mClientECPointFormats, mServerECPointFormats;
  18. protected AsymmetricKeyParameter mServerPublicKey;
  19. protected TlsAgreementCredentials mAgreementCredentials;
  20. protected ECPrivateKeyParameters mECAgreePrivateKey;
  21. protected ECPublicKeyParameters mECAgreePublicKey;
  22. public TlsECDHKeyExchange(int keyExchange, IList supportedSignatureAlgorithms, int[] namedCurves,
  23. byte[] clientECPointFormats, byte[] serverECPointFormats)
  24. : base(keyExchange, supportedSignatureAlgorithms)
  25. {
  26. switch (keyExchange)
  27. {
  28. case KeyExchangeAlgorithm.ECDHE_RSA:
  29. this.mTlsSigner = new TlsRsaSigner();
  30. break;
  31. case KeyExchangeAlgorithm.ECDHE_ECDSA:
  32. this.mTlsSigner = new TlsECDsaSigner();
  33. break;
  34. case KeyExchangeAlgorithm.ECDH_anon:
  35. case KeyExchangeAlgorithm.ECDH_RSA:
  36. case KeyExchangeAlgorithm.ECDH_ECDSA:
  37. this.mTlsSigner = null;
  38. break;
  39. default:
  40. throw new InvalidOperationException("unsupported key exchange algorithm");
  41. }
  42. this.mNamedCurves = namedCurves;
  43. this.mClientECPointFormats = clientECPointFormats;
  44. this.mServerECPointFormats = serverECPointFormats;
  45. }
  46. public override void Init(TlsContext context)
  47. {
  48. base.Init(context);
  49. if (this.mTlsSigner != null)
  50. {
  51. this.mTlsSigner.Init(context);
  52. }
  53. }
  54. public override void SkipServerCredentials()
  55. {
  56. if (mKeyExchange != KeyExchangeAlgorithm.ECDH_anon)
  57. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  58. }
  59. public override void ProcessServerCertificate(Certificate serverCertificate)
  60. {
  61. if (mKeyExchange == KeyExchangeAlgorithm.ECDH_anon)
  62. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  63. if (serverCertificate.IsEmpty)
  64. throw new TlsFatalAlert(AlertDescription.bad_certificate);
  65. X509CertificateStructure x509Cert = serverCertificate.GetCertificateAt(0);
  66. SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
  67. try
  68. {
  69. this.mServerPublicKey = PublicKeyFactory.CreateKey(keyInfo);
  70. }
  71. catch (Exception e)
  72. {
  73. throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e);
  74. }
  75. if (mTlsSigner == null)
  76. {
  77. try
  78. {
  79. this.mECAgreePublicKey = TlsEccUtilities.ValidateECPublicKey((ECPublicKeyParameters) this.mServerPublicKey);
  80. }
  81. catch (InvalidCastException e)
  82. {
  83. throw new TlsFatalAlert(AlertDescription.certificate_unknown, e);
  84. }
  85. TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyAgreement);
  86. }
  87. else
  88. {
  89. if (!mTlsSigner.IsValidPublicKey(this.mServerPublicKey))
  90. throw new TlsFatalAlert(AlertDescription.certificate_unknown);
  91. TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature);
  92. }
  93. base.ProcessServerCertificate(serverCertificate);
  94. }
  95. public override bool RequiresServerKeyExchange
  96. {
  97. get
  98. {
  99. switch (mKeyExchange)
  100. {
  101. case KeyExchangeAlgorithm.ECDH_anon:
  102. case KeyExchangeAlgorithm.ECDHE_ECDSA:
  103. case KeyExchangeAlgorithm.ECDHE_RSA:
  104. return true;
  105. default:
  106. return false;
  107. }
  108. }
  109. }
  110. public override byte[] GenerateServerKeyExchange()
  111. {
  112. if (!RequiresServerKeyExchange)
  113. return null;
  114. // ECDH_anon is handled here, ECDHE_* in a subclass
  115. MemoryStream buf = new MemoryStream();
  116. this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralServerKeyExchange(mContext.SecureRandom, mNamedCurves,
  117. mClientECPointFormats, buf);
  118. return buf.ToArray();
  119. }
  120. public override void ProcessServerKeyExchange(Stream input)
  121. {
  122. if (!RequiresServerKeyExchange)
  123. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  124. // ECDH_anon is handled here, ECDHE_* in a subclass
  125. ECDomainParameters curve_params = TlsEccUtilities.ReadECParameters(mNamedCurves, mClientECPointFormats, input);
  126. byte[] point = TlsUtilities.ReadOpaque8(input);
  127. this.mECAgreePublicKey = TlsEccUtilities.ValidateECPublicKey(TlsEccUtilities.DeserializeECPublicKey(
  128. mClientECPointFormats, curve_params, point));
  129. }
  130. public override void ValidateCertificateRequest(CertificateRequest certificateRequest)
  131. {
  132. if (mKeyExchange == KeyExchangeAlgorithm.ECDH_anon)
  133. throw new TlsFatalAlert(AlertDescription.handshake_failure);
  134. /*
  135. * RFC 4492 3. [...] The ECDSA_fixed_ECDH and RSA_fixed_ECDH mechanisms are usable with
  136. * ECDH_ECDSA and ECDH_RSA. Their use with ECDHE_ECDSA and ECDHE_RSA is prohibited because
  137. * the use of a long-term ECDH client key would jeopardize the forward secrecy property of
  138. * these algorithms.
  139. */
  140. byte[] types = certificateRequest.CertificateTypes;
  141. for (int i = 0; i < types.Length; ++i)
  142. {
  143. switch (types[i])
  144. {
  145. case ClientCertificateType.rsa_sign:
  146. case ClientCertificateType.dss_sign:
  147. case ClientCertificateType.ecdsa_sign:
  148. case ClientCertificateType.rsa_fixed_ecdh:
  149. case ClientCertificateType.ecdsa_fixed_ecdh:
  150. break;
  151. default:
  152. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  153. }
  154. }
  155. }
  156. public override void ProcessClientCredentials(TlsCredentials clientCredentials)
  157. {
  158. if (mKeyExchange == KeyExchangeAlgorithm.ECDH_anon)
  159. throw new TlsFatalAlert(AlertDescription.internal_error);
  160. if (clientCredentials is TlsAgreementCredentials)
  161. {
  162. // TODO Validate client cert has matching parameters (see 'TlsEccUtilities.AreOnSameCurve')?
  163. this.mAgreementCredentials = (TlsAgreementCredentials)clientCredentials;
  164. }
  165. else if (clientCredentials is TlsSignerCredentials)
  166. {
  167. // OK
  168. }
  169. else
  170. {
  171. throw new TlsFatalAlert(AlertDescription.internal_error);
  172. }
  173. }
  174. public override void GenerateClientKeyExchange(Stream output)
  175. {
  176. if (mAgreementCredentials == null)
  177. {
  178. this.mECAgreePrivateKey = TlsEccUtilities.GenerateEphemeralClientKeyExchange(mContext.SecureRandom,
  179. mServerECPointFormats, mECAgreePublicKey.Parameters, output);
  180. }
  181. }
  182. public override void ProcessClientCertificate(Certificate clientCertificate)
  183. {
  184. if (mKeyExchange == KeyExchangeAlgorithm.ECDH_anon)
  185. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  186. // TODO Extract the public key
  187. // TODO If the certificate is 'fixed', take the public key as mECAgreeClientPublicKey
  188. }
  189. public override void ProcessClientKeyExchange(Stream input)
  190. {
  191. if (mECAgreePublicKey != null)
  192. {
  193. // For ecdsa_fixed_ecdh and rsa_fixed_ecdh, the key arrived in the client certificate
  194. return;
  195. }
  196. byte[] point = TlsUtilities.ReadOpaque8(input);
  197. ECDomainParameters curve_params = this.mECAgreePrivateKey.Parameters;
  198. this.mECAgreePublicKey = TlsEccUtilities.ValidateECPublicKey(TlsEccUtilities.DeserializeECPublicKey(
  199. mServerECPointFormats, curve_params, point));
  200. }
  201. public override byte[] GeneratePremasterSecret()
  202. {
  203. if (mAgreementCredentials != null)
  204. {
  205. return mAgreementCredentials.GenerateAgreement(mECAgreePublicKey);
  206. }
  207. if (mECAgreePrivateKey != null)
  208. {
  209. return TlsEccUtilities.CalculateECDHBasicAgreement(mECAgreePublicKey, mECAgreePrivateKey);
  210. }
  211. throw new TlsFatalAlert(AlertDescription.internal_error);
  212. }
  213. }
  214. }
  215. #pragma warning restore
  216. #endif