public static Message CreateServerHello(ServerLink link, CipherSuiteIdentifier chosen_suite) { Message msg = new Message(MessageType.ServerHello, 0x00); msg.Store["chosen_suite"] = chosen_suite == null ? new byte[0] : chosen_suite.Serialize(); return(msg); }
/// <summary> /// Perform a client-side handshake. /// </summary> /// <returns>A HandshakeResult class containing information about the handshake attempt.</returns> private HandshakeResult _PerformHandshake(List <CipherSuiteIdentifier> allowed_suites) { Suite = new CipherSuite() { Cipher = new IdentityCipher(), MAC = new IdentityMAC() }; SendMessage(MessageHelpers.CreateClientHello(this, allowed_suites)); Message msg = Receive(); if (msg == null) { var result = new HandshakeResult(HandshakeResultType.ConnectionClosed, "Connection closed."); Log.Error(result.Message); Tunnel.Close(); return(result); } if (!msg.CheckType(MessageType.ServerHello, 0x00)) { var result = new HandshakeResult(HandshakeResultType.UnexpectedMessage, "Received message of type {0}/0x{1:X} while expecting ServerHello/0x00. Terminating handshake.", msg.Type, msg.Subtype); Log.Error(result.Message); Tunnel.Close(); return(result); } var chosen_suite = msg.Store["chosen_suite"]; if (chosen_suite.Length == 0) { var result = new HandshakeResult(HandshakeResultType.NoCipherSuite, "Server refused to pick a cipher suite."); Log.Error(result.Message); Tunnel.Close(); return(result); } if (!allowed_suites.Any(s => s.Serialize().SequenceEqual(chosen_suite))) { var result = new HandshakeResult(HandshakeResultType.NoCipherSuite, "Server picked a forbidden suite."); Log.Error(result.Message); Tunnel.Close(); return(result); } Suite = new CipherSuiteIdentifier(chosen_suite).CreateSuite(); var real_cipher = Suite.Cipher; var real_mac = Suite.MAC; Suite.Cipher = new IdentityCipher(); Suite.MAC = new IdentityMAC(); Suite.Initialize(); SendMessage(MessageHelpers.CreateAuthRequest(this)); msg = Receive(); if (msg == null) { var result = new HandshakeResult(HandshakeResultType.ConnectionClosed, "Connection closed."); Log.Error(result.Message); Tunnel.Close(); return(result); } if (!msg.CheckType(MessageType.AuthResponse, 0x00)) { var result = new HandshakeResult(HandshakeResultType.UnexpectedMessage, "Received message of type {0}/0x{1:X} while expecting AuthRequest/0x00. Terminating handshake.", msg.Type, msg.Subtype); Log.Error(result.Message); Tunnel.Close(); return(result); } byte[] rsa_public_key = msg.Store["rsa_public_key"]; byte[] rsa_signature = msg.Store["rsa_signature"]; byte[] ecdh_public_key = msg.Store["ecdh_public_key"]; byte[] ecdh_signature = msg.Store["ecdh_signature"]; PeerSignature = rsa_signature; byte[] shared_salt = msg.Store["shared_salt"]; byte[] salt_signature = msg.Store["shared_salt_signature"]; byte[] timestamp = msg.Store["timestamp"]; DateTime timestamp_dt = MessageHelpers.GetDateTime(BitConverter.ToInt64(timestamp, 0)); TimeSpan difference = (DateTime.UtcNow - timestamp_dt).Duration(); if (!timestamp.SequenceEqual(ecdh_public_key.Skip(ecdh_public_key.Length - 8))) { var result = new HandshakeResult(HandshakeResultType.UntrustedTimestamp, "Timestamp mismatch between ECDH public key and explicit timestamp. Terminating handshake."); Log.Error(result.Message); Tunnel.Close(); return(result); } if (difference > MaximumTimeMismatch) { var result = new HandshakeResult(HandshakeResultType.ReplayAttack, "Timestamp difference between client and server exceeds allowed window of {0}(provided timestamp is {1}, our clock is {2}). Terminating handshake.", MaximumTimeMismatch, timestamp_dt, DateTime.UtcNow); Log.Error(result.Message); Tunnel.Close(); return(result); } Log.Info("Clock drift between peers is {0}.", difference); if (!RsaHelpers.VerifyData(rsa_public_key, rsa_signature, CertificateAuthority)) { var result = new HandshakeResult(HandshakeResultType.UntrustedStaticPublicKey, "Failed to verify RSA public key against certificate authority. Terminating handshake."); Log.Error(result.Message); Tunnel.Close(); return(result); } var parameters = (RsaKeyParameters)RsaHelpers.PemDeserialize(Encoding.UTF8.GetString(rsa_public_key)); if (!RsaHelpers.VerifyData(ecdh_public_key, ecdh_signature, parameters)) { var result = new HandshakeResult(HandshakeResultType.UntrustedEphemeralPublicKey, "Failed to verify ECDH public key authenticity. Terminating handshake."); Log.Error(result.Message); Tunnel.Close(); return(result); } Suite.SharedSalt = shared_salt; Suite.Cipher = real_cipher; Suite.MAC = real_mac; var shared_secret = Suite.FinalizeKeyExchange(ecdh_public_key); StartThreads(); var result_final = new HandshakeResult(HandshakeResultType.Successful, "Handshake successful.") { TimeDrift = difference.TotalSeconds }; Log.Info(result_final.Message); Log.Info("Cipher: {0}, key exchange: {1}, MAC: {2}", Suite.Cipher.HumanName, Suite.KeyExchange.HumanName, Suite.MAC.HumanName); return(result_final); }