/* 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; }
/* 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) { /* for v3 this is done in ssl3_FinishHandshake */ if (!ss->firstHsDone && ss->version < SSL_LIBRARY_VERSION_3_0) { ssl_GetRecvBufLock(ss); ss->gs.recordLen = 0; ssl_FinishHandshake(ss); ssl_ReleaseRecvBufLock(ss); } 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; }
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) { ss->handshake = ss->nextHandshake; ss->nextHandshake = 0; } if (ss->handshake == 0) { ss->handshake = ss->securityHandshake; ss->securityHandshake = 0; } if (ss->handshake == 0) { if (!ss->firstHsDone && ss->version < SSL_LIBRARY_VERSION_3_0) { ssl_GetRecvBufLock(ss); ss->gs.recordLen = 0; ssl_FinishHandshake(ss); ssl_ReleaseRecvBufLock(ss); } break; } rv = (*ss->handshake)(ss); ++loopCount; } while (rv != SECFailure); 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; }
/* This function encodes the key_exchange field in * the KeyShareEntry structure. */ SECStatus tls13_EncodeECDHEKeyShareKEX(sslSocket *ss, const SECKEYPublicKey *pubKey) { PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); PORT_Assert(pubKey->keyType == ecKey); return ssl3_AppendHandshake(ss, pubKey->u.ec.publicValue.data, pubKey->u.ec.publicValue.len); }
/* ** 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; }
/* 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 * ssl_BeginClientHandshake * ssl_BeginServerHandshake * * The ss->handshake function returns SECWouldBlock if it was returned by * one of the callback functions, via one of these paths: * * - 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; while (ss->handshake && rv == SECSuccess) { 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)); rv = (*ss->handshake)(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 (rv == SECWouldBlock) { PORT_SetError(PR_WOULD_BLOCK_ERROR); rv = SECFailure; } return rv; }
/* ** 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; }
/* 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; }
/* 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; }