public static GetExtensionData ( IDictionary extensions, int extensionType ) : byte[] | ||
extensions | IDictionary | |
extensionType | int | |
return | byte[] |
public static int GetPaddingExtension(IDictionary extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, 0x15); return((extensionData != null) ? ReadPaddingExtension(extensionData) : -1); }
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; }
public static byte[] GetNegotiatedDheGroupsClientExtension(IDictionary extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.negotiated_ff_dhe_groups); return(extensionData == null ? null : ReadNegotiatedDheGroupsClientExtension(extensionData)); }
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; securityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(state.clientExtensions); 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) { state.server.ProcessClientExtensions(state.clientExtensions); } }
public static int[] GetSupportedEllipticCurvesExtension(IDictionary extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.supported_groups); return(extensionData == null ? null : ReadSupportedEllipticCurvesExtension(extensionData)); }
protected virtual byte[] GenerateClientHello(ClientHandshakeState state, TlsClient client) { ProtocolVersion client_version = client.ClientVersion; if (!client_version.IsDtls) { throw new TlsFatalAlert(AlertDescription.internal_error); } TlsClientContextImpl context = state.clientContext; context.SetClientVersion(client_version); SecurityParameters securityParameters = context.SecurityParameters; // Session ID byte[] session_id = TlsUtilities.EmptyBytes; if (state.tlsSession != null) { session_id = state.tlsSession.SessionID; if (session_id == null || session_id.Length > 32) { session_id = TlsUtilities.EmptyBytes; } } bool fallback = client.IsFallback; state.offeredCipherSuites = client.GetCipherSuites(); if (session_id.Length > 0 && state.sessionParameters != null) { if (!state.sessionParameters.IsExtendedMasterSecret || !Arrays.Contains(state.offeredCipherSuites, state.sessionParameters.CipherSuite) || CompressionMethod.cls_null != state.sessionParameters.CompressionAlgorithm) { session_id = TlsUtilities.EmptyBytes; } } state.clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(client.GetClientExtensions()); TlsExtensionsUtilities.AddExtendedMasterSecretExtension(state.clientExtensions); MemoryStream buf = new MemoryStream(); TlsUtilities.WriteVersion(client_version, buf); buf.Write(securityParameters.ClientRandom, 0, securityParameters.ClientRandom.Length); TlsUtilities.WriteOpaque8(session_id, buf); // Cookie TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, buf); // 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(state.clientExtensions, ExtensionType.renegotiation_info); bool noRenegExt = (null == renegExtData); bool noRenegSCSV = !Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); if (noRenegExt && noRenegSCSV) { // TODO Consider whether to default to a client extension instead state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); } /* * RFC 7507 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 [..]. (The * client SHOULD put TLS_FALLBACK_SCSV after all cipher suites that it actually intends * to negotiate.) */ if (fallback && !Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV)) { state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV); } TlsUtilities.WriteUint16ArrayWithUint16Length(state.offeredCipherSuites, buf); } TlsUtilities.WriteUint8ArrayWithUint8Length(new byte[] { CompressionMethod.cls_null }, buf); TlsProtocol.WriteExtensions(buf, state.clientExtensions); return(buf.ToArray()); }
protected virtual void ProcessServerHello(ClientHandshakeState state, byte[] body) { SecurityParameters securityParameters = state.clientContext.SecurityParameters; MemoryStream buf = new MemoryStream(body, false); ProtocolVersion server_version = TlsUtilities.ReadVersion(buf); ReportServerVersion(state, server_version); securityParameters.serverRandom = TlsUtilities.ReadFully(32, buf); state.selectedSessionID = TlsUtilities.ReadOpaque8(buf); if (state.selectedSessionID.Length > 32) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } state.client.NotifySessionID(state.selectedSessionID); state.selectedCipherSuite = TlsUtilities.ReadUint16(buf); if (!Arrays.Contains(state.offeredCipherSuites, state.selectedCipherSuite) || state.selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL || CipherSuite.IsScsv(state.selectedCipherSuite) || !TlsUtilities.IsValidCipherSuiteForVersion(state.selectedCipherSuite, server_version)) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } ValidateSelectedCipherSuite(state.selectedCipherSuite, AlertDescription.illegal_parameter); state.client.NotifySelectedCipherSuite(state.selectedCipherSuite); state.selectedCompressionMethod = TlsUtilities.ReadUint8(buf); if (!Arrays.Contains(state.offeredCompressionMethods, (byte)state.selectedCompressionMethod)) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } state.client.NotifySelectedCompressionMethod((byte)state.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. */ /* * 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. */ // Integer -> byte[] IDictionary serverExtensions = TlsProtocol.ReadExtensions(buf); /* * draft-ietf-tls-session-hash-01 5.2. If a server receives the "extended_master_secret" * extension, it MUST include the "extended_master_secret" extension in its ServerHello * message. */ bool serverSentExtendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(serverExtensions); if (serverSentExtendedMasterSecret != securityParameters.extendedMasterSecret) { throw new TlsFatalAlert(AlertDescription.handshake_failure); } /* * 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 (serverExtensions != null) { foreach (int extType in serverExtensions.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(state.clientExtensions, extType)) { throw new TlsFatalAlert(AlertDescription.unsupported_extension); } /* * draft-ietf-tls-session-hash-01 5.2. Implementation note: if the server decides to * proceed with resumption, the extension does not have any effect. Requiring the * extension to be included anyway makes the extension negotiation logic easier, * because it does not depend on whether resumption is accepted or not. */ if (extType == ExtensionType.extended_master_secret) { continue; } /* * 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[.] */ // TODO[sessions] // 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 = (byte[])serverExtensions[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). */ state.secure_renegotiation = true; if (!Arrays.ConstantTimeAreEqual(renegExtData, TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes))) { throw new TlsFatalAlert(AlertDescription.handshake_failure); } } } /* * 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(serverExtensions); if (serverSentEncryptThenMAC && !TlsUtilities.IsBlockCipherSuite(state.selectedCipherSuite)) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } securityParameters.encryptThenMac = serverSentEncryptThenMAC; state.maxFragmentLength = EvaluateMaxFragmentLengthExtension(state.clientExtensions, serverExtensions, AlertDescription.illegal_parameter); securityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(serverExtensions); state.allowCertificateStatus = TlsUtilities.HasExpectedEmptyExtensionData(serverExtensions, ExtensionType.status_request, AlertDescription.illegal_parameter); state.expectSessionTicket = TlsUtilities.HasExpectedEmptyExtensionData(serverExtensions, ExtensionType.session_ticket, AlertDescription.illegal_parameter); } state.client.NotifySecureRenegotiation(state.secure_renegotiation); if (state.clientExtensions != null) { state.client.ProcessServerExtensions(serverExtensions); } }
/// <exception cref="IOException"></exception> public static HeartbeatExtension GetHeartbeatExtension(IDictionary extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.heartbeat); return(extensionData == null ? null : ReadHeartbeatExtension(extensionData)); }
/// <exception cref="IOException"></exception> public static short GetMaxFragmentLengthExtension(IDictionary extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.max_fragment_length); return(extensionData == null ? (short)-1 : (short)ReadMaxFragmentLengthExtension(extensionData)); }
public static bool HasExtendedMasterSecretExtension(IDictionary extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, 0x17); return((extensionData != null) ? ReadExtendedMasterSecretExtension(extensionData) : false); }
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); ProcessCertificateFormats(state, state.clientExtensions, state.serverExtensions); 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()); }
public static bool HasEncryptThenMacExtension(IDictionary extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, 0x16); return((extensionData != null) ? ReadEncryptThenMacExtension(extensionData) : false); }
public static CertificateStatusRequest GetStatusRequestExtension(IDictionary extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, 5); return((extensionData != null) ? ReadStatusRequestExtension(extensionData) : null); }
public static ServerNameList GetServerNameExtension(IDictionary extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, 0); return((extensionData != null) ? ReadServerNameExtension(extensionData) : null); }
public static bool HasExtendedMasterSecretExtension(IDictionary extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, 23); return(extensionData != null && TlsExtensionsUtilities.ReadExtendedMasterSecretExtension(extensionData)); }
/// <exception cref="IOException"></exception> public static ServerNameList GetServerNameExtension(IDictionary extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.server_name); return(extensionData == null ? null : ReadServerNameExtension(extensionData)); }
protected virtual void ReceiveServerHelloMessage(MemoryStream buf) { ProtocolVersion protocolVersion = TlsUtilities.ReadVersion(buf); if (protocolVersion.IsDtls) { throw new TlsFatalAlert(47); } if (!protocolVersion.Equals(mRecordStream.ReadVersion)) { throw new TlsFatalAlert(47); } ProtocolVersion clientVersion = Context.ClientVersion; if (!protocolVersion.IsEqualOrEarlierVersionOf(clientVersion)) { throw new TlsFatalAlert(47); } mRecordStream.SetWriteVersion(protocolVersion); ContextAdmin.SetServerVersion(protocolVersion); mTlsClient.NotifyServerVersion(protocolVersion); mSecurityParameters.serverRandom = TlsUtilities.ReadFully(32, buf); mSelectedSessionID = TlsUtilities.ReadOpaque8(buf); if (mSelectedSessionID.Length > 32) { throw new TlsFatalAlert(47); } mTlsClient.NotifySessionID(mSelectedSessionID); mResumedSession = (mSelectedSessionID.Length > 0 && mTlsSession != null && Arrays.AreEqual(mSelectedSessionID, mTlsSession.SessionID)); int num = TlsUtilities.ReadUint16(buf); if (!Arrays.Contains(mOfferedCipherSuites, num) || num == 0 || CipherSuite.IsScsv(num) || !TlsUtilities.IsValidCipherSuiteForVersion(num, Context.ServerVersion)) { throw new TlsFatalAlert(47); } mTlsClient.NotifySelectedCipherSuite(num); byte b = TlsUtilities.ReadUint8(buf); if (!Arrays.Contains(mOfferedCompressionMethods, b)) { throw new TlsFatalAlert(47); } mTlsClient.NotifySelectedCompressionMethod(b); mServerExtensions = TlsProtocol.ReadExtensions(buf); if (mServerExtensions != null) { foreach (int key in mServerExtensions.Keys) { if (key != 65281) { if (TlsUtilities.GetExtensionData(mClientExtensions, key) == null) { throw new TlsFatalAlert(110); } if (!mResumedSession) { } } } } byte[] extensionData = TlsUtilities.GetExtensionData(mServerExtensions, 65281); if (extensionData != null) { mSecureRenegotiation = true; if (!Arrays.ConstantTimeAreEqual(extensionData, TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes))) { throw new TlsFatalAlert(40); } } mTlsClient.NotifySecureRenegotiation(mSecureRenegotiation); IDictionary dictionary = mClientExtensions; IDictionary dictionary2 = mServerExtensions; if (mResumedSession) { if (num != mSessionParameters.CipherSuite || b != mSessionParameters.CompressionAlgorithm) { throw new TlsFatalAlert(47); } dictionary = null; dictionary2 = mSessionParameters.ReadServerExtensions(); } mSecurityParameters.cipherSuite = num; mSecurityParameters.compressionAlgorithm = b; if (dictionary2 != null) { bool flag = TlsExtensionsUtilities.HasEncryptThenMacExtension(dictionary2); if (flag && !TlsUtilities.IsBlockCipherSuite(num)) { throw new TlsFatalAlert(47); } mSecurityParameters.encryptThenMac = flag; mSecurityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(dictionary2); mSecurityParameters.maxFragmentLength = ProcessMaxFragmentLengthExtension(dictionary, dictionary2, 47); mSecurityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(dictionary2); mAllowCertificateStatus = (!mResumedSession && TlsUtilities.HasExpectedEmptyExtensionData(dictionary2, 5, 47)); mExpectSessionTicket = (!mResumedSession && TlsUtilities.HasExpectedEmptyExtensionData(dictionary2, 35, 47)); } if (dictionary != null) { mTlsClient.ProcessServerExtensions(dictionary2); } mSecurityParameters.prfAlgorithm = TlsProtocol.GetPrfAlgorithm(Context, mSecurityParameters.CipherSuite); mSecurityParameters.verifyDataLength = 12; }
/// <exception cref="IOException"></exception> public static CertificateStatusRequest GetStatusRequestExtension(IDictionary extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.status_request); return(extensionData == null ? null : ReadStatusRequestExtension(extensionData)); }
protected virtual byte[] GenerateClientHello(ClientHandshakeState state, TlsClient client) { MemoryStream buf = new MemoryStream(); ProtocolVersion client_version = client.ClientVersion; if (!client_version.IsDtls) { throw new TlsFatalAlert(AlertDescription.internal_error); } TlsClientContextImpl context = state.clientContext; context.SetClientVersion(client_version); TlsUtilities.WriteVersion(client_version, buf); SecurityParameters securityParameters = context.SecurityParameters; buf.Write(securityParameters.ClientRandom, 0, securityParameters.ClientRandom.Length); // Session ID byte[] session_id = TlsUtilities.EmptyBytes; if (state.tlsSession != null) { session_id = state.tlsSession.SessionID; if (session_id == null || session_id.Length > 32) { session_id = TlsUtilities.EmptyBytes; } } TlsUtilities.WriteOpaque8(session_id, buf); // Cookie TlsUtilities.WriteOpaque8(TlsUtilities.EmptyBytes, buf); bool fallback = client.IsFallback; /* * Cipher suites */ state.offeredCipherSuites = client.GetCipherSuites(); // Integer -> byte[] state.clientExtensions = client.GetClientExtensions(); securityParameters.extendedMasterSecret = TlsExtensionsUtilities.HasExtendedMasterSecretExtension(state.clientExtensions); // 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(state.clientExtensions, ExtensionType.renegotiation_info); bool noRenegExt = (null == renegExtData); bool noRenegSCSV = !Arrays.Contains(state.offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); if (noRenegExt && noRenegSCSV) { // TODO Consider whether to default to a client extension instead state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, 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(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV)) { state.offeredCipherSuites = Arrays.Append(state.offeredCipherSuites, CipherSuite.TLS_FALLBACK_SCSV); } TlsUtilities.WriteUint16ArrayWithUint16Length(state.offeredCipherSuites, buf); } // TODO Add support for compression // Compression methods // state.offeredCompressionMethods = client.getCompressionMethods(); state.offeredCompressionMethods = new byte[] { CompressionMethod.cls_null }; TlsUtilities.WriteUint8ArrayWithUint8Length(state.offeredCompressionMethods, buf); // Extensions if (state.clientExtensions != null) { TlsProtocol.WriteExtensions(buf, state.clientExtensions); } return(buf.ToArray()); }
/// <exception cref="IOException"></exception> public static bool HasEncryptThenMacExtension(IDictionary extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.encrypt_then_mac); return(extensionData == null ? false : ReadEncryptThenMacExtension(extensionData)); }
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); state.selectedCipherSuite = state.server.GetSelectedCipherSuite(); if (!Arrays.Contains(state.offeredCipherSuites, state.selectedCipherSuite) || state.selectedCipherSuite == CipherSuite.TLS_NULL_WITH_NULL_NULL || CipherSuite.IsScsv(state.selectedCipherSuite) || !TlsUtilities.IsValidCipherSuiteForVersion(state.selectedCipherSuite, server_version)) { throw new TlsFatalAlert(AlertDescription.internal_error); } ValidateSelectedCipherSuite(state.selectedCipherSuite, AlertDescription.internal_error); state.selectedCompressionMethod = state.server.GetSelectedCompressionMethod(); if (!Arrays.Contains(state.offeredCompressionMethods, (byte)state.selectedCompressionMethod)) { throw new TlsFatalAlert(AlertDescription.internal_error); } TlsUtilities.WriteUint16(state.selectedCipherSuite, buf); TlsUtilities.WriteUint8((byte)state.selectedCompressionMethod, buf); state.serverExtensions = 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 = TlsExtensionsUtilities.EnsureExtensionsInitialised(state.serverExtensions); state.serverExtensions[ExtensionType.renegotiation_info] = TlsProtocol.CreateRenegotiationInfo(TlsUtilities.EmptyBytes); } } if (securityParameters.extendedMasterSecret) { state.serverExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(state.serverExtensions); TlsExtensionsUtilities.AddExtendedMasterSecretExtension(state.serverExtensions); } if (state.serverExtensions != null) { securityParameters.encryptThenMac = TlsExtensionsUtilities.HasEncryptThenMacExtension(state.serverExtensions); state.maxFragmentLength = EvaluateMaxFragmentLengthExtension(state.clientExtensions, state.serverExtensions, AlertDescription.internal_error); securityParameters.truncatedHMac = TlsExtensionsUtilities.HasTruncatedHMacExtension(state.serverExtensions); state.allowCertificateStatus = TlsUtilities.HasExpectedEmptyExtensionData(state.serverExtensions, ExtensionType.status_request, AlertDescription.internal_error); state.expectSessionTicket = TlsUtilities.HasExpectedEmptyExtensionData(state.serverExtensions, ExtensionType.session_ticket, AlertDescription.internal_error); TlsProtocol.WriteExtensions(buf, state.serverExtensions); } return(buf.ToArray()); }
/// <exception cref="IOException"></exception> public static bool HasExtendedMasterSecretExtension(IDictionary extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.extended_master_secret); return(extensionData == null ? false : ReadExtendedMasterSecretExtension(extensionData)); }
public static UseSrtpData GetUseSrtpExtension(IDictionary extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.use_srtp); return(extensionData == null ? null : ReadUseSrtpExtension(extensionData)); }
/// <exception cref="IOException"></exception> public static bool HasTruncatedHMacExtension(IDictionary extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.truncated_hmac); return(extensionData == null ? false : ReadTruncatedHMacExtension(extensionData)); }
public static byte[] GetSupportedPointFormatsExtension(IDictionary extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.ec_point_formats); return(extensionData == null ? null : ReadSupportedPointFormatsExtension(extensionData)); }
public static bool HasTruncatedHMacExtension(IDictionary extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, 4); return(extensionData != null && TlsExtensionsUtilities.ReadTruncatedHMacExtension(extensionData)); }
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); } /* * RFC 7507 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 [..]. (The * client SHOULD put TLS_FALLBACK_SCSV after all cipher suites that it actually intends * to negotiate.) */ 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); }
public static bool HasEncryptThenMacExtension(IDictionary extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, 22); return(extensionData != null && TlsExtensionsUtilities.ReadEncryptThenMacExtension(extensionData)); }
public static short GetNegotiatedDheGroupsServerExtension(IDictionary extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, ExtensionType.negotiated_ff_dhe_groups); return(extensionData == null ? (short)-1 : (short)ReadNegotiatedDheGroupsServerExtension(extensionData)); }
public static short GetMaxFragmentLengthExtension(IDictionary extensions) { byte[] extensionData = TlsUtilities.GetExtensionData(extensions, 1); return((extensionData != null) ? ReadMaxFragmentLengthExtension(extensionData) : ((short)(-1))); }