**** Merged from MCS ****
[mono-project.git] / mcs / class / Mono.Security / Test / tools / tlstest / tlstest.cs
blob2f06912ca55cf814b88c6394560840ddd5a24ae3
1 //
2 // TlsTest.cs: TLS/SSL Test Program
3 //
4 // Author:
5 // Sebastien Pouliot <sebastien@ximian.com>
6 //
7 // (C) 2004 Novell (http://www.novell.com)
8 //
10 using System;
11 using System.Collections;
12 using System.Globalization;
13 using System.IO;
14 using System.Net;
15 using System.Net.Sockets;
16 using System.Reflection;
17 using System.Security.Cryptography.X509Certificates;
18 using System.Text;
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");
64 return;
67 ArrayList urls = new ArrayList ();
68 foreach (string arg in args) {
69 switch (arg) {
70 // protocol
71 case "--any":
72 protocol = Mono.Security.Protocol.Tls.SecurityProtocolType.Default;
73 break;
74 case "--ssl":
75 case "--ssl3":
76 protocol = Mono.Security.Protocol.Tls.SecurityProtocolType.Ssl3;
77 break;
78 case "--ssl2":
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");
83 return;
84 case "--tls":
85 case "--tls1":
86 protocol = Mono.Security.Protocol.Tls.SecurityProtocolType.Tls;
87 break;
88 // class
89 case "--stream":
90 web = false;
91 break;
92 case "--web":
93 web = true;
94 break;
95 // options
96 case "--time":
97 time = true;
98 break;
99 case "--show":
100 show = true;
101 break;
102 case "--help":
103 Usage (null);
104 return;
105 // credentials, certificates, urls or bad options
106 default:
107 if (arg.StartsWith ("--digest:")) {
108 digestCred = GetCredentials (arg.Substring (9));
109 continue;
111 else if (arg.StartsWith ("--basic:")) {
112 basicCred = GetCredentials (arg.Substring (8));
113 continue;
115 else if (arg.StartsWith ("--x:")) {
116 string filename = arg.Substring (4);
117 X509Certificate x509 = X509Certificate.CreateFromCertFile (filename);
118 certificates.Add (x509);
119 continue;
121 else if (arg.StartsWith ("--")) {
122 Usage ("Invalid option " + arg);
123 return;
125 urls.Add (arg);
126 break;
130 if ((web) && (protocol != Mono.Security.Protocol.Tls.SecurityProtocolType.Default)) {
131 Usage ("You can't set the protocol when using the WebRequest/WebResponse class");
132 return;
135 if (urls.Count == 0) {
136 Usage ("no URL were specified");
137 return;
140 foreach (string url in urls) {
141 Console.WriteLine ("{0}{1}", Environment.NewLine, url);
142 string content = null;
143 DateTime start = DateTime.Now;
145 try {
146 if (web) {
147 content = GetWebPage (url);
149 else {
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);
164 if (time) {
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);
211 sw.Flush ();
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);
224 return nc;
227 private static void ShowCertificateError (int error)
229 string message = null;
230 switch (error) {
231 case -2146762490:
232 message = "CERT_E_PURPOSE 0x800B0106";
233 break;
234 case -2146762481:
235 message = "CERT_E_CN_NO_MATCH 0x800B010F";
236 break;
237 case -2146869223:
238 message = "TRUST_E_BASIC_CONSTRAINTS 0x80096019";
239 break;
240 case -2146869232:
241 message = "TRUST_E_BAD_DIGEST 0x80096010";
242 break;
243 case -2146762494:
244 message = "CERT_E_VALIDITYPERIODNESTING 0x800B0102";
245 break;
246 case -2146762495:
247 message = "CERT_E_EXPIRED 0x800B0101";
248 break;
249 case -2146762486:
250 message = "CERT_E_CHAINING 0x800B010A";
251 break;
252 case -2146762487:
253 message = "CERT_E_UNTRUSTEDROOT 0x800B0109";
254 break;
255 default:
256 message = "unknown (try WinError.h)";
257 break;
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
275 return true;
278 public class TestCertificatePolicy : ICertificatePolicy {
280 public bool CheckValidationResult (ServicePoint sp, X509Certificate certificate, WebRequest request, int error)
282 if (error != 0) {
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
291 return true;