changes to regions ssl suport: verify if hostnames are validate by the selected cert, make clear that for now all regions need to have the same ExternalHostName if using sll (due to other code that needs to be changed later)
parent
9843e3776e
commit
5b946405a0
|
@ -43,10 +43,11 @@ using log4net;
|
||||||
using Nwc.XmlRpc;
|
using Nwc.XmlRpc;
|
||||||
using OpenMetaverse.StructuredData;
|
using OpenMetaverse.StructuredData;
|
||||||
using CoolHTTPListener = HttpServer.HttpListener;
|
using CoolHTTPListener = HttpServer.HttpListener;
|
||||||
using HttpListener=System.Net.HttpListener;
|
using HttpListener = System.Net.HttpListener;
|
||||||
using LogPrio=HttpServer.LogPrio;
|
using LogPrio = HttpServer.LogPrio;
|
||||||
using OpenSim.Framework.Monitoring;
|
using OpenSim.Framework.Monitoring;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
namespace OpenSim.Framework.Servers.HttpServer
|
namespace OpenSim.Framework.Servers.HttpServer
|
||||||
{
|
{
|
||||||
|
@ -112,6 +113,9 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
private X509Certificate2 m_cert;
|
private X509Certificate2 m_cert;
|
||||||
protected bool m_firstcaps = true;
|
protected bool m_firstcaps = true;
|
||||||
protected string m_SSLCommonName = "";
|
protected string m_SSLCommonName = "";
|
||||||
|
protected List<string> m_certNames = new List<string>();
|
||||||
|
protected List<string> m_certIPs = new List<string>();
|
||||||
|
protected string m_certCN= "";
|
||||||
|
|
||||||
protected IPAddress m_listenIPAddress = IPAddress.Any;
|
protected IPAddress m_listenIPAddress = IPAddress.Any;
|
||||||
|
|
||||||
|
@ -153,30 +157,150 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
m_ssl = ssl;
|
m_ssl = ssl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BaseHttpServer(uint port, bool ssl, uint sslport, string CN, string CPath, string CPass) : this (port, ssl)
|
private void load_cert(string CPath, string CPass)
|
||||||
{
|
{
|
||||||
if (m_ssl)
|
try
|
||||||
{
|
{
|
||||||
if(string.IsNullOrEmpty(CPass))
|
m_cert = new X509Certificate2(CPath, CPass);
|
||||||
|
X509Extension ext = m_cert.Extensions["2.5.29.17"];
|
||||||
|
if(ext != null)
|
||||||
|
{
|
||||||
|
AsnEncodedData asndata = new AsnEncodedData(ext.Oid, ext.RawData);
|
||||||
|
string datastr = asndata.Format(true);
|
||||||
|
string[] lines = datastr.Split(new char[] {'\n','\r'});
|
||||||
|
foreach(string s in lines)
|
||||||
|
{
|
||||||
|
if(String.IsNullOrEmpty(s))
|
||||||
|
continue;
|
||||||
|
string[] parts = s.Split(new char[] {'='});
|
||||||
|
if(String.IsNullOrEmpty(parts[0]))
|
||||||
|
continue;
|
||||||
|
string entryName = parts[0].Replace(" ","");
|
||||||
|
if(entryName == "DNSName")
|
||||||
|
m_certNames.Add(parts[1]);
|
||||||
|
else if(entryName == "IPAddress")
|
||||||
|
m_certIPs.Add(parts[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_certCN = m_cert.GetNameInfo(X509NameType.SimpleName, false);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
throw new Exception("SSL cert load error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BaseHttpServer(uint port, bool ssl, uint sslport, string CN, string CPath, string CPass)
|
||||||
|
{
|
||||||
|
m_port = port;
|
||||||
|
if (ssl)
|
||||||
|
{
|
||||||
|
if(string.IsNullOrEmpty(CPath))
|
||||||
throw new Exception("invalid main http server cert path");
|
throw new Exception("invalid main http server cert path");
|
||||||
|
|
||||||
|
if(Uri.CheckHostName(CN) == UriHostNameType.Unknown)
|
||||||
|
throw new Exception("invalid main http server CN (ExternalHostName)");
|
||||||
|
|
||||||
|
m_certNames.Clear();
|
||||||
|
m_certIPs.Clear();
|
||||||
|
m_certCN= "";
|
||||||
|
|
||||||
|
m_ssl = true;
|
||||||
m_sslport = sslport;
|
m_sslport = sslport;
|
||||||
m_cert = new X509Certificate2(CPath, CPass);
|
load_cert(CPath, CPass);
|
||||||
m_SSLCommonName = m_cert.GetNameInfo(X509NameType.SimpleName,false);
|
|
||||||
if(CN != m_SSLCommonName)
|
if(!CheckSSLCertHost(CN))
|
||||||
throw new Exception("main http server CN does not match cert CN");
|
throw new Exception("invalid main http server CN (ExternalHostName)");
|
||||||
|
|
||||||
|
m_SSLCommonName = CN;
|
||||||
|
|
||||||
|
if(m_cert.Issuer == m_cert.Subject )
|
||||||
|
m_log.Warn("Self signed certificate. Clients need to allow this (some viewers debug option NoVerifySSLcert must be set to true");
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
m_ssl = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BaseHttpServer(uint port, bool ssl, string CPath, string CPass) : this (port, ssl)
|
public BaseHttpServer(uint port, bool ssl, string CPath, string CPass) : this (port, ssl)
|
||||||
{
|
{
|
||||||
if (m_ssl)
|
if (m_ssl)
|
||||||
{
|
{
|
||||||
m_cert = new X509Certificate2(CPath, CPass);
|
load_cert(CPath, CPass);
|
||||||
|
if(m_cert.Issuer == m_cert.Subject )
|
||||||
|
m_log.Warn("Self signed certificate. Http clients need to allow this");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool MatchDNS (string hostname, string dns)
|
||||||
|
{
|
||||||
|
int indx = dns.IndexOf ('*');
|
||||||
|
if (indx == -1)
|
||||||
|
return (String.Compare(hostname, dns, true, CultureInfo.InvariantCulture) == 0);
|
||||||
|
|
||||||
|
int dnslen = dns.Length;
|
||||||
|
dnslen--;
|
||||||
|
if(indx == dnslen)
|
||||||
|
return true; // just * ?
|
||||||
|
|
||||||
|
if(indx > dnslen - 2)
|
||||||
|
return false; // 2 short ?
|
||||||
|
|
||||||
|
if (dns[indx + 1] != '.')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int indx2 = dns.IndexOf ('*', indx + 1);
|
||||||
|
if (indx2 != -1)
|
||||||
|
return false; // there can only be one;
|
||||||
|
|
||||||
|
string end = dns.Substring(indx + 1);
|
||||||
|
int hostlen = hostname.Length;
|
||||||
|
int endlen = end.Length;
|
||||||
|
int length = hostlen - endlen;
|
||||||
|
if (length <= 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (String.Compare(hostname, length, end, 0, endlen, true, CultureInfo.InvariantCulture) != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (indx == 0)
|
||||||
|
{
|
||||||
|
indx2 = hostname.IndexOf ('.');
|
||||||
|
return ((indx2 == -1) || (indx2 >= length));
|
||||||
|
}
|
||||||
|
|
||||||
|
string start = dns.Substring (0, indx);
|
||||||
|
return (String.Compare (hostname, 0, start, 0, start.Length, true, CultureInfo.InvariantCulture) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CheckSSLCertHost(string hostname)
|
||||||
|
{
|
||||||
|
UriHostNameType htype = Uri.CheckHostName(hostname);
|
||||||
|
|
||||||
|
if(htype == UriHostNameType.Unknown || htype == UriHostNameType.Basic)
|
||||||
|
return false;
|
||||||
|
if(htype == UriHostNameType.Dns)
|
||||||
|
{
|
||||||
|
foreach(string name in m_certNames)
|
||||||
|
{
|
||||||
|
if(MatchDNS(hostname, name))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if(MatchDNS(hostname, m_certCN))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach(string ip in m_certIPs)
|
||||||
|
{
|
||||||
|
if (String.Compare(hostname, ip, true, CultureInfo.InvariantCulture) != 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add a stream handler to the http server. If the handler already exists, then nothing happens.
|
/// Add a stream handler to the http server. If the handler already exists, then nothing happens.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -417,7 +417,7 @@ namespace OpenSim
|
||||||
regionInfo.HttpPort = m_httpServerPort;
|
regionInfo.HttpPort = m_httpServerPort;
|
||||||
if(m_httpServerSSL)
|
if(m_httpServerSSL)
|
||||||
{
|
{
|
||||||
if(m_networkServersInfo.HttpSSLCN != regionInfo.ExternalHostName)
|
if(!m_httpServer.CheckSSLCertHost(regionInfo.ExternalHostName))
|
||||||
throw new Exception("main http cert CN doesn't match region External IP");
|
throw new Exception("main http cert CN doesn't match region External IP");
|
||||||
|
|
||||||
regionInfo.ServerURI = "https://" + regionInfo.ExternalHostName +
|
regionInfo.ServerURI = "https://" + regionInfo.ExternalHostName +
|
||||||
|
|
|
@ -501,10 +501,12 @@
|
||||||
console_port = 0
|
console_port = 0
|
||||||
|
|
||||||
; ssl config: Experimental!
|
; ssl config: Experimental!
|
||||||
http_listener_ssl = false ; if set to true main server is replaced a ssl one
|
http_listener_ssl = false ; if set to true main server is replaced by a ssl one
|
||||||
http_listener_sslport = 9001 ; Use this port for SSL connections
|
http_listener_sslport = 9001 ; Use this port for SSL connections
|
||||||
http_listener_cn = "myexternalip" ; // should be the External ip and match the CN on the cert
|
; currently if using ssl, regions ExternalHostName must the the same and equal to http_listener_cn
|
||||||
http_listener_cert_path = "mycert.p12" ; path for the cert file
|
; this will change is future
|
||||||
|
http_listener_cn = "myRegionsExternalHostName"
|
||||||
|
http_listener_cert_path = "mycert.p12" ; path for the cert file that is valid for the ExternalHostName
|
||||||
http_listener_cert_pass = "mycertpass" ; the cert passwork
|
http_listener_cert_pass = "mycertpass" ; the cert passwork
|
||||||
|
|
||||||
; HTTPS for "Out of band" management applications such as the remote
|
; HTTPS for "Out of band" management applications such as the remote
|
||||||
|
|
Loading…
Reference in New Issue