| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840 |
- #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
- #pragma warning disable
- using System;
- using System.Collections;
- using System.IO;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.Asn1.X509;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.Security;
- using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
- namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Tls
- {
- public class TlsServerProtocol
- : TlsProtocol
- {
- protected TlsServer mTlsServer = null;
- internal TlsServerContextImpl mTlsServerContext = null;
- protected TlsKeyExchange mKeyExchange = null;
- protected TlsCredentials mServerCredentials = null;
- protected CertificateRequest mCertificateRequest = null;
- protected short mClientCertificateType = -1;
- protected TlsHandshakeHash mPrepareFinishHash = null;
- /**
- * Constructor for blocking mode.
- * @param stream The bi-directional stream of data to/from the client
- * @param output The stream of data to the client
- * @param secureRandom Random number generator for various cryptographic functions
- */
- public TlsServerProtocol(Stream stream, SecureRandom secureRandom)
- : base(stream, secureRandom)
- {
- }
- /**
- * Constructor for blocking mode.
- * @param input The stream of data from the client
- * @param output The stream of data to the client
- * @param secureRandom Random number generator for various cryptographic functions
- */
- public TlsServerProtocol(Stream input, Stream output, SecureRandom secureRandom)
- : base(input, output, secureRandom)
- {
- }
- /**
- * Constructor for non-blocking mode.<br/>
- * <br/>
- * When data is received, use {@link #offerInput(java.nio.ByteBuffer)} to
- * provide the received ciphertext, then use
- * {@link #readInput(byte[], int, int)} to read the corresponding cleartext.<br/>
- * <br/>
- * Similarly, when data needs to be sent, use
- * {@link #offerOutput(byte[], int, int)} to provide the cleartext, then use
- * {@link #readOutput(byte[], int, int)} to get the corresponding
- * ciphertext.
- *
- * @param secureRandom
- * Random number generator for various cryptographic functions
- */
- public TlsServerProtocol(SecureRandom secureRandom)
- : base(secureRandom)
- {
- }
- /**
- * Receives a TLS handshake in the role of server.<br/>
- * <br/>
- * In blocking mode, this will not return until the handshake is complete.
- * In non-blocking mode, use {@link TlsPeer#notifyHandshakeComplete()} to
- * receive a callback when the handshake is complete.
- *
- * @param tlsServer
- * @throws IOException If in blocking mode and handshake was not successful.
- */
- public virtual void Accept(TlsServer tlsServer)
- {
- if (tlsServer == null)
- throw new ArgumentNullException("tlsServer");
- if (this.mTlsServer != null)
- throw new InvalidOperationException("'Accept' can only be called once");
- this.mTlsServer = tlsServer;
- this.mSecurityParameters = new SecurityParameters();
- this.mSecurityParameters.entity = ConnectionEnd.server;
- this.mTlsServerContext = new TlsServerContextImpl(mSecureRandom, mSecurityParameters);
- this.mSecurityParameters.serverRandom = CreateRandomBlock(tlsServer.ShouldUseGmtUnixTime(),
- mTlsServerContext.NonceRandomGenerator);
- this.mTlsServer.Init(mTlsServerContext);
- this.mRecordStream.Init(mTlsServerContext);
- this.mRecordStream.SetRestrictReadVersion(false);
- BlockForHandshake();
- }
- protected override void CleanupHandshake()
- {
- base.CleanupHandshake();
-
- this.mKeyExchange = null;
- this.mServerCredentials = null;
- this.mCertificateRequest = null;
- this.mPrepareFinishHash = null;
- }
- protected override TlsContext Context
- {
- get { return mTlsServerContext; }
- }
- internal override AbstractTlsContext ContextAdmin
- {
- get { return mTlsServerContext; }
- }
- protected override TlsPeer Peer
- {
- get { return mTlsServer; }
- }
- protected override void HandleHandshakeMessage(byte type, MemoryStream buf)
- {
- switch (type)
- {
- case HandshakeType.client_hello:
- {
- switch (this.mConnectionState)
- {
- case CS_START:
- {
- ReceiveClientHelloMessage(buf);
- this.mConnectionState = CS_CLIENT_HELLO;
- SendServerHelloMessage();
- this.mConnectionState = CS_SERVER_HELLO;
- mRecordStream.NotifyHelloComplete();
- IList serverSupplementalData = mTlsServer.GetServerSupplementalData();
- if (serverSupplementalData != null)
- {
- SendSupplementalDataMessage(serverSupplementalData);
- }
- this.mConnectionState = CS_SERVER_SUPPLEMENTAL_DATA;
- this.mKeyExchange = mTlsServer.GetKeyExchange();
- this.mKeyExchange.Init(Context);
- this.mServerCredentials = mTlsServer.GetCredentials();
- Certificate serverCertificate = null;
- if (this.mServerCredentials == null)
- {
- this.mKeyExchange.SkipServerCredentials();
- }
- else
- {
- this.mKeyExchange.ProcessServerCredentials(this.mServerCredentials);
- serverCertificate = this.mServerCredentials.Certificate;
- SendCertificateMessage(serverCertificate);
- }
- this.mConnectionState = CS_SERVER_CERTIFICATE;
- // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus
- if (serverCertificate == null || serverCertificate.IsEmpty)
- {
- this.mAllowCertificateStatus = false;
- }
- if (this.mAllowCertificateStatus)
- {
- CertificateStatus certificateStatus = mTlsServer.GetCertificateStatus();
- if (certificateStatus != null)
- {
- SendCertificateStatusMessage(certificateStatus);
- }
- }
- this.mConnectionState = CS_CERTIFICATE_STATUS;
- byte[] serverKeyExchange = this.mKeyExchange.GenerateServerKeyExchange();
- if (serverKeyExchange != null)
- {
- SendServerKeyExchangeMessage(serverKeyExchange);
- }
- this.mConnectionState = CS_SERVER_KEY_EXCHANGE;
- if (this.mServerCredentials != null)
- {
- this.mCertificateRequest = mTlsServer.GetCertificateRequest();
- if (this.mCertificateRequest != null)
- {
- if (TlsUtilities.IsTlsV12(Context) != (mCertificateRequest.SupportedSignatureAlgorithms != null))
- throw new TlsFatalAlert(AlertDescription.internal_error);
- this.mKeyExchange.ValidateCertificateRequest(mCertificateRequest);
- SendCertificateRequestMessage(mCertificateRequest);
- TlsUtilities.TrackHashAlgorithms(this.mRecordStream.HandshakeHash,
- this.mCertificateRequest.SupportedSignatureAlgorithms);
- }
- }
- this.mConnectionState = CS_CERTIFICATE_REQUEST;
- SendServerHelloDoneMessage();
- this.mConnectionState = CS_SERVER_HELLO_DONE;
- this.mRecordStream.HandshakeHash.SealHashAlgorithms();
- break;
- }
- case CS_END:
- {
- RefuseRenegotiation();
- break;
- }
- default:
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
- }
- break;
- }
- case HandshakeType.supplemental_data:
- {
- switch (this.mConnectionState)
- {
- case CS_SERVER_HELLO_DONE:
- {
- mTlsServer.ProcessClientSupplementalData(ReadSupplementalDataMessage(buf));
- this.mConnectionState = CS_CLIENT_SUPPLEMENTAL_DATA;
- break;
- }
- default:
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
- }
- break;
- }
- case HandshakeType.certificate:
- {
- switch (this.mConnectionState)
- {
- case CS_SERVER_HELLO_DONE:
- case CS_CLIENT_SUPPLEMENTAL_DATA:
- {
- if (mConnectionState < CS_CLIENT_SUPPLEMENTAL_DATA)
- {
- mTlsServer.ProcessClientSupplementalData(null);
- }
- if (this.mCertificateRequest == null)
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
- ReceiveCertificateMessage(buf);
- this.mConnectionState = CS_CLIENT_CERTIFICATE;
- break;
- }
- default:
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
- }
- break;
- }
- case HandshakeType.client_key_exchange:
- {
- switch (this.mConnectionState)
- {
- case CS_SERVER_HELLO_DONE:
- case CS_CLIENT_SUPPLEMENTAL_DATA:
- case CS_CLIENT_CERTIFICATE:
- {
- if (mConnectionState < CS_CLIENT_SUPPLEMENTAL_DATA)
- {
- mTlsServer.ProcessClientSupplementalData(null);
- }
- if (mConnectionState < CS_CLIENT_CERTIFICATE)
- {
- if (this.mCertificateRequest == null)
- {
- this.mKeyExchange.SkipClientCredentials();
- }
- else
- {
- if (TlsUtilities.IsTlsV12(Context))
- {
- /*
- * RFC 5246 If no suitable certificate is available, the client MUST Send a
- * certificate message containing no certificates.
- *
- * NOTE: In previous RFCs, this was SHOULD instead of MUST.
- */
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
- }
- else if (TlsUtilities.IsSsl(Context))
- {
- if (this.mPeerCertificate == null)
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
- }
- else
- {
- NotifyClientCertificate(Certificate.EmptyChain);
- }
- }
- }
- ReceiveClientKeyExchangeMessage(buf);
- this.mConnectionState = CS_CLIENT_KEY_EXCHANGE;
- break;
- }
- default:
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
- }
- break;
- }
- case HandshakeType.certificate_verify:
- {
- switch (this.mConnectionState)
- {
- case CS_CLIENT_KEY_EXCHANGE:
- {
- /*
- * RFC 5246 7.4.8 This message is only sent following a client certificate that has
- * signing capability (i.e., all certificates except those containing fixed
- * Diffie-Hellman parameters).
- */
- if (!ExpectCertificateVerifyMessage())
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
- ReceiveCertificateVerifyMessage(buf);
- this.mConnectionState = CS_CERTIFICATE_VERIFY;
- break;
- }
- default:
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
- }
- break;
- }
- case HandshakeType.finished:
- {
- switch (this.mConnectionState)
- {
- case CS_CLIENT_KEY_EXCHANGE:
- case CS_CERTIFICATE_VERIFY:
- {
- if (mConnectionState < CS_CERTIFICATE_VERIFY && ExpectCertificateVerifyMessage())
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
- ProcessFinishedMessage(buf);
- this.mConnectionState = CS_CLIENT_FINISHED;
- if (this.mExpectSessionTicket)
- {
- SendNewSessionTicketMessage(mTlsServer.GetNewSessionTicket());
- }
- this.mConnectionState = CS_SERVER_SESSION_TICKET;
- SendChangeCipherSpecMessage();
- SendFinishedMessage();
- this.mConnectionState = CS_SERVER_FINISHED;
- CompleteHandshake();
- break;
- }
- default:
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
- }
- break;
- }
- case HandshakeType.hello_request:
- case HandshakeType.hello_verify_request:
- case HandshakeType.server_hello:
- case HandshakeType.server_key_exchange:
- case HandshakeType.certificate_request:
- case HandshakeType.server_hello_done:
- case HandshakeType.session_ticket:
- default:
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
- }
- }
- protected override void HandleAlertWarningMessage(byte alertDescription)
- {
- base.HandleAlertWarningMessage(alertDescription);
- switch (alertDescription)
- {
- case AlertDescription.no_certificate:
- {
- /*
- * SSL 3.0 If the server has sent a certificate request Message, the client must send
- * either the certificate message or a no_certificate alert.
- */
- if (TlsUtilities.IsSsl(Context) && this.mCertificateRequest != null)
- {
- switch (this.mConnectionState)
- {
- case CS_SERVER_HELLO_DONE:
- case CS_CLIENT_SUPPLEMENTAL_DATA:
- {
- if (mConnectionState < CS_CLIENT_SUPPLEMENTAL_DATA)
- {
- mTlsServer.ProcessClientSupplementalData(null);
- }
- NotifyClientCertificate(Certificate.EmptyChain);
- this.mConnectionState = CS_CLIENT_CERTIFICATE;
- return;
- }
- }
- }
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
- }
- }
- }
- protected virtual void NotifyClientCertificate(Certificate clientCertificate)
- {
- if (mCertificateRequest == null)
- throw new InvalidOperationException();
- if (mPeerCertificate != null)
- throw new TlsFatalAlert(AlertDescription.unexpected_message);
- this.mPeerCertificate = clientCertificate;
- if (clientCertificate.IsEmpty)
- {
- this.mKeyExchange.SkipClientCredentials();
- }
- else
- {
- /*
- * TODO RFC 5246 7.4.6. If the certificate_authorities list in the certificate request
- * message was non-empty, one of the certificates in the certificate chain SHOULD be
- * issued by one of the listed CAs.
- */
- this.mClientCertificateType = TlsUtilities.GetClientCertificateType(clientCertificate,
- this.mServerCredentials.Certificate);
- this.mKeyExchange.ProcessClientCertificate(clientCertificate);
- }
- /*
- * RFC 5246 7.4.6. If the client does not Send any certificates, the server MAY at its
- * discretion either continue the handshake without client authentication, or respond with a
- * fatal handshake_failure alert. Also, if some aspect of the certificate chain was
- * unacceptable (e.g., it was not signed by a known, trusted CA), the server MAY at its
- * discretion either continue the handshake (considering the client unauthenticated) or Send
- * a fatal alert.
- */
- this.mTlsServer.NotifyClientCertificate(clientCertificate);
- }
- protected virtual void ReceiveCertificateMessage(MemoryStream buf)
- {
- Certificate clientCertificate = Certificate.Parse(buf);
- AssertEmpty(buf);
- NotifyClientCertificate(clientCertificate);
- }
- protected virtual void ReceiveCertificateVerifyMessage(MemoryStream buf)
- {
- if (mCertificateRequest == null)
- throw new InvalidOperationException();
- DigitallySigned clientCertificateVerify = DigitallySigned.Parse(Context, buf);
- AssertEmpty(buf);
- // Verify the CertificateVerify message contains a correct signature.
- try
- {
- SignatureAndHashAlgorithm signatureAlgorithm = clientCertificateVerify.Algorithm;
- byte[] hash;
- if (TlsUtilities.IsTlsV12(Context))
- {
- TlsUtilities.VerifySupportedSignatureAlgorithm(mCertificateRequest.SupportedSignatureAlgorithms, signatureAlgorithm);
- hash = mPrepareFinishHash.GetFinalHash(signatureAlgorithm.Hash);
- }
- else
- {
- hash = mSecurityParameters.SessionHash;
- }
- X509CertificateStructure x509Cert = mPeerCertificate.GetCertificateAt(0);
- SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo;
- AsymmetricKeyParameter publicKey = PublicKeyFactory.CreateKey(keyInfo);
- TlsSigner tlsSigner = TlsUtilities.CreateTlsSigner((byte)mClientCertificateType);
- tlsSigner.Init(Context);
- if (!tlsSigner.VerifyRawSignature(signatureAlgorithm, clientCertificateVerify.Signature, publicKey, hash))
- throw new TlsFatalAlert(AlertDescription.decrypt_error);
- }
- catch (TlsFatalAlert e)
- {
- throw e;
- }
- catch (Exception e)
- {
- throw new TlsFatalAlert(AlertDescription.decrypt_error, e);
- }
- }
- protected virtual void ReceiveClientHelloMessage(MemoryStream buf)
- {
- ProtocolVersion client_version = TlsUtilities.ReadVersion(buf);
- mRecordStream.SetWriteVersion(client_version);
- if (client_version.IsDtls)
- throw new TlsFatalAlert(AlertDescription.illegal_parameter);
- byte[] client_random = TlsUtilities.ReadFully(32, buf);
- /*
- * TODO RFC 5077 3.4. If a ticket is presented by the client, the server MUST NOT attempt to
- * use the Session ID in the ClientHello for stateful session resumption.
- */
- byte[] sessionID = TlsUtilities.ReadOpaque8(buf);
- if (sessionID.Length > 32)
- throw new TlsFatalAlert(AlertDescription.illegal_parameter);
- /*
- * TODO RFC 5246 7.4.1.2. If the session_id field is not empty (implying a session
- * resumption request), this vector MUST include at least the cipher_suite from that
- * session.
- */
- int cipher_suites_length = TlsUtilities.ReadUint16(buf);
- if (cipher_suites_length < 2 || (cipher_suites_length & 1) != 0)
- throw new TlsFatalAlert(AlertDescription.decode_error);
- this.mOfferedCipherSuites = TlsUtilities.ReadUint16Array(cipher_suites_length / 2, buf);
- /*
- * TODO RFC 5246 7.4.1.2. If the session_id field is not empty (implying a session
- * resumption request), it MUST include the compression_method from that session.
- */
- int compression_methods_length = TlsUtilities.ReadUint8(buf);
- if (compression_methods_length < 1)
- throw new TlsFatalAlert(AlertDescription.illegal_parameter);
- this.mOfferedCompressionMethods = TlsUtilities.ReadUint8Array(compression_methods_length, buf);
- /*
- * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore
- * extensions appearing in the client hello, and Send a server hello containing no
- * extensions.
- */
- this.mClientExtensions = ReadExtensions(buf);
- /*
- * TODO[resumption] Check RFC 7627 5.4. for required behaviour
- */
- /*
- * RFC 7627 4. Clients and servers SHOULD NOT accept handshakes that do not use the extended
- * master secret [..]. (and see 5.2, 5.3)
- */
- this.mSecurityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(mClientExtensions);
- if (!mSecurityParameters.IsExtendedMasterSecret && mTlsServer.RequiresExtendedMasterSecret())
- {
- throw new TlsFatalAlert(AlertDescription.handshake_failure);
- }
- ContextAdmin.SetClientVersion(client_version);
- mTlsServer.NotifyClientVersion(client_version);
- mTlsServer.NotifyFallback(Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV));
- mSecurityParameters.clientRandom = client_random;
- mTlsServer.NotifyOfferedCipherSuites(mOfferedCipherSuites);
- mTlsServer.NotifyOfferedCompressionMethods(mOfferedCompressionMethods);
- /*
- * RFC 5746 3.6. Server Behavior: Initial Handshake
- */
- {
- /*
- * RFC 5746 3.4. The client MUST include either an empty "renegotiation_info" extension,
- * or the TLS_EMPTY_RENEGOTIATION_INFO_SCSV signaling cipher suite value in the
- * ClientHello. Including both is NOT RECOMMENDED.
- */
- /*
- * When a ClientHello is received, the server MUST check if it includes the
- * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV. If it does, set the secure_renegotiation flag
- * to TRUE.
- */
- if (Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV))
- {
- this.mSecureRenegotiation = true;
- }
- /*
- * The server MUST check if the "renegotiation_info" extension is included in the
- * ClientHello.
- */
- byte[] renegExtData = TlsUtilities.GetExtensionData(mClientExtensions, ExtensionType.renegotiation_info);
- if (renegExtData != null)
- {
- /*
- * If the extension is present, set secure_renegotiation flag to TRUE. The
- * server MUST then verify that the length of the "renegotiated_connection"
- * field is zero, and if it is not, MUST abort the handshake.
- */
- this.mSecureRenegotiation = true;
- if (!Arrays.ConstantTimeAreEqual(renegExtData, CreateRenegotiationInfo(TlsUtilities.EmptyBytes)))
- throw new TlsFatalAlert(AlertDescription.handshake_failure);
- }
- }
- mTlsServer.NotifySecureRenegotiation(this.mSecureRenegotiation);
- if (mClientExtensions != null)
- {
- // NOTE: Validates the padding extension data, if present
- TlsExtensionsUtilities.GetPaddingExtension(mClientExtensions);
- mTlsServer.ProcessClientExtensions(mClientExtensions);
- }
- }
- protected virtual void ReceiveClientKeyExchangeMessage(MemoryStream buf)
- {
- mKeyExchange.ProcessClientKeyExchange(buf);
- AssertEmpty(buf);
- if (TlsUtilities.IsSsl(Context))
- {
- EstablishMasterSecret(Context, mKeyExchange);
- }
- this.mPrepareFinishHash = mRecordStream.PrepareToFinish();
- this.mSecurityParameters.sessionHash = GetCurrentPrfHash(Context, mPrepareFinishHash, null);
- if (!TlsUtilities.IsSsl(Context))
- {
- EstablishMasterSecret(Context, mKeyExchange);
- }
- mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher());
- }
- protected virtual void SendCertificateRequestMessage(CertificateRequest certificateRequest)
- {
- HandshakeMessage message = new HandshakeMessage(HandshakeType.certificate_request);
- certificateRequest.Encode(message);
- message.WriteToRecordStream(this);
- }
- protected virtual void SendCertificateStatusMessage(CertificateStatus certificateStatus)
- {
- HandshakeMessage message = new HandshakeMessage(HandshakeType.certificate_status);
- certificateStatus.Encode(message);
- message.WriteToRecordStream(this);
- }
- protected virtual void SendNewSessionTicketMessage(NewSessionTicket newSessionTicket)
- {
- if (newSessionTicket == null)
- throw new TlsFatalAlert(AlertDescription.internal_error);
- HandshakeMessage message = new HandshakeMessage(HandshakeType.session_ticket);
- newSessionTicket.Encode(message);
- message.WriteToRecordStream(this);
- }
- protected virtual void SendServerHelloMessage()
- {
- HandshakeMessage message = new HandshakeMessage(HandshakeType.server_hello);
- {
- ProtocolVersion server_version = mTlsServer.GetServerVersion();
- if (!server_version.IsEqualOrEarlierVersionOf(Context.ClientVersion))
- throw new TlsFatalAlert(AlertDescription.internal_error);
- mRecordStream.ReadVersion = server_version;
- mRecordStream.SetWriteVersion(server_version);
- mRecordStream.SetRestrictReadVersion(true);
- ContextAdmin.SetServerVersion(server_version);
- TlsUtilities.WriteVersion(server_version, message);
- }
- message.Write(this.mSecurityParameters.serverRandom);
- /*
- * The server may return an empty session_id to indicate that the session will not be cached
- * and therefore cannot be resumed.
- */
- TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, message);
- int selectedCipherSuite = mTlsServer.GetSelectedCipherSuite();
- if (!Arrays.Contains(mOfferedCipherSuites, selectedCipherSuite)
- || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL
- || CipherSuite.IsScsv(selectedCipherSuite)
- || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, Context.ServerVersion))
- {
- throw new TlsFatalAlert(AlertDescription.internal_error);
- }
- mSecurityParameters.cipherSuite = selectedCipherSuite;
- byte selectedCompressionMethod = mTlsServer.GetSelectedCompressionMethod();
- if (!Arrays.Contains(mOfferedCompressionMethods, selectedCompressionMethod))
- {
- throw new TlsFatalAlert(AlertDescription.internal_error);
- }
- mSecurityParameters.compressionAlgorithm = selectedCompressionMethod;
- TlsUtilities.WriteUint16(selectedCipherSuite, message);
- TlsUtilities.WriteUint8(selectedCompressionMethod, message);
- this.mServerExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(mTlsServer.GetServerExtensions());
- /*
- * RFC 5746 3.6. Server Behavior: Initial Handshake
- */
- if (this.mSecureRenegotiation)
- {
- byte[] renegExtData = TlsUtilities.GetExtensionData(this.mServerExtensions, ExtensionType.renegotiation_info);
- bool noRenegExt = (null == renegExtData);
- if (noRenegExt)
- {
- /*
- * Note that Sending a "renegotiation_info" extension in response to a ClientHello
- * containing only the SCSV is an explicit exception to the prohibition in RFC 5246,
- * Section 7.4.1.4, on the server Sending unsolicited extensions and is only allowed
- * because the client is signaling its willingness to receive the extension via the
- * TLS_EMPTY_RENEGOTIATION_INFO_SCSV SCSV.
- */
- /*
- * If the secure_renegotiation flag is set to TRUE, the server MUST include an empty
- * "renegotiation_info" extension in the ServerHello message.
- */
- this.mServerExtensions[ExtensionType.renegotiation_info] = CreateRenegotiationInfo(TlsUtilities.EmptyBytes);
- }
- }
- if (TlsUtilities.IsSsl(mTlsServerContext))
- {
- mSecurityParameters.extendedMasterSecret = false;
- }
- else if (mSecurityParameters.IsExtendedMasterSecret)
- {
- TlsExtensionsUtilities.AddExtendedMasterSecretExtension(mServerExtensions);
- }
- /*
- * TODO RFC 3546 2.3 If [...] the older session is resumed, then the server MUST ignore
- * extensions appearing in the client hello, and Send a server hello containing no
- * extensions.
- */
- if (this.mServerExtensions.Count > 0)
- {
- this.mSecurityParameters.encryptThenMac = TlsExtensionsUtilities.HasEncryptThenMacExtension(mServerExtensions);
- this.mSecurityParameters.maxFragmentLength = ProcessMaxFragmentLengthExtension(mClientExtensions,
- mServerExtensions, AlertDescription.internal_error);
- this.mSecurityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(mServerExtensions);
- /*
- * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in
- * a session resumption handshake.
- */
- this.mAllowCertificateStatus = !mResumedSession
- && TlsUtilities.HasExpectedEmptyExtensionData(mServerExtensions, ExtensionType.status_request,
- AlertDescription.internal_error);
- this.mExpectSessionTicket = !mResumedSession
- && TlsUtilities.HasExpectedEmptyExtensionData(mServerExtensions, ExtensionType.session_ticket,
- AlertDescription.internal_error);
- WriteExtensions(message, this.mServerExtensions);
- }
- mSecurityParameters.prfAlgorithm = GetPrfAlgorithm(Context, mSecurityParameters.CipherSuite);
- /*
- * RFC 5246 7.4.9. Any cipher suite which does not explicitly specify verify_data_length has
- * a verify_data_length equal to 12. This includes all existing cipher suites.
- */
- mSecurityParameters.verifyDataLength = 12;
- ApplyMaxFragmentLengthExtension();
- message.WriteToRecordStream(this);
- }
- protected virtual void SendServerHelloDoneMessage()
- {
- byte[] message = new byte[4];
- TlsUtilities.WriteUint8(HandshakeType.server_hello_done, message, 0);
- TlsUtilities.WriteUint24(0, message, 1);
- WriteHandshakeMessage(message, 0, message.Length);
- }
- protected virtual void SendServerKeyExchangeMessage(byte[] serverKeyExchange)
- {
- HandshakeMessage message = new HandshakeMessage(HandshakeType.server_key_exchange, serverKeyExchange.Length);
- message.Write(serverKeyExchange);
- message.WriteToRecordStream(this);
- }
- protected virtual bool ExpectCertificateVerifyMessage()
- {
- return mClientCertificateType >= 0 && TlsUtilities.HasSigningCapability((byte)mClientCertificateType);
- }
- }
- }
- #pragma warning restore
- #endif
|