protected virtual void ReceiveServerHelloMessage(MemoryStream buf) { { ProtocolVersion server_version = TlsUtilities.ReadVersion(buf); if (server_version.IsDtls) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } // Check that this matches what the server is Sending in the record layer if (!server_version.Equals(this.mRecordStream.ReadVersion)) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } ProtocolVersion client_version = Context.ClientVersion; if (!server_version.IsEqualOrEarlierVersionOf(client_version)) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } this.mRecordStream.SetWriteVersion(server_version); ContextAdmin.SetServerVersion(server_version); this.mTlsClient.NotifyServerVersion(server_version); } /* * Read the server random */ this.mSecurityParameters.serverRandom = TlsUtilities.ReadFully(32, buf); this.mSelectedSessionID = TlsUtilities.ReadOpaque8(buf); if (this.mSelectedSessionID.Length > 32) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } this.mTlsClient.NotifySessionID(this.mSelectedSessionID); this.mResumedSession = this.mSelectedSessionID.Length > 0 && this.mTlsSession != null && Arrays.AreEqual(this.mSelectedSessionID, this.mTlsSession.SessionID); /* * Find out which CipherSuite the server has chosen and check that it was one of the offered * ones, and is a valid selection for the negotiated version. */ int selectedCipherSuite = TlsUtilities.ReadUint16(buf); if (!Arrays.Contains(this.mOfferedCipherSuites, selectedCipherSuite) || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL || CipherSuite.IsScsv(selectedCipherSuite) || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, Context.ServerVersion)) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } this.mTlsClient.NotifySelectedCipherSuite(selectedCipherSuite); /* * Find out which CompressionMethod the server has chosen and check that it was one of the * offered ones. */ byte selectedCompressionMethod = TlsUtilities.ReadUint8(buf); if (!Arrays.Contains(this.mOfferedCompressionMethods, selectedCompressionMethod)) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } this.mTlsClient.NotifySelectedCompressionMethod(selectedCompressionMethod); /* * RFC3546 2.2 The extended server hello message format MAY be sent in place of the server * hello message when the client has requested extended functionality via the extended * client hello message specified in Section 2.1. ... Note that the extended server hello * message is only sent in response to an extended client hello message. This prevents the * possibility that the extended server hello message could "break" existing TLS 1.0 * clients. */ this.mServerExtensions = ReadExtensions(buf); /* * RFC 3546 2.2 Note that the extended server hello message is only sent in response to an * extended client hello message. * * However, see RFC 5746 exception below. We always include the SCSV, so an Extended Server * Hello is always allowed. */ if (this.mServerExtensions != null) { foreach (int extType in this.mServerExtensions.Keys) { /* * RFC 5746 3.6. 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 (extType == ExtensionType.renegotiation_info) { continue; } /* * RFC 5246 7.4.1.4 An extension type MUST NOT appear in the ServerHello unless the * same extension type appeared in the corresponding ClientHello. If a client * receives an extension type in ServerHello that it did not request in the * associated ClientHello, it MUST abort the handshake with an unsupported_extension * fatal alert. */ if (null == TlsUtilities.GetExtensionData(this.mClientExtensions, extType)) { throw new TlsFatalAlert(AlertDescription.unsupported_extension); } /* * 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.mResumedSession) { // TODO[compat-gnutls] GnuTLS test server Sends server extensions e.g. ec_point_formats // TODO[compat-openssl] OpenSSL test server Sends server extensions e.g. ec_point_formats // TODO[compat-polarssl] PolarSSL test server Sends server extensions e.g. ec_point_formats // throw new TlsFatalAlert(AlertDescription.illegal_parameter); } } } /* * RFC 5746 3.4. Client Behavior: Initial Handshake */ { /* * When a ServerHello is received, the client MUST check if it includes the * "renegotiation_info" extension: */ byte[] renegExtData = TlsUtilities.GetExtensionData(this.mServerExtensions, ExtensionType.renegotiation_info); if (renegExtData != null) { /* * If the extension is present, set the secure_renegotiation flag to TRUE. The * client MUST then verify that the length of the "renegotiated_connection" * field is zero, and if it is not, MUST abort the handshake (by Sending a fatal * handshake_failure alert). */ this.mSecureRenegotiation = true; if (!Arrays.ConstantTimeAreEqual(renegExtData, CreateRenegotiationInfo(TlsUtilities.EmptyBytes))) { throw new TlsFatalAlert(AlertDescription.handshake_failure); } } } // TODO[compat-gnutls] GnuTLS test server fails to Send renegotiation_info extension when resuming this.mTlsClient.NotifySecureRenegotiation(this.mSecureRenegotiation); IDictionary sessionClientExtensions = mClientExtensions, sessionServerExtensions = mServerExtensions; if (this.mResumedSession) { if (selectedCipherSuite != this.mSessionParameters.CipherSuite || selectedCompressionMethod != this.mSessionParameters.CompressionAlgorithm) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } sessionClientExtensions = null; sessionServerExtensions = this.mSessionParameters.ReadServerExtensions(); } this.mSecurityParameters.cipherSuite = selectedCipherSuite; this.mSecurityParameters.compressionAlgorithm = selectedCompressionMethod; if (sessionServerExtensions != null) { { /* * RFC 7366 3. If a server receives an encrypt-then-MAC request extension from a client * and then selects a stream or Authenticated Encryption with Associated Data (AEAD) * ciphersuite, it MUST NOT send an encrypt-then-MAC response extension back to the * client. */ bool serverSentEncryptThenMAC = TlsExtensionsUtilities.HasEncryptThenMacExtension(sessionServerExtensions); if (serverSentEncryptThenMAC && !TlsUtilities.IsBlockCipherSuite(selectedCipherSuite)) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } this.mSecurityParameters.encryptThenMac = serverSentEncryptThenMAC; } this.mSecurityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(sessionServerExtensions); this.mSecurityParameters.maxFragmentLength = ProcessMaxFragmentLengthExtension(sessionClientExtensions, sessionServerExtensions, AlertDescription.illegal_parameter); this.mSecurityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(sessionServerExtensions); /* * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in * a session resumption handshake. */ this.mAllowCertificateStatus = !this.mResumedSession && TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.status_request, AlertDescription.illegal_parameter); this.mExpectSessionTicket = !this.mResumedSession && TlsUtilities.HasExpectedEmptyExtensionData(sessionServerExtensions, ExtensionType.session_ticket, AlertDescription.illegal_parameter); } /* * TODO[session-hash] * * draft-ietf-tls-session-hash-04 4. Clients and servers SHOULD NOT accept handshakes * that do not use the extended master secret [..]. (and see 5.2, 5.3) */ if (sessionClientExtensions != null) { this.mTlsClient.ProcessServerExtensions(sessionServerExtensions); } this.mSecurityParameters.prfAlgorithm = GetPrfAlgorithm(Context, this.mSecurityParameters.CipherSuite); /* * RFC 5264 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. */ this.mSecurityParameters.verifyDataLength = 12; }
protected virtual bool ExpectCertificateVerifyMessage() { return(mClientCertificateType >= 0 && TlsUtilities.HasSigningCapability((byte)mClientCertificateType)); }
protected internal static byte[] CreateRenegotiationInfo(byte[] renegotiated_connection) { return(TlsUtilities.EncodeOpaque8(renegotiated_connection)); }
public virtual void Encode(Stream output) { TlsUtilities.WriteUint8(this.mMode, output); }
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 byte[] GenerateServerHello(ServerHandshakeState state) { SecurityParameters securityParameters = state.serverContext.SecurityParameters; MemoryStream buf = new MemoryStream(); { ProtocolVersion server_version = state.server.GetServerVersion(); if (!server_version.IsEqualOrEarlierVersionOf(state.serverContext.ClientVersion)) { throw new TlsFatalAlert(AlertDescription.internal_error); } // TODO Read RFCs for guidance on the expected record layer version number // recordStream.setReadVersion(server_version); // recordStream.setWriteVersion(server_version); // recordStream.setRestrictReadVersion(true); state.serverContext.SetServerVersion(server_version); TlsUtilities.WriteVersion(state.serverContext.ServerVersion, buf); } buf.Write(securityParameters.ServerRandom, 0, securityParameters.ServerRandom.Length); /* * 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, buf); int selectedCipherSuite = state.server.GetSelectedCipherSuite(); if (!Arrays.Contains(state.offeredCipherSuites, selectedCipherSuite) || selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL || CipherSuite.IsScsv(selectedCipherSuite) || !TlsUtilities.IsValidCipherSuiteForVersion(selectedCipherSuite, state.serverContext.ServerVersion)) { throw new TlsFatalAlert(AlertDescription.internal_error); } ValidateSelectedCipherSuite(selectedCipherSuite, AlertDescription.internal_error); securityParameters.cipherSuite = selectedCipherSuite; byte selectedCompressionMethod = state.server.GetSelectedCompressionMethod(); if (!Arrays.Contains(state.offeredCompressionMethods, selectedCompressionMethod)) { throw new TlsFatalAlert(AlertDescription.internal_error); } securityParameters.compressionAlgorithm = selectedCompressionMethod; TlsUtilities.WriteUint16(selectedCipherSuite, buf); TlsUtilities.WriteUint8(selectedCompressionMethod, buf); state.serverExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(state.server.GetServerExtensions()); /* * RFC 5746 3.6. Server Behavior: Initial Handshake */ if (state.secure_renegotiation) { byte[] renegExtData = TlsUtilities.GetExtensionData(state.serverExtensions, 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. */ state.serverExtensions[ExtensionType.renegotiation_info] = TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes); } } if (securityParameters.IsExtendedMasterSecret) { TlsExtensionsUtilities.AddExtendedMasterSecretExtension(state.serverExtensions); } /* * 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 (state.serverExtensions.Count > 0) { securityParameters.encryptThenMac = TlsExtensionsUtilities.HasEncryptThenMacExtension(state.serverExtensions); securityParameters.maxFragmentLength = EvaluateMaxFragmentLengthExtension(state.resumedSession, state.clientExtensions, state.serverExtensions, AlertDescription.internal_error); securityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(state.serverExtensions); /* * TODO It's surprising that there's no provision to allow a 'fresh' CertificateStatus to be sent in * a session resumption handshake. */ state.allowCertificateStatus = !state.resumedSession && TlsUtilities.HasExpectedEmptyExtensionData(state.serverExtensions, ExtensionType.status_request, AlertDescription.internal_error); state.expectSessionTicket = !state.resumedSession && TlsUtilities.HasExpectedEmptyExtensionData(state.serverExtensions, ExtensionType.session_ticket, AlertDescription.internal_error); TlsProtocol.WriteExtensions(buf, state.serverExtensions); } securityParameters.prfAlgorithm = TlsProtocol.GetPrfAlgorithm(state.serverContext, securityParameters.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. */ securityParameters.verifyDataLength = 12; return(buf.ToArray()); }
protected virtual bool ExpectCertificateVerifyMessage(ServerHandshakeState state) { return(state.clientCertificateType >= 0 && TlsUtilities.HasSigningCapability((byte)state.clientCertificateType)); }
public static BigInteger ReadDHParameter(Stream input) { return(new BigInteger(1, TlsUtilities.ReadOpaque16(input))); }
public static void WriteDHParameter(BigInteger x, Stream output) { TlsUtilities.WriteOpaque16(BigIntegers.AsUnsignedByteArray(x), output); }
internal CombinedHash() { this.mMd5 = TlsUtilities.CreateHash(HashAlgorithm.md5); this.mSha1 = TlsUtilities.CreateHash(HashAlgorithm.sha1); }
internal CombinedHash(CombinedHash t) { this.mContext = t.mContext; this.mMd5 = TlsUtilities.CloneHash(HashAlgorithm.md5, t.mMd5); this.mSha1 = TlsUtilities.CloneHash(HashAlgorithm.sha1, t.mSha1); }
public TlsBlockCipher(TlsContext context, IBlockCipher clientWriteCipher, IBlockCipher serverWriteCipher, IDigest clientWriteDigest, IDigest serverWriteDigest, int cipherKeySize) { this.context = context; this.randomData = new byte[256]; context.NonceRandomGenerator.NextBytes(this.randomData); this.useExplicitIV = TlsUtilities.IsTlsV11(context); this.encryptThenMac = context.SecurityParameters.encryptThenMac; int num = 2 * cipherKeySize + clientWriteDigest.GetDigestSize() + serverWriteDigest.GetDigestSize(); if (!this.useExplicitIV) { num += clientWriteCipher.GetBlockSize() + serverWriteCipher.GetBlockSize(); } byte[] array = TlsUtilities.CalculateKeyBlock(context, num); int num2 = 0; TlsMac tlsMac = new TlsMac(context, clientWriteDigest, array, num2, clientWriteDigest.GetDigestSize()); num2 += clientWriteDigest.GetDigestSize(); TlsMac tlsMac2 = new TlsMac(context, serverWriteDigest, array, num2, serverWriteDigest.GetDigestSize()); num2 += serverWriteDigest.GetDigestSize(); KeyParameter parameters = new KeyParameter(array, num2, cipherKeySize); num2 += cipherKeySize; KeyParameter parameters2 = new KeyParameter(array, num2, cipherKeySize); num2 += cipherKeySize; byte[] iv; byte[] iv2; if (this.useExplicitIV) { iv = new byte[clientWriteCipher.GetBlockSize()]; iv2 = new byte[serverWriteCipher.GetBlockSize()]; } else { iv = Arrays.CopyOfRange(array, num2, num2 + clientWriteCipher.GetBlockSize()); num2 += clientWriteCipher.GetBlockSize(); iv2 = Arrays.CopyOfRange(array, num2, num2 + serverWriteCipher.GetBlockSize()); num2 += serverWriteCipher.GetBlockSize(); } if (num2 != num) { throw new TlsFatalAlert(80); } ICipherParameters parameters3; ICipherParameters parameters4; if (context.IsServer) { this.mWriteMac = tlsMac2; this.mReadMac = tlsMac; this.encryptCipher = serverWriteCipher; this.decryptCipher = clientWriteCipher; parameters3 = new ParametersWithIV(parameters2, iv2); parameters4 = new ParametersWithIV(parameters, iv); } else { this.mWriteMac = tlsMac; this.mReadMac = tlsMac2; this.encryptCipher = clientWriteCipher; this.decryptCipher = serverWriteCipher; parameters3 = new ParametersWithIV(parameters, iv); parameters4 = new ParametersWithIV(parameters2, iv2); } this.encryptCipher.Init(true, parameters3); this.decryptCipher.Init(false, parameters4); }
public override void ProcessServerCertificate(AbstractCertificate serverCertificate) { if (mKeyExchange == KeyExchangeAlgorithm.DH_anon) { throw new TlsFatalAlert(AlertDescription.unexpected_message); } if (serverCertificate.IsEmpty) { throw new TlsFatalAlert(AlertDescription.decode_error); } Certificate real = serverCertificate as Certificate; X509CertificateStructure x509Cert = null; if (real != null) { x509Cert = real.GetCertificateAt(0); } SubjectPublicKeyInfo keyInfo = serverCertificate.SubjectPublicKeyInfo(); try { this.mServerPublicKey = PublicKeyFactory.CreateKey(keyInfo); } catch (Exception e) { throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e); } if (mTlsSigner == null) { try { this.mDHAgreePublicKey = (DHPublicKeyParameters)this.mServerPublicKey; this.mDHParameters = mDHAgreePublicKey.Parameters; } catch (InvalidCastException e) { throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); } if (x509Cert != null) { TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.KeyAgreement); } } else { if (!mTlsSigner.IsValidPublicKey(this.mServerPublicKey)) { throw new TlsFatalAlert(AlertDescription.certificate_unknown); } if (x509Cert != null) { TlsUtilities.ValidateKeyUsage(x509Cert, KeyUsage.DigitalSignature); } } base.ProcessServerCertificate(serverCertificate); }
protected virtual void SendClientHelloMessage() { this.mRecordStream.SetWriteVersion(this.mTlsClient.ClientHelloRecordLayerVersion); ProtocolVersion client_version = this.mTlsClient.ClientVersion; if (client_version.IsDtls) { throw new TlsFatalAlert(AlertDescription.internal_error); } ContextAdmin.SetClientVersion(client_version); /* * TODO RFC 5077 3.4. When presenting a ticket, the client MAY generate and include a * Session ID in the TLS ClientHello. */ byte[] session_id = TlsUtilities.EmptyBytes; if (this.mTlsSession != null) { session_id = this.mTlsSession.SessionID; if (session_id == null || session_id.Length > 32) { session_id = TlsUtilities.EmptyBytes; } } bool fallback = this.mTlsClient.IsFallback; this.mOfferedCipherSuites = this.mTlsClient.GetCipherSuites(); this.mOfferedCompressionMethods = this.mTlsClient.GetCompressionMethods(); if (session_id.Length > 0 && this.mSessionParameters != null) { if (!Arrays.Contains(this.mOfferedCipherSuites, mSessionParameters.CipherSuite) || !Arrays.Contains(this.mOfferedCompressionMethods, mSessionParameters.CompressionAlgorithm)) { session_id = TlsUtilities.EmptyBytes; } } this.mClientExtensions = this.mTlsClient.GetClientExtensions(); HandshakeMessage message = new HandshakeMessage(HandshakeType.client_hello); TlsUtilities.WriteVersion(client_version, message); message.Write(this.mSecurityParameters.ClientRandom); TlsUtilities.WriteOpaque8(session_id, message); // Cipher Suites (and SCSV) { /* * 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. */ byte[] renegExtData = TlsUtilities.GetExtensionData(mClientExtensions, ExtensionType.renegotiation_info); bool noRenegExt = (null == renegExtData); bool noRenegScsv = !Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); if (noRenegExt && noRenegScsv) { // TODO Consider whether to default to a client extension instead // this.mClientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(this.mClientExtensions); // this.mClientExtensions[ExtensionType.renegotiation_info] = CreateRenegotiationInfo(TlsUtilities.EmptyBytes); this.mOfferedCipherSuites = Arrays.Append(mOfferedCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); } /* * draft-ietf-tls-downgrade-scsv-00 4. If a client sends a ClientHello.client_version * containing a lower value than the latest (highest-valued) version supported by the * client, it SHOULD include the TLS_FALLBACK_SCSV cipher suite value in * ClientHello.cipher_suites. */ if (fallback && !Arrays.Contains(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV)) { this.mOfferedCipherSuites = Arrays.Append(mOfferedCipherSuites, CipherSuite.TLS_FALLBACK_SCSV); } TlsUtilities.WriteUint16ArrayWithUint16Length(mOfferedCipherSuites, message); } TlsUtilities.WriteUint8ArrayWithUint8Length(mOfferedCompressionMethods, message); if (mClientExtensions != null) { WriteExtensions(message, mClientExtensions); } message.WriteToRecordStream(this); }
/// <summary>Connects to the remote system.</summary> /// <param name="verifyer">Will be used when a certificate is received to verify /// that this certificate is accepted by the client.</param> /// <exception cref="IOException">If handshake was not successful</exception> public virtual void Connect( ICertificateVerifyer verifyer) { this.verifyer = verifyer; /* * Send Client hello * * First, generate some random data. */ this.clientRandom = new byte[32]; /* * TLS 1.0 requires a unix-timestamp in the first 4 bytes */ int t = (int)(DateTimeUtilities.CurrentUnixMs() / 1000L); this.clientRandom[0] = (byte)(t >> 24); this.clientRandom[1] = (byte)(t >> 16); this.clientRandom[2] = (byte)(t >> 8); this.clientRandom[3] = (byte)t; random.NextBytes(this.clientRandom, 4, 28); MemoryStream outStr = new MemoryStream(); TlsUtilities.WriteVersion(outStr); outStr.Write(this.clientRandom, 0, this.clientRandom.Length); /* * Length of Session id */ TlsUtilities.WriteUint8((short)0, outStr); /* * Cipher suites */ TlsCipherSuiteManager.WriteCipherSuites(outStr); /* * Compression methods, just the null method. */ byte[] compressionMethods = new byte[] { 0x00 }; TlsUtilities.WriteUint8((short)compressionMethods.Length, outStr); outStr.Write(compressionMethods, 0, compressionMethods.Length); MemoryStream bos = new MemoryStream(); TlsUtilities.WriteUint8(HP_CLIENT_HELLO, bos); TlsUtilities.WriteUint24((int)outStr.Length, bos); byte[] outBytes = outStr.ToArray(); bos.Write(outBytes, 0, outBytes.Length); byte[] message = bos.ToArray(); rs.WriteMessage(RL_HANDSHAKE, message, 0, message.Length); connection_state = CS_CLIENT_HELLO_SEND; /* * We will now read data, until we have completed the handshake. */ while (connection_state != CS_DONE) { rs.ReadData(); } this.tlsInputStream = new TlsInputStream(this); this.tlsOutputStream = new TlsOuputStream(this); }
public static byte[] GetNegotiatedDheGroupsClientExtension(IDictionary extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.negotiated_ff_dhe_groups); return((extensionData != null) ? ReadNegotiatedDheGroupsClientExtension(extensionData) : null); }
/// <exception cref="IOException"></exception> public TlsBlockCipher(TlsContext context, IBlockCipher clientWriteCipher, IBlockCipher serverWriteCipher, IDigest clientWriteDigest, IDigest serverWriteDigest, int cipherKeySize) { this.context = context; this.randomData = new byte[256]; context.NonceRandomGenerator.NextBytes(randomData); this.useExplicitIV = TlsUtilities.IsTlsV11(context); this.encryptThenMac = context.SecurityParameters.encryptThenMac; int key_block_size = (2 * cipherKeySize) + clientWriteDigest.GetDigestSize() + serverWriteDigest.GetDigestSize(); // From TLS 1.1 onwards, block ciphers don't need client_write_IV if (!useExplicitIV) { key_block_size += clientWriteCipher.GetBlockSize() + serverWriteCipher.GetBlockSize(); } byte[] key_block = TlsUtilities.CalculateKeyBlock(context, key_block_size); int offset = 0; TlsMac clientWriteMac = new TlsMac(context, clientWriteDigest, key_block, offset, clientWriteDigest.GetDigestSize()); offset += clientWriteDigest.GetDigestSize(); TlsMac serverWriteMac = new TlsMac(context, serverWriteDigest, key_block, offset, serverWriteDigest.GetDigestSize()); offset += serverWriteDigest.GetDigestSize(); KeyParameter client_write_key = new KeyParameter(key_block, offset, cipherKeySize); offset += cipherKeySize; KeyParameter server_write_key = new KeyParameter(key_block, offset, cipherKeySize); offset += cipherKeySize; byte[] client_write_IV, server_write_IV; if (useExplicitIV) { client_write_IV = new byte[clientWriteCipher.GetBlockSize()]; server_write_IV = new byte[serverWriteCipher.GetBlockSize()]; } else { client_write_IV = Arrays.CopyOfRange(key_block, offset, offset + clientWriteCipher.GetBlockSize()); offset += clientWriteCipher.GetBlockSize(); server_write_IV = Arrays.CopyOfRange(key_block, offset, offset + serverWriteCipher.GetBlockSize()); offset += serverWriteCipher.GetBlockSize(); } if (offset != key_block_size) { throw new TlsFatalAlert(AlertDescription.internal_error); } ICipherParameters encryptParams, decryptParams; if (context.IsServer) { this.mWriteMac = serverWriteMac; this.mReadMac = clientWriteMac; this.encryptCipher = serverWriteCipher; this.decryptCipher = clientWriteCipher; encryptParams = new ParametersWithIV(server_write_key, server_write_IV); decryptParams = new ParametersWithIV(client_write_key, client_write_IV); } else { this.mWriteMac = clientWriteMac; this.mReadMac = serverWriteMac; this.encryptCipher = clientWriteCipher; this.decryptCipher = serverWriteCipher; encryptParams = new ParametersWithIV(client_write_key, client_write_IV); decryptParams = new ParametersWithIV(server_write_key, server_write_IV); } this.encryptCipher.Init(true, encryptParams); this.decryptCipher.Init(false, decryptParams); }
public static short GetNegotiatedDheGroupsServerExtension(IDictionary extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.negotiated_ff_dhe_groups); return((short)((extensionData != null) ? ReadNegotiatedDheGroupsServerExtension(extensionData) : (-1))); }
protected virtual void ProcessClientHello(ServerHandshakeState state, byte[] body) { MemoryStream buf = new MemoryStream(body, false); // TODO Read RFCs for guidance on the expected record layer version number ProtocolVersion client_version = TlsUtilities.ReadVersion(buf); if (!client_version.IsDtls) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } /* * Read the client random */ byte[] client_random = TlsUtilities.ReadFully(32, buf); byte[] sessionID = TlsUtilities.ReadOpaque8(buf); if (sessionID.Length > 32) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } // TODO RFC 4347 has the cookie length restricted to 32, but not in RFC 6347 byte[] cookie = TlsUtilities.ReadOpaque8(buf); int cipher_suites_length = TlsUtilities.ReadUint16(buf); if (cipher_suites_length < 2 || (cipher_suites_length & 1) != 0) { throw new TlsFatalAlert(AlertDescription.decode_error); } /* * NOTE: "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." */ state.offeredCipherSuites = TlsUtilities.ReadUint16Array(cipher_suites_length / 2, buf); int compression_methods_length = TlsUtilities.ReadUint8(buf); if (compression_methods_length < 1) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } state.offeredCompressionMethods = 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. */ state.clientExtensions = TlsProtocol.ReadExtensions(buf); TlsServerContextImpl context = state.serverContext; SecurityParameters securityParameters = context.SecurityParameters; /* * 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) */ securityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(state.clientExtensions); if (!securityParameters.IsExtendedMasterSecret && state.server.RequiresExtendedMasterSecret()) { throw new TlsFatalAlert(AlertDescription.handshake_failure); } context.SetClientVersion(client_version); state.server.NotifyClientVersion(client_version); state.server.NotifyFallback(Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV)); securityParameters.clientRandom = client_random; state.server.NotifyOfferedCipherSuites(state.offeredCipherSuites); state.server.NotifyOfferedCompressionMethods(state.offeredCompressionMethods); /* * 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(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV)) { state.secure_renegotiation = true; } /* * The server MUST check if the "renegotiation_info" extension is included in the * ClientHello. */ byte[] renegExtData = TlsUtilities.GetExtensionData(state.clientExtensions, 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. */ state.secure_renegotiation = true; if (!Arrays.ConstantTimeAreEqual(renegExtData, TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes))) { throw new TlsFatalAlert(AlertDescription.handshake_failure); } } } state.server.NotifySecureRenegotiation(state.secure_renegotiation); if (state.clientExtensions != null) { // NOTE: Validates the padding extension data, if present TlsExtensionsUtilities.GetPaddingExtension(state.clientExtensions); state.server.ProcessClientExtensions(state.clientExtensions); } }
/// <exception cref="IOException"></exception> public TlsAeadCipher(TlsContext context, IAeadBlockCipher clientWriteCipher, IAeadBlockCipher serverWriteCipher, int cipherKeySize, int macSize) { if (!TlsUtilities.IsTlsV12(context)) { throw new TlsFatalAlert(AlertDescription.internal_error); } this.context = context; this.macSize = macSize; // NOTE: Valid for RFC 5288/6655 ciphers but may need review for other AEAD ciphers this.nonce_explicit_length = 8; // TODO SecurityParameters.fixed_iv_length int fixed_iv_length = 4; int key_block_size = (2 * cipherKeySize) + (2 * fixed_iv_length); byte[] key_block = TlsUtilities.CalculateKeyBlock(context, key_block_size); int offset = 0; KeyParameter client_write_key = new KeyParameter(key_block, offset, cipherKeySize); offset += cipherKeySize; KeyParameter server_write_key = new KeyParameter(key_block, offset, cipherKeySize); offset += cipherKeySize; byte[] client_write_IV = Arrays.CopyOfRange(key_block, offset, offset + fixed_iv_length); offset += fixed_iv_length; byte[] server_write_IV = Arrays.CopyOfRange(key_block, offset, offset + fixed_iv_length); offset += fixed_iv_length; if (offset != key_block_size) { throw new TlsFatalAlert(AlertDescription.internal_error); } KeyParameter encryptKey, decryptKey; if (context.IsServer) { this.encryptCipher = serverWriteCipher; this.decryptCipher = clientWriteCipher; this.encryptImplicitNonce = server_write_IV; this.decryptImplicitNonce = client_write_IV; encryptKey = server_write_key; decryptKey = client_write_key; } else { this.encryptCipher = clientWriteCipher; this.decryptCipher = serverWriteCipher; this.encryptImplicitNonce = client_write_IV; this.decryptImplicitNonce = server_write_IV; encryptKey = client_write_key; decryptKey = server_write_key; } byte[] dummyNonce = new byte[fixed_iv_length + nonce_explicit_length]; this.encryptCipher.Init(true, new AeadParameters(encryptKey, 8 * macSize, dummyNonce)); this.decryptCipher.Init(false, new AeadParameters(decryptKey, 8 * macSize, dummyNonce)); }
internal virtual DtlsTransport ServerHandshake(ServerHandshakeState state, DtlsRecordLayer recordLayer) { SecurityParameters securityParameters = state.serverContext.SecurityParameters; DtlsReliableHandshake handshake = new DtlsReliableHandshake(state.serverContext, recordLayer, state.server.GetHandshakeTimeoutMillis()); DtlsReliableHandshake.Message clientMessage = handshake.ReceiveMessage(); // NOTE: DTLSRecordLayer requires any DTLS version, we don't otherwise constrain this //ProtocolVersion recordLayerVersion = recordLayer.ReadVersion; if (clientMessage.Type == HandshakeType.client_hello) { ProcessClientHello(state, clientMessage.Body); } else { throw new TlsFatalAlert(AlertDescription.unexpected_message); } { byte[] serverHelloBody = GenerateServerHello(state); ApplyMaxFragmentLengthExtension(recordLayer, securityParameters.maxFragmentLength); ProtocolVersion recordLayerVersion = state.serverContext.ServerVersion; recordLayer.ReadVersion = recordLayerVersion; recordLayer.SetWriteVersion(recordLayerVersion); handshake.SendMessage(HandshakeType.server_hello, serverHelloBody); } handshake.NotifyHelloComplete(); IList serverSupplementalData = state.server.GetServerSupplementalData(); if (serverSupplementalData != null) { byte[] supplementalDataBody = GenerateSupplementalData(serverSupplementalData); handshake.SendMessage(HandshakeType.supplemental_data, supplementalDataBody); } state.keyExchange = state.server.GetKeyExchange(); state.keyExchange.Init(state.serverContext); state.serverCredentials = state.server.GetCredentials(); Certificate serverCertificate = null; if (state.serverCredentials == null) { state.keyExchange.SkipServerCredentials(); } else { state.keyExchange.ProcessServerCredentials(state.serverCredentials); serverCertificate = state.serverCredentials.Certificate; byte[] certificateBody = GenerateCertificate(serverCertificate); handshake.SendMessage(HandshakeType.certificate, certificateBody); } // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus if (serverCertificate == null || serverCertificate.IsEmpty) { state.allowCertificateStatus = false; } if (state.allowCertificateStatus) { CertificateStatus certificateStatus = state.server.GetCertificateStatus(); if (certificateStatus != null) { byte[] certificateStatusBody = GenerateCertificateStatus(state, certificateStatus); handshake.SendMessage(HandshakeType.certificate_status, certificateStatusBody); } } byte[] serverKeyExchange = state.keyExchange.GenerateServerKeyExchange(); if (serverKeyExchange != null) { handshake.SendMessage(HandshakeType.server_key_exchange, serverKeyExchange); } if (state.serverCredentials != null) { state.certificateRequest = state.server.GetCertificateRequest(); if (state.certificateRequest != null) { if (TlsUtilities.IsTlsV12(state.serverContext) != (state.certificateRequest.SupportedSignatureAlgorithms != null)) { throw new TlsFatalAlert(AlertDescription.internal_error); } state.keyExchange.ValidateCertificateRequest(state.certificateRequest); byte[] certificateRequestBody = GenerateCertificateRequest(state, state.certificateRequest); handshake.SendMessage(HandshakeType.certificate_request, certificateRequestBody); TlsUtilities.TrackHashAlgorithms(handshake.HandshakeHash, state.certificateRequest.SupportedSignatureAlgorithms); } } handshake.SendMessage(HandshakeType.server_hello_done, TlsUtilities.EmptyBytes); handshake.HandshakeHash.SealHashAlgorithms(); clientMessage = handshake.ReceiveMessage(); if (clientMessage.Type == HandshakeType.supplemental_data) { ProcessClientSupplementalData(state, clientMessage.Body); clientMessage = handshake.ReceiveMessage(); } else { state.server.ProcessClientSupplementalData(null); } if (state.certificateRequest == null) { state.keyExchange.SkipClientCredentials(); } else { if (clientMessage.Type == HandshakeType.certificate) { ProcessClientCertificate(state, clientMessage.Body); clientMessage = handshake.ReceiveMessage(); } else { if (TlsUtilities.IsTlsV12(state.serverContext)) { /* * 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); } NotifyClientCertificate(state, Certificate.EmptyChain); } } if (clientMessage.Type == HandshakeType.client_key_exchange) { ProcessClientKeyExchange(state, clientMessage.Body); } else { throw new TlsFatalAlert(AlertDescription.unexpected_message); } TlsHandshakeHash prepareFinishHash = handshake.PrepareToFinish(); securityParameters.sessionHash = TlsProtocol.GetCurrentPrfHash(state.serverContext, prepareFinishHash, null); TlsProtocol.EstablishMasterSecret(state.serverContext, state.keyExchange); recordLayer.InitPendingEpoch(state.server.GetCipher()); /* * 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(state)) { byte[] certificateVerifyBody = handshake.ReceiveMessageBody(HandshakeType.certificate_verify); ProcessCertificateVerify(state, certificateVerifyBody, prepareFinishHash); } // NOTE: Calculated exclusive of the actual Finished message from the client byte[] expectedClientVerifyData = TlsUtilities.CalculateVerifyData(state.serverContext, ExporterLabel.client_finished, TlsProtocol.GetCurrentPrfHash(state.serverContext, handshake.HandshakeHash, null)); ProcessFinished(handshake.ReceiveMessageBody(HandshakeType.finished), expectedClientVerifyData); if (state.expectSessionTicket) { NewSessionTicket newSessionTicket = state.server.GetNewSessionTicket(); byte[] newSessionTicketBody = GenerateNewSessionTicket(state, newSessionTicket); handshake.SendMessage(HandshakeType.session_ticket, newSessionTicketBody); } // NOTE: Calculated exclusive of the Finished message itself byte[] serverVerifyData = TlsUtilities.CalculateVerifyData(state.serverContext, ExporterLabel.server_finished, TlsProtocol.GetCurrentPrfHash(state.serverContext, handshake.HandshakeHash, null)); handshake.SendMessage(HandshakeType.finished, serverVerifyData); handshake.Finish(); //{ // state.sessionParameters = new SessionParameters.Builder() // .SetCipherSuite(securityParameters.CipherSuite) // .SetCompressionAlgorithm(securityParameters.CompressionAlgorithm) // .SetExtendedMasterSecret(securityParameters.IsExtendedMasterSecret) // .SetMasterSecret(securityParameters.MasterSecret) // .SetPeerCertificate(state.clientCertificate) // .SetPskIdentity(securityParameters.PskIdentity) // .SetSrpIdentity(securityParameters.SrpIdentity) // // TODO Consider filtering extensions that aren't relevant to resumed sessions // .SetServerExtensions(state.serverExtensions) // .Build(); // state.tlsSession = TlsUtilities.ImportSession(state.tlsSession.SessionID, state.sessionParameters); // state.serverContext.SetResumableSession(state.tlsSession); //} state.server.NotifyHandshakeComplete(); return(new DtlsTransport(recordLayer)); }
public virtual void Init(TlsContext context) { this.mContext = context; ProtocolVersion clientVersion = context.ClientVersion; if (TlsUtilities.IsSignatureAlgorithmsExtensionAllowed(clientVersion)) { /* * RFC 5264 7.4.1.4.1. If the client does not send the signature_algorithms extension, * the server MUST do the following: * * - If the negotiated key exchange algorithm is one of (RSA, DHE_RSA, DH_RSA, RSA_PSK, * ECDH_RSA, ECDHE_RSA), behave as if client had sent the value {sha1,rsa}. * * - If the negotiated key exchange algorithm is one of (DHE_DSS, DH_DSS), behave as if * the client had sent the value {sha1,dsa}. * * - If the negotiated key exchange algorithm is one of (ECDH_ECDSA, ECDHE_ECDSA), * behave as if the client had sent value {sha1,ecdsa}. */ if (this.mSupportedSignatureAlgorithms == null) { switch (mKeyExchange) { case KeyExchangeAlgorithm.DH_DSS: case KeyExchangeAlgorithm.DHE_DSS: case KeyExchangeAlgorithm.SRP_DSS: { this.mSupportedSignatureAlgorithms = TlsUtilities.GetDefaultDssSignatureAlgorithms(); break; } case KeyExchangeAlgorithm.ECDH_ECDSA: case KeyExchangeAlgorithm.ECDHE_ECDSA: { this.mSupportedSignatureAlgorithms = TlsUtilities.GetDefaultECDsaSignatureAlgorithms(); break; } case KeyExchangeAlgorithm.DH_RSA: case KeyExchangeAlgorithm.DHE_RSA: case KeyExchangeAlgorithm.ECDH_RSA: case KeyExchangeAlgorithm.ECDHE_RSA: case KeyExchangeAlgorithm.RSA: case KeyExchangeAlgorithm.RSA_PSK: case KeyExchangeAlgorithm.SRP_RSA: { this.mSupportedSignatureAlgorithms = TlsUtilities.GetDefaultRsaSignatureAlgorithms(); break; } case KeyExchangeAlgorithm.DHE_PSK: case KeyExchangeAlgorithm.ECDHE_PSK: case KeyExchangeAlgorithm.PSK: case KeyExchangeAlgorithm.SRP: break; default: throw new InvalidOperationException("unsupported key exchange algorithm"); } } } else if (this.mSupportedSignatureAlgorithms != null) { throw new InvalidOperationException("supported_signature_algorithms not allowed for " + clientVersion); } }
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(); AbstractCertificate 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); } }
private bool ProcessRecord(int windowSize, int epoch, byte[] buf, int off, int len) { bool checkPreviousFlight = false; while (len >= MessageHeaderLength) { int fragment_length = TlsUtilities.ReadUint24(buf, off + 9); int message_length = fragment_length + MessageHeaderLength; if (len < message_length) { // NOTE: Truncated message - ignore it break; } int length = TlsUtilities.ReadUint24(buf, off + 1); int fragment_offset = TlsUtilities.ReadUint24(buf, off + 6); if (fragment_offset + fragment_length > length) { // NOTE: Malformed fragment - ignore it and the rest of the record break; } /* * NOTE: This very simple epoch check will only work until we want to support * renegotiation (and we're not likely to do that anyway). */ byte msg_type = TlsUtilities.ReadUint8(buf, off + 0); int expectedEpoch = msg_type == HandshakeType.finished ? 1 : 0; if (epoch != expectedEpoch) { break; } int message_seq = TlsUtilities.ReadUint16(buf, off + 4); if (message_seq >= (mNextReceiveSeq + windowSize)) { // NOTE: Too far ahead - ignore } else if (message_seq >= mNextReceiveSeq) { DtlsReassembler reassembler = (DtlsReassembler)mCurrentInboundFlight[message_seq]; if (reassembler == null) { reassembler = new DtlsReassembler(msg_type, length); mCurrentInboundFlight[message_seq] = reassembler; } reassembler.ContributeFragment(msg_type, length, buf, off + MessageHeaderLength, fragment_offset, fragment_length); } else if (mPreviousInboundFlight != null) { /* * NOTE: If we receive the previous flight of incoming messages in full again, * retransmit our last flight */ DtlsReassembler reassembler = (DtlsReassembler)mPreviousInboundFlight[message_seq]; if (reassembler != null) { reassembler.ContributeFragment(msg_type, length, buf, off + MessageHeaderLength, fragment_offset, fragment_length); checkPreviousFlight = true; } } off += message_length; len -= message_length; } bool result = checkPreviousFlight && CheckAll(mPreviousInboundFlight); if (result) { ResendOutboundFlight(); ResetAll(mPreviousInboundFlight); } return(result); }
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); ProcessCertificateFormats(); /* * */ 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); }
private void processHandshake() { bool read; do { read = false; /* * We need the first 4 bytes, they contain type and length of * the message. */ if (handshakeQueue.Available >= 4) { byte[] beginning = new byte[4]; handshakeQueue.Read(beginning, 0, 4, 0); MemoryStream bis = new MemoryStream(beginning, false); short type = TlsUtilities.ReadUint8(bis); int len = TlsUtilities.ReadUint24(bis); /* * Check if we have enough bytes in the buffer to read * the full message. */ if (handshakeQueue.Available >= (len + 4)) { /* * Read the message. */ byte[] buf = new byte[len]; handshakeQueue.Read(buf, 0, len, 4); handshakeQueue.RemoveData(len + 4); /* * If it is not a finished message, update our hashes * we prepare for the finish message. */ if (type != HP_FINISHED) { rs.hash1.BlockUpdate(beginning, 0, 4); rs.hash2.BlockUpdate(beginning, 0, 4); rs.hash1.BlockUpdate(buf, 0, len); rs.hash2.BlockUpdate(buf, 0, len); } /* * Now, parse the message. */ MemoryStream inStr = new MemoryStream(buf, false); /* * Check the type. */ switch (type) { case HP_CERTIFICATE: { switch (connection_state) { case CS_SERVER_HELLO_RECEIVED: { /* * Parse the certificates. */ Certificate cert = Certificate.Parse(inStr); AssertEmpty(inStr); X509CertificateStructure x509Cert = cert.certs[0]; SubjectPublicKeyInfo keyInfo = x509Cert.SubjectPublicKeyInfo; try { this.serverPublicKey = PublicKeyFactory.CreateKey(keyInfo); } catch (Exception) { this.FailWithError(AL_fatal, AP_unsupported_certificate); } // Sanity check the PublicKeyFactory if (this.serverPublicKey.IsPrivate) { this.FailWithError(AL_fatal, AP_internal_error); } /* * Perform various checks per RFC2246 7.4.2 * TODO "Unless otherwise specified, the signing algorithm for the certificate * must be the same as the algorithm for the certificate key." */ switch (this.chosenCipherSuite.KeyExchangeAlgorithm) { case TlsCipherSuite.KE_RSA: if (!(this.serverPublicKey is RsaKeyParameters)) { this.FailWithError(AL_fatal, AP_certificate_unknown); } validateKeyUsage(x509Cert, KeyUsage.KeyEncipherment); break; case TlsCipherSuite.KE_DHE_RSA: if (!(this.serverPublicKey is RsaKeyParameters)) { this.FailWithError(AL_fatal, AP_certificate_unknown); } validateKeyUsage(x509Cert, KeyUsage.DigitalSignature); break; case TlsCipherSuite.KE_DHE_DSS: if (!(this.serverPublicKey is DsaPublicKeyParameters)) { this.FailWithError(AL_fatal, AP_certificate_unknown); } break; default: this.FailWithError(AL_fatal, AP_unsupported_certificate); break; } /* * Verify them. */ if (!this.verifyer.IsValid(cert.GetCerts())) { this.FailWithError(AL_fatal, AP_user_canceled); } break; } default: this.FailWithError(AL_fatal, AP_unexpected_message); break; } connection_state = CS_SERVER_CERTIFICATE_RECEIVED; read = true; break; } case HP_FINISHED: switch (connection_state) { case CS_SERVER_CHANGE_CIPHER_SPEC_RECEIVED: /* * Read the checksum from the finished message, * it has always 12 bytes. */ byte[] receivedChecksum = new byte[12]; TlsUtilities.ReadFully(receivedChecksum, inStr); AssertEmpty(inStr); /* * Calculate our own checksum. */ byte[] checksum = new byte[12]; byte[] md5andsha1 = new byte[16 + 20]; rs.hash2.DoFinal(md5andsha1, 0); TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("server finished"), md5andsha1, checksum); /* * Compare both checksums. */ for (int i = 0; i < receivedChecksum.Length; i++) { if (receivedChecksum[i] != checksum[i]) { /* * Wrong checksum in the finished message. */ this.FailWithError(AL_fatal, AP_handshake_failure); } } connection_state = CS_DONE; /* * We are now ready to receive application data. */ this.appDataReady = true; read = true; break; default: this.FailWithError(AL_fatal, AP_unexpected_message); break; } break; case HP_SERVER_HELLO: switch (connection_state) { case CS_CLIENT_HELLO_SEND: /* * Read the server hello message */ TlsUtilities.CheckVersion(inStr, this); /* * Read the server random */ this.serverRandom = new byte[32]; TlsUtilities.ReadFully(this.serverRandom, inStr); /* * Currently, we don't support session ids */ short sessionIdLength = TlsUtilities.ReadUint8(inStr); byte[] sessionId = new byte[sessionIdLength]; TlsUtilities.ReadFully(sessionId, inStr); /* * Find out which ciphersuite the server has * chosen. If we don't support this ciphersuite, * the TlsCipherSuiteManager will throw an * exception. */ this.chosenCipherSuite = TlsCipherSuiteManager.GetCipherSuite( TlsUtilities.ReadUint16(inStr), this); /* * We support only the null compression which * means no compression. */ short compressionMethod = TlsUtilities.ReadUint8(inStr); if (compressionMethod != 0) { this.FailWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_illegal_parameter); } AssertEmpty(inStr); connection_state = CS_SERVER_HELLO_RECEIVED; read = true; break; default: this.FailWithError(AL_fatal, AP_unexpected_message); break; } break; case HP_SERVER_HELLO_DONE: switch (connection_state) { case CS_SERVER_CERTIFICATE_RECEIVED: case CS_SERVER_KEY_EXCHANGE_RECEIVED: case CS_CERTIFICATE_REQUEST_RECEIVED: // NB: Original code used case label fall-through if (connection_state == CS_SERVER_CERTIFICATE_RECEIVED) { /* * There was no server key exchange message, check * that we are doing RSA key exchange. */ if (this.chosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_RSA) { this.FailWithError(AL_fatal, AP_unexpected_message); } } AssertEmpty(inStr); bool isCertReq = (connection_state == CS_CERTIFICATE_REQUEST_RECEIVED); connection_state = CS_SERVER_HELLO_DONE_RECEIVED; if (isCertReq) { sendClientCertificate(); } /* * Send the client key exchange message, depending * on the key exchange we are using in our * ciphersuite. */ switch (this.chosenCipherSuite.KeyExchangeAlgorithm) { case TlsCipherSuite.KE_RSA: { /* * We are doing RSA key exchange. We will * choose a pre master secret and send it * rsa encrypted to the server. * * Prepare pre master secret. */ pms = new byte[48]; pms[0] = 3; pms[1] = 1; random.NextBytes(pms, 2, 46); /* * Encode the pms and send it to the server. * * Prepare an Pkcs1Encoding with good random * padding. */ RsaBlindedEngine rsa = new RsaBlindedEngine(); Pkcs1Encoding encoding = new Pkcs1Encoding(rsa); encoding.Init(true, new ParametersWithRandom(this.serverPublicKey, this.random)); byte[] encrypted = null; try { encrypted = encoding.ProcessBlock(pms, 0, pms.Length); } catch (InvalidCipherTextException) { /* * This should never happen, only during decryption. */ this.FailWithError(AL_fatal, AP_internal_error); } /* * Send the encrypted pms. */ sendClientKeyExchange(encrypted); break; } case TlsCipherSuite.KE_DHE_DSS: case TlsCipherSuite.KE_DHE_RSA: { /* * Send the Client Key Exchange message for * DHE key exchange. */ byte[] YcByte = BigIntegers.AsUnsignedByteArray(this.Yc); sendClientKeyExchange(YcByte); break; } default: /* * Problem during handshake, we don't know * how to handle this key exchange method. */ this.FailWithError(AL_fatal, AP_unexpected_message); break; } connection_state = CS_CLIENT_KEY_EXCHANGE_SEND; /* * Now, we send change cipher state */ byte[] cmessage = new byte[1]; cmessage[0] = 1; rs.WriteMessage((short)RL_CHANGE_CIPHER_SPEC, cmessage, 0, cmessage.Length); connection_state = CS_CLIENT_CHANGE_CIPHER_SPEC_SEND; /* * Calculate the ms */ this.ms = new byte[48]; byte[] randBytes = new byte[clientRandom.Length + serverRandom.Length]; Array.Copy(clientRandom, 0, randBytes, 0, clientRandom.Length); Array.Copy(serverRandom, 0, randBytes, clientRandom.Length, serverRandom.Length); TlsUtilities.PRF(pms, TlsUtilities.ToByteArray("master secret"), randBytes, this.ms); /* * Initialize our cipher suite */ rs.writeSuite = this.chosenCipherSuite; rs.writeSuite.Init(this.ms, clientRandom, serverRandom); /* * Send our finished message. */ byte[] checksum = new byte[12]; byte[] md5andsha1 = new byte[16 + 20]; rs.hash1.DoFinal(md5andsha1, 0); TlsUtilities.PRF(this.ms, TlsUtilities.ToByteArray("client finished"), md5andsha1, checksum); MemoryStream bos2 = new MemoryStream(); TlsUtilities.WriteUint8(HP_FINISHED, bos2); TlsUtilities.WriteUint24(12, bos2); bos2.Write(checksum, 0, checksum.Length); byte[] message2 = bos2.ToArray(); rs.WriteMessage((short)RL_HANDSHAKE, message2, 0, message2.Length); this.connection_state = CS_CLIENT_FINISHED_SEND; read = true; break; default: this.FailWithError(AL_fatal, AP_handshake_failure); break; } break; case HP_SERVER_KEY_EXCHANGE: { switch (connection_state) { case CS_SERVER_CERTIFICATE_RECEIVED: { /* * Check that we are doing DHE key exchange */ switch (this.chosenCipherSuite.KeyExchangeAlgorithm) { case TlsCipherSuite.KE_DHE_RSA: { processDHEKeyExchange(inStr, new TlsRsaSigner()); break; } case TlsCipherSuite.KE_DHE_DSS: { processDHEKeyExchange(inStr, new TlsDssSigner()); break; } default: this.FailWithError(AL_fatal, AP_unexpected_message); break; } break; } default: this.FailWithError(AL_fatal, AP_unexpected_message); break; } this.connection_state = CS_SERVER_KEY_EXCHANGE_RECEIVED; read = true; break; } case HP_CERTIFICATE_REQUEST: switch (connection_state) { case CS_SERVER_CERTIFICATE_RECEIVED: case CS_SERVER_KEY_EXCHANGE_RECEIVED: { // NB: Original code used case label fall-through if (connection_state == CS_SERVER_CERTIFICATE_RECEIVED) { /* * There was no server key exchange message, check * that we are doing RSA key exchange. */ if (this.chosenCipherSuite.KeyExchangeAlgorithm != TlsCipherSuite.KE_RSA) { this.FailWithError(AL_fatal, AP_unexpected_message); } } int typesLength = TlsUtilities.ReadUint8(inStr); byte[] types = new byte[typesLength]; TlsUtilities.ReadFully(types, inStr); int authsLength = TlsUtilities.ReadUint16(inStr); byte[] auths = new byte[authsLength]; TlsUtilities.ReadFully(auths, inStr); AssertEmpty(inStr); break; } default: this.FailWithError(AL_fatal, AP_unexpected_message); break; } this.connection_state = CS_CERTIFICATE_REQUEST_RECEIVED; read = true; break; case HP_HELLO_REQUEST: case HP_CLIENT_KEY_EXCHANGE: case HP_CERTIFICATE_VERIFY: case HP_CLIENT_HELLO: default: // We do not support this! this.FailWithError(AL_fatal, AP_unexpected_message); break; } } } }while (read); }
private void ProcessHandshake() { bool read; do { read = false; /* * We need the first 4 bytes, they contain type and length of the message. */ if (mHandshakeQueue.Available >= 4) { byte[] beginning = new byte[4]; mHandshakeQueue.Read(beginning, 0, 4, 0); byte type = TlsUtilities.ReadUint8(beginning, 0); int len = TlsUtilities.ReadUint24(beginning, 1); /* * Check if we have enough bytes in the buffer to read the full message. */ if (mHandshakeQueue.Available >= (len + 4)) { /* * Read the message. */ byte[] buf = mHandshakeQueue.RemoveData(len, 4); CheckReceivedChangeCipherSpec(mConnectionState == CS_END || type == HandshakeType.finished); /* * RFC 2246 7.4.9. The value handshake_messages includes all handshake messages * starting at client hello up to, but not including, this finished message. * [..] Note: [Also,] Hello Request messages are omitted from handshake hashes. */ switch (type) { case HandshakeType.hello_request: break; case HandshakeType.finished: default: { TlsContext ctx = Context; if (type == HandshakeType.finished && this.mExpectedVerifyData == null && ctx.SecurityParameters.MasterSecret != null) { this.mExpectedVerifyData = CreateVerifyData(!ctx.IsServer); } mRecordStream.UpdateHandshakeData(beginning, 0, 4); mRecordStream.UpdateHandshakeData(buf, 0, len); break; } } /* * Now, parse the message. */ HandleHandshakeMessage(type, buf); read = true; } } }while (read); }
private void processDHEKeyExchange( MemoryStream inStr, ISigner signer) { Stream sigIn = inStr; if (signer != null) { signer.Init(false, this.serverPublicKey); signer.BlockUpdate(this.clientRandom, 0, this.clientRandom.Length); signer.BlockUpdate(this.serverRandom, 0, this.serverRandom.Length); sigIn = new SignerStream(inStr, signer, null); } /* * Parse the Structure */ int pLength = TlsUtilities.ReadUint16(sigIn); byte[] pByte = new byte[pLength]; TlsUtilities.ReadFully(pByte, sigIn); int gLength = TlsUtilities.ReadUint16(sigIn); byte[] gByte = new byte[gLength]; TlsUtilities.ReadFully(gByte, sigIn); int YsLength = TlsUtilities.ReadUint16(sigIn); byte[] YsByte = new byte[YsLength]; TlsUtilities.ReadFully(YsByte, sigIn); if (signer != null) { int sigLength = TlsUtilities.ReadUint16(inStr); byte[] sigByte = new byte[sigLength]; TlsUtilities.ReadFully(sigByte, inStr); /* * Verify the Signature. */ if (!signer.VerifySignature(sigByte)) { this.FailWithError(AL_fatal, AP_bad_certificate); } } this.AssertEmpty(inStr); /* * Do the DH calculation. */ BigInteger p = new BigInteger(1, pByte); BigInteger g = new BigInteger(1, gByte); BigInteger Ys = new BigInteger(1, YsByte); /* * Check the DH parameter values */ if (!p.IsProbablePrime(10)) { this.FailWithError(AL_fatal, AP_illegal_parameter); } if (g.CompareTo(BigInteger.Two) < 0 || g.CompareTo(p.Subtract(BigInteger.Two)) > 0) { this.FailWithError(AL_fatal, AP_illegal_parameter); } // TODO For static DH public values, see additional checks in RFC 2631 2.1.5 if (Ys.CompareTo(BigInteger.Two) < 0 || Ys.CompareTo(p.Subtract(BigInteger.One)) > 0) { this.FailWithError(AL_fatal, AP_illegal_parameter); } /* * Diffie-Hellman basic key agreement */ DHParameters dhParams = new DHParameters(p, g); // Generate a keypair DHBasicKeyPairGenerator dhGen = new DHBasicKeyPairGenerator(); dhGen.Init(new DHKeyGenerationParameters(random, dhParams)); AsymmetricCipherKeyPair dhPair = dhGen.GenerateKeyPair(); // Store the public value to send to server this.Yc = ((DHPublicKeyParameters)dhPair.Public).Y; // Calculate the shared secret DHBasicAgreement dhAgree = new DHBasicAgreement(); dhAgree.Init(dhPair.Private); BigInteger agreement = dhAgree.CalculateAgreement(new DHPublicKeyParameters(Ys, dhParams)); this.pms = BigIntegers.AsUnsignedByteArray(agreement); }
protected internal static int GetPrfAlgorithm(TlsContext context, int ciphersuite) { bool isTLSv12 = TlsUtilities.IsTlsV12(context); switch (ciphersuite) { case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256: case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256: case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256: case CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA256: case CipherSuite.TLS_DH_DSS_WITH_AES_128_GCM_SHA256: case CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA256: case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256: case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256: case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256: case CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA256: case CipherSuite.TLS_DH_RSA_WITH_AES_128_GCM_SHA256: case CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA256: case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256: case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256: case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256: case CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256: case CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256: case CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA256: case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256: case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256: case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256: case CipherSuite.TLS_DHE_PSK_WITH_AES_128_CCM: case CipherSuite.TLS_DHE_PSK_WITH_AES_128_GCM_SHA256: case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CCM: case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256: case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256: case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM: case CipherSuite.TLS_DHE_RSA_WITH_AES_128_CCM_8: case CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256: case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256: case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM: case CipherSuite.TLS_DHE_RSA_WITH_AES_256_CCM_8: case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256: case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256: case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256: case CipherSuite.TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256: case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256: case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256: case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256: case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256: case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256: case CipherSuite.TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256: case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256: case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256: case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM: case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8: case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM: case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8: case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256: case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256: case CipherSuite.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: case CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256: case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256: case CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: case CipherSuite.TLS_PSK_DHE_WITH_AES_128_CCM_8: case CipherSuite.TLS_PSK_DHE_WITH_AES_256_CCM_8: case CipherSuite.TLS_PSK_WITH_AES_128_CCM: case CipherSuite.TLS_PSK_WITH_AES_128_CCM_8: case CipherSuite.TLS_PSK_WITH_AES_128_GCM_SHA256: case CipherSuite.TLS_PSK_WITH_AES_256_CCM: case CipherSuite.TLS_PSK_WITH_AES_256_CCM_8: case CipherSuite.TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256: case CipherSuite.TLS_RSA_PSK_WITH_AES_128_GCM_SHA256: case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256: case CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256: case CipherSuite.TLS_RSA_WITH_AES_128_CCM: case CipherSuite.TLS_RSA_WITH_AES_128_CCM_8: case CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256: case CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA256: case CipherSuite.TLS_RSA_WITH_AES_256_CCM: case CipherSuite.TLS_RSA_WITH_AES_256_CCM_8: case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256: case CipherSuite.TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256: case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256: case CipherSuite.TLS_RSA_WITH_NULL_SHA256: { if (isTLSv12) { return(PrfAlgorithm.tls_prf_sha256); } throw new TlsFatalAlert(AlertDescription.illegal_parameter); } case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384: case CipherSuite.TLS_DH_DSS_WITH_AES_256_GCM_SHA384: case CipherSuite.TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384: case CipherSuite.TLS_DH_RSA_WITH_AES_256_GCM_SHA384: case CipherSuite.TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384: case CipherSuite.TLS_DHE_DSS_WITH_AES_256_GCM_SHA384: case CipherSuite.TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384: case CipherSuite.TLS_DHE_PSK_WITH_AES_256_GCM_SHA384: case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384: case CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384: case CipherSuite.TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384: case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384: case CipherSuite.TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384: case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384: case CipherSuite.TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384: case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384: case CipherSuite.TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384: case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384: case CipherSuite.TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384: case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384: case CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384: case CipherSuite.TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384: case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384: case CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384: case CipherSuite.TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384: case CipherSuite.TLS_PSK_WITH_AES_256_GCM_SHA384: case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384: case CipherSuite.TLS_RSA_PSK_WITH_AES_256_GCM_SHA384: case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384: case CipherSuite.TLS_RSA_WITH_AES_256_GCM_SHA384: case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384: { if (isTLSv12) { return(PrfAlgorithm.tls_prf_sha384); } throw new TlsFatalAlert(AlertDescription.illegal_parameter); } case CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384: case CipherSuite.TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384: case CipherSuite.TLS_DHE_PSK_WITH_NULL_SHA384: case CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384: case CipherSuite.TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384: case CipherSuite.TLS_ECDHE_PSK_WITH_NULL_SHA384: case CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA384: case CipherSuite.TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384: case CipherSuite.TLS_PSK_WITH_NULL_SHA384: case CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384: case CipherSuite.TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384: case CipherSuite.TLS_RSA_PSK_WITH_NULL_SHA384: { if (isTLSv12) { return(PrfAlgorithm.tls_prf_sha384); } return(PrfAlgorithm.tls_prf_legacy); } default: { if (isTLSv12) { return(PrfAlgorithm.tls_prf_sha256); } return(PrfAlgorithm.tls_prf_legacy); } } }
protected override void HandleHandshakeMessage(byte type, byte[] data) { MemoryStream buf = new MemoryStream(data, false); if (this.mResumedSession) { if (type != HandshakeType.finished || this.mConnectionState != CS_SERVER_HELLO) { throw new TlsFatalAlert(AlertDescription.unexpected_message); } ProcessFinishedMessage(buf); this.mConnectionState = CS_SERVER_FINISHED; SendFinishedMessage(); this.mConnectionState = CS_CLIENT_FINISHED; this.mConnectionState = CS_END; return; } switch (type) { case HandshakeType.certificate: { switch (this.mConnectionState) { case CS_SERVER_HELLO: case CS_SERVER_SUPPLEMENTAL_DATA: { if (this.mConnectionState == CS_SERVER_HELLO) { HandleSupplementalData(null); } // Parse the Certificate message and Send to cipher suite this.mPeerCertificate = Certificate.Parse(buf); AssertEmpty(buf); // TODO[RFC 3546] Check whether empty certificates is possible, allowed, or excludes CertificateStatus if (this.mPeerCertificate == null || this.mPeerCertificate.IsEmpty) { this.mAllowCertificateStatus = false; } this.mKeyExchange.ProcessServerCertificate(this.mPeerCertificate); this.mAuthentication = mTlsClient.GetAuthentication(); this.mAuthentication.NotifyServerCertificate(this.mPeerCertificate); break; } default: throw new TlsFatalAlert(AlertDescription.unexpected_message); } this.mConnectionState = CS_SERVER_CERTIFICATE; break; } case HandshakeType.certificate_status: { switch (this.mConnectionState) { case CS_SERVER_CERTIFICATE: { if (!this.mAllowCertificateStatus) { /* * RFC 3546 3.6. If a server returns a "CertificateStatus" message, then the * server MUST have included an extension of type "status_request" with empty * "extension_data" in the extended server hello.. */ throw new TlsFatalAlert(AlertDescription.unexpected_message); } this.mCertificateStatus = CertificateStatus.Parse(buf); AssertEmpty(buf); // TODO[RFC 3546] Figure out how to provide this to the client/authentication. this.mConnectionState = CS_CERTIFICATE_STATUS; break; } default: throw new TlsFatalAlert(AlertDescription.unexpected_message); } break; } case HandshakeType.finished: { switch (this.mConnectionState) { case CS_CLIENT_FINISHED: case CS_SERVER_SESSION_TICKET: { if (this.mConnectionState == CS_CLIENT_FINISHED && this.mExpectSessionTicket) { /* * RFC 5077 3.3. This message MUST be sent if the server included a * SessionTicket extension in the ServerHello. */ throw new TlsFatalAlert(AlertDescription.unexpected_message); } ProcessFinishedMessage(buf); this.mConnectionState = CS_SERVER_FINISHED; this.mConnectionState = CS_END; break; } default: throw new TlsFatalAlert(AlertDescription.unexpected_message); } break; } case HandshakeType.server_hello: { switch (this.mConnectionState) { case CS_CLIENT_HELLO: { ReceiveServerHelloMessage(buf); this.mConnectionState = CS_SERVER_HELLO; this.mRecordStream.NotifyHelloComplete(); ApplyMaxFragmentLengthExtension(); if (this.mResumedSession) { this.mSecurityParameters.masterSecret = Arrays.Clone(this.mSessionParameters.MasterSecret); this.mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher()); SendChangeCipherSpecMessage(); } else { InvalidateSession(); if (this.mSelectedSessionID.Length > 0) { this.mTlsSession = new TlsSessionImpl(this.mSelectedSessionID, null); } } break; } default: throw new TlsFatalAlert(AlertDescription.unexpected_message); } break; } case HandshakeType.supplemental_data: { switch (this.mConnectionState) { case CS_SERVER_HELLO: { HandleSupplementalData(ReadSupplementalDataMessage(buf)); break; } default: throw new TlsFatalAlert(AlertDescription.unexpected_message); } break; } case HandshakeType.server_hello_done: { switch (this.mConnectionState) { case CS_SERVER_HELLO: case CS_SERVER_SUPPLEMENTAL_DATA: case CS_SERVER_CERTIFICATE: case CS_CERTIFICATE_STATUS: case CS_SERVER_KEY_EXCHANGE: case CS_CERTIFICATE_REQUEST: { if (mConnectionState < CS_SERVER_SUPPLEMENTAL_DATA) { HandleSupplementalData(null); } if (mConnectionState < CS_SERVER_CERTIFICATE) { // There was no server certificate message; check it's OK this.mKeyExchange.SkipServerCredentials(); this.mAuthentication = null; } if (mConnectionState < CS_SERVER_KEY_EXCHANGE) { // There was no server key exchange message; check it's OK this.mKeyExchange.SkipServerKeyExchange(); } AssertEmpty(buf); this.mConnectionState = CS_SERVER_HELLO_DONE; this.mRecordStream.HandshakeHash.SealHashAlgorithms(); IList clientSupplementalData = mTlsClient.GetClientSupplementalData(); if (clientSupplementalData != null) { SendSupplementalDataMessage(clientSupplementalData); } this.mConnectionState = CS_CLIENT_SUPPLEMENTAL_DATA; TlsCredentials clientCreds = null; if (mCertificateRequest == null) { this.mKeyExchange.SkipClientCredentials(); } else { clientCreds = this.mAuthentication.GetClientCredentials(mCertificateRequest); if (clientCreds == null) { this.mKeyExchange.SkipClientCredentials(); /* * 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. */ SendCertificateMessage(Certificate.EmptyChain); } else { this.mKeyExchange.ProcessClientCredentials(clientCreds); SendCertificateMessage(clientCreds.Certificate); } } this.mConnectionState = CS_CLIENT_CERTIFICATE; /* * Send the client key exchange message, depending on the key exchange we are using * in our CipherSuite. */ SendClientKeyExchangeMessage(); this.mConnectionState = CS_CLIENT_KEY_EXCHANGE; TlsHandshakeHash prepareFinishHash = mRecordStream.PrepareToFinish(); this.mSecurityParameters.sessionHash = GetCurrentPrfHash(Context, prepareFinishHash, null); EstablishMasterSecret(Context, mKeyExchange); mRecordStream.SetPendingConnectionState(Peer.GetCompression(), Peer.GetCipher()); if (clientCreds != null && clientCreds is TlsSignerCredentials) { TlsSignerCredentials signerCredentials = (TlsSignerCredentials)clientCreds; /* * RFC 5246 4.7. digitally-signed element needs SignatureAndHashAlgorithm from TLS 1.2 */ SignatureAndHashAlgorithm signatureAndHashAlgorithm = TlsUtilities.GetSignatureAndHashAlgorithm( Context, signerCredentials); byte[] hash; if (signatureAndHashAlgorithm == null) { hash = mSecurityParameters.SessionHash; } else { hash = prepareFinishHash.GetFinalHash(signatureAndHashAlgorithm.Hash); } byte[] signature = signerCredentials.GenerateCertificateSignature(hash); DigitallySigned certificateVerify = new DigitallySigned(signatureAndHashAlgorithm, signature); SendCertificateVerifyMessage(certificateVerify); this.mConnectionState = CS_CERTIFICATE_VERIFY; } SendChangeCipherSpecMessage(); SendFinishedMessage(); break; } default: throw new TlsFatalAlert(AlertDescription.handshake_failure); } this.mConnectionState = CS_CLIENT_FINISHED; break; } case HandshakeType.server_key_exchange: { switch (this.mConnectionState) { case CS_SERVER_HELLO: case CS_SERVER_SUPPLEMENTAL_DATA: case CS_SERVER_CERTIFICATE: case CS_CERTIFICATE_STATUS: { if (mConnectionState < CS_SERVER_SUPPLEMENTAL_DATA) { HandleSupplementalData(null); } if (mConnectionState < CS_SERVER_CERTIFICATE) { // There was no server certificate message; check it's OK this.mKeyExchange.SkipServerCredentials(); this.mAuthentication = null; } this.mKeyExchange.ProcessServerKeyExchange(buf); AssertEmpty(buf); break; } default: throw new TlsFatalAlert(AlertDescription.unexpected_message); } this.mConnectionState = CS_SERVER_KEY_EXCHANGE; break; } case HandshakeType.certificate_request: { switch (this.mConnectionState) { case CS_SERVER_CERTIFICATE: case CS_CERTIFICATE_STATUS: case CS_SERVER_KEY_EXCHANGE: { if (this.mConnectionState != CS_SERVER_KEY_EXCHANGE) { // There was no server key exchange message; check it's OK this.mKeyExchange.SkipServerKeyExchange(); } if (this.mAuthentication == null) { /* * RFC 2246 7.4.4. It is a fatal handshake_failure alert for an anonymous server * to request client identification. */ throw new TlsFatalAlert(AlertDescription.handshake_failure); } this.mCertificateRequest = CertificateRequest.Parse(Context, buf); AssertEmpty(buf); this.mKeyExchange.ValidateCertificateRequest(this.mCertificateRequest); /* * TODO Give the client a chance to immediately select the CertificateVerify hash * algorithm here to avoid tracking the other hash algorithms unnecessarily? */ TlsUtilities.TrackHashAlgorithms(this.mRecordStream.HandshakeHash, this.mCertificateRequest.SupportedSignatureAlgorithms); break; } default: throw new TlsFatalAlert(AlertDescription.unexpected_message); } this.mConnectionState = CS_CERTIFICATE_REQUEST; break; } case HandshakeType.session_ticket: { switch (this.mConnectionState) { case CS_CLIENT_FINISHED: { if (!this.mExpectSessionTicket) { /* * RFC 5077 3.3. This message MUST NOT be sent if the server did not include a * SessionTicket extension in the ServerHello. */ throw new TlsFatalAlert(AlertDescription.unexpected_message); } /* * RFC 5077 3.4. If the client receives a session ticket from the server, then it * discards any Session ID that was sent in the ServerHello. */ InvalidateSession(); ReceiveNewSessionTicketMessage(buf); break; } default: throw new TlsFatalAlert(AlertDescription.unexpected_message); } this.mConnectionState = CS_SERVER_SESSION_TICKET; break; } case HandshakeType.hello_request: { AssertEmpty(buf); /* * RFC 2246 7.4.1.1 Hello request This message will be ignored by the client if the * client is currently negotiating a session. This message may be ignored by the client * if it does not wish to renegotiate a session, or the client may, if it wishes, * respond with a no_renegotiation alert. */ if (this.mConnectionState == CS_END) { RefuseRenegotiation(); } break; } case HandshakeType.client_hello: case HandshakeType.client_key_exchange: case HandshakeType.certificate_verify: case HandshakeType.hello_verify_request: default: throw new TlsFatalAlert(AlertDescription.unexpected_message); } }