File: | s/cmd/tstclnt/tstclnt.c |
Warning: | line 755, column 32 Access to field 'arg' results in a dereference of a null pointer (loaded from variable 'args') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* This Source Code Form is subject to the terms of the Mozilla Public | ||||
2 | * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||||
4 | |||||
5 | /* | ||||
6 | ** | ||||
7 | ** Sample client side test program that uses SSL and NSS | ||||
8 | ** | ||||
9 | */ | ||||
10 | |||||
11 | #include "secutil.h" | ||||
12 | #include "basicutil.h" | ||||
13 | |||||
14 | #if defined(XP_UNIX1) | ||||
15 | #include <unistd.h> | ||||
16 | #else | ||||
17 | #include <ctype.h> /* for isalpha() */ | ||||
18 | #endif | ||||
19 | |||||
20 | #include <stdio.h> | ||||
21 | #include <string.h> | ||||
22 | #include <stdlib.h> | ||||
23 | #include <errno(*__errno_location ()).h> | ||||
24 | #include <fcntl.h> | ||||
25 | #include <stdarg.h> | ||||
26 | |||||
27 | #include "nspr.h" | ||||
28 | #include "prio.h" | ||||
29 | #include "prnetdb.h" | ||||
30 | #include "nss.h" | ||||
31 | #include "nssb64.h" | ||||
32 | #include "ocsp.h" | ||||
33 | #include "ssl.h" | ||||
34 | #include "sslproto.h" | ||||
35 | #include "sslexp.h" | ||||
36 | #include "pk11func.h" | ||||
37 | #include "secmod.h" | ||||
38 | #include "plgetopt.h" | ||||
39 | #include "plstr.h" | ||||
40 | |||||
41 | #if defined(WIN32) | ||||
42 | #include <fcntl.h> | ||||
43 | #include <io.h> | ||||
44 | #endif | ||||
45 | |||||
46 | #define PRINTFif (verbose) printf \ | ||||
47 | if (verbose) \ | ||||
48 | printf | ||||
49 | #define FPRINTFif (verbose) fprintf \ | ||||
50 | if (verbose) \ | ||||
51 | fprintf | ||||
52 | |||||
53 | #define MAX_WAIT_FOR_SERVER600 600 | ||||
54 | #define WAIT_INTERVAL100 100 | ||||
55 | #define ZERO_RTT_MAX(2 << 16) (2 << 16) | ||||
56 | |||||
57 | #define EXIT_CODE_HANDSHAKE_FAILED254 254 | ||||
58 | |||||
59 | #define EXIT_CODE_SIDECHANNELTEST_GOOD0 0 | ||||
60 | #define EXIT_CODE_SIDECHANNELTEST_BADCERT1 1 | ||||
61 | #define EXIT_CODE_SIDECHANNELTEST_NODATA2 2 | ||||
62 | #define EXIT_CODE_SIDECHANNELTEST_REVOKED3 3 | ||||
63 | |||||
64 | PRIntervalTime maxInterval = PR_INTERVAL_NO_TIMEOUT0xffffffffUL; | ||||
65 | |||||
66 | int ssl3CipherSuites[] = { | ||||
67 | -1, /* SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA* a */ | ||||
68 | -1, /* SSL_FORTEZZA_DMS_WITH_RC4_128_SHA * b */ | ||||
69 | TLS_RSA_WITH_RC4_128_MD50x0004, /* c */ | ||||
70 | TLS_RSA_WITH_3DES_EDE_CBC_SHA0x000a, /* d */ | ||||
71 | TLS_RSA_WITH_DES_CBC_SHA0x0009, /* e */ | ||||
72 | -1, /* TLS_RSA_EXPORT_WITH_RC4_40_MD5 * f */ | ||||
73 | -1, /* TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 * g */ | ||||
74 | -1, /* SSL_FORTEZZA_DMS_WITH_NULL_SHA * h */ | ||||
75 | TLS_RSA_WITH_NULL_MD50x0001, /* i */ | ||||
76 | -1, /* SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA * j */ | ||||
77 | -1, /* SSL_RSA_FIPS_WITH_DES_CBC_SHA * k */ | ||||
78 | -1, /* TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA * l */ | ||||
79 | -1, /* TLS_RSA_EXPORT1024_WITH_RC4_56_SHA * m */ | ||||
80 | TLS_RSA_WITH_RC4_128_SHA0x0005, /* n */ | ||||
81 | TLS_DHE_DSS_WITH_RC4_128_SHA0x0066, /* o */ | ||||
82 | TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA0x0016, /* p */ | ||||
83 | TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA0x0013, /* q */ | ||||
84 | TLS_DHE_RSA_WITH_DES_CBC_SHA0x0015, /* r */ | ||||
85 | TLS_DHE_DSS_WITH_DES_CBC_SHA0x0012, /* s */ | ||||
86 | TLS_DHE_DSS_WITH_AES_128_CBC_SHA0x0032, /* t */ | ||||
87 | TLS_DHE_RSA_WITH_AES_128_CBC_SHA0x0033, /* u */ | ||||
88 | TLS_RSA_WITH_AES_128_CBC_SHA0x002F, /* v */ | ||||
89 | TLS_DHE_DSS_WITH_AES_256_CBC_SHA0x0038, /* w */ | ||||
90 | TLS_DHE_RSA_WITH_AES_256_CBC_SHA0x0039, /* x */ | ||||
91 | TLS_RSA_WITH_AES_256_CBC_SHA0x0035, /* y */ | ||||
92 | TLS_RSA_WITH_NULL_SHA0x0002, /* z */ | ||||
93 | 0 | ||||
94 | }; | ||||
95 | |||||
96 | unsigned long __cmp_umuls; | ||||
97 | PRBool verbose; | ||||
98 | int dumpServerChain = 0; | ||||
99 | int renegotiationsToDo = 0; | ||||
100 | int renegotiationsDone = 0; | ||||
101 | PRBool initializedServerSessionCache = PR_FALSE0; | ||||
102 | |||||
103 | static char *progName; | ||||
104 | static const char *requestFile; | ||||
105 | |||||
106 | secuPWData pwdata = { PW_NONE, 0 }; | ||||
107 | |||||
108 | SSLNamedGroup *enabledGroups = NULL((void*)0); | ||||
109 | unsigned int enabledGroupsCount = 0; | ||||
110 | const SSLSignatureScheme *enabledSigSchemes = NULL((void*)0); | ||||
111 | unsigned int enabledSigSchemeCount = 0; | ||||
112 | SECItem psk = { siBuffer, NULL((void*)0), 0 }; | ||||
113 | SECItem pskLabel = { siBuffer, NULL((void*)0), 0 }; | ||||
114 | |||||
115 | const char * | ||||
116 | signatureSchemeName(SSLSignatureScheme scheme) | ||||
117 | { | ||||
118 | switch (scheme) { | ||||
119 | #define strcase(x) \ | ||||
120 | case ssl_sig_##x: \ | ||||
121 | return #x | ||||
122 | strcase(none); | ||||
123 | strcase(rsa_pkcs1_sha1); | ||||
124 | strcase(rsa_pkcs1_sha256); | ||||
125 | strcase(rsa_pkcs1_sha384); | ||||
126 | strcase(rsa_pkcs1_sha512); | ||||
127 | strcase(ecdsa_sha1); | ||||
128 | strcase(ecdsa_secp256r1_sha256); | ||||
129 | strcase(ecdsa_secp384r1_sha384); | ||||
130 | strcase(ecdsa_secp521r1_sha512); | ||||
131 | strcase(rsa_pss_rsae_sha256); | ||||
132 | strcase(rsa_pss_rsae_sha384); | ||||
133 | strcase(rsa_pss_rsae_sha512); | ||||
134 | strcase(ed25519); | ||||
135 | strcase(ed448); | ||||
136 | strcase(rsa_pss_pss_sha256); | ||||
137 | strcase(rsa_pss_pss_sha384); | ||||
138 | strcase(rsa_pss_pss_sha512); | ||||
139 | strcase(dsa_sha1); | ||||
140 | strcase(dsa_sha256); | ||||
141 | strcase(dsa_sha384); | ||||
142 | strcase(dsa_sha512); | ||||
143 | #undef strcase | ||||
144 | case ssl_sig_rsa_pkcs1_sha1md5: | ||||
145 | return "RSA PKCS#1 SHA1+MD5"; | ||||
146 | default: | ||||
147 | break; | ||||
148 | } | ||||
149 | return "Unknown Scheme"; | ||||
150 | } | ||||
151 | |||||
152 | void | ||||
153 | printSecurityInfo(PRFileDesc *fd) | ||||
154 | { | ||||
155 | CERTCertificate *cert; | ||||
156 | const SECItemArray *csa; | ||||
157 | const SECItem *scts; | ||||
158 | SSL3Statistics *ssl3stats = SSL_GetStatistics(); | ||||
159 | SECStatus result; | ||||
160 | SSLChannelInfo channel; | ||||
161 | SSLCipherSuiteInfo suite; | ||||
162 | |||||
163 | result = SSL_GetChannelInfo(fd, &channel, sizeof channel); | ||||
164 | if (result == SECSuccess && | ||||
165 | channel.length == sizeof channel && | ||||
166 | channel.cipherSuite) { | ||||
167 | result = SSL_GetCipherSuiteInfo(channel.cipherSuite, | ||||
168 | &suite, sizeof suite); | ||||
169 | if (result == SECSuccess) { | ||||
170 | FPRINTFif (verbose) fprintf(stderrstderr, | ||||
171 | "tstclnt: SSL version %d.%d using %d-bit %s with %d-bit %s MAC%s\n", | ||||
172 | channel.protocolVersion >> 8, channel.protocolVersion & 0xff, | ||||
173 | suite.effectiveKeyBits, suite.symCipherName, | ||||
174 | suite.macBits, suite.macAlgorithmName, | ||||
175 | channel.isFIPS ? " FIPS" : ""); | ||||
176 | FPRINTFif (verbose) fprintf(stderrstderr, | ||||
177 | "tstclnt: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n" | ||||
178 | " Compression: %s, Extended Master Secret: %s\n" | ||||
179 | " Signature Scheme: %s\n", | ||||
180 | channel.authKeyBits, suite.authAlgorithmName, | ||||
181 | channel.keaKeyBits, suite.keaTypeName, | ||||
182 | channel.compressionMethodName, | ||||
183 | channel.extendedMasterSecretUsed ? "Yes" : "No", | ||||
184 | signatureSchemeName(channel.signatureScheme)); | ||||
185 | } | ||||
186 | } | ||||
187 | cert = SSL_RevealCert(fd); | ||||
188 | if (cert) { | ||||
189 | char *ip = CERT_NameToAscii(&cert->issuer); | ||||
190 | char *sp = CERT_NameToAscii(&cert->subject); | ||||
191 | if (sp) { | ||||
192 | fprintf(stderrstderr, "subject DN: %s\n", sp); | ||||
193 | PORT_FreePORT_Free_Util(sp); | ||||
194 | } | ||||
195 | if (ip) { | ||||
196 | fprintf(stderrstderr, "issuer DN: %s\n", ip); | ||||
197 | PORT_FreePORT_Free_Util(ip); | ||||
198 | } | ||||
199 | CERT_DestroyCertificate(cert); | ||||
200 | cert = NULL((void*)0); | ||||
201 | } | ||||
202 | fprintf(stderrstderr, | ||||
203 | "%ld cache hits; %ld cache misses, %ld cache not reusable\n" | ||||
204 | "%ld stateless resumes\n", | ||||
205 | ssl3stats->hsh_sid_cache_hits, ssl3stats->hsh_sid_cache_misses, | ||||
206 | ssl3stats->hsh_sid_cache_not_ok, ssl3stats->hsh_sid_stateless_resumes); | ||||
207 | |||||
208 | csa = SSL_PeerStapledOCSPResponses(fd); | ||||
209 | if (csa) { | ||||
210 | fprintf(stderrstderr, "Received %d Cert Status items (OCSP stapled data)\n", | ||||
211 | csa->len); | ||||
212 | } | ||||
213 | scts = SSL_PeerSignedCertTimestamps(fd); | ||||
214 | if (scts && scts->len) { | ||||
215 | fprintf(stderrstderr, "Received a Signed Certificate Timestamp of length" | ||||
216 | " %u\n", | ||||
217 | scts->len); | ||||
218 | } | ||||
219 | if (channel.peerDelegCred) { | ||||
220 | fprintf(stderrstderr, "Received a Delegated Credential\n"); | ||||
221 | } | ||||
222 | } | ||||
223 | |||||
224 | static void | ||||
225 | PrintUsageHeader() | ||||
226 | { | ||||
227 | fprintf(stderrstderr, | ||||
228 | "Usage: %s -h host [-a 1st_hs_name ] [-a 2nd_hs_name ] [-p port]\n" | ||||
229 | " [-D | -d certdir] [-C] [-b | -R root-module] \n" | ||||
230 | " [-n nickname] [-Bafosvx] [-c ciphers] [-Y] [-Z] [-E]\n" | ||||
231 | " [-V [min-version]:[max-version]] [-K] [-T] [-U]\n" | ||||
232 | " [-r N] [-w passwd] [-W pwfile] [-q [-t seconds]]\n" | ||||
233 | " [-I groups] [-J signatureschemes]\n" | ||||
234 | " [-A requestfile] [-L totalconnections] [-P {client,server}]\n" | ||||
235 | " [-N echConfigs] [-Q] [-z externalPsk]\n" | ||||
236 | " [-i echGreaseSize]\n" | ||||
237 | "\n", | ||||
238 | progName); | ||||
239 | } | ||||
240 | |||||
241 | static void | ||||
242 | PrintParameterUsage() | ||||
243 | { | ||||
244 | fprintf(stderrstderr, "%-20s Send different SNI name. 1st_hs_name - at first\n" | ||||
245 | "%-20s handshake, 2nd_hs_name - at second handshake.\n" | ||||
246 | "%-20s Default is host from the -h argument.\n", | ||||
247 | "-a name", | ||||
248 | "", ""); | ||||
249 | fprintf(stderrstderr, "%-20s Hostname to connect with\n", "-h host"); | ||||
250 | fprintf(stderrstderr, "%-20s Port number for SSL server\n", "-p port"); | ||||
251 | fprintf(stderrstderr, | ||||
252 | "%-20s Directory with cert database (default is ~/.netscape)\n", | ||||
253 | "-d certdir"); | ||||
254 | fprintf(stderrstderr, "%-20s Run without a cert database\n", "-D"); | ||||
255 | fprintf(stderrstderr, "%-20s Load the default \"builtins\" root CA module\n", "-b"); | ||||
256 | fprintf(stderrstderr, "%-20s Load the given root CA module\n", "-R"); | ||||
257 | fprintf(stderrstderr, "%-20s Print certificate chain information\n", "-C"); | ||||
258 | fprintf(stderrstderr, "%-20s (use -C twice to print more certificate details)\n", ""); | ||||
259 | fprintf(stderrstderr, "%-20s (use -C three times to include PEM format certificate dumps)\n", ""); | ||||
260 | fprintf(stderrstderr, "%-20s Nickname of key and cert\n", | ||||
261 | "-n nickname"); | ||||
262 | fprintf(stderrstderr, | ||||
263 | "%-20s Restricts the set of enabled SSL/TLS protocols versions.\n" | ||||
264 | "%-20s All versions are enabled by default.\n" | ||||
265 | "%-20s Possible values for min/max: ssl3 tls1.0 tls1.1 tls1.2 tls1.3\n" | ||||
266 | "%-20s Example: \"-V ssl3:\" enables SSL 3 and newer.\n", | ||||
267 | "-V [min]:[max]", "", "", ""); | ||||
268 | fprintf(stderrstderr, "%-20s Send TLS_FALLBACK_SCSV\n", "-K"); | ||||
269 | fprintf(stderrstderr, "%-20s Prints only payload data. Skips HTTP header.\n", "-S"); | ||||
270 | fprintf(stderrstderr, "%-20s Client speaks first. \n", "-f"); | ||||
271 | fprintf(stderrstderr, "%-20s Use synchronous certificate selection & validation\n", "-O"); | ||||
272 | fprintf(stderrstderr, "%-20s Override bad server cert. Make it OK.\n", "-o"); | ||||
273 | fprintf(stderrstderr, "%-20s Disable SSL socket locking.\n", "-s"); | ||||
274 | fprintf(stderrstderr, "%-20s Verbose progress reporting.\n", "-v"); | ||||
275 | fprintf(stderrstderr, "%-20s Ping the server and then exit.\n", "-q"); | ||||
276 | fprintf(stderrstderr, "%-20s Timeout for server ping (default: no timeout).\n", "-t seconds"); | ||||
277 | fprintf(stderrstderr, "%-20s Renegotiate N times (resuming session if N>1).\n", "-r N"); | ||||
278 | fprintf(stderrstderr, "%-20s Enable the session ticket extension.\n", "-u"); | ||||
279 | fprintf(stderrstderr, "%-20s Enable false start.\n", "-g"); | ||||
280 | fprintf(stderrstderr, "%-20s Enable the cert_status extension (OCSP stapling).\n", "-T"); | ||||
281 | fprintf(stderrstderr, "%-20s Enable the signed_certificate_timestamp extension.\n", "-U"); | ||||
282 | fprintf(stderrstderr, "%-20s Enable the delegated credentials extension.\n", "-B"); | ||||
283 | fprintf(stderrstderr, "%-20s Require fresh revocation info from side channel.\n" | ||||
284 | "%-20s -F once means: require for server cert only\n" | ||||
285 | "%-20s -F twice means: require for intermediates, too\n" | ||||
286 | "%-20s (Connect, handshake with server, disable dynamic download\n" | ||||
287 | "%-20s of OCSP/CRL, verify cert using CERT_PKIXVerifyCert.)\n" | ||||
288 | "%-20s Exit code:\n" | ||||
289 | "%-20s 0: have fresh and valid revocation data, status good\n" | ||||
290 | "%-20s 1: cert failed to verify, prior to revocation checking\n" | ||||
291 | "%-20s 2: missing, old or invalid revocation data\n" | ||||
292 | "%-20s 3: have fresh and valid revocation data, status revoked\n", | ||||
293 | "-F", "", "", "", "", "", "", "", "", ""); | ||||
294 | fprintf(stderrstderr, "%-20s Test -F allows 0=any (default), 1=only OCSP, 2=only CRL\n", "-M"); | ||||
295 | fprintf(stderrstderr, "%-20s Restrict ciphers\n", "-c ciphers"); | ||||
296 | fprintf(stderrstderr, "%-20s Print cipher values allowed for parameter -c and exit\n", "-Y"); | ||||
297 | fprintf(stderrstderr, "%-20s Enforce using an IPv4 destination address\n", "-4"); | ||||
298 | fprintf(stderrstderr, "%-20s Enforce using an IPv6 destination address\n", "-6"); | ||||
299 | fprintf(stderrstderr, "%-20s (Options -4 and -6 cannot be combined.)\n", ""); | ||||
300 | fprintf(stderrstderr, "%-20s Enable the extended master secret extension [RFC7627]\n", "-G"); | ||||
301 | fprintf(stderrstderr, "%-20s Require the use of FFDHE supported groups [RFC7919]\n", "-H"); | ||||
302 | fprintf(stderrstderr, "%-20s Read from a file instead of stdin\n", "-A"); | ||||
303 | fprintf(stderrstderr, "%-20s Allow 0-RTT data (TLS 1.3 only)\n", "-Z"); | ||||
304 | fprintf(stderrstderr, "%-20s Disconnect and reconnect up to N times total\n", "-L"); | ||||
305 | fprintf(stderrstderr, "%-20s Comma separated list of enabled groups for TLS key exchange.\n" | ||||
306 | "%-20s The following values are valid:\n" | ||||
307 | "%-20s P256, P384, P521, x25519, FF2048, FF3072, FF4096, FF6144, FF8192\n" | ||||
308 | "%-20s xyber768d00\n", | ||||
309 | "-I", "", "", ""); | ||||
310 | fprintf(stderrstderr, "%-20s Comma separated list of signature schemes in preference order.\n" | ||||
311 | "%-20s The following values are valid:\n" | ||||
312 | "%-20s rsa_pkcs1_sha1, rsa_pkcs1_sha256, rsa_pkcs1_sha384, rsa_pkcs1_sha512,\n" | ||||
313 | "%-20s ecdsa_sha1, ecdsa_secp256r1_sha256, ecdsa_secp384r1_sha384,\n" | ||||
314 | "%-20s ecdsa_secp521r1_sha512,\n" | ||||
315 | "%-20s rsa_pss_rsae_sha256, rsa_pss_rsae_sha384, rsa_pss_rsae_sha512,\n" | ||||
316 | "%-20s rsa_pss_pss_sha256, rsa_pss_pss_sha384, rsa_pss_pss_sha512,\n" | ||||
317 | "%-20s dsa_sha1, dsa_sha256, dsa_sha384, dsa_sha512\n", | ||||
318 | "-J", "", "", "", "", "", "", ""); | ||||
319 | fprintf(stderrstderr, "%-20s Use DTLS\n", "-P {client, server}"); | ||||
320 | fprintf(stderrstderr, "%-20s Exit after handshake\n", "-Q"); | ||||
321 | fprintf(stderrstderr, "%-20s Use Encrypted Client Hello with the given Base64-encoded ECHConfigs\n", "-N"); | ||||
322 | fprintf(stderrstderr, "%-20s Enable Encrypted Client Hello GREASEing with the given padding size (0-255) \n", "-i"); | ||||
323 | fprintf(stderrstderr, "%-20s Enable post-handshake authentication\n" | ||||
324 | "%-20s for TLS 1.3; need to specify -n\n", | ||||
325 | "-E", ""); | ||||
326 | fprintf(stderrstderr, "%-20s Export and print keying material after successful handshake.\n" | ||||
327 | "%-20s The argument is a comma separated list of exporters in the form:\n" | ||||
328 | "%-20s LABEL[:OUTPUT-LENGTH[:CONTEXT]]\n" | ||||
329 | "%-20s where LABEL and CONTEXT can be either a free-form string or\n" | ||||
330 | "%-20s a hex string if it is preceded by \"0x\"; OUTPUT-LENGTH\n" | ||||
331 | "%-20s is a decimal integer.\n", | ||||
332 | "-x", "", "", "", "", ""); | ||||
333 | fprintf(stderrstderr, | ||||
334 | "%-20s Configure a TLS 1.3 External PSK with the given hex string for a key\n" | ||||
335 | "%-20s To specify a label, use ':' as a delimiter. For example\n" | ||||
336 | "%-20s 0xAAAABBBBCCCCDDDD:mylabel. Otherwise, the default label of\n" | ||||
337 | "%-20s 'Client_identity' will be used.\n", | ||||
338 | "-z externalPsk", "", "", ""); | ||||
339 | fprintf(stderrstderr, "%-20s Enable middlebox compatibility mode (TLS 1.3 only)\n", "-e"); | ||||
340 | } | ||||
341 | |||||
342 | static void | ||||
343 | Usage() | ||||
344 | { | ||||
345 | PrintUsageHeader(); | ||||
346 | PrintParameterUsage(); | ||||
347 | exit(1); | ||||
348 | } | ||||
349 | |||||
350 | static void | ||||
351 | PrintCipherUsage() | ||||
352 | { | ||||
353 | PrintUsageHeader(); | ||||
354 | fprintf(stderrstderr, "%-20s Letter(s) chosen from the following list\n", | ||||
355 | "-c ciphers"); | ||||
356 | fprintf(stderrstderr, | ||||
357 | "c SSL3 RSA WITH RC4 128 MD5\n" | ||||
358 | "d SSL3 RSA WITH 3DES EDE CBC SHA\n" | ||||
359 | "e SSL3 RSA WITH DES CBC SHA\n" | ||||
360 | "i SSL3 RSA WITH NULL MD5\n" | ||||
361 | "n SSL3 RSA WITH RC4 128 SHA\n" | ||||
362 | "o SSL3 DHE DSS WITH RC4 128 SHA\n" | ||||
363 | "p SSL3 DHE RSA WITH 3DES EDE CBC SHA\n" | ||||
364 | "q SSL3 DHE DSS WITH 3DES EDE CBC SHA\n" | ||||
365 | "r SSL3 DHE RSA WITH DES CBC SHA\n" | ||||
366 | "s SSL3 DHE DSS WITH DES CBC SHA\n" | ||||
367 | "t SSL3 DHE DSS WITH AES 128 CBC SHA\n" | ||||
368 | "u SSL3 DHE RSA WITH AES 128 CBC SHA\n" | ||||
369 | "v SSL3 RSA WITH AES 128 CBC SHA\n" | ||||
370 | "w SSL3 DHE DSS WITH AES 256 CBC SHA\n" | ||||
371 | "x SSL3 DHE RSA WITH AES 256 CBC SHA\n" | ||||
372 | "y SSL3 RSA WITH AES 256 CBC SHA\n" | ||||
373 | "z SSL3 RSA WITH NULL SHA\n" | ||||
374 | "\n" | ||||
375 | ":WXYZ Use cipher with hex code { 0xWX , 0xYZ } in TLS\n"); | ||||
376 | exit(1); | ||||
377 | } | ||||
378 | |||||
379 | void | ||||
380 | milliPause(PRUint32 milli) | ||||
381 | { | ||||
382 | PRIntervalTime ticks = PR_MillisecondsToInterval(milli); | ||||
383 | PR_Sleep(ticks); | ||||
384 | } | ||||
385 | |||||
386 | void | ||||
387 | disableAllSSLCiphers() | ||||
388 | { | ||||
389 | const PRUint16 *cipherSuites = SSL_GetImplementedCiphers(); | ||||
390 | int i = SSL_GetNumImplementedCiphers(); | ||||
391 | SECStatus rv; | ||||
392 | |||||
393 | /* disable all the SSL3 cipher suites */ | ||||
394 | while (--i >= 0) { | ||||
395 | PRUint16 suite = cipherSuites[i]; | ||||
396 | rv = SSL_CipherPrefSetDefault(suite, PR_FALSE0); | ||||
397 | if (rv != SECSuccess) { | ||||
398 | PRErrorCode err = PR_GetError(); | ||||
399 | fprintf(stderrstderr, | ||||
400 | "SSL_CipherPrefSet didn't like value 0x%04x (i = %d): %s\n", | ||||
401 | suite, i, SECU_Strerror(err)PR_ErrorToString((err), 0)); | ||||
402 | exit(2); | ||||
403 | } | ||||
404 | } | ||||
405 | } | ||||
406 | |||||
407 | typedef struct | ||||
408 | { | ||||
409 | PRBool shouldPause; /* PR_TRUE if we should use asynchronous peer cert | ||||
410 | * authentication */ | ||||
411 | PRBool isPaused; /* PR_TRUE if libssl is waiting for us to validate the | ||||
412 | * peer's certificate and restart the handshake. */ | ||||
413 | void *dbHandle; /* Certificate database handle to use while | ||||
414 | * authenticating the peer's certificate. */ | ||||
415 | PRBool testFreshStatusFromSideChannel; | ||||
416 | PRErrorCode sideChannelRevocationTestResultCode; | ||||
417 | PRBool requireDataForIntermediates; | ||||
418 | PRBool allowOCSPSideChannelData; | ||||
419 | PRBool allowCRLSideChannelData; | ||||
420 | } ServerCertAuth; | ||||
421 | |||||
422 | /* | ||||
423 | * Callback is called when incoming certificate is not valid. | ||||
424 | * Returns SECSuccess to accept the cert anyway, SECFailure to reject. | ||||
425 | */ | ||||
426 | static SECStatus | ||||
427 | ownBadCertHandler(void *arg, PRFileDesc *socket) | ||||
428 | { | ||||
429 | PRErrorCode err = PR_GetError(); | ||||
430 | /* can log invalid cert here */ | ||||
431 | fprintf(stderrstderr, "Bad server certificate: %d, %s\n", err, | ||||
432 | SECU_Strerror(err)PR_ErrorToString((err), 0)); | ||||
433 | return SECSuccess; /* override, say it's OK. */ | ||||
434 | } | ||||
435 | |||||
436 | #define EXIT_CODE_SIDECHANNELTEST_GOOD0 0 | ||||
437 | #define EXIT_CODE_SIDECHANNELTEST_BADCERT1 1 | ||||
438 | #define EXIT_CODE_SIDECHANNELTEST_NODATA2 2 | ||||
439 | #define EXIT_CODE_SIDECHANNELTEST_REVOKED3 3 | ||||
440 | |||||
441 | static void | ||||
442 | verifyFromSideChannel(CERTCertificate *cert, ServerCertAuth *sca) | ||||
443 | { | ||||
444 | PRUint64 revDoNotUse = | ||||
445 | CERT_REV_M_DO_NOT_TEST_USING_THIS_METHOD0UL; | ||||
446 | |||||
447 | PRUint64 revUseLocalOnlyAndSoftFail = | ||||
448 | CERT_REV_M_TEST_USING_THIS_METHOD1UL | | ||||
449 | CERT_REV_M_FORBID_NETWORK_FETCHING2UL | | ||||
450 | CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE8UL | | ||||
451 | CERT_REV_M_IGNORE_MISSING_FRESH_INFO0UL | | ||||
452 | CERT_REV_M_STOP_TESTING_ON_FRESH_INFO0UL; | ||||
453 | |||||
454 | PRUint64 revUseLocalOnlyAndHardFail = | ||||
455 | CERT_REV_M_TEST_USING_THIS_METHOD1UL | | ||||
456 | CERT_REV_M_FORBID_NETWORK_FETCHING2UL | | ||||
457 | CERT_REV_M_REQUIRE_INFO_ON_MISSING_SOURCE8UL | | ||||
458 | CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO16UL | | ||||
459 | CERT_REV_M_STOP_TESTING_ON_FRESH_INFO0UL; | ||||
460 | |||||
461 | PRUint64 methodFlagsDoNotUse[2]; | ||||
462 | PRUint64 methodFlagsCheckSoftFail[2]; | ||||
463 | PRUint64 methodFlagsCheckHardFail[2]; | ||||
464 | CERTRevocationTests revTestsDoNotCheck; | ||||
465 | CERTRevocationTests revTestsOverallSoftFail; | ||||
466 | CERTRevocationTests revTestsOverallHardFail; | ||||
467 | CERTRevocationFlags rev; | ||||
468 | CERTValInParam cvin[2]; | ||||
469 | CERTValOutParam cvout[1]; | ||||
470 | SECStatus rv; | ||||
471 | |||||
472 | methodFlagsDoNotUse[cert_revocation_method_crl] = revDoNotUse; | ||||
473 | methodFlagsDoNotUse[cert_revocation_method_ocsp] = revDoNotUse; | ||||
474 | |||||
475 | methodFlagsCheckSoftFail[cert_revocation_method_crl] = | ||||
476 | sca->allowCRLSideChannelData ? revUseLocalOnlyAndSoftFail : revDoNotUse; | ||||
477 | methodFlagsCheckSoftFail[cert_revocation_method_ocsp] = | ||||
478 | sca->allowOCSPSideChannelData ? revUseLocalOnlyAndSoftFail : revDoNotUse; | ||||
479 | |||||
480 | methodFlagsCheckHardFail[cert_revocation_method_crl] = | ||||
481 | sca->allowCRLSideChannelData ? revUseLocalOnlyAndHardFail : revDoNotUse; | ||||
482 | methodFlagsCheckHardFail[cert_revocation_method_ocsp] = | ||||
483 | sca->allowOCSPSideChannelData ? revUseLocalOnlyAndHardFail : revDoNotUse; | ||||
484 | |||||
485 | revTestsDoNotCheck.cert_rev_flags_per_method = methodFlagsDoNotUse; | ||||
486 | revTestsDoNotCheck.number_of_defined_methods = 2; | ||||
487 | revTestsDoNotCheck.number_of_preferred_methods = 0; | ||||
488 | revTestsDoNotCheck.cert_rev_method_independent_flags = | ||||
489 | CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST1UL | | ||||
490 | CERT_REV_MI_NO_OVERALL_INFO_REQUIREMENT0UL; | ||||
491 | |||||
492 | revTestsOverallSoftFail.cert_rev_flags_per_method = 0; /* must define later */ | ||||
493 | revTestsOverallSoftFail.number_of_defined_methods = 2; | ||||
494 | revTestsOverallSoftFail.number_of_preferred_methods = 0; | ||||
495 | revTestsOverallSoftFail.cert_rev_method_independent_flags = | ||||
496 | CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST1UL | | ||||
497 | CERT_REV_MI_NO_OVERALL_INFO_REQUIREMENT0UL; | ||||
498 | |||||
499 | revTestsOverallHardFail.cert_rev_flags_per_method = 0; /* must define later */ | ||||
500 | revTestsOverallHardFail.number_of_defined_methods = 2; | ||||
501 | revTestsOverallHardFail.number_of_preferred_methods = 0; | ||||
502 | revTestsOverallHardFail.cert_rev_method_independent_flags = | ||||
503 | CERT_REV_MI_TEST_ALL_LOCAL_INFORMATION_FIRST1UL | | ||||
504 | CERT_REV_MI_REQUIRE_SOME_FRESH_INFO_AVAILABLE2UL; | ||||
505 | |||||
506 | rev.chainTests = revTestsDoNotCheck; | ||||
507 | rev.leafTests = revTestsDoNotCheck; | ||||
508 | |||||
509 | cvin[0].type = cert_pi_revocationFlags; | ||||
510 | cvin[0].value.pointer.revocation = &rev; | ||||
511 | cvin[1].type = cert_pi_end; | ||||
512 | |||||
513 | cvout[0].type = cert_po_end; | ||||
514 | |||||
515 | /* Strategy: | ||||
516 | * | ||||
517 | * Verify with revocation checking disabled. | ||||
518 | * On failure return 1. | ||||
519 | * | ||||
520 | * if result if "good", then continue testing. | ||||
521 | * | ||||
522 | * Verify with CERT_REV_M_FAIL_ON_MISSING_FRESH_INFO. | ||||
523 | * If result is good, return 0. | ||||
524 | * | ||||
525 | * On failure continue testing, find out why it failed. | ||||
526 | * | ||||
527 | * Verify with CERT_REV_M_IGNORE_MISSING_FRESH_INFO | ||||
528 | * | ||||
529 | * If result is "good", then our previous test failed, | ||||
530 | * because we don't have fresh revocation info, return 2. | ||||
531 | * | ||||
532 | * If result is still bad, we do have revocation info, | ||||
533 | * and it says "revoked" or something equivalent, return 3. | ||||
534 | */ | ||||
535 | |||||
536 | /* revocation checking disabled */ | ||||
537 | rv = CERT_PKIXVerifyCert(cert, certificateUsageSSLServer(0x0002), | ||||
538 | cvin, cvout, NULL((void*)0)); | ||||
539 | if (rv != SECSuccess) { | ||||
540 | sca->sideChannelRevocationTestResultCode = | ||||
541 | EXIT_CODE_SIDECHANNELTEST_BADCERT1; | ||||
542 | return; | ||||
543 | } | ||||
544 | |||||
545 | /* revocation checking, hard fail */ | ||||
546 | if (sca->allowOCSPSideChannelData && sca->allowCRLSideChannelData) { | ||||
547 | /* any method is allowed. use soft fail on individual checks, | ||||
548 | * but use hard fail on the overall check | ||||
549 | */ | ||||
550 | revTestsOverallHardFail.cert_rev_flags_per_method = methodFlagsCheckSoftFail; | ||||
551 | } else { | ||||
552 | /* only one method is allowed. use hard fail on the individual checks. | ||||
553 | * hard/soft fail is irrelevant on overall flags. | ||||
554 | */ | ||||
555 | revTestsOverallHardFail.cert_rev_flags_per_method = methodFlagsCheckHardFail; | ||||
556 | } | ||||
557 | rev.leafTests = revTestsOverallHardFail; | ||||
558 | rev.chainTests = | ||||
559 | sca->requireDataForIntermediates ? revTestsOverallHardFail : revTestsDoNotCheck; | ||||
560 | rv = CERT_PKIXVerifyCert(cert, certificateUsageSSLServer(0x0002), | ||||
561 | cvin, cvout, NULL((void*)0)); | ||||
562 | if (rv == SECSuccess) { | ||||
563 | sca->sideChannelRevocationTestResultCode = | ||||
564 | EXIT_CODE_SIDECHANNELTEST_GOOD0; | ||||
565 | return; | ||||
566 | } | ||||
567 | |||||
568 | /* revocation checking, soft fail */ | ||||
569 | revTestsOverallSoftFail.cert_rev_flags_per_method = methodFlagsCheckSoftFail; | ||||
570 | rev.leafTests = revTestsOverallSoftFail; | ||||
571 | rev.chainTests = | ||||
572 | sca->requireDataForIntermediates ? revTestsOverallSoftFail : revTestsDoNotCheck; | ||||
573 | rv = CERT_PKIXVerifyCert(cert, certificateUsageSSLServer(0x0002), | ||||
574 | cvin, cvout, NULL((void*)0)); | ||||
575 | if (rv == SECSuccess) { | ||||
576 | sca->sideChannelRevocationTestResultCode = | ||||
577 | EXIT_CODE_SIDECHANNELTEST_NODATA2; | ||||
578 | return; | ||||
579 | } | ||||
580 | |||||
581 | sca->sideChannelRevocationTestResultCode = | ||||
582 | EXIT_CODE_SIDECHANNELTEST_REVOKED3; | ||||
583 | } | ||||
584 | |||||
585 | static void | ||||
586 | dumpCertificatePEM(CERTCertificate *cert) | ||||
587 | { | ||||
588 | SECItem data; | ||||
589 | data.data = cert->derCert.data; | ||||
590 | data.len = cert->derCert.len; | ||||
591 | fprintf(stderrstderr, "%s\n%s\n%s\n", NS_CERT_HEADER"-----BEGIN CERTIFICATE-----", | ||||
592 | BTOA_DataToAsciiBTOA_DataToAscii_Util(data.data, data.len), NS_CERT_TRAILER"-----END CERTIFICATE-----"); | ||||
593 | } | ||||
594 | |||||
595 | static void | ||||
596 | dumpServerCertificateChain(PRFileDesc *fd) | ||||
597 | { | ||||
598 | CERTCertList *peerCertChain = NULL((void*)0); | ||||
599 | CERTCertListNode *node = NULL((void*)0); | ||||
600 | CERTCertificate *peerCert = NULL((void*)0); | ||||
601 | CERTCertificateList *foundChain = NULL((void*)0); | ||||
602 | SECU_PPFunc dumpFunction = NULL((void*)0); | ||||
603 | PRBool dumpCertPEM = PR_FALSE0; | ||||
604 | |||||
605 | if (!dumpServerChain) { | ||||
606 | return; | ||||
607 | } else if (dumpServerChain == 1) { | ||||
608 | dumpFunction = (SECU_PPFunc)SECU_PrintCertificateBasicInfo; | ||||
609 | } else { | ||||
610 | dumpFunction = (SECU_PPFunc)SECU_PrintCertificate; | ||||
611 | if (dumpServerChain > 2) { | ||||
612 | dumpCertPEM = PR_TRUE1; | ||||
613 | } | ||||
614 | } | ||||
615 | |||||
616 | SECU_EnableWrap(PR_FALSE0); | ||||
617 | |||||
618 | fprintf(stderrstderr, "==== certificate(s) sent by server: ====\n"); | ||||
619 | peerCertChain = SSL_PeerCertificateChain(fd); | ||||
620 | if (peerCertChain) { | ||||
621 | node = CERT_LIST_HEAD(peerCertChain)((CERTCertListNode *)(&peerCertChain->list)->next); | ||||
622 | while (!CERT_LIST_END(node, peerCertChain)(((void *)node) == ((void *)&peerCertChain->list))) { | ||||
623 | CERTCertificate *cert = node->cert; | ||||
624 | SECU_PrintSignedContent(stderrstderr, &cert->derCert, "Certificate", 0, | ||||
625 | dumpFunction); | ||||
626 | if (dumpCertPEM) { | ||||
627 | dumpCertificatePEM(cert); | ||||
628 | } | ||||
629 | node = CERT_LIST_NEXT(node)((CERTCertListNode *)node->links.next); | ||||
630 | } | ||||
631 | } | ||||
632 | |||||
633 | if (peerCertChain) { | ||||
634 | peerCert = SSL_RevealCert(fd); | ||||
635 | if (peerCert) { | ||||
636 | foundChain = CERT_CertChainFromCert(peerCert, certificateUsageSSLServer(0x0002), | ||||
637 | PR_TRUE1); | ||||
638 | } | ||||
639 | if (foundChain) { | ||||
640 | unsigned int count = 0; | ||||
641 | fprintf(stderrstderr, "==== locally found issuer certificate(s): ====\n"); | ||||
642 | for (count = 0; count < (unsigned int)foundChain->len; count++) { | ||||
643 | CERTCertificate *c; | ||||
644 | PRBool wasSentByServer = PR_FALSE0; | ||||
645 | c = CERT_FindCertByDERCert(CERT_GetDefaultCertDB(), &foundChain->certs[count]); | ||||
646 | |||||
647 | node = CERT_LIST_HEAD(peerCertChain)((CERTCertListNode *)(&peerCertChain->list)->next); | ||||
648 | while (!CERT_LIST_END(node, peerCertChain)(((void *)node) == ((void *)&peerCertChain->list))) { | ||||
649 | CERTCertificate *cert = node->cert; | ||||
650 | if (CERT_CompareCerts(cert, c)) { | ||||
651 | wasSentByServer = PR_TRUE1; | ||||
652 | break; | ||||
653 | } | ||||
654 | node = CERT_LIST_NEXT(node)((CERTCertListNode *)node->links.next); | ||||
655 | } | ||||
656 | |||||
657 | if (!wasSentByServer) { | ||||
658 | SECU_PrintSignedContent(stderrstderr, &c->derCert, "Certificate", 0, | ||||
659 | dumpFunction); | ||||
660 | if (dumpCertPEM) { | ||||
661 | dumpCertificatePEM(c); | ||||
662 | } | ||||
663 | } | ||||
664 | CERT_DestroyCertificate(c); | ||||
665 | } | ||||
666 | CERT_DestroyCertificateList(foundChain); | ||||
667 | } | ||||
668 | if (peerCert) { | ||||
669 | CERT_DestroyCertificate(peerCert); | ||||
670 | } | ||||
671 | |||||
672 | CERT_DestroyCertList(peerCertChain); | ||||
673 | peerCertChain = NULL((void*)0); | ||||
674 | } | ||||
675 | |||||
676 | fprintf(stderrstderr, "==== end of certificate chain information ====\n"); | ||||
677 | fflush(stderrstderr); | ||||
678 | } | ||||
679 | |||||
680 | static SECStatus | ||||
681 | ownAuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig, | ||||
682 | PRBool isServer) | ||||
683 | { | ||||
684 | ServerCertAuth *serverCertAuth = (ServerCertAuth *)arg; | ||||
685 | |||||
686 | if (dumpServerChain) { | ||||
687 | dumpServerCertificateChain(fd); | ||||
688 | } | ||||
689 | |||||
690 | if (!serverCertAuth->shouldPause) { | ||||
691 | CERTCertificate *cert; | ||||
692 | unsigned int i; | ||||
693 | const SECItemArray *csa; | ||||
694 | |||||
695 | if (!serverCertAuth->testFreshStatusFromSideChannel) { | ||||
696 | return SSL_AuthCertificate(serverCertAuth->dbHandle, | ||||
697 | fd, checkSig, isServer); | ||||
698 | } | ||||
699 | |||||
700 | /* No verification attempt must have happened before now, | ||||
701 | * to ensure revocation data has been actively retrieved yet, | ||||
702 | * or our test will produce incorrect results. | ||||
703 | */ | ||||
704 | |||||
705 | cert = SSL_RevealCert(fd); | ||||
706 | if (!cert) { | ||||
707 | exit(254); | ||||
708 | } | ||||
709 | |||||
710 | csa = SSL_PeerStapledOCSPResponses(fd); | ||||
711 | if (csa) { | ||||
712 | for (i = 0; i < csa->len; ++i) { | ||||
713 | PORT_SetErrorPORT_SetError_Util(0); | ||||
714 | if (CERT_CacheOCSPResponseFromSideChannel( | ||||
715 | serverCertAuth->dbHandle, cert, PR_Now(), | ||||
716 | &csa->items[i], arg) != SECSuccess) { | ||||
717 | PORT_Assert(PR_GetError() != 0)((PR_GetError() != 0)?((void)0):PR_Assert("PR_GetError() != 0" ,"tstclnt.c",717)); | ||||
718 | } | ||||
719 | } | ||||
720 | } | ||||
721 | |||||
722 | verifyFromSideChannel(cert, serverCertAuth); | ||||
723 | CERT_DestroyCertificate(cert); | ||||
724 | /* return success to ensure our caller will continue and we will | ||||
725 | * reach the code that handles | ||||
726 | * serverCertAuth->sideChannelRevocationTestResultCode | ||||
727 | */ | ||||
728 | return SECSuccess; | ||||
729 | } | ||||
730 | |||||
731 | FPRINTFif (verbose) fprintf(stderrstderr, "%s: using asynchronous certificate validation\n", | ||||
732 | progName); | ||||
733 | |||||
734 | PORT_Assert(!serverCertAuth->isPaused)((!serverCertAuth->isPaused)?((void)0):PR_Assert("!serverCertAuth->isPaused" ,"tstclnt.c",734)); | ||||
735 | serverCertAuth->isPaused = PR_TRUE1; | ||||
736 | return SECWouldBlock; | ||||
737 | } | ||||
738 | |||||
739 | struct clientCertAsyncParamsStr { | ||||
740 | void *arg; /* The nickname used for selection, not owned */ | ||||
741 | struct CERTDistNamesStr *caNames; /* CA Names specified by Server, owned. */ | ||||
742 | }; | ||||
743 | |||||
744 | /* tstclnt can only have a single handshake in progress at any instant. */ | ||||
745 | PRBool clientCertAsyncSelect = PR_TRUE1; /* Async by default */ | ||||
746 | PRBool clientCertIsBlocked = PR_FALSE0; /* Whether we waiting to finish ClientAuth */ | ||||
747 | struct clientCertAsyncParamsStr *clientCertParams = NULL((void*)0); | ||||
748 | |||||
749 | SECStatus | ||||
750 | own_CompleteClientAuthData(PRFileDesc *fd, struct clientCertAsyncParamsStr *args) | ||||
751 | { | ||||
752 | SECStatus rv; | ||||
753 | CERTCertificate *pRetCert = NULL((void*)0); | ||||
754 | SECKEYPrivateKey *pRetKey = NULL((void*)0); | ||||
755 | rv = NSS_GetClientAuthData(args->arg, fd, args->caNames, &pRetCert, &pRetKey); | ||||
| |||||
756 | if (rv != SECSuccess) { | ||||
757 | fprintf(stderrstderr, "Failed to load a suitable client certificate \n"); | ||||
758 | } | ||||
759 | return SSL_ClientCertCallbackComplete(fd, rv, pRetKey, pRetCert); | ||||
760 | } | ||||
761 | |||||
762 | SECStatus | ||||
763 | restartHandshakeAfterClientCertIfNeeded(PRFileDesc *fd) | ||||
764 | { | ||||
765 | if (!clientCertIsBlocked) { | ||||
766 | return SECFailure; | ||||
767 | } | ||||
768 | clientCertIsBlocked = PR_FALSE0; | ||||
769 | own_CompleteClientAuthData(fd, clientCertParams); | ||||
770 | CERT_FreeDistNames(clientCertParams->caNames); | ||||
771 | PORT_FreePORT_Free_Util(clientCertParams); | ||||
772 | clientCertParams = NULL((void*)0); | ||||
773 | return SECSuccess; | ||||
774 | } | ||||
775 | |||||
776 | SECStatus | ||||
777 | own_GetClientAuthData(void *arg, | ||||
778 | PRFileDesc *socket, | ||||
779 | struct CERTDistNamesStr *caNames, | ||||
780 | struct CERTCertificateStr **pRetCert, | ||||
781 | struct SECKEYPrivateKeyStr **pRetKey) | ||||
782 | { | ||||
783 | if (clientCertAsyncSelect) { | ||||
784 | PR_ASSERT(!clientCertIsBlocked)((!clientCertIsBlocked)?((void)0):PR_Assert("!clientCertIsBlocked" ,"tstclnt.c",784)); | ||||
785 | PR_ASSERT(!clientCertParams)((!clientCertParams)?((void)0):PR_Assert("!clientCertParams", "tstclnt.c",785)); | ||||
786 | |||||
787 | clientCertIsBlocked = PR_TRUE1; | ||||
788 | clientCertParams = PORT_AllocPORT_Alloc_Util(sizeof(struct clientCertAsyncParamsStr)); | ||||
789 | if (!clientCertParams) { | ||||
790 | fprintf(stderrstderr, "Unable to allocate buffer for client cert callback\n"); | ||||
791 | exit(1); | ||||
792 | } | ||||
793 | |||||
794 | clientCertParams->arg = arg; | ||||
795 | clientCertParams->caNames = caNames ? CERT_DupDistNames(caNames) : NULL((void*)0); | ||||
796 | if (caNames && !clientCertParams->caNames) { | ||||
797 | fprintf(stderrstderr, "Unable to allocate buffer for client cert callback\n"); | ||||
798 | exit(1); | ||||
799 | } | ||||
800 | return SECWouldBlock; | ||||
801 | } | ||||
802 | |||||
803 | if (verbose > 1) { | ||||
804 | SECStatus rv; | ||||
805 | fprintf(stderrstderr, "Server requested Client Authentication\n"); | ||||
806 | if (caNames && caNames->nnames > 0) { | ||||
807 | PLArenaPool *arena = caNames->arena; | ||||
808 | if (!arena) | ||||
809 | arena = PORT_NewArenaPORT_NewArena_Util(2048); | ||||
810 | if (arena) { | ||||
811 | int i; | ||||
812 | for (i = 0; i < caNames->nnames; ++i) { | ||||
813 | char *nameString; | ||||
814 | CERTName dn; | ||||
815 | rv = SEC_QuickDERDecodeItemSEC_QuickDERDecodeItem_Util(arena, | ||||
816 | &dn, | ||||
817 | SEC_ASN1_GET(CERT_NameTemplate)CERT_NameTemplate, | ||||
818 | caNames->names + i); | ||||
819 | if (rv != SECSuccess) | ||||
820 | continue; | ||||
821 | nameString = CERT_NameToAscii(&dn); | ||||
822 | if (!nameString) | ||||
823 | continue; | ||||
824 | fprintf(stderrstderr, "CA[%d]: %s\n", i + 1, nameString); | ||||
825 | PORT_FreePORT_Free_Util(nameString); | ||||
826 | } | ||||
827 | if (!caNames->arena) { | ||||
828 | PORT_FreeArenaPORT_FreeArena_Util(arena, PR_FALSE0); | ||||
829 | } | ||||
830 | } | ||||
831 | } | ||||
832 | rv = NSS_GetClientAuthData(arg, socket, caNames, pRetCert, pRetKey); | ||||
833 | if (rv == SECSuccess && *pRetCert) { | ||||
834 | char *nameString = CERT_NameToAscii(&((*pRetCert)->subject)); | ||||
835 | if (nameString) { | ||||
836 | fprintf(stderrstderr, "sent cert: %s\n", nameString); | ||||
837 | PORT_FreePORT_Free_Util(nameString); | ||||
838 | } | ||||
839 | } else { | ||||
840 | fprintf(stderrstderr, "send no cert\n"); | ||||
841 | } | ||||
842 | return rv; | ||||
843 | } | ||||
844 | return NSS_GetClientAuthData(arg, socket, caNames, pRetCert, pRetKey); | ||||
845 | } | ||||
846 | |||||
847 | #if defined(WIN32) || defined(OS2) | ||||
848 | void | ||||
849 | thread_main(void *arg) | ||||
850 | { | ||||
851 | PRFileDesc *ps = (PRFileDesc *)arg; | ||||
852 | PRFileDesc *std_in; | ||||
853 | int wc, rc; | ||||
854 | char buf[256]; | ||||
855 | |||||
856 | if (requestFile) { | ||||
857 | std_in = PR_Open(requestFile, PR_RDONLY0x01, 0); | ||||
858 | } else { | ||||
859 | std_in = PR_GetSpecialFD(PR_StandardInput); | ||||
860 | } | ||||
861 | |||||
862 | #ifdef WIN32 | ||||
863 | if (!requestFile) { | ||||
864 | /* Put stdin into O_BINARY mode | ||||
865 | ** or else incoming \r\n's will become \n's. | ||||
866 | */ | ||||
867 | int smrv = _setmode(_fileno(stdinstdin), _O_BINARY); | ||||
868 | if (smrv == -1) { | ||||
869 | fprintf(stderrstderr, | ||||
870 | "%s: Cannot change stdin to binary mode. Use -i option instead.\n", | ||||
871 | progName); | ||||
872 | /* plow ahead anyway */ | ||||
873 | } | ||||
874 | } | ||||
875 | #endif | ||||
876 | |||||
877 | do { | ||||
878 | rc = PR_Read(std_in, buf, sizeof buf); | ||||
879 | if (rc <= 0) | ||||
880 | break; | ||||
881 | wc = PR_Send(ps, buf, rc, 0, maxInterval); | ||||
882 | } while (wc == rc); | ||||
883 | PR_Close(ps); | ||||
884 | if (requestFile) { | ||||
885 | PR_Close(std_in); | ||||
886 | } | ||||
887 | } | ||||
888 | |||||
889 | #endif | ||||
890 | |||||
891 | static void | ||||
892 | printHostNameAndAddr(const char *host, const PRNetAddr *addr) | ||||
893 | { | ||||
894 | PRUint16 port = PR_NetAddrInetPort(addr)((addr)->raw.family == 10 ? (addr)->ipv6.port : (addr)-> inet.port); | ||||
895 | char addrBuf[80]; | ||||
896 | PRStatus st = PR_NetAddrToString(addr, addrBuf, sizeof addrBuf); | ||||
897 | |||||
898 | if (st == PR_SUCCESS) { | ||||
899 | port = PR_ntohs(port); | ||||
900 | FPRINTFif (verbose) fprintf(stderrstderr, "%s: connecting to %s:%hu (address=%s)\n", | ||||
901 | progName, host, port, addrBuf); | ||||
902 | } | ||||
903 | } | ||||
904 | |||||
905 | /* | ||||
906 | * Prints output according to skipProtoHeader flag. If skipProtoHeader | ||||
907 | * is not set, prints without any changes, otherwise looking | ||||
908 | * for \n\r\n(empty line sequence: HTTP header separator) and | ||||
909 | * prints everything after it. | ||||
910 | */ | ||||
911 | static void | ||||
912 | separateReqHeader(const PRFileDesc *outFd, const char *buf, const int nb, | ||||
913 | PRBool *wrStarted, int *ptrnMatched) | ||||
914 | { | ||||
915 | |||||
916 | /* it is sufficient to look for only "\n\r\n". Hopping that | ||||
917 | * HTTP response format satisfies the standard */ | ||||
918 | char *ptrnStr = "\n\r\n"; | ||||
919 | char *resPtr; | ||||
920 | |||||
921 | if (nb == 0) { | ||||
922 | return; | ||||
923 | } | ||||
924 | |||||
925 | if (*ptrnMatched > 0) { | ||||
926 | /* Get here only if previous separateReqHeader call found | ||||
927 | * only a fragment of "\n\r\n" in previous buffer. */ | ||||
928 | PORT_Assert(*ptrnMatched < 3)((*ptrnMatched < 3)?((void)0):PR_Assert("*ptrnMatched < 3" ,"tstclnt.c",928)); | ||||
929 | |||||
930 | /* the size of fragment of "\n\r\n" what we want to find in this | ||||
931 | * buffer is equal to *ptrnMatched */ | ||||
932 | if (*ptrnMatched <= nb) { | ||||
933 | /* move the pointer to the beginning of the fragment */ | ||||
934 | int strSize = *ptrnMatched; | ||||
935 | char *tmpPtrn = ptrnStr + (3 - strSize); | ||||
936 | if (PL_strncmp(buf, tmpPtrn, strSize) == 0) { | ||||
937 | /* print the rest of the buffer(without the fragment) */ | ||||
938 | PR_Write((void *)outFd, buf + strSize, nb - strSize); | ||||
939 | *wrStarted = PR_TRUE1; | ||||
940 | return; | ||||
941 | } | ||||
942 | } else { | ||||
943 | /* we are here only when nb == 1 && *ptrnMatched == 2 */ | ||||
944 | if (*buf == '\r') { | ||||
945 | *ptrnMatched = 1; | ||||
946 | } else { | ||||
947 | *ptrnMatched = 0; | ||||
948 | } | ||||
949 | return; | ||||
950 | } | ||||
951 | } | ||||
952 | resPtr = PL_strnstr(buf, ptrnStr, nb); | ||||
953 | if (resPtr != NULL((void*)0)) { | ||||
954 | /* if "\n\r\n" was found in the buffer, calculate offset | ||||
955 | * and print the rest of the buffer */ | ||||
956 | int newBn = nb - (resPtr - buf + 3); /* 3 is the length of "\n\r\n" */ | ||||
957 | |||||
958 | PR_Write((void *)outFd, resPtr + 3, newBn); | ||||
959 | *wrStarted = PR_TRUE1; | ||||
960 | return; | ||||
961 | } else { | ||||
962 | /* try to find a fragment of "\n\r\n" at the end of the buffer. | ||||
963 | * if found, set *ptrnMatched to the number of chars left to find | ||||
964 | * in the next buffer.*/ | ||||
965 | int i; | ||||
966 | for (i = 1; i < 3; i++) { | ||||
967 | char *bufPrt; | ||||
968 | int strSize = 3 - i; | ||||
969 | |||||
970 | if (strSize > nb) { | ||||
971 | continue; | ||||
972 | } | ||||
973 | bufPrt = (char *)(buf + nb - strSize); | ||||
974 | |||||
975 | if (PL_strncmp(bufPrt, ptrnStr, strSize) == 0) { | ||||
976 | *ptrnMatched = i; | ||||
977 | return; | ||||
978 | } | ||||
979 | } | ||||
980 | } | ||||
981 | } | ||||
982 | |||||
983 | #define SSOCK_FD0 0 | ||||
984 | #define STDIN_FD1 1 | ||||
985 | |||||
986 | #define HEXCHAR_TO_INT(c, i)if (((c) >= '0') && ((c) <= '9')) { i = (c) - '0' ; } else if (((c) >= 'a') && ((c) <= 'f')) { i = (c) - 'a' + 10; } else if (((c) >= 'A') && ((c) <= 'F')) { i = (c) - 'A' + 10; } else { Usage(); } \ | ||||
987 | if (((c) >= '0') && ((c) <= '9')) { \ | ||||
988 | i = (c) - '0'; \ | ||||
989 | } else if (((c) >= 'a') && ((c) <= 'f')) { \ | ||||
990 | i = (c) - 'a' + 10; \ | ||||
991 | } else if (((c) >= 'A') && ((c) <= 'F')) { \ | ||||
992 | i = (c) - 'A' + 10; \ | ||||
993 | } else { \ | ||||
994 | Usage(); \ | ||||
995 | } | ||||
996 | |||||
997 | static SECStatus | ||||
998 | restartHandshakeAfterServerCertIfNeeded(PRFileDesc *fd, | ||||
999 | ServerCertAuth *serverCertAuth, | ||||
1000 | PRBool override) | ||||
1001 | { | ||||
1002 | SECStatus rv; | ||||
1003 | PRErrorCode error = 0; | ||||
1004 | |||||
1005 | if (!serverCertAuth->isPaused || clientCertIsBlocked) | ||||
1006 | return SECSuccess; | ||||
1007 | |||||
1008 | FPRINTFif (verbose) fprintf(stderrstderr, "%s: handshake was paused by auth certificate hook\n", | ||||
1009 | progName); | ||||
1010 | |||||
1011 | serverCertAuth->isPaused = PR_FALSE0; | ||||
1012 | rv = SSL_AuthCertificate(serverCertAuth->dbHandle, fd, PR_TRUE1, PR_FALSE0); | ||||
1013 | if (rv != SECSuccess) { | ||||
1014 | error = PR_GetError(); | ||||
1015 | if (error == 0) { | ||||
1016 | PR_NOT_REACHED("SSL_AuthCertificate return SECFailure without "PR_Assert("SSL_AuthCertificate return SECFailure without " "setting error code." ,"tstclnt.c",1017) | ||||
1017 | "setting error code.")PR_Assert("SSL_AuthCertificate return SECFailure without " "setting error code." ,"tstclnt.c",1017); | ||||
1018 | error = PR_INVALID_STATE_ERROR(-5931L); | ||||
1019 | } else if (override) { | ||||
1020 | rv = ownBadCertHandler(NULL((void*)0), fd); | ||||
1021 | } | ||||
1022 | } | ||||
1023 | if (rv == SECSuccess) { | ||||
1024 | error = 0; | ||||
1025 | } | ||||
1026 | |||||
1027 | if (SSL_AuthCertificateComplete(fd, error) != SECSuccess) { | ||||
1028 | rv = SECFailure; | ||||
1029 | } else { | ||||
1030 | /* restore the original error code, which could be reset by | ||||
1031 | * SSL_AuthCertificateComplete */ | ||||
1032 | PORT_SetErrorPORT_SetError_Util(error); | ||||
1033 | } | ||||
1034 | |||||
1035 | return rv; | ||||
1036 | } | ||||
1037 | |||||
1038 | char *host = NULL((void*)0); | ||||
1039 | char *nickname = NULL((void*)0); | ||||
1040 | char *cipherString = NULL((void*)0); | ||||
1041 | int multiplier = 0; | ||||
1042 | SSLVersionRange enabledVersions; | ||||
1043 | int disableLocking = 0; | ||||
1044 | int enableSessionTickets = 0; | ||||
1045 | int enableFalseStart = 0; | ||||
1046 | int enableCertStatus = 0; | ||||
1047 | int enableSignedCertTimestamps = 0; | ||||
1048 | int forceFallbackSCSV = 0; | ||||
1049 | int enableExtendedMasterSecret = 0; | ||||
1050 | PRBool requireDHNamedGroups = 0; | ||||
1051 | PRBool middleboxCompatMode = 0; | ||||
1052 | PRSocketOptionData opt; | ||||
1053 | PRNetAddr addr; | ||||
1054 | PRBool allowIPv4 = PR_TRUE1; | ||||
1055 | PRBool allowIPv6 = PR_TRUE1; | ||||
1056 | PRBool pingServerFirst = PR_FALSE0; | ||||
1057 | int pingTimeoutSeconds = -1; | ||||
1058 | PRBool clientSpeaksFirst = PR_FALSE0; | ||||
1059 | PRBool skipProtoHeader = PR_FALSE0; | ||||
1060 | ServerCertAuth serverCertAuth; | ||||
1061 | char *hs1SniHostName = NULL((void*)0); | ||||
1062 | char *hs2SniHostName = NULL((void*)0); | ||||
1063 | PRUint16 portno = 443; | ||||
1064 | int override = 0; | ||||
1065 | PRBool enableZeroRtt = PR_FALSE0; | ||||
1066 | PRUint8 *zeroRttData; | ||||
1067 | unsigned int zeroRttLen = 0; | ||||
1068 | PRBool enableAltServerHello = PR_FALSE0; | ||||
1069 | PRBool useDTLS = PR_FALSE0; | ||||
1070 | PRBool actAsServer = PR_FALSE0; | ||||
1071 | PRBool stopAfterHandshake = PR_FALSE0; | ||||
1072 | PRBool requestToExit = PR_FALSE0; | ||||
1073 | char *versionString = NULL((void*)0); | ||||
1074 | PRBool handshakeComplete = PR_FALSE0; | ||||
1075 | char *echConfigs = NULL((void*)0); | ||||
1076 | PRUint16 echGreaseSize = 0; | ||||
1077 | PRBool enablePostHandshakeAuth = PR_FALSE0; | ||||
1078 | PRBool enableDelegatedCredentials = PR_FALSE0; | ||||
1079 | const secuExporter *enabledExporters = NULL((void*)0); | ||||
1080 | unsigned int enabledExporterCount = 0; | ||||
1081 | |||||
1082 | static int | ||||
1083 | writeBytesToServer(PRFileDesc *s, const PRUint8 *buf, int nb) | ||||
1084 | { | ||||
1085 | SECStatus rv; | ||||
1086 | const PRUint8 *bufp = buf; | ||||
1087 | PRPollDesc pollDesc; | ||||
1088 | |||||
1089 | pollDesc.in_flags = PR_POLL_WRITE0x2 | PR_POLL_EXCEPT0x4; | ||||
1090 | pollDesc.out_flags = 0; | ||||
1091 | pollDesc.fd = s; | ||||
1092 | |||||
1093 | FPRINTFif (verbose) fprintf(stderrstderr, "%s: Writing %d bytes to server\n", | ||||
1094 | progName, nb); | ||||
1095 | do { | ||||
1096 | PRInt32 cc = PR_Send(s, bufp, nb, 0, maxInterval); | ||||
1097 | if (cc < 0) { | ||||
1098 | PRErrorCode err = PR_GetError(); | ||||
1099 | if (err != PR_WOULD_BLOCK_ERROR(-5998L)) { | ||||
1100 | SECU_PrintError(progName, "write to SSL socket failed"); | ||||
1101 | return 254; | ||||
1102 | } | ||||
1103 | cc = 0; | ||||
1104 | } | ||||
1105 | FPRINTFif (verbose) fprintf(stderrstderr, "%s: %d bytes written\n", progName, cc); | ||||
1106 | if (enableZeroRtt && !handshakeComplete) { | ||||
1107 | if (zeroRttLen + cc > ZERO_RTT_MAX(2 << 16)) { | ||||
1108 | SECU_PrintError(progName, "too much early data to save"); | ||||
1109 | return -1; | ||||
1110 | } | ||||
1111 | PORT_Memcpymemcpy(zeroRttData + zeroRttLen, bufp, cc); | ||||
1112 | zeroRttLen += cc; | ||||
1113 | } | ||||
1114 | bufp += cc; | ||||
1115 | nb -= cc; | ||||
1116 | if (nb <= 0) | ||||
1117 | break; | ||||
1118 | |||||
1119 | rv = restartHandshakeAfterServerCertIfNeeded(s, | ||||
1120 | &serverCertAuth, override); | ||||
1121 | if (rv != SECSuccess) { | ||||
1122 | SECU_PrintError(progName, "authentication of server cert failed"); | ||||
1123 | return EXIT_CODE_HANDSHAKE_FAILED254; | ||||
1124 | } | ||||
1125 | |||||
1126 | rv = restartHandshakeAfterClientCertIfNeeded(s); | ||||
1127 | if (rv == SECSuccess) { | ||||
1128 | continue; | ||||
1129 | } | ||||
1130 | |||||
1131 | pollDesc.in_flags = PR_POLL_WRITE0x2 | PR_POLL_EXCEPT0x4; | ||||
1132 | pollDesc.out_flags = 0; | ||||
1133 | FPRINTFif (verbose) fprintf(stderrstderr, | ||||
1134 | "%s: about to call PR_Poll on writable socket !\n", | ||||
1135 | progName); | ||||
1136 | cc = PR_Poll(&pollDesc, 1, PR_INTERVAL_NO_TIMEOUT0xffffffffUL); | ||||
1137 | if (cc < 0) { | ||||
1138 | SECU_PrintError(progName, "PR_Poll failed"); | ||||
1139 | return -1; | ||||
1140 | } | ||||
1141 | FPRINTFif (verbose) fprintf(stderrstderr, | ||||
1142 | "%s: PR_Poll returned with writable socket !\n", | ||||
1143 | progName); | ||||
1144 | } while (1); | ||||
1145 | |||||
1146 | return 0; | ||||
1147 | } | ||||
1148 | |||||
1149 | void | ||||
1150 | handshakeCallback(PRFileDesc *fd, void *client_data) | ||||
1151 | { | ||||
1152 | const char *secondHandshakeName = (char *)client_data; | ||||
1153 | if (secondHandshakeName) { | ||||
1154 | SSL_SetURL(fd, secondHandshakeName); | ||||
1155 | } | ||||
1156 | printSecurityInfo(fd); | ||||
1157 | if (renegotiationsDone < renegotiationsToDo) { | ||||
1158 | SSL_ReHandshake(fd, (renegotiationsToDo < 2)); | ||||
1159 | ++renegotiationsDone; | ||||
1160 | } | ||||
1161 | if (zeroRttLen) { | ||||
1162 | /* This data was sent in 0-RTT. */ | ||||
1163 | SSLChannelInfo info; | ||||
1164 | SECStatus rv; | ||||
1165 | |||||
1166 | rv = SSL_GetChannelInfo(fd, &info, sizeof(info)); | ||||
1167 | if (rv != SECSuccess) | ||||
1168 | return; | ||||
1169 | |||||
1170 | if (!info.earlyDataAccepted) { | ||||
1171 | FPRINTFif (verbose) fprintf(stderrstderr, "Early data rejected. Re-sending %d bytes\n", | ||||
1172 | zeroRttLen); | ||||
1173 | writeBytesToServer(fd, zeroRttData, zeroRttLen); | ||||
1174 | zeroRttLen = 0; | ||||
1175 | } | ||||
1176 | } | ||||
1177 | if (stopAfterHandshake) { | ||||
1178 | requestToExit = PR_TRUE1; | ||||
1179 | } | ||||
1180 | handshakeComplete = PR_TRUE1; | ||||
1181 | |||||
1182 | if (enabledExporters) { | ||||
1183 | SECStatus rv; | ||||
1184 | |||||
1185 | rv = exportKeyingMaterials(fd, enabledExporters, enabledExporterCount); | ||||
1186 | if (rv != SECSuccess) { | ||||
1187 | PRErrorCode err = PR_GetError(); | ||||
1188 | FPRINTFif (verbose) fprintf(stderrstderr, | ||||
1189 | "couldn't export keying material: %s\n", | ||||
1190 | SECU_Strerror(err)PR_ErrorToString((err), 0)); | ||||
1191 | } | ||||
1192 | } | ||||
1193 | } | ||||
1194 | |||||
1195 | static SECStatus | ||||
1196 | installServerCertificate(PRFileDesc *s, char *nick) | ||||
1197 | { | ||||
1198 | CERTCertificate *cert; | ||||
1199 | SECKEYPrivateKey *privKey = NULL((void*)0); | ||||
1200 | |||||
1201 | if (!nick) { | ||||
1202 | PORT_SetErrorPORT_SetError_Util(SEC_ERROR_INVALID_ARGS); | ||||
1203 | return SECFailure; | ||||
1204 | } | ||||
1205 | |||||
1206 | cert = PK11_FindCertFromNickname(nick, &pwdata); | ||||
1207 | if (cert == NULL((void*)0)) { | ||||
1208 | return SECFailure; | ||||
1209 | } | ||||
1210 | |||||
1211 | privKey = PK11_FindKeyByAnyCert(cert, &pwdata); | ||||
1212 | if (privKey == NULL((void*)0)) { | ||||
1213 | return SECFailure; | ||||
1214 | } | ||||
1215 | if (SSL_ConfigServerCert(s, cert, privKey, NULL((void*)0), 0) != SECSuccess) { | ||||
1216 | return SECFailure; | ||||
1217 | } | ||||
1218 | SECKEY_DestroyPrivateKey(privKey); | ||||
1219 | CERT_DestroyCertificate(cert); | ||||
1220 | |||||
1221 | return SECSuccess; | ||||
1222 | } | ||||
1223 | |||||
1224 | static SECStatus | ||||
1225 | bindToClient(PRFileDesc *s) | ||||
1226 | { | ||||
1227 | PRStatus status; | ||||
1228 | status = PR_Bind(s, &addr); | ||||
1229 | if (status != PR_SUCCESS) { | ||||
1230 | return SECFailure; | ||||
1231 | } | ||||
1232 | |||||
1233 | for (;;) { | ||||
1234 | /* Bind the remote address on first packet. This must happen | ||||
1235 | * before we SSL-ize the socket because we need to get the | ||||
1236 | * peer's address before SSLizing. Recvfrom gives us that | ||||
1237 | * while not consuming any data. */ | ||||
1238 | unsigned char tmp; | ||||
1239 | PRNetAddr remote; | ||||
1240 | int nb; | ||||
1241 | |||||
1242 | nb = PR_RecvFrom(s, &tmp, 1, PR_MSG_PEEK0x2, | ||||
1243 | &remote, PR_INTERVAL_NO_TIMEOUT0xffffffffUL); | ||||
1244 | if (nb != 1) | ||||
1245 | continue; | ||||
1246 | |||||
1247 | status = PR_Connect(s, &remote, PR_INTERVAL_NO_TIMEOUT0xffffffffUL); | ||||
1248 | if (status != PR_SUCCESS) { | ||||
1249 | SECU_PrintError(progName, "server bind to remote end failed"); | ||||
1250 | return SECFailure; | ||||
1251 | } | ||||
1252 | return SECSuccess; | ||||
1253 | } | ||||
1254 | |||||
1255 | /* Unreachable. */ | ||||
1256 | } | ||||
1257 | |||||
1258 | static SECStatus | ||||
1259 | connectToServer(PRFileDesc *s, PRPollDesc *pollset) | ||||
1260 | { | ||||
1261 | PRStatus status; | ||||
1262 | PRInt32 filesReady; | ||||
1263 | |||||
1264 | status = PR_Connect(s, &addr, PR_INTERVAL_NO_TIMEOUT0xffffffffUL); | ||||
1265 | if (status != PR_SUCCESS) { | ||||
1266 | if (PR_GetError() == PR_IN_PROGRESS_ERROR(-5934L)) { | ||||
1267 | if (verbose) | ||||
1268 | SECU_PrintError(progName, "connect"); | ||||
1269 | milliPause(50 * multiplier); | ||||
1270 | pollset[SSOCK_FD0].in_flags = PR_POLL_WRITE0x2 | PR_POLL_EXCEPT0x4; | ||||
1271 | pollset[SSOCK_FD0].out_flags = 0; | ||||
1272 | pollset[SSOCK_FD0].fd = s; | ||||
1273 | while (1) { | ||||
1274 | FPRINTFif (verbose) fprintf(stderrstderr, | ||||
1275 | "%s: about to call PR_Poll for connect completion!\n", | ||||
1276 | progName); | ||||
1277 | filesReady = PR_Poll(pollset, 1, PR_INTERVAL_NO_TIMEOUT0xffffffffUL); | ||||
1278 | if (filesReady < 0) { | ||||
1279 | SECU_PrintError(progName, "unable to connect (poll)"); | ||||
1280 | return SECFailure; | ||||
1281 | } | ||||
1282 | FPRINTFif (verbose) fprintf(stderrstderr, | ||||
1283 | "%s: PR_Poll returned 0x%02x for socket out_flags.\n", | ||||
1284 | progName, pollset[SSOCK_FD0].out_flags); | ||||
1285 | if (filesReady == 0) { /* shouldn't happen! */ | ||||
1286 | SECU_PrintError(progName, "%s: PR_Poll returned zero!\n"); | ||||
1287 | return SECFailure; | ||||
1288 | } | ||||
1289 | status = PR_GetConnectStatus(pollset); | ||||
1290 | if (status == PR_SUCCESS) { | ||||
1291 | break; | ||||
1292 | } | ||||
1293 | if (PR_GetError() != PR_IN_PROGRESS_ERROR(-5934L)) { | ||||
1294 | SECU_PrintError(progName, "unable to connect (poll)"); | ||||
1295 | return SECFailure; | ||||
1296 | } | ||||
1297 | SECU_PrintError(progName, "poll"); | ||||
1298 | milliPause(50 * multiplier); | ||||
1299 | } | ||||
1300 | } else { | ||||
1301 | SECU_PrintError(progName, "unable to connect"); | ||||
1302 | return SECFailure; | ||||
1303 | } | ||||
1304 | } | ||||
1305 | |||||
1306 | return SECSuccess; | ||||
1307 | } | ||||
1308 | |||||
1309 | static SECStatus | ||||
1310 | importPsk(PRFileDesc *s) | ||||
1311 | { | ||||
1312 | SECU_PrintAsHex(stdoutstdout, &psk, "Using External PSK", 0); | ||||
1313 | PK11SlotInfo *slot = NULL((void*)0); | ||||
1314 | PK11SymKey *symKey = NULL((void*)0); | ||||
1315 | slot = PK11_GetInternalSlot(); | ||||
1316 | if (!slot) { | ||||
1317 | SECU_PrintError(progName, "PK11_GetInternalSlot failed"); | ||||
1318 | return SECFailure; | ||||
1319 | } | ||||
1320 | symKey = PK11_ImportSymKey(slot, CKM_HKDF_KEY_GEN0x0000402cUL, PK11_OriginUnwrap, | ||||
1321 | CKA_DERIVE0x0000010CUL, &psk, NULL((void*)0)); | ||||
1322 | PK11_FreeSlot(slot); | ||||
1323 | if (!symKey) { | ||||
1324 | SECU_PrintError(progName, "PK11_ImportSymKey failed"); | ||||
1325 | return SECFailure; | ||||
1326 | } | ||||
1327 | |||||
1328 | SECStatus rv = SSL_AddExternalPsk(s, symKey, (const PRUint8 *)pskLabel.data,(SSL_GetExperimentalAPI("SSL_AddExternalPsk") ? ((SECStatus(* ) (PRFileDesc * _fd, PK11SymKey * _psk, const PRUint8 *_identity , unsigned int _identityLen, SSLHashType _hash))SSL_GetExperimentalAPI ("SSL_AddExternalPsk"))(s, symKey, (const PRUint8 *)pskLabel. data, pskLabel.len, ssl_hash_sha256) : SECFailure) | ||||
1329 | pskLabel.len, ssl_hash_sha256)(SSL_GetExperimentalAPI("SSL_AddExternalPsk") ? ((SECStatus(* ) (PRFileDesc * _fd, PK11SymKey * _psk, const PRUint8 *_identity , unsigned int _identityLen, SSLHashType _hash))SSL_GetExperimentalAPI ("SSL_AddExternalPsk"))(s, symKey, (const PRUint8 *)pskLabel. data, pskLabel.len, ssl_hash_sha256) : SECFailure); | ||||
1330 | PK11_FreeSymKey(symKey); | ||||
1331 | return rv; | ||||
1332 | } | ||||
1333 | |||||
1334 | static SECStatus | ||||
1335 | printEchRetryConfigs(PRFileDesc *s) | ||||
1336 | { | ||||
1337 | if (PORT_GetErrorPORT_GetError_Util() == SSL_ERROR_ECH_RETRY_WITH_ECH) { | ||||
1338 | SECItem retries = { siBuffer, NULL((void*)0), 0 }; | ||||
1339 | SECStatus rv = SSL_GetEchRetryConfigs(s, &retries)(SSL_GetExperimentalAPI("SSL_GetEchRetryConfigs") ? ((SECStatus (*) (PRFileDesc * _fd, SECItem * _out))SSL_GetExperimentalAPI ("SSL_GetEchRetryConfigs"))(s, &retries) : SECFailure); | ||||
1340 | if (rv != SECSuccess) { | ||||
1341 | SECU_PrintError(progName, "SSL_GetEchRetryConfigs failed"); | ||||
1342 | return SECFailure; | ||||
1343 | } | ||||
1344 | char *retriesBase64 = NSSBase64_EncodeItemNSSBase64_EncodeItem_Util(NULL((void*)0), NULL((void*)0), 0, &retries); | ||||
1345 | if (!retriesBase64) { | ||||
1346 | SECU_PrintError(progName, "NSSBase64_EncodeItem on retry_configs failed"); | ||||
1347 | SECITEM_FreeItemSECITEM_FreeItem_Util(&retries, PR_FALSE0); | ||||
1348 | return SECFailure; | ||||
1349 | } | ||||
1350 | |||||
1351 | // Remove the newline characters that NSSBase64_EncodeItem unhelpfully inserts. | ||||
1352 | char *newline = strstr(retriesBase64, "\r\n"); | ||||
1353 | if (newline) { | ||||
1354 | memmove(newline, newline + 2, strlen(newline + 2) + 1); | ||||
1355 | } | ||||
1356 | fprintf(stderrstderr, "Received ECH retry_configs: \n%s\n", retriesBase64); | ||||
1357 | PORT_FreePORT_Free_Util(retriesBase64); | ||||
1358 | SECITEM_FreeItemSECITEM_FreeItem_Util(&retries, PR_FALSE0); | ||||
1359 | } | ||||
1360 | return SECSuccess; | ||||
1361 | } | ||||
1362 | |||||
1363 | static int | ||||
1364 | run() | ||||
1365 | { | ||||
1366 | int headerSeparatorPtrnId = 0; | ||||
1367 | int error = 0; | ||||
1368 | SECStatus rv; | ||||
1369 | PRStatus status; | ||||
1370 | PRInt32 filesReady; | ||||
1371 | PRFileDesc *s = NULL((void*)0); | ||||
1372 | PRFileDesc *std_out; | ||||
1373 | PRPollDesc pollset[2] = { { 0 }, { 0 } }; | ||||
1374 | PRBool wrStarted = PR_FALSE0; | ||||
1375 | |||||
1376 | handshakeComplete = PR_FALSE0; | ||||
1377 | |||||
1378 | /* Create socket */ | ||||
1379 | if (useDTLS) { | ||||
| |||||
1380 | s = PR_OpenUDPSocket(addr.raw.family); | ||||
1381 | } else { | ||||
1382 | s = PR_OpenTCPSocket(addr.raw.family); | ||||
1383 | } | ||||
1384 | |||||
1385 | if (s == NULL((void*)0)) { | ||||
1386 | SECU_PrintError(progName, "error creating socket"); | ||||
1387 | error = 1; | ||||
1388 | goto done; | ||||
1389 | } | ||||
1390 | |||||
1391 | if (actAsServer) { | ||||
1392 | if (bindToClient(s) != SECSuccess) { | ||||
1393 | return 1; | ||||
1394 | } | ||||
1395 | } | ||||
1396 | opt.option = PR_SockOpt_Nonblocking; | ||||
1397 | opt.value.non_blocking = PR_TRUE1; /* default */ | ||||
1398 | if (serverCertAuth.testFreshStatusFromSideChannel) { | ||||
1399 | opt.value.non_blocking = PR_FALSE0; | ||||
1400 | } | ||||
1401 | status = PR_SetSocketOption(s, &opt); | ||||
1402 | if (status != PR_SUCCESS) { | ||||
1403 | SECU_PrintError(progName, "error setting socket options"); | ||||
1404 | error = 1; | ||||
1405 | goto done; | ||||
1406 | } | ||||
1407 | |||||
1408 | if (useDTLS) { | ||||
1409 | s = DTLS_ImportFD(NULL((void*)0), s); | ||||
1410 | } else { | ||||
1411 | s = SSL_ImportFD(NULL((void*)0), s); | ||||
1412 | } | ||||
1413 | if (s == NULL((void*)0)) { | ||||
1414 | SECU_PrintError(progName, "error importing socket"); | ||||
1415 | error = 1; | ||||
1416 | goto done; | ||||
1417 | } | ||||
1418 | SSL_SetPKCS11PinArg(s, &pwdata); | ||||
1419 | |||||
1420 | rv = SSL_OptionSet(s, SSL_SECURITY1, 1); | ||||
1421 | if (rv != SECSuccess) { | ||||
1422 | SECU_PrintError(progName, "error enabling socket"); | ||||
1423 | error = 1; | ||||
1424 | goto done; | ||||
1425 | } | ||||
1426 | |||||
1427 | rv = SSL_OptionSet(s, actAsServer ? SSL_HANDSHAKE_AS_SERVER6 : SSL_HANDSHAKE_AS_CLIENT5, 1); | ||||
1428 | if (rv != SECSuccess) { | ||||
1429 | SECU_PrintError(progName, "error enabling client handshake"); | ||||
1430 | error = 1; | ||||
1431 | goto done; | ||||
1432 | } | ||||
1433 | |||||
1434 | /* all SSL3 cipher suites are enabled by default. */ | ||||
1435 | if (cipherString) { | ||||
1436 | char *cstringSaved = cipherString; | ||||
1437 | int ndx; | ||||
1438 | |||||
1439 | while (0 != (ndx = *cipherString++)) { | ||||
1440 | int cipher = 0; | ||||
1441 | |||||
1442 | if (ndx == ':') { | ||||
1443 | int ctmp = 0; | ||||
1444 | |||||
1445 | HEXCHAR_TO_INT(*cipherString, ctmp)if (((*cipherString) >= '0') && ((*cipherString) <= '9')) { ctmp = (*cipherString) - '0'; } else if (((*cipherString ) >= 'a') && ((*cipherString) <= 'f')) { ctmp = (*cipherString) - 'a' + 10; } else if (((*cipherString) >= 'A') && ((*cipherString) <= 'F')) { ctmp = (*cipherString ) - 'A' + 10; } else { Usage(); } | ||||
1446 | cipher |= (ctmp << 12); | ||||
1447 | cipherString++; | ||||
1448 | HEXCHAR_TO_INT(*cipherString, ctmp)if (((*cipherString) >= '0') && ((*cipherString) <= '9')) { ctmp = (*cipherString) - '0'; } else if (((*cipherString ) >= 'a') && ((*cipherString) <= 'f')) { ctmp = (*cipherString) - 'a' + 10; } else if (((*cipherString) >= 'A') && ((*cipherString) <= 'F')) { ctmp = (*cipherString ) - 'A' + 10; } else { Usage(); } | ||||
1449 | cipher |= (ctmp << 8); | ||||
1450 | cipherString++; | ||||
1451 | HEXCHAR_TO_INT(*cipherString, ctmp)if (((*cipherString) >= '0') && ((*cipherString) <= '9')) { ctmp = (*cipherString) - '0'; } else if (((*cipherString ) >= 'a') && ((*cipherString) <= 'f')) { ctmp = (*cipherString) - 'a' + 10; } else if (((*cipherString) >= 'A') && ((*cipherString) <= 'F')) { ctmp = (*cipherString ) - 'A' + 10; } else { Usage(); } | ||||
1452 | cipher |= (ctmp << 4); | ||||
1453 | cipherString++; | ||||
1454 | HEXCHAR_TO_INT(*cipherString, ctmp)if (((*cipherString) >= '0') && ((*cipherString) <= '9')) { ctmp = (*cipherString) - '0'; } else if (((*cipherString ) >= 'a') && ((*cipherString) <= 'f')) { ctmp = (*cipherString) - 'a' + 10; } else if (((*cipherString) >= 'A') && ((*cipherString) <= 'F')) { ctmp = (*cipherString ) - 'A' + 10; } else { Usage(); } | ||||
1455 | cipher |= ctmp; | ||||
1456 | cipherString++; | ||||
1457 | } else { | ||||
1458 | if (!isalpha(ndx)((*__ctype_b_loc ())[(int) ((ndx))] & (unsigned short int ) _ISalpha)) | ||||
1459 | Usage(); | ||||
1460 | ndx = tolower(ndx) - 'a'; | ||||
1461 | if (ndx < PR_ARRAY_SIZE(ssl3CipherSuites)(sizeof(ssl3CipherSuites)/sizeof((ssl3CipherSuites)[0]))) { | ||||
1462 | cipher = ssl3CipherSuites[ndx]; | ||||
1463 | } | ||||
1464 | } | ||||
1465 | if (cipher > 0) { | ||||
1466 | rv = SSL_CipherPrefSet(s, cipher, SSL_ALLOWED1); | ||||
1467 | if (rv != SECSuccess) { | ||||
1468 | SECU_PrintError(progName, "SSL_CipherPrefSet()"); | ||||
1469 | error = 1; | ||||
1470 | goto done; | ||||
1471 | } | ||||
1472 | } else { | ||||
1473 | Usage(); | ||||
1474 | } | ||||
1475 | } | ||||
1476 | PORT_FreePORT_Free_Util(cstringSaved); | ||||
1477 | } | ||||
1478 | |||||
1479 | rv = SSL_VersionRangeSet(s, &enabledVersions); | ||||
1480 | if (rv != SECSuccess) { | ||||
1481 | SECU_PrintError(progName, "error setting SSL/TLS version range "); | ||||
1482 | error = 1; | ||||
1483 | goto done; | ||||
1484 | } | ||||
1485 | |||||
1486 | /* disable SSL socket locking */ | ||||
1487 | rv = SSL_OptionSet(s, SSL_NO_LOCKS17, disableLocking); | ||||
1488 | if (rv != SECSuccess) { | ||||
1489 | SECU_PrintError(progName, "error disabling SSL socket locking"); | ||||
1490 | error = 1; | ||||
1491 | goto done; | ||||
1492 | } | ||||
1493 | |||||
1494 | /* enable Session Ticket extension. */ | ||||
1495 | rv = SSL_OptionSet(s, SSL_ENABLE_SESSION_TICKETS18, enableSessionTickets); | ||||
1496 | if (rv != SECSuccess) { | ||||
1497 | SECU_PrintError(progName, "error enabling Session Ticket extension"); | ||||
1498 | error = 1; | ||||
1499 | goto done; | ||||
1500 | } | ||||
1501 | |||||
1502 | /* enable false start. */ | ||||
1503 | rv = SSL_OptionSet(s, SSL_ENABLE_FALSE_START22, enableFalseStart); | ||||
1504 | if (rv != SECSuccess) { | ||||
1505 | SECU_PrintError(progName, "error enabling false start"); | ||||
1506 | error = 1; | ||||
1507 | goto done; | ||||
1508 | } | ||||
1509 | |||||
1510 | if (forceFallbackSCSV) { | ||||
1511 | rv = SSL_OptionSet(s, SSL_ENABLE_FALLBACK_SCSV28, PR_TRUE1); | ||||
1512 | if (rv != SECSuccess) { | ||||
1513 | SECU_PrintError(progName, "error forcing fallback scsv"); | ||||
1514 | error = 1; | ||||
1515 | goto done; | ||||
1516 | } | ||||
1517 | } | ||||
1518 | |||||
1519 | /* enable cert status (OCSP stapling). */ | ||||
1520 | rv = SSL_OptionSet(s, SSL_ENABLE_OCSP_STAPLING24, enableCertStatus); | ||||
1521 | if (rv != SECSuccess) { | ||||
1522 | SECU_PrintError(progName, "error enabling cert status (OCSP stapling)"); | ||||
1523 | error = 1; | ||||
1524 | goto done; | ||||
1525 | } | ||||
1526 | |||||
1527 | /* enable negotiation of delegated credentials (draft-ietf-tls-subcerts) */ | ||||
1528 | rv = SSL_OptionSet(s, SSL_ENABLE_DELEGATED_CREDENTIALS40, enableDelegatedCredentials); | ||||
1529 | if (rv != SECSuccess) { | ||||
1530 | SECU_PrintError(progName, "error enabling delegated credentials"); | ||||
1531 | error = 1; | ||||
1532 | goto done; | ||||
1533 | } | ||||
1534 | |||||
1535 | /* enable extended master secret mode */ | ||||
1536 | if (enableExtendedMasterSecret) { | ||||
1537 | rv = SSL_OptionSet(s, SSL_ENABLE_EXTENDED_MASTER_SECRET30, PR_TRUE1); | ||||
1538 | if (rv != SECSuccess) { | ||||
1539 | SECU_PrintError(progName, "error enabling extended master secret"); | ||||
1540 | error = 1; | ||||
1541 | goto done; | ||||
1542 | } | ||||
1543 | } | ||||
1544 | |||||
1545 | /* enable 0-RTT (TLS 1.3 only) */ | ||||
1546 | if (enableZeroRtt) { | ||||
1547 | rv = SSL_OptionSet(s, SSL_ENABLE_0RTT_DATA33, PR_TRUE1); | ||||
1548 | if (rv != SECSuccess) { | ||||
1549 | SECU_PrintError(progName, "error enabling 0-RTT"); | ||||
1550 | error = 1; | ||||
1551 | goto done; | ||||
1552 | } | ||||
1553 | } | ||||
1554 | |||||
1555 | /* Alternate ServerHello content type (TLS 1.3 only) */ | ||||
1556 | if (enableAltServerHello) { | ||||
1557 | rv = SSL_UseAltServerHelloType(s, PR_TRUE)(PR_SetError(SSL_ERROR_UNSUPPORTED_EXPERIMENTAL_API, 0), SECFailure ); | ||||
1558 | if (rv != SECSuccess) { | ||||
1559 | SECU_PrintError(progName, "error enabling alternate ServerHello type"); | ||||
1560 | error = 1; | ||||
1561 | goto done; | ||||
1562 | } | ||||
1563 | } | ||||
1564 | |||||
1565 | /* Middlebox compatibility mode (TLS 1.3 only) */ | ||||
1566 | if (middleboxCompatMode) { | ||||
1567 | rv = SSL_OptionSet(s, SSL_ENABLE_TLS13_COMPAT_MODE35, PR_TRUE1); | ||||
1568 | if (rv != SECSuccess) { | ||||
1569 | SECU_PrintError(progName, "error enabling middlebox compatibility mode"); | ||||
1570 | error = 1; | ||||
1571 | goto done; | ||||
1572 | } | ||||
1573 | } | ||||
1574 | |||||
1575 | /* require the use of fixed finite-field DH groups */ | ||||
1576 | if (requireDHNamedGroups) { | ||||
1577 | rv = SSL_OptionSet(s, SSL_REQUIRE_DH_NAMED_GROUPS32, PR_TRUE1); | ||||
1578 | if (rv != SECSuccess) { | ||||
1579 | SECU_PrintError(progName, "error in requiring the use of fixed finite-field DH groups"); | ||||
1580 | error = 1; | ||||
1581 | goto done; | ||||
1582 | } | ||||
1583 | } | ||||
1584 | |||||
1585 | /* enable Signed Certificate Timestamps. */ | ||||
1586 | rv = SSL_OptionSet(s, SSL_ENABLE_SIGNED_CERT_TIMESTAMPS31, | ||||
1587 | enableSignedCertTimestamps); | ||||
1588 | if (rv != SECSuccess) { | ||||
1589 | SECU_PrintError(progName, "error enabling signed cert timestamps"); | ||||
1590 | error = 1; | ||||
1591 | goto done; | ||||
1592 | } | ||||
1593 | |||||
1594 | if (enablePostHandshakeAuth) { | ||||
1595 | rv = SSL_OptionSet(s, SSL_ENABLE_POST_HANDSHAKE_AUTH39, PR_TRUE1); | ||||
1596 | if (rv != SECSuccess) { | ||||
1597 | SECU_PrintError(progName, "error enabling post-handshake auth"); | ||||
1598 | error = 1; | ||||
1599 | goto done; | ||||
1600 | } | ||||
1601 | } | ||||
1602 | |||||
1603 | if (enabledGroups) { | ||||
1604 | rv = SSL_NamedGroupConfig(s, enabledGroups, enabledGroupsCount); | ||||
1605 | if (rv < 0) { | ||||
1606 | SECU_PrintError(progName, "SSL_NamedGroupConfig failed"); | ||||
1607 | error = 1; | ||||
1608 | goto done; | ||||
1609 | } | ||||
1610 | } | ||||
1611 | |||||
1612 | if (enabledSigSchemes) { | ||||
1613 | rv = SSL_SignatureSchemePrefSet(s, enabledSigSchemes, enabledSigSchemeCount); | ||||
1614 | if (rv < 0) { | ||||
1615 | SECU_PrintError(progName, "SSL_SignatureSchemePrefSet failed"); | ||||
1616 | error = 1; | ||||
1617 | goto done; | ||||
1618 | } | ||||
1619 | } | ||||
1620 | |||||
1621 | if (echConfigs) { | ||||
1622 | SECItem echConfigsBin = { siBuffer, NULL((void*)0), 0 }; | ||||
1623 | |||||
1624 | if (!NSSBase64_DecodeBufferNSSBase64_DecodeBuffer_Util(NULL((void*)0), &echConfigsBin, echConfigs, | ||||
1625 | strlen(echConfigs))) { | ||||
1626 | SECU_PrintError(progName, "ECHConfigs record is invalid base64"); | ||||
1627 | error = 1; | ||||
1628 | goto done; | ||||
1629 | } | ||||
1630 | |||||
1631 | rv = SSL_SetClientEchConfigs(s, echConfigsBin.data, echConfigsBin.len)(SSL_GetExperimentalAPI("SSL_SetClientEchConfigs") ? ((SECStatus (*) (PRFileDesc * _fd, const PRUint8 *_echConfigs, unsigned int _echConfigsLen))SSL_GetExperimentalAPI("SSL_SetClientEchConfigs" ))(s, echConfigsBin.data, echConfigsBin.len) : SECFailure); | ||||
1632 | SECITEM_FreeItemSECITEM_FreeItem_Util(&echConfigsBin, PR_FALSE0); | ||||
1633 | if (rv < 0) { | ||||
1634 | SECU_PrintError(progName, "SSL_SetClientEchConfigs failed"); | ||||
1635 | error = 1; | ||||
1636 | goto done; | ||||
1637 | } | ||||
1638 | } | ||||
1639 | |||||
1640 | if (echGreaseSize) { | ||||
1641 | rv = SSL_EnableTls13GreaseEch(s, PR_TRUE)(SSL_GetExperimentalAPI("SSL_EnableTls13GreaseEch") ? ((SECStatus (*) (PRFileDesc * _fd, PRBool _enabled))SSL_GetExperimentalAPI ("SSL_EnableTls13GreaseEch"))(s, 1) : SECFailure); | ||||
1642 | if (rv != SECSuccess) { | ||||
1643 | SECU_PrintError(progName, "SSL_EnableTls13GreaseEch failed"); | ||||
1644 | error = 1; | ||||
1645 | goto done; | ||||
1646 | } | ||||
1647 | rv = SSL_SetTls13GreaseEchSize(s, echGreaseSize)(SSL_GetExperimentalAPI("SSL_SetTls13GreaseEchSize") ? ((SECStatus (*) (PRFileDesc * _fd, PRUint8 _size))SSL_GetExperimentalAPI( "SSL_SetTls13GreaseEchSize"))(s, echGreaseSize) : SECFailure); | ||||
1648 | if (rv != SECSuccess) { | ||||
1649 | SECU_PrintError(progName, "SSL_SetTls13GreaseEchSize failed"); | ||||
1650 | error = 1; | ||||
1651 | goto done; | ||||
1652 | } | ||||
1653 | } | ||||
1654 | |||||
1655 | if (psk.data) { | ||||
1656 | rv = importPsk(s); | ||||
1657 | if (rv != SECSuccess) { | ||||
1658 | SECU_PrintError(progName, "importPsk failed"); | ||||
1659 | error = 1; | ||||
1660 | goto done; | ||||
1661 | } | ||||
1662 | } | ||||
1663 | |||||
1664 | serverCertAuth.dbHandle = CERT_GetDefaultCertDB(); | ||||
1665 | |||||
1666 | SSL_AuthCertificateHook(s, ownAuthCertificate, &serverCertAuth); | ||||
1667 | if (override) { | ||||
1668 | SSL_BadCertHook(s, ownBadCertHandler, NULL((void*)0)); | ||||
1669 | } | ||||
1670 | if (actAsServer) { | ||||
1671 | rv = installServerCertificate(s, nickname); | ||||
1672 | if (rv != SECSuccess) { | ||||
1673 | SECU_PrintError(progName, "error installing server cert"); | ||||
1674 | return 1; | ||||
1675 | } | ||||
1676 | rv = SSL_ConfigServerSessionIDCache(1024, 0, 0, "."); | ||||
1677 | if (rv != SECSuccess) { | ||||
1678 | SECU_PrintError(progName, "error configuring session cache"); | ||||
1679 | return 1; | ||||
1680 | } | ||||
1681 | initializedServerSessionCache = PR_TRUE1; | ||||
1682 | } else { | ||||
1683 | SSL_GetClientAuthDataHook(s, own_GetClientAuthData, (void *)nickname); | ||||
1684 | } | ||||
1685 | SSL_HandshakeCallback(s, handshakeCallback, hs2SniHostName); | ||||
1686 | if (hs1SniHostName) { | ||||
1687 | SSL_SetURL(s, hs1SniHostName); | ||||
1688 | } else { | ||||
1689 | SSL_SetURL(s, host); | ||||
1690 | } | ||||
1691 | |||||
1692 | if (actAsServer) { | ||||
1693 | rv = SSL_ResetHandshake(s, PR_TRUE1 /* server */); | ||||
1694 | if (rv != SECSuccess) { | ||||
1695 | return 1; | ||||
1696 | } | ||||
1697 | } else { | ||||
1698 | /* Try to connect to the server */ | ||||
1699 | rv = connectToServer(s, pollset); | ||||
1700 | if (rv != SECSuccess) { | ||||
1701 | error = 1; | ||||
1702 | goto done; | ||||
1703 | } | ||||
1704 | } | ||||
1705 | |||||
1706 | pollset[SSOCK_FD0].fd = s; | ||||
1707 | pollset[SSOCK_FD0].in_flags = PR_POLL_EXCEPT0x4; | ||||
1708 | if (!actAsServer) | ||||
1709 | pollset[SSOCK_FD0].in_flags |= (clientSpeaksFirst ? 0 : PR_POLL_READ0x1); | ||||
1710 | else | ||||
1711 | pollset[SSOCK_FD0].in_flags |= PR_POLL_READ0x1; | ||||
1712 | if (requestFile) { | ||||
1713 | pollset[STDIN_FD1].fd = PR_Open(requestFile, PR_RDONLY0x01, 0); | ||||
1714 | if (!pollset[STDIN_FD1].fd) { | ||||
1715 | fprintf(stderrstderr, "%s: unable to open input file: %s\n", | ||||
1716 | progName, requestFile); | ||||
1717 | error = 1; | ||||
1718 | goto done; | ||||
1719 | } | ||||
1720 | } else { | ||||
1721 | pollset[STDIN_FD1].fd = PR_GetSpecialFD(PR_StandardInput); | ||||
1722 | } | ||||
1723 | pollset[STDIN_FD1].in_flags = PR_POLL_READ0x1; | ||||
1724 | std_out = PR_GetSpecialFD(PR_StandardOutput); | ||||
1725 | |||||
1726 | #if defined(WIN32) || defined(OS2) | ||||
1727 | /* PR_Poll cannot be used with stdin on Windows or OS/2. (sigh). | ||||
1728 | ** But use of PR_Poll and non-blocking sockets is a major feature | ||||
1729 | ** of this program. So, we simulate a pollable stdin with a | ||||
1730 | ** TCP socket pair and a thread that reads stdin and writes to | ||||
1731 | ** that socket pair. | ||||
1732 | */ | ||||
1733 | { | ||||
1734 | PRFileDesc *fds[2]; | ||||
1735 | PRThread *thread; | ||||
1736 | |||||
1737 | int nspr_rv = PR_NewTCPSocketPair(fds); | ||||
1738 | if (nspr_rv != PR_SUCCESS) { | ||||
1739 | SECU_PrintError(progName, "PR_NewTCPSocketPair failed"); | ||||
1740 | error = 1; | ||||
1741 | goto done; | ||||
1742 | } | ||||
1743 | pollset[STDIN_FD1].fd = fds[1]; | ||||
1744 | |||||
1745 | thread = PR_CreateThread(PR_USER_THREAD, thread_main, fds[0], | ||||
1746 | PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, | ||||
1747 | PR_UNJOINABLE_THREAD, 0); | ||||
1748 | if (!thread) { | ||||
1749 | SECU_PrintError(progName, "PR_CreateThread failed"); | ||||
1750 | error = 1; | ||||
1751 | goto done; | ||||
1752 | } | ||||
1753 | } | ||||
1754 | #endif | ||||
1755 | |||||
1756 | if (serverCertAuth.testFreshStatusFromSideChannel) { | ||||
1757 | SSL_ForceHandshake(s); | ||||
1758 | error = serverCertAuth.sideChannelRevocationTestResultCode; | ||||
1759 | goto done; | ||||
1760 | } | ||||
1761 | |||||
1762 | /* | ||||
1763 | ** Select on stdin and on the socket. Write data from stdin to | ||||
1764 | ** socket, read data from socket and write to stdout. | ||||
1765 | */ | ||||
1766 | requestToExit = PR_FALSE0; | ||||
1767 | FPRINTFif (verbose) fprintf(stderrstderr, "%s: ready...\n", progName); | ||||
1768 | while (!requestToExit
| ||||
1769 | (pollset[SSOCK_FD0].in_flags
| ||||
1770 | PRUint8 buf[4000]; /* buffer for stdin */ | ||||
1771 | int nb; /* num bytes read from stdin. */ | ||||
1772 | |||||
1773 | rv = restartHandshakeAfterServerCertIfNeeded(s, &serverCertAuth, | ||||
1774 | override); | ||||
1775 | if (rv
| ||||
1776 | error = EXIT_CODE_HANDSHAKE_FAILED254; | ||||
1777 | SECU_PrintError(progName, "authentication of server cert failed"); | ||||
1778 | goto done; | ||||
1779 | } | ||||
1780 | |||||
1781 | rv = restartHandshakeAfterClientCertIfNeeded(s); | ||||
1782 | if (rv
| ||||
1783 | continue; | ||||
1784 | } | ||||
1785 | |||||
1786 | pollset[SSOCK_FD0].out_flags = 0; | ||||
1787 | pollset[STDIN_FD1].out_flags = 0; | ||||
1788 | |||||
1789 | FPRINTFif (verbose) fprintf(stderrstderr, "%s: about to call PR_Poll !\n", progName); | ||||
1790 | filesReady = PR_Poll(pollset, PR_ARRAY_SIZE(pollset)(sizeof(pollset)/sizeof((pollset)[0])), | ||||
1791 | PR_INTERVAL_NO_TIMEOUT0xffffffffUL); | ||||
1792 | if (filesReady < 0) { | ||||
1793 | SECU_PrintError(progName, "select failed"); | ||||
1794 | error = 1; | ||||
1795 | goto done; | ||||
1796 | } | ||||
1797 | if (filesReady == 0) { /* shouldn't happen! */ | ||||
1798 | FPRINTFif (verbose) fprintf(stderrstderr, "%s: PR_Poll returned zero!\n", progName); | ||||
1799 | error = 1; | ||||
1800 | goto done; | ||||
1801 | } | ||||
1802 | FPRINTFif (verbose) fprintf(stderrstderr, "%s: PR_Poll returned!\n", progName); | ||||
1803 | if (pollset[STDIN_FD1].in_flags) { | ||||
1804 | FPRINTFif (verbose) fprintf(stderrstderr, | ||||
1805 | "%s: PR_Poll returned 0x%02x for stdin out_flags.\n", | ||||
1806 | progName, pollset[STDIN_FD1].out_flags); | ||||
1807 | } | ||||
1808 | if (pollset[SSOCK_FD0].in_flags) { | ||||
1809 | FPRINTFif (verbose) fprintf(stderrstderr, | ||||
1810 | "%s: PR_Poll returned 0x%02x for socket out_flags.\n", | ||||
1811 | progName, pollset[SSOCK_FD0].out_flags); | ||||
1812 | } | ||||
1813 | if (pollset[STDIN_FD1].out_flags & PR_POLL_READ0x1) { | ||||
1814 | /* Read from stdin and write to socket */ | ||||
1815 | nb = PR_Read(pollset[STDIN_FD1].fd, buf, sizeof(buf)); | ||||
1816 | FPRINTFif (verbose) fprintf(stderrstderr, "%s: stdin read %d bytes\n", progName, nb); | ||||
1817 | if (nb < 0) { | ||||
1818 | if (PR_GetError() != PR_WOULD_BLOCK_ERROR(-5998L)) { | ||||
1819 | SECU_PrintError(progName, "read from stdin failed"); | ||||
1820 | error = 1; | ||||
1821 | break; | ||||
1822 | } | ||||
1823 | } else if (nb == 0) { | ||||
1824 | /* EOF on stdin, stop polling stdin for read. */ | ||||
1825 | pollset[STDIN_FD1].in_flags = 0; | ||||
1826 | if (actAsServer) | ||||
1827 | requestToExit = PR_TRUE1; | ||||
1828 | } else { | ||||
1829 | error = writeBytesToServer(s, buf, nb); | ||||
1830 | if (error) { | ||||
1831 | if (echConfigs) { | ||||
1832 | (void)printEchRetryConfigs(s); | ||||
1833 | } | ||||
1834 | goto done; | ||||
1835 | } | ||||
1836 | pollset[SSOCK_FD0].in_flags = PR_POLL_READ0x1; | ||||
1837 | } | ||||
1838 | } | ||||
1839 | |||||
1840 | if (pollset[SSOCK_FD0].in_flags) { | ||||
1841 | FPRINTFif (verbose) fprintf(stderrstderr, | ||||
1842 | "%s: PR_Poll returned 0x%02x for socket out_flags.\n", | ||||
1843 | progName, pollset[SSOCK_FD0].out_flags); | ||||
1844 | } | ||||
1845 | #ifdef PR_POLL_HUP0x20 | ||||
1846 | #define POLL_RECV_FLAGS(0x1 | 0x8 | 0x20) (PR_POLL_READ0x1 | PR_POLL_ERR0x8 | PR_POLL_HUP0x20) | ||||
1847 | #else | ||||
1848 | #define POLL_RECV_FLAGS(0x1 | 0x8 | 0x20) (PR_POLL_READ0x1 | PR_POLL_ERR0x8) | ||||
1849 | #endif | ||||
1850 | if (pollset[SSOCK_FD0].out_flags & POLL_RECV_FLAGS(0x1 | 0x8 | 0x20)) { | ||||
1851 | /* Read from socket and write to stdout */ | ||||
1852 | nb = PR_Recv(pollset[SSOCK_FD0].fd, buf, sizeof buf, 0, maxInterval); | ||||
1853 | FPRINTFif (verbose) fprintf(stderrstderr, "%s: Read from server %d bytes\n", progName, nb); | ||||
1854 | if (nb < 0) { | ||||
1855 | if (PR_GetError() != PR_WOULD_BLOCK_ERROR(-5998L)) { | ||||
1856 | SECU_PrintError(progName, "read from socket failed"); | ||||
1857 | error = 1; | ||||
1858 | goto done; | ||||
1859 | } | ||||
1860 | } else if (nb == 0) { | ||||
1861 | /* EOF from socket... stop polling socket for read */ | ||||
1862 | pollset[SSOCK_FD0].in_flags = 0; | ||||
1863 | } else { | ||||
1864 | if (skipProtoHeader != PR_TRUE1 || wrStarted == PR_TRUE1) { | ||||
1865 | PR_Write(std_out, buf, nb); | ||||
1866 | } else { | ||||
1867 | separateReqHeader(std_out, (char *)buf, nb, &wrStarted, | ||||
1868 | &headerSeparatorPtrnId); | ||||
1869 | } | ||||
1870 | if (verbose) | ||||
1871 | fputs("\n\n", stderrstderr); | ||||
1872 | } | ||||
1873 | } | ||||
1874 | milliPause(50 * multiplier); | ||||
1875 | } | ||||
1876 | |||||
1877 | done: | ||||
1878 | if (s) { | ||||
1879 | PR_Close(s); | ||||
1880 | } | ||||
1881 | if (requestFile && pollset[STDIN_FD1].fd) { | ||||
1882 | PR_Close(pollset[STDIN_FD1].fd); | ||||
1883 | } | ||||
1884 | return error; | ||||
1885 | } | ||||
1886 | |||||
1887 | int | ||||
1888 | main(int argc, char **argv) | ||||
1889 | { | ||||
1890 | PLOptState *optstate; | ||||
1891 | PLOptStatus optstatus; | ||||
1892 | PRStatus status; | ||||
1893 | PRStatus prStatus; | ||||
1894 | int error = 0; | ||||
1895 | char *tmp; | ||||
1896 | SECStatus rv; | ||||
1897 | char *certDir = NULL((void*)0); | ||||
1898 | PRBool openDB = PR_TRUE1; | ||||
1899 | PRBool loadDefaultRootCAs = PR_FALSE0; | ||||
1900 | char *rootModule = NULL((void*)0); | ||||
1901 | int numConnections = 1; | ||||
1902 | PRFileDesc *s = NULL((void*)0); | ||||
1903 | |||||
1904 | serverCertAuth.shouldPause = PR_TRUE1; | ||||
1905 | serverCertAuth.isPaused = PR_FALSE0; | ||||
1906 | serverCertAuth.dbHandle = NULL((void*)0); | ||||
1907 | serverCertAuth.testFreshStatusFromSideChannel = PR_FALSE0; | ||||
1908 | serverCertAuth.sideChannelRevocationTestResultCode = EXIT_CODE_HANDSHAKE_FAILED254; | ||||
1909 | serverCertAuth.requireDataForIntermediates = PR_FALSE0; | ||||
1910 | serverCertAuth.allowOCSPSideChannelData = PR_TRUE1; | ||||
1911 | serverCertAuth.allowCRLSideChannelData = PR_TRUE1; | ||||
1912 | |||||
1913 | progName = strrchr(argv[0], '/'); | ||||
1914 | if (!progName) | ||||
1915 | progName = strrchr(argv[0], '\\'); | ||||
1916 | progName = progName ? progName + 1 : argv[0]; | ||||
1917 | |||||
1918 | tmp = PR_GetEnvSecure("NSS_DEBUG_TIMEOUT"); | ||||
1919 | if (tmp && tmp[0]) { | ||||
1920 | int sec = PORT_Atoi(tmp)(int)strtol(tmp, ((void*)0), 10); | ||||
1921 | if (sec > 0) { | ||||
1922 | maxInterval = PR_SecondsToInterval(sec); | ||||
1923 | } | ||||
1924 | } | ||||
1925 | |||||
1926 | optstate = PL_CreateOptState(argc, argv, | ||||
1927 | "46A:BCDEFGHI:J:KL:M:N:OP:QR:STUV:W:X:YZa:bc:d:efgh:i:m:n:op:qr:st:uvw:x:z:"); | ||||
1928 | while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) { | ||||
1929 | switch (optstate->option) { | ||||
1930 | case '?': | ||||
1931 | default: | ||||
1932 | Usage(); | ||||
1933 | break; | ||||
1934 | |||||
1935 | case '4': | ||||
1936 | allowIPv6 = PR_FALSE0; | ||||
1937 | if (!allowIPv4) | ||||
1938 | Usage(); | ||||
1939 | break; | ||||
1940 | case '6': | ||||
1941 | allowIPv4 = PR_FALSE0; | ||||
1942 | if (!allowIPv6) | ||||
1943 | Usage(); | ||||
1944 | break; | ||||
1945 | |||||
1946 | case 'A': | ||||
1947 | requestFile = PORT_StrdupPORT_Strdup_Util(optstate->value); | ||||
1948 | break; | ||||
1949 | |||||
1950 | case 'B': | ||||
1951 | enableDelegatedCredentials = PR_TRUE1; | ||||
1952 | break; | ||||
1953 | |||||
1954 | case 'C': | ||||
1955 | ++dumpServerChain; | ||||
1956 | break; | ||||
1957 | |||||
1958 | case 'D': | ||||
1959 | openDB = PR_FALSE0; | ||||
1960 | break; | ||||
1961 | |||||
1962 | case 'E': | ||||
1963 | enablePostHandshakeAuth = PR_TRUE1; | ||||
1964 | break; | ||||
1965 | |||||
1966 | case 'F': | ||||
1967 | if (serverCertAuth.testFreshStatusFromSideChannel) { | ||||
1968 | /* parameter given twice or more */ | ||||
1969 | serverCertAuth.requireDataForIntermediates = PR_TRUE1; | ||||
1970 | } | ||||
1971 | serverCertAuth.testFreshStatusFromSideChannel = PR_TRUE1; | ||||
1972 | break; | ||||
1973 | |||||
1974 | case 'G': | ||||
1975 | enableExtendedMasterSecret = PR_TRUE1; | ||||
1976 | break; | ||||
1977 | |||||
1978 | case 'H': | ||||
1979 | requireDHNamedGroups = PR_TRUE1; | ||||
1980 | break; | ||||
1981 | |||||
1982 | case 'O': | ||||
1983 | clientCertAsyncSelect = PR_FALSE0; | ||||
1984 | serverCertAuth.shouldPause = PR_FALSE0; | ||||
1985 | break; | ||||
1986 | |||||
1987 | case 'K': | ||||
1988 | forceFallbackSCSV = PR_TRUE1; | ||||
1989 | break; | ||||
1990 | |||||
1991 | case 'L': | ||||
1992 | numConnections = atoi(optstate->value); | ||||
1993 | break; | ||||
1994 | |||||
1995 | case 'M': | ||||
1996 | switch (atoi(optstate->value)) { | ||||
1997 | case 1: | ||||
1998 | serverCertAuth.allowOCSPSideChannelData = PR_TRUE1; | ||||
1999 | serverCertAuth.allowCRLSideChannelData = PR_FALSE0; | ||||
2000 | break; | ||||
2001 | case 2: | ||||
2002 | serverCertAuth.allowOCSPSideChannelData = PR_FALSE0; | ||||
2003 | serverCertAuth.allowCRLSideChannelData = PR_TRUE1; | ||||
2004 | break; | ||||
2005 | case 0: | ||||
2006 | default: | ||||
2007 | serverCertAuth.allowOCSPSideChannelData = PR_TRUE1; | ||||
2008 | serverCertAuth.allowCRLSideChannelData = PR_TRUE1; | ||||
2009 | break; | ||||
2010 | }; | ||||
2011 | break; | ||||
2012 | |||||
2013 | case 'N': | ||||
2014 | echConfigs = PORT_StrdupPORT_Strdup_Util(optstate->value); | ||||
2015 | break; | ||||
2016 | |||||
2017 | case 'i': | ||||
2018 | echGreaseSize = PORT_Atoi(optstate->value)(int)strtol(optstate->value, ((void*)0), 10); | ||||
2019 | if (!echGreaseSize || echGreaseSize > 255) { | ||||
2020 | fprintf(stderrstderr, "ECH Grease size must be within 1..255 (inclusive).\n"); | ||||
2021 | exit(-1); | ||||
2022 | } | ||||
2023 | break; | ||||
2024 | |||||
2025 | case 'P': | ||||
2026 | useDTLS = PR_TRUE1; | ||||
2027 | if (!strcmp(optstate->value, "server")) { | ||||
2028 | actAsServer = 1; | ||||
2029 | } else { | ||||
2030 | if (strcmp(optstate->value, "client")) { | ||||
2031 | Usage(); | ||||
2032 | } | ||||
2033 | } | ||||
2034 | break; | ||||
2035 | |||||
2036 | case 'Q': | ||||
2037 | stopAfterHandshake = PR_TRUE1; | ||||
2038 | break; | ||||
2039 | |||||
2040 | case 'R': | ||||
2041 | rootModule = PORT_StrdupPORT_Strdup_Util(optstate->value); | ||||
2042 | break; | ||||
2043 | |||||
2044 | case 'S': | ||||
2045 | skipProtoHeader = PR_TRUE1; | ||||
2046 | break; | ||||
2047 | |||||
2048 | case 'T': | ||||
2049 | enableCertStatus = 1; | ||||
2050 | break; | ||||
2051 | |||||
2052 | case 'U': | ||||
2053 | enableSignedCertTimestamps = 1; | ||||
2054 | break; | ||||
2055 | |||||
2056 | case 'V': | ||||
2057 | versionString = PORT_StrdupPORT_Strdup_Util(optstate->value); | ||||
2058 | break; | ||||
2059 | |||||
2060 | case 'X': | ||||
2061 | if (!strcmp(optstate->value, "alt-server-hello")) { | ||||
2062 | enableAltServerHello = PR_TRUE1; | ||||
2063 | } else { | ||||
2064 | Usage(); | ||||
2065 | } | ||||
2066 | break; | ||||
2067 | case 'Y': | ||||
2068 | PrintCipherUsage(); | ||||
2069 | exit(0); | ||||
2070 | break; | ||||
2071 | |||||
2072 | case 'Z': | ||||
2073 | enableZeroRtt = PR_TRUE1; | ||||
2074 | zeroRttData = PORT_ZAllocPORT_ZAlloc_Util(ZERO_RTT_MAX(2 << 16)); | ||||
2075 | if (!zeroRttData) { | ||||
2076 | fprintf(stderrstderr, "Unable to allocate buffer for 0-RTT\n"); | ||||
2077 | exit(1); | ||||
2078 | } | ||||
2079 | break; | ||||
2080 | |||||
2081 | case 'a': | ||||
2082 | if (!hs1SniHostName) { | ||||
2083 | hs1SniHostName = PORT_StrdupPORT_Strdup_Util(optstate->value); | ||||
2084 | } else if (!hs2SniHostName) { | ||||
2085 | hs2SniHostName = PORT_StrdupPORT_Strdup_Util(optstate->value); | ||||
2086 | } else { | ||||
2087 | Usage(); | ||||
2088 | } | ||||
2089 | break; | ||||
2090 | |||||
2091 | case 'b': | ||||
2092 | loadDefaultRootCAs = PR_TRUE1; | ||||
2093 | break; | ||||
2094 | |||||
2095 | case 'c': | ||||
2096 | cipherString = PORT_StrdupPORT_Strdup_Util(optstate->value); | ||||
2097 | break; | ||||
2098 | |||||
2099 | case 'g': | ||||
2100 | enableFalseStart = 1; | ||||
2101 | break; | ||||
2102 | |||||
2103 | case 'd': | ||||
2104 | certDir = PORT_StrdupPORT_Strdup_Util(optstate->value); | ||||
2105 | break; | ||||
2106 | |||||
2107 | case 'e': | ||||
2108 | middleboxCompatMode = PR_TRUE1; | ||||
2109 | break; | ||||
2110 | |||||
2111 | case 'f': | ||||
2112 | clientSpeaksFirst = PR_TRUE1; | ||||
2113 | break; | ||||
2114 | |||||
2115 | case 'h': | ||||
2116 | host = PORT_StrdupPORT_Strdup_Util(optstate->value); | ||||
2117 | break; | ||||
2118 | |||||
2119 | case 'm': | ||||
2120 | multiplier = atoi(optstate->value); | ||||
2121 | if (multiplier < 0) | ||||
2122 | multiplier = 0; | ||||
2123 | break; | ||||
2124 | |||||
2125 | case 'n': | ||||
2126 | nickname = PORT_StrdupPORT_Strdup_Util(optstate->value); | ||||
2127 | break; | ||||
2128 | |||||
2129 | case 'o': | ||||
2130 | override = 1; | ||||
2131 | break; | ||||
2132 | |||||
2133 | case 'p': | ||||
2134 | portno = (PRUint16)atoi(optstate->value); | ||||
2135 | break; | ||||
2136 | |||||
2137 | case 'q': | ||||
2138 | pingServerFirst = PR_TRUE1; | ||||
2139 | break; | ||||
2140 | |||||
2141 | case 's': | ||||
2142 | disableLocking = 1; | ||||
2143 | break; | ||||
2144 | |||||
2145 | case 't': | ||||
2146 | pingTimeoutSeconds = atoi(optstate->value); | ||||
2147 | break; | ||||
2148 | |||||
2149 | case 'u': | ||||
2150 | enableSessionTickets = PR_TRUE1; | ||||
2151 | break; | ||||
2152 | |||||
2153 | case 'v': | ||||
2154 | verbose++; | ||||
2155 | break; | ||||
2156 | |||||
2157 | case 'r': | ||||
2158 | renegotiationsToDo = atoi(optstate->value); | ||||
2159 | break; | ||||
2160 | |||||
2161 | case 'w': | ||||
2162 | pwdata.source = PW_PLAINTEXT; | ||||
2163 | pwdata.data = PORT_StrdupPORT_Strdup_Util(optstate->value); | ||||
2164 | break; | ||||
2165 | |||||
2166 | case 'W': | ||||
2167 | pwdata.source = PW_FROMFILE; | ||||
2168 | pwdata.data = PORT_StrdupPORT_Strdup_Util(optstate->value); | ||||
2169 | break; | ||||
2170 | |||||
2171 | case 'I': | ||||
2172 | rv = parseGroupList(optstate->value, &enabledGroups, &enabledGroupsCount); | ||||
2173 | if (rv != SECSuccess) { | ||||
2174 | PL_DestroyOptState(optstate); | ||||
2175 | fprintf(stderrstderr, "Bad group specified.\n"); | ||||
2176 | Usage(); | ||||
2177 | } | ||||
2178 | break; | ||||
2179 | |||||
2180 | case 'J': | ||||
2181 | rv = parseSigSchemeList(optstate->value, &enabledSigSchemes, &enabledSigSchemeCount); | ||||
2182 | if (rv != SECSuccess) { | ||||
2183 | PL_DestroyOptState(optstate); | ||||
2184 | fprintf(stderrstderr, "Bad signature scheme specified.\n"); | ||||
2185 | Usage(); | ||||
2186 | } | ||||
2187 | break; | ||||
2188 | |||||
2189 | case 'x': | ||||
2190 | rv = parseExporters(optstate->value, | ||||
2191 | &enabledExporters, | ||||
2192 | &enabledExporterCount); | ||||
2193 | if (rv != SECSuccess) { | ||||
2194 | PL_DestroyOptState(optstate); | ||||
2195 | fprintf(stderrstderr, "Bad exporter specified.\n"); | ||||
2196 | Usage(); | ||||
2197 | } | ||||
2198 | break; | ||||
2199 | |||||
2200 | case 'z': | ||||
2201 | rv = readPSK(optstate->value, &psk, &pskLabel); | ||||
2202 | if (rv != SECSuccess) { | ||||
2203 | PL_DestroyOptState(optstate); | ||||
2204 | fprintf(stderrstderr, "Bad PSK specified.\n"); | ||||
2205 | Usage(); | ||||
2206 | } | ||||
2207 | break; | ||||
2208 | } | ||||
2209 | } | ||||
2210 | PL_DestroyOptState(optstate); | ||||
2211 | |||||
2212 | SSL_VersionRangeGetSupported(useDTLS ? ssl_variant_datagram : ssl_variant_stream, &enabledVersions); | ||||
2213 | |||||
2214 | if (versionString) { | ||||
2215 | if (SECU_ParseSSLVersionRangeString(versionString, | ||||
2216 | enabledVersions, &enabledVersions) != | ||||
2217 | SECSuccess) { | ||||
2218 | fprintf(stderrstderr, "Bad version specified.\n"); | ||||
2219 | Usage(); | ||||
2220 | } | ||||
2221 | PORT_FreePORT_Free_Util(versionString); | ||||
2222 | } | ||||
2223 | |||||
2224 | if (optstatus == PL_OPT_BAD) { | ||||
2225 | Usage(); | ||||
2226 | } | ||||
2227 | |||||
2228 | if (!host || !portno) { | ||||
2229 | fprintf(stderrstderr, "%s: parameters -h and -p are mandatory\n", progName); | ||||
2230 | Usage(); | ||||
2231 | } | ||||
2232 | |||||
2233 | if (serverCertAuth.testFreshStatusFromSideChannel && | ||||
2234 | serverCertAuth.shouldPause) { | ||||
2235 | fprintf(stderrstderr, "%s: -F requires the use of -O\n", progName); | ||||
2236 | exit(1); | ||||
2237 | } | ||||
2238 | |||||
2239 | if (certDir && !openDB) { | ||||
2240 | fprintf(stderrstderr, "%s: Cannot combine parameters -D and -d\n", progName); | ||||
2241 | exit(1); | ||||
2242 | } | ||||
2243 | |||||
2244 | if (rootModule && loadDefaultRootCAs) { | ||||
2245 | fprintf(stderrstderr, "%s: Cannot combine parameters -b and -R\n", progName); | ||||
2246 | exit(1); | ||||
2247 | } | ||||
2248 | |||||
2249 | if (enablePostHandshakeAuth && !nickname) { | ||||
2250 | fprintf(stderrstderr, "%s: -E requires the use of -n\n", progName); | ||||
2251 | exit(1); | ||||
2252 | } | ||||
2253 | |||||
2254 | PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); | ||||
2255 | |||||
2256 | PK11_SetPasswordFunc(SECU_GetModulePassword); | ||||
2257 | memset(&addr, 0, sizeof(addr)); | ||||
2258 | status = PR_StringToNetAddr(host, &addr); | ||||
2259 | if (status == PR_SUCCESS) { | ||||
2260 | addr.inet.port = PR_htons(portno); | ||||
2261 | } else { | ||||
2262 | PRBool gotLoopbackIP = PR_FALSE0; | ||||
2263 | if ((!strcmp(host, "localhost") || !strcmp(host, "localhost.localdomain")) | ||||
2264 | /* only check for preference if both types are allowed */ | ||||
2265 | && allowIPv4 && allowIPv6) { | ||||
2266 | /* make a decision which IP to prefer */ | ||||
2267 | status = PR_GetPrefLoopbackAddrInfo(&addr, portno); | ||||
2268 | if (status != PR_FAILURE) { | ||||
2269 | gotLoopbackIP = PR_TRUE1; | ||||
2270 | } | ||||
2271 | } | ||||
2272 | |||||
2273 | if (!gotLoopbackIP) { | ||||
2274 | /* Lookup host */ | ||||
2275 | PRAddrInfo *addrInfo; | ||||
2276 | void *enumPtr = NULL((void*)0); | ||||
2277 | |||||
2278 | addrInfo = PR_GetAddrInfoByName(host, PR_AF_UNSPEC0, | ||||
2279 | PR_AI_ADDRCONFIG0x20 | PR_AI_NOCANONNAME0x8000); | ||||
2280 | if (!addrInfo) { | ||||
2281 | fprintf(stderrstderr, "HOSTNAME=%s\n", host); | ||||
2282 | SECU_PrintError(progName, "error looking up host"); | ||||
2283 | error = 1; | ||||
2284 | goto done; | ||||
2285 | } | ||||
2286 | for (;;) { | ||||
2287 | enumPtr = PR_EnumerateAddrInfo(enumPtr, addrInfo, portno, &addr); | ||||
2288 | if (enumPtr == NULL((void*)0)) | ||||
2289 | break; | ||||
2290 | if (addr.raw.family == PR_AF_INET2 && allowIPv4) | ||||
2291 | break; | ||||
2292 | if (addr.raw.family == PR_AF_INET610 && allowIPv6) | ||||
2293 | break; | ||||
2294 | } | ||||
2295 | PR_FreeAddrInfo(addrInfo); | ||||
2296 | if (enumPtr == NULL((void*)0)) { | ||||
2297 | SECU_PrintError(progName, "error looking up host address"); | ||||
2298 | error = 1; | ||||
2299 | goto done; | ||||
2300 | } | ||||
2301 | } | ||||
2302 | } | ||||
2303 | |||||
2304 | printHostNameAndAddr(host, &addr); | ||||
2305 | |||||
2306 | if (!certDir) { | ||||
2307 | certDir = SECU_DefaultSSLDir(); /* Look in $SSL_DIR */ | ||||
2308 | certDir = SECU_ConfigDirectory(certDir); | ||||
2309 | } else { | ||||
2310 | char *certDirTmp = certDir; | ||||
2311 | certDir = SECU_ConfigDirectory(certDirTmp); | ||||
2312 | PORT_FreePORT_Free_Util(certDirTmp); | ||||
2313 | } | ||||
2314 | |||||
2315 | if (pingServerFirst) { | ||||
2316 | int iter = 0; | ||||
2317 | PRErrorCode err; | ||||
2318 | |||||
2319 | int max_attempts = MAX_WAIT_FOR_SERVER600; | ||||
2320 | if (pingTimeoutSeconds >= 0) { | ||||
2321 | /* If caller requested a timeout, let's try just twice. */ | ||||
2322 | max_attempts = 2; | ||||
2323 | } | ||||
2324 | do { | ||||
2325 | PRIntervalTime timeoutInterval = PR_INTERVAL_NO_TIMEOUT0xffffffffUL; | ||||
2326 | s = PR_OpenTCPSocket(addr.raw.family); | ||||
2327 | if (s == NULL((void*)0)) { | ||||
2328 | SECU_PrintError(progName, "Failed to create a TCP socket"); | ||||
2329 | error = 1; | ||||
2330 | goto done; | ||||
2331 | } | ||||
2332 | opt.option = PR_SockOpt_Nonblocking; | ||||
2333 | opt.value.non_blocking = PR_FALSE0; | ||||
2334 | prStatus = PR_SetSocketOption(s, &opt); | ||||
2335 | if (prStatus != PR_SUCCESS) { | ||||
2336 | SECU_PrintError(progName, | ||||
2337 | "Failed to set blocking socket option"); | ||||
2338 | error = 1; | ||||
2339 | goto done; | ||||
2340 | } | ||||
2341 | if (pingTimeoutSeconds >= 0) { | ||||
2342 | timeoutInterval = PR_SecondsToInterval(pingTimeoutSeconds); | ||||
2343 | } | ||||
2344 | prStatus = PR_Connect(s, &addr, timeoutInterval); | ||||
2345 | if (prStatus == PR_SUCCESS) { | ||||
2346 | PR_Shutdown(s, PR_SHUTDOWN_BOTH); | ||||
2347 | goto done; | ||||
2348 | } | ||||
2349 | err = PR_GetError(); | ||||
2350 | if ((err != PR_CONNECT_REFUSED_ERROR(-5981L)) && | ||||
2351 | (err != PR_CONNECT_RESET_ERROR(-5961L))) { | ||||
2352 | SECU_PrintError(progName, "TCP Connection failed"); | ||||
2353 | error = 1; | ||||
2354 | goto done; | ||||
2355 | } | ||||
2356 | PR_Close(s); | ||||
2357 | s = NULL((void*)0); | ||||
2358 | PR_Sleep(PR_MillisecondsToInterval(WAIT_INTERVAL100)); | ||||
2359 | } while (++iter < max_attempts); | ||||
2360 | SECU_PrintError(progName, | ||||
2361 | "Client timed out while waiting for connection to server"); | ||||
2362 | error = 1; | ||||
2363 | goto done; | ||||
2364 | } | ||||
2365 | |||||
2366 | /* open the cert DB, the key DB, and the secmod DB. */ | ||||
2367 | if (openDB) { | ||||
2368 | rv = NSS_Init(certDir); | ||||
2369 | if (rv != SECSuccess) { | ||||
2370 | SECU_PrintError(progName, "unable to open cert database"); | ||||
2371 | error = 1; | ||||
2372 | goto done; | ||||
2373 | } | ||||
2374 | } else { | ||||
2375 | rv = NSS_NoDB_Init(NULL((void*)0)); | ||||
2376 | if (rv != SECSuccess) { | ||||
2377 | SECU_PrintError(progName, "failed to initialize NSS"); | ||||
2378 | error = 1; | ||||
2379 | goto done; | ||||
2380 | } | ||||
2381 | } | ||||
2382 | |||||
2383 | if (loadDefaultRootCAs) { | ||||
2384 | SECMOD_AddNewModule("Builtins", | ||||
2385 | DLL_PREFIX"lib" "nssckbi." DLL_SUFFIX"so", 0, 0); | ||||
2386 | } else if (rootModule) { | ||||
2387 | SECMOD_AddNewModule("Builtins", rootModule, 0, 0); | ||||
2388 | } | ||||
2389 | |||||
2390 | /* all SSL3 cipher suites are enabled by default. */ | ||||
2391 | if (cipherString) { | ||||
2392 | /* disable all the ciphers, then enable the ones we want. */ | ||||
2393 | disableAllSSLCiphers(); | ||||
2394 | } | ||||
2395 | |||||
2396 | while (numConnections--) { | ||||
2397 | error = run(); | ||||
2398 | if (error) { | ||||
2399 | goto done; | ||||
2400 | } | ||||
2401 | } | ||||
2402 | |||||
2403 | done: | ||||
2404 | if (s) { | ||||
2405 | PR_Close(s); | ||||
2406 | } | ||||
2407 | |||||
2408 | PORT_FreePORT_Free_Util((void *)requestFile); | ||||
2409 | PORT_FreePORT_Free_Util(hs1SniHostName); | ||||
2410 | PORT_FreePORT_Free_Util(hs2SniHostName); | ||||
2411 | PORT_FreePORT_Free_Util(nickname); | ||||
2412 | PORT_FreePORT_Free_Util(pwdata.data); | ||||
2413 | PORT_FreePORT_Free_Util(host); | ||||
2414 | PORT_FreePORT_Free_Util(zeroRttData); | ||||
2415 | PORT_FreePORT_Free_Util(echConfigs); | ||||
2416 | SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(&psk, PR_FALSE0); | ||||
2417 | SECITEM_ZfreeItemSECITEM_ZfreeItem_Util(&pskLabel, PR_FALSE0); | ||||
2418 | |||||
2419 | if (enabledGroups) { | ||||
2420 | PORT_FreePORT_Free_Util(enabledGroups); | ||||
2421 | } | ||||
2422 | if (NSS_IsInitialized()) { | ||||
2423 | SSL_ClearSessionCache(); | ||||
2424 | if (initializedServerSessionCache) { | ||||
2425 | if (SSL_ShutdownServerSessionIDCache() != SECSuccess) { | ||||
2426 | error = 1; | ||||
2427 | } | ||||
2428 | } | ||||
2429 | |||||
2430 | if (NSS_Shutdown() != SECSuccess) { | ||||
2431 | error = 1; | ||||
2432 | } | ||||
2433 | } | ||||
2434 | |||||
2435 | FPRINTFif (verbose) fprintf(stderrstderr, "tstclnt: exiting with return code %d\n", error); | ||||
2436 | PR_Cleanup(); | ||||
2437 | return error; | ||||
2438 | } |