Donet读取证书扩展域

//

// server.cs: Web Server that uses ASP.NET hosting

//

// Authors:

//	Gonzalo Paniagua Javier ([email protected])

//

// (C) 2002,2003 Ximian, Inc (http://www.ximian.com)

// (C) Copyright 2004-2005 Novell, Inc. (http://www.novell.com)

//

// Permission is hereby granted, free of charge, to any person obtaining

// a copy of this software and associated documentation files (the

// "Software"), to deal in the Software without restriction, including

// without limitation the rights to use, copy, modify, merge, publish,

// distribute, sublicense, and/or sell copies of the Software, and to

// permit persons to whom the Software is furnished to do so, subject to

// the following conditions:

//

// The above copyright notice and this permission notice shall be

// included in all copies or substantial portions of the Software.

//

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND

// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE

// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION

// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION

// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

//

using System;

#if !MODMONO_SERVER

using System.Collections;

using System.Security.Cryptography;

using System.Security.Cryptography.X509Certificates;

using System.Text;

using Mono.Security.Authenticode;

using Mono.Security.Protocol.Tls;

using MSX = Mono.Security.X509;

using Mono.Security.X509.Extensions;

using SecurityProtocolType = Mono.Security.Protocol.Tls.SecurityProtocolType;

#endif

