News  [SoftwareSite

Latest News
Older News
RSS Feed
 
Complete Projects
Useful Classes
Top Downloads
Message Board
AllAPI.net
 
Send Comments
Software License
Mentalis.org Buttons
Donate
 
Forums -> Security Library Forum
 
Modifying Cassini for SSL  
by J.R. Brown [jbrown at les dot com]
posted on 2004/01/23

I've talked to a lot of people regarding the Cassini webserver and enhancing it to provide SSL capabilities. Mentalis .NET SSL seems like a very good fit. Now for some resources and a little background...

Resources
Cassini Webserver (Supports ASP.NET)
http://www.asp.net/Projects/Cassini/Download/Default.aspx?tabindex=0&tabid=1

Using Mentalis .NET security library version 1.0

Background - The Cassini webserver implements the System.Net.Sockets for network commmunications. My understanding is that you should be able to "drop-in" the Mentalis security library in place of the System.Net.Sockets library since it is inherited.

The problem - When I've changed the Cassini source code to use SecureSocket or VirtualSocket definitions the application seems to continuosly loop, waiting for data.

To see this watch:
private void OnStart
private void OnSocketAccept

The 'Start' menthod has been substantially modified also.

Here is the modified Host.cs - If you would like the complete project please e-mail me at jbrown@les.com and I will send it to you.

Once this is working I would like to share it with the .Net community.

Thanks for your time.

- J.R.

----------------CODE---------------------

/*=======================================================================
  Copyright (C) Microsoft Corporation.  All rights reserved.
 
THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
=======================================================================*/

namespace Cassini {
using System;
using System.Collections;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Web;
using System.Web.Hosting;
using Org.Mentalis.Security;
using Org.Mentalis.Security.Ssl;
using Org.Mentalis.Security.Certificates;


//
// Instances of an internal Host class are created in the App Domain
// processing HTTP request. Typeof(Host) is passed to CreateApplicationHost()
//
// Host uses System.Net to listen to the configured port and accept
// incoming HTTP connections.
//
internal class Host : MarshalByRefObject {
private bool _started;
private bool _stopped;

private Server _server;

private int _port;
private String _virtualPath;
private String _lowerCasedVirtualPath;
private String _lowerCasedVirtualPathWithTrailingSlash;
private String _physicalPath;
private String _installPath;
private String _physicalClientScriptPath;
private String _lowerCasedClientScriptPathWithTrailingSlashV10;
private String _lowerCasedClientScriptPathWithTrailingSlashV11;

private VirtualSocket _socket;

private WaitCallback _onStart;
private WaitCallback _onSocketAccept;
private EventHandler _onAppDomainUnload;

public override Object InitializeLifetimeService() {
return null; // never expire lease
}

public void Configure(Server server, int port, String virtualPath, String physicalPath, String installPath) {
_server = server;

_port = port;
_virtualPath = virtualPath;
_lowerCasedVirtualPath = CultureInfo.InvariantCulture.TextInfo.ToLower(_virtualPath);
_lowerCasedVirtualPathWithTrailingSlash = virtualPath.EndsWith("/") ? virtualPath : virtualPath + "/";
_lowerCasedVirtualPathWithTrailingSlash = CultureInfo.InvariantCulture.TextInfo.ToLower(_lowerCasedVirtualPathWithTrailingSlash);
_physicalPath = physicalPath;
_installPath = installPath;
_physicalClientScriptPath = installPath + "\\asp.netclientfiles\\";

String version4 = FileVersionInfo.GetVersionInfo(typeof(HttpRuntime).Module.FullyQualifiedName).FileVersion;
String version3 = version4.Substring(0, version4.LastIndexOf('.'));
_lowerCasedClientScriptPathWithTrailingSlashV10 = "/aspnet_client/system_web/" + version4.Replace('.', '_') + "/";
_lowerCasedClientScriptPathWithTrailingSlashV11 = "/aspnet_client/system_web/" + version3.Replace('.', '_') + "/";

_onSocketAccept = new WaitCallback(OnSocketAccept);
_onStart = new WaitCallback(OnStart);

// start watching for app domain unloading
_onAppDomainUnload = new EventHandler(OnAppDomainUnload);
Thread.GetDomain().DomainUnload += _onAppDomainUnload;
}

public String NormalizedVirtualPath {
get { return _lowerCasedVirtualPathWithTrailingSlash; }
}

public String PhysicalPath {
get { return _physicalPath; }
}

public String InstallPath {
get { return _installPath; }
}

public String PhysicalClientScriptPath {
get { return _physicalClientScriptPath; }
}

public int Port {
get { return _port; }
}

public String VirtualPath {
get { return _virtualPath; }
}

public bool IsVirtualPathInApp(String path) {
bool isClientScriptPath;
String clientScript;
return IsVirtualPathInApp(path, out isClientScriptPath, out clientScript);
}

public bool IsVirtualPathInApp(String path, out bool isClientScriptPath, out String clientScript) {
isClientScriptPath = false;
clientScript = null;

if (path == null)
return false;

if (_virtualPath == "/" && path.StartsWith("/")) {
if (path.StartsWith(_lowerCasedClientScriptPathWithTrailingSlashV10)) {
isClientScriptPath = true;
clientScript = path.Substring(_lowerCasedClientScriptPathWithTrailingSlashV10.Length);
}

if (path.StartsWith(_lowerCasedClientScriptPathWithTrailingSlashV11)) {
isClientScriptPath = true;
clientScript = path.Substring(_lowerCasedClientScriptPathWithTrailingSlashV11.Length);
}

return true;
}

path = CultureInfo.InvariantCulture.TextInfo.ToLower(path);

if (path.StartsWith(_lowerCasedVirtualPathWithTrailingSlash))
return true;

if (path == _lowerCasedVirtualPath)
return true;

if (path.StartsWith(_lowerCasedClientScriptPathWithTrailingSlashV10)) {
isClientScriptPath = true;
clientScript = path.Substring(_lowerCasedClientScriptPathWithTrailingSlashV10.Length);
return true;
}

if (path.StartsWith(_lowerCasedClientScriptPathWithTrailingSlashV11)) {
isClientScriptPath = true;
clientScript = path.Substring(_lowerCasedClientScriptPathWithTrailingSlashV11.Length);
return true;
}

return false;
}

public bool IsVirtualPathAppPath(String path) {
if (path == null)
return false;

path = CultureInfo.InvariantCulture.TextInfo.ToLower(path);
return (path == _lowerCasedVirtualPath || path == _lowerCasedVirtualPathWithTrailingSlash);
}

private void OnAppDomainUnload(Object unusedObject, EventArgs unusedEventArgs) {
Thread.GetDomain().DomainUnload -= _onAppDomainUnload;

if (_stopped)
return;

Stop();

_server.Restart();
_server = null;
}

private void OnSocketAccept(Object acceptedSocket) {
Connection conn = new Connection(this, (VirtualSocket)acceptedSocket);
conn.ProcessOneRequest();
}

private void OnStart(Object unused) {
while (_started) {
try {
VirtualSocket socket = _socket.Accept();
ThreadPool.QueueUserWorkItem(_onSocketAccept, socket);
}
catch {
Thread.Sleep(100);
}
}

_stopped = true;
}

public void Start() {
if (_started)
throw new InvalidOperationException();

//JRBSOFT
SecureProtocol sp;
sp = SecureProtocol.Ssl3;

CertificateStore cs;
cs = CertificateStore.CreateFromPfxFile("server.pfx", "test");
Certificate cert = cs.FindCertificateByUsage( new string[] {"1.3.6.1.5.5.7.3.1"});

SecurityOptions options = new SecurityOptions(sp, cert, ConnectionEnd.Server);
VirtualSocket _socket = new SecureSocket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp, options);

//JRBSOFT

_socket = new VirtualSocket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_socket.Bind(new IPEndPoint(IPAddress.Any, _port));
_socket.Listen((int)SocketOptionName.MaxConnections);

_started = true;
ThreadPool.QueueUserWorkItem(_onStart);
}

public void Stop() {
if (!_started)
return;

_started = false;

try {
// _socket.Shutdown(SocketShutdown.Both); /* blocks! */
_socket.Close();
}
catch {
}
finally {
_socket = null;
}

while (!_stopped)
Thread.Sleep(100);
}

}
}

