public static CipherSuite InitializeCipherSuite(byte[] master, byte[] clientrnd, byte[] serverrnd, CipherDefinition definition, ConnectionEnd entity) { CipherSuite ret = new CipherSuite(); SymmetricAlgorithm bulk = (SymmetricAlgorithm)Activator.CreateInstance(definition.BulkCipherAlgorithm); if (definition.BulkIVSize > 0) bulk.Mode = CipherMode.CBC; bulk.Padding = PaddingMode.None; bulk.BlockSize = definition.BulkIVSize * 8; // get the keys and IVs byte[] client_mac, server_mac, client_key, server_key, client_iv, server_iv; byte[] random = new byte[64]; Array.Copy(serverrnd, 0, random, 0, 32); Array.Copy(clientrnd, 0, random, 32, 32); PseudoRandomDeriveBytes prf = new PseudoRandomDeriveBytes(master, "key expansion", random); client_mac = prf.GetBytes(definition.HashSize); server_mac = prf.GetBytes(definition.HashSize); client_key = prf.GetBytes(definition.BulkKeySize); server_key = prf.GetBytes(definition.BulkKeySize); client_iv = prf.GetBytes(definition.BulkIVSize); server_iv = prf.GetBytes(definition.BulkIVSize); prf.Dispose(); if (definition.Exportable) { // make some extra modifications if the keys are exportable Array.Copy(clientrnd, 0, random, 0, 32); Array.Copy(serverrnd, 0, random, 32, 32); prf = new PseudoRandomDeriveBytes(client_key, "client write key", random); client_key = prf.GetBytes(definition.BulkExpandedSize); prf.Dispose(); prf = new PseudoRandomDeriveBytes(server_key, "server write key", random); server_key = prf.GetBytes(definition.BulkExpandedSize); prf.Dispose(); prf = new PseudoRandomDeriveBytes(new byte[0], "IV block", random); client_iv = prf.GetBytes(definition.BulkIVSize); server_iv = prf.GetBytes(definition.BulkIVSize); prf.Dispose(); } // generate the cipher objects if (entity == ConnectionEnd.Client) { ret.Encryptor = bulk.CreateEncryptor(client_key, client_iv); ret.Decryptor = bulk.CreateDecryptor(server_key, server_iv); ret.LocalHasher = new HMAC((HashAlgorithm)Activator.CreateInstance(definition.HashAlgorithm), client_mac); ret.RemoteHasher = new HMAC((HashAlgorithm)Activator.CreateInstance(definition.HashAlgorithm), server_mac); } else { ret.Encryptor = bulk.CreateEncryptor(server_key, server_iv); ret.Decryptor = bulk.CreateDecryptor(client_key, client_iv); ret.LocalHasher = new HMAC((HashAlgorithm)Activator.CreateInstance(definition.HashAlgorithm), server_mac); ret.RemoteHasher = new HMAC((HashAlgorithm)Activator.CreateInstance(definition.HashAlgorithm), client_mac); } // clear sensitive data Array.Clear(client_mac, 0, client_mac.Length); Array.Clear(server_mac, 0, server_mac.Length); Array.Clear(client_key, 0, client_key.Length); Array.Clear(server_key, 0, server_key.Length); Array.Clear(client_iv, 0, client_iv.Length); Array.Clear(server_iv, 0, server_iv.Length); Array.Clear(random, 0, random.Length); return ret; }
protected SslHandshakeStatus ProcessServerKeyExchange(HandshakeMessage message) { if (m_State != HandshakeType.Certificate) { throw new SslException(AlertDescription.UnexpectedMessage, "ServerKeyExchange message must be preceded by a Certificate message."); } CipherDefinition cd = CipherSuites.GetCipherDefinition(m_EncryptionScheme); if (!cd.Exportable) { throw new SslException(AlertDescription.HandshakeFailure, "The ServerKeyExchange message should not be sent for non-exportable ciphers."); } if (m_RemoteCertificate.GetPublicKeyLength() <= 512) { throw new SslException(AlertDescription.HandshakeFailure, "The ServerKeyExchange message should not be sent because the server certificate public key is of exportable length."); } UpdateHashes(message, HashUpdate.All); // input message // extract modulus and exponent RSAParameters pars = new RSAParameters(); int size = message.fragment[0] * 256 + message.fragment[1]; pars.Modulus = new byte[size]; Buffer.BlockCopy(message.fragment, 2, pars.Modulus, 0, size); int offset = size + 2; size = message.fragment[offset] * 256 + message.fragment[offset + 1]; pars.Exponent = new byte[size]; Buffer.BlockCopy(message.fragment, offset + 2, pars.Exponent, 0, size); offset += size + 2; pars.Modulus = RemoveLeadingZeros(pars.Modulus); pars.Exponent = RemoveLeadingZeros(pars.Exponent); m_KeyCipher = new RSACryptoServiceProvider(); m_KeyCipher.ImportParameters(pars); // compute verification hashes MD5SHA1CryptoServiceProvider ms = new MD5SHA1CryptoServiceProvider(); ms.TransformBlock(m_ClientTime, 0, m_ClientTime.Length, m_ClientTime, 0); ms.TransformBlock(m_ClientRandom, 0, m_ClientRandom.Length, m_ClientRandom, 0); ms.TransformBlock(m_ServerTime, 0, m_ServerTime.Length, m_ServerTime, 0); ms.TransformBlock(m_ServerRandom, 0, m_ServerRandom.Length, m_ServerRandom, 0); ms.TransformFinalBlock(message.fragment, 0, offset); // verify the signature size = message.fragment[offset] * 256 + message.fragment[offset + 1]; byte[] signature = new byte[size]; // holds the signature returned by the server Buffer.BlockCopy(message.fragment, offset + 2, signature, 0, size); if (!ms.VerifySignature(m_RemoteCertificate, signature)) { throw new SslException(AlertDescription.HandshakeFailure, "The data was not signed by the server certificate."); } ms.Clear(); return(new SslHandshakeStatus(SslStatus.MessageIncomplete, null)); }
public static CipherSuite InitializeCipherSuite(byte[] master, byte[] clientrnd, byte[] serverrnd, CipherDefinition definition, ConnectionEnd entity) { CipherSuite ret = new CipherSuite(); SymmetricAlgorithm bulk = (SymmetricAlgorithm)Activator.CreateInstance(definition.BulkCipherAlgorithm); if (definition.BulkIVSize > 0) bulk.Mode = CipherMode.CBC; bulk.Padding = PaddingMode.None; bulk.BlockSize = definition.BulkIVSize * 8; // get the keys and IVs byte[] client_mac, server_mac, client_key, server_key, client_iv, server_iv; Ssl3DeriveBytes prf = new Ssl3DeriveBytes(master, clientrnd, serverrnd, false); client_mac = prf.GetBytes(definition.HashSize); server_mac = prf.GetBytes(definition.HashSize); client_key = prf.GetBytes(definition.BulkKeySize); server_key = prf.GetBytes(definition.BulkKeySize); client_iv = prf.GetBytes(definition.BulkIVSize); server_iv = prf.GetBytes(definition.BulkIVSize); prf.Dispose(); if (definition.Exportable) { // make some extra modifications if the keys are exportable MD5 md5 = new MD5CryptoServiceProvider(); md5.TransformBlock(client_key, 0, client_key.Length, client_key, 0); md5.TransformBlock(clientrnd, 0, clientrnd.Length, clientrnd, 0); md5.TransformFinalBlock(serverrnd, 0, serverrnd.Length); client_key = new byte[definition.BulkExpandedSize]; Buffer.BlockCopy(md5.Hash, 0, client_key, 0, client_key.Length); md5.Initialize(); md5.TransformBlock(server_key, 0, server_key.Length, server_key, 0); md5.TransformBlock(serverrnd, 0, serverrnd.Length, serverrnd, 0); md5.TransformFinalBlock(clientrnd, 0, clientrnd.Length); server_key = new byte[definition.BulkExpandedSize]; Buffer.BlockCopy(md5.Hash, 0, server_key, 0, server_key.Length); md5.Initialize(); md5.TransformBlock(clientrnd, 0, clientrnd.Length, clientrnd, 0); md5.TransformFinalBlock(serverrnd, 0, serverrnd.Length); client_iv = new byte[definition.BulkIVSize]; Buffer.BlockCopy(md5.Hash, 0, client_iv, 0, client_iv.Length); md5.Initialize(); md5.TransformBlock(serverrnd, 0, serverrnd.Length, serverrnd, 0); md5.TransformFinalBlock(clientrnd, 0, clientrnd.Length); server_iv = new byte[definition.BulkIVSize]; Buffer.BlockCopy(md5.Hash, 0, server_iv, 0, server_iv.Length); md5.Clear(); } // generate the cipher objects if (entity == ConnectionEnd.Client) { ret.Encryptor = bulk.CreateEncryptor(client_key, client_iv); ret.Decryptor = bulk.CreateDecryptor(server_key, server_iv); ret.LocalHasher = new Ssl3RecordMAC(definition.HashAlgorithmType, client_mac); ret.RemoteHasher = new Ssl3RecordMAC(definition.HashAlgorithmType, server_mac); } else { ret.Encryptor = bulk.CreateEncryptor(server_key, server_iv); ret.Decryptor = bulk.CreateDecryptor(client_key, client_iv); ret.LocalHasher = new Ssl3RecordMAC(definition.HashAlgorithmType, server_mac); ret.RemoteHasher = new Ssl3RecordMAC(definition.HashAlgorithmType, client_mac); } // clear sensitive data Array.Clear(client_mac, 0, client_mac.Length); Array.Clear(server_mac, 0, server_mac.Length); Array.Clear(client_key, 0, client_key.Length); Array.Clear(server_key, 0, server_key.Length); Array.Clear(client_iv, 0, client_iv.Length); Array.Clear(server_iv, 0, server_iv.Length); return ret; }
protected SslHandshakeStatus ProcessCertificateRequest(HandshakeMessage message) { if (m_State == HandshakeType.ServerKeyExchange) { CipherDefinition cd = CipherSuites.GetCipherDefinition(m_EncryptionScheme); if (this.m_RemoteCertificate.GetPublicKeyLength() <= 512 || !cd.Exportable) { throw new SslException(AlertDescription.HandshakeFailure, "Invalid message."); } } else if (m_State != HandshakeType.Certificate) { throw new SslException(AlertDescription.UnexpectedMessage, "CertificateRequest message must be preceded by a Certificate or ServerKeyExchange message."); } UpdateHashes(message, HashUpdate.All); // input message // get supported certificate types bool supportsRsaCerts = false; byte[] certTypes = new byte[message.fragment[0]]; // currently we're not doing anything with the supported certificate types Buffer.BlockCopy(message.fragment, 1, certTypes, 0, certTypes.Length); for (int i = 0; i < certTypes.Length; i++) { if (certTypes[i] == 1) // rsa_sign { supportsRsaCerts = true; break; } } // get list of distinguished names if (m_Options.RequestHandler != null && supportsRsaCerts) // make sure the client passed a delegate { Queue q = new Queue(); DistinguishedNameList r = new DistinguishedNameList(); int size, offset = message.fragment[0] + 3; byte[] buffer; while (offset < message.fragment.Length) { size = message.fragment[offset] * 256 + message.fragment[offset + 1]; buffer = new byte[size]; Buffer.BlockCopy(message.fragment, offset + 2, buffer, 0, size); q.Enqueue(buffer); offset += size + 2; } // decode RDN structures while (q.Count > 0) { r.Add(ProcessName((byte[])q.Dequeue())); } RequestEventArgs e = new RequestEventArgs(); try { m_Options.RequestHandler(Parent, r, e); if (e.Certificate != null) { m_Options.Certificate = e.Certificate; } } catch (Exception de) { throw new SslException(de, AlertDescription.InternalError, "The code in the CertRequestEventHandler delegate threw an error."); } } if (!supportsRsaCerts) { m_Options.Certificate = null; // do not send client certificate } m_MutualAuthentication = true; return(new SslHandshakeStatus(SslStatus.MessageIncomplete, null)); }