/* ** Called from ssl3_HandleClientKeyExchange() */ SECStatus ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length, SECKEYPublicKey *srvrPubKey, SECKEYPrivateKey *srvrPrivKey) { PK11SymKey * pms; SECStatus rv; SECKEYPublicKey clntPubKey; CK_MECHANISM_TYPE target; PRBool isTLS, isTLS12; PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); clntPubKey.keyType = ecKey; clntPubKey.u.ec.DEREncodedParams.len = srvrPubKey->u.ec.DEREncodedParams.len; clntPubKey.u.ec.DEREncodedParams.data = srvrPubKey->u.ec.DEREncodedParams.data; rv = ssl3_ConsumeHandshakeVariable(ss, &clntPubKey.u.ec.publicValue, 1, &b, &length); if (rv != SECSuccess) { SEND_ALERT return SECFailure; /* XXX Who sets the error code?? */ }
SECStatus ssl3_ExtConsumeHandshakeVariable(const sslSocket *ss, SECItem *i, PRUint32 bytes, PRUint8 **b, PRUint32 *length) { return ssl3_ConsumeHandshakeVariable((sslSocket *)ss, i, bytes, b, length); }
/* 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; }
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; }
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; }