by Pieter Philippaerts [Pieter at mentalis dot org]
posted on 2004/01/25

Looks like you forgot to comment a line of code. Here's a small piece of the code you posted:

VirtualSocket _socket = new SecureSocket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp, options);
//JRBSOFT
_socket = new VirtualSocket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

You first create a SecureSocket and then immediately throw it away and replace it with a normal non-SSL socket. I guess that second line should be commented. Let me know if it works after you make that change.

by J.R. Brown [jbrown at les dot com]
posted on 2004/01/27

Sorry about that.. I've been through the code so much that my head is spinning!

I commented out that line however, it did not fix the problem.

Just to clarify a little bit.... When I debug the application, it keeps looping on the line I marked with *LOOP*, and never proceeds to the next line.

private void OnStart(Object unused) {
while (_started) {
try {
VirtualSocket socket = _socket.Accept(); *LOOP*
ThreadPool.QueueUserWorkItem(_onSocketAccept, socket);
}
catch {
Thread.Sleep(100);
}
}

_stopped = true;
}

by J.R. Brown [jrbrown625 at hotmail dot com]
posted on 2004/01/30

Anyone? ;)

by TheXenocide
posted on 2005/04/10

This may or may not be accurate as I have not used the library in question, but I believe that this line of code is your culprit:

Connection conn = new Connection(this, (VirtualSocket)acceptedSocket);

You have changed the code over to using SecureSocket, which, if it does not extend VirtualSocket, may cause a cast exception to occur. This may or may not be the cause, but either way, you should place some sort of debugging code in your catch block in case you are encountering an exception.

 

Copyright © 2002-2007, The Mentalis.org Team. All rights reserved.
This site is located at http://www.mentalis.org/
Send comments to the webmaster.