2 // TlsTest.cs: TLS/SSL Test Program
5 // Sebastien Pouliot <sebastien@ximian.com>
7 // (C) 2004 Novell (http://www.novell.com)
11 using System
.Collections
;
12 using System
.Globalization
;
15 using System
.Net
.Sockets
;
16 using System
.Reflection
;
17 using System
.Security
.Cryptography
.X509Certificates
;
20 using Mono
.Security
.Protocol
.Tls
;
22 public class TlsTest
{
24 public static void Usage (string message
)
26 Console
.WriteLine ("{0}tlstest - Copyright (c) 2004 Novell", Environment
.NewLine
);
27 if (message
!= null) {
28 Console
.WriteLine ("{0}{1}{0}", Environment
.NewLine
, message
);
30 Console
.WriteLine ("Usage:");
31 Console
.WriteLine ("tlstest [protocol] [class] [credentials] [--x:x509 [--x:x509]] [--time] [--show] url [...]");
32 Console
.WriteLine ("{0}protocol (only applicable when using stream)", Environment
.NewLine
);
33 Console
.WriteLine ("\t--any \tNegotiate protocol [default]");
34 Console
.WriteLine ("\t--ssl \tUse SSLv3");
35 Console
.WriteLine ("\t--ssl2 \tUse SSLv2 - unsupported on Mono");
36 Console
.WriteLine ("\t--ssl3 \tUse SSLv3");
37 Console
.WriteLine ("\t--tls \tUse TLSv1");
38 Console
.WriteLine ("\t--tls1 \tUse TLSv1");
39 Console
.WriteLine ("{0}class", Environment
.NewLine
);
40 Console
.WriteLine ("\t--stream\tDirectly use the SslClientStream [default]");
41 Console
.WriteLine ("\t--web \tUse the WebRequest/WebResponse classes");
42 Console
.WriteLine ("{0}credentials", Environment
.NewLine
);
43 Console
.WriteLine ("\t--basic:username:password:domain\tBasic Authentication");
44 Console
.WriteLine ("\t--digest:username:password:domain\tDigest Authentication");
45 Console
.WriteLine ("{0}options", Environment
.NewLine
);
46 Console
.WriteLine ("\t--x:x509\tX.509 client certificate (multiple entries allowed");
47 Console
.WriteLine ("\t--time \tShow the time required for each page load");
48 Console
.WriteLine ("\t--show \tShow the web page content on screen");
49 Console
.WriteLine ("{0}\turl [...]\tOne, or more, URL to download{0}", Environment
.NewLine
);
52 private static bool show
;
53 private static bool time
;
54 private static bool web
;
55 private static Mono
.Security
.Protocol
.Tls
.SecurityProtocolType protocol
= Mono
.Security
.Protocol
.Tls
.SecurityProtocolType
.Default
;
56 private static X509CertificateCollection certificates
= new X509CertificateCollection ();
57 private static NetworkCredential basicCred
;
58 private static NetworkCredential digestCred
;
60 public static void Main (string[] args
)
62 if (args
.Length
== 0) {
63 Usage ("Missing arguments");
67 ArrayList urls
= new ArrayList ();
68 foreach (string arg
in args
) {
72 protocol
= Mono
.Security
.Protocol
.Tls
.SecurityProtocolType
.Default
;
76 protocol
= Mono
.Security
.Protocol
.Tls
.SecurityProtocolType
.Ssl3
;
79 protocol
= Mono
.Security
.Protocol
.Tls
.SecurityProtocolType
.Ssl2
;
80 // note: will only works with Fx 1.2
81 // but the tool doesn't link with it
82 Usage ("Not supported");
86 protocol
= Mono
.Security
.Protocol
.Tls
.SecurityProtocolType
.Tls
;
105 // credentials, certificates, urls or bad options
107 if (arg
.StartsWith ("--digest:")) {
108 digestCred
= GetCredentials (arg
.Substring (9));
111 else if (arg
.StartsWith ("--basic:")) {
112 basicCred
= GetCredentials (arg
.Substring (8));
115 else if (arg
.StartsWith ("--x:")) {
116 string filename
= arg
.Substring (4);
117 X509Certificate x509
= X509Certificate
.CreateFromCertFile (filename
);
118 certificates
.Add (x509
);
121 else if (arg
.StartsWith ("--")) {
122 Usage ("Invalid option " + arg
);
130 if ((web
) && (protocol
!= Mono
.Security
.Protocol
.Tls
.SecurityProtocolType
.Default
)) {
131 Usage ("You can't set the protocol when using the WebRequest/WebResponse class");
135 if (urls
.Count
== 0) {
136 Usage ("no URL were specified");
140 foreach (string url
in urls
) {
141 Console
.WriteLine ("{0}{1}", Environment
.NewLine
, url
);
142 string content
= null;
143 DateTime start
= DateTime
.Now
;
147 content
= GetWebPage (url
);
150 content
= GetStreamPage (url
);
153 catch (Exception e
) {
154 // HResult is protected - but very useful in debugging
155 PropertyInfo pi
= e
.GetType ().GetProperty ("HResult", BindingFlags
.NonPublic
| BindingFlags
.GetProperty
| BindingFlags
.Instance
);
156 Console
.WriteLine ("FAILED: #{0}", (int)pi
.GetValue (e
, null));
157 Console
.WriteLine (e
.ToString ());
160 TimeSpan ts
= (DateTime
.Now
- start
);
161 if ((show
) && (content
!= null)) {
162 Console
.WriteLine ("{0}{1}{0}", Environment
.NewLine
, content
);
165 Console
.WriteLine ("Time: " + ts
.ToString ());
170 public static string GetWebPage (string url
)
172 ServicePointManager
.CertificatePolicy
= new TestCertificatePolicy ();
174 Uri uri
= new Uri (url
);
175 HttpWebRequest req
= (HttpWebRequest
) WebRequest
.Create (uri
);
177 if ((digestCred
!= null) || (basicCred
!= null)) {
178 CredentialCache cache
= new CredentialCache ();
179 if (digestCred
!= null)
180 cache
.Add (uri
, "Digest", digestCred
);
181 if (basicCred
!= null)
182 cache
.Add (uri
, "Basic", basicCred
);
183 req
.Credentials
= cache
;
186 if (certificates
.Count
> 0)
187 req
.ClientCertificates
.AddRange (certificates
);
189 WebResponse resp
= req
.GetResponse ();
190 Stream stream
= resp
.GetResponseStream ();
191 StreamReader sr
= new StreamReader (stream
, Encoding
.UTF8
);
192 return sr
.ReadToEnd ();
195 public static string GetStreamPage (string url
)
197 Uri uri
= new Uri (url
);
198 if (uri
.Scheme
!= Uri
.UriSchemeHttps
)
199 throw new NotSupportedException ("Stream only works with HTTPS protocol");
201 IPHostEntry host
= Dns
.Resolve (uri
.Host
);
202 IPAddress ip
= host
.AddressList
[0];
203 Socket socket
= new Socket (ip
.AddressFamily
, SocketType
.Stream
, ProtocolType
.Tcp
);
204 socket
.Connect (new IPEndPoint (ip
, uri
.Port
));
205 NetworkStream ns
= new NetworkStream (socket
, false);
206 SslClientStream ssl
= new SslClientStream (ns
, uri
.Host
, false, protocol
, certificates
);
207 ssl
.ServerCertValidationDelegate
+= new CertificateValidationCallback (CertificateValidation
);
209 StreamWriter sw
= new StreamWriter (ssl
);
210 sw
.WriteLine ("GET {0}{1}", uri
.AbsolutePath
, Environment
.NewLine
);
213 StreamReader sr
= new StreamReader (ssl
, Encoding
.UTF8
);
214 return sr
.ReadToEnd ();
217 private static NetworkCredential
GetCredentials (string credentials
)
219 string[] creds
= credentials
.Split (':');
220 NetworkCredential nc
= new NetworkCredential ();
221 nc
.UserName
= ((creds
.Length
> 0) ? creds
[0] : String
.Empty
);
222 nc
.Password
= ((creds
.Length
> 1) ? creds
[1] : String
.Empty
);
223 nc
.Domain
= ((creds
.Length
> 2) ? creds
[2] : String
.Empty
);
227 private static void ShowCertificateError (int error
)
229 string message
= null;
232 message
= "CERT_E_PURPOSE 0x800B0106";
235 message
= "CERT_E_CN_NO_MATCH 0x800B010F";
238 message
= "TRUST_E_BASIC_CONSTRAINTS 0x80096019";
241 message
= "TRUST_E_BAD_DIGEST 0x80096010";
244 message
= "CERT_E_VALIDITYPERIODNESTING 0x800B0102";
247 message
= "CERT_E_EXPIRED 0x800B0101";
250 message
= "CERT_E_CHAINING 0x800B010A";
253 message
= "CERT_E_UNTRUSTEDROOT 0x800B0109";
256 message
= "unknown (try WinError.h)";
259 Console
.WriteLine ("Error #{0}: {1}", error
, message
);
262 private static bool CertificateValidation (X509Certificate certificate
, int[] certificateErrors
)
264 if (certificateErrors
.Length
> 0) {
265 Console
.WriteLine (certificate
.ToString (true));
266 // X509Certificate.ToString(true) doesn't show dates :-(
267 Console
.WriteLine ("\tValid From: {0}", certificate
.GetEffectiveDateString ());
268 Console
.WriteLine ("\tValid Until: {0}{1}", certificate
.GetExpirationDateString (), Environment
.NewLine
);
269 // multiple errors are possible using SslClientStream
270 foreach (int error
in certificateErrors
) {
271 ShowCertificateError (error
);
274 // whatever the reason we do not stop the SSL connection
278 public class TestCertificatePolicy
: ICertificatePolicy
{
280 public bool CheckValidationResult (ServicePoint sp
, X509Certificate certificate
, WebRequest request
, int error
)
283 Console
.WriteLine (certificate
.ToString (true));
284 // X509Certificate.ToString(true) doesn't show dates :-(
285 Console
.WriteLine ("\tValid From: {0}", certificate
.GetEffectiveDateString ());
286 Console
.WriteLine ("\tValid Until: {0}{1}", certificate
.GetExpirationDateString (), Environment
.NewLine
);
288 ShowCertificateError (error
);
290 // whatever the reason we do not stop the SSL connection