namespace Mono.XSP {

public class SecurityConfiguration {

#if MODMONO_SERVER

public bool Enabled {

get { return false; }

}

public override string ToString ()

{

return String.Empty;

}

#else

private bool enabled;

private bool valid;

private bool accept_client_certificates;

private bool require_client_certificates;

private RSA key;

private SecurityProtocolType protocol;

private X509Certificate x509;

private string p12Filename;

private string certFilename;

private string keyFilename;

private string password;

public SecurityConfiguration ()

{

protocol = SecurityProtocolType.Default;

}

// properties

public bool AcceptClientCertificates {

get { return accept_client_certificates; }

set { accept_client_certificates = value; }

}

public string CertificateFile {

get { return certFilename; }

set { certFilename = value; }

}

public bool Enabled {

get { return enabled; }

set { enabled = value; }

}

public bool RequireClientCertificates {

get { return require_client_certificates; }

set { require_client_certificates = value; }

}

public string Password {

get { throw new CryptographicException ("Password is write-only."); }

set { password = value; }

}

public string Pkcs12File {

get { return p12Filename; }

set { p12Filename = value; }

}

public RSA KeyPair {

get {

if (!valid)

CheckSecurityContextValidity ();

return key;

}

}

public string PvkFile {

get { return keyFilename; }

set { keyFilename = value; }

}

public X509Certificate ServerCertificate {

get {

if (!valid)

CheckSecurityContextValidity ();

return x509;

}

}

public SecurityProtocolType Protocol {

get { return protocol; }

set { protocol = value; }

}

// methods

public void CheckSecurityContextValidity ()

{

if (enabled) {

// give priority to pkcs12 (for conflicting options)

LoadPkcs12File (p12Filename, password);

LoadCertificate (certFilename);

LoadPrivateKeyFile (keyFilename, password);

}

valid = true;

}

public override string ToString ()

{

if (!enabled)

return "(non-secure)";

StringBuilder sb = new StringBuilder ("(");

switch (protocol) {

case SecurityProtocolType.Default:

sb.Append ("auto-detect SSL3/TLS1");

break;

case SecurityProtocolType.Ssl3:

sb.Append ("SSL3");

break;

case SecurityProtocolType.Tls:

sb.Append ("TLS1");

break;

}

if (require_client_certificates)

sb.Append (" with mandatory client certificates");

sb.Append (")");

return sb.ToString ();

}

public void SetProtocol (string protocol)

{

if (protocol != null) {

try {

this.protocol = (SecurityProtocolType) Enum.Parse (typeof (SecurityProtocolType), protocol);

}

catch (Exception e) {

string message = String.Format ("The value '{0}' given for security protocol is invalid.", protocol);

throw new CryptographicException (message, e);

}

} else {

this.protocol = SecurityProtocolType.Default;

}

}

// private stuff

private void LoadCertificate (string filename)

{

if ((filename == null) || (x509 != null))

return;

try {

x509 = X509Certificate.CreateFromCertFile (filename);

}

catch (Exception e) {

string message = String.Format ("Unable to load X.509 certicate file '{0}'.", filename);

throw new CryptographicException (message, e);

}

}

private void LoadPrivateKeyFile (string filename, string password)

{

if ((filename == null) || (key != null))

return;

try {

if (password == null)

key = PrivateKey.CreateFromFile (filename).RSA;

else

key = PrivateKey.CreateFromFile (filename, password).RSA;

}

catch (CryptographicException ce) {

string message = String.Format ("Invalid private key password or private key file '{0}' is corrupt.", filename);

throw new CryptographicException (message, ce);

}

catch (Exception e) {

string message = String.Format ("Unable to load private key '{0}'.", filename);

throw new CryptographicException (message, e);

}

}

private void LoadPkcs12File (string filename, string password)

{

if ((filename == null) || (key != null))

return;

try {

MSX.PKCS12 pfx = null;

if (password == null)

pfx = MSX.PKCS12.LoadFromFile (filename);

else

pfx = MSX.PKCS12.LoadFromFile (filename, password);

// a PKCS12 file may contain many certificates and keys so we must find

// the best one (i.e. not the first one)

// test for only one certificate / keypair

if (Simple (pfx))

return;

// next, we look for a certificate with the server authentication EKU (oid

// 1.3.6.1.5.5.7.3.1) and, if found, try to find a key associated with it

if (ExtendedKeyUsage (pfx))

return;

// next, we look for a certificate with the KU matching the use of a private

// key matching SSL usage and, if found, try to find a key associated with it

if (KeyUsage (pfx))

return;

// next, we look for the old netscape extension

if (NetscapeCertType (pfx))

return;

// finally we iterate all keys (not certificates) to find a certificate with the

// same public key

if (BruteForce (pfx))

return;

// we don't merit to use SSL ;-)

throw new Exception ("Couldn't find an appropriate certificate and private key to use for SSL.");

}

catch (CryptographicException ce) {

string message = String.Format ("Invalid private key password or private key file '{0}' is corrupt.", filename);

throw new CryptographicException (message, ce);

}

catch (Exception e) {

string message = String.Format ("Unable to load private key '{0}'.", filename);

throw new CryptographicException (message, e);

}

}

private bool Simple (MSX.PKCS12 pfx)

{

int ncerts = pfx.Certificates.Count;

if (ncerts == 0)

throw new Exception ("No certificates are present in the PKCS#12 file.");

int nkeys = pfx.Keys.Count;

if (nkeys == 0)

throw new Exception ("No keypair is present in the PKCS#12 file.");

if (ncerts == 1) {

MSX.X509Certificate cert = pfx.Certificates [0];

// only one certificate, find matching key

if (nkeys == 1) {

// only one key

key = (pfx.Keys [0] as RSA);

} else {

// many keys (strange case)

key = GetKeyMatchingCertificate (pfx, cert);

}

// complete ?

if ((key != null) && (cert != null)) {

x509 = new X509Certificate (cert.RawData);

return true;

}

}

return false;

}

private bool ExtendedKeyUsage (MSX.PKCS12 pfx)

{

foreach (MSX.X509Certificate cert in pfx.Certificates) {

MSX.X509Extension xtn = cert.Extensions ["2.5.29.37"];

if (xtn == null)

continue;

ExtendedKeyUsageExtension eku = new ExtendedKeyUsageExtension (xtn);

if (!eku.KeyPurpose.Contains ("1.3.6.1.5.5.7.3.1"))

continue;

key = GetKeyMatchingCertificate (pfx, cert);

if (key == null)

continue;

x509 = new X509Certificate (cert.RawData);

break;

}

// complete ?

return ((x509 != null) && (key != null));

}

private bool KeyUsage (MSX.PKCS12 pfx)

{

foreach (MSX.X509Certificate cert in pfx.Certificates) {

MSX.X509Extension xtn = cert.Extensions ["2.5.29.15"];

if (xtn == null)

continue;

KeyUsageExtension ku = new KeyUsageExtension (xtn);

if (!ku.Support (KeyUsages.digitalSignature) && !ku.Support (KeyUsages.keyEncipherment))

continue;

key = GetKeyMatchingCertificate (pfx, cert);

if (key == null)

continue;

x509 = new X509Certificate (cert.RawData);

break;

}

// complete ?

return ((x509 != null) && (key != null));

}

private bool NetscapeCertType (MSX.PKCS12 pfx)

{

foreach (MSX.X509Certificate cert in pfx.Certificates) {

MSX.X509Extension xtn = cert.Extensions ["2.16.840.1.113730.1.1"];

if (xtn == null)

continue;

NetscapeCertTypeExtension ct = new NetscapeCertTypeExtension (xtn);

if (!ct.Support (NetscapeCertTypeExtension.CertTypes.SslServer))

continue;

key = GetKeyMatchingCertificate (pfx, cert);

if (key == null)

continue;

x509 = new X509Certificate (cert.RawData);

break;

}

// complete ?

return ((x509 != null) && (key != null));

}

private bool BruteForce (MSX.PKCS12 pfx)

{

foreach (object o in pfx.Keys) {

key = (o as RSA);

if (key == null)

continue;

string s = key.ToXmlString (false);

foreach (MSX.X509Certificate cert in pfx.Certificates) {

if (s == cert.RSA.ToXmlString (false))

x509 = new X509Certificate (cert.RawData);

}

// complete ?

if ((x509 != null) && (key != null))

return true;

}

return false;

}

private RSA GetKeyMatchingCertificate (MSX.PKCS12 pfx, MSX.X509Certificate cert)

{

IDictionary attributes = pfx.GetAttributes (cert);

return (pfx.GetAsymmetricAlgorithm (attributes) as RSA);

}

#endif

}

}

你可能感兴趣的:(net)