protected override SslHandshakeStatus ProcessMessage(HandshakeMessage message) { // throws SslExceptions SslHandshakeStatus ret = new SslHandshakeStatus(); switch(message.type) { case HandshakeType.ServerHello: ret = ProcessServerHello(message); break; case HandshakeType.Certificate: // optional ret = ProcessCertificate(message, true); break; case HandshakeType.ServerKeyExchange: // optional ret = ProcessServerKeyExchange(message); break; case HandshakeType.CertificateRequest: // optional ret = ProcessCertificateRequest(message); break; case HandshakeType.ServerHelloDone: ret = ProcessServerHelloDone(message); break; case HandshakeType.Finished: ret = ProcessFinished(message); break; case HandshakeType.HelloRequest: ret = ProcessHelloRequest(message); break; default: throw new SslException(AlertDescription.UnexpectedMessage, "The received message was not expected from a server."); } return ret; }
// processes Handshake & ChangeCipherSpec messages public SslHandshakeStatus ProcessMessages(RecordMessage message) { if (message == null) { throw new ArgumentNullException(); } SslHandshakeStatus ret; if (message.contentType == ContentType.ChangeCipherSpec) { ret = ProcessChangeCipherSpec(message); m_State = HandshakeType.ChangeCipherSpec; } else if (message.contentType == ContentType.Handshake) { ret = new SslHandshakeStatus(); // copy the new bytes and the old bytes in one buffer MemoryStream ms = new MemoryStream(); byte[] fullbuffer = new byte[m_IncompleteMessage.Length + message.length]; Buffer.BlockCopy(m_IncompleteMessage, 0, fullbuffer, 0, m_IncompleteMessage.Length); Buffer.BlockCopy(message.fragment, 0, fullbuffer, m_IncompleteMessage.Length, message.length); // loop through all messages in buffer, if any int offset = 0; HandshakeMessage hm = GetHandshakeMessage(fullbuffer, offset); while (hm != null) { offset += hm.fragment.Length + 4; SslHandshakeStatus status = ProcessMessage(hm); if (status.Message != null) { ms.Write(status.Message, 0, status.Message.Length); } ret.Status = status.Status; // go to next message m_State = hm.type; hm = GetHandshakeMessage(fullbuffer, offset); } if (offset > 0) { m_IncompleteMessage = new byte[fullbuffer.Length - offset]; Buffer.BlockCopy(fullbuffer, offset, m_IncompleteMessage, 0, m_IncompleteMessage.Length); } else { m_IncompleteMessage = fullbuffer; } if (ms.Length > 0) { ret.Message = ms.ToArray(); } ms.Close(); } else // message.contentType == ContentType.Alert { ret = ProcessAlert(message); } return(ret); }
protected SslHandshakeStatus ProcessAlert(RecordMessage message) { if (message.length != 2 || message.fragment.Length != 2) { throw new SslException(AlertDescription.RecordOverflow, "The alert message is invalid."); } try { AlertLevel level = (AlertLevel)message.fragment[0]; AlertDescription description = (AlertDescription)message.fragment[1]; if (level == AlertLevel.Fatal && description == AlertDescription.NoApplicationProtocol) { throw new ALPNCantSelectProtocolException(); } if (level == AlertLevel.Fatal) { throw new SslException(description, "The other side has sent a failure alert with code: " + description.ToString()); } SslHandshakeStatus ret; if (description == AlertDescription.CloseNotify) { if (m_State == HandshakeType.ShuttingDown) // true if we've already sent a shutdown notification // close connection { ret = new SslHandshakeStatus(SslStatus.Close, null); } else { // send a shutdown notifications, and then close the connection ret = new SslHandshakeStatus(SslStatus.Close, GetControlBytes(ControlType.Shutdown)); } } else { ret = new SslHandshakeStatus(SslStatus.OK, null); } return(ret); } catch (SslException) { throw; } catch (Exception e) { throw new SslException(e, AlertDescription.InternalError, "There was an internal error."); } }
protected override SslHandshakeStatus ProcessMessage(HandshakeMessage message) // throws SslExceptions { SslHandshakeStatus ret = new SslHandshakeStatus(); switch (message.type) { case HandshakeType.ServerHello: ret = ProcessServerHello(message); break; case HandshakeType.Certificate: // optional ret = ProcessCertificate(message, true); break; case HandshakeType.ServerKeyExchange: // optional ret = ProcessServerKeyExchange(message); break; case HandshakeType.CertificateRequest: // optional ret = ProcessCertificateRequest(message); break; case HandshakeType.ServerHelloDone: ret = ProcessServerHelloDone(message); break; case HandshakeType.Finished: ret = ProcessFinished(message); break; case HandshakeType.HelloRequest: ret = ProcessHelloRequest(message); break; default: throw new SslException(AlertDescription.UnexpectedMessage, "The received message was not expected from a server."); } return(ret); }
protected SslHandshakeStatus ProcessAlert(RecordMessage message) { if (message.length != 2 || message.fragment.Length != 2) throw new SslException(AlertDescription.RecordOverflow, "The alert message is invalid."); try { AlertLevel level = (AlertLevel)message.fragment[0]; AlertDescription description = (AlertDescription)message.fragment[1]; if (level == AlertLevel.Fatal) throw new SslException(description, "The other side has sent a failure alert."); SslHandshakeStatus ret; if (description == AlertDescription.CloseNotify) { if (m_State == HandshakeType.ShuttingDown) { // true if we've already sent a shutdown notification // close connection ret = new SslHandshakeStatus(SslStatus.Close, null); } else { // send a shutdown notifications, and then close the connection ret = new SslHandshakeStatus(SslStatus.Close, GetControlBytes(ControlType.Shutdown)); } } else { ret = new SslHandshakeStatus(SslStatus.OK, null); } return ret; } catch (SslException t) { throw t; } catch (Exception e) { throw new SslException(e, AlertDescription.InternalError, "There was an internal error."); } }
// processes Handshake & ChangeCipherSpec messages public SslHandshakeStatus ProcessMessages(RecordMessage message) { if (message == null) throw new ArgumentNullException(); SslHandshakeStatus ret; if (message.contentType == ContentType.ChangeCipherSpec) { ret = ProcessChangeCipherSpec(message); m_State = HandshakeType.ChangeCipherSpec; } else if (message.contentType == ContentType.Handshake) { ret = new SslHandshakeStatus(); // copy the new bytes and the old bytes in one buffer MemoryStream ms = new MemoryStream(); byte[] fullbuffer = new byte[m_IncompleteMessage.Length + message.length]; Array.Copy(m_IncompleteMessage, 0, fullbuffer, 0, m_IncompleteMessage.Length); Array.Copy(message.fragment, 0, fullbuffer, m_IncompleteMessage.Length, message.length); // loop through all messages in buffer, if any int offset = 0; HandshakeMessage hm = GetHandshakeMessage(fullbuffer, offset); while(hm != null) { offset += hm.fragment.Length + 4; SslHandshakeStatus status = ProcessMessage(hm); if (status.Message != null) { ms.Write(status.Message, 0, status.Message.Length); } ret.Status = status.Status; // go to next message m_State = hm.type; hm = GetHandshakeMessage(fullbuffer, offset); } if (offset > 0) { m_IncompleteMessage = new byte[fullbuffer.Length - offset]; Array.Copy(fullbuffer, offset, m_IncompleteMessage, 0, m_IncompleteMessage.Length); } else { m_IncompleteMessage = fullbuffer; } if (ms.Length > 0) { ret.Message = ms.ToArray(); } ms.Close(); } else { // message.contentType == ContentType.Alert ret = ProcessAlert(message); } return ret; }
protected SslHandshakeStatus GetClientHelloResult() { MemoryStream retMessage = new MemoryStream(); SslHandshakeStatus ret = new SslHandshakeStatus(); HandshakeMessage temp; byte[] bytes; // ServerHello message temp = new HandshakeMessage(HandshakeType.ServerHello, new byte[38]); m_ServerTime = GetUnixTime(); m_ServerRandom = new byte[28]; m_RNG.GetBytes(m_ServerRandom); temp.fragment[0] = GetVersion().major; temp.fragment[1] = GetVersion().minor; Array.Copy(m_ServerTime, 0, temp.fragment, 2, 4); Array.Copy(m_ServerRandom, 0, temp.fragment, 6, 28); temp.fragment[34] = 0; // do not resume a session, and do not let the other side cache it Array.Copy(CipherSuites.GetCipherAlgorithmBytes(m_EncryptionScheme), 0, temp.fragment, 35, 2); temp.fragment[37] = CompressionAlgorithm.GetAlgorithmByte(m_CompressionMethod); bytes = temp.ToBytes(); retMessage.Write(bytes, 0, bytes.Length); // Certificate message byte[] certs = GetCertificateList(m_Options.Certificate); temp.type = HandshakeType.Certificate; temp.fragment = certs; bytes = temp.ToBytes(); retMessage.Write(bytes, 0, bytes.Length); // ServerKeyExchange message [optional] => only with RSA_EXPORT and public key > 512 bits if (m_Options.Certificate.GetPublicKeyLength() > 512 && CipherSuites.GetCipherDefinition(m_EncryptionScheme).Exportable) { MemoryStream kes = new MemoryStream(); MD5SHA1CryptoServiceProvider mscsp = new MD5SHA1CryptoServiceProvider(); // hash the client and server random values mscsp.TransformBlock(m_ClientTime, 0, 4, m_ClientTime, 0); mscsp.TransformBlock(m_ClientRandom, 0, 28, m_ClientRandom, 0); mscsp.TransformBlock(m_ServerTime, 0, 4, m_ServerTime, 0); mscsp.TransformBlock(m_ServerRandom, 0, 28, m_ServerRandom, 0); // create a new 512 bit RSA key m_KeyCipher = new RSACryptoServiceProvider(512); RSAParameters p = m_KeyCipher.ExportParameters(false); // write the key parameters to the output stream bytes = new byte[]{(byte)(p.Modulus.Length / 256), (byte)(p.Modulus.Length % 256)}; kes.Write(bytes, 0, 2); kes.Write(p.Modulus, 0, p.Modulus.Length); mscsp.TransformBlock(bytes, 0, 2, bytes, 0); mscsp.TransformBlock(p.Modulus, 0, p.Modulus.Length, p.Modulus, 0); bytes = new byte[]{(byte)(p.Exponent.Length / 256), (byte)(p.Exponent.Length % 256)}; kes.Write(bytes, 0, 2); kes.Write(p.Exponent, 0, p.Exponent.Length); mscsp.TransformBlock(bytes, 0, 2, bytes, 0); mscsp.TransformFinalBlock(p.Exponent, 0, p.Exponent.Length); // create signature bytes = mscsp.CreateSignature(m_Options.Certificate); kes.Write(new byte[]{(byte)(bytes.Length / 256), (byte)(bytes.Length % 256)}, 0, 2); kes.Write(bytes, 0, bytes.Length); // write to output temp.type = HandshakeType.ServerKeyExchange; temp.fragment = kes.ToArray(); bytes = temp.ToBytes(); retMessage.Write(bytes, 0, bytes.Length); kes.Close(); } else { m_KeyCipher = (RSACryptoServiceProvider)m_Options.Certificate.PrivateKey; } // CertificateRequest message [optional] if (m_MutualAuthentication) { bytes = GetDistinguishedNames(); if (bytes.Length != 0) { // make sure at least one certificate is returned temp.type = HandshakeType.CertificateRequest; temp.fragment = new byte[bytes.Length + 4]; temp.fragment[0] = 1; // one certificate type supported temp.fragment[1] = 1; // cert type RSA temp.fragment[2] = (byte)(bytes.Length / 256); temp.fragment[3] = (byte)(bytes.Length % 256); Array.Copy(bytes, 0, temp.fragment, 4, bytes.Length); bytes = temp.ToBytes(); retMessage.Write(bytes, 0, bytes.Length); } } // ServerHelloDone message temp.type = HandshakeType.ServerHelloDone; temp.fragment = new byte[0]; bytes = temp.ToBytes(); retMessage.Write(bytes, 0, bytes.Length); // final adjustments ret.Status = SslStatus.ContinueNeeded; ret.Message = retMessage.ToArray(); retMessage.Close(); UpdateHashes(ret.Message, HashUpdate.All); // output message ret.Message = m_RecordLayer.EncryptBytes(ret.Message, 0, ret.Message.Length, ContentType.Handshake); return ret; }
protected SslHandshakeStatus GetClientHelloResult() { MemoryStream retMessage = new MemoryStream(); SslHandshakeStatus ret = new SslHandshakeStatus(); HandshakeMessage temp; byte[] bytes; // ServerHello message temp = new HandshakeMessage(HandshakeType.ServerHello, new byte[38]); m_ServerTime = GetUnixTime(); m_ServerRandom = new byte[28]; m_RNG.GetBytes(m_ServerRandom); temp.fragment[0] = GetVersion().major; temp.fragment[1] = GetVersion().minor; Array.Copy(m_ServerTime, 0, temp.fragment, 2, 4); Array.Copy(m_ServerRandom, 0, temp.fragment, 6, 28); temp.fragment[34] = 0; // do not resume a session, and do not let the other side cache it Array.Copy(CipherSuites.GetCipherAlgorithmBytes(m_EncryptionScheme), 0, temp.fragment, 35, 2); temp.fragment[37] = CompressionAlgorithm.GetAlgorithmByte(m_CompressionMethod); bytes = temp.ToBytes(); retMessage.Write(bytes, 0, bytes.Length); // Certificate message byte[] certs = GetCertificateList(m_Options.Certificate); temp.type = HandshakeType.Certificate; temp.fragment = certs; bytes = temp.ToBytes(); retMessage.Write(bytes, 0, bytes.Length); // ServerKeyExchange message [optional] => only with RSA_EXPORT and public key > 512 bits if (m_Options.Certificate.GetPublicKeyLength() > 512 && CipherSuites.GetCipherDefinition(m_EncryptionScheme).Exportable) { MemoryStream kes = new MemoryStream(); MD5SHA1CryptoServiceProvider mscsp = new MD5SHA1CryptoServiceProvider(); // hash the client and server random values mscsp.TransformBlock(m_ClientTime, 0, 4, m_ClientTime, 0); mscsp.TransformBlock(m_ClientRandom, 0, 28, m_ClientRandom, 0); mscsp.TransformBlock(m_ServerTime, 0, 4, m_ServerTime, 0); mscsp.TransformBlock(m_ServerRandom, 0, 28, m_ServerRandom, 0); // create a new 512 bit RSA key m_KeyCipher = new RSACryptoServiceProvider(512); RSAParameters p = m_KeyCipher.ExportParameters(false); // write the key parameters to the output stream bytes = new byte[] { (byte)(p.Modulus.Length / 256), (byte)(p.Modulus.Length % 256) }; kes.Write(bytes, 0, 2); kes.Write(p.Modulus, 0, p.Modulus.Length); mscsp.TransformBlock(bytes, 0, 2, bytes, 0); mscsp.TransformBlock(p.Modulus, 0, p.Modulus.Length, p.Modulus, 0); bytes = new byte[] { (byte)(p.Exponent.Length / 256), (byte)(p.Exponent.Length % 256) }; kes.Write(bytes, 0, 2); kes.Write(p.Exponent, 0, p.Exponent.Length); mscsp.TransformBlock(bytes, 0, 2, bytes, 0); mscsp.TransformFinalBlock(p.Exponent, 0, p.Exponent.Length); // create signature bytes = mscsp.CreateSignature(m_Options.Certificate); kes.Write(new byte[] { (byte)(bytes.Length / 256), (byte)(bytes.Length % 256) }, 0, 2); kes.Write(bytes, 0, bytes.Length); // write to output temp.type = HandshakeType.ServerKeyExchange; temp.fragment = kes.ToArray(); bytes = temp.ToBytes(); retMessage.Write(bytes, 0, bytes.Length); kes.Close(); } else { m_KeyCipher = (RSACryptoServiceProvider)m_Options.Certificate.PrivateKey; } // CertificateRequest message [optional] if (m_MutualAuthentication) { bytes = GetDistinguishedNames(); if (bytes.Length != 0) // make sure at least one certificate is returned { temp.type = HandshakeType.CertificateRequest; temp.fragment = new byte[bytes.Length + 4]; temp.fragment[0] = 1; // one certificate type supported temp.fragment[1] = 1; // cert type RSA temp.fragment[2] = (byte)(bytes.Length / 256); temp.fragment[3] = (byte)(bytes.Length % 256); Array.Copy(bytes, 0, temp.fragment, 4, bytes.Length); bytes = temp.ToBytes(); retMessage.Write(bytes, 0, bytes.Length); } } // ServerHelloDone message temp.type = HandshakeType.ServerHelloDone; temp.fragment = new byte[0]; bytes = temp.ToBytes(); retMessage.Write(bytes, 0, bytes.Length); // final adjustments ret.Status = SslStatus.ContinueNeeded; ret.Message = retMessage.ToArray(); retMessage.Close(); UpdateHashes(ret.Message, HashUpdate.All); // output message ret.Message = m_RecordLayer.EncryptBytes(ret.Message, 0, ret.Message.Length, ContentType.Handshake); return(ret); }
public SslRecordStatus ProcessSsl2Hello(byte[] hello) { SslHandshakeStatus hs = m_HandshakeLayer.ProcessSsl2Hello(hello); return(new SslRecordStatus(hs.Status, hs.Message, null)); }
public SslRecordStatus ProcessBytes(byte[] buffer, int offset, int size) { if (buffer == null) { throw new ArgumentNullException(); } if (offset < 0 || offset + size > buffer.Length || size <= 0) { throw new ArgumentException(); } SslRecordStatus ret = new SslRecordStatus(); ret.Status = SslStatus.MessageIncomplete; MemoryStream decrypted = new MemoryStream(); MemoryStream protocol = new MemoryStream(); // copy the new bytes and the old bytes in one buffer byte[] fullbuffer = new byte[m_IncompleteMessage.Length + size]; Array.Copy(m_IncompleteMessage, 0, fullbuffer, 0, m_IncompleteMessage.Length); Array.Copy(buffer, offset, fullbuffer, m_IncompleteMessage.Length, size); // extract all record messages, if any, and process them int recordSize = 0; int recordLength; while (IsRecordMessageComplete(fullbuffer, recordSize)) { RecordMessage message = new RecordMessage(fullbuffer, recordSize); recordLength = message.length + 5; UnwrapMessage(message); // decrypt and verify message // process message if (message.contentType == ContentType.ApplicationData) { if (!m_HandshakeLayer.IsNegotiating()) { decrypted.Write(message.fragment, 0, message.fragment.Length); } else { throw new SslException(AlertDescription.UnexpectedMessage, "The handshake procedure was not completed successfully before application data was received."); } ret.Status = SslStatus.OK; } else // handshake message or change cipher spec message { SslHandshakeStatus status = m_HandshakeLayer.ProcessMessages(message); if (status.Message != null) { protocol.Write(status.Message, 0, status.Message.Length); } ret.Status = status.Status; } recordSize += recordLength; } // copy remaining data [incomplete record] if (recordSize > 0) { m_IncompleteMessage = new byte[fullbuffer.Length - recordSize]; Array.Copy(fullbuffer, recordSize, m_IncompleteMessage, 0, m_IncompleteMessage.Length); } else { m_IncompleteMessage = fullbuffer; } if (decrypted.Length > 0) { ret.Decrypted = decrypted.ToArray(); } decrypted.Close(); if (protocol.Length > 0) { ret.Buffer = protocol.ToArray(); } protocol.Close(); return(ret); }