3 * Release $Name: MATRIXSSL_1_8_8_OPEN $
5 * Simple example program for MatrixSSL
6 * Sends a HTTPS request and echos the response back to the sender.
9 * Copyright (c) PeerSec Networks, 2002-2009. All Rights Reserved.
10 * The latest version of this code is available at http://www.matrixssl.org
12 * This software is open source; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This General Public License does NOT permit incorporating this software
18 * into proprietary programs. If you are unable to comply with the GPL, a
19 * commercial license for this software may be purchased from PeerSec Networks
20 * at http://www.peersec.com
22 * This program is distributed in WITHOUT ANY WARRANTY; without even the
23 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
24 * See the GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 * http://www.gnu.org/copyleft/gpl.html
31 /******************************************************************************/
39 /******************************************************************************/
41 #include "sslSocket.h"
43 /******************************************************************************/
45 #define HTTPS_PORT 4433
46 #define HTTPS_IP "127.0.0.1"
48 static char CAfile
[] = "CAcertSrv.pem";
51 #define ITERATIONS 100 /* How many individual connections to make */
52 #define REQUESTS 10 /* How many requests per each connection */
53 #define REUSE 0 /* 0 if session resumption disabled */
55 #define ENFORCE_CERT_VALIDATION 1 /* 0 to allow connection without validation */
58 static const char request
[] = "GET / HTTP/1.0\r\n"
59 "User-Agent: MatrixSSL httpClient\r\n"
63 static const char requestAgain
[] = "GET /again HTTP/1.0\r\n"
64 "User-Agent: MatrixSSL httpClient\r\n"
68 static const char quitString
[] = "GET /quit";
71 Callback that is registered to receive server certificate
72 information for custom validation
74 static int certChecker(sslCertInfo_t
*cert
, void *arg
);
76 /******************************************************************************/
78 Example ssl client that connects to a server and sends https messages
81 int _httpsClient(char *arg1
)
83 int WINAPI
WinMain (HINSTANCE hInstance
, HINSTANCE hPrevInstance
,
84 LPWSTR lpCmdLine
, int nCmdShow
)
86 int main(int argc
, char **argv
)
89 sslSessionId_t
*sessionId
;
95 unsigned char *ip
, *c
, *requestBuf
;
96 unsigned char buf
[1024];
97 int iterations
, requests
, connectAgain
, status
;
98 int quit
, rc
, bytes
, i
, j
, err
;
106 parseCmdLineArgs(arg1
, &argc
, &argv
);
115 * parseCmdLineArgs expects an ASCII string and CE is unicoded, so convert
116 * the command line. args will get hacked up, so you can't pass in a
119 WideCharToMultiByte(CP_ACP
, 0, lpCmdLine
, -1, args
, 256, NULL
, NULL
);
122 * Parse the command line into an argv array. This allocs memory, so
123 * we have to free argv when we're done.
125 parseCmdLineArgs(args
, &argc
, &argv
);
130 First (optional) argument is ip address to connect to (port is hardcoded)
131 Second (optional) argument is number of iterations to perform
132 Third (optional) argument is number of keepalive HTTP requests
133 Fourth (optional) argument is cipher suite number to use (0 for any)
136 iterations
= ITERATIONS
;
138 cipherSuite
= 0x0000;
142 iterations
= atoi(argv
[2]);
143 socketAssert(iterations
> 0);
145 requests
= atoi(argv
[3]);
146 socketAssert(requests
> 0);
148 cipherSuite
= (short)atoi(argv
[4]);
154 Initialize Windows sockets (no-op on other platforms)
156 WSAStartup(MAKEWORD(1,1), &wsaData
);
158 Initialize the MatrixSSL Library, and read in the certificate file
159 used to validate the server.
161 if (matrixSslOpen() < 0) {
162 fprintf(stderr
, "matrixSslOpen failed, exiting...");
165 if (matrixSslReadKeys(&keys
, NULL
, NULL
, NULL
, CAfile
) < 0) {
169 Intialize loop control variables
175 Just reuse the requestBuf and malloc to largest possible message size
177 requestBuf
= malloc(sizeof(requestAgain
));
182 while (!quit
&& (i
< iterations
)) {
184 sslConnect uses port and ip address to connect to SSL server.
185 Generates a new session
188 if ((fd
= socketConnect(ip
, HTTPS_PORT
, &err
)) == INVALID_SOCKET
) {
189 fprintf(stdout
, "Error connecting to server %s:%d\n", ip
, HTTPS_PORT
);
190 matrixSslFreeKeys(keys
);
193 if (sslConnect(&conn
, fd
, keys
, sessionId
, cipherSuite
, certChecker
) < 0) {
196 fprintf(stderr
, "Error connecting to %s:%d\n", ip
, HTTPS_PORT
);
208 Copy the HTTP request header into the buffer, based of whether or
209 not we want httpReflector to keep the socket open or not
212 bytes
= (int)strlen(request
);
213 memcpy(requestBuf
, request
, bytes
);
215 bytes
= (int)strlen(requestAgain
);
216 memcpy(requestBuf
, requestAgain
, bytes
);
220 < 0 return indicates an error.
221 0 return indicates not all data was sent and we must retry
222 > 0 indicates that all requested bytes were sent
225 rc
= sslWrite(conn
, requestBuf
, bytes
, &status
);
227 fprintf(stdout
, "Internal sslWrite error\n");
228 socketShutdown(conn
->fd
);
229 sslFreeConnection(&conn
);
231 } else if (rc
== 0) {
236 < 0 return indicates an error.
237 0 return indicates an EOF or CLOSE_NOTIFY in this situation
238 > 0 indicates that some bytes were read. Keep reading until we see
239 the /r/n/r/n from the response header. There may be data following
240 this header, but we don't try too hard to read it for this example.
244 if ((rc
= sslRead(conn
, c
, sizeof(buf
) - (int)(c
- buf
), &status
)) > 0) {
246 if (c
- buf
< 4 || memcmp(c
- 4, "\r\n\r\n", 4) != 0) {
251 fprintf(stdout
, "sslRead error. dropping connection.\n");
253 if (rc
< 0 || status
== SSLSOCKET_EOF
||
254 status
== SSLSOCKET_CLOSE_NOTIFY
) {
255 socketShutdown(conn
->fd
);
256 sslFreeConnection(&conn
);
262 Determine if we want to do a pipelined HTTP request/response
264 if (j
++ < requests
) {
265 fprintf(stdout
, "R");
269 fprintf(stdout
, "C");
273 Reuse the session. Comment out these two lines to test the entire
274 public key renegotiation each iteration
277 matrixSslFreeSessionId(sessionId
);
278 matrixSslGetSessionId(conn
->ssl
, &sessionId
);
280 This example shows how a user might want to limit a client to
281 resuming handshakes only with authenticated servers. In this
282 example, the client will force any non-authenticated (anonymous)
283 server to go through a complete handshake each time. This is
284 strictly an example of one policy decision an implementation
287 matrixSslGetAnonStatus(conn
->ssl
, &anonStatus
);
289 matrixSslFreeSessionId(sessionId
);
294 Send a closure alert for clean shutdown of remote SSL connection
295 This is for good form, some implementations just close the socket
297 sslWriteClosureAlert(conn
);
299 Session done. Connect again if more iterations remaining
301 socketShutdown(conn
->fd
);
302 sslFreeConnection(&conn
);
308 matrixSslFreeSessionId(sessionId
);
309 if (conn
&& conn
->ssl
) {
310 socketShutdown(conn
->fd
);
311 sslFreeConnection(&conn
);
313 fprintf(stdout
, "\n%d connections in %d seconds (%f c/s)\n",
314 i
, (int)(t1
- t0
), (double)i
/ (t1
- t0
));
315 fprintf(stdout
, "\n%d requests in %d seconds (%f r/s)\n",
316 i
* requests
, (int)(t1
- t0
),
317 (double)(i
* requests
) / (t1
- t0
));
319 Close listening socket, free remaining items
321 matrixSslFreeKeys(keys
);
325 fprintf(stdout
, "Press return to exit...\n");
336 /******************************************************************************/
338 Stub for a user-level certificate validator. Just using
339 the default validation value here.
341 static int certChecker(sslCertInfo_t
*cert
, void *arg
)
346 Make sure we are checking the last cert in the chain
350 while (next
->next
!= NULL
) {
353 #if ENFORCE_CERT_VALIDATION
355 This case passes the true RSA authentication status through
357 return next
->verified
;
360 This case passes an authenticated server through, but flags a
361 non-authenticated server correctly. The user can call the
362 matrixSslGetAnonStatus later to see the status of this connection.
364 if (next
->verified
!= 1) {
365 return SSL_ALLOW_ANON_CONNECTION
;
367 return next
->verified
;
368 #endif /* ENFORCE_CERT_VALIDATION */
371 /******************************************************************************/