/* Acquires and releases HandshakeLock. */ SECStatus SSL_ResetHandshake(PRFileDesc *s, PRBool asServer) { sslSocket *ss; SECStatus status; PRNetAddr addr; ss = ssl_FindSocket(s); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in ResetHandshake", SSL_GETPID(), s)); return SECFailure; } /* Don't waste my time */ if (!ss->opt.useSecurity) return SECSuccess; SSL_LOCK_READER(ss); SSL_LOCK_WRITER(ss); /* Reset handshake state */ ssl_Get1stHandshakeLock(ss); ss->firstHsDone = PR_FALSE; if ( asServer ) { ss->handshake = ssl2_BeginServerHandshake; ss->handshaking = sslHandshakingAsServer; } else { ss->handshake = ssl2_BeginClientHandshake; ss->handshaking = sslHandshakingAsClient; } ss->nextHandshake = 0; ss->securityHandshake = 0; ssl_GetRecvBufLock(ss); status = ssl_InitGather(&ss->gs); ssl_ReleaseRecvBufLock(ss); ssl_GetSSL3HandshakeLock(ss); /* ** Blow away old security state and get a fresh setup. */ ssl_GetXmitBufLock(ss); ssl_ResetSecurityInfo(&ss->sec, PR_TRUE); status = ssl_CreateSecurityInfo(ss); ssl_ReleaseXmitBufLock(ss); ssl_ReleaseSSL3HandshakeLock(ss); ssl_Release1stHandshakeLock(ss); if (!ss->TCPconnected) ss->TCPconnected = (PR_SUCCESS == ssl_DefGetpeername(ss, &addr)); SSL_UNLOCK_WRITER(ss); SSL_UNLOCK_READER(ss); return status; }
/* Try to make progress on an SSL handshake by attempting to read the ** next handshake from the peer, and sending any responses. ** For non-blocking sockets, returns PR_ERROR_WOULD_BLOCK if it cannot ** read the next handshake from the underlying socket. ** For SSLv2, returns when handshake is complete or fatal error occurs. ** For SSLv3, returns when handshake is complete, or application data has ** arrived that must be taken by application before handshake can continue, ** or a fatal error occurs. ** Application should use handshake completion callback to tell which. */ SECStatus SSL_ForceHandshake(PRFileDesc *fd) { sslSocket *ss; SECStatus rv = SECFailure; ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in ForceHandshake", SSL_GETPID(), fd)); return rv; } /* Don't waste my time */ if (!ss->opt.useSecurity) return SECSuccess; if (!ssl_SocketIsBlocking(ss)) { ssl_GetXmitBufLock(ss); if (ss->pendingBuf.len != 0) { int sent = ssl_SendSavedWriteData(ss); if ((sent < 0) && (PORT_GetError() != PR_WOULD_BLOCK_ERROR)) { ssl_ReleaseXmitBufLock(ss); return SECFailure; } } ssl_ReleaseXmitBufLock(ss); } ssl_Get1stHandshakeLock(ss); if (ss->version >= SSL_LIBRARY_VERSION_3_0) { int gatherResult; ssl_GetRecvBufLock(ss); gatherResult = ssl3_GatherCompleteHandshake(ss, 0); ssl_ReleaseRecvBufLock(ss); if (gatherResult > 0) { rv = SECSuccess; } else if (gatherResult == 0) { PORT_SetError(PR_END_OF_FILE_ERROR); } else if (gatherResult == SECWouldBlock) { PORT_SetError(PR_WOULD_BLOCK_ERROR); } } else if (!ss->firstHsDone) { rv = ssl_Do1stHandshake(ss); } else { /* tried to force handshake on an SSL 2 socket that has ** already completed the handshake. */ rv = SECSuccess; /* just pretend we did it. */ } ssl_Release1stHandshakeLock(ss); return rv; }
SECStatus ssl_CreateSecurityInfo(sslSocket *ss) { SECStatus status; ssl_GetXmitBufLock(ss); status = sslBuffer_Grow(&ss->sec.writeBuf, 4096); ssl_ReleaseXmitBufLock(ss); return status; }
int ssl_SecureRecv(sslSocket *ss, unsigned char *buf, int len, int flags) { int rv = 0; if (ss->shutdownHow & ssl_SHUTDOWN_RCV) { PORT_SetError(PR_SOCKET_SHUTDOWN_ERROR); return PR_FAILURE; } if (flags & ~PR_MSG_PEEK) { PORT_SetError(PR_INVALID_ARGUMENT_ERROR); return PR_FAILURE; } if (!ssl_SocketIsBlocking(ss) && !ss->opt.fdx) { ssl_GetXmitBufLock(ss); if (ss->pendingBuf.len != 0) { rv = ssl_SendSavedWriteData(ss); if ((rv < 0) && (PORT_GetError() != PR_WOULD_BLOCK_ERROR)) { ssl_ReleaseXmitBufLock(ss); return SECFailure; } } ssl_ReleaseXmitBufLock(ss); } rv = 0; if (!PR_CLIST_IS_EMPTY(&ss->ssl3.hs.bufferedEarlyData)) { PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); return tls13_Read0RttData(ss, buf, len); } /* If any of these is non-zero, the initial handshake is not done. */ if (!ss->firstHsDone) { ssl_Get1stHandshakeLock(ss); if (ss->handshake) { rv = ssl_Do1stHandshake(ss); } ssl_Release1stHandshakeLock(ss); } if (rv < 0) { return rv; } if (len == 0) return 0; rv = DoRecv(ss, (unsigned char *)buf, len, flags); SSL_TRC(2, ("%d: SSL[%d]: recving %d bytes securely (errno=%d)", SSL_GETPID(), ss->fd, rv, PORT_GetError())); return rv; }
int ssl_SecureRecv(sslSocket *ss, unsigned char *buf, int len, int flags) { sslSecurityInfo *sec; int rv = 0; sec = &ss->sec; if (ss->shutdownHow & ssl_SHUTDOWN_RCV) { PORT_SetError(PR_SOCKET_SHUTDOWN_ERROR); return PR_FAILURE; } if (flags & ~PR_MSG_PEEK) { PORT_SetError(PR_INVALID_ARGUMENT_ERROR); return PR_FAILURE; } if (!ssl_SocketIsBlocking(ss) && !ss->opt.fdx) { ssl_GetXmitBufLock(ss); if (ss->pendingBuf.len != 0) { rv = ssl_SendSavedWriteData(ss); if ((rv < 0) && (PORT_GetError() != PR_WOULD_BLOCK_ERROR)) { ssl_ReleaseXmitBufLock(ss); return SECFailure; } /* XXX short write? */ } ssl_ReleaseXmitBufLock(ss); } rv = 0; /* If any of these is non-zero, the initial handshake is not done. */ if (!ss->firstHsDone) { ssl_Get1stHandshakeLock(ss); if (ss->handshake || ss->nextHandshake || ss->securityHandshake) { rv = ssl_Do1stHandshake(ss); } ssl_Release1stHandshakeLock(ss); } if (rv < 0) { return rv; } if (len == 0) return 0; rv = DoRecv(ss, (unsigned char*) buf, len, flags); SSL_TRC(2, ("%d: SSL[%d]: recving %d bytes securely (errno=%d)", SSL_GETPID(), ss->fd, rv, PORT_GetError())); return rv; }
SECStatus ssl_CreateSecurityInfo(sslSocket *ss) { SECStatus status; /* initialize sslv2 socket to send data in the clear. */ ssl2_UseClearSendFunc(ss); ss->sec.blockSize = 1; ss->sec.blockShift = 0; ssl_GetXmitBufLock(ss); status = sslBuffer_Grow(&ss->sec.writeBuf, 4096); ssl_ReleaseXmitBufLock(ss); return status; }
SECStatus ssl_CreateSecurityInfo(sslSocket *ss) { SECStatus status; ssl2_UseClearSendFunc(ss); ss->sec.blockSize = 1; ss->sec.blockShift = 0; ssl_GetXmitBufLock(ss); status = sslBuffer_Grow(&ss->sec.writeBuf, 4096); ssl_ReleaseXmitBufLock(ss); return status; }
PRBool SSLInt_SendNewSessionTicket(PRFileDesc *fd) { sslSocket *ss = ssl_FindSocket(fd); if (!ss) { return PR_FALSE; } ssl_GetSSL3HandshakeLock(ss); ssl_GetXmitBufLock(ss); SECStatus rv = tls13_SendNewSessionTicket(ss); if (rv == SECSuccess) { rv = ssl3_FlushHandshake(ss, 0); } ssl_ReleaseXmitBufLock(ss); ssl_ReleaseSSL3HandshakeLock(ss); return rv == SECSuccess; }
/* Caller holds the SSL Socket's write lock. SSL_LOCK_WRITER(ss) */ int ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags) { int rv = 0; PRBool falseStart = PR_FALSE; SSL_TRC(2, ("%d: SSL[%d]: SecureSend: sending %d bytes", SSL_GETPID(), ss->fd, len)); if (ss->shutdownHow & ssl_SHUTDOWN_SEND) { PORT_SetError(PR_SOCKET_SHUTDOWN_ERROR); rv = PR_FAILURE; goto done; } if (flags) { PORT_SetError(PR_INVALID_ARGUMENT_ERROR); rv = PR_FAILURE; goto done; } ssl_GetXmitBufLock(ss); if (ss->pendingBuf.len != 0) { PORT_Assert(ss->pendingBuf.len > 0); rv = ssl_SendSavedWriteData(ss); if (rv >= 0 && ss->pendingBuf.len != 0) { PORT_Assert(ss->pendingBuf.len > 0); PORT_SetError(PR_WOULD_BLOCK_ERROR); rv = SECFailure; } } ssl_ReleaseXmitBufLock(ss); if (rv < 0) { goto done; } if (len > 0) ss->writerThread = PR_GetCurrentThread(); /* If any of these is non-zero, the initial handshake is not done. */ if (!ss->firstHsDone) { ssl_Get1stHandshakeLock(ss); if (ss->opt.enableFalseStart && ss->version >= SSL_LIBRARY_VERSION_3_0) { ssl_GetSSL3HandshakeLock(ss); falseStart = ss->ssl3.hs.canFalseStart; ssl_ReleaseSSL3HandshakeLock(ss); } if (!falseStart && (ss->handshake || ss->nextHandshake || ss->securityHandshake)) { rv = ssl_Do1stHandshake(ss); } ssl_Release1stHandshakeLock(ss); } if (rv < 0) { ss->writerThread = NULL; goto done; } /* Check for zero length writes after we do housekeeping so we make forward * progress. */ if (len == 0) { rv = 0; goto done; } PORT_Assert(buf != NULL); if (!buf) { PORT_SetError(PR_INVALID_ARGUMENT_ERROR); rv = PR_FAILURE; goto done; } if (!ss->firstHsDone) { PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_3_0); #ifdef DEBUG ssl_GetSSL3HandshakeLock(ss); PORT_Assert(ss->ssl3.hs.canFalseStart); ssl_ReleaseSSL3HandshakeLock(ss); #endif SSL_TRC(3, ("%d: SSL[%d]: SecureSend: sending data due to false start", SSL_GETPID(), ss->fd)); } /* Send out the data using one of these functions: * ssl2_SendClear, ssl2_SendStream, ssl2_SendBlock, * ssl3_SendApplicationData */ ssl_GetXmitBufLock(ss); rv = (*ss->sec.send)(ss, buf, len, flags); ssl_ReleaseXmitBufLock(ss); ss->writerThread = NULL; done: if (rv < 0) { SSL_TRC(2, ("%d: SSL[%d]: SecureSend: returning %d count, error %d", SSL_GETPID(), ss->fd, rv, PORT_GetError())); } else { SSL_TRC(2, ("%d: SSL[%d]: SecureSend: returning %d count", SSL_GETPID(), ss->fd, rv)); } return rv; }
int ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags) { int rv = 0; PRBool falseStart = PR_FALSE; SSL_TRC(2, ("%d: SSL[%d]: SecureSend: sending %d bytes", SSL_GETPID(), ss->fd, len)); if (ss->shutdownHow & ssl_SHUTDOWN_SEND) { PORT_SetError(PR_SOCKET_SHUTDOWN_ERROR); rv = PR_FAILURE; goto done; } if (flags) { PORT_SetError(PR_INVALID_ARGUMENT_ERROR); rv = PR_FAILURE; goto done; } ssl_GetXmitBufLock(ss); if (ss->pendingBuf.len != 0) { PORT_Assert(ss->pendingBuf.len > 0); rv = ssl_SendSavedWriteData(ss); if (rv >= 0 && ss->pendingBuf.len != 0) { PORT_Assert(ss->pendingBuf.len > 0); PORT_SetError(PR_WOULD_BLOCK_ERROR); rv = SECFailure; } } ssl_ReleaseXmitBufLock(ss); if (rv < 0) { goto done; } if (len > 0) ss->writerThread = PR_GetCurrentThread(); if (!ss->firstHsDone) { ssl_Get1stHandshakeLock(ss); if (ss->opt.enableFalseStart && ss->version >= SSL_LIBRARY_VERSION_3_0) { ssl_GetSSL3HandshakeLock(ss); falseStart = ss->ssl3.hs.canFalseStart; ssl_ReleaseSSL3HandshakeLock(ss); } if (!falseStart && (ss->handshake || ss->nextHandshake || ss->securityHandshake)) { rv = ssl_Do1stHandshake(ss); } ssl_Release1stHandshakeLock(ss); } if (rv < 0) { ss->writerThread = NULL; goto done; } if (len == 0) { rv = 0; goto done; } PORT_Assert(buf != NULL); if (!buf) { PORT_SetError(PR_INVALID_ARGUMENT_ERROR); rv = PR_FAILURE; goto done; } if (!ss->firstHsDone) { PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_3_0); #ifdef DEBUG ssl_GetSSL3HandshakeLock(ss); PORT_Assert(ss->ssl3.hs.canFalseStart); ssl_ReleaseSSL3HandshakeLock(ss); #endif SSL_TRC(3, ("%d: SSL[%d]: SecureSend: sending data due to false start", SSL_GETPID(), ss->fd)); } ssl_GetXmitBufLock(ss); rv = (*ss->sec.send)(ss, buf, len, flags); ssl_ReleaseXmitBufLock(ss); ss->writerThread = NULL; done: if (rv < 0) { SSL_TRC(2, ("%d: SSL[%d]: SecureSend: returning %d count, error %d", SSL_GETPID(), ss->fd, rv, PORT_GetError())); } else { SSL_TRC(2, ("%d: SSL[%d]: SecureSend: returning %d count", SSL_GETPID(), ss->fd, rv)); } return rv; }
/* Sends out the initial client Hello message on the connection. * Acquires and releases the socket's xmitBufLock. */ SECStatus ssl_BeginClientHandshake(sslSocket *ss) { sslSessionID *sid; SECStatus rv; PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); ss->sec.isServer = PR_FALSE; ssl_ChooseSessionIDProcs(&ss->sec); rv = ssl_CheckConfigSanity(ss); if (rv != SECSuccess) goto loser; /* Get peer name of server */ rv = ssl_GetPeerInfo(ss); if (rv < 0) { #ifdef HPUX11 /* * On some HP-UX B.11.00 systems, getpeername() occasionally * fails with ENOTCONN after a successful completion of * non-blocking connect. I found that if we do a write() * and then retry getpeername(), it will work. */ if (PR_GetError() == PR_NOT_CONNECTED_ERROR) { char dummy; (void)PR_Write(ss->fd->lower, &dummy, 0); rv = ssl_GetPeerInfo(ss); if (rv < 0) { goto loser; } } #else goto loser; #endif } SSL_TRC(3, ("%d: SSL[%d]: sending client-hello", SSL_GETPID(), ss->fd)); /* Try to find server in our session-id cache */ if (ss->opt.noCache) { sid = NULL; } else { sid = ssl_LookupSID(&ss->sec.ci.peer, ss->sec.ci.port, ss->peerID, ss->url); } if (sid) { if (sid->version >= ss->vrange.min && sid->version <= ss->vrange.max) { PORT_Assert(!ss->sec.localCert); ss->sec.localCert = CERT_DupCertificate(sid->localCert); } else { ss->sec.uncache(sid); ssl_FreeSID(sid); sid = NULL; } } if (!sid) { sid = PORT_ZNew(sslSessionID); if (!sid) { goto loser; } sid->references = 1; sid->cached = never_cached; sid->addr = ss->sec.ci.peer; sid->port = ss->sec.ci.port; if (ss->peerID != NULL) { sid->peerID = PORT_Strdup(ss->peerID); } if (ss->url != NULL) { sid->urlSvrName = PORT_Strdup(ss->url); } } ss->sec.ci.sid = sid; PORT_Assert(sid != NULL); ss->gs.state = GS_INIT; ss->handshake = ssl_GatherRecord1stHandshake; /* ssl3_SendClientHello will override this if it succeeds. */ ss->version = SSL_LIBRARY_VERSION_3_0; ssl_GetSSL3HandshakeLock(ss); ssl_GetXmitBufLock(ss); rv = ssl3_SendClientHello(ss, client_hello_initial); ssl_ReleaseXmitBufLock(ss); ssl_ReleaseSSL3HandshakeLock(ss); return rv; loser: return SECFailure; }
/* Caller holds the SSL Socket's write lock. SSL_LOCK_WRITER(ss) */ int ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags) { int rv = 0; SSL_TRC(2, ("%d: SSL[%d]: SecureSend: sending %d bytes", SSL_GETPID(), ss->fd, len)); if (ss->shutdownHow & ssl_SHUTDOWN_SEND) { PORT_SetError(PR_SOCKET_SHUTDOWN_ERROR); rv = PR_FAILURE; goto done; } if (flags) { PORT_SetError(PR_INVALID_ARGUMENT_ERROR); rv = PR_FAILURE; goto done; } ssl_GetXmitBufLock(ss); if (ss->pendingBuf.len != 0) { PORT_Assert(ss->pendingBuf.len > 0); rv = ssl_SendSavedWriteData(ss); if (rv >= 0 && ss->pendingBuf.len != 0) { PORT_Assert(ss->pendingBuf.len > 0); PORT_SetError(PR_WOULD_BLOCK_ERROR); rv = SECFailure; } } ssl_ReleaseXmitBufLock(ss); if (rv < 0) { goto done; } if (len > 0) ss->writerThread = PR_GetCurrentThread(); /* Check to see if we can write even though we're not finished. * * Case 1: False start * Case 2: TLS 1.3 0-RTT */ if (!ss->firstHsDone) { PRBool falseStart = PR_FALSE; ssl_Get1stHandshakeLock(ss); if (ss->opt.enableFalseStart || (ss->opt.enable0RttData && !ss->sec.isServer)) { ssl_GetSSL3HandshakeLock(ss); /* The client can sometimes send before the handshake is fully * complete. In TLS 1.2: false start; in TLS 1.3: 0-RTT. */ falseStart = ss->ssl3.hs.canFalseStart || ss->ssl3.hs.zeroRttState == ssl_0rtt_sent || ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted; ssl_ReleaseSSL3HandshakeLock(ss); } if (!falseStart && ss->handshake) { rv = ssl_Do1stHandshake(ss); } ssl_Release1stHandshakeLock(ss); } if (rv < 0) { ss->writerThread = NULL; goto done; } /* Check for zero length writes after we do housekeeping so we make forward * progress. */ if (len == 0) { rv = 0; goto done; } PORT_Assert(buf != NULL); if (!buf) { PORT_SetError(PR_INVALID_ARGUMENT_ERROR); rv = PR_FAILURE; goto done; } if (!ss->firstHsDone) { #ifdef DEBUG ssl_GetSSL3HandshakeLock(ss); PORT_Assert(!ss->sec.isServer && (ss->ssl3.hs.canFalseStart || ss->ssl3.hs.zeroRttState == ssl_0rtt_sent || ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted)); ssl_ReleaseSSL3HandshakeLock(ss); #endif SSL_TRC(3, ("%d: SSL[%d]: SecureSend: sending data due to false start", SSL_GETPID(), ss->fd)); } ssl_GetXmitBufLock(ss); rv = ssl3_SendApplicationData(ss, buf, len, flags); ssl_ReleaseXmitBufLock(ss); ss->writerThread = NULL; done: if (rv < 0) { SSL_TRC(2, ("%d: SSL[%d]: SecureSend: returning %d count, error %d", SSL_GETPID(), ss->fd, rv, PORT_GetError())); } else { SSL_TRC(2, ("%d: SSL[%d]: SecureSend: returning %d count", SSL_GETPID(), ss->fd, rv)); } return rv; }