OLD | NEW |
| (Empty) |
1 /* | |
2 * Various SSL functions. | |
3 * | |
4 * This Source Code Form is subject to the terms of the Mozilla Public | |
5 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
7 #include "cert.h" | |
8 #include "secitem.h" | |
9 #include "keyhi.h" | |
10 #include "ssl.h" | |
11 #include "sslimpl.h" | |
12 #include "sslproto.h" | |
13 #include "secoid.h" /* for SECOID_GetALgorithmTag */ | |
14 #include "pk11func.h" /* for PK11_GenerateRandom */ | |
15 #include "nss.h" /* for NSS_RegisterShutdown */ | |
16 #include "prinit.h" /* for PR_CallOnceWithArg */ | |
17 | |
18 #define MAX_BLOCK_CYPHER_SIZE 32 | |
19 | |
20 #define TEST_FOR_FAILURE /* reminder */ | |
21 #define SET_ERROR_CODE /* reminder */ | |
22 | |
23 /* Returns a SECStatus: SECSuccess or SECFailure, NOT SECWouldBlock. | |
24 * | |
25 * Currently, the list of functions called through ss->handshake is: | |
26 * | |
27 * In sslsocks.c: | |
28 * SocksGatherRecord | |
29 * SocksHandleReply | |
30 * SocksStartGather | |
31 * | |
32 * In sslcon.c: | |
33 * ssl_GatherRecord1stHandshake | |
34 * ssl2_HandleClientSessionKeyMessage | |
35 * ssl2_HandleMessage | |
36 * ssl2_HandleVerifyMessage | |
37 * ssl2_BeginClientHandshake | |
38 * ssl2_BeginServerHandshake | |
39 * ssl2_HandleClientHelloMessage | |
40 * ssl2_HandleServerHelloMessage | |
41 * | |
42 * The ss->handshake function returns SECWouldBlock under these conditions: | |
43 * 1. ssl_GatherRecord1stHandshake called ssl2_GatherData which read in | |
44 * the beginning of an SSL v3 hello message and returned SECWouldBlock | |
45 * to switch to SSL v3 handshake processing. | |
46 * | |
47 * 2. ssl2_HandleClientHelloMessage discovered version 3.0 in the incoming | |
48 * v2 client hello msg, and called ssl3_HandleV2ClientHello which | |
49 * returned SECWouldBlock. | |
50 * | |
51 * 3. SECWouldBlock was returned by one of the callback functions, via | |
52 * one of these paths: | |
53 * - ssl2_HandleMessage() -> ssl2_HandleRequestCertificate() -> | |
54 * ss->getClientAuthData() | |
55 * | |
56 * - ssl2_HandleServerHelloMessage() -> ss->handleBadCert() | |
57 * | |
58 * - ssl_GatherRecord1stHandshake() -> ssl3_GatherCompleteHandshake() -> | |
59 * ssl3_HandleRecord() -> ssl3_HandleHandshake() -> | |
60 * ssl3_HandleHandshakeMessage() -> ssl3_HandleCertificate() -> | |
61 * ss->handleBadCert() | |
62 * | |
63 * - ssl_GatherRecord1stHandshake() -> ssl3_GatherCompleteHandshake() -> | |
64 * ssl3_HandleRecord() -> ssl3_HandleHandshake() -> | |
65 * ssl3_HandleHandshakeMessage() -> ssl3_HandleCertificateRequest() -> | |
66 * ss->getClientAuthData() | |
67 * | |
68 * Called from: SSL_ForceHandshake (below), | |
69 * ssl_SecureRecv (below) and | |
70 * ssl_SecureSend (below) | |
71 * from: WaitForResponse in sslsocks.c | |
72 * ssl_SocksRecv in sslsocks.c | |
73 * ssl_SocksSend in sslsocks.c | |
74 * | |
75 * Caller must hold the (write) handshakeLock. | |
76 */ | |
77 int | |
78 ssl_Do1stHandshake(sslSocket *ss) | |
79 { | |
80 int rv = SECSuccess; | |
81 int loopCount = 0; | |
82 | |
83 do { | |
84 PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); | |
85 PORT_Assert(ss->opt.noLocks || !ssl_HaveRecvBufLock(ss)); | |
86 PORT_Assert(ss->opt.noLocks || !ssl_HaveXmitBufLock(ss)); | |
87 PORT_Assert(ss->opt.noLocks || !ssl_HaveSSL3HandshakeLock(ss)); | |
88 | |
89 if (ss->handshake == 0) { | |
90 /* Previous handshake finished. Switch to next one */ | |
91 ss->handshake = ss->nextHandshake; | |
92 ss->nextHandshake = 0; | |
93 } | |
94 if (ss->handshake == 0) { | |
95 /* Previous handshake finished. Switch to security handshake */ | |
96 ss->handshake = ss->securityHandshake; | |
97 ss->securityHandshake = 0; | |
98 } | |
99 if (ss->handshake == 0) { | |
100 /* for v3 this is done in ssl3_FinishHandshake */ | |
101 if (!ss->firstHsDone && ss->version < SSL_LIBRARY_VERSION_3_0) { | |
102 ssl_GetRecvBufLock(ss); | |
103 ss->gs.recordLen = 0; | |
104 ssl_FinishHandshake(ss); | |
105 ssl_ReleaseRecvBufLock(ss); | |
106 } | |
107 break; | |
108 } | |
109 rv = (*ss->handshake)(ss); | |
110 ++loopCount; | |
111 /* This code must continue to loop on SECWouldBlock, | |
112 * or any positive value. See XXX_1 comments. | |
113 */ | |
114 } while (rv != SECFailure); /* was (rv >= 0); XXX_1 */ | |
115 | |
116 PORT_Assert(ss->opt.noLocks || !ssl_HaveRecvBufLock(ss)); | |
117 PORT_Assert(ss->opt.noLocks || !ssl_HaveXmitBufLock(ss)); | |
118 PORT_Assert(ss->opt.noLocks || !ssl_HaveSSL3HandshakeLock(ss)); | |
119 | |
120 if (rv == SECWouldBlock) { | |
121 PORT_SetError(PR_WOULD_BLOCK_ERROR); | |
122 rv = SECFailure; | |
123 } | |
124 return rv; | |
125 } | |
126 | |
127 void | |
128 ssl_FinishHandshake(sslSocket *ss) | |
129 { | |
130 PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); | |
131 PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); | |
132 | |
133 SSL_TRC(3, ("%d: SSL[%d]: handshake is completed", SSL_GETPID(), ss->fd)); | |
134 | |
135 ss->firstHsDone = PR_TRUE; | |
136 ss->enoughFirstHsDone = PR_TRUE; | |
137 ss->gs.writeOffset = 0; | |
138 ss->gs.readOffset = 0; | |
139 | |
140 if (ss->handshakeCallback) { | |
141 PORT_Assert(ss->version < SSL_LIBRARY_VERSION_3_0 || | |
142 (ss->ssl3.hs.preliminaryInfo & ssl_preinfo_all) == | |
143 ssl_preinfo_all); | |
144 (ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData); | |
145 } | |
146 } | |
147 | |
148 /* | |
149 * Handshake function that blocks. Used to force a | |
150 * retry on a connection on the next read/write. | |
151 */ | |
152 static SECStatus | |
153 ssl3_AlwaysBlock(sslSocket *ss) | |
154 { | |
155 PORT_SetError(PR_WOULD_BLOCK_ERROR); /* perhaps redundant. */ | |
156 return SECWouldBlock; | |
157 } | |
158 | |
159 /* | |
160 * set the initial handshake state machine to block | |
161 */ | |
162 void | |
163 ssl3_SetAlwaysBlock(sslSocket *ss) | |
164 { | |
165 if (!ss->firstHsDone) { | |
166 ss->handshake = ssl3_AlwaysBlock; | |
167 ss->nextHandshake = 0; | |
168 } | |
169 } | |
170 | |
171 static SECStatus | |
172 ssl_SetTimeout(PRFileDesc *fd, PRIntervalTime timeout) | |
173 { | |
174 sslSocket *ss; | |
175 | |
176 ss = ssl_FindSocket(fd); | |
177 if (!ss) { | |
178 SSL_DBG(("%d: SSL[%d]: bad socket in SetTimeout", SSL_GETPID(), fd)); | |
179 return SECFailure; | |
180 } | |
181 SSL_LOCK_READER(ss); | |
182 ss->rTimeout = timeout; | |
183 if (ss->opt.fdx) { | |
184 SSL_LOCK_WRITER(ss); | |
185 } | |
186 ss->wTimeout = timeout; | |
187 if (ss->opt.fdx) { | |
188 SSL_UNLOCK_WRITER(ss); | |
189 } | |
190 SSL_UNLOCK_READER(ss); | |
191 return SECSuccess; | |
192 } | |
193 | |
194 /* Acquires and releases HandshakeLock. | |
195 */ | |
196 SECStatus | |
197 SSL_ResetHandshake(PRFileDesc *s, PRBool asServer) | |
198 { | |
199 sslSocket *ss; | |
200 SECStatus status; | |
201 PRNetAddr addr; | |
202 | |
203 ss = ssl_FindSocket(s); | |
204 if (!ss) { | |
205 SSL_DBG(("%d: SSL[%d]: bad socket in ResetHandshake", SSL_GETPID(), s)); | |
206 return SECFailure; | |
207 } | |
208 | |
209 /* Don't waste my time */ | |
210 if (!ss->opt.useSecurity) | |
211 return SECSuccess; | |
212 | |
213 SSL_LOCK_READER(ss); | |
214 SSL_LOCK_WRITER(ss); | |
215 | |
216 /* Reset handshake state */ | |
217 ssl_Get1stHandshakeLock(ss); | |
218 | |
219 ss->firstHsDone = PR_FALSE; | |
220 ss->enoughFirstHsDone = PR_FALSE; | |
221 if (asServer) { | |
222 ss->handshake = ssl2_BeginServerHandshake; | |
223 ss->handshaking = sslHandshakingAsServer; | |
224 } else { | |
225 ss->handshake = ssl2_BeginClientHandshake; | |
226 ss->handshaking = sslHandshakingAsClient; | |
227 } | |
228 ss->nextHandshake = 0; | |
229 ss->securityHandshake = 0; | |
230 | |
231 ssl_GetRecvBufLock(ss); | |
232 status = ssl_InitGather(&ss->gs); | |
233 ssl_ReleaseRecvBufLock(ss); | |
234 | |
235 ssl_GetSSL3HandshakeLock(ss); | |
236 ss->ssl3.hs.canFalseStart = PR_FALSE; | |
237 ss->ssl3.hs.restartTarget = NULL; | |
238 | |
239 /* | |
240 ** Blow away old security state and get a fresh setup. | |
241 */ | |
242 ssl_GetXmitBufLock(ss); | |
243 ssl_ResetSecurityInfo(&ss->sec, PR_TRUE); | |
244 status = ssl_CreateSecurityInfo(ss); | |
245 ssl_ReleaseXmitBufLock(ss); | |
246 | |
247 ssl_ReleaseSSL3HandshakeLock(ss); | |
248 ssl_Release1stHandshakeLock(ss); | |
249 | |
250 if (!ss->TCPconnected) | |
251 ss->TCPconnected = (PR_SUCCESS == ssl_DefGetpeername(ss, &addr)); | |
252 | |
253 SSL_UNLOCK_WRITER(ss); | |
254 SSL_UNLOCK_READER(ss); | |
255 | |
256 return status; | |
257 } | |
258 | |
259 /* For SSLv2, does nothing but return an error. | |
260 ** For SSLv3, flushes SID cache entry (if requested), | |
261 ** and then starts new client hello or hello request. | |
262 ** Acquires and releases HandshakeLock. | |
263 */ | |
264 SECStatus | |
265 SSL_ReHandshake(PRFileDesc *fd, PRBool flushCache) | |
266 { | |
267 sslSocket *ss; | |
268 SECStatus rv; | |
269 | |
270 ss = ssl_FindSocket(fd); | |
271 if (!ss) { | |
272 SSL_DBG(("%d: SSL[%d]: bad socket in RedoHandshake", SSL_GETPID(), fd)); | |
273 return SECFailure; | |
274 } | |
275 | |
276 if (!ss->opt.useSecurity) | |
277 return SECSuccess; | |
278 | |
279 ssl_Get1stHandshakeLock(ss); | |
280 | |
281 /* SSL v2 protocol does not support subsequent handshakes. */ | |
282 if (ss->version < SSL_LIBRARY_VERSION_3_0) { | |
283 PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2); | |
284 rv = SECFailure; | |
285 } else { | |
286 ssl_GetSSL3HandshakeLock(ss); | |
287 rv = ssl3_RedoHandshake(ss, flushCache); /* force full handshake. */ | |
288 ssl_ReleaseSSL3HandshakeLock(ss); | |
289 } | |
290 | |
291 ssl_Release1stHandshakeLock(ss); | |
292 | |
293 return rv; | |
294 } | |
295 | |
296 /* | |
297 ** Same as above, but with an I/O timeout. | |
298 */ | |
299 SSL_IMPORT SECStatus | |
300 SSL_ReHandshakeWithTimeout(PRFileDesc *fd, | |
301 PRBool flushCache, | |
302 PRIntervalTime timeout) | |
303 { | |
304 if (SECSuccess != ssl_SetTimeout(fd, timeout)) { | |
305 return SECFailure; | |
306 } | |
307 return SSL_ReHandshake(fd, flushCache); | |
308 } | |
309 | |
310 SECStatus | |
311 SSL_RedoHandshake(PRFileDesc *fd) | |
312 { | |
313 return SSL_ReHandshake(fd, PR_TRUE); | |
314 } | |
315 | |
316 /* Register an application callback to be called when SSL handshake completes. | |
317 ** Acquires and releases HandshakeLock. | |
318 */ | |
319 SECStatus | |
320 SSL_HandshakeCallback(PRFileDesc *fd, SSLHandshakeCallback cb, | |
321 void *client_data) | |
322 { | |
323 sslSocket *ss; | |
324 | |
325 ss = ssl_FindSocket(fd); | |
326 if (!ss) { | |
327 SSL_DBG(("%d: SSL[%d]: bad socket in HandshakeCallback", | |
328 SSL_GETPID(), fd)); | |
329 return SECFailure; | |
330 } | |
331 | |
332 if (!ss->opt.useSecurity) { | |
333 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
334 return SECFailure; | |
335 } | |
336 | |
337 ssl_Get1stHandshakeLock(ss); | |
338 ssl_GetSSL3HandshakeLock(ss); | |
339 | |
340 ss->handshakeCallback = cb; | |
341 ss->handshakeCallbackData = client_data; | |
342 | |
343 ssl_ReleaseSSL3HandshakeLock(ss); | |
344 ssl_Release1stHandshakeLock(ss); | |
345 | |
346 return SECSuccess; | |
347 } | |
348 | |
349 /* Register an application callback to be called when false start may happen. | |
350 ** Acquires and releases HandshakeLock. | |
351 */ | |
352 SECStatus | |
353 SSL_SetCanFalseStartCallback(PRFileDesc *fd, SSLCanFalseStartCallback cb, | |
354 void *arg) | |
355 { | |
356 sslSocket *ss; | |
357 | |
358 ss = ssl_FindSocket(fd); | |
359 if (!ss) { | |
360 SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetCanFalseStartCallback", | |
361 SSL_GETPID(), fd)); | |
362 return SECFailure; | |
363 } | |
364 | |
365 if (!ss->opt.useSecurity) { | |
366 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
367 return SECFailure; | |
368 } | |
369 | |
370 ssl_Get1stHandshakeLock(ss); | |
371 ssl_GetSSL3HandshakeLock(ss); | |
372 | |
373 ss->canFalseStartCallback = cb; | |
374 ss->canFalseStartCallbackData = arg; | |
375 | |
376 ssl_ReleaseSSL3HandshakeLock(ss); | |
377 ssl_Release1stHandshakeLock(ss); | |
378 | |
379 return SECSuccess; | |
380 } | |
381 | |
382 SECStatus | |
383 SSL_RecommendedCanFalseStart(PRFileDesc *fd, PRBool *canFalseStart) | |
384 { | |
385 sslSocket *ss; | |
386 | |
387 *canFalseStart = PR_FALSE; | |
388 ss = ssl_FindSocket(fd); | |
389 if (!ss) { | |
390 SSL_DBG(("%d: SSL[%d]: bad socket in SSL_RecommendedCanFalseStart", | |
391 SSL_GETPID(), fd)); | |
392 return SECFailure; | |
393 } | |
394 | |
395 if (!ss->ssl3.initialized) { | |
396 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
397 return SECFailure; | |
398 } | |
399 | |
400 if (ss->version < SSL_LIBRARY_VERSION_3_0) { | |
401 PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2); | |
402 return SECFailure; | |
403 } | |
404 | |
405 /* Require a forward-secret key exchange. */ | |
406 *canFalseStart = ss->ssl3.hs.kea_def->kea == kea_dhe_dss || | |
407 ss->ssl3.hs.kea_def->kea == kea_dhe_rsa || | |
408 ss->ssl3.hs.kea_def->kea == kea_ecdhe_ecdsa || | |
409 ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa; | |
410 | |
411 return SECSuccess; | |
412 } | |
413 | |
414 /* Try to make progress on an SSL handshake by attempting to read the | |
415 ** next handshake from the peer, and sending any responses. | |
416 ** For non-blocking sockets, returns PR_ERROR_WOULD_BLOCK if it cannot | |
417 ** read the next handshake from the underlying socket. | |
418 ** For SSLv2, returns when handshake is complete or fatal error occurs. | |
419 ** For SSLv3, returns when handshake is complete, or application data has | |
420 ** arrived that must be taken by application before handshake can continue, | |
421 ** or a fatal error occurs. | |
422 ** Application should use handshake completion callback to tell which. | |
423 */ | |
424 SECStatus | |
425 SSL_ForceHandshake(PRFileDesc *fd) | |
426 { | |
427 sslSocket *ss; | |
428 SECStatus rv = SECFailure; | |
429 | |
430 ss = ssl_FindSocket(fd); | |
431 if (!ss) { | |
432 SSL_DBG(("%d: SSL[%d]: bad socket in ForceHandshake", | |
433 SSL_GETPID(), fd)); | |
434 return rv; | |
435 } | |
436 | |
437 /* Don't waste my time */ | |
438 if (!ss->opt.useSecurity) | |
439 return SECSuccess; | |
440 | |
441 if (!ssl_SocketIsBlocking(ss)) { | |
442 ssl_GetXmitBufLock(ss); | |
443 if (ss->pendingBuf.len != 0) { | |
444 int sent = ssl_SendSavedWriteData(ss); | |
445 if ((sent < 0) && (PORT_GetError() != PR_WOULD_BLOCK_ERROR)) { | |
446 ssl_ReleaseXmitBufLock(ss); | |
447 return SECFailure; | |
448 } | |
449 } | |
450 ssl_ReleaseXmitBufLock(ss); | |
451 } | |
452 | |
453 ssl_Get1stHandshakeLock(ss); | |
454 | |
455 if (ss->version >= SSL_LIBRARY_VERSION_3_0) { | |
456 int gatherResult; | |
457 | |
458 ssl_GetRecvBufLock(ss); | |
459 gatherResult = ssl3_GatherCompleteHandshake(ss, 0); | |
460 ssl_ReleaseRecvBufLock(ss); | |
461 if (gatherResult > 0) { | |
462 rv = SECSuccess; | |
463 } else if (gatherResult == 0) { | |
464 PORT_SetError(PR_END_OF_FILE_ERROR); | |
465 } else if (gatherResult == SECWouldBlock) { | |
466 PORT_SetError(PR_WOULD_BLOCK_ERROR); | |
467 } | |
468 } else if (!ss->firstHsDone) { | |
469 rv = ssl_Do1stHandshake(ss); | |
470 } else { | |
471 /* tried to force handshake on an SSL 2 socket that has | |
472 ** already completed the handshake. */ | |
473 rv = SECSuccess; /* just pretend we did it. */ | |
474 } | |
475 | |
476 ssl_Release1stHandshakeLock(ss); | |
477 | |
478 return rv; | |
479 } | |
480 | |
481 /* | |
482 ** Same as above, but with an I/O timeout. | |
483 */ | |
484 SSL_IMPORT SECStatus | |
485 SSL_ForceHandshakeWithTimeout(PRFileDesc *fd, | |
486 PRIntervalTime timeout) | |
487 { | |
488 if (SECSuccess != ssl_SetTimeout(fd, timeout)) { | |
489 return SECFailure; | |
490 } | |
491 return SSL_ForceHandshake(fd); | |
492 } | |
493 | |
494 /************************************************************************/ | |
495 | |
496 /* | |
497 ** Grow a buffer to hold newLen bytes of data. | |
498 ** Called for both recv buffers and xmit buffers. | |
499 ** Caller must hold xmitBufLock or recvBufLock, as appropriate. | |
500 */ | |
501 SECStatus | |
502 sslBuffer_Grow(sslBuffer *b, unsigned int newLen) | |
503 { | |
504 newLen = PR_MAX(newLen, MAX_FRAGMENT_LENGTH + 2048); | |
505 if (newLen > b->space) { | |
506 unsigned char *newBuf; | |
507 if (b->buf) { | |
508 newBuf = (unsigned char *)PORT_Realloc(b->buf, newLen); | |
509 } else { | |
510 newBuf = (unsigned char *)PORT_Alloc(newLen); | |
511 } | |
512 if (!newBuf) { | |
513 return SECFailure; | |
514 } | |
515 SSL_TRC(10, ("%d: SSL: grow buffer from %d to %d", | |
516 SSL_GETPID(), b->space, newLen)); | |
517 b->buf = newBuf; | |
518 b->space = newLen; | |
519 } | |
520 return SECSuccess; | |
521 } | |
522 | |
523 SECStatus | |
524 sslBuffer_Append(sslBuffer *b, const void *data, unsigned int len) | |
525 { | |
526 unsigned int newLen = b->len + len; | |
527 SECStatus rv; | |
528 | |
529 rv = sslBuffer_Grow(b, newLen); | |
530 if (rv != SECSuccess) | |
531 return rv; | |
532 PORT_Memcpy(b->buf + b->len, data, len); | |
533 b->len += len; | |
534 return SECSuccess; | |
535 } | |
536 | |
537 /* | |
538 ** Save away write data that is trying to be written before the security | |
539 ** handshake has been completed. When the handshake is completed, we will | |
540 ** flush this data out. | |
541 ** Caller must hold xmitBufLock | |
542 */ | |
543 SECStatus | |
544 ssl_SaveWriteData(sslSocket *ss, const void *data, unsigned int len) | |
545 { | |
546 SECStatus rv; | |
547 | |
548 PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); | |
549 rv = sslBuffer_Append(&ss->pendingBuf, data, len); | |
550 SSL_TRC(5, ("%d: SSL[%d]: saving %u bytes of data (%u total saved so far)", | |
551 SSL_GETPID(), ss->fd, len, ss->pendingBuf.len)); | |
552 return rv; | |
553 } | |
554 | |
555 /* | |
556 ** Send saved write data. This will flush out data sent prior to a | |
557 ** complete security handshake. Hopefully there won't be too much of it. | |
558 ** Returns count of the bytes sent, NOT a SECStatus. | |
559 ** Caller must hold xmitBufLock | |
560 */ | |
561 int | |
562 ssl_SendSavedWriteData(sslSocket *ss) | |
563 { | |
564 int rv = 0; | |
565 | |
566 PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); | |
567 if (ss->pendingBuf.len != 0) { | |
568 SSL_TRC(5, ("%d: SSL[%d]: sending %d bytes of saved data", | |
569 SSL_GETPID(), ss->fd, ss->pendingBuf.len)); | |
570 rv = ssl_DefSend(ss, ss->pendingBuf.buf, ss->pendingBuf.len, 0); | |
571 if (rv < 0) { | |
572 return rv; | |
573 } | |
574 ss->pendingBuf.len -= rv; | |
575 if (ss->pendingBuf.len > 0 && rv > 0) { | |
576 /* UGH !! This shifts the whole buffer down by copying it */ | |
577 PORT_Memmove(ss->pendingBuf.buf, ss->pendingBuf.buf + rv, | |
578 ss->pendingBuf.len); | |
579 } | |
580 } | |
581 return rv; | |
582 } | |
583 | |
584 /************************************************************************/ | |
585 | |
586 /* | |
587 ** Receive some application data on a socket. Reads SSL records from the input | |
588 ** stream, decrypts them and then copies them to the output buffer. | |
589 ** Called from ssl_SecureRecv() below. | |
590 ** | |
591 ** Caller does NOT hold 1stHandshakeLock because that handshake is over. | |
592 ** Caller doesn't call this until initial handshake is complete. | |
593 ** For SSLv2, there is no subsequent handshake. | |
594 ** For SSLv3, the call to ssl3_GatherAppDataRecord may encounter handshake | |
595 ** messages from a subsequent handshake. | |
596 ** | |
597 ** This code is similar to, and easily confused with, | |
598 ** ssl_GatherRecord1stHandshake() in sslcon.c | |
599 */ | |
600 static int | |
601 DoRecv(sslSocket *ss, unsigned char *out, int len, int flags) | |
602 { | |
603 int rv; | |
604 int amount; | |
605 int available; | |
606 | |
607 /* ssl3_GatherAppDataRecord may call ssl_FinishHandshake, which needs the | |
608 * 1stHandshakeLock. */ | |
609 ssl_Get1stHandshakeLock(ss); | |
610 ssl_GetRecvBufLock(ss); | |
611 | |
612 available = ss->gs.writeOffset - ss->gs.readOffset; | |
613 if (available == 0) { | |
614 /* Get some more data */ | |
615 if (ss->version >= SSL_LIBRARY_VERSION_3_0) { | |
616 /* Wait for application data to arrive. */ | |
617 rv = ssl3_GatherAppDataRecord(ss, 0); | |
618 } else { | |
619 /* See if we have a complete record */ | |
620 rv = ssl2_GatherRecord(ss, 0); | |
621 } | |
622 if (rv <= 0) { | |
623 if (rv == 0) { | |
624 /* EOF */ | |
625 SSL_TRC(10, ("%d: SSL[%d]: ssl_recv EOF", | |
626 SSL_GETPID(), ss->fd)); | |
627 goto done; | |
628 } | |
629 if ((rv != SECWouldBlock) && | |
630 (PR_GetError() != PR_WOULD_BLOCK_ERROR)) { | |
631 /* Some random error */ | |
632 goto done; | |
633 } | |
634 | |
635 /* | |
636 ** Gather record is blocked waiting for more record data to | |
637 ** arrive. Try to process what we have already received | |
638 */ | |
639 } else { | |
640 /* Gather record has finished getting a complete record */ | |
641 } | |
642 | |
643 /* See if any clear data is now available */ | |
644 available = ss->gs.writeOffset - ss->gs.readOffset; | |
645 if (available == 0) { | |
646 /* | |
647 ** No partial data is available. Force error code to | |
648 ** EWOULDBLOCK so that caller will try again later. Note | |
649 ** that the error code is probably EWOULDBLOCK already, | |
650 ** but if it isn't (for example, if we received a zero | |
651 ** length record) then this will force it to be correct. | |
652 */ | |
653 PORT_SetError(PR_WOULD_BLOCK_ERROR); | |
654 rv = SECFailure; | |
655 goto done; | |
656 } | |
657 SSL_TRC(30, ("%d: SSL[%d]: partial data ready, available=%d", | |
658 SSL_GETPID(), ss->fd, available)); | |
659 } | |
660 | |
661 if (IS_DTLS(ss) && (len < available)) { | |
662 /* DTLS does not allow you to do partial reads */ | |
663 SSL_TRC(30, ("%d: SSL[%d]: DTLS short read. len=%d available=%d", | |
664 SSL_GETPID(), ss->fd, len, available)); | |
665 ss->gs.readOffset += available; | |
666 PORT_SetError(SSL_ERROR_RX_SHORT_DTLS_READ); | |
667 rv = SECFailure; | |
668 goto done; | |
669 } | |
670 | |
671 /* Dole out clear data to reader */ | |
672 amount = PR_MIN(len, available); | |
673 PORT_Memcpy(out, ss->gs.buf.buf + ss->gs.readOffset, amount); | |
674 if (!(flags & PR_MSG_PEEK)) { | |
675 ss->gs.readOffset += amount; | |
676 } | |
677 PORT_Assert(ss->gs.readOffset <= ss->gs.writeOffset); | |
678 rv = amount; | |
679 | |
680 SSL_TRC(30, ("%d: SSL[%d]: amount=%d available=%d", | |
681 SSL_GETPID(), ss->fd, amount, available)); | |
682 PRINT_BUF(4, (ss, "DoRecv receiving plaintext:", out, amount)); | |
683 | |
684 done: | |
685 ssl_ReleaseRecvBufLock(ss); | |
686 ssl_Release1stHandshakeLock(ss); | |
687 return rv; | |
688 } | |
689 | |
690 /************************************************************************/ | |
691 | |
692 /* | |
693 ** Return SSLKEAType derived from cert's Public Key algorithm info. | |
694 */ | |
695 SSLKEAType | |
696 NSS_FindCertKEAType(CERTCertificate *cert) | |
697 { | |
698 SSLKEAType keaType = kt_null; | |
699 int tag; | |
700 | |
701 if (!cert) | |
702 goto loser; | |
703 | |
704 tag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm)); | |
705 | |
706 switch (tag) { | |
707 case SEC_OID_X500_RSA_ENCRYPTION: | |
708 case SEC_OID_PKCS1_RSA_ENCRYPTION: | |
709 keaType = kt_rsa; | |
710 break; | |
711 case SEC_OID_ANSIX9_DSA_SIGNATURE: /* hah, signature, not a key? */ | |
712 case SEC_OID_X942_DIFFIE_HELMAN_KEY: | |
713 keaType = kt_dh; | |
714 break; | |
715 #ifndef NSS_DISABLE_ECC | |
716 case SEC_OID_ANSIX962_EC_PUBLIC_KEY: | |
717 keaType = kt_ecdh; | |
718 break; | |
719 #endif /* NSS_DISABLE_ECC */ | |
720 default: | |
721 keaType = kt_null; | |
722 } | |
723 | |
724 loser: | |
725 | |
726 return keaType; | |
727 } | |
728 | |
729 static const PRCallOnceType pristineCallOnce; | |
730 static PRCallOnceType setupServerCAListOnce; | |
731 | |
732 static SECStatus | |
733 serverCAListShutdown(void *appData, void *nssData) | |
734 { | |
735 PORT_Assert(ssl3_server_ca_list); | |
736 if (ssl3_server_ca_list) { | |
737 CERT_FreeDistNames(ssl3_server_ca_list); | |
738 ssl3_server_ca_list = NULL; | |
739 } | |
740 setupServerCAListOnce = pristineCallOnce; | |
741 return SECSuccess; | |
742 } | |
743 | |
744 static PRStatus | |
745 serverCAListSetup(void *arg) | |
746 { | |
747 CERTCertDBHandle *dbHandle = (CERTCertDBHandle *)arg; | |
748 SECStatus rv = NSS_RegisterShutdown(serverCAListShutdown, NULL); | |
749 PORT_Assert(SECSuccess == rv); | |
750 if (SECSuccess == rv) { | |
751 ssl3_server_ca_list = CERT_GetSSLCACerts(dbHandle); | |
752 return PR_SUCCESS; | |
753 } | |
754 return PR_FAILURE; | |
755 } | |
756 | |
757 SECStatus | |
758 ssl_ConfigSecureServer(sslSocket *ss, CERTCertificate *cert, | |
759 const CERTCertificateList *certChain, | |
760 ssl3KeyPair *keyPair, SSLKEAType kea) | |
761 { | |
762 CERTCertificateList *localCertChain = NULL; | |
763 sslServerCerts *sc = ss->serverCerts + kea; | |
764 | |
765 /* load the server certificate */ | |
766 if (sc->serverCert != NULL) { | |
767 CERT_DestroyCertificate(sc->serverCert); | |
768 sc->serverCert = NULL; | |
769 sc->serverKeyBits = 0; | |
770 } | |
771 /* load the server cert chain */ | |
772 if (sc->serverCertChain != NULL) { | |
773 CERT_DestroyCertificateList(sc->serverCertChain); | |
774 sc->serverCertChain = NULL; | |
775 } | |
776 if (cert) { | |
777 sc->serverCert = CERT_DupCertificate(cert); | |
778 /* get the size of the cert's public key, and remember it */ | |
779 sc->serverKeyBits = SECKEY_PublicKeyStrengthInBits(keyPair->pubKey); | |
780 if (!certChain) { | |
781 localCertChain = | |
782 CERT_CertChainFromCert(sc->serverCert, certUsageSSLServer, | |
783 PR_TRUE); | |
784 if (!localCertChain) | |
785 goto loser; | |
786 } | |
787 sc->serverCertChain = (certChain) ? CERT_DupCertList(certChain) : | |
788 localCertChain; | |
789 if (!sc->serverCertChain) { | |
790 goto loser; | |
791 } | |
792 localCertChain = NULL; /* consumed */ | |
793 } | |
794 | |
795 /* get keyPair */ | |
796 if (sc->serverKeyPair != NULL) { | |
797 ssl3_FreeKeyPair(sc->serverKeyPair); | |
798 sc->serverKeyPair = NULL; | |
799 } | |
800 if (keyPair) { | |
801 SECKEY_CacheStaticFlags(keyPair->privKey); | |
802 sc->serverKeyPair = ssl3_GetKeyPairRef(keyPair); | |
803 } | |
804 if (kea == kt_rsa && cert && sc->serverKeyBits > 512 && | |
805 !ss->opt.noStepDown && !ss->stepDownKeyPair) { | |
806 if (ssl3_CreateRSAStepDownKeys(ss) != SECSuccess) { | |
807 goto loser; | |
808 } | |
809 } | |
810 if (kea == ssl_kea_dh || kea == ssl_kea_rsa) { | |
811 if (ssl3_SelectDHParams(ss) != SECSuccess) { | |
812 goto loser; | |
813 } | |
814 } | |
815 return SECSuccess; | |
816 | |
817 loser: | |
818 if (localCertChain) { | |
819 CERT_DestroyCertificateList(localCertChain); | |
820 } | |
821 if (sc->serverCert != NULL) { | |
822 CERT_DestroyCertificate(sc->serverCert); | |
823 sc->serverCert = NULL; | |
824 } | |
825 if (sc->serverCertChain != NULL) { | |
826 CERT_DestroyCertificateList(sc->serverCertChain); | |
827 sc->serverCertChain = NULL; | |
828 } | |
829 if (sc->serverKeyPair != NULL) { | |
830 ssl3_FreeKeyPair(sc->serverKeyPair); | |
831 sc->serverKeyPair = NULL; | |
832 } | |
833 return SECFailure; | |
834 } | |
835 | |
836 /* XXX need to protect the data that gets changed here.!! */ | |
837 | |
838 SECStatus | |
839 SSL_ConfigSecureServer(PRFileDesc *fd, CERTCertificate *cert, | |
840 SECKEYPrivateKey *key, SSL3KEAType kea) | |
841 { | |
842 | |
843 return SSL_ConfigSecureServerWithCertChain(fd, cert, NULL, key, kea); | |
844 } | |
845 | |
846 SECStatus | |
847 SSL_ConfigSecureServerWithCertChain(PRFileDesc *fd, CERTCertificate *cert, | |
848 const CERTCertificateList *certChainOpt, | |
849 SECKEYPrivateKey *key, SSL3KEAType kea) | |
850 { | |
851 sslSocket *ss; | |
852 SECKEYPublicKey *pubKey = NULL; | |
853 ssl3KeyPair *keyPair = NULL; | |
854 SECStatus rv = SECFailure; | |
855 | |
856 ss = ssl_FindSocket(fd); | |
857 if (!ss) { | |
858 return SECFailure; | |
859 } | |
860 | |
861 /* Both key and cert must have a value or be NULL */ | |
862 /* Passing a value of NULL will turn off key exchange algorithms that were | |
863 * previously turned on */ | |
864 if (!cert != !key) { | |
865 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
866 return SECFailure; | |
867 } | |
868 | |
869 /* make sure the key exchange is recognized */ | |
870 if ((kea >= kt_kea_size) || (kea < kt_null)) { | |
871 PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); | |
872 return SECFailure; | |
873 } | |
874 | |
875 if (kea != NSS_FindCertKEAType(cert)) { | |
876 PORT_SetError(SSL_ERROR_CERT_KEA_MISMATCH); | |
877 return SECFailure; | |
878 } | |
879 | |
880 if (cert) { | |
881 /* get the size of the cert's public key, and remember it */ | |
882 pubKey = CERT_ExtractPublicKey(cert); | |
883 if (!pubKey) | |
884 return SECFailure; | |
885 } | |
886 | |
887 if (key) { | |
888 SECKEYPrivateKey *keyCopy = NULL; | |
889 CK_MECHANISM_TYPE keyMech = CKM_INVALID_MECHANISM; | |
890 | |
891 if (key->pkcs11Slot) { | |
892 PK11SlotInfo *bestSlot; | |
893 bestSlot = PK11_ReferenceSlot(key->pkcs11Slot); | |
894 if (bestSlot) { | |
895 keyCopy = PK11_CopyTokenPrivKeyToSessionPrivKey(bestSlot, key); | |
896 PK11_FreeSlot(bestSlot); | |
897 } | |
898 } | |
899 if (keyCopy == NULL) | |
900 keyMech = PK11_MapSignKeyType(key->keyType); | |
901 if (keyMech != CKM_INVALID_MECHANISM) { | |
902 PK11SlotInfo *bestSlot; | |
903 /* XXX Maybe should be bestSlotMultiple? */ | |
904 bestSlot = PK11_GetBestSlot(keyMech, NULL /* wincx */); | |
905 if (bestSlot) { | |
906 keyCopy = PK11_CopyTokenPrivKeyToSessionPrivKey(bestSlot, key); | |
907 PK11_FreeSlot(bestSlot); | |
908 } | |
909 } | |
910 if (keyCopy == NULL) | |
911 keyCopy = SECKEY_CopyPrivateKey(key); | |
912 if (keyCopy == NULL) | |
913 goto loser; | |
914 keyPair = ssl3_NewKeyPair(keyCopy, pubKey); | |
915 if (keyPair == NULL) { | |
916 SECKEY_DestroyPrivateKey(keyCopy); | |
917 goto loser; | |
918 } | |
919 pubKey = NULL; /* adopted by serverKeyPair */ | |
920 } | |
921 if (ssl_ConfigSecureServer(ss, cert, certChainOpt, | |
922 keyPair, kea) == SECFailure) { | |
923 goto loser; | |
924 } | |
925 | |
926 /* Only do this once because it's global. */ | |
927 if (PR_SUCCESS == PR_CallOnceWithArg(&setupServerCAListOnce, | |
928 &serverCAListSetup, | |
929 (void *)(ss->dbHandle))) { | |
930 rv = SECSuccess; | |
931 } | |
932 | |
933 loser: | |
934 if (keyPair) { | |
935 ssl3_FreeKeyPair(keyPair); | |
936 } | |
937 if (pubKey) { | |
938 SECKEY_DestroyPublicKey(pubKey); | |
939 pubKey = NULL; | |
940 } | |
941 return rv; | |
942 } | |
943 | |
944 /************************************************************************/ | |
945 | |
946 SECStatus | |
947 ssl_CreateSecurityInfo(sslSocket *ss) | |
948 { | |
949 SECStatus status; | |
950 | |
951 /* initialize sslv2 socket to send data in the clear. */ | |
952 ssl2_UseClearSendFunc(ss); | |
953 | |
954 ss->sec.blockSize = 1; | |
955 ss->sec.blockShift = 0; | |
956 | |
957 ssl_GetXmitBufLock(ss); | |
958 status = sslBuffer_Grow(&ss->sec.writeBuf, 4096); | |
959 ssl_ReleaseXmitBufLock(ss); | |
960 | |
961 return status; | |
962 } | |
963 | |
964 SECStatus | |
965 ssl_CopySecurityInfo(sslSocket *ss, sslSocket *os) | |
966 { | |
967 ss->sec.send = os->sec.send; | |
968 ss->sec.isServer = os->sec.isServer; | |
969 ss->sec.keyBits = os->sec.keyBits; | |
970 ss->sec.secretKeyBits = os->sec.secretKeyBits; | |
971 | |
972 ss->sec.peerCert = CERT_DupCertificate(os->sec.peerCert); | |
973 if (os->sec.peerCert && !ss->sec.peerCert) | |
974 goto loser; | |
975 | |
976 ss->sec.cache = os->sec.cache; | |
977 ss->sec.uncache = os->sec.uncache; | |
978 | |
979 /* we don't dup the connection info. */ | |
980 | |
981 ss->sec.sendSequence = os->sec.sendSequence; | |
982 ss->sec.rcvSequence = os->sec.rcvSequence; | |
983 | |
984 if (os->sec.hash && os->sec.hashcx) { | |
985 ss->sec.hash = os->sec.hash; | |
986 ss->sec.hashcx = os->sec.hash->clone(os->sec.hashcx); | |
987 if (os->sec.hashcx && !ss->sec.hashcx) | |
988 goto loser; | |
989 } else { | |
990 ss->sec.hash = NULL; | |
991 ss->sec.hashcx = NULL; | |
992 } | |
993 | |
994 if (SECITEM_CopyItem(0, &ss->sec.sendSecret, &os->sec.sendSecret)) | |
995 goto loser; | |
996 if (SECITEM_CopyItem(0, &ss->sec.rcvSecret, &os->sec.rcvSecret)) | |
997 goto loser; | |
998 | |
999 /* XXX following code is wrong if either cx != 0 */ | |
1000 PORT_Assert(os->sec.readcx == 0); | |
1001 PORT_Assert(os->sec.writecx == 0); | |
1002 ss->sec.readcx = os->sec.readcx; | |
1003 ss->sec.writecx = os->sec.writecx; | |
1004 ss->sec.destroy = 0; | |
1005 | |
1006 ss->sec.enc = os->sec.enc; | |
1007 ss->sec.dec = os->sec.dec; | |
1008 | |
1009 ss->sec.blockShift = os->sec.blockShift; | |
1010 ss->sec.blockSize = os->sec.blockSize; | |
1011 | |
1012 return SECSuccess; | |
1013 | |
1014 loser: | |
1015 return SECFailure; | |
1016 } | |
1017 | |
1018 /* Reset sec back to its initial state. | |
1019 ** Caller holds any relevant locks. | |
1020 */ | |
1021 void | |
1022 ssl_ResetSecurityInfo(sslSecurityInfo *sec, PRBool doMemset) | |
1023 { | |
1024 /* Destroy MAC */ | |
1025 if (sec->hash && sec->hashcx) { | |
1026 (*sec->hash->destroy)(sec->hashcx, PR_TRUE); | |
1027 sec->hashcx = NULL; | |
1028 sec->hash = NULL; | |
1029 } | |
1030 SECITEM_ZfreeItem(&sec->sendSecret, PR_FALSE); | |
1031 SECITEM_ZfreeItem(&sec->rcvSecret, PR_FALSE); | |
1032 | |
1033 /* Destroy ciphers */ | |
1034 if (sec->destroy) { | |
1035 (*sec->destroy)(sec->readcx, PR_TRUE); | |
1036 (*sec->destroy)(sec->writecx, PR_TRUE); | |
1037 sec->readcx = NULL; | |
1038 sec->writecx = NULL; | |
1039 } else { | |
1040 PORT_Assert(sec->readcx == 0); | |
1041 PORT_Assert(sec->writecx == 0); | |
1042 } | |
1043 sec->readcx = 0; | |
1044 sec->writecx = 0; | |
1045 | |
1046 if (sec->localCert) { | |
1047 CERT_DestroyCertificate(sec->localCert); | |
1048 sec->localCert = NULL; | |
1049 } | |
1050 if (sec->peerCert) { | |
1051 CERT_DestroyCertificate(sec->peerCert); | |
1052 sec->peerCert = NULL; | |
1053 } | |
1054 if (sec->peerKey) { | |
1055 SECKEY_DestroyPublicKey(sec->peerKey); | |
1056 sec->peerKey = NULL; | |
1057 } | |
1058 | |
1059 /* cleanup the ci */ | |
1060 if (sec->ci.sid != NULL) { | |
1061 ssl_FreeSID(sec->ci.sid); | |
1062 } | |
1063 PORT_ZFree(sec->ci.sendBuf.buf, sec->ci.sendBuf.space); | |
1064 if (doMemset) { | |
1065 memset(&sec->ci, 0, sizeof sec->ci); | |
1066 } | |
1067 } | |
1068 | |
1069 /* | |
1070 ** Called from SSL_ResetHandshake (above), and | |
1071 ** from ssl_FreeSocket in sslsock.c | |
1072 ** Caller should hold relevant locks (e.g. XmitBufLock) | |
1073 */ | |
1074 void | |
1075 ssl_DestroySecurityInfo(sslSecurityInfo *sec) | |
1076 { | |
1077 ssl_ResetSecurityInfo(sec, PR_FALSE); | |
1078 | |
1079 PORT_ZFree(sec->writeBuf.buf, sec->writeBuf.space); | |
1080 sec->writeBuf.buf = 0; | |
1081 | |
1082 memset(sec, 0, sizeof *sec); | |
1083 } | |
1084 | |
1085 /************************************************************************/ | |
1086 | |
1087 int | |
1088 ssl_SecureConnect(sslSocket *ss, const PRNetAddr *sa) | |
1089 { | |
1090 PRFileDesc *osfd = ss->fd->lower; | |
1091 int rv; | |
1092 | |
1093 if (ss->opt.handshakeAsServer) { | |
1094 ss->securityHandshake = ssl2_BeginServerHandshake; | |
1095 ss->handshaking = sslHandshakingAsServer; | |
1096 } else { | |
1097 ss->securityHandshake = ssl2_BeginClientHandshake; | |
1098 ss->handshaking = sslHandshakingAsClient; | |
1099 } | |
1100 | |
1101 /* connect to server */ | |
1102 rv = osfd->methods->connect(osfd, sa, ss->cTimeout); | |
1103 if (rv == PR_SUCCESS) { | |
1104 ss->TCPconnected = 1; | |
1105 } else { | |
1106 int err = PR_GetError(); | |
1107 SSL_DBG(("%d: SSL[%d]: connect failed, errno=%d", | |
1108 SSL_GETPID(), ss->fd, err)); | |
1109 if (err == PR_IS_CONNECTED_ERROR) { | |
1110 ss->TCPconnected = 1; | |
1111 } | |
1112 } | |
1113 | |
1114 SSL_TRC(5, ("%d: SSL[%d]: secure connect completed, rv == %d", | |
1115 SSL_GETPID(), ss->fd, rv)); | |
1116 return rv; | |
1117 } | |
1118 | |
1119 /* | |
1120 * The TLS 1.2 RFC 5246, Section 7.2.1 says: | |
1121 * | |
1122 * Unless some other fatal alert has been transmitted, each party is | |
1123 * required to send a close_notify alert before closing the write side | |
1124 * of the connection. The other party MUST respond with a close_notify | |
1125 * alert of its own and close down the connection immediately, | |
1126 * discarding any pending writes. It is not required for the initiator | |
1127 * of the close to wait for the responding close_notify alert before | |
1128 * closing the read side of the connection. | |
1129 * | |
1130 * The second sentence requires that we send a close_notify alert when we | |
1131 * have received a close_notify alert. In practice, all SSL implementations | |
1132 * close the socket immediately after sending a close_notify alert (which is | |
1133 * allowed by the third sentence), so responding with a close_notify alert | |
1134 * would result in a write failure with the ECONNRESET error. This is why | |
1135 * we don't respond with a close_notify alert. | |
1136 * | |
1137 * Also, in the unlikely event that the TCP pipe is full and the peer stops | |
1138 * reading, the SSL3_SendAlert call in ssl_SecureClose and ssl_SecureShutdown | |
1139 * may block indefinitely in blocking mode, and may fail (without retrying) | |
1140 * in non-blocking mode. | |
1141 */ | |
1142 | |
1143 int | |
1144 ssl_SecureClose(sslSocket *ss) | |
1145 { | |
1146 int rv; | |
1147 | |
1148 if (ss->version >= SSL_LIBRARY_VERSION_3_0 && | |
1149 !(ss->shutdownHow & ssl_SHUTDOWN_SEND) && | |
1150 ss->firstHsDone && | |
1151 !ss->recvdCloseNotify && | |
1152 ss->ssl3.initialized) { | |
1153 | |
1154 /* We don't want the final alert to be Nagle delayed. */ | |
1155 if (!ss->delayDisabled) { | |
1156 ssl_EnableNagleDelay(ss, PR_FALSE); | |
1157 ss->delayDisabled = 1; | |
1158 } | |
1159 | |
1160 (void)SSL3_SendAlert(ss, alert_warning, close_notify); | |
1161 } | |
1162 rv = ssl_DefClose(ss); | |
1163 return rv; | |
1164 } | |
1165 | |
1166 /* Caller handles all locking */ | |
1167 int | |
1168 ssl_SecureShutdown(sslSocket *ss, int nsprHow) | |
1169 { | |
1170 PRFileDesc *osfd = ss->fd->lower; | |
1171 int rv; | |
1172 PRIntn sslHow = nsprHow + 1; | |
1173 | |
1174 if ((unsigned)nsprHow > PR_SHUTDOWN_BOTH) { | |
1175 PORT_SetError(PR_INVALID_ARGUMENT_ERROR); | |
1176 return PR_FAILURE; | |
1177 } | |
1178 | |
1179 if ((sslHow & ssl_SHUTDOWN_SEND) != 0 && | |
1180 ss->version >= SSL_LIBRARY_VERSION_3_0 && | |
1181 !(ss->shutdownHow & ssl_SHUTDOWN_SEND) && | |
1182 ss->firstHsDone && | |
1183 !ss->recvdCloseNotify && | |
1184 ss->ssl3.initialized) { | |
1185 | |
1186 (void)SSL3_SendAlert(ss, alert_warning, close_notify); | |
1187 } | |
1188 | |
1189 rv = osfd->methods->shutdown(osfd, nsprHow); | |
1190 | |
1191 ss->shutdownHow |= sslHow; | |
1192 | |
1193 return rv; | |
1194 } | |
1195 | |
1196 /************************************************************************/ | |
1197 | |
1198 int | |
1199 ssl_SecureRecv(sslSocket *ss, unsigned char *buf, int len, int flags) | |
1200 { | |
1201 int rv = 0; | |
1202 | |
1203 if (ss->shutdownHow & ssl_SHUTDOWN_RCV) { | |
1204 PORT_SetError(PR_SOCKET_SHUTDOWN_ERROR); | |
1205 return PR_FAILURE; | |
1206 } | |
1207 if (flags & ~PR_MSG_PEEK) { | |
1208 PORT_SetError(PR_INVALID_ARGUMENT_ERROR); | |
1209 return PR_FAILURE; | |
1210 } | |
1211 | |
1212 if (!ssl_SocketIsBlocking(ss) && !ss->opt.fdx) { | |
1213 ssl_GetXmitBufLock(ss); | |
1214 if (ss->pendingBuf.len != 0) { | |
1215 rv = ssl_SendSavedWriteData(ss); | |
1216 if ((rv < 0) && (PORT_GetError() != PR_WOULD_BLOCK_ERROR)) { | |
1217 ssl_ReleaseXmitBufLock(ss); | |
1218 return SECFailure; | |
1219 } | |
1220 } | |
1221 ssl_ReleaseXmitBufLock(ss); | |
1222 } | |
1223 | |
1224 rv = 0; | |
1225 /* If any of these is non-zero, the initial handshake is not done. */ | |
1226 if (!ss->firstHsDone) { | |
1227 ssl_Get1stHandshakeLock(ss); | |
1228 if (ss->handshake || ss->nextHandshake || ss->securityHandshake) { | |
1229 rv = ssl_Do1stHandshake(ss); | |
1230 } | |
1231 ssl_Release1stHandshakeLock(ss); | |
1232 } | |
1233 if (rv < 0) { | |
1234 return rv; | |
1235 } | |
1236 | |
1237 if (len == 0) | |
1238 return 0; | |
1239 | |
1240 rv = DoRecv(ss, (unsigned char *)buf, len, flags); | |
1241 SSL_TRC(2, ("%d: SSL[%d]: recving %d bytes securely (errno=%d)", | |
1242 SSL_GETPID(), ss->fd, rv, PORT_GetError())); | |
1243 return rv; | |
1244 } | |
1245 | |
1246 int | |
1247 ssl_SecureRead(sslSocket *ss, unsigned char *buf, int len) | |
1248 { | |
1249 return ssl_SecureRecv(ss, buf, len, 0); | |
1250 } | |
1251 | |
1252 /* Caller holds the SSL Socket's write lock. SSL_LOCK_WRITER(ss) */ | |
1253 int | |
1254 ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags) | |
1255 { | |
1256 int rv = 0; | |
1257 | |
1258 SSL_TRC(2, ("%d: SSL[%d]: SecureSend: sending %d bytes", | |
1259 SSL_GETPID(), ss->fd, len)); | |
1260 | |
1261 if (ss->shutdownHow & ssl_SHUTDOWN_SEND) { | |
1262 PORT_SetError(PR_SOCKET_SHUTDOWN_ERROR); | |
1263 rv = PR_FAILURE; | |
1264 goto done; | |
1265 } | |
1266 if (flags) { | |
1267 PORT_SetError(PR_INVALID_ARGUMENT_ERROR); | |
1268 rv = PR_FAILURE; | |
1269 goto done; | |
1270 } | |
1271 | |
1272 ssl_GetXmitBufLock(ss); | |
1273 if (ss->pendingBuf.len != 0) { | |
1274 PORT_Assert(ss->pendingBuf.len > 0); | |
1275 rv = ssl_SendSavedWriteData(ss); | |
1276 if (rv >= 0 && ss->pendingBuf.len != 0) { | |
1277 PORT_Assert(ss->pendingBuf.len > 0); | |
1278 PORT_SetError(PR_WOULD_BLOCK_ERROR); | |
1279 rv = SECFailure; | |
1280 } | |
1281 } | |
1282 ssl_ReleaseXmitBufLock(ss); | |
1283 if (rv < 0) { | |
1284 goto done; | |
1285 } | |
1286 | |
1287 if (len > 0) | |
1288 ss->writerThread = PR_GetCurrentThread(); | |
1289 /* If any of these is non-zero, the initial handshake is not done. */ | |
1290 if (!ss->firstHsDone) { | |
1291 PRBool falseStart = PR_FALSE; | |
1292 ssl_Get1stHandshakeLock(ss); | |
1293 if (ss->opt.enableFalseStart && | |
1294 ss->version >= SSL_LIBRARY_VERSION_3_0) { | |
1295 ssl_GetSSL3HandshakeLock(ss); | |
1296 falseStart = ss->ssl3.hs.canFalseStart; | |
1297 ssl_ReleaseSSL3HandshakeLock(ss); | |
1298 } | |
1299 if (!falseStart && | |
1300 (ss->handshake || ss->nextHandshake || ss->securityHandshake)) { | |
1301 rv = ssl_Do1stHandshake(ss); | |
1302 } | |
1303 ssl_Release1stHandshakeLock(ss); | |
1304 } | |
1305 if (rv < 0) { | |
1306 ss->writerThread = NULL; | |
1307 goto done; | |
1308 } | |
1309 | |
1310 /* Check for zero length writes after we do housekeeping so we make forward | |
1311 * progress. | |
1312 */ | |
1313 if (len == 0) { | |
1314 rv = 0; | |
1315 goto done; | |
1316 } | |
1317 PORT_Assert(buf != NULL); | |
1318 if (!buf) { | |
1319 PORT_SetError(PR_INVALID_ARGUMENT_ERROR); | |
1320 rv = PR_FAILURE; | |
1321 goto done; | |
1322 } | |
1323 | |
1324 if (!ss->firstHsDone) { | |
1325 PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_3_0); | |
1326 #ifdef DEBUG | |
1327 ssl_GetSSL3HandshakeLock(ss); | |
1328 PORT_Assert(ss->ssl3.hs.canFalseStart); | |
1329 ssl_ReleaseSSL3HandshakeLock(ss); | |
1330 #endif | |
1331 SSL_TRC(3, ("%d: SSL[%d]: SecureSend: sending data due to false start", | |
1332 SSL_GETPID(), ss->fd)); | |
1333 } | |
1334 | |
1335 /* Send out the data using one of these functions: | |
1336 * ssl2_SendClear, ssl2_SendStream, ssl2_SendBlock, | |
1337 * ssl3_SendApplicationData | |
1338 */ | |
1339 ssl_GetXmitBufLock(ss); | |
1340 rv = (*ss->sec.send)(ss, buf, len, flags); | |
1341 ssl_ReleaseXmitBufLock(ss); | |
1342 ss->writerThread = NULL; | |
1343 done: | |
1344 if (rv < 0) { | |
1345 SSL_TRC(2, ("%d: SSL[%d]: SecureSend: returning %d count, error %d", | |
1346 SSL_GETPID(), ss->fd, rv, PORT_GetError())); | |
1347 } else { | |
1348 SSL_TRC(2, ("%d: SSL[%d]: SecureSend: returning %d count", | |
1349 SSL_GETPID(), ss->fd, rv)); | |
1350 } | |
1351 return rv; | |
1352 } | |
1353 | |
1354 int | |
1355 ssl_SecureWrite(sslSocket *ss, const unsigned char *buf, int len) | |
1356 { | |
1357 return ssl_SecureSend(ss, buf, len, 0); | |
1358 } | |
1359 | |
1360 SECStatus | |
1361 SSL_BadCertHook(PRFileDesc *fd, SSLBadCertHandler f, void *arg) | |
1362 { | |
1363 sslSocket *ss; | |
1364 | |
1365 ss = ssl_FindSocket(fd); | |
1366 if (!ss) { | |
1367 SSL_DBG(("%d: SSL[%d]: bad socket in SSLBadCertHook", | |
1368 SSL_GETPID(), fd)); | |
1369 return SECFailure; | |
1370 } | |
1371 | |
1372 ss->handleBadCert = f; | |
1373 ss->badCertArg = arg; | |
1374 | |
1375 return SECSuccess; | |
1376 } | |
1377 | |
1378 /* | |
1379 * Allow the application to pass the url or hostname into the SSL library | |
1380 * so that we can do some checking on it. It will be used for the value in | |
1381 * SNI extension of client hello message. | |
1382 */ | |
1383 SECStatus | |
1384 SSL_SetURL(PRFileDesc *fd, const char *url) | |
1385 { | |
1386 sslSocket *ss = ssl_FindSocket(fd); | |
1387 SECStatus rv = SECSuccess; | |
1388 | |
1389 if (!ss) { | |
1390 SSL_DBG(("%d: SSL[%d]: bad socket in SSLSetURL", | |
1391 SSL_GETPID(), fd)); | |
1392 return SECFailure; | |
1393 } | |
1394 ssl_Get1stHandshakeLock(ss); | |
1395 ssl_GetSSL3HandshakeLock(ss); | |
1396 | |
1397 if (ss->url) { | |
1398 PORT_Free((void *)ss->url); /* CONST */ | |
1399 } | |
1400 | |
1401 ss->url = (const char *)PORT_Strdup(url); | |
1402 if (ss->url == NULL) { | |
1403 rv = SECFailure; | |
1404 } | |
1405 | |
1406 ssl_ReleaseSSL3HandshakeLock(ss); | |
1407 ssl_Release1stHandshakeLock(ss); | |
1408 | |
1409 return rv; | |
1410 } | |
1411 | |
1412 /* | |
1413 * Allow the application to pass the set of trust anchors | |
1414 */ | |
1415 SECStatus | |
1416 SSL_SetTrustAnchors(PRFileDesc *fd, CERTCertList *certList) | |
1417 { | |
1418 sslSocket *ss = ssl_FindSocket(fd); | |
1419 CERTDistNames *names = NULL; | |
1420 | |
1421 if (!certList) { | |
1422 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
1423 return SECFailure; | |
1424 } | |
1425 if (!ss) { | |
1426 SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetTrustAnchors", | |
1427 SSL_GETPID(), fd)); | |
1428 return SECFailure; | |
1429 } | |
1430 | |
1431 names = CERT_DistNamesFromCertList(certList); | |
1432 if (names == NULL) { | |
1433 return SECFailure; | |
1434 } | |
1435 ssl_Get1stHandshakeLock(ss); | |
1436 ssl_GetSSL3HandshakeLock(ss); | |
1437 if (ss->ssl3.ca_list) { | |
1438 CERT_FreeDistNames(ss->ssl3.ca_list); | |
1439 } | |
1440 ss->ssl3.ca_list = names; | |
1441 ssl_ReleaseSSL3HandshakeLock(ss); | |
1442 ssl_Release1stHandshakeLock(ss); | |
1443 | |
1444 return SECSuccess; | |
1445 } | |
1446 | |
1447 /* | |
1448 ** Returns Negative number on error, zero or greater on success. | |
1449 ** Returns the amount of data immediately available to be read. | |
1450 */ | |
1451 int | |
1452 SSL_DataPending(PRFileDesc *fd) | |
1453 { | |
1454 sslSocket *ss; | |
1455 int rv = 0; | |
1456 | |
1457 ss = ssl_FindSocket(fd); | |
1458 | |
1459 if (ss && ss->opt.useSecurity) { | |
1460 ssl_GetRecvBufLock(ss); | |
1461 rv = ss->gs.writeOffset - ss->gs.readOffset; | |
1462 ssl_ReleaseRecvBufLock(ss); | |
1463 } | |
1464 | |
1465 return rv; | |
1466 } | |
1467 | |
1468 SECStatus | |
1469 SSL_InvalidateSession(PRFileDesc *fd) | |
1470 { | |
1471 sslSocket *ss = ssl_FindSocket(fd); | |
1472 SECStatus rv = SECFailure; | |
1473 | |
1474 if (ss) { | |
1475 ssl_Get1stHandshakeLock(ss); | |
1476 ssl_GetSSL3HandshakeLock(ss); | |
1477 | |
1478 if (ss->sec.ci.sid && ss->sec.uncache) { | |
1479 ss->sec.uncache(ss->sec.ci.sid); | |
1480 rv = SECSuccess; | |
1481 } | |
1482 | |
1483 ssl_ReleaseSSL3HandshakeLock(ss); | |
1484 ssl_Release1stHandshakeLock(ss); | |
1485 } | |
1486 return rv; | |
1487 } | |
1488 | |
1489 static void | |
1490 ssl3_CacheSessionUnlocked(sslSocket *ss) | |
1491 { | |
1492 PORT_Assert(!ss->sec.isServer); | |
1493 | |
1494 if (ss->ssl3.hs.cacheSID) { | |
1495 ss->sec.cache(ss->sec.ci.sid); | |
1496 ss->ssl3.hs.cacheSID = PR_FALSE; | |
1497 } | |
1498 } | |
1499 | |
1500 SECStatus | |
1501 SSL_CacheSession(PRFileDesc *fd) | |
1502 { | |
1503 sslSocket *ss = ssl_FindSocket(fd); | |
1504 SECStatus rv = SECFailure; | |
1505 | |
1506 if (ss) { | |
1507 ssl_Get1stHandshakeLock(ss); | |
1508 ssl_GetSSL3HandshakeLock(ss); | |
1509 | |
1510 ssl3_CacheSessionUnlocked(ss); | |
1511 rv = SECSuccess; | |
1512 | |
1513 ssl_ReleaseSSL3HandshakeLock(ss); | |
1514 ssl_Release1stHandshakeLock(ss); | |
1515 } | |
1516 return rv; | |
1517 } | |
1518 | |
1519 SECStatus | |
1520 SSL_CacheSessionUnlocked(PRFileDesc *fd) | |
1521 { | |
1522 sslSocket *ss = ssl_FindSocket(fd); | |
1523 SECStatus rv = SECFailure; | |
1524 | |
1525 if (ss) { | |
1526 ssl3_CacheSessionUnlocked(ss); | |
1527 rv = SECSuccess; | |
1528 } | |
1529 return rv; | |
1530 } | |
1531 | |
1532 SECItem * | |
1533 SSL_GetSessionID(PRFileDesc *fd) | |
1534 { | |
1535 sslSocket *ss; | |
1536 SECItem *item = NULL; | |
1537 | |
1538 ss = ssl_FindSocket(fd); | |
1539 if (ss) { | |
1540 ssl_Get1stHandshakeLock(ss); | |
1541 ssl_GetSSL3HandshakeLock(ss); | |
1542 | |
1543 if (ss->opt.useSecurity && ss->firstHsDone && ss->sec.ci.sid) { | |
1544 item = (SECItem *)PORT_Alloc(sizeof(SECItem)); | |
1545 if (item) { | |
1546 sslSessionID *sid = ss->sec.ci.sid; | |
1547 if (sid->version < SSL_LIBRARY_VERSION_3_0) { | |
1548 item->len = SSL2_SESSIONID_BYTES; | |
1549 item->data = (unsigned char *)PORT_Alloc(item->len); | |
1550 PORT_Memcpy(item->data, sid->u.ssl2.sessionID, item->len); | |
1551 } else { | |
1552 item->len = sid->u.ssl3.sessionIDLength; | |
1553 item->data = (unsigned char *)PORT_Alloc(item->len); | |
1554 PORT_Memcpy(item->data, sid->u.ssl3.sessionID, item->len); | |
1555 } | |
1556 } | |
1557 } | |
1558 | |
1559 ssl_ReleaseSSL3HandshakeLock(ss); | |
1560 ssl_Release1stHandshakeLock(ss); | |
1561 } | |
1562 return item; | |
1563 } | |
1564 | |
1565 SECStatus | |
1566 SSL_CertDBHandleSet(PRFileDesc *fd, CERTCertDBHandle *dbHandle) | |
1567 { | |
1568 sslSocket *ss; | |
1569 | |
1570 ss = ssl_FindSocket(fd); | |
1571 if (!ss) | |
1572 return SECFailure; | |
1573 if (!dbHandle) { | |
1574 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
1575 return SECFailure; | |
1576 } | |
1577 ss->dbHandle = dbHandle; | |
1578 return SECSuccess; | |
1579 } | |
1580 | |
1581 /* | |
1582 * attempt to restart the handshake after asynchronously handling | |
1583 * a request for the client's certificate. | |
1584 * | |
1585 * inputs: | |
1586 * cert Client cert chosen by application. | |
1587 * Note: ssl takes this reference, and does not bump the | |
1588 * reference count. The caller should drop its reference | |
1589 * without calling CERT_DestroyCertificate after calling this | |
1590 * function. | |
1591 * | |
1592 * key Private key associated with cert. This function takes | |
1593 * ownership of the private key, so the caller should drop its | |
1594 * reference without destroying the private key after this | |
1595 * function returns. | |
1596 * | |
1597 * certChain Chain of signers for cert. | |
1598 * Note: ssl takes this reference, and does not copy the chain. | |
1599 * The caller should drop its reference without destroying the | |
1600 * chain. SSL will free the chain when it is done with it. | |
1601 * | |
1602 * Return value: XXX | |
1603 * | |
1604 * XXX This code only works on the initial handshake on a connection, XXX | |
1605 * It does not work on a subsequent handshake (redo). | |
1606 */ | |
1607 SECStatus | |
1608 SSL_RestartHandshakeAfterCertReq(PRFileDesc *fd, | |
1609 CERTCertificate *cert, | |
1610 SECKEYPrivateKey *key, | |
1611 CERTCertificateList *certChain) | |
1612 { | |
1613 sslSocket *ss = ssl_FindSocket(fd); | |
1614 SECStatus ret; | |
1615 | |
1616 if (!ss) { | |
1617 SSL_DBG(("%d: SSL[%d]: bad socket in SSL_RestartHandshakeAfterCertReq", | |
1618 SSL_GETPID(), fd)); | |
1619 if (cert) { | |
1620 CERT_DestroyCertificate(cert); | |
1621 } | |
1622 if (key) { | |
1623 SECKEY_DestroyPrivateKey(key); | |
1624 } | |
1625 if (certChain) { | |
1626 CERT_DestroyCertificateList(certChain); | |
1627 } | |
1628 return SECFailure; | |
1629 } | |
1630 | |
1631 ssl_Get1stHandshakeLock(ss); /************************************/ | |
1632 | |
1633 if (ss->version >= SSL_LIBRARY_VERSION_3_0) { | |
1634 ret = ssl3_RestartHandshakeAfterCertReq(ss, cert, key, certChain); | |
1635 } else { | |
1636 if (certChain != NULL) { | |
1637 CERT_DestroyCertificateList(certChain); | |
1638 } | |
1639 PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2); | |
1640 ret = SECFailure; | |
1641 } | |
1642 | |
1643 ssl_Release1stHandshakeLock(ss); /************************************/ | |
1644 return ret; | |
1645 } | |
1646 | |
1647 SECStatus | |
1648 SSL_RestartHandshakeAfterChannelIDReq(PRFileDesc *fd, | |
1649 SECKEYPublicKey *channelIDPub, | |
1650 SECKEYPrivateKey *channelID) | |
1651 { | |
1652 sslSocket *ss = ssl_FindSocket(fd); | |
1653 SECStatus ret; | |
1654 | |
1655 if (!ss) { | |
1656 SSL_DBG(("%d: SSL[%d]: bad socket in" | |
1657 " SSL_RestartHandshakeAfterChannelIDReq", | |
1658 SSL_GETPID(), fd)); | |
1659 goto loser; | |
1660 } | |
1661 | |
1662 ssl_Get1stHandshakeLock(ss); | |
1663 | |
1664 if (ss->version < SSL_LIBRARY_VERSION_3_0) { | |
1665 PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2); | |
1666 ssl_Release1stHandshakeLock(ss); | |
1667 goto loser; | |
1668 } | |
1669 | |
1670 ret = ssl3_RestartHandshakeAfterChannelIDReq(ss, channelIDPub, | |
1671 channelID); | |
1672 ssl_Release1stHandshakeLock(ss); | |
1673 | |
1674 return ret; | |
1675 | |
1676 loser: | |
1677 SECKEY_DestroyPublicKey(channelIDPub); | |
1678 SECKEY_DestroyPrivateKey(channelID); | |
1679 return SECFailure; | |
1680 } | |
1681 | |
1682 /* DO NOT USE. This function was exported in ssl.def with the wrong signature; | |
1683 * this implementation exists to maintain link-time compatibility. | |
1684 */ | |
1685 int | |
1686 SSL_RestartHandshakeAfterServerCert(sslSocket *ss) | |
1687 { | |
1688 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); | |
1689 return -1; | |
1690 } | |
1691 | |
1692 /* See documentation in ssl.h */ | |
1693 SECStatus | |
1694 SSL_AuthCertificateComplete(PRFileDesc *fd, PRErrorCode error) | |
1695 { | |
1696 SECStatus rv; | |
1697 sslSocket *ss = ssl_FindSocket(fd); | |
1698 | |
1699 if (!ss) { | |
1700 SSL_DBG(("%d: SSL[%d]: bad socket in SSL_AuthCertificateComplete", | |
1701 SSL_GETPID(), fd)); | |
1702 return SECFailure; | |
1703 } | |
1704 | |
1705 ssl_Get1stHandshakeLock(ss); | |
1706 | |
1707 if (!ss->ssl3.initialized) { | |
1708 PORT_SetError(SEC_ERROR_INVALID_ARGS); | |
1709 rv = SECFailure; | |
1710 } else if (ss->version < SSL_LIBRARY_VERSION_3_0) { | |
1711 PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2); | |
1712 rv = SECFailure; | |
1713 } else { | |
1714 rv = ssl3_AuthCertificateComplete(ss, error); | |
1715 } | |
1716 | |
1717 ssl_Release1stHandshakeLock(ss); | |
1718 | |
1719 return rv; | |
1720 } | |
1721 | |
1722 /* For more info see ssl.h */ | |
1723 SECStatus | |
1724 SSL_SNISocketConfigHook(PRFileDesc *fd, SSLSNISocketConfig func, | |
1725 void *arg) | |
1726 { | |
1727 sslSocket *ss; | |
1728 | |
1729 ss = ssl_FindSocket(fd); | |
1730 if (!ss) { | |
1731 SSL_DBG(("%d: SSL[%d]: bad socket in SNISocketConfigHook", | |
1732 SSL_GETPID(), fd)); | |
1733 return SECFailure; | |
1734 } | |
1735 | |
1736 ss->sniSocketConfig = func; | |
1737 ss->sniSocketConfigArg = arg; | |
1738 return SECSuccess; | |
1739 } | |
OLD | NEW |