/* Caller handles all locking */ int ssl_SecureShutdown(sslSocket *ss, int nsprHow) { PRFileDesc *osfd = ss->fd->lower; int rv; PRIntn sslHow = nsprHow + 1; if ((unsigned)nsprHow > PR_SHUTDOWN_BOTH) { PORT_SetError(PR_INVALID_ARGUMENT_ERROR); return PR_FAILURE; } if ((sslHow & ssl_SHUTDOWN_SEND) != 0 && ss->version >= SSL_LIBRARY_VERSION_3_0 && !(ss->shutdownHow & ssl_SHUTDOWN_SEND) && ss->firstHsDone && !ss->recvdCloseNotify && ss->ssl3.initialized) { (void) SSL3_SendAlert(ss, alert_warning, close_notify); } rv = osfd->methods->shutdown(osfd, nsprHow); ss->shutdownHow |= sslHow; return rv; }
PRBool SSLInt_SendAlert(PRFileDesc *fd, uint8_t level, uint8_t type) { sslSocket *ss = ssl_FindSocket(fd); if (!ss) { return PR_FALSE; } SECStatus rv = SSL3_SendAlert(ss, level, type); if (rv != SECSuccess) return PR_FALSE; return PR_TRUE; }
/* 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; }
int ssl_SecureClose(sslSocket *ss) { int rv; if (!(ss->shutdownHow & ssl_SHUTDOWN_SEND) && ss->firstHsDone && !ss->recvdCloseNotify && ss->ssl3.initialized) { /* We don't want the final alert to be Nagle delayed. */ if (!ss->delayDisabled) { ssl_EnableNagleDelay(ss, PR_FALSE); ss->delayDisabled = 1; } (void)SSL3_SendAlert(ss, alert_warning, close_notify); } rv = ssl_DefClose(ss); return rv; }
static SECStatus ssl_CallExtensionHandler(sslSocket *ss, SSLHandshakeType handshakeMessage, TLSExtension *extension, const ssl3ExtensionHandler *handler) { SECStatus rv = SECSuccess; SSLAlertDescription alert = handshake_failure; sslCustomExtensionHooks *customHooks; customHooks = ssl_FindCustomExtensionHooks(ss, extension->type); if (customHooks) { if (customHooks->handler) { rv = customHooks->handler(ss->fd, handshakeMessage, extension->data.data, extension->data.len, &alert, customHooks->handlerArg); } } else { /* Find extension_type in table of Hello Extension Handlers. */ for (; handler->ex_handler != NULL; ++handler) { if (handler->ex_type == extension->type) { SECItem tmp = extension->data; rv = (*handler->ex_handler)(ss, &ss->xtnData, &tmp); break; } } } if (rv != SECSuccess) { if (!ss->ssl3.fatalAlertSent) { /* Send an alert if the handler didn't already. */ (void)SSL3_SendAlert(ss, alert_fatal, alert); } return SECFailure; } return SECSuccess; }
int ssl_SecureClose(sslSocket *ss) { int rv; if (ss->version >= SSL_LIBRARY_VERSION_3_0 && !(ss->shutdownHow & ssl_SHUTDOWN_SEND) && ss->firstHsDone && !ss->recvdCloseNotify && ss->ssl3.initialized) { if (!ss->delayDisabled) { ssl_EnableNagleDelay(ss, PR_FALSE); ss->delayDisabled = 1; } (void) SSL3_SendAlert(ss, alert_warning, close_notify); } rv = ssl_DefClose(ss); return rv; }
/* Called from ssl3_SendClientKeyExchange(). */ SECStatus ssl3_SendECDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey) { PK11SymKey * pms = NULL; SECStatus rv = SECFailure; PRBool isTLS, isTLS12; CK_MECHANISM_TYPE target; SECKEYPublicKey *pubKey = NULL; /* Ephemeral ECDH key */ SECKEYPrivateKey *privKey = NULL; /* Ephemeral ECDH key */ PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); /* Generate ephemeral EC keypair */ if (svrPubKey->keyType != ecKey) { PORT_SetError(SEC_ERROR_BAD_KEY); goto loser; } /* XXX SHOULD CALL ssl3_CreateECDHEphemeralKeys here, instead! */ privKey = SECKEY_CreateECPrivateKey(&svrPubKey->u.ec.DEREncodedParams, &pubKey, ss->pkcs11PinArg); if (!privKey || !pubKey) { ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL); rv = SECFailure; goto loser; } PRINT_BUF(50, (ss, "ECDH public value:", pubKey->u.ec.publicValue.data, pubKey->u.ec.publicValue.len)); if (isTLS12) { target = CKM_NSS_TLS_MASTER_KEY_DERIVE_DH_SHA256; } else if (isTLS) { target = CKM_TLS_MASTER_KEY_DERIVE_DH; } else { target = CKM_SSL3_MASTER_KEY_DERIVE_DH; } /* Determine the PMS */ pms = PK11_PubDeriveWithKDF(privKey, svrPubKey, PR_FALSE, NULL, NULL, CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0, CKD_NULL, NULL, NULL); if (pms == NULL) { SSL3AlertDescription desc = illegal_parameter; (void)SSL3_SendAlert(ss, alert_fatal, desc); ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); goto loser; } SECKEY_DestroyPrivateKey(privKey); privKey = NULL; rv = ssl3_InitPendingCipherSpec(ss, pms); PK11_FreeSymKey(pms); pms = NULL; if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); goto loser; } rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange, pubKey->u.ec.publicValue.len + 1); if (rv != SECSuccess) { goto loser; /* err set by ssl3_AppendHandshake* */ } rv = ssl3_AppendHandshakeVariable(ss, pubKey->u.ec.publicValue.data, pubKey->u.ec.publicValue.len, 1); SECKEY_DestroyPublicKey(pubKey); pubKey = NULL; if (rv != SECSuccess) { goto loser; /* err set by ssl3_AppendHandshake* */ } rv = SECSuccess; loser: if(pms) PK11_FreeSymKey(pms); if(privKey) SECKEY_DestroyPrivateKey(privKey); if(pubKey) SECKEY_DestroyPublicKey(pubKey); return rv; }
SECStatus ssl3_HandleECDHServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) { PLArenaPool *arena = NULL; SECKEYPublicKey *peerKey = NULL; PRBool isTLS; SECStatus rv; int errCode = SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH; SSL3AlertDescription desc = illegal_parameter; SSL3Hashes hashes; SECItem signature = { siBuffer, NULL, 0 }; SSLHashType hashAlg = ssl_hash_none; SECItem ec_params = { siBuffer, NULL, 0 }; SECItem ec_point = { siBuffer, NULL, 0 }; unsigned char paramBuf[3]; /* only for curve_type == named_curve */ const namedGroupDef *ecGroup; isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); ec_params.len = sizeof paramBuf; ec_params.data = paramBuf; rv = ssl3_ConsumeHandshake(ss, ec_params.data, ec_params.len, &b, &length); if (rv != SECSuccess) { goto loser; /* malformed. */ } /* Fail if the curve is not a named curve */ if (ec_params.data[0] != ec_type_named) { errCode = SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE; desc = handshake_failure; goto alert_loser; } ecGroup = ssl_LookupNamedGroup(ec_params.data[1] << 8 | ec_params.data[2]); if (!ecGroup || ecGroup->type != group_type_ec) { errCode = SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE; desc = handshake_failure; goto alert_loser; } rv = ssl3_ConsumeHandshakeVariable(ss, &ec_point, 1, &b, &length); if (rv != SECSuccess) { goto loser; /* malformed. */ } /* Fail if the provided point has length 0. */ if (!ec_point.len) { /* desc and errCode are initialized already */ goto alert_loser; } /* Fail if the ec point uses compressed representation. */ if (ec_point.data[0] != EC_POINT_FORM_UNCOMPRESSED) { errCode = SEC_ERROR_UNSUPPORTED_EC_POINT_FORM; desc = handshake_failure; goto alert_loser; } if (ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2) { SSLSignatureAndHashAlg sigAndHash; rv = ssl3_ConsumeSignatureAndHashAlgorithm(ss, &b, &length, &sigAndHash); if (rv != SECSuccess) { goto loser; /* malformed or unsupported. */ } rv = ssl3_CheckSignatureAndHashAlgorithmConsistency( ss, &sigAndHash, ss->sec.peerCert); if (rv != SECSuccess) { goto loser; } hashAlg = sigAndHash.hashAlg; } rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length); if (rv != SECSuccess) { goto loser; /* malformed. */ } if (length != 0) { if (isTLS) desc = decode_error; goto alert_loser; /* malformed. */ } PRINT_BUF(60, (NULL, "Server EC params", ec_params.data, ec_params.len)); PRINT_BUF(60, (NULL, "Server EC point", ec_point.data, ec_point.len)); /* failures after this point are not malformed handshakes. */ /* TLS: send decrypt_error if signature failed. */ desc = isTLS ? decrypt_error : handshake_failure; /* * check to make sure the hash is signed by right guy */ rv = ssl3_ComputeECDHKeyHash(hashAlg, ec_params, ec_point, &ss->ssl3.hs.client_random, &ss->ssl3.hs.server_random, &hashes, ss->opt.bypassPKCS11); if (rv != SECSuccess) { errCode = ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); goto alert_loser; } rv = ssl3_VerifySignedHashes(&hashes, ss->sec.peerCert, &signature, isTLS, ss->pkcs11PinArg); if (rv != SECSuccess) { errCode = ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); goto alert_loser; } arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (arena == NULL) { errCode = SEC_ERROR_NO_MEMORY; goto loser; } peerKey = PORT_ArenaZNew(arena, SECKEYPublicKey); if (peerKey == NULL) { errCode = SEC_ERROR_NO_MEMORY; goto loser; } peerKey->arena = arena; peerKey->keyType = ecKey; /* set up EC parameters in peerKey */ rv = ssl_NamedGroup2ECParams(arena, ecGroup, &peerKey->u.ec.DEREncodedParams); if (rv != SECSuccess) { /* we should never get here since we already * checked that we are dealing with a supported curve */ errCode = SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE; goto alert_loser; } /* copy publicValue in peerKey */ if (SECITEM_CopyItem(arena, &peerKey->u.ec.publicValue, &ec_point)) { errCode = SEC_ERROR_NO_MEMORY; goto loser; } peerKey->pkcs11Slot = NULL; peerKey->pkcs11ID = CK_INVALID_HANDLE; ss->sec.peerKey = peerKey; return SECSuccess; alert_loser: (void)SSL3_SendAlert(ss, alert_fatal, desc); loser: if (arena) { PORT_FreeArena(arena, PR_FALSE); } PORT_SetError(errCode); return SECFailure; }
/* ** Called from ssl3_HandleClientKeyExchange() */ SECStatus ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length, sslKeyPair *serverKeyPair) { PK11SymKey *pms; SECStatus rv; SECKEYPublicKey clntPubKey; CK_MECHANISM_TYPE target; PRBool isTLS, isTLS12; int errCode = SSL_ERROR_RX_MALFORMED_CLIENT_KEY_EXCH; PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); clntPubKey.keyType = ecKey; clntPubKey.u.ec.DEREncodedParams.len = serverKeyPair->pubKey->u.ec.DEREncodedParams.len; clntPubKey.u.ec.DEREncodedParams.data = serverKeyPair->pubKey->u.ec.DEREncodedParams.data; rv = ssl3_ConsumeHandshakeVariable(ss, &clntPubKey.u.ec.publicValue, 1, &b, &length); if (rv != SECSuccess) { PORT_SetError(errCode); return SECFailure; } /* we have to catch the case when the client's public key has length 0. */ if (!clntPubKey.u.ec.publicValue.len) { (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter); PORT_SetError(errCode); return SECFailure; } isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); isTLS12 = (PRBool)(ss->ssl3.prSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); if (isTLS12) { target = CKM_TLS12_MASTER_KEY_DERIVE_DH; } else if (isTLS) { target = CKM_TLS_MASTER_KEY_DERIVE_DH; } else { target = CKM_SSL3_MASTER_KEY_DERIVE_DH; } /* Determine the PMS */ pms = PK11_PubDeriveWithKDF(serverKeyPair->privKey, &clntPubKey, PR_FALSE, NULL, NULL, CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0, CKD_NULL, NULL, NULL); if (pms == NULL) { /* last gasp. */ errCode = ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); PORT_SetError(errCode); return SECFailure; } rv = ssl3_InitPendingCipherSpec(ss, pms); PK11_FreeSymKey(pms); if (rv != SECSuccess) { /* error code set by ssl3_InitPendingCipherSpec */ return SECFailure; } return SECSuccess; }
/* Called from ssl3_SendClientKeyExchange(). */ SECStatus ssl3_SendECDHClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey) { PK11SymKey *pms = NULL; SECStatus rv = SECFailure; PRBool isTLS, isTLS12; CK_MECHANISM_TYPE target; const namedGroupDef *groupDef; sslEphemeralKeyPair *keyPair = NULL; SECKEYPublicKey *pubKey; PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); /* Generate ephemeral EC keypair */ if (svrPubKey->keyType != ecKey) { PORT_SetError(SEC_ERROR_BAD_KEY); goto loser; } groupDef = ssl_ECPubKey2NamedGroup(svrPubKey); if (!groupDef) { PORT_SetError(SEC_ERROR_BAD_KEY); goto loser; } rv = ssl_CreateECDHEphemeralKeyPair(groupDef, &keyPair); if (rv != SECSuccess) { ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL); goto loser; } pubKey = keyPair->keys->pubKey; PRINT_BUF(50, (ss, "ECDH public value:", pubKey->u.ec.publicValue.data, pubKey->u.ec.publicValue.len)); if (isTLS12) { target = CKM_TLS12_MASTER_KEY_DERIVE_DH; } else if (isTLS) { target = CKM_TLS_MASTER_KEY_DERIVE_DH; } else { target = CKM_SSL3_MASTER_KEY_DERIVE_DH; } /* Determine the PMS */ pms = PK11_PubDeriveWithKDF(keyPair->keys->privKey, svrPubKey, PR_FALSE, NULL, NULL, CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0, CKD_NULL, NULL, NULL); if (pms == NULL) { (void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter); ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); goto loser; } rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange, pubKey->u.ec.publicValue.len + 1); if (rv != SECSuccess) { goto loser; /* err set by ssl3_AppendHandshake* */ } rv = ssl3_AppendHandshakeVariable(ss, pubKey->u.ec.publicValue.data, pubKey->u.ec.publicValue.len, 1); if (rv != SECSuccess) { goto loser; /* err set by ssl3_AppendHandshake* */ } rv = ssl3_InitPendingCipherSpec(ss, pms); if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); goto loser; } PK11_FreeSymKey(pms); ssl_FreeEphemeralKeyPair(keyPair); return SECSuccess; loser: if (pms) PK11_FreeSymKey(pms); if (keyPair) ssl_FreeEphemeralKeyPair(keyPair); return SECFailure; }
/* * Attempt to read in an entire SSL3 record. * Blocks here for blocking sockets, otherwise returns -1 with * PR_WOULD_BLOCK_ERROR when socket would block. * * returns 1 if received a complete SSL3 record. * returns 0 if recv returns EOF * returns -1 if recv returns < 0 * (The error value may have already been set to PR_WOULD_BLOCK_ERROR) * * Caller must hold the recv buf lock. * * The Gather state machine has 3 states: GS_INIT, GS_HEADER, GS_DATA. * GS_HEADER: waiting for the 5-byte SSL3 record header to come in. * GS_DATA: waiting for the body of the SSL3 record to come in. * * This loop returns when either * (a) an error or EOF occurs, * (b) PR_WOULD_BLOCK_ERROR, * (c) data (entire SSL3 record) has been received. */ static int ssl3_GatherData(sslSocket *ss, sslGather *gs, int flags) { unsigned char *bp; unsigned char *lbp; int nb; int err; int rv = 1; PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); if (gs->state == GS_INIT) { gs->state = GS_HEADER; gs->remainder = 5; gs->offset = 0; gs->writeOffset = 0; gs->readOffset = 0; gs->inbuf.len = 0; } lbp = gs->inbuf.buf; for (;;) { SSL_TRC(30, ("%d: SSL3[%d]: gather state %d (need %d more)", SSL_GETPID(), ss->fd, gs->state, gs->remainder)); bp = ((gs->state != GS_HEADER) ? lbp : gs->hdr) + gs->offset; nb = ssl_DefRecv(ss, bp, gs->remainder, flags); if (nb > 0) { PRINT_BUF(60, (ss, "raw gather data:", bp, nb)); } else if (nb == 0) { /* EOF */ SSL_TRC(30, ("%d: SSL3[%d]: EOF", SSL_GETPID(), ss->fd)); rv = 0; break; } else /* if (nb < 0) */ { SSL_DBG(("%d: SSL3[%d]: recv error %d", SSL_GETPID(), ss->fd, PR_GetError())); rv = SECFailure; break; } PORT_Assert((unsigned int)nb <= gs->remainder); if ((unsigned int)nb > gs->remainder) { /* ssl_DefRecv is misbehaving! this error is fatal to SSL. */ gs->state = GS_INIT; /* so we don't crash next time */ rv = SECFailure; break; } gs->offset += nb; gs->remainder -= nb; if (gs->state == GS_DATA) gs->inbuf.len += nb; /* if there's more to go, read some more. */ if (gs->remainder > 0) { continue; } /* have received entire record header, or entire record. */ switch (gs->state) { case GS_HEADER: /* ** Have received SSL3 record header in gs->hdr. ** Now extract the length of the following encrypted data, ** and then read in the rest of the SSL3 record into gs->inbuf. */ gs->remainder = (gs->hdr[3] << 8) | gs->hdr[4]; /* This is the max fragment length for an encrypted fragment ** plus the size of the record header. */ if (gs->remainder > (MAX_FRAGMENT_LENGTH + 2048 + 5)) { SSL3_SendAlert(ss, alert_fatal, unexpected_message); gs->state = GS_INIT; PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG); return SECFailure; } gs->state = GS_DATA; gs->offset = 0; gs->inbuf.len = 0; if (gs->remainder > gs->inbuf.space) { err = sslBuffer_Grow(&gs->inbuf, gs->remainder); if (err) { /* realloc has set error code to no mem. */ return err; } lbp = gs->inbuf.buf; } break; /* End this case. Continue around the loop. */ case GS_DATA: /* ** SSL3 record has been completely received. */ gs->state = GS_INIT; return 1; } } return rv; }
/* Thunks to let extension handlers operate on const sslSocket* objects. */ void ssl3_ExtSendAlert(const sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc) { (void)SSL3_SendAlert((sslSocket *)ss, level, desc); }
/* Go through the hello extensions in |ss->ssl3.hs.remoteExtensions|. * For each one, find the extension handler in the table, and * if present, invoke that handler. * Servers ignore any extensions with unknown extension types. * Clients reject any extensions with unadvertised extension types * * In TLS >= 1.3, the client checks that extensions appear in the * right phase. */ SECStatus ssl3_HandleParsedExtensions(sslSocket *ss, SSLHandshakeType message) { const ssl3ExtensionHandler *handlers; /* HelloRetryRequest doesn't set ss->version. It might be safe to * do so, but we weren't entirely sure. TODO([email protected]). */ PRBool isTLS13 = (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) || (message == ssl_hs_hello_retry_request); /* The following messages can include extensions that were not included in * the original ClientHello. */ PRBool allowNotOffered = (message == ssl_hs_client_hello) || (message == ssl_hs_certificate_request) || (message == ssl_hs_new_session_ticket); PRCList *cursor; switch (message) { case ssl_hs_client_hello: handlers = clientHelloHandlers; break; case ssl_hs_new_session_ticket: PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); handlers = newSessionTicketHandlers; break; case ssl_hs_hello_retry_request: handlers = helloRetryRequestHandlers; break; case ssl_hs_encrypted_extensions: PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); /* fall through */ case ssl_hs_server_hello: if (ss->version > SSL_LIBRARY_VERSION_3_0) { handlers = serverHelloHandlersTLS; } else { handlers = serverHelloHandlersSSL3; } break; case ssl_hs_certificate: PORT_Assert(!ss->sec.isServer); handlers = serverCertificateHandlers; break; case ssl_hs_certificate_request: PORT_Assert(!ss->sec.isServer); handlers = certificateRequestHandlers; break; default: PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); PORT_Assert(0); return SECFailure; } for (cursor = PR_NEXT_LINK(&ss->ssl3.hs.remoteExtensions); cursor != &ss->ssl3.hs.remoteExtensions; cursor = PR_NEXT_LINK(cursor)) { TLSExtension *extension = (TLSExtension *)cursor; SECStatus rv; /* Check whether the server sent an extension which was not advertised * in the ClientHello. * * Note that a TLS 1.3 server should check if CertificateRequest * extensions were sent. But the extensions used for CertificateRequest * do not have any response, so we rely on * ssl3_ExtensionAdvertised to return false on the server. That * results in the server only rejecting any extension. */ if (!allowNotOffered && (extension->type != ssl_tls13_cookie_xtn) && !ssl3_ExtensionAdvertised(ss, extension->type)) { (void)SSL3_SendAlert(ss, alert_fatal, unsupported_extension); PORT_SetError(SSL_ERROR_RX_UNEXPECTED_EXTENSION); return SECFailure; } /* Check that this is a legal extension in TLS 1.3 */ if (isTLS13 && !ssl_FindCustomExtensionHooks(ss, extension->type)) { switch (tls13_ExtensionStatus(extension->type, message)) { case tls13_extension_allowed: break; case tls13_extension_unknown: if (allowNotOffered) { continue; /* Skip over unknown extensions. */ } /* Fall through. */ case tls13_extension_disallowed: SSL_TRC(3, ("%d: TLS13: unexpected extension %d in message %d", SSL_GETPID(), extension, message)); tls13_FatalError(ss, SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION, unsupported_extension); return SECFailure; } } /* Special check for this being the last extension if it's * PreSharedKey */ if (ss->sec.isServer && isTLS13 && (extension->type == ssl_tls13_pre_shared_key_xtn) && (PR_NEXT_LINK(cursor) != &ss->ssl3.hs.remoteExtensions)) { tls13_FatalError(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter); return SECFailure; } rv = ssl_CallExtensionHandler(ss, message, extension, handlers); if (rv != SECSuccess) { return SECFailure; } } return SECSuccess; }
static int ssl3_GatherData(sslSocket *ss, sslGather *gs, int flags) { unsigned char *bp; unsigned char *lbp; int nb; int err; int rv = 1; PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); if (gs->state == GS_INIT) { gs->state = GS_HEADER; gs->remainder = 5; gs->offset = 0; gs->writeOffset = 0; gs->readOffset = 0; gs->inbuf.len = 0; } lbp = gs->inbuf.buf; for(;;) { SSL_TRC(30, ("%d: SSL3[%d]: gather state %d (need %d more)", SSL_GETPID(), ss->fd, gs->state, gs->remainder)); bp = ((gs->state != GS_HEADER) ? lbp : gs->hdr) + gs->offset; nb = ssl_DefRecv(ss, bp, gs->remainder, flags); if (nb > 0) { PRINT_BUF(60, (ss, "raw gather data:", bp, nb)); } else if (nb == 0) { SSL_TRC(30, ("%d: SSL3[%d]: EOF", SSL_GETPID(), ss->fd)); rv = 0; break; } else { SSL_DBG(("%d: SSL3[%d]: recv error %d", SSL_GETPID(), ss->fd, PR_GetError())); rv = SECFailure; break; } PORT_Assert( nb <= gs->remainder ); if (nb > gs->remainder) { gs->state = GS_INIT; rv = SECFailure; break; } gs->offset += nb; gs->remainder -= nb; if (gs->state == GS_DATA) gs->inbuf.len += nb; if (gs->remainder > 0) { continue; } switch (gs->state) { case GS_HEADER: gs->remainder = (gs->hdr[3] << 8) | gs->hdr[4]; if(gs->remainder > (MAX_FRAGMENT_LENGTH + 2048 + 5)) { SSL3_SendAlert(ss, alert_fatal, unexpected_message); gs->state = GS_INIT; PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG); return SECFailure; } gs->state = GS_DATA; gs->offset = 0; gs->inbuf.len = 0; if (gs->remainder > gs->inbuf.space) { err = sslBuffer_Grow(&gs->inbuf, gs->remainder); if (err) { return err; } lbp = gs->inbuf.buf; } break; case GS_DATA: gs->state = GS_INIT; return 1; } } return rv; }
SECStatus ssl3_HandleECDHServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) { PLArenaPool *arena = NULL; SECKEYPublicKey *peerKey = NULL; PRBool isTLS; SECStatus rv; int errCode = SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH; SSL3AlertDescription desc = illegal_parameter; SSL3Hashes hashes; SECItem signature = { siBuffer, NULL, 0 }; SSLHashType hashAlg; SSLSignatureScheme sigScheme; SECItem ec_params = { siBuffer, NULL, 0 }; SECItem ec_point = { siBuffer, NULL, 0 }; unsigned char paramBuf[3]; const sslNamedGroupDef *ecGroup; isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); ec_params.len = sizeof paramBuf; ec_params.data = paramBuf; rv = ssl3_ConsumeHandshake(ss, ec_params.data, ec_params.len, &b, &length); if (rv != SECSuccess) { goto loser; /* malformed. */ } /* Fail if the curve is not a named curve */ if (ec_params.data[0] != ec_type_named) { errCode = SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE; desc = handshake_failure; goto alert_loser; } ecGroup = ssl_LookupNamedGroup(ec_params.data[1] << 8 | ec_params.data[2]); if (!ecGroup || ecGroup->keaType != ssl_kea_ecdh) { errCode = SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE; desc = handshake_failure; goto alert_loser; } rv = ssl3_ConsumeHandshakeVariable(ss, &ec_point, 1, &b, &length); if (rv != SECSuccess) { goto loser; /* malformed. */ } /* Fail if the provided point has length 0. */ if (!ec_point.len) { /* desc and errCode are initialized already */ goto alert_loser; } /* Fail if the ec point is not uncompressed for any curve that's not 25519. */ if (ecGroup->name != ssl_grp_ec_curve25519 && ec_point.data[0] != EC_POINT_FORM_UNCOMPRESSED) { errCode = SEC_ERROR_UNSUPPORTED_EC_POINT_FORM; desc = handshake_failure; goto alert_loser; } PORT_Assert(ss->ssl3.prSpec->version <= SSL_LIBRARY_VERSION_TLS_1_2); if (ss->ssl3.prSpec->version == SSL_LIBRARY_VERSION_TLS_1_2) { rv = ssl_ConsumeSignatureScheme(ss, &b, &length, &sigScheme); if (rv != SECSuccess) { goto loser; /* malformed or unsupported. */ } rv = ssl_CheckSignatureSchemeConsistency(ss, sigScheme, ss->sec.peerCert); if (rv != SECSuccess) { goto loser; } hashAlg = ssl_SignatureSchemeToHashType(sigScheme); } else { /* Use ssl_hash_none to represent the MD5+SHA1 combo. */ hashAlg = ssl_hash_none; sigScheme = ssl_sig_none; } rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length); if (rv != SECSuccess) { goto loser; /* malformed. */ } if (length != 0) { if (isTLS) desc = decode_error; goto alert_loser; /* malformed. */ } PRINT_BUF(60, (NULL, "Server EC params", ec_params.data, ec_params.len)); PRINT_BUF(60, (NULL, "Server EC point", ec_point.data, ec_point.len)); /* failures after this point are not malformed handshakes. */ /* TLS: send decrypt_error if signature failed. */ desc = isTLS ? decrypt_error : handshake_failure; /* * check to make sure the hash is signed by right guy */ rv = ssl3_ComputeECDHKeyHash(hashAlg, ec_params, ec_point, &ss->ssl3.hs.client_random, &ss->ssl3.hs.server_random, &hashes); if (rv != SECSuccess) { errCode = ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); goto alert_loser; } rv = ssl3_VerifySignedHashes(ss, sigScheme, &hashes, &signature); if (rv != SECSuccess) { errCode = ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); goto alert_loser; } arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (arena == NULL) { errCode = SEC_ERROR_NO_MEMORY; goto loser; } peerKey = PORT_ArenaZNew(arena, SECKEYPublicKey); if (peerKey == NULL) { errCode = SEC_ERROR_NO_MEMORY; goto loser; } peerKey->arena = arena; /* create public key from point data */ rv = ssl_ImportECDHKeyShare(ss, peerKey, ec_point.data, ec_point.len, ecGroup); if (rv != SECSuccess) { /* error code is set */ desc = handshake_failure; errCode = PORT_GetError(); goto alert_loser; } peerKey->pkcs11Slot = NULL; peerKey->pkcs11ID = CK_INVALID_HANDLE; ss->sec.peerKey = peerKey; return SECSuccess; alert_loser: (void)SSL3_SendAlert(ss, alert_fatal, desc); loser: if (arena) { PORT_FreeArena(arena, PR_FALSE); } PORT_SetError(errCode); return SECFailure; }
/* Go through the hello extensions in |ss->ssl3.hs.remoteExtensions|. * For each one, find the extension handler in the table, and * if present, invoke that handler. * Servers ignore any extensions with unknown extension types. * Clients reject any extensions with unadvertised extension types * * In TLS >= 1.3, the client checks that extensions appear in the * right phase. */ SECStatus ssl3_HandleParsedExtensions(sslSocket *ss, SSL3HandshakeType handshakeMessage) { const ssl3ExtensionHandler *handlers; PRBool isTLS13 = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3; PRCList *cursor; switch (handshakeMessage) { case client_hello: handlers = clientHelloHandlers; break; case new_session_ticket: PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); handlers = newSessionTicketHandlers; break; case hello_retry_request: handlers = helloRetryRequestHandlers; break; case encrypted_extensions: PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3); /* fall through */ case server_hello: if (ss->version > SSL_LIBRARY_VERSION_3_0) { handlers = serverHelloHandlersTLS; } else { handlers = serverHelloHandlersSSL3; } break; case certificate: PORT_Assert(!ss->sec.isServer); handlers = serverCertificateHandlers; break; default: PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); PORT_Assert(0); return SECFailure; } for (cursor = PR_NEXT_LINK(&ss->ssl3.hs.remoteExtensions); cursor != &ss->ssl3.hs.remoteExtensions; cursor = PR_NEXT_LINK(cursor)) { TLSExtension *extension = (TLSExtension *)cursor; const ssl3ExtensionHandler *handler; /* Check whether the server sent an extension which was not advertised * in the ClientHello */ if (!ss->sec.isServer && !ssl3_ClientExtensionAdvertised(ss, extension->type) && (handshakeMessage != new_session_ticket) && (extension->type != ssl_tls13_cookie_xtn)) { (void)SSL3_SendAlert(ss, alert_fatal, unsupported_extension); PORT_SetError(SSL_ERROR_RX_UNEXPECTED_EXTENSION); return SECFailure; } /* Check that this is a legal extension in TLS 1.3 */ if (isTLS13 && !tls13_ExtensionAllowed(extension->type, handshakeMessage)) { if (handshakeMessage == client_hello) { /* Skip extensions not used in TLS 1.3 */ continue; } tls13_FatalError(ss, SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION, unsupported_extension); return SECFailure; } /* Special check for this being the last extension if it's * PreSharedKey */ if (ss->sec.isServer && isTLS13 && (extension->type == ssl_tls13_pre_shared_key_xtn) && (PR_NEXT_LINK(cursor) != &ss->ssl3.hs.remoteExtensions)) { tls13_FatalError(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter); return SECFailure; } /* find extension_type in table of Hello Extension Handlers */ for (handler = handlers; handler->ex_type >= 0; handler++) { /* if found, call this handler */ if (handler->ex_type == extension->type) { SECStatus rv; rv = (*handler->ex_handler)(ss, &ss->xtnData, (PRUint16)extension->type, &extension->data); if (rv != SECSuccess) { if (!ss->ssl3.fatalAlertSent) { /* send a generic alert if the handler didn't already */ (void)SSL3_SendAlert(ss, alert_fatal, handshake_failure); } return SECFailure; } } } } return SECSuccess; }