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; }
/* * 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; }
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; }
/* 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; }
/* 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; }
int ssl_SecureConnect(sslSocket *ss, const PRNetAddr *sa) { PRFileDesc *osfd = ss->fd->lower; int rv; if ( ss->opt.handshakeAsServer ) { ss->securityHandshake = ssl2_BeginServerHandshake; ss->handshaking = sslHandshakingAsServer; } else { ss->securityHandshake = ssl2_BeginClientHandshake; ss->handshaking = sslHandshakingAsClient; } /* connect to server */ rv = osfd->methods->connect(osfd, sa, ss->cTimeout); if (rv == PR_SUCCESS) { ss->TCPconnected = 1; } else { int err = PR_GetError(); SSL_DBG(("%d: SSL[%d]: connect failed, errno=%d", SSL_GETPID(), ss->fd, err)); if (err == PR_IS_CONNECTED_ERROR) { ss->TCPconnected = 1; } } SSL_TRC(5, ("%d: SSL[%d]: secure connect completed, rv == %d", SSL_GETPID(), ss->fd, rv)); return rv; }
/* 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; }
/* ** 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; }
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; }
/* BEWARE: This function gets called for both client and server SIDs !! * If the unreferenced sid is not in the cache, Free sid and its contents. */ static void ssl_DestroySID(sslSessionID *sid) { int i; SSL_TRC(8, ("SSL: destroy sid: sid=0x%x cached=%d", sid, sid->cached)); PORT_Assert(sid->references == 0); PORT_Assert(sid->cached != in_client_cache); if (sid->version < SSL_LIBRARY_VERSION_3_0) { SECITEM_ZfreeItem(&sid->u.ssl2.masterKey, PR_FALSE); SECITEM_ZfreeItem(&sid->u.ssl2.cipherArg, PR_FALSE); } else { if (sid->u.ssl3.locked.sessionTicket.ticket.data) { SECITEM_FreeItem(&sid->u.ssl3.locked.sessionTicket.ticket, PR_FALSE); } if (sid->u.ssl3.srvName.data) { SECITEM_FreeItem(&sid->u.ssl3.srvName, PR_FALSE); } if (sid->u.ssl3.originalHandshakeHash.data) { SECITEM_FreeItem(&sid->u.ssl3.originalHandshakeHash, PR_FALSE); } if (sid->u.ssl3.signedCertTimestamps.data) { SECITEM_FreeItem(&sid->u.ssl3.signedCertTimestamps, PR_FALSE); } if (sid->u.ssl3.lock) { NSSRWLock_Destroy(sid->u.ssl3.lock); } } if (sid->peerID != NULL) PORT_Free((void *)sid->peerID); /* CONST */ if (sid->urlSvrName != NULL) PORT_Free((void *)sid->urlSvrName); /* CONST */ if ( sid->peerCert ) { CERT_DestroyCertificate(sid->peerCert); } for (i = 0; i < MAX_PEER_CERT_CHAIN_SIZE && sid->peerCertChain[i]; i++) { CERT_DestroyCertificate(sid->peerCertChain[i]); } if (sid->peerCertStatus.items) { SECITEM_FreeArray(&sid->peerCertStatus, PR_FALSE); } if ( sid->localCert ) { CERT_DestroyCertificate(sid->localCert); } PORT_ZFree(sid, sizeof(sslSessionID)); }
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; }
/* Go through hello extensions in |b| and deserialize * them into the list in |ss->ssl3.hs.remoteExtensions|. * The only checking we do in this point is for duplicates. * * IMPORTANT: This list just contains pointers to the incoming * buffer so they can only be used during ClientHello processing. */ SECStatus ssl3_ParseExtensions(sslSocket *ss, PRUint8 **b, PRUint32 *length) { /* Clean out the extensions list. */ ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions); while (*length) { SECStatus rv; PRUint32 extension_type; SECItem extension_data = { siBuffer, NULL, 0 }; TLSExtension *extension; PRCList *cursor; /* Get the extension's type field */ rv = ssl3_ConsumeHandshakeNumber(ss, &extension_type, 2, b, length); if (rv != SECSuccess) { return SECFailure; /* alert already sent */ } /* Check whether an extension has been sent multiple times. */ for (cursor = PR_NEXT_LINK(&ss->ssl3.hs.remoteExtensions); cursor != &ss->ssl3.hs.remoteExtensions; cursor = PR_NEXT_LINK(cursor)) { if (((TLSExtension *)cursor)->type == extension_type) { (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter); PORT_SetError(SSL_ERROR_RX_UNEXPECTED_EXTENSION); return SECFailure; } } /* Get the data for this extension, so we can pass it or skip it. */ rv = ssl3_ConsumeHandshakeVariable(ss, &extension_data, 2, b, length); if (rv != SECSuccess) { return rv; /* alert already sent */ } SSL_TRC(10, ("%d: SSL3[%d]: parsed extension %d len=%u", SSL_GETPID(), ss->fd, extension_type, extension_data.len)); extension = PORT_ZNew(TLSExtension); if (!extension) { return SECFailure; } extension->type = (PRUint16)extension_type; extension->data = extension_data; PR_APPEND_LINK(&extension->link, &ss->ssl3.hs.remoteExtensions); } return SECSuccess; }
/* * struct { * ProtocolVersion versions<2..254>; * } SupportedVersions; */ PRInt32 tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) { PRInt32 extensions_len; PRUint16 version; SECStatus rv; if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) { return 0; } SSL_TRC(3, ("%d: TLS13[%d]: send supported_versions extension", SSL_GETPID(), ss->fd)); /* Extension type, extension len fiels, vector len field, * length of the values. */ extensions_len = 2 + 2 + 1 + 2 * (ss->vrange.max - ss->vrange.min + 1); if (maxBytes < (PRUint32)extensions_len) { PORT_Assert(0); return 0; } if (append) { rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_tls13_supported_versions_xtn, 2); if (rv != SECSuccess) return -1; rv = ssl3_ExtAppendHandshakeNumber(ss, extensions_len - 4, 2); if (rv != SECSuccess) return -1; rv = ssl3_ExtAppendHandshakeNumber(ss, extensions_len - 5, 1); if (rv != SECSuccess) return -1; for (version = ss->vrange.max; version >= ss->vrange.min; --version) { rv = ssl3_ExtAppendHandshakeNumber( ss, tls13_EncodeDraftVersion(version), 2); if (rv != SECSuccess) return -1; } xtnData->advertised[xtnData->numAdvertised++] = ssl_tls13_supported_versions_xtn; } return extensions_len; }
void ssl_CipherSpecReleaseByEpoch(sslSocket *ss, CipherSpecDirection dir, DTLSEpoch epoch) { ssl3CipherSpec *spec; SSL_TRC(10, ("%d: SSL[%d]: releasing %s cipher spec for epoch %d", SSL_GETPID(), ss->fd, (dir == CipherSpecRead) ? "read" : "write", epoch)); spec = ssl_FindCipherSpecByEpoch(ss, dir, epoch); if (spec) { ssl_CipherSpecRelease(spec); } }
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 tls13_HandleShortHeaderXtn( const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SSL_TRC(3, ("%d: TLS13[%d]: handle short_header extension", SSL_GETPID(), ss->fd)); /* The client might have asked for this, but we didn't negotiate TLS 1.3. */ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { return SECSuccess; } /* Presently this is incompatible with 0-RTT. We will fix if * it becomes more than an experiment. */ if (ss->opt.enable0RttData) { return SECSuccess; } if (IS_DTLS(ss)) { PORT_SetError(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION); return SECFailure; } if (data->len) { PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); return SECFailure; } if (!ss->opt.enableShortHeaders) { /* Ignore. */ return SECSuccess; } /* Keep track of negotiated extensions. */ xtnData->negotiated[xtnData->numNegotiated++] = ex_type; if (ss->sec.isServer) { SECStatus rv; rv = ssl3_RegisterExtensionSender(ss, xtnData, ssl_tls13_short_header_xtn, tls13_SendShortHeaderXtn); if (rv != SECSuccess) { return SECFailure; } } return SECSuccess; }
/* Handle an incoming KeyShare extension at the server and copy to * |xtnData->remoteKeyShares| for future use. The key * share is processed in tls13_HandleClientKeyShare(). */ SECStatus tls13_ServerHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECStatus rv; PRUint32 length; PORT_Assert(ss->sec.isServer); PORT_Assert(PR_CLIST_IS_EMPTY(&xtnData->remoteKeyShares)); if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { return SECSuccess; } SSL_TRC(3, ("%d: SSL3[%d]: handle key_share extension", SSL_GETPID(), ss->fd)); /* Redundant length because of TLS encoding (this vector consumes * the entire extension.) */ rv = ssl3_ExtConsumeHandshakeNumber(ss, &length, 2, &data->data, &data->len); if (rv != SECSuccess) goto loser; if (length != data->len) { /* Check for consistency */ PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE); goto loser; } while (data->len) { rv = tls13_HandleKeyShareEntry(ss, xtnData, data); if (rv != SECSuccess) goto loser; } /* Check that the client only offered one share if this is * after HRR. */ if (ss->ssl3.hs.helloRetry) { if (PR_PREV_LINK(&xtnData->remoteKeyShares) != PR_NEXT_LINK(&xtnData->remoteKeyShares)) { PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); goto loser; } } return SECSuccess; loser: tls13_DestroyKeyShares(&xtnData->remoteKeyShares); return SECFailure; }
ssl3CipherSpec * ssl_CreateCipherSpec(sslSocket *ss, CipherSpecDirection direction) { ssl3CipherSpec *spec = PORT_ZNew(ssl3CipherSpec); if (!spec) { return NULL; } spec->refCt = 1; spec->version = ss->version; spec->direction = direction; SSL_TRC(10, ("%d: SSL[%d]: new %s spec %d ct=%d", SSL_GETPID(), ss->fd, SPEC_DIR(spec), spec, spec->refCt)); return spec; }
/* This function is never called on a spec which is on the * cipherSpecs list. */ void ssl_CipherSpecRelease(ssl3CipherSpec *spec) { if (!spec) { return; } PORT_Assert(spec->refCt > 0); --spec->refCt; SSL_TRC(10, ("%d: SSL[-]: decrement refct for %s spec %d. epoch=%d new ct = %d", SSL_GETPID(), SPEC_DIR(spec), spec, spec->epoch, spec->refCt)); if (!spec->refCt) { ssl_FreeCipherSpec(spec); } }
void ssl_FinishHandshake(sslSocket *ss) { PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); SSL_TRC(3, ("%d: SSL[%d]: handshake is completed", SSL_GETPID(), ss->fd)); ss->firstHsDone = PR_TRUE; ss->enoughFirstHsDone = PR_TRUE; ss->gs.writeOffset = 0; ss->gs.readOffset = 0; if (ss->handshakeCallback) { (ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData); } }
SECStatus tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECStatus rv; PRUint32 tmp; const sslNamedGroupDef *group; PORT_Assert(!ss->sec.isServer); PORT_Assert(ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3); SSL_TRC(3, ("%d: SSL3[%d]: handle key_share extension in HRR", SSL_GETPID(), ss->fd)); rv = ssl3_ExtConsumeHandshakeNumber(ss, &tmp, 2, &data->data, &data->len); if (rv != SECSuccess) { return SECFailure; /* error code already set */ } if (data->len) { ssl3_ExtSendAlert(ss, alert_fatal, decode_error); PORT_SetError(SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST); return SECFailure; } group = ssl_LookupNamedGroup((SSLNamedGroup)tmp); /* If the group is not enabled, or we already have a share for the * requested group, abort. */ if (!ssl_NamedGroupEnabled(ss, group) || ssl_HaveEphemeralKeyPair(ss, group)) { ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter); PORT_SetError(SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST); return SECFailure; } /* Now delete all the key shares per [draft-ietf-tls-tls13 S 4.1.2] */ ssl_FreeEphemeralKeyPairs(CONST_CAST(sslSocket, ss)); /* And replace with our new share. */ rv = tls13_CreateKeyShare(CONST_CAST(sslSocket, ss), group); if (rv != SECSuccess) { ssl3_ExtSendAlert(ss, alert_fatal, internal_error); PORT_SetError(SEC_ERROR_KEYGEN_FAIL); return SECFailure; } return SECSuccess; }
static void ssl_FreeCipherSpec(ssl3CipherSpec *spec) { SSL_TRC(10, ("%d: SSL[-]: Freeing %s spec %d. epoch=%d", SSL_GETPID(), SPEC_DIR(spec), spec, spec->epoch)); PR_REMOVE_LINK(&spec->link); /* PORT_Assert( ss->opt.noLocks || ssl_HaveSpecWriteLock(ss)); Don't have ss! */ if (spec->cipherContext) { PK11_DestroyContext(spec->cipherContext, PR_TRUE); } PK11_FreeSymKey(spec->masterSecret); ssl_DestroyKeyMaterial(&spec->keyMaterial); PORT_ZFree(spec, sizeof(*spec)); }
/* * enum { psk_ke(0), psk_dhe_ke(1), (255) } PskKeyExchangeMode; * * struct { * PskKeyExchangeMode ke_modes<1..255>; * } PskKeyExchangeModes; */ PRInt32 tls13_ClientSendPskKeyExchangeModesXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes) { static const PRUint8 ke_modes[] = { tls13_psk_dh_ke }; static const unsigned long ke_modes_len = sizeof(ke_modes); PRInt32 extension_len; if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3 || ss->opt.noCache) { return 0; } extension_len = 2 + 2 + /* Type + length */ 1 + ke_modes_len; /* key exchange modes vector */ SSL_TRC(3, ("%d: TLS13[%d]: send psk key exchange modes extension", SSL_GETPID(), ss->fd)); if (maxBytes < (PRUint32)extension_len) { PORT_Assert(0); return 0; } if (append) { SECStatus rv = ssl3_ExtAppendHandshakeNumber( ss, ssl_tls13_psk_key_exchange_modes_xtn, 2); if (rv != SECSuccess) return -1; rv = ssl3_ExtAppendHandshakeNumber(ss, extension_len - 4, 2); if (rv != SECSuccess) return -1; rv = ssl3_ExtAppendHandshakeVariable( ss, ke_modes, ke_modes_len, 1); if (rv != SECSuccess) return -1; } return extension_len; }
void ssl_FinishHandshake(sslSocket *ss) { PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) ); PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); SSL_TRC(3, ("%d: SSL[%d]: handshake is completed", SSL_GETPID(), ss->fd)); ss->firstHsDone = PR_TRUE; ss->enoughFirstHsDone = PR_TRUE; ss->gs.writeOffset = 0; ss->gs.readOffset = 0; if (ss->handshakeCallback) { PORT_Assert(ss->version < SSL_LIBRARY_VERSION_3_0 || (ss->ssl3.hs.preliminaryInfo & ssl_preinfo_all) == ssl_preinfo_all); (ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData); } }
/* ** Grow a buffer to hold newLen bytes of data. ** Called for both recv buffers and xmit buffers. ** Caller must hold xmitBufLock or recvBufLock, as appropriate. */ SECStatus sslBuffer_Grow(sslBuffer *b, unsigned int newLen) { newLen = PR_MAX(newLen, MAX_FRAGMENT_LENGTH + 2048); if (newLen > b->space) { unsigned char *newBuf; if (b->buf) { newBuf = (unsigned char *) PORT_Realloc(b->buf, newLen); } else { newBuf = (unsigned char *) PORT_Alloc(newLen); } if (!newBuf) { return SECFailure; } SSL_TRC(10, ("%d: SSL: grow buffer from %d to %d", SSL_GETPID(), b->space, newLen)); b->buf = newBuf; b->space = newLen; } return SECSuccess; }
SECStatus tls13_ServerHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SSL_TRC(3, ("%d: TLS13[%d]: handle early_data extension", SSL_GETPID(), ss->fd)); /* If we are doing < TLS 1.3, then ignore this. */ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { return SECSuccess; } if (data->len) { PORT_SetError(SSL_ERROR_MALFORMED_EARLY_DATA); return SECFailure; } xtnData->negotiated[xtnData->numNegotiated++] = ex_type; return SECSuccess; }
/* * If sid "zap" is in the cache, * removes sid from cache, and decrements reference count. * Caller must hold cache lock. */ static void UncacheSID(sslSessionID *zap) { sslSessionID **sidp = &cache; sslSessionID *sid; if (zap->cached != in_client_cache) { return; } SSL_TRC(8,("SSL: Uncache: zap=0x%x cached=%d addr=0x%08x%08x%08x%08x port=0x%04x " "time=%x cipher=%d", zap, zap->cached, zap->addr.pr_s6_addr32[0], zap->addr.pr_s6_addr32[1], zap->addr.pr_s6_addr32[2], zap->addr.pr_s6_addr32[3], zap->port, zap->creationTime, zap->u.ssl2.cipherType)); if (zap->version < SSL_LIBRARY_VERSION_3_0) { PRINT_BUF(8, (0, "sessionID:", zap->u.ssl2.sessionID, sizeof(zap->u.ssl2.sessionID))); PRINT_BUF(8, (0, "masterKey:", zap->u.ssl2.masterKey.data, zap->u.ssl2.masterKey.len)); PRINT_BUF(8, (0, "cipherArg:", zap->u.ssl2.cipherArg.data, zap->u.ssl2.cipherArg.len)); } /* See if it's in the cache, if so nuke it */ while ((sid = *sidp) != 0) { if (sid == zap) { /* ** Bingo. Reduce reference count by one so that when ** everyone is done with the sid we can free it up. */ *sidp = zap->next; zap->cached = invalid_cache; ssl_FreeLockedSID(zap); return; } sidp = &sid->next; } }
/* ** Send saved write data. This will flush out data sent prior to a ** complete security handshake. Hopefully there won't be too much of it. ** Returns count of the bytes sent, NOT a SECStatus. ** Caller must hold xmitBufLock */ int ssl_SendSavedWriteData(sslSocket *ss) { int rv = 0; PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) ); if (ss->pendingBuf.len != 0) { SSL_TRC(5, ("%d: SSL[%d]: sending %d bytes of saved data", SSL_GETPID(), ss->fd, ss->pendingBuf.len)); rv = ssl_DefSend(ss, ss->pendingBuf.buf, ss->pendingBuf.len, 0); if (rv < 0) { return rv; } ss->pendingBuf.len -= rv; if (ss->pendingBuf.len > 0 && rv > 0) { /* UGH !! This shifts the whole buffer down by copying it */ PORT_Memmove(ss->pendingBuf.buf, ss->pendingBuf.buf + rv, ss->pendingBuf.len); } } return rv; }
/* BEWARE: This function gets called for both client and server SIDs !! * If the unreferenced sid is not in the cache, Free sid and its contents. */ static void ssl_DestroySID(sslSessionID *sid) { int i; SSL_TRC(8, ("SSL: destroy sid: sid=0x%x cached=%d", sid, sid->cached)); PORT_Assert((sid->references == 0)); if (sid->cached == in_client_cache) return; /* it will get taken care of next time cache is traversed. */ if (sid->version < SSL_LIBRARY_VERSION_3_0) { SECITEM_ZfreeItem(&sid->u.ssl2.masterKey, PR_FALSE); SECITEM_ZfreeItem(&sid->u.ssl2.cipherArg, PR_FALSE); } if (sid->peerID != NULL) PORT_Free((void *)sid->peerID); /* CONST */ if (sid->urlSvrName != NULL) PORT_Free((void *)sid->urlSvrName); /* CONST */ if ( sid->peerCert ) { CERT_DestroyCertificate(sid->peerCert); } for (i = 0; i < MAX_PEER_CERT_CHAIN_SIZE && sid->peerCertChain[i]; i++) { CERT_DestroyCertificate(sid->peerCertChain[i]); } if ( sid->localCert ) { CERT_DestroyCertificate(sid->localCert); } if (sid->u.ssl3.sessionTicket.ticket.data) { SECITEM_FreeItem(&sid->u.ssl3.sessionTicket.ticket, PR_FALSE); } if (sid->u.ssl3.srvName.data) { SECITEM_FreeItem(&sid->u.ssl3.srvName, PR_FALSE); } PORT_ZFree(sid, sizeof(sslSessionID)); }