AbstractTlsContext.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.IO;
  5. using System.Threading;
  6. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
  7. using BestHTTP.SecureProtocol.Org.BouncyCastle.Tls.Crypto;
  8. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  9. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Tls
  10. {
  11. internal abstract class AbstractTlsContext
  12. : TlsContext
  13. {
  14. private static long counter = Times.NanoTime();
  15. #if NETCF_1_0
  16. private static object counterLock = new object();
  17. private static long NextCounterValue()
  18. {
  19. lock (counterLock)
  20. {
  21. return ++counter;
  22. }
  23. }
  24. #else
  25. private static long NextCounterValue()
  26. {
  27. return Interlocked.Increment(ref counter);
  28. }
  29. #endif
  30. private static TlsNonceGenerator CreateNonceGenerator(TlsCrypto crypto, int connectionEnd)
  31. {
  32. byte[] additionalSeedMaterial = new byte[16];
  33. Pack.UInt64_To_BE((ulong)NextCounterValue(), additionalSeedMaterial, 0);
  34. Pack.UInt64_To_BE((ulong)Times.NanoTime(), additionalSeedMaterial, 8);
  35. additionalSeedMaterial[0] &= 0x7F;
  36. additionalSeedMaterial[0] |= (byte)(connectionEnd << 7);
  37. return crypto.CreateNonceGenerator(additionalSeedMaterial);
  38. }
  39. private readonly TlsCrypto m_crypto;
  40. private readonly int m_connectionEnd;
  41. private readonly TlsNonceGenerator m_nonceGenerator;
  42. private SecurityParameters m_securityParameters = null;
  43. private ProtocolVersion[] m_clientSupportedVersions = null;
  44. private ProtocolVersion m_clientVersion = null;
  45. private ProtocolVersion m_rsaPreMasterSecretVersion = null;
  46. private TlsSession m_session = null;
  47. private object m_userObject = null;
  48. private bool m_connected = false;
  49. internal AbstractTlsContext(TlsCrypto crypto, int connectionEnd)
  50. {
  51. this.m_crypto = crypto;
  52. this.m_connectionEnd = connectionEnd;
  53. this.m_nonceGenerator = CreateNonceGenerator(crypto, connectionEnd);
  54. }
  55. /// <exception cref="IOException"/>
  56. internal void HandshakeBeginning(TlsPeer peer)
  57. {
  58. lock (this)
  59. {
  60. //if (null != m_securityParameters)
  61. // throw new TlsFatalAlert(AlertDescription.internal_error, "Handshake already started");
  62. var tmp = this.m_securityParameters;
  63. m_securityParameters = new SecurityParameters();
  64. m_securityParameters.m_entity = m_connectionEnd;
  65. if (tmp != null)
  66. {
  67. this.m_securityParameters.IsRenegotiating = true;
  68. this.m_securityParameters.m_secureRenegotiation = tmp.m_secureRenegotiation;
  69. this.m_securityParameters.m_negotiatedVersion = tmp.m_negotiatedVersion;
  70. this.m_securityParameters.m_localVerifyData = tmp.m_localVerifyData;
  71. this.m_securityParameters.m_peerVerifyData = tmp.m_peerVerifyData;
  72. this.m_securityParameters.PreRenegotiatingServerCert = tmp.m_peerCertificate;
  73. }
  74. }
  75. peer.NotifyHandshakeBeginning();
  76. }
  77. /// <exception cref="IOException"/>
  78. internal void HandshakeComplete(TlsPeer peer, TlsSession session)
  79. {
  80. lock (this)
  81. {
  82. if (null == m_securityParameters)
  83. throw new TlsFatalAlert(AlertDescription.internal_error);
  84. this.m_session = session;
  85. this.m_connected = true;
  86. }
  87. peer.NotifyHandshakeComplete();
  88. }
  89. internal bool IsConnected
  90. {
  91. get { lock (this) return m_connected; }
  92. }
  93. internal bool IsHandshaking
  94. {
  95. get { lock (this) return !m_connected && null != m_securityParameters; }
  96. }
  97. public TlsCrypto Crypto
  98. {
  99. get { return m_crypto; }
  100. }
  101. public virtual TlsNonceGenerator NonceGenerator
  102. {
  103. get { return m_nonceGenerator; }
  104. }
  105. public SecurityParameters SecurityParameters
  106. {
  107. get { lock (this) return m_securityParameters; }
  108. }
  109. public abstract bool IsServer { get; }
  110. public virtual ProtocolVersion[] ClientSupportedVersions
  111. {
  112. get { return m_clientSupportedVersions; }
  113. }
  114. internal void SetClientSupportedVersions(ProtocolVersion[] clientSupportedVersions)
  115. {
  116. this.m_clientSupportedVersions = clientSupportedVersions;
  117. }
  118. public virtual ProtocolVersion ClientVersion
  119. {
  120. get { return m_clientVersion; }
  121. }
  122. internal void SetClientVersion(ProtocolVersion clientVersion)
  123. {
  124. this.m_clientVersion = clientVersion;
  125. }
  126. public virtual ProtocolVersion RsaPreMasterSecretVersion
  127. {
  128. get { return m_rsaPreMasterSecretVersion; }
  129. }
  130. internal void SetRsaPreMasterSecretVersion(ProtocolVersion rsaPreMasterSecretVersion)
  131. {
  132. this.m_rsaPreMasterSecretVersion = rsaPreMasterSecretVersion;
  133. }
  134. public virtual ProtocolVersion ServerVersion
  135. {
  136. get { return SecurityParameters.NegotiatedVersion; }
  137. }
  138. public virtual TlsSession ResumableSession
  139. {
  140. get
  141. {
  142. TlsSession session = Session;
  143. if (session == null || !session.IsResumable)
  144. return null;
  145. return session;
  146. }
  147. }
  148. public virtual TlsSession Session
  149. {
  150. get { return m_session; }
  151. }
  152. public virtual object UserObject
  153. {
  154. get { return m_userObject; }
  155. set { this.m_userObject = value; }
  156. }
  157. public virtual byte[] ExportChannelBinding(int channelBinding)
  158. {
  159. if (!IsConnected)
  160. throw new InvalidOperationException("Export of channel bindings unavailable before handshake completion");
  161. SecurityParameters securityParameters = SecurityParameters;
  162. if (TlsUtilities.IsTlsV13(securityParameters.NegotiatedVersion))
  163. return null;
  164. switch (channelBinding)
  165. {
  166. case ChannelBinding.tls_server_end_point:
  167. {
  168. byte[] tlsServerEndPoint = securityParameters.TlsServerEndPoint;
  169. return TlsUtilities.IsNullOrEmpty(tlsServerEndPoint) ? null : Arrays.Clone(tlsServerEndPoint);
  170. }
  171. case ChannelBinding.tls_unique:
  172. {
  173. return Arrays.Clone(securityParameters.TlsUnique);
  174. }
  175. case ChannelBinding.tls_unique_for_telnet:
  176. default:
  177. throw new NotSupportedException();
  178. }
  179. }
  180. public virtual byte[] ExportEarlyKeyingMaterial(string asciiLabel, byte[] context, int length)
  181. {
  182. // TODO[tls13] Ensure early_exporter_master_secret is available suitably early!
  183. if (!IsConnected)
  184. throw new InvalidOperationException("Export of early key material only available during handshake");
  185. SecurityParameters sp = SecurityParameters;
  186. return ExportKeyingMaterial13(CheckEarlyExportSecret(sp.EarlyExporterMasterSecret),
  187. sp.PrfCryptoHashAlgorithm, asciiLabel, context, length);
  188. }
  189. public virtual byte[] ExportKeyingMaterial(string asciiLabel, byte[] context, int length)
  190. {
  191. if (!IsConnected)
  192. throw new InvalidOperationException("Export of key material unavailable before handshake completion");
  193. /*
  194. * TODO[tls13] Introduce a TlsExporter interface? Avoid calculating (early) exporter
  195. * secret(s) unless the peer actually uses it.
  196. */
  197. SecurityParameters sp = SecurityParameters;
  198. if (!sp.IsExtendedMasterSecret)
  199. {
  200. /*
  201. * RFC 7627 5.4. If a client or server chooses to continue with a full handshake without
  202. * the extended master secret extension, [..] the client or server MUST NOT export any
  203. * key material based on the new master secret for any subsequent application-level
  204. * authentication. In particular, it MUST disable [RFC5705] [..].
  205. */
  206. throw new InvalidOperationException("Export of key material requires extended_master_secret");
  207. }
  208. if (TlsUtilities.IsTlsV13(sp.NegotiatedVersion))
  209. {
  210. return ExportKeyingMaterial13(CheckExportSecret(sp.ExporterMasterSecret), sp.PrfCryptoHashAlgorithm,
  211. asciiLabel, context, length);
  212. }
  213. byte[] seed = TlsUtilities.CalculateExporterSeed(sp, context);
  214. return TlsUtilities.Prf(sp, CheckExportSecret(sp.MasterSecret), asciiLabel, seed, length).Extract();
  215. }
  216. protected virtual byte[] ExportKeyingMaterial13(TlsSecret secret, int cryptoHashAlgorithm, string asciiLabel,
  217. byte[] context, int length)
  218. {
  219. if (null == context)
  220. {
  221. context = TlsUtilities.EmptyBytes;
  222. }
  223. else if (!TlsUtilities.IsValidUint16(context.Length))
  224. {
  225. throw new ArgumentException("must have length less than 2^16 (or be null)", "context");
  226. }
  227. return TlsCryptoUtilities.HkdfExpandLabel(secret, cryptoHashAlgorithm, asciiLabel, context, length)
  228. .Extract();
  229. }
  230. protected virtual TlsSecret CheckEarlyExportSecret(TlsSecret secret)
  231. {
  232. if (null == secret)
  233. {
  234. // TODO[tls13] For symmetry with normal export, ideally available for NotifyHandshakeBeginning() only
  235. //throw new InvalidOperationException("Export of early key material only available from NotifyHandshakeBeginning()");
  236. throw new InvalidOperationException("Export of early key material not available for this handshake");
  237. }
  238. return secret;
  239. }
  240. protected virtual TlsSecret CheckExportSecret(TlsSecret secret)
  241. {
  242. if (null == secret)
  243. throw new InvalidOperationException(
  244. "Export of key material only available from NotifyHandshakeComplete()");
  245. return secret;
  246. }
  247. }
  248. }
  249. #pragma warning restore
  250. #endif