TlsClientProtocol.cs 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. using System;
  3. using System.Collections;
  4. using System.IO;
  5. using Org.BouncyCastle.Security;
  6. using Org.BouncyCastle.Utilities;
  7. namespace Org.BouncyCastle.Crypto.Tls
  8. {
  9. public class TlsClientProtocol
  10. : TlsProtocol
  11. {
  12. protected TlsClient mTlsClient = null;
  13. internal TlsClientContextImpl mTlsClientContext = null;
  14. protected byte[] mSelectedSessionID = null;
  15. protected TlsKeyExchange mKeyExchange = null;
  16. protected TlsAuthentication mAuthentication = null;
  17. protected CertificateStatus mCertificateStatus = null;
  18. protected CertificateRequest mCertificateRequest = null;
  19. /**
  20. * Constructor for blocking mode.
  21. * @param stream The bi-directional stream of data to/from the server
  22. * @param secureRandom Random number generator for various cryptographic functions
  23. */
  24. public TlsClientProtocol(Stream stream, SecureRandom secureRandom)
  25. : base(stream, secureRandom)
  26. {
  27. }
  28. /**
  29. * Constructor for blocking mode.
  30. * @param input The stream of data from the server
  31. * @param output The stream of data to the server
  32. * @param secureRandom Random number generator for various cryptographic functions
  33. */
  34. public TlsClientProtocol(Stream input, Stream output, SecureRandom secureRandom)
  35. : base(input, output, secureRandom)
  36. {
  37. }
  38. /**
  39. * Constructor for non-blocking mode.<br/>
  40. * <br/>
  41. * When data is received, use {@link #offerInput(java.nio.ByteBuffer)} to
  42. * provide the received ciphertext, then use
  43. * {@link #readInput(byte[], int, int)} to read the corresponding cleartext.<br/>
  44. * <br/>
  45. * Similarly, when data needs to be sent, use
  46. * {@link #offerOutput(byte[], int, int)} to provide the cleartext, then use
  47. * {@link #readOutput(byte[], int, int)} to get the corresponding
  48. * ciphertext.
  49. *
  50. * @param secureRandom
  51. * Random number generator for various cryptographic functions
  52. */
  53. public TlsClientProtocol(SecureRandom secureRandom)
  54. : base(secureRandom)
  55. {
  56. }
  57. /**
  58. * Initiates a TLS handshake in the role of client.<br/>
  59. * <br/>
  60. * In blocking mode, this will not return until the handshake is complete.
  61. * In non-blocking mode, use {@link TlsPeer#NotifyHandshakeComplete()} to
  62. * receive a Callback when the handshake is complete.
  63. *
  64. * @param tlsClient The {@link TlsClient} to use for the handshake.
  65. * @throws IOException If in blocking mode and handshake was not successful.
  66. */
  67. public virtual void Connect(TlsClient tlsClient)
  68. {
  69. if (tlsClient == null)
  70. throw new ArgumentNullException("tlsClient");
  71. if (this.mTlsClient != null)
  72. throw new InvalidOperationException("'Connect' can only be called once");
  73. this.mTlsClient = tlsClient;
  74. this.mSecurityParameters = new SecurityParameters();
  75. this.mSecurityParameters.entity = ConnectionEnd.client;
  76. this.mTlsClientContext = new TlsClientContextImpl(mSecureRandom, mSecurityParameters);
  77. this.mSecurityParameters.clientRandom = CreateRandomBlock(tlsClient.ShouldUseGmtUnixTime(),
  78. mTlsClientContext.NonceRandomGenerator);
  79. this.mTlsClient.Init(mTlsClientContext);
  80. this.mRecordStream.Init(mTlsClientContext);
  81. TlsSession sessionToResume = tlsClient.GetSessionToResume();
  82. if (sessionToResume != null && sessionToResume.IsResumable)
  83. {
  84. SessionParameters sessionParameters = sessionToResume.ExportSessionParameters();
  85. if (sessionParameters != null)
  86. {
  87. this.mTlsSession = sessionToResume;
  88. this.mSessionParameters = sessionParameters;
  89. }
  90. }
  91. SendClientHelloMessage();
  92. this.mConnectionState = CS_CLIENT_HELLO;
  93. BlockForHandshake();
  94. }
  95. protected override void CleanupHandshake()
  96. {
  97. base.CleanupHandshake();
  98. this.mSelectedSessionID = null;
  99. this.mKeyExchange = null;
  100. this.mAuthentication = null;
  101. this.mCertificateStatus = null;
  102. this.mCertificateRequest = null;
  103. }
  104. protected override TlsContext Context
  105. {
  106. get { return mTlsClientContext; }
  107. }
  108. internal override AbstractTlsContext ContextAdmin
  109. {
  110. get { return mTlsClientContext; }
  111. }
  112. protected override TlsPeer Peer
  113. {
  114. get { return mTlsClient; }
  115. }
  116. protected override void HandleHandshakeMessage(byte type, byte[] data)
  117. {
  118. MemoryStream buf = new MemoryStream(data, false);
  119. if (this.mResumedSession)
  120. {
  121. if (type != HandshakeType.finished || this.mConnectionState != CS_SERVER_HELLO)
  122. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  123. ProcessFinishedMessage(buf);
  124. this.mConnectionState = CS_SERVER_FINISHED;
  125. SendFinishedMessage();
  126. this.mConnectionState = CS_CLIENT_FINISHED;
  127. this.mConnectionState = CS_END;
  128. CompleteHandshake();
  129. return;
  130. }
  131. switch (type)
  132. {
  133. case HandshakeType.certificate:
  134. {
  135. switch (this.mConnectionState)
  136. {
  137. case CS_SERVER_HELLO:
  138. case CS_SERVER_SUPPLEMENTAL_DATA:
  139. {
  140. if (this.mConnectionState == CS_SERVER_HELLO)
  141. {
  142. HandleSupplementalData(null);
  143. }
  144. // Parse the Certificate message and Send to cipher suite
  145. this.mPeerCertificate = Certificate.Parse(buf);
  146. AssertEmpty(buf);
  147. // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus
  148. if (this.mPeerCertificate == null || this.mPeerCertificate.IsEmpty)
  149. {
  150. this.mAllowCertificateStatus = false;
  151. }
  152. this.mKeyExchange.ProcessServerCertificate(this.mPeerCertificate);
  153. this.mAuthentication = mTlsClient.GetAuthentication();
  154. this.mAuthentication.NotifyServerCertificate(this.mPeerCertificate);
  155. break;
  156. }
  157. default:
  158. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  159. }
  160. this.mConnectionState = CS_SERVER_CERTIFICATE;
  161. break;
  162. }
  163. case HandshakeType.certificate_status:
  164. {
  165. switch (this.mConnectionState)
  166. {
  167. case CS_SERVER_CERTIFICATE:
  168. {
  169. if (!this.mAllowCertificateStatus)
  170. {
  171. /*
  172. * RFC 3546 3.6. If a server returns a "CertificateStatus" message, then the
  173. * server MUST have included an extension of type "status_request" with empty
  174. * "extension_data" in the extended server hello..
  175. */
  176. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  177. }
  178. this.mCertificateStatus = CertificateStatus.Parse(buf);
  179. AssertEmpty(buf);
  180. // TODO[RFC 3546] Figure out how to provide this to the client/authentication.
  181. this.mConnectionState = CS_CERTIFICATE_STATUS;
  182. break;
  183. }
  184. default:
  185. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  186. }
  187. break;
  188. }
  189. case HandshakeType.finished:
  190. {
  191. switch (this.mConnectionState)
  192. {
  193. case CS_CLIENT_FINISHED:
  194. case CS_SERVER_SESSION_TICKET:
  195. {
  196. if (this.mConnectionState == CS_CLIENT_FINISHED && this.mExpectSessionTicket)
  197. {
  198. /*
  199. * RFC 5077 3.3. This message MUST be sent if the server included a
  200. * SessionTicket extension in the ServerHello.
  201. */
  202. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  203. }
  204. ProcessFinishedMessage(buf);
  205. this.mConnectionState = CS_SERVER_FINISHED;
  206. this.mConnectionState = CS_END;
  207. CompleteHandshake();
  208. break;
  209. }
  210. default:
  211. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  212. }
  213. break;
  214. }
  215. case HandshakeType.server_hello:
  216. {
  217. switch (this.mConnectionState)
  218. {
  219. case CS_CLIENT_HELLO:
  220. {
  221. ReceiveServerHelloMessage(buf);
  222. this.mConnectionState = CS_SERVER_HELLO;
  223. this.mRecordStream.NotifyHelloComplete();
  224. ApplyMaxFragmentLengthExtension();
  225. if (this.mResumedSession)
  226. {
  227. this.mSecurityParameters.masterSecret = Arrays.Clone(this.mSessionParameters.MasterSecret);
  228. this.mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher());
  229. SendChangeCipherSpecMessage();
  230. }
  231. else
  232. {
  233. InvalidateSession();
  234. if (this.mSelectedSessionID.Length > 0)
  235. {
  236. this.mTlsSession = new TlsSessionImpl(this.mSelectedSessionID, null);
  237. }
  238. }
  239. break;
  240. }
  241. default:
  242. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  243. }
  244. break;
  245. }
  246. case HandshakeType.supplemental_data:
  247. {
  248. switch (this.mConnectionState)
  249. {
  250. case CS_SERVER_HELLO:
  251. {
  252. HandleSupplementalData(ReadSupplementalDataMessage(buf));
  253. break;
  254. }
  255. default:
  256. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  257. }
  258. break;
  259. }
  260. case HandshakeType.server_hello_done:
  261. {
  262. switch (this.mConnectionState)
  263. {
  264. case CS_SERVER_HELLO:
  265. case CS_SERVER_SUPPLEMENTAL_DATA:
  266. case CS_SERVER_CERTIFICATE:
  267. case CS_CERTIFICATE_STATUS:
  268. case CS_SERVER_KEY_EXCHANGE:
  269. case CS_CERTIFICATE_REQUEST:
  270. {
  271. if (mConnectionState < CS_SERVER_SUPPLEMENTAL_DATA)
  272. {
  273. HandleSupplementalData(null);
  274. }
  275. if (mConnectionState < CS_SERVER_CERTIFICATE)
  276. {
  277. // There was no server certificate message; check it's OK
  278. this.mKeyExchange.SkipServerCredentials();
  279. this.mAuthentication = null;
  280. }
  281. if (mConnectionState < CS_SERVER_KEY_EXCHANGE)
  282. {
  283. // There was no server key exchange message; check it's OK
  284. this.mKeyExchange.SkipServerKeyExchange();
  285. }
  286. AssertEmpty(buf);
  287. this.mConnectionState = CS_SERVER_HELLO_DONE;
  288. this.mRecordStream.HandshakeHash.SealHashAlgorithms();
  289. IList clientSupplementalData = mTlsClient.GetClientSupplementalData();
  290. if (clientSupplementalData != null)
  291. {
  292. SendSupplementalDataMessage(clientSupplementalData);
  293. }
  294. this.mConnectionState = CS_CLIENT_SUPPLEMENTAL_DATA;
  295. TlsCredentials clientCreds = null;
  296. if (mCertificateRequest == null)
  297. {
  298. this.mKeyExchange.SkipClientCredentials();
  299. }
  300. else
  301. {
  302. clientCreds = this.mAuthentication.GetClientCredentials(Context, mCertificateRequest);
  303. if (clientCreds == null)
  304. {
  305. this.mKeyExchange.SkipClientCredentials();
  306. /*
  307. * RFC 5246 If no suitable certificate is available, the client MUST Send a
  308. * certificate message containing no certificates.
  309. *
  310. * NOTE: In previous RFCs, this was SHOULD instead of MUST.
  311. */
  312. SendCertificateMessage(Certificate.EmptyChain);
  313. }
  314. else
  315. {
  316. this.mKeyExchange.ProcessClientCredentials(clientCreds);
  317. SendCertificateMessage(clientCreds.Certificate);
  318. }
  319. }
  320. this.mConnectionState = CS_CLIENT_CERTIFICATE;
  321. /*
  322. * Send the client key exchange message, depending on the key exchange we are using
  323. * in our CipherSuite.
  324. */
  325. SendClientKeyExchangeMessage();
  326. this.mConnectionState = CS_CLIENT_KEY_EXCHANGE;
  327. TlsHandshakeHash prepareFinishHash = mRecordStream.PrepareToFinish();
  328. this.mSecurityParameters.sessionHash = GetCurrentPrfHash(Context, prepareFinishHash, null);
  329. EstablishMasterSecret(Context, mKeyExchange);
  330. mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher());
  331. if (clientCreds != null && clientCreds is TlsSignerCredentials)
  332. {
  333. TlsSignerCredentials signerCredentials = (TlsSignerCredentials)clientCreds;
  334. /*
  335. * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2
  336. */
  337. SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm(
  338. Context, signerCredentials);
  339. byte[] hash;
  340. if (signatureAndHashAlgorithm == null)
  341. {
  342. hash = mSecurityParameters.SessionHash;
  343. }
  344. else
  345. {
  346. hash = prepareFinishHash.GetFinalHash(signatureAndHashAlgorithm.Hash);
  347. }
  348. byte[] signature = signerCredentials.GenerateCertificateSignature(hash);
  349. DigitallySigned certificateVerify = new DigitallySigned(signatureAndHashAlgorithm, signature);
  350. SendCertificateVerifyMessage(certificateVerify);
  351. this.mConnectionState = CS_CERTIFICATE_VERIFY;
  352. }
  353. SendChangeCipherSpecMessage();
  354. SendFinishedMessage();
  355. break;
  356. }
  357. default:
  358. throw new TlsFatalAlert(AlertDescription.handshake_failure);
  359. }
  360. this.mConnectionState = CS_CLIENT_FINISHED;
  361. break;
  362. }
  363. case HandshakeType.server_key_exchange:
  364. {
  365. switch (this.mConnectionState)
  366. {
  367. case CS_SERVER_HELLO:
  368. case CS_SERVER_SUPPLEMENTAL_DATA:
  369. case CS_SERVER_CERTIFICATE:
  370. case CS_CERTIFICATE_STATUS:
  371. {
  372. if (mConnectionState < CS_SERVER_SUPPLEMENTAL_DATA)
  373. {
  374. HandleSupplementalData(null);
  375. }
  376. if (mConnectionState < CS_SERVER_CERTIFICATE)
  377. {
  378. // There was no server certificate message; check it's OK
  379. this.mKeyExchange.SkipServerCredentials();
  380. this.mAuthentication = null;
  381. }
  382. this.mKeyExchange.ProcessServerKeyExchange(buf);
  383. AssertEmpty(buf);
  384. break;
  385. }
  386. default:
  387. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  388. }
  389. this.mConnectionState = CS_SERVER_KEY_EXCHANGE;
  390. break;
  391. }
  392. case HandshakeType.certificate_request:
  393. {
  394. switch (this.mConnectionState)
  395. {
  396. case CS_SERVER_CERTIFICATE:
  397. case CS_CERTIFICATE_STATUS:
  398. case CS_SERVER_KEY_EXCHANGE:
  399. {
  400. if (this.mConnectionState != CS_SERVER_KEY_EXCHANGE)
  401. {
  402. // There was no server key exchange message; check it's OK
  403. this.mKeyExchange.SkipServerKeyExchange();
  404. }
  405. if (this.mAuthentication == null)
  406. {
  407. /*
  408. * RFC 2246 7.4.4. It is a fatal handshake_failure alert for an anonymous server
  409. * to request client identification.
  410. */
  411. throw new TlsFatalAlert(AlertDescription.handshake_failure);
  412. }
  413. this.mCertificateRequest = CertificateRequest.Parse(Context, buf);
  414. AssertEmpty(buf);
  415. this.mKeyExchange.ValidateCertificateRequest(this.mCertificateRequest);
  416. /*
  417. * TODO Give the client a chance to immediately select the CertificateVerify hash
  418. * algorithm here to avoid tracking the other hash algorithms unnecessarily?
  419. */
  420. TlsUtilities.TrackHashAlgorithms(this.mRecordStream.HandshakeHash,
  421. this.mCertificateRequest.SupportedSignatureAlgorithms);
  422. break;
  423. }
  424. default:
  425. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  426. }
  427. this.mConnectionState = CS_CERTIFICATE_REQUEST;
  428. break;
  429. }
  430. case HandshakeType.session_ticket:
  431. {
  432. switch (this.mConnectionState)
  433. {
  434. case CS_CLIENT_FINISHED:
  435. {
  436. if (!this.mExpectSessionTicket)
  437. {
  438. /*
  439. * RFC 5077 3.3. This message MUST NOT be sent if the server did not include a
  440. * SessionTicket extension in the ServerHello.
  441. */
  442. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  443. }
  444. /*
  445. * RFC 5077 3.4. If the client receives a session ticket from the server, then it
  446. * discards any Session ID that was sent in the ServerHello.
  447. */
  448. InvalidateSession();
  449. ReceiveNewSessionTicketMessage(buf);
  450. break;
  451. }
  452. default:
  453. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  454. }
  455. this.mConnectionState = CS_SERVER_SESSION_TICKET;
  456. break;
  457. }
  458. case HandshakeType.hello_request:
  459. {
  460. AssertEmpty(buf);
  461. /*
  462. * RFC 2246 7.4.1.1 Hello request This message will be ignored by the client if the
  463. * client is currently negotiating a session. This message may be ignored by the client
  464. * if it does not wish to renegotiate a session, or the client may, if it wishes,
  465. * respond with a no_renegotiation alert.
  466. */
  467. if (this.mConnectionState == CS_END)
  468. {
  469. RefuseRenegotiation();
  470. }
  471. break;
  472. }
  473. case HandshakeType.client_hello:
  474. case HandshakeType.client_key_exchange:
  475. case HandshakeType.certificate_verify:
  476. case HandshakeType.hello_verify_request:
  477. default:
  478. throw new TlsFatalAlert(AlertDescription.unexpected_message);
  479. }
  480. }
  481. protected virtual void HandleSupplementalData(IList serverSupplementalData)
  482. {
  483. this.mTlsClient.ProcessServerSupplementalData(serverSupplementalData);
  484. this.mConnectionState = CS_SERVER_SUPPLEMENTAL_DATA;
  485. this.mKeyExchange = mTlsClient.GetKeyExchange();
  486. this.mKeyExchange.Init(Context);
  487. }
  488. protected virtual void ReceiveNewSessionTicketMessage(MemoryStream buf)
  489. {
  490. NewSessionTicket newSessionTicket = NewSessionTicket.Parse(buf);
  491. AssertEmpty(buf);
  492. mTlsClient.NotifyNewSessionTicket(newSessionTicket);
  493. }
  494. protected virtual void ReceiveServerHelloMessage(MemoryStream buf)
  495. {
  496. {
  497. ProtocolVersion server_version = TlsUtilities.ReadVersion(buf);
  498. if (server_version.IsDtls)
  499. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  500. // Check that this matches what the server is Sending in the record layer
  501. if (!server_version.Equals(this.mRecordStream.ReadVersion))
  502. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  503. ProtocolVersion client_version = Context.ClientVersion;
  504. if (!server_version.IsEqualOrEarlierVersionOf(client_version))
  505. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  506. this.mRecordStream.SetWriteVersion(server_version);
  507. ContextAdmin.SetServerVersion(server_version);
  508. this.mTlsClient.NotifyServerVersion(server_version);
  509. }
  510. /*
  511. * Read the server random
  512. */
  513. this.mSecurityParameters.serverRandom = TlsUtilities.ReadFully(32, buf);
  514. this.mSelectedSessionID = TlsUtilities.ReadOpaque8(buf);
  515. if (this.mSelectedSessionID.Length > 32)
  516. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  517. this.mTlsClient.NotifySessionID(this.mSelectedSessionID);
  518. this.mResumedSession = this.mSelectedSessionID.Length > 0 && this.mTlsSession != null
  519. && Arrays.AreEqual(this.mSelectedSessionID, this.mTlsSession.SessionID);
  520. /*
  521. * Find out which CipherSuite the server has chosen and check that it was one of the offered
  522. * ones, and is a valid selection for the negotiated version.
  523. */
  524. int selectedCipherSuite = TlsUtilities.ReadUint16(buf);
  525. if (!Arrays.Contains(this.mOfferedCipherSuites, selectedCipherSuite)
  526. || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
  527. || CipherSuite.IsScsv(selectedCipherSuite)
  528. || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, Context.ServerVersion))
  529. {
  530. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  531. }
  532. this.mTlsClient.NotifySelectedCipherSuite(selectedCipherSuite);
  533. /*
  534. * Find out which CompressionMethod the server has chosen and check that it was one of the
  535. * offered ones.
  536. */
  537. byte selectedCompressionMethod = TlsUtilities.ReadUint8(buf);
  538. if (!Arrays.Contains(this.mOfferedCompressionMethods, selectedCompressionMethod))
  539. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  540. this.mTlsClient.NotifySelectedCompressionMethod(selectedCompressionMethod);
  541. /*
  542. * RFC3546 2.2 The extended server hello message format MAY be sent in place of the server
  543. * hello message when the client has requested extended functionality via the extended
  544. * client hello message specified in Section 2.1. ... Note that the extended server hello
  545. * message is only sent in response to an extended client hello message. This prevents the
  546. * possibility that the extended server hello message could "break" existing TLS 1.0
  547. * clients.
  548. */
  549. this.mServerExtensions = ReadExtensions(buf);
  550. /*
  551. * RFC 3546 2.2 Note that the extended server hello message is only sent in response to an
  552. * extended client hello message.
  553. *
  554. * However, see RFC 5746 exception below. We always include the SCSV, so an Extended Server
  555. * Hello is always allowed.
  556. */
  557. if (this.mServerExtensions != null)
  558. {
  559. foreach (int extType in this.mServerExtensions.Keys)
  560. {
  561. /*
  562. * RFC 5746 3.6. Note that Sending a "renegotiation_info" extension in response to a
  563. * ClientHello containing only the SCSV is an explicit exception to the prohibition
  564. * in RFC 5246, Section 7.4.1.4, on the server Sending unsolicited extensions and is
  565. * only allowed because the client is signaling its willingness to receive the
  566. * extension via the TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV.
  567. */
  568. if (extType == ExtensionType.renegotiation_info)
  569. continue;
  570. /*
  571. * RFC 5246 7.4.1.4 An extension type MUST NOT appear in the ServerHello unless the
  572. * same extension type appeared in the corresponding ClientHello. If a client
  573. * receives an extension type in ServerHello that it did not request in the
  574. * associated ClientHello, it MUST abort the handshake with an unsupported_extension
  575. * fatal alert.
  576. */
  577. if (null == TlsUtilities.GetExtensionData(this.mClientExtensions, extType))
  578. throw new TlsFatalAlert(AlertDescription.unsupported_extension);
  579. /*
  580. * RFC 3546 2.3. If [...] the older session is resumed, then the server MUST ignore
  581. * extensions appearing in the client hello, and Send a server hello containing no
  582. * extensions[.]
  583. */
  584. if (this.mResumedSession)
  585. {
  586. // TODO[compat-gnutls] GnuTLS test server Sends server extensions e.g. ec_point_formats
  587. // TODO[compat-openssl] OpenSSL test server Sends server extensions e.g. ec_point_formats
  588. // TODO[compat-polarssl] PolarSSL test server Sends server extensions e.g. ec_point_formats
  589. // throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  590. }
  591. }
  592. }
  593. /*
  594. * RFC 5746 3.4. Client Behavior: Initial Handshake
  595. */
  596. {
  597. /*
  598. * When a ServerHello is received, the client MUST check if it includes the
  599. * "renegotiation_info" extension:
  600. */
  601. byte[] renegExtData = TlsUtilities.GetExtensionData(this.mServerExtensions, ExtensionType.renegotiation_info);
  602. if (renegExtData != null)
  603. {
  604. /*
  605. * If the extension is present, set the secure_renegotiation flag to TRUE. The
  606. * client MUST then verify that the length of the "renegotiated_connection"
  607. * field is zero, and if it is not, MUST abort the handshake (by Sending a fatal
  608. * handshake_failure alert).
  609. */
  610. this.mSecureRenegotiation = true;
  611. if (!Arrays.ConstantTimeAreEqual(renegExtData, CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
  612. throw new TlsFatalAlert(AlertDescription.handshake_failure);
  613. }
  614. }
  615. // TODO[compat-gnutls] GnuTLS test server fails to Send renegotiation_info extension when resuming
  616. this.mTlsClient.NotifySecureRenegotiation(this.mSecureRenegotiation);
  617. IDictionary sessionClientExtensions = mClientExtensions, sessionServerExtensions = mServerExtensions;
  618. if (this.mResumedSession)
  619. {
  620. if (selectedCipherSuite != this.mSessionParameters.CipherSuite
  621. || selectedCompressionMethod != this.mSessionParameters.CompressionAlgorithm)
  622. {
  623. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  624. }
  625. sessionClientExtensions = null;
  626. sessionServerExtensions = this.mSessionParameters.ReadServerExtensions();
  627. }
  628. this.mSecurityParameters.cipherSuite = selectedCipherSuite;
  629. this.mSecurityParameters.compressionAlgorithm = selectedCompressionMethod;
  630. if (sessionServerExtensions != null)
  631. {
  632. {
  633. /*
  634. * RFC 7366 3. If a server receives an encrypt-then-MAC request extension from a client
  635. * and then selects a stream or Authenticated Encryption with Associated Data (AEAD)
  636. * ciphersuite, it MUST NOT send an encrypt-then-MAC response extension back to the
  637. * client.
  638. */
  639. bool serverSentEncryptThenMAC = TlsExtensionsUtilities.HasEncryptThenMacExtension(sessionServerExtensions);
  640. if (serverSentEncryptThenMAC && !TlsUtilities.IsBlockCipherSuite(selectedCipherSuite))
  641. throw new TlsFatalAlert(AlertDescription.illegal_parameter);
  642. this.mSecurityParameters.encryptThenMac = serverSentEncryptThenMAC;
  643. }
  644. this.mSecurityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(sessionServerExtensions);
  645. this.mSecurityParameters.maxFragmentLength = ProcessMaxFragmentLengthExtension(sessionClientExtensions,
  646. sessionServerExtensions, AlertDescription.illegal_parameter);
  647. this.mSecurityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(sessionServerExtensions);
  648. /*
  649. * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in
  650. * a session resumption handshake.
  651. */
  652. this.mAllowCertificateStatus = !this.mResumedSession
  653. && TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.status_request,
  654. AlertDescription.illegal_parameter);
  655. this.mExpectSessionTicket = !this.mResumedSession
  656. && TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.session_ticket,
  657. AlertDescription.illegal_parameter);
  658. }
  659. /*
  660. * TODO[session-hash]
  661. *
  662. * draft-ietf-tls-session-hash-04 4. Clients and servers SHOULD NOT accept handshakes
  663. * that do not use the extended master secret [..]. (and see 5.2, 5.3)
  664. */
  665. if (sessionClientExtensions != null)
  666. {
  667. this.mTlsClient.ProcessServerExtensions(sessionServerExtensions);
  668. }
  669. this.mSecurityParameters.prfAlgorithm = GetPrfAlgorithm(Context, this.mSecurityParameters.CipherSuite);
  670. /*
  671. * RFC 5264 7.4.9. Any cipher suite which does not explicitly specify
  672. * verify_data_length has a verify_data_length equal to 12. This includes all
  673. * existing cipher suites.
  674. */
  675. this.mSecurityParameters.verifyDataLength = 12;
  676. }
  677. protected virtual void SendCertificateVerifyMessage(DigitallySigned certificateVerify)
  678. {
  679. HandshakeMessage message = new HandshakeMessage(HandshakeType.certificate_verify);
  680. certificateVerify.Encode(message);
  681. message.WriteToRecordStream(this);
  682. }
  683. protected virtual void SendClientHelloMessage()
  684. {
  685. this.mRecordStream.SetWriteVersion(this.mTlsClient.ClientHelloRecordLayerVersion);
  686. ProtocolVersion client_version = this.mTlsClient.ClientVersion;
  687. if (client_version.IsDtls)
  688. throw new TlsFatalAlert(AlertDescription.internal_error);
  689. ContextAdmin.SetClientVersion(client_version);
  690. /*
  691. * TODO RFC 5077 3.4. When presenting a ticket, the client MAY generate and include a
  692. * Session ID in the TLS ClientHello.
  693. */
  694. byte[] session_id = TlsUtilities.EmptyBytes;
  695. if (this.mTlsSession != null)
  696. {
  697. session_id = this.mTlsSession.SessionID;
  698. if (session_id == null || session_id.Length > 32)
  699. {
  700. session_id = TlsUtilities.EmptyBytes;
  701. }
  702. }
  703. bool fallback = this.mTlsClient.IsFallback;
  704. this.mOfferedCipherSuites = this.mTlsClient.GetCipherSuites();
  705. this.mOfferedCompressionMethods = this.mTlsClient.GetCompressionMethods();
  706. if (session_id.Length > 0 && this.mSessionParameters != null)
  707. {
  708. if (!Arrays.Contains(this.mOfferedCipherSuites, mSessionParameters.CipherSuite)
  709. || !Arrays.Contains(this.mOfferedCompressionMethods, mSessionParameters.CompressionAlgorithm))
  710. {
  711. session_id = TlsUtilities.EmptyBytes;
  712. }
  713. }
  714. this.mClientExtensions = this.mTlsClient.GetClientExtensions();
  715. HandshakeMessage message = new HandshakeMessage(HandshakeType.client_hello);
  716. TlsUtilities.WriteVersion(client_version, message);
  717. message.Write(this.mSecurityParameters.ClientRandom);
  718. TlsUtilities.WriteOpaque8(session_id, message);
  719. // Cipher Suites (and SCSV)
  720. {
  721. /*
  722. * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension,
  723. * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the
  724. * ClientHello. Including both is NOT RECOMMENDED.
  725. */
  726. byte[] renegExtData = TlsUtilities.GetExtensionData(mClientExtensions, ExtensionType.renegotiation_info);
  727. bool noRenegExt = (null == renegExtData);
  728. bool noRenegScsv = !Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
  729. if (noRenegExt && noRenegScsv)
  730. {
  731. // TODO Consider whether to default to a client extension instead
  732. // this.mClientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(this.mClientExtensions);
  733. // this.mClientExtensions[ExtensionType.renegotiation_info] = CreateRenegotiationInfo(TlsUtilities.EmptyBytes);
  734. this.mOfferedCipherSuites = Arrays.Append(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV);
  735. }
  736. /*
  737. * RFC 7507 4. If a client sends a ClientHello.client_version containing a lower value
  738. * than the latest (highest-valued) version supported by the client, it SHOULD include
  739. * the TLS_FALLBACK_SCSV cipher suite value in ClientHello.cipher_suites [..]. (The
  740. * client SHOULD put TLS_FALLBACK_SCSV after all cipher suites that it actually intends
  741. * to negotiate.)
  742. */
  743. if (fallback && !Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV))
  744. {
  745. this.mOfferedCipherSuites = Arrays.Append(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV);
  746. }
  747. TlsUtilities.WriteUint16ArrayWithUint16Length(mOfferedCipherSuites, message);
  748. }
  749. TlsUtilities.WriteUint8ArrayWithUint8Length(mOfferedCompressionMethods, message);
  750. if (mClientExtensions != null)
  751. {
  752. WriteExtensions(message, mClientExtensions);
  753. }
  754. message.WriteToRecordStream(this);
  755. }
  756. protected virtual void SendClientKeyExchangeMessage()
  757. {
  758. HandshakeMessage message = new HandshakeMessage(HandshakeType.client_key_exchange);
  759. this.mKeyExchange.GenerateClientKeyExchange(message);
  760. message.WriteToRecordStream(this);
  761. }
  762. }
  763. }
  764. #endif