/// <summary> /// Loads a keypair and signature from the provided paths. /// </summary> /// <param name="ca_path">The file that contains the certificate authority public key.</param> /// <param name="key_path">The file that contains our public/private keypair.</param> /// <param name="sign_path">The file that contains our signature.</param> public void LoadCertificatesFromFiles(string ca_path, string key_path, string sign_path) { CertificateAuthority = (RsaKeyParameters)RsaHelpers.PemDeserialize(File.ReadAllText(ca_path)); Log.Trace("Loaded certificate authority from {0}", ca_path); Certificate = (AsymmetricCipherKeyPair)RsaHelpers.PemDeserialize(File.ReadAllText(key_path)); Log.Trace("Loaded certificate from {0}", key_path); Signature = File.ReadAllBytes(sign_path); Log.Trace("Loaded signature from {0}", sign_path); }
/// <summary> /// Loads a keypair and signature from the provided strings. /// </summary> /// <param name="ca">The public key of the certificate authority in text form.</param> /// <param name="key">Both our public and private key, concatenated, in text form.</param> /// <param name="sign">The signature in Base64.</param> public void LoadCertificatesNonBase64(string caPublicKey, string pubPrivKeyPair, byte[] sign) { CertificateAuthority = (RsaKeyParameters)RsaHelpers.PemDeserialize(caPublicKey); Log.Trace("Loaded certificate authority."); Certificate = (AsymmetricCipherKeyPair)RsaHelpers.PemDeserialize(pubPrivKeyPair); Log.Trace("Loaded certificate."); Signature = sign; Log.Trace("Loaded signature."); }
/// <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[] ca_public_key = msg.Store["ca_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"]; string cert_name = Encoding.UTF8.GetString(msg.Store["cert_name"]); PeerSignature = rsa_signature; remoteCertificateHash = Convert.ToBase64String(SHA.ComputeHash(msg.Store["ca_public_key"])); RemoteCertificateAuthority = CertManager.RetrievePublicCertificateByHash(remoteCertificateHash); //RemoteCertificate = CertManager.RetrievePrivateCertificateByHash(remoteCertificateHash); if (RemoteCertificateAuthority != null) { TrustedCertificateUsed = CertManager.IsCertificateTrusted(remoteCertificateHash); Log.Debug("Known certificate found and loaded: " + (TrustedCertificateUsed ? "Trusted" : "Untrusted")); } else if (RememberRemoteCertAuthority) { Log.Debug("Known certificate not found, adding.."); CertManager.AddKnownCertificateAuthority(cert_name, remoteCertificateHash, Encoding.UTF8.GetString(ca_public_key)); RemoteCertificateAuthority = CertManager.RetrievePublicCertificateByHash(remoteCertificateHash); TrustedCertificateUsed = false; } 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.Debug("Clock drift between peers is {0}.", difference); if (!NoAuthentication) { if (RemoteCertificateAuthority != null) { if (!RsaHelpers.VerifyData(rsa_public_key, rsa_signature, RemoteCertificateAuthority)) { if (!RsaHelpers.VerifyData(rsa_public_key, rsa_signature, CertificateAuthority)) { var result = new HandshakeResult(HandshakeResultType.UntrustedStaticPublicKey, "1. Failed to verify RSA public key against certificate authority. Terminating handshake."); Log.Error(result.Message); Tunnel.Close(); return(result); } } } else if (!RsaHelpers.VerifyData(rsa_public_key, rsa_signature, CertificateAuthority)) { var result = new HandshakeResult(HandshakeResultType.UntrustedStaticPublicKey, "2. Failed to verify RSA public key against certificate authority. Terminating handshake."); Log.Error(result.Message); Tunnel.Close(); return(result); } } RsaKeyParameters parameters = (RsaKeyParameters)RsaHelpers.PemDeserialize(Encoding.UTF8.GetString(rsa_public_key)); if (!NoAuthentication && !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.Debug(result_final.Message); Log.Debug("Cipher: {0}, key exchange: {1}, MAC: {2}", Suite.Cipher.HumanName, Suite.KeyExchange.HumanName, Suite.MAC.HumanName); return(result_final); }
/// <summary> /// Perform a server-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() }; Message msg = Receive(); Log.Debug(msg.Type); if (msg == null) { var result = new HandshakeResult(HandshakeResultType.ConnectionClosed, "Connection closed."); Log.Error(result.Message); Tunnel.Close(); return(result); } if (!msg.CheckType(MessageType.ClientHello, 0x00)) { var result = new HandshakeResult(HandshakeResultType.UnexpectedMessage, "Received message of type {0}/0x{1:X2} while expecting ClientHello/0x00. Terminating handshake.", msg.Type, msg.Subtype); Log.Error(result.Message); Tunnel.Close(); return(result); } var peer_suites = new List <CipherSuiteIdentifier>(); var suite_data = msg.Store["allowed_suites"]; Log.Debug("{0} bytes of allowed suites", suite_data.Length); for (int i = 0; i < suite_data.Length; i += CipherSuiteIdentifier.IdentifierLength) { peer_suites.Add(new CipherSuiteIdentifier(suite_data, i)); } peer_suites = peer_suites.Distinct().ToList(); var suite_scores = new Dictionary <CipherSuiteIdentifier, int>(); for (int i = 0; i < allowed_suites.Count; i++) { for (int j = 0; j < peer_suites.Count; j++) { var our_suite = allowed_suites[i]; var their_suite = peer_suites[j]; if (our_suite != their_suite) { continue; } suite_scores[our_suite] = i + j; } } var chosen_suite = suite_scores.OrderBy(p => p.Value).First().Key; SendMessage(MessageHelpers.CreateServerHello(this, chosen_suite)); Suite = chosen_suite.CreateSuite(); var real_cipher = Suite.Cipher; var real_mac = Suite.MAC; Suite.Cipher = new IdentityCipher(); // temporarily set suite cipher to IdentityCipher so we can continue handshake Suite.MAC = new IdentityMAC(); // likewise Suite.Initialize(); msg = Receive(); if (!msg.CheckType(MessageType.AuthRequest, 0x00)) { var result = new HandshakeResult(HandshakeResultType.UnexpectedMessage, "Received message of type {0}/0x{1:X2} 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[] ca_public_key = msg.Store["ca_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"]; string cert_name = Encoding.UTF8.GetString(msg.Store["cert_name"]); PeerSignature = rsa_signature; remoteCertificateHash = Convert.ToBase64String(SHA.ComputeHash(msg.Store["ca_public_key"])); RemoteCertificateAuthority = CertManager.RetrievePublicCertificateByHash(remoteCertificateHash); //RemoteCertificate = CertManager.RetrievePrivateCertificateByHash(remoteCertificateHash); if (RemoteCertificateAuthority != null) { TrustedCertificateUsed = CertManager.IsCertificateTrusted(remoteCertificateHash); Log.Debug("Known certificate found and loaded: " + (TrustedCertificateUsed ? "Trusted" : "Untrusted")); } else if (RememberRemoteCertAuthority) { Log.Debug("Known certificate not found, adding.."); CertManager.AddKnownCertificateAuthority(cert_name, remoteCertificateHash, Encoding.UTF8.GetString(ca_public_key)); RemoteCertificateAuthority = CertManager.RetrievePublicCertificateByHash(remoteCertificateHash); TrustedCertificateUsed = false; } byte[] timestamp = msg.Store["timestamp"]; DateTime timestamp_dt = MessageHelpers.GetDateTime(BitConverter.ToInt64(timestamp, 0)); TimeSpan difference = (DateTime.UtcNow - timestamp_dt).Duration(); if (msg.Store.ContainsKey("attestation_token")) { AttestationToken = msg.Store["attestation_token"]; } 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.Debug("Clock drift between peers is {0}.", difference); if (!NoAuthentication) { if (RemoteCertificateAuthority != null) { if (!RsaHelpers.VerifyData(rsa_public_key, rsa_signature, RemoteCertificateAuthority)) { if (!RsaHelpers.VerifyData(rsa_public_key, rsa_signature, CertificateAuthority)) { var result = new HandshakeResult(HandshakeResultType.UntrustedStaticPublicKey, "1. Failed to verify RSA public key against certificate authority. Terminating handshake."); Log.Error(result.Message); Tunnel.Close(); return(result); } } } else if (!RsaHelpers.VerifyData(rsa_public_key, rsa_signature, CertificateAuthority)) { var result = new HandshakeResult(HandshakeResultType.UntrustedStaticPublicKey, "2. Failed to verify RSA public key against certificate authority. Terminating handshake."); Log.Error(result.Message); Tunnel.Close(); return(result); } } RsaKeyParameters parameters = (RsaKeyParameters)RsaHelpers.PemDeserialize(Encoding.UTF8.GetString(rsa_public_key)); if (!NoAuthentication && !RsaHelpers.VerifyData(ecdh_public_key, ecdh_signature, parameters)) { var result = new HandshakeResult(HandshakeResultType.UntrustedEphemeralPublicKey, "1. Failed to verify ECDH public key authenticity. Terminating handshake."); Log.Error(result.Message); Tunnel.Close(); return(result); } Suite.SharedSalt = new byte[16]; RNG.GetBytes(Suite.SharedSalt); SendMessage(MessageHelpers.CreateAuthResponse(this)); 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."); result_final.TimeDrift = difference.TotalSeconds; Log.Debug(result_final.Message); Log.Debug("Cipher: {0}, key exchange: {1}, MAC: {2}", Suite.Cipher.HumanName, Suite.KeyExchange.HumanName, Suite.MAC.HumanName); return(result_final); }