Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | /**************************************************************************** |
michael@0 | 6 | * SSL client program that tests a server for proper operation of SSL2, * |
michael@0 | 7 | * SSL3, and TLS. Test propder certificate installation. * |
michael@0 | 8 | * * |
michael@0 | 9 | * This code was modified from the SSLSample code also kept in the NSS * |
michael@0 | 10 | * directory. * |
michael@0 | 11 | ****************************************************************************/ |
michael@0 | 12 | |
michael@0 | 13 | #include <stdio.h> |
michael@0 | 14 | #include <string.h> |
michael@0 | 15 | |
michael@0 | 16 | #if defined(XP_UNIX) |
michael@0 | 17 | #include <unistd.h> |
michael@0 | 18 | #endif |
michael@0 | 19 | |
michael@0 | 20 | #include "prerror.h" |
michael@0 | 21 | |
michael@0 | 22 | #include "pk11func.h" |
michael@0 | 23 | #include "secmod.h" |
michael@0 | 24 | #include "secitem.h" |
michael@0 | 25 | |
michael@0 | 26 | |
michael@0 | 27 | #include <stdlib.h> |
michael@0 | 28 | #include <errno.h> |
michael@0 | 29 | #include <fcntl.h> |
michael@0 | 30 | #include <stdarg.h> |
michael@0 | 31 | |
michael@0 | 32 | #include "nspr.h" |
michael@0 | 33 | #include "plgetopt.h" |
michael@0 | 34 | #include "prio.h" |
michael@0 | 35 | #include "prnetdb.h" |
michael@0 | 36 | #include "nss.h" |
michael@0 | 37 | #include "secutil.h" |
michael@0 | 38 | #include "ocsp.h" |
michael@0 | 39 | |
michael@0 | 40 | #include "vfyserv.h" |
michael@0 | 41 | |
michael@0 | 42 | #define RD_BUF_SIZE (60 * 1024) |
michael@0 | 43 | |
michael@0 | 44 | extern int ssl2CipherSuites[]; |
michael@0 | 45 | extern int ssl3CipherSuites[]; |
michael@0 | 46 | |
michael@0 | 47 | GlobalThreadMgr threadMGR; |
michael@0 | 48 | char *certNickname = NULL; |
michael@0 | 49 | char *hostName = NULL; |
michael@0 | 50 | secuPWData pwdata = { PW_NONE, 0 }; |
michael@0 | 51 | unsigned short port = 0; |
michael@0 | 52 | PRBool dumpChain; |
michael@0 | 53 | |
michael@0 | 54 | static void |
michael@0 | 55 | Usage(const char *progName) |
michael@0 | 56 | { |
michael@0 | 57 | PRFileDesc *pr_stderr; |
michael@0 | 58 | |
michael@0 | 59 | pr_stderr = PR_STDERR; |
michael@0 | 60 | |
michael@0 | 61 | PR_fprintf(pr_stderr, "Usage:\n" |
michael@0 | 62 | " %s [-c ] [-o] [-p port] [-d dbdir] [-w password] [-f pwfile]\n" |
michael@0 | 63 | " \t\t[-C cipher(s)] [-l <url> -t <nickname> ] hostname", |
michael@0 | 64 | progName); |
michael@0 | 65 | PR_fprintf (pr_stderr, "\nWhere:\n"); |
michael@0 | 66 | PR_fprintf (pr_stderr, |
michael@0 | 67 | " %-13s dump server cert chain into files\n", |
michael@0 | 68 | "-c"); |
michael@0 | 69 | PR_fprintf (pr_stderr, |
michael@0 | 70 | " %-13s perform server cert OCSP check\n", |
michael@0 | 71 | "-o"); |
michael@0 | 72 | PR_fprintf (pr_stderr, |
michael@0 | 73 | " %-13s server port to be used\n", |
michael@0 | 74 | "-p"); |
michael@0 | 75 | PR_fprintf (pr_stderr, |
michael@0 | 76 | " %-13s use security databases in \"dbdir\"\n", |
michael@0 | 77 | "-d dbdir"); |
michael@0 | 78 | PR_fprintf (pr_stderr, |
michael@0 | 79 | " %-13s key database password\n", |
michael@0 | 80 | "-w password"); |
michael@0 | 81 | PR_fprintf (pr_stderr, |
michael@0 | 82 | " %-13s token password file\n", |
michael@0 | 83 | "-f pwfile"); |
michael@0 | 84 | PR_fprintf (pr_stderr, |
michael@0 | 85 | " %-13s communication cipher list\n", |
michael@0 | 86 | "-C cipher(s)"); |
michael@0 | 87 | PR_fprintf (pr_stderr, |
michael@0 | 88 | " %-13s OCSP responder location. This location is used to\n" |
michael@0 | 89 | " %-13s check status of a server certificate. If not \n" |
michael@0 | 90 | " %-13s specified, location will be taken from the AIA\n" |
michael@0 | 91 | " %-13s server certificate extension.\n", |
michael@0 | 92 | "-l url", "", "", ""); |
michael@0 | 93 | PR_fprintf (pr_stderr, |
michael@0 | 94 | " %-13s OCSP Trusted Responder Cert nickname\n\n", |
michael@0 | 95 | "-t nickname"); |
michael@0 | 96 | |
michael@0 | 97 | exit(1); |
michael@0 | 98 | } |
michael@0 | 99 | |
michael@0 | 100 | PRFileDesc * |
michael@0 | 101 | setupSSLSocket(PRNetAddr *addr) |
michael@0 | 102 | { |
michael@0 | 103 | PRFileDesc *tcpSocket; |
michael@0 | 104 | PRFileDesc *sslSocket; |
michael@0 | 105 | PRSocketOptionData socketOption; |
michael@0 | 106 | PRStatus prStatus; |
michael@0 | 107 | SECStatus secStatus; |
michael@0 | 108 | |
michael@0 | 109 | |
michael@0 | 110 | tcpSocket = PR_NewTCPSocket(); |
michael@0 | 111 | if (tcpSocket == NULL) { |
michael@0 | 112 | errWarn("PR_NewTCPSocket"); |
michael@0 | 113 | } |
michael@0 | 114 | |
michael@0 | 115 | /* Make the socket blocking. */ |
michael@0 | 116 | socketOption.option = PR_SockOpt_Nonblocking; |
michael@0 | 117 | socketOption.value.non_blocking = PR_FALSE; |
michael@0 | 118 | |
michael@0 | 119 | prStatus = PR_SetSocketOption(tcpSocket, &socketOption); |
michael@0 | 120 | if (prStatus != PR_SUCCESS) { |
michael@0 | 121 | errWarn("PR_SetSocketOption"); |
michael@0 | 122 | goto loser; |
michael@0 | 123 | } |
michael@0 | 124 | |
michael@0 | 125 | |
michael@0 | 126 | /* Import the socket into the SSL layer. */ |
michael@0 | 127 | sslSocket = SSL_ImportFD(NULL, tcpSocket); |
michael@0 | 128 | if (!sslSocket) { |
michael@0 | 129 | errWarn("SSL_ImportFD"); |
michael@0 | 130 | goto loser; |
michael@0 | 131 | } |
michael@0 | 132 | |
michael@0 | 133 | /* Set configuration options. */ |
michael@0 | 134 | secStatus = SSL_OptionSet(sslSocket, SSL_SECURITY, PR_TRUE); |
michael@0 | 135 | if (secStatus != SECSuccess) { |
michael@0 | 136 | errWarn("SSL_OptionSet:SSL_SECURITY"); |
michael@0 | 137 | goto loser; |
michael@0 | 138 | } |
michael@0 | 139 | |
michael@0 | 140 | secStatus = SSL_OptionSet(sslSocket, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); |
michael@0 | 141 | if (secStatus != SECSuccess) { |
michael@0 | 142 | errWarn("SSL_OptionSet:SSL_HANDSHAKE_AS_CLIENT"); |
michael@0 | 143 | goto loser; |
michael@0 | 144 | } |
michael@0 | 145 | |
michael@0 | 146 | /* Set SSL callback routines. */ |
michael@0 | 147 | secStatus = SSL_GetClientAuthDataHook(sslSocket, |
michael@0 | 148 | (SSLGetClientAuthData)myGetClientAuthData, |
michael@0 | 149 | (void *)certNickname); |
michael@0 | 150 | if (secStatus != SECSuccess) { |
michael@0 | 151 | errWarn("SSL_GetClientAuthDataHook"); |
michael@0 | 152 | goto loser; |
michael@0 | 153 | } |
michael@0 | 154 | |
michael@0 | 155 | secStatus = SSL_AuthCertificateHook(sslSocket, |
michael@0 | 156 | (SSLAuthCertificate)myAuthCertificate, |
michael@0 | 157 | (void *)CERT_GetDefaultCertDB()); |
michael@0 | 158 | if (secStatus != SECSuccess) { |
michael@0 | 159 | errWarn("SSL_AuthCertificateHook"); |
michael@0 | 160 | goto loser; |
michael@0 | 161 | } |
michael@0 | 162 | |
michael@0 | 163 | secStatus = SSL_BadCertHook(sslSocket, |
michael@0 | 164 | (SSLBadCertHandler)myBadCertHandler, NULL); |
michael@0 | 165 | if (secStatus != SECSuccess) { |
michael@0 | 166 | errWarn("SSL_BadCertHook"); |
michael@0 | 167 | goto loser; |
michael@0 | 168 | } |
michael@0 | 169 | |
michael@0 | 170 | secStatus = SSL_HandshakeCallback(sslSocket, |
michael@0 | 171 | myHandshakeCallback, |
michael@0 | 172 | NULL); |
michael@0 | 173 | if (secStatus != SECSuccess) { |
michael@0 | 174 | errWarn("SSL_HandshakeCallback"); |
michael@0 | 175 | goto loser; |
michael@0 | 176 | } |
michael@0 | 177 | |
michael@0 | 178 | return sslSocket; |
michael@0 | 179 | |
michael@0 | 180 | loser: |
michael@0 | 181 | |
michael@0 | 182 | PR_Close(tcpSocket); |
michael@0 | 183 | return NULL; |
michael@0 | 184 | } |
michael@0 | 185 | |
michael@0 | 186 | |
michael@0 | 187 | const char requestString[] = {"GET /testfile HTTP/1.0\r\n\r\n" }; |
michael@0 | 188 | |
michael@0 | 189 | SECStatus |
michael@0 | 190 | handle_connection(PRFileDesc *sslSocket, int connection) |
michael@0 | 191 | { |
michael@0 | 192 | int countRead = 0; |
michael@0 | 193 | PRInt32 numBytes; |
michael@0 | 194 | char *readBuffer; |
michael@0 | 195 | |
michael@0 | 196 | readBuffer = PORT_Alloc(RD_BUF_SIZE); |
michael@0 | 197 | if (!readBuffer) { |
michael@0 | 198 | exitErr("PORT_Alloc"); |
michael@0 | 199 | } |
michael@0 | 200 | |
michael@0 | 201 | /* compose the http request here. */ |
michael@0 | 202 | |
michael@0 | 203 | numBytes = PR_Write(sslSocket, requestString, strlen(requestString)); |
michael@0 | 204 | if (numBytes <= 0) { |
michael@0 | 205 | errWarn("PR_Write"); |
michael@0 | 206 | PR_Free(readBuffer); |
michael@0 | 207 | readBuffer = NULL; |
michael@0 | 208 | return SECFailure; |
michael@0 | 209 | } |
michael@0 | 210 | |
michael@0 | 211 | /* read until EOF */ |
michael@0 | 212 | while (PR_TRUE) { |
michael@0 | 213 | numBytes = PR_Read(sslSocket, readBuffer, RD_BUF_SIZE); |
michael@0 | 214 | if (numBytes == 0) { |
michael@0 | 215 | break; /* EOF */ |
michael@0 | 216 | } |
michael@0 | 217 | if (numBytes < 0) { |
michael@0 | 218 | errWarn("PR_Read"); |
michael@0 | 219 | break; |
michael@0 | 220 | } |
michael@0 | 221 | countRead += numBytes; |
michael@0 | 222 | } |
michael@0 | 223 | |
michael@0 | 224 | printSecurityInfo(stderr, sslSocket); |
michael@0 | 225 | |
michael@0 | 226 | PR_Free(readBuffer); |
michael@0 | 227 | readBuffer = NULL; |
michael@0 | 228 | |
michael@0 | 229 | /* Caller closes the socket. */ |
michael@0 | 230 | |
michael@0 | 231 | fprintf(stderr, |
michael@0 | 232 | "***** Connection %d read %d bytes total.\n", |
michael@0 | 233 | connection, countRead); |
michael@0 | 234 | |
michael@0 | 235 | return SECSuccess; /* success */ |
michael@0 | 236 | } |
michael@0 | 237 | |
michael@0 | 238 | #define BYTE(n,i) (((i)>>((n)*8))&0xff) |
michael@0 | 239 | |
michael@0 | 240 | /* one copy of this function is launched in a separate thread for each |
michael@0 | 241 | ** connection to be made. |
michael@0 | 242 | */ |
michael@0 | 243 | SECStatus |
michael@0 | 244 | do_connects(void *a, int connection) |
michael@0 | 245 | { |
michael@0 | 246 | PRNetAddr *addr = (PRNetAddr *)a; |
michael@0 | 247 | PRFileDesc *sslSocket; |
michael@0 | 248 | PRHostEnt hostEntry; |
michael@0 | 249 | char buffer[PR_NETDB_BUF_SIZE]; |
michael@0 | 250 | PRStatus prStatus; |
michael@0 | 251 | PRIntn hostenum; |
michael@0 | 252 | PRInt32 ip; |
michael@0 | 253 | SECStatus secStatus; |
michael@0 | 254 | |
michael@0 | 255 | /* Set up SSL secure socket. */ |
michael@0 | 256 | sslSocket = setupSSLSocket(addr); |
michael@0 | 257 | if (sslSocket == NULL) { |
michael@0 | 258 | errWarn("setupSSLSocket"); |
michael@0 | 259 | return SECFailure; |
michael@0 | 260 | } |
michael@0 | 261 | |
michael@0 | 262 | secStatus = SSL_SetPKCS11PinArg(sslSocket, &pwdata); |
michael@0 | 263 | if (secStatus != SECSuccess) { |
michael@0 | 264 | errWarn("SSL_SetPKCS11PinArg"); |
michael@0 | 265 | return secStatus; |
michael@0 | 266 | } |
michael@0 | 267 | |
michael@0 | 268 | secStatus = SSL_SetURL(sslSocket, hostName); |
michael@0 | 269 | if (secStatus != SECSuccess) { |
michael@0 | 270 | errWarn("SSL_SetURL"); |
michael@0 | 271 | return secStatus; |
michael@0 | 272 | } |
michael@0 | 273 | |
michael@0 | 274 | /* Prepare and setup network connection. */ |
michael@0 | 275 | prStatus = PR_GetHostByName(hostName, buffer, sizeof(buffer), &hostEntry); |
michael@0 | 276 | if (prStatus != PR_SUCCESS) { |
michael@0 | 277 | errWarn("PR_GetHostByName"); |
michael@0 | 278 | return SECFailure; |
michael@0 | 279 | } |
michael@0 | 280 | |
michael@0 | 281 | hostenum = PR_EnumerateHostEnt(0, &hostEntry, port, addr); |
michael@0 | 282 | if (hostenum == -1) { |
michael@0 | 283 | errWarn("PR_EnumerateHostEnt"); |
michael@0 | 284 | return SECFailure; |
michael@0 | 285 | } |
michael@0 | 286 | |
michael@0 | 287 | ip = PR_ntohl(addr->inet.ip); |
michael@0 | 288 | fprintf(stderr, |
michael@0 | 289 | "Connecting to host %s (addr %d.%d.%d.%d) on port %d\n", |
michael@0 | 290 | hostName, BYTE(3,ip), BYTE(2,ip), BYTE(1,ip), |
michael@0 | 291 | BYTE(0,ip), PR_ntohs(addr->inet.port)); |
michael@0 | 292 | |
michael@0 | 293 | prStatus = PR_Connect(sslSocket, addr, PR_INTERVAL_NO_TIMEOUT); |
michael@0 | 294 | if (prStatus != PR_SUCCESS) { |
michael@0 | 295 | errWarn("PR_Connect"); |
michael@0 | 296 | return SECFailure; |
michael@0 | 297 | } |
michael@0 | 298 | |
michael@0 | 299 | /* Established SSL connection, ready to send data. */ |
michael@0 | 300 | #if 0 |
michael@0 | 301 | secStatus = SSL_ForceHandshake(sslSocket); |
michael@0 | 302 | if (secStatus != SECSuccess) { |
michael@0 | 303 | errWarn("SSL_ForceHandshake"); |
michael@0 | 304 | return secStatus; |
michael@0 | 305 | } |
michael@0 | 306 | #endif |
michael@0 | 307 | |
michael@0 | 308 | secStatus = SSL_ResetHandshake(sslSocket, /* asServer */ PR_FALSE); |
michael@0 | 309 | if (secStatus != SECSuccess) { |
michael@0 | 310 | errWarn("SSL_ResetHandshake"); |
michael@0 | 311 | prStatus = PR_Close(sslSocket); |
michael@0 | 312 | if (prStatus != PR_SUCCESS) { |
michael@0 | 313 | errWarn("PR_Close"); |
michael@0 | 314 | } |
michael@0 | 315 | return secStatus; |
michael@0 | 316 | } |
michael@0 | 317 | |
michael@0 | 318 | secStatus = handle_connection(sslSocket, connection); |
michael@0 | 319 | if (secStatus != SECSuccess) { |
michael@0 | 320 | /* error already printed out in handle_connection */ |
michael@0 | 321 | /* errWarn("handle_connection"); */ |
michael@0 | 322 | prStatus = PR_Close(sslSocket); |
michael@0 | 323 | if (prStatus != PR_SUCCESS) { |
michael@0 | 324 | errWarn("PR_Close"); |
michael@0 | 325 | } |
michael@0 | 326 | return secStatus; |
michael@0 | 327 | } |
michael@0 | 328 | |
michael@0 | 329 | PR_Close(sslSocket); |
michael@0 | 330 | return SECSuccess; |
michael@0 | 331 | } |
michael@0 | 332 | |
michael@0 | 333 | void |
michael@0 | 334 | client_main(unsigned short port, |
michael@0 | 335 | int connections, |
michael@0 | 336 | const char * hostName) |
michael@0 | 337 | { |
michael@0 | 338 | int i; |
michael@0 | 339 | SECStatus secStatus; |
michael@0 | 340 | PRStatus prStatus; |
michael@0 | 341 | PRInt32 rv; |
michael@0 | 342 | PRNetAddr addr; |
michael@0 | 343 | PRHostEnt hostEntry; |
michael@0 | 344 | char buffer[PR_NETDB_BUF_SIZE]; |
michael@0 | 345 | |
michael@0 | 346 | /* Setup network connection. */ |
michael@0 | 347 | prStatus = PR_GetHostByName(hostName, buffer, sizeof(buffer), &hostEntry); |
michael@0 | 348 | if (prStatus != PR_SUCCESS) { |
michael@0 | 349 | exitErr("PR_GetHostByName"); |
michael@0 | 350 | } |
michael@0 | 351 | |
michael@0 | 352 | rv = PR_EnumerateHostEnt(0, &hostEntry, port, &addr); |
michael@0 | 353 | if (rv < 0) { |
michael@0 | 354 | exitErr("PR_EnumerateHostEnt"); |
michael@0 | 355 | } |
michael@0 | 356 | |
michael@0 | 357 | secStatus = launch_thread(&threadMGR, do_connects, &addr, 1); |
michael@0 | 358 | if (secStatus != SECSuccess) { |
michael@0 | 359 | exitErr("launch_thread"); |
michael@0 | 360 | } |
michael@0 | 361 | |
michael@0 | 362 | if (connections > 1) { |
michael@0 | 363 | /* wait for the first connection to terminate, then launch the rest. */ |
michael@0 | 364 | reap_threads(&threadMGR); |
michael@0 | 365 | /* Start up the connections */ |
michael@0 | 366 | for (i = 2; i <= connections; ++i) { |
michael@0 | 367 | secStatus = launch_thread(&threadMGR, do_connects, &addr, i); |
michael@0 | 368 | if (secStatus != SECSuccess) { |
michael@0 | 369 | errWarn("launch_thread"); |
michael@0 | 370 | } |
michael@0 | 371 | } |
michael@0 | 372 | } |
michael@0 | 373 | |
michael@0 | 374 | reap_threads(&threadMGR); |
michael@0 | 375 | destroy_thread_data(&threadMGR); |
michael@0 | 376 | } |
michael@0 | 377 | |
michael@0 | 378 | #define HEXCHAR_TO_INT(c, i) \ |
michael@0 | 379 | if (((c) >= '0') && ((c) <= '9')) { \ |
michael@0 | 380 | i = (c) - '0'; \ |
michael@0 | 381 | } else if (((c) >= 'a') && ((c) <= 'f')) { \ |
michael@0 | 382 | i = (c) - 'a' + 10; \ |
michael@0 | 383 | } else if (((c) >= 'A') && ((c) <= 'F')) { \ |
michael@0 | 384 | i = (c) - 'A' + 10; \ |
michael@0 | 385 | } else { \ |
michael@0 | 386 | Usage(progName); \ |
michael@0 | 387 | } |
michael@0 | 388 | |
michael@0 | 389 | int |
michael@0 | 390 | main(int argc, char **argv) |
michael@0 | 391 | { |
michael@0 | 392 | char * certDir = NULL; |
michael@0 | 393 | char * progName = NULL; |
michael@0 | 394 | int connections = 1; |
michael@0 | 395 | char * cipherString = NULL; |
michael@0 | 396 | char * respUrl = NULL; |
michael@0 | 397 | char * respCertName = NULL; |
michael@0 | 398 | SECStatus secStatus; |
michael@0 | 399 | PLOptState * optstate; |
michael@0 | 400 | PLOptStatus status; |
michael@0 | 401 | PRBool doOcspCheck = PR_FALSE; |
michael@0 | 402 | |
michael@0 | 403 | /* Call the NSPR initialization routines */ |
michael@0 | 404 | PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); |
michael@0 | 405 | |
michael@0 | 406 | progName = PORT_Strdup(argv[0]); |
michael@0 | 407 | |
michael@0 | 408 | hostName = NULL; |
michael@0 | 409 | optstate = PL_CreateOptState(argc, argv, "C:cd:f:l:n:p:ot:w:"); |
michael@0 | 410 | while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { |
michael@0 | 411 | switch(optstate->option) { |
michael@0 | 412 | case 'C' : cipherString = PL_strdup(optstate->value); break; |
michael@0 | 413 | case 'c' : dumpChain = PR_TRUE; break; |
michael@0 | 414 | case 'd' : certDir = PL_strdup(optstate->value); break; |
michael@0 | 415 | case 'l' : respUrl = PL_strdup(optstate->value); break; |
michael@0 | 416 | case 'p' : port = PORT_Atoi(optstate->value); break; |
michael@0 | 417 | case 'o' : doOcspCheck = PR_TRUE; break; |
michael@0 | 418 | case 't' : respCertName = PL_strdup(optstate->value); break; |
michael@0 | 419 | case 'w': |
michael@0 | 420 | pwdata.source = PW_PLAINTEXT; |
michael@0 | 421 | pwdata.data = PORT_Strdup(optstate->value); |
michael@0 | 422 | break; |
michael@0 | 423 | |
michael@0 | 424 | case 'f': |
michael@0 | 425 | pwdata.source = PW_FROMFILE; |
michael@0 | 426 | pwdata.data = PORT_Strdup(optstate->value); |
michael@0 | 427 | break; |
michael@0 | 428 | case '\0': hostName = PL_strdup(optstate->value); break; |
michael@0 | 429 | default : Usage(progName); |
michael@0 | 430 | } |
michael@0 | 431 | } |
michael@0 | 432 | |
michael@0 | 433 | if (port == 0) { |
michael@0 | 434 | port = 443; |
michael@0 | 435 | } |
michael@0 | 436 | |
michael@0 | 437 | if (port == 0 || hostName == NULL) |
michael@0 | 438 | Usage(progName); |
michael@0 | 439 | |
michael@0 | 440 | if (doOcspCheck && |
michael@0 | 441 | ((respCertName != NULL && respUrl == NULL) || |
michael@0 | 442 | (respUrl != NULL && respCertName == NULL))) { |
michael@0 | 443 | SECU_PrintError (progName, "options -l <url> and -t " |
michael@0 | 444 | "<responder> must be used together"); |
michael@0 | 445 | Usage(progName); |
michael@0 | 446 | } |
michael@0 | 447 | |
michael@0 | 448 | PK11_SetPasswordFunc(SECU_GetModulePassword); |
michael@0 | 449 | |
michael@0 | 450 | /* Initialize the NSS libraries. */ |
michael@0 | 451 | if (certDir) { |
michael@0 | 452 | secStatus = NSS_Init(certDir); |
michael@0 | 453 | } else { |
michael@0 | 454 | secStatus = NSS_NoDB_Init(NULL); |
michael@0 | 455 | |
michael@0 | 456 | /* load the builtins */ |
michael@0 | 457 | SECMOD_AddNewModule("Builtins", |
michael@0 | 458 | DLL_PREFIX"nssckbi."DLL_SUFFIX, 0, 0); |
michael@0 | 459 | } |
michael@0 | 460 | if (secStatus != SECSuccess) { |
michael@0 | 461 | exitErr("NSS_Init"); |
michael@0 | 462 | } |
michael@0 | 463 | SECU_RegisterDynamicOids(); |
michael@0 | 464 | |
michael@0 | 465 | if (doOcspCheck == PR_TRUE) { |
michael@0 | 466 | SECStatus rv; |
michael@0 | 467 | CERTCertDBHandle *handle = CERT_GetDefaultCertDB(); |
michael@0 | 468 | if (handle == NULL) { |
michael@0 | 469 | SECU_PrintError (progName, "problem getting certdb handle"); |
michael@0 | 470 | goto cleanup; |
michael@0 | 471 | } |
michael@0 | 472 | |
michael@0 | 473 | rv = CERT_EnableOCSPChecking (handle); |
michael@0 | 474 | if (rv != SECSuccess) { |
michael@0 | 475 | SECU_PrintError (progName, "error enabling OCSP checking"); |
michael@0 | 476 | goto cleanup; |
michael@0 | 477 | } |
michael@0 | 478 | |
michael@0 | 479 | if (respUrl != NULL) { |
michael@0 | 480 | rv = CERT_SetOCSPDefaultResponder (handle, respUrl, |
michael@0 | 481 | respCertName); |
michael@0 | 482 | if (rv != SECSuccess) { |
michael@0 | 483 | SECU_PrintError (progName, |
michael@0 | 484 | "error setting default responder"); |
michael@0 | 485 | goto cleanup; |
michael@0 | 486 | } |
michael@0 | 487 | |
michael@0 | 488 | rv = CERT_EnableOCSPDefaultResponder (handle); |
michael@0 | 489 | if (rv != SECSuccess) { |
michael@0 | 490 | SECU_PrintError (progName, |
michael@0 | 491 | "error enabling default responder"); |
michael@0 | 492 | goto cleanup; |
michael@0 | 493 | } |
michael@0 | 494 | } |
michael@0 | 495 | } |
michael@0 | 496 | |
michael@0 | 497 | /* All cipher suites except RSA_NULL_MD5 are enabled by |
michael@0 | 498 | * Domestic Policy. */ |
michael@0 | 499 | NSS_SetDomesticPolicy(); |
michael@0 | 500 | SSL_CipherPrefSetDefault(TLS_RSA_WITH_NULL_MD5, PR_TRUE); |
michael@0 | 501 | |
michael@0 | 502 | /* all the SSL2 and SSL3 cipher suites are enabled by default. */ |
michael@0 | 503 | if (cipherString) { |
michael@0 | 504 | int ndx; |
michael@0 | 505 | |
michael@0 | 506 | /* disable all the ciphers, then enable the ones we want. */ |
michael@0 | 507 | disableAllSSLCiphers(); |
michael@0 | 508 | |
michael@0 | 509 | while (0 != (ndx = *cipherString++)) { |
michael@0 | 510 | int cipher; |
michael@0 | 511 | |
michael@0 | 512 | if (ndx == ':') { |
michael@0 | 513 | int ctmp; |
michael@0 | 514 | |
michael@0 | 515 | cipher = 0; |
michael@0 | 516 | HEXCHAR_TO_INT(*cipherString, ctmp) |
michael@0 | 517 | cipher |= (ctmp << 12); |
michael@0 | 518 | cipherString++; |
michael@0 | 519 | HEXCHAR_TO_INT(*cipherString, ctmp) |
michael@0 | 520 | cipher |= (ctmp << 8); |
michael@0 | 521 | cipherString++; |
michael@0 | 522 | HEXCHAR_TO_INT(*cipherString, ctmp) |
michael@0 | 523 | cipher |= (ctmp << 4); |
michael@0 | 524 | cipherString++; |
michael@0 | 525 | HEXCHAR_TO_INT(*cipherString, ctmp) |
michael@0 | 526 | cipher |= ctmp; |
michael@0 | 527 | cipherString++; |
michael@0 | 528 | } else { |
michael@0 | 529 | const int *cptr; |
michael@0 | 530 | if (! isalpha(ndx)) |
michael@0 | 531 | Usage(progName); |
michael@0 | 532 | cptr = islower(ndx) ? ssl3CipherSuites : ssl2CipherSuites; |
michael@0 | 533 | for (ndx &= 0x1f; (cipher = *cptr++) != 0 && --ndx > 0; ) |
michael@0 | 534 | /* do nothing */; |
michael@0 | 535 | } |
michael@0 | 536 | if (cipher > 0) { |
michael@0 | 537 | SSL_CipherPrefSetDefault(cipher, PR_TRUE); |
michael@0 | 538 | } else { |
michael@0 | 539 | Usage(progName); |
michael@0 | 540 | } |
michael@0 | 541 | } |
michael@0 | 542 | } |
michael@0 | 543 | |
michael@0 | 544 | client_main(port, connections, hostName); |
michael@0 | 545 | |
michael@0 | 546 | cleanup: |
michael@0 | 547 | if (doOcspCheck) { |
michael@0 | 548 | CERTCertDBHandle *handle = CERT_GetDefaultCertDB(); |
michael@0 | 549 | CERT_DisableOCSPDefaultResponder(handle); |
michael@0 | 550 | CERT_DisableOCSPChecking (handle); |
michael@0 | 551 | } |
michael@0 | 552 | |
michael@0 | 553 | if (NSS_Shutdown() != SECSuccess) { |
michael@0 | 554 | exit(1); |
michael@0 | 555 | } |
michael@0 | 556 | |
michael@0 | 557 | PR_Cleanup(); |
michael@0 | 558 | PORT_Free(progName); |
michael@0 | 559 | return 0; |
michael@0 | 560 | } |
michael@0 | 561 |