3272c53e56a3ae6e5bfcf6fc2cd88444c2daa8e4
[mono.git] / mcs / class / Mono.Security / Test / tools / postecho / postecho.cs
1 //
2 // postecho.cs: TLS/SSL Post Echo Test Program
3 //
4 // Authors:
5 //      Gonzalo Paniagua Javier  <gonzalo@ximian.com>
6 //      Sebastien Pouliot  <sebastien@ximian.com>
7 //
8 // (C) 2005 Novell (http://www.novell.com)
9 //
10
11 using System;
12 using System.IO;
13 using System.Net;\r
14 using System.Net.Sockets;\r
15 using System.Text;\r
16 using System.Security.Cryptography.X509Certificates;\r
17 using Mono.Security.Protocol.Tls;
18
19 class PostEcho {\r
20 \r
21         static void Help ()\r
22         {\r
23                 Console.WriteLine ("postecho url [size] [--web | --ssl3 | --tls1]");\r
24                 Console.WriteLine ("  default size is 1024");\r
25                 Console.WriteLine ("  default mode is --tls1");\r
26                 Console.WriteLine ("* a server side script must be installed to run postecho");\r
27         }\r
28 \r
29         static string PostWeb (string url, byte[] buffer)\r
30         {\r
31                 string postdata = "TEST=";
32                 HttpWebRequest req = (HttpWebRequest) WebRequest.Create (url);
33                 req.Method = "POST";
34                 req.ContentType = "application/x-www-form-urlencoded";
35                 req.ContentLength = 5 + buffer.Length;
36                 Stream output = req.GetRequestStream ();
37                 byte [] bytes = Encoding.Default.GetBytes (postdata);
38                 output.Write (bytes, 0, bytes.Length);\r
39                 output.Write (buffer, 0, buffer.Length);
40                 output.Close ();
41                 HttpWebResponse response = (HttpWebResponse) req.GetResponse ();
42                 StreamReader reader = new StreamReader (response.GetResponseStream ());
43                 return reader.ReadToEnd ();\r
44         }\r
45 \r
46         static string PostStream (Mono.Security.Protocol.Tls.SecurityProtocolType protocol, string url, byte[] buffer)\r
47         {\r
48                 Uri uri = new Uri (url);
49                 string post = "POST " + uri.AbsolutePath + " HTTP/1.0\r\n";\r
50                 post += "Content-Type: application/x-www-form-urlencoded\r\n";\r
51                 post += "Content-Length: " + (buffer.Length + 5).ToString () + "\r\n";\r
52                 post += "Host: " + uri.Host + "\r\n\r\n";\r
53                 post += "TEST=";\r
54                 byte[] bytes = Encoding.Default.GetBytes (post);\r
55 \r
56                 IPHostEntry host = Dns.Resolve (uri.Host);
57                 IPAddress ip = host.AddressList [0];
58                 Socket socket = new Socket (ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
59                 socket.Connect (new IPEndPoint (ip, uri.Port));
60                 NetworkStream ns = new NetworkStream (socket, false);
61                 SslClientStream ssl = new SslClientStream (ns, uri.Host, false, protocol);
62                 ssl.ServerCertValidationDelegate += new CertificateValidationCallback (CertificateValidation);
63
64                 ssl.Write (bytes, 0, bytes.Length);\r
65                 ssl.Write (buffer, 0, buffer.Length);\r
66                 ssl.Flush ();\r
67 \r
68                 StreamReader reader = new StreamReader (ssl, Encoding.UTF8);\r
69                 string result = reader.ReadToEnd ();\r
70                 int start = result.IndexOf ("\r\n\r\n") + 4;\r
71                 start = result.IndexOf ("\r\n\r\n") + 4;\r
72                 return result.Substring (start);\r
73         }
74
75         static int Main (string[] args)
76         {
77                 if (args.Length < 1) {\r
78                         Help ();\r
79                         return 2;\r
80                 }
81
82                 string url = args [0];
83                 int size = 1024;
84                 bool ssl = true;\r
85                 Mono.Security.Protocol.Tls.SecurityProtocolType protocol = Mono.Security.Protocol.Tls.SecurityProtocolType.Tls;
86
87                 if (args.Length > 1) {
88                         for (int i=1; i < args.Length; i++) {
89                                 switch (args [i].ToLower ()) {
90                                 case "--ssl3":
91                                         ssl = true;\r
92                                         protocol = Mono.Security.Protocol.Tls.SecurityProtocolType.Ssl3;
93                                         break;\r
94                                 case "--tls":\r
95                                 case "--tls1":
96                                         ssl = true;\r
97                                         protocol = Mono.Security.Protocol.Tls.SecurityProtocolType.Tls;
98                                         break;
99                                 case "--web":
100                                         ssl = false;
101                                         break;
102                                 default:
103                                         size = Int32.Parse (args [i]);\r
104                                         break;\r
105                                 }\r
106                         }\r
107                 }\r
108 \r
109                 // prepare test buffer\r
110                 byte[] data = new byte[size];\r
111                 for (int i = 0; i < size; i++)\r
112                         data[i] = 65;
113
114                 string result = (ssl ? PostStream (protocol, url, data) : PostWeb (url, data));\r
115 \r
116                 if (data.Length != result.Length) {\r
117                         Console.WriteLine ("Invalid length {0}. Expected {1}", result.Length, data.Length);\r
118                         return 1;\r
119                 }\r
120                 for (int i = 0; i < result.Length; i++) {\r
121                         if (result[i] != 'A') {\r
122                                 Console.WriteLine ("Error at {0} - reveived {1}", i, result[i]);\r
123                                 return 1;\r
124                         }\r
125                 }\r
126                 Console.WriteLine ("Result OK (length: {0})", result.Length);\r
127                 return 0;\r
128         }
129
130         private static void ShowCertificateError (int error)\r
131         {\r
132                 string message = null;\r
133                 switch (error)\r
134                 {\r
135                         case -2146762490:\r
136                                 message = "CERT_E_PURPOSE 0x800B0106";\r
137                                 break;\r
138                         case -2146762481:\r
139                                 message = "CERT_E_CN_NO_MATCH 0x800B010F";\r
140                                 break;\r
141                         case -2146869223:\r
142                                 message = "TRUST_E_BASIC_CONSTRAINTS 0x80096019";\r
143                                 break;\r
144                         case -2146869232:\r
145                                 message = "TRUST_E_BAD_DIGEST 0x80096010";\r
146                                 break;\r
147                         case -2146762494:\r
148                                 message = "CERT_E_VALIDITYPERIODNESTING 0x800B0102";\r
149                                 break;\r
150                         case -2146762495:\r
151                                 message = "CERT_E_EXPIRED 0x800B0101";\r
152                                 break;\r
153                         case -2146762486:\r
154                                 message = "CERT_E_CHAINING 0x800B010A";\r
155                                 break;\r
156                         case -2146762487:\r
157                                 message = "CERT_E_UNTRUSTEDROOT 0x800B0109";\r
158                                 break;\r
159                         default:\r
160                                 message = "unknown (try WinError.h)";\r
161                                 break;\r
162                 }\r
163                 Console.WriteLine ("Error #{0}: {1}", error, message);\r
164         }\r
165 \r
166         private static bool CertificateValidation (X509Certificate certificate, int[] certificateErrors)\r
167         {\r
168                 if (certificateErrors.Length > 0)\r
169                 {\r
170                         Console.WriteLine (certificate.ToString (true));\r
171                         // X509Certificate.ToString(true) doesn't show dates :-(\r
172                         Console.WriteLine ("\tValid From:  {0}", certificate.GetEffectiveDateString ());\r
173                         Console.WriteLine ("\tValid Until: {0}{1}", certificate.GetExpirationDateString (), Environment.NewLine);\r
174                         // multiple errors are possible using SslClientStream\r
175                         foreach (int error in certificateErrors)\r
176                         {\r
177                                 ShowCertificateError (error);\r
178                         }\r
179                 }\r
180                 // whatever the reason we do not stop the SSL connection\r
181                 return true;\r
182         }\r
183 }
184