/* * struct { * opaque cookie<1..2^16-1>; * } Cookie; */ SECStatus tls13_ClientHandleHrrCookie(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECStatus rv; SSL_TRC(3, ("%d: TLS13[%d]: handle cookie extension", SSL_GETPID(), ss->fd)); PORT_Assert(ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3); /* IMPORTANT: this is only valid while the HelloRetryRequest is still valid. */ rv = ssl3_ExtConsumeHandshakeVariable( ss, &CONST_CAST(sslSocket, ss)->ssl3.hs.cookie, 2, &data->data, &data->len); if (rv != SECSuccess) { PORT_SetError(SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST); return SECFailure; } if (!ss->ssl3.hs.cookie.len || data->len) { ssl3_ExtSendAlert(ss, alert_fatal, decode_error); PORT_SetError(SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST); return SECFailure; } return SECSuccess; }
/* This is only registered if we are sending it. */ PRInt32 tls13_ServerSendEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) { SSL_TRC(3, ("%d: TLS13[%d]: send early_data extension", SSL_GETPID(), ss->fd)); PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted); if (maxBytes < 4) { PORT_Assert(0); return 0; } if (append) { SECStatus rv; rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_early_data_xtn, 2); if (rv != SECSuccess) return -1; rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); if (rv != SECSuccess) return -1; } return 4; }
SECStatus tls13_ClientHandleTicketEarlyDataInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { PRUint32 utmp; SECStatus rv; SSL_TRC(3, ("%d: TLS13[%d]: handle early_data_info extension", SSL_GETPID(), ss->fd)); /* If we are doing < TLS 1.3, then ignore this. */ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { PORT_SetError(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION); return SECFailure; } rv = ssl3_ExtConsumeHandshake(ss, &utmp, sizeof(utmp), &data->data, &data->len); if (rv != SECSuccess) { PORT_SetError(SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET); return SECFailure; } if (data->len) { PORT_SetError(SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET); return SECFailure; } xtnData->max_early_data_size = PR_ntohl(utmp); return SECSuccess; }
SECStatus tls13_ServerHandlePskKeyExchangeModesXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECStatus rv; /* If we are doing < TLS 1.3, then ignore this. */ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { return SECSuccess; } SSL_TRC(3, ("%d: TLS13[%d]: handle PSK key exchange modes extension", SSL_GETPID(), ss->fd)); /* IMPORTANT: We aren't copying these values, just setting pointers. * They will only be valid as long as the ClientHello is in memory. */ rv = ssl3_ExtConsumeHandshakeVariable(ss, &xtnData->psk_ke_modes, 1, &data->data, &data->len); if (rv != SECSuccess) return rv; if (!xtnData->psk_ke_modes.len || data->len) { PORT_SetError(SSL_ERROR_MALFORMED_PSK_KEY_EXCHANGE_MODES); return SECFailure; } /* Keep track of negotiated extensions. */ xtnData->negotiated[xtnData->numNegotiated++] = ex_type; return SECSuccess; }
/* Handle an incoming KeyShare extension at the client and copy to * |xtnData->remoteKeyShares| for future use. The key * share is processed in tls13_HandleServerKeyShare(). */ SECStatus tls13_ClientHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECStatus rv; PORT_Assert(PR_CLIST_IS_EMPTY(&xtnData->remoteKeyShares)); PORT_Assert(!ss->sec.isServer); if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { /* This can't happen because the extension processing * code filters out TLS 1.3 extensions when not in * TLS 1.3 mode. */ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } SSL_TRC(3, ("%d: SSL3[%d]: handle key_share extension", SSL_GETPID(), ss->fd)); rv = tls13_HandleKeyShareEntry(ss, xtnData, data); if (rv != SECSuccess) { PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE); return SECFailure; } if (data->len) { PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE); return SECFailure; } return SECSuccess; }
/* For SSLv2, does nothing but return an error. ** For SSLv3, flushes SID cache entry (if requested), ** and then starts new client hello or hello request. ** Acquires and releases HandshakeLock. */ SECStatus SSL_ReHandshake(PRFileDesc *fd, PRBool flushCache) { sslSocket *ss; SECStatus rv; ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in RedoHandshake", SSL_GETPID(), fd)); return SECFailure; } if (!ss->opt.useSecurity) return SECSuccess; ssl_Get1stHandshakeLock(ss); /* SSL v2 protocol does not support subsequent handshakes. */ if (ss->version < SSL_LIBRARY_VERSION_3_0) { PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2); rv = SECFailure; } else { ssl_GetSSL3HandshakeLock(ss); rv = ssl3_RedoHandshake(ss, flushCache); /* force full handshake. */ ssl_ReleaseSSL3HandshakeLock(ss); } ssl_Release1stHandshakeLock(ss); return rv; }
SECStatus SSL_ExportEarlyKeyingMaterial(PRFileDesc *fd, const char *label, unsigned int labelLen, const unsigned char *context, unsigned int contextLen, unsigned char *out, unsigned int outLen) { sslSocket *ss; ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in SSL_ExportEarlyKeyingMaterial", SSL_GETPID(), fd)); return SECFailure; } if (!label || !labelLen || !out || !outLen || (!context && contextLen)) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } return tls13_Exporter(ss, ss->ssl3.hs.earlyExporterSecret, label, labelLen, context, contextLen, out, outLen); }
SECStatus SSL_RecommendedCanFalseStart(PRFileDesc *fd, PRBool *canFalseStart) { sslSocket *ss; *canFalseStart = PR_FALSE; ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in SSL_RecommendedCanFalseStart", SSL_GETPID(), fd)); return SECFailure; } if (!ss->ssl3.initialized) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* Require a forward-secret key exchange. */ *canFalseStart = ss->ssl3.hs.kea_def->kea == kea_dhe_dss || ss->ssl3.hs.kea_def->kea == kea_dhe_rsa || ss->ssl3.hs.kea_def->kea == kea_ecdhe_ecdsa || ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa; return SECSuccess; }
void ssl_CipherSpecAddRef(ssl3CipherSpec *spec) { ++spec->refCt; SSL_TRC(10, ("%d: SSL[-]: Increment ref ct for %s spec %d. new ct = %d", SSL_GETPID(), SPEC_DIR(spec), spec, spec->refCt)); }
SECStatus SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len) { sslSocket * ss; SSLChannelInfo inf; sslSessionID * sid; if (!info || len < sizeof inf.length) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetChannelInfo", SSL_GETPID(), fd)); return SECFailure; } memset(&inf, 0, sizeof inf); inf.length = PR_MIN(sizeof inf, len); if (ss->opt.useSecurity && ss->enoughFirstHsDone) { sid = ss->sec.ci.sid; inf.protocolVersion = ss->version; inf.authKeyBits = ss->sec.authKeyBits; inf.keaKeyBits = ss->sec.keaKeyBits; if (ss->version < SSL_LIBRARY_VERSION_3_0) { inf.cipherSuite = ss->sec.cipherType | 0xff00; inf.compressionMethod = ssl_compression_null; inf.compressionMethodName = "N/A"; } else if (ss->ssl3.initialized) { ssl_GetSpecReadLock(ss); inf.cipherSuite = ss->ssl3.hs.cipher_suite; inf.compressionMethod = ss->ssl3.cwSpec->compression_method; ssl_ReleaseSpecReadLock(ss); inf.compressionMethodName = ssl_GetCompressionMethodName(inf.compressionMethod); } if (sid) { inf.creationTime = sid->creationTime; inf.lastAccessTime = sid->lastAccessTime; inf.expirationTime = sid->expirationTime; if (ss->version < SSL_LIBRARY_VERSION_3_0) { inf.sessionIDLength = SSL2_SESSIONID_BYTES; memcpy(inf.sessionID, sid->u.ssl2.sessionID, SSL2_SESSIONID_BYTES); } else { unsigned int sidLen = sid->u.ssl3.sessionIDLength; sidLen = PR_MIN(sidLen, sizeof inf.sessionID); inf.sessionIDLength = sidLen; memcpy(inf.sessionID, sid->u.ssl3.sessionID, sidLen); } } } memcpy(info, &inf, inf.length); return SECSuccess; }
SECStatus SSL_GetPreliminaryChannelInfo(PRFileDesc *fd, SSLPreliminaryChannelInfo *info, PRUintn len) { sslSocket *ss; SSLPreliminaryChannelInfo inf; /* Check if we can properly return the length of data written and that * we're not asked to return more information than we know how to provide. */ if (!info || len < sizeof inf.length || len > sizeof inf) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetPreliminaryChannelInfo", SSL_GETPID(), fd)); return SECFailure; } memset(&inf, 0, sizeof(inf)); inf.length = PR_MIN(sizeof(inf), len); inf.valuesSet = ss->ssl3.hs.preliminaryInfo; inf.protocolVersion = ss->version; inf.cipherSuite = ss->ssl3.hs.cipher_suite; memcpy(info, &inf, inf.length); return SECSuccess; }
/* * Allow the application to pass the url or hostname into the SSL library * so that we can do some checking on it. It will be used for the value in * SNI extension of client hello message. */ SECStatus SSL_SetURL(PRFileDesc *fd, const char *url) { sslSocket * ss = ssl_FindSocket(fd); SECStatus rv = SECSuccess; if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in SSLSetURL", SSL_GETPID(), fd)); return SECFailure; } ssl_Get1stHandshakeLock(ss); ssl_GetSSL3HandshakeLock(ss); if ( ss->url ) { PORT_Free((void *)ss->url); /* CONST */ } ss->url = (const char *)PORT_Strdup(url); if ( ss->url == NULL ) { rv = SECFailure; } ssl_ReleaseSSL3HandshakeLock(ss); ssl_Release1stHandshakeLock(ss); return rv; }
SECStatus SSL_RecommendedCanFalseStart(PRFileDesc *fd, PRBool *canFalseStart) { sslSocket *ss; *canFalseStart = PR_FALSE; ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in SSL_RecommendedCanFalseStart", SSL_GETPID(), fd)); return SECFailure; } if (!ss->ssl3.initialized) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } if (ss->version < SSL_LIBRARY_VERSION_3_0) { PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2); return SECFailure; } *canFalseStart = ss->ssl3.hs.kea_def->kea == kea_dhe_dss || ss->ssl3.hs.kea_def->kea == kea_dhe_rsa || ss->ssl3.hs.kea_def->kea == kea_ecdhe_ecdsa || ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa; return SECSuccess; }
/* NEED LOCKS IN HERE. */ SECStatus SSL_PeerCertificateChain(PRFileDesc *fd, CERTCertificate **certs, unsigned int *numCerts, unsigned int maxNumCerts) { sslSocket *ss; ssl3CertNode* cur; ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificateChain", SSL_GETPID(), fd)); return SECFailure; } if (!ss->opt.useSecurity) return SECFailure; if (ss->sec.peerCert == NULL) { *numCerts = 0; return SECSuccess; } *numCerts = 1; /* for the leaf certificate */ if (maxNumCerts > 0) certs[0] = CERT_DupCertificate(ss->sec.peerCert); for (cur = ss->ssl3.peerCertChain; cur; cur = cur->next) { if (*numCerts < maxNumCerts) certs[*numCerts] = CERT_DupCertificate(cur->cert); (*numCerts)++; } return SECSuccess; }
SECStatus SSL_ReHandshake(PRFileDesc *fd, PRBool flushCache) { sslSocket *ss; SECStatus rv; ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in RedoHandshake", SSL_GETPID(), fd)); return SECFailure; } if (!ss->opt.useSecurity) return SECSuccess; ssl_Get1stHandshakeLock(ss); if (ss->version < SSL_LIBRARY_VERSION_3_0) { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; } else { ssl_GetSSL3HandshakeLock(ss); rv = ssl3_RedoHandshake(ss, flushCache); ssl_ReleaseSSL3HandshakeLock(ss); } ssl_Release1stHandshakeLock(ss); return rv; }
SECStatus SSL_SetCanFalseStartCallback(PRFileDesc *fd, SSLCanFalseStartCallback cb, void *arg) { sslSocket *ss; ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetCanFalseStartCallback", SSL_GETPID(), fd)); return SECFailure; } if (!ss->opt.useSecurity) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } ssl_Get1stHandshakeLock(ss); ssl_GetSSL3HandshakeLock(ss); ss->canFalseStartCallback = cb; ss->canFalseStartCallbackData = arg; ssl_ReleaseSSL3HandshakeLock(ss); ssl_Release1stHandshakeLock(ss); return SECSuccess; }
SECStatus SSL_RestartHandshakeAfterChannelIDReq(PRFileDesc * fd, SECKEYPublicKey * channelIDPub, SECKEYPrivateKey *channelID) { sslSocket * ss = ssl_FindSocket(fd); SECStatus ret; if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in" " SSL_RestartHandshakeAfterChannelIDReq", SSL_GETPID(), fd)); goto loser; } ssl_Get1stHandshakeLock(ss); if (ss->version < SSL_LIBRARY_VERSION_3_0) { PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2); ssl_Release1stHandshakeLock(ss); goto loser; } ret = ssl3_RestartHandshakeAfterChannelIDReq(ss, channelIDPub, channelID); ssl_Release1stHandshakeLock(ss); return ret; loser: SECKEY_DestroyPublicKey(channelIDPub); SECKEY_DestroyPrivateKey(channelID); return SECFailure; }
SECStatus SSL_AuthCertificateComplete(PRFileDesc *fd, PRErrorCode error) { SECStatus rv; sslSocket *ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in SSL_AuthCertificateComplete", SSL_GETPID(), fd)); return SECFailure; } ssl_Get1stHandshakeLock(ss); if (!ss->ssl3.initialized) { PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; } else if (ss->version < SSL_LIBRARY_VERSION_3_0) { PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2); rv = SECFailure; } else { rv = ssl3_AuthCertificateComplete(ss, error); } ssl_Release1stHandshakeLock(ss); return rv; }
/* For SSLv2, does nothing but return an error. ** For SSLv3, flushes SID cache entry (if requested), ** and then starts new client hello or hello request. ** Acquires and releases HandshakeLock. */ SECStatus SSL_ReHandshake(PRFileDesc *fd, PRBool flushCache) { sslSocket *ss; SECStatus rv; ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in RedoHandshake", SSL_GETPID(), fd)); return SECFailure; } if (!ss->opt.useSecurity) return SECSuccess; ssl_Get1stHandshakeLock(ss); ssl_GetSSL3HandshakeLock(ss); rv = ssl3_RedoHandshake(ss, flushCache); /* force full handshake. */ ssl_ReleaseSSL3HandshakeLock(ss); ssl_Release1stHandshakeLock(ss); return rv; }
/* * Allow the application to pass the set of trust anchors */ SECStatus SSL_SetTrustAnchors(PRFileDesc *fd, CERTCertList *certList) { sslSocket * ss = ssl_FindSocket(fd); CERTDistNames *names = NULL; if (!certList) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetTrustAnchors", SSL_GETPID(), fd)); return SECFailure; } names = CERT_DistNamesFromCertList(certList); if (names == NULL) { return SECFailure; } ssl_Get1stHandshakeLock(ss); ssl_GetSSL3HandshakeLock(ss); if (ss->ssl3.ca_list) { CERT_FreeDistNames(ss->ssl3.ca_list); } ss->ssl3.ca_list = names; ssl_ReleaseSSL3HandshakeLock(ss); ssl_Release1stHandshakeLock(ss); return SECSuccess; }
SECStatus SSL_GetPreliminaryChannelInfo(PRFileDesc *fd, SSLPreliminaryChannelInfo *info, PRUintn len) { sslSocket *ss; SSLPreliminaryChannelInfo inf; if (!info || len < sizeof inf.length) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetPreliminaryChannelInfo", SSL_GETPID(), fd)); return SECFailure; } if (ss->version < SSL_LIBRARY_VERSION_3_0) { PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_VERSION); return SECFailure; } memset(&inf, 0, sizeof(inf)); inf.length = PR_MIN(sizeof(inf), len); inf.valuesSet = ss->ssl3.hs.preliminaryInfo; inf.protocolVersion = ss->version; inf.cipherSuite = ss->ssl3.hs.cipher_suite; memcpy(info, &inf, inf.length); return SECSuccess; }
/* 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; }
/* Returns a SECStatus: SECSuccess or SECFailure, NOT SECWouldBlock. * * Currently, the list of functions called through ss->handshake is: * * In sslsocks.c: * SocksGatherRecord * SocksHandleReply * SocksStartGather * * In sslcon.c: * ssl_GatherRecord1stHandshake * ssl2_HandleClientSessionKeyMessage * ssl2_HandleMessage * ssl2_HandleVerifyMessage * ssl2_BeginClientHandshake * ssl2_BeginServerHandshake * ssl2_HandleClientHelloMessage * ssl2_HandleServerHelloMessage * * The ss->handshake function returns SECWouldBlock under these conditions: * 1. ssl_GatherRecord1stHandshake called ssl2_GatherData which read in * the beginning of an SSL v3 hello message and returned SECWouldBlock * to switch to SSL v3 handshake processing. * * 2. ssl2_HandleClientHelloMessage discovered version 3.0 in the incoming * v2 client hello msg, and called ssl3_HandleV2ClientHello which * returned SECWouldBlock. * * 3. SECWouldBlock was returned by one of the callback functions, via * one of these paths: * - ssl2_HandleMessage() -> ssl2_HandleRequestCertificate() -> * ss->getClientAuthData() * * - ssl2_HandleServerHelloMessage() -> ss->handleBadCert() * * - ssl_GatherRecord1stHandshake() -> ssl3_GatherCompleteHandshake() -> * ssl3_HandleRecord() -> ssl3_HandleHandshake() -> * ssl3_HandleHandshakeMessage() -> ssl3_HandleCertificate() -> * ss->handleBadCert() * * - ssl_GatherRecord1stHandshake() -> ssl3_GatherCompleteHandshake() -> * ssl3_HandleRecord() -> ssl3_HandleHandshake() -> * ssl3_HandleHandshakeMessage() -> ssl3_HandleCertificateRequest() -> * ss->getClientAuthData() * * Called from: SSL_ForceHandshake (below), * ssl_SecureRecv (below) and * ssl_SecureSend (below) * from: WaitForResponse in sslsocks.c * ssl_SocksRecv in sslsocks.c * ssl_SocksSend in sslsocks.c * * Caller must hold the (write) handshakeLock. */ int ssl_Do1stHandshake(sslSocket *ss) { int rv = SECSuccess; int loopCount = 0; do { PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); PORT_Assert(ss->opt.noLocks || !ssl_HaveRecvBufLock(ss)); PORT_Assert(ss->opt.noLocks || !ssl_HaveXmitBufLock(ss)); PORT_Assert(ss->opt.noLocks || !ssl_HaveSSL3HandshakeLock(ss)); if (ss->handshake == 0) { /* Previous handshake finished. Switch to next one */ ss->handshake = ss->nextHandshake; ss->nextHandshake = 0; } if (ss->handshake == 0) { /* Previous handshake finished. Switch to security handshake */ ss->handshake = ss->securityHandshake; ss->securityHandshake = 0; } if (ss->handshake == 0) { ssl_GetRecvBufLock(ss); ss->gs.recordLen = 0; ssl_ReleaseRecvBufLock(ss); SSL_TRC(3, ("%d: SSL[%d]: handshake is completed", SSL_GETPID(), ss->fd)); /* call handshake callback for ssl v2 */ /* for v3 this is done in ssl3_HandleFinished() */ if ((ss->handshakeCallback != NULL) && /* has callback */ (!ss->firstHsDone) && /* only first time */ (ss->version < SSL_LIBRARY_VERSION_3_0)) { /* not ssl3 */ ss->firstHsDone = PR_TRUE; (ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData); } ss->firstHsDone = PR_TRUE; ss->gs.writeOffset = 0; ss->gs.readOffset = 0; break; } rv = (*ss->handshake)(ss); ++loopCount; /* This code must continue to loop on SECWouldBlock, * or any positive value. See XXX_1 comments. */ } while (rv != SECFailure); /* was (rv >= 0); XXX_1 */ PORT_Assert(ss->opt.noLocks || !ssl_HaveRecvBufLock(ss)); PORT_Assert(ss->opt.noLocks || !ssl_HaveXmitBufLock(ss)); PORT_Assert(ss->opt.noLocks || !ssl_HaveSSL3HandshakeLock(ss)); if (rv == SECWouldBlock) { PORT_SetError(PR_WOULD_BLOCK_ERROR); rv = SECFailure; } return rv; }
PRInt32 tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) { PRUint32 extension_length; if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) { return 0; } /* Optimistically try to send an ECDHE key using the * preexisting key (in future will be keys) */ SSL_TRC(3, ("%d: TLS13[%d]: send client key share xtn", SSL_GETPID(), ss->fd)); extension_length = tls13_SizeOfClientKeyShareExtension(ss); if (maxBytes < extension_length) { PORT_Assert(0); return 0; } if (append) { SECStatus rv; PRCList *cursor; rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_key_share_xtn, 2); if (rv != SECSuccess) goto loser; /* The extension length */ rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 4, 2); if (rv != SECSuccess) goto loser; /* The length of KeyShares */ rv = ssl3_ExtAppendHandshakeNumber(ss, extension_length - 6, 2); if (rv != SECSuccess) goto loser; for (cursor = PR_NEXT_LINK(&ss->ephemeralKeyPairs); cursor != &ss->ephemeralKeyPairs; cursor = PR_NEXT_LINK(cursor)) { sslEphemeralKeyPair *keyPair = (sslEphemeralKeyPair *)cursor; rv = tls13_EncodeKeyShareEntry(ss, keyPair); if (rv != SECSuccess) goto loser; } xtnData->advertised[xtnData->numAdvertised++] = ssl_tls13_key_share_xtn; } return extension_length; loser: return -1; }
/* 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; }
/* Public deprecated function */ SECStatus SSL_SetSignedCertTimestamps(PRFileDesc *fd, const SECItem *scts, SSLKEAType certType) { sslSocket *ss; SECStatus rv; ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetSignedCertTimestamps", SSL_GETPID(), fd)); return SECFailure; } switch (certType) { case ssl_kea_rsa: rv = ssl_SetSignedTimestampsInSlot(ss, ssl_auth_rsa_decrypt, scts); if (rv != SECSuccess) { return SECFailure; } return ssl_SetSignedTimestampsInSlot(ss, ssl_auth_rsa_sign, scts); case ssl_kea_dh: return ssl_SetSignedTimestampsInSlot(ss, ssl_auth_dsa, scts); case ssl_kea_ecdh: rv = ssl_SetSignedTimestampsInSlot(ss, ssl_auth_ecdsa, scts); if (rv != SECSuccess) { return SECFailure; } rv = ssl_SetSignedTimestampsInSlot(ss, ssl_auth_ecdh_rsa, scts); if (rv != SECSuccess) { return SECFailure; } return ssl_SetSignedTimestampsInSlot(ss, ssl_auth_ecdh_ecdsa, scts); default: SSL_DBG(("%d: SSL[%d]: invalid cert type in SSL_SetSignedCertTimestamps", SSL_GETPID(), fd)); PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } }
void ssl_PrintBuf(sslSocket *ss, const char *msg, const void *vp, int len) { const unsigned char *cp = (const unsigned char *)vp; char buf[80]; char *bp; char *ap; if (ss) { SSL_TRACE(("%d: SSL[%d]: %s [Len: %d]", SSL_GETPID(), ss->fd, msg, len)); } else { SSL_TRACE(("%d: SSL: %s [Len: %d]", SSL_GETPID(), msg, len)); } if (!cp) { SSL_TRACE((" <NULL>")); return; } memset(buf, ' ', sizeof buf); bp = buf; ap = buf + 50; while (--len >= 0) { unsigned char ch = *cp++; *bp++ = hex[(ch >> 4) & 0xf]; *bp++ = hex[ch & 0xf]; *bp++ = ' '; *ap++ = printable[ch]; if (ap - buf >= 66) { *ap = 0; SSL_TRACE((" %s", buf)); memset(buf, ' ', sizeof buf); bp = buf; ap = buf + 50; } } if (bp > buf) { *ap = 0; SSL_TRACE((" %s", buf)); } }
/* ** Save away write data that is trying to be written before the security ** handshake has been completed. When the handshake is completed, we will ** flush this data out. ** Caller must hold xmitBufLock */ SECStatus ssl_SaveWriteData(sslSocket *ss, const void *data, unsigned int len) { SECStatus rv; PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) ); rv = sslBuffer_Append(&ss->pendingBuf, data, len); SSL_TRC(5, ("%d: SSL[%d]: saving %u bytes of data (%u total saved so far)", SSL_GETPID(), ss->fd, len, ss->pendingBuf.len)); return rv; }
/* This function is called at the beginning of a handshake to ensure that at * least one SSL/TLS version is enabled. */ static SECStatus ssl_CheckConfigSanity(sslSocket *ss) { if (SSL_ALL_VERSIONS_DISABLED(&ss->vrange)) { SSL_DBG(("%d: SSL[%d]: Can't handshake! all versions disabled.", SSL_GETPID(), ss->fd)); PORT_SetError(SSL_ERROR_SSL_DISABLED); return SECFailure; } return SECSuccess; }
PRInt32 tls13_SendShortHeaderXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) { PRUint32 extension_len = 2 + 2; /* Type + length (0). */ if (!ss->opt.enableShortHeaders) { return 0; } /* Presently this is incompatible with 0-RTT. We will fix if * it becomes more than an experiment. */ if (ss->opt.enable0RttData) { return 0; } if (IS_DTLS(ss)) { return 0; } /* Don't send this if TLS 1.3 isn't at least possible. */ if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) { /* This should only happen on the client. */ PORT_Assert(!ss->sec.isServer); return 0; } SSL_TRC(3, ("%d: TLS13[%d]: send short_header extension", SSL_GETPID(), ss->fd)); if (maxBytes < extension_len) { PORT_Assert(0); return 0; } if (append) { SECStatus rv; rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_short_header_xtn, 2); if (rv != SECSuccess) return -1; rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); if (rv != SECSuccess) return -1; xtnData->advertised[xtnData->numAdvertised++] = ssl_tls13_short_header_xtn; } return extension_len; }