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 SECStatus tls13_HandleKeyShareEntry(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data) { SECStatus rv; PRUint32 group; const sslNamedGroupDef *groupDef; TLS13KeyShareEntry *ks = NULL; SECItem share = { siBuffer, NULL, 0 }; rv = ssl3_ExtConsumeHandshakeNumber(ss, &group, 2, &data->data, &data->len); if (rv != SECSuccess) { PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE); goto loser; } groupDef = ssl_LookupNamedGroup(group); rv = ssl3_ExtConsumeHandshakeVariable(ss, &share, 2, &data->data, &data->len); if (rv != SECSuccess) { goto loser; } /* If the group is disabled, continue. */ if (!groupDef) { return SECSuccess; } ks = PORT_ZNew(TLS13KeyShareEntry); if (!ks) goto loser; ks->group = groupDef; rv = SECITEM_CopyItem(NULL, &ks->key_exchange, &share); if (rv != SECSuccess) goto loser; PR_APPEND_LINK(&ks->link, &xtnData->remoteKeyShares); return SECSuccess; loser: if (ks) tls13_DestroyKeyShareEntry(ks); return SECFailure; }
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; }
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; }
static SECStatus ssl_UpdateSupportedGroups(sslSocket *ss, SECItem *data) { PRInt32 list_len; unsigned int i; const sslNamedGroupDef *enabled[SSL_NAMED_GROUP_COUNT] = { 0 }; PORT_Assert(SSL_NAMED_GROUP_COUNT == PR_ARRAY_SIZE(enabled)); if (!data->data || data->len < 4) { (void)ssl3_DecodeError(ss); return SECFailure; } /* get the length of elliptic_curve_list */ list_len = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len); if (list_len < 0 || data->len != list_len || (data->len % 2) != 0) { (void)ssl3_DecodeError(ss); return SECFailure; } /* disable all groups and remember the enabled groups */ for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) { enabled[i] = ss->namedGroupPreferences[i]; ss->namedGroupPreferences[i] = NULL; } /* Read groups from data and enable if in |enabled| */ while (data->len) { const sslNamedGroupDef *group; PRInt32 curve_name = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len); if (curve_name < 0) { return SECFailure; /* fatal alert already sent */ } group = ssl_LookupNamedGroup(curve_name); if (group) { for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) { if (enabled[i] && group == enabled[i]) { ss->namedGroupPreferences[i] = enabled[i]; break; } } } /* "Codepoints in the NamedCurve registry with a high byte of 0x01 (that * is, between 256 and 511 inclusive) are set aside for FFDHE groups," * -- https://tools.ietf.org/html/draft-ietf-tls-negotiated-ff-dhe-10 */ if ((curve_name & 0xff00) == 0x0100) { ss->ssl3.hs.peerSupportsFfdheGroups = PR_TRUE; } } /* Note: if ss->opt.requireDHENamedGroups is set, we disable DHE cipher * suites, but we do that in ssl3_config_match(). */ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3 && !ss->opt.requireDHENamedGroups && !ss->ssl3.hs.peerSupportsFfdheGroups) { /* If we don't require that DHE use named groups, and no FFDHE was * included, we pretend that they support all the FFDHE groups we do. */ for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) { if (enabled[i] && enabled[i]->keaType == ssl_kea_dh) { ss->namedGroupPreferences[i] = enabled[i]; } } } return SECSuccess; }
SSLKEAType SSLInt_GetKEAType(SSLNamedGroup group) { const sslNamedGroupDef *groupDef = ssl_LookupNamedGroup(group); if (!groupDef) return ssl_kea_null; return groupDef->keaType; }