Merge pull request #2274 from esdrubal/udpclientreceive
[mono.git] / mcs / class / Mono.Security / Mono.Security.Protocol.Tls.Handshake.Client / TlsServerCertificate.cs
index ef12ed1075e6a816034892981ca36769e2bc17c5..a96b415ef0c56c338ae57dedbe6b9e27f53d3645 100644 (file)
@@ -1,6 +1,6 @@
 // Transport Security Layer (TLS)
 // Copyright (c) 2003-2004 Carlos Guzman Alvarez
-// Copyright (C) 2004, 2006-2007 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2004, 2006-2010 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
@@ -33,6 +33,8 @@ using X509Cert = System.Security.Cryptography.X509Certificates;
 using Mono.Security.X509;
 using Mono.Security.X509.Extensions;
 
+using Mono.Security.Interface;
+
 namespace Mono.Security.Protocol.Tls.Handshake.Client
 {
        internal class TlsServerCertificate : HandshakeMessage
@@ -177,8 +179,9 @@ namespace Mono.Security.Protocol.Tls.Handshake.Client
                                return ct.Support (NetscapeCertTypeExtension.CertTypes.SslServer);
                        }
 
-                       // certificate isn't valid for SSL server usage
-                       return false;
+                       // if the CN=host (checked later) then we assume this is meant for SSL/TLS
+                       // e.g. the new smtp.gmail.com certificate
+                       return true;
                }
 
                private void validateCertificates(X509CertificateCollection certificates)
@@ -186,6 +189,45 @@ namespace Mono.Security.Protocol.Tls.Handshake.Client
                        ClientContext           context                 = (ClientContext)this.Context;
                        AlertDescription        description             = AlertDescription.BadCertificate;
 
+#if INSIDE_SYSTEM
+                       // This helps the linker to remove a lot of validation code that will never be used since 
+                       // System.dll will, for OSX and iOS, uses the operating system X.509 certificate validations
+                       RemoteValidation (context, description);
+#else
+                       if (context.SslStream.HaveRemoteValidation2Callback)
+                               RemoteValidation (context, description);
+                       else 
+                               LocalValidation (context, description);
+#endif
+               }
+
+               void RemoteValidation (ClientContext context, AlertDescription description)
+               {
+                       ValidationResult res = context.SslStream.RaiseServerCertificateValidation2 (certificates);
+                       if (res.Trusted)
+                               return;
+
+                       long error = res.ErrorCode;
+                       switch (error) {
+                       case 0x800B0101:
+                               description = AlertDescription.CertificateExpired;
+                               break;
+                       case 0x800B010A:
+                               description = AlertDescription.UnknownCA;
+                               break;
+                       case 0x800B0109:
+                               description = AlertDescription.UnknownCA;
+                               break;
+                       default:
+                               description = AlertDescription.CertificateUnknown;
+                               break;
+                       }
+                       string err = String.Format ("Invalid certificate received from server. Error code: 0x{0:x}", error);
+                       throw new TlsException (description, err);
+               }
+
+               void LocalValidation (ClientContext context, AlertDescription description)
+               {
                        // the leaf is the web server certificate
                        X509Certificate leaf = certificates [0];
                        X509Cert.X509Certificate cert = new X509Cert.X509Certificate (leaf.RawData);