1
/* ***** BEGIN LICENSE BLOCK *****
2
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
4
* The contents of this file are subject to the Mozilla Public License Version
5
* 1.1 (the "License"); you may not use this file except in compliance with
6
* the License. You may obtain a copy of the License at
7
* http://www.mozilla.org/MPL/
9
* Software distributed under the License is distributed on an "AS IS" basis,
10
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11
* for the specific language governing rights and limitations under the
14
* The Original Code is the Netscape security libraries.
16
* The Initial Developer of the Original Code is
17
* Netscape Communications Corporation.
18
* Portions created by the Initial Developer are Copyright (C) 1994-2000
19
* the Initial Developer. All Rights Reserved.
23
* Alternatively, the contents of this file may be used under the terms of
24
* either the GNU General Public License Version 2 or later (the "GPL"), or
25
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26
* in which case the provisions of the GPL or the LGPL are applicable instead
27
* of those above. If you wish to allow use of your version of this file only
28
* under the terms of either the GPL or the LGPL, and not to allow others to
29
* use your version of this file under the terms of the MPL, indicate your
30
* decision by deleting the provisions above and replace them with the notice
31
* and other provisions required by the GPL or the LGPL. If you do not delete
32
* the provisions above, a recipient may use your version of this file under
33
* the terms of any one of the MPL, the GPL or the LGPL.
35
* ***** END LICENSE BLOCK ***** */
37
/****************************************************************************
38
* SSL client program that sets up a connection to SSL server, transmits *
39
* some data and then reads the reply *
40
****************************************************************************/
66
#include "sslsample.h"
68
#define RD_BUF_SIZE (60 * 1024)
70
extern int ssl2CipherSuites[];
71
extern int ssl3CipherSuites[];
73
GlobalThreadMgr threadMGR;
74
char *certNickname = NULL;
75
char *hostName = NULL;
76
char *password = NULL;
77
unsigned short port = 0;
80
Usage(const char *progName)
83
"Usage: %s [-n rsa_nickname] [-p port] [-d dbdir] [-c connections]\n"
84
" [-w dbpasswd] [-C cipher(s)] hostname\n",
90
setupSSLSocket(PRNetAddr *addr)
92
PRFileDesc *tcpSocket;
93
PRFileDesc *sslSocket;
94
PRSocketOptionData socketOption;
102
tcpSocket = PR_NewTCPSocket();
103
if (tcpSocket == NULL) {
104
errWarn("PR_NewTCPSocket");
107
/* Make the socket blocking. */
108
socketOption.option = PR_SockOpt_Nonblocking;
109
socketOption.value.non_blocking = PR_FALSE;
111
prStatus = PR_SetSocketOption(tcpSocket, &socketOption);
112
if (prStatus != PR_SUCCESS) {
113
errWarn("PR_SetSocketOption");
118
/* Verify that a connection can be made to the socket. */
119
prStatus = PR_Connect(tcpSocket, addr, PR_INTERVAL_NO_TIMEOUT);
120
if (prStatus != PR_SUCCESS) {
121
PRErrorCode err = PR_GetError();
122
if (err == PR_CONNECT_REFUSED_ERROR) {
124
PR_Sleep(PR_MillisecondsToInterval(10));
125
fprintf(stderr, "Connection to port refused, retrying.\n");
128
errWarn("PR_Connect");
133
/* Import the socket into the SSL layer. */
134
sslSocket = SSL_ImportFD(NULL, tcpSocket);
136
errWarn("SSL_ImportFD");
140
/* Set configuration options. */
141
secStatus = SSL_OptionSet(sslSocket, SSL_SECURITY, PR_TRUE);
142
if (secStatus != SECSuccess) {
143
errWarn("SSL_OptionSet:SSL_SECURITY");
147
secStatus = SSL_OptionSet(sslSocket, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE);
148
if (secStatus != SECSuccess) {
149
errWarn("SSL_OptionSet:SSL_HANDSHAKE_AS_CLIENT");
153
/* Set SSL callback routines. */
154
secStatus = SSL_GetClientAuthDataHook(sslSocket,
155
(SSLGetClientAuthData)myGetClientAuthData,
156
(void *)certNickname);
157
if (secStatus != SECSuccess) {
158
errWarn("SSL_GetClientAuthDataHook");
162
secStatus = SSL_AuthCertificateHook(sslSocket,
163
(SSLAuthCertificate)myAuthCertificate,
164
(void *)CERT_GetDefaultCertDB());
165
if (secStatus != SECSuccess) {
166
errWarn("SSL_AuthCertificateHook");
170
secStatus = SSL_BadCertHook(sslSocket,
171
(SSLBadCertHandler)myBadCertHandler, NULL);
172
if (secStatus != SECSuccess) {
173
errWarn("SSL_BadCertHook");
177
secStatus = SSL_HandshakeCallback(sslSocket,
180
if (secStatus != SECSuccess) {
181
errWarn("SSL_HandshakeCallback");
194
const char requestString[] = {"GET /testfile HTTP/1.0\r\n\r\n" };
197
handle_connection(PRFileDesc *sslSocket, int connection)
203
readBuffer = PORT_Alloc(RD_BUF_SIZE);
205
exitErr("PORT_Alloc");
208
/* compose the http request here. */
210
numBytes = PR_Write(sslSocket, requestString, strlen(requestString));
220
numBytes = PR_Read(sslSocket, readBuffer, RD_BUF_SIZE);
228
countRead += numBytes;
229
fprintf(stderr, "***** Connection %d read %d bytes (%d total).\n",
230
connection, numBytes, countRead );
231
readBuffer[numBytes] = '\0';
232
fprintf(stderr, "************\n%s\n************\n", readBuffer);
235
printSecurityInfo(sslSocket);
240
/* Caller closes the socket. */
243
"***** Connection %d read %d bytes total.\n",
244
connection, countRead);
246
return SECSuccess; /* success */
249
/* one copy of this function is launched in a separate thread for each
250
** connection to be made.
253
do_connects(void *a, int connection)
255
PRNetAddr *addr = (PRNetAddr *)a;
256
PRFileDesc *sslSocket;
258
char buffer[PR_NETDB_BUF_SIZE];
263
/* Set up SSL secure socket. */
264
sslSocket = setupSSLSocket(addr);
265
if (sslSocket == NULL) {
266
errWarn("setupSSLSocket");
270
secStatus = SSL_SetPKCS11PinArg(sslSocket, password);
271
if (secStatus != SECSuccess) {
272
errWarn("SSL_SetPKCS11PinArg");
276
secStatus = SSL_SetURL(sslSocket, hostName);
277
if (secStatus != SECSuccess) {
278
errWarn("SSL_SetURL");
282
/* Prepare and setup network connection. */
283
prStatus = PR_GetHostByName(hostName, buffer, sizeof(buffer), &hostEntry);
284
if (prStatus != PR_SUCCESS) {
285
errWarn("PR_GetHostByName");
289
hostenum = PR_EnumerateHostEnt(0, &hostEntry, port, addr);
290
if (hostenum == -1) {
291
errWarn("PR_EnumerateHostEnt");
295
prStatus = PR_Connect(sslSocket, addr, PR_INTERVAL_NO_TIMEOUT);
296
if (prStatus != PR_SUCCESS) {
297
errWarn("PR_Connect");
301
/* Established SSL connection, ready to send data. */
303
secStatus = SSL_ForceHandshake(sslSocket);
304
if (secStatus != SECSuccess) {
305
errWarn("SSL_ForceHandshake");
310
secStatus = SSL_ResetHandshake(sslSocket, /* asServer */ PR_FALSE);
311
if (secStatus != SECSuccess) {
312
errWarn("SSL_ResetHandshake");
313
prStatus = PR_Close(sslSocket);
314
if (prStatus != PR_SUCCESS) {
320
secStatus = handle_connection(sslSocket, connection);
321
if (secStatus != SECSuccess) {
322
errWarn("handle_connection");
331
client_main(unsigned short port,
333
const char * hostName)
343
/* Setup network connection. */
344
prStatus = PR_GetHostByName(hostName, buffer, 256, &hostEntry);
345
if (prStatus != PR_SUCCESS) {
346
exitErr("PR_GetHostByName");
349
rv = PR_EnumerateHostEnt(0, &hostEntry, port, &addr);
351
exitErr("PR_EnumerateHostEnt");
354
secStatus = launch_thread(&threadMGR, do_connects, &addr, 1);
355
if (secStatus != SECSuccess) {
356
exitErr("launch_thread");
359
if (connections > 1) {
360
/* wait for the first connection to terminate, then launch the rest. */
361
reap_threads(&threadMGR);
362
/* Start up the connections */
363
for (i = 2; i <= connections; ++i) {
364
secStatus = launch_thread(&threadMGR, do_connects, &addr, i);
365
if (secStatus != SECSuccess) {
366
errWarn("launch_thread");
371
reap_threads(&threadMGR);
372
destroy_thread_data(&threadMGR);
376
main(int argc, char **argv)
378
char * certDir = ".";
379
char * progName = NULL;
381
char * cipherString = NULL;
383
PLOptState * optstate;
386
/* Call the NSPR initialization routines */
387
PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
389
progName = PL_strdup(argv[0]);
392
optstate = PL_CreateOptState(argc, argv, "C:c:d:n:p:w:");
393
while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
394
switch(optstate->option) {
395
case 'C' : cipherString = PL_strdup(optstate->value); break;
396
case 'c' : connections = PORT_Atoi(optstate->value); break;
397
case 'd' : certDir = PL_strdup(optstate->value); break;
398
case 'n' : certNickname = PL_strdup(optstate->value); break;
399
case 'p' : port = PORT_Atoi(optstate->value); break;
400
case 'w' : password = PL_strdup(optstate->value); break;
401
case '\0': hostName = PL_strdup(optstate->value); break;
402
default : Usage(progName);
406
if (port == 0 || hostName == NULL)
409
if (certDir == NULL) {
410
certDir = PR_smprintf("%s/.netscape", getenv("HOME"));
413
/* Set our password function callback. */
414
PK11_SetPasswordFunc(myPasswd);
416
/* Initialize the NSS libraries. */
417
secStatus = NSS_Init(certDir);
418
if (secStatus != SECSuccess) {
422
/* All cipher suites except RSA_NULL_MD5 are enabled by Domestic Policy. */
423
NSS_SetDomesticPolicy();
424
SSL_CipherPrefSetDefault(SSL_RSA_WITH_NULL_MD5, PR_TRUE);
426
/* all the SSL2 and SSL3 cipher suites are enabled by default. */
430
/* disable all the ciphers, then enable the ones we want. */
431
disableAllSSLCiphers();
433
while (0 != (ndx = *cipherString++)) {
439
cptr = islower(ndx) ? ssl3CipherSuites : ssl2CipherSuites;
440
for (ndx &= 0x1f; (cipher = *cptr++) != 0 && --ndx > 0; )
443
SSL_CipherPrefSetDefault(cipher, PR_TRUE);
448
client_main(port, connections, hostName);
450
if (NSS_Shutdown() != SECSuccess) {