SECStatus ssl3_SendECDHServerKeyExchange(sslSocket *ss) { SECStatus rv = SECFailure; int length; PRBool isTLS12; SECItem signed_hash = { siBuffer, NULL, 0 }; SSLHashType hashAlg = ssl_hash_none; SSL3Hashes hashes; SECItem ec_params = { siBuffer, NULL, 0 }; unsigned char paramBuf[3]; const sslNamedGroupDef *ecGroup; sslEphemeralKeyPair *keyPair; SECKEYPublicKey *pubKey; /* Generate ephemeral ECDH key pair and send the public key */ ecGroup = ssl_GetECGroupForServerSocket(ss); if (!ecGroup) { goto loser; } PORT_Assert(PR_CLIST_IS_EMPTY(&ss->ephemeralKeyPairs)); if (ss->opt.reuseServerECDHEKey) { rv = ssl_CreateStaticECDHEKey(ss, ecGroup); if (rv != SECSuccess) { goto loser; } keyPair = (sslEphemeralKeyPair *)PR_NEXT_LINK(&ss->ephemeralKeyPairs); } else { rv = ssl_CreateECDHEphemeralKeyPair(ss, ecGroup, &keyPair); if (rv != SECSuccess) { goto loser; } PR_APPEND_LINK(&keyPair->link, &ss->ephemeralKeyPairs); } PORT_Assert(keyPair); if (!keyPair) { PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); return SECFailure; } ec_params.len = sizeof(paramBuf); ec_params.data = paramBuf; PORT_Assert(keyPair->group); PORT_Assert(keyPair->group->keaType == ssl_kea_ecdh); ec_params.data[0] = ec_type_named; ec_params.data[1] = keyPair->group->name >> 8; ec_params.data[2] = keyPair->group->name & 0xff; pubKey = keyPair->keys->pubKey; if (ss->ssl3.pwSpec->version == SSL_LIBRARY_VERSION_TLS_1_2) { hashAlg = ssl_SignatureSchemeToHashType(ss->ssl3.hs.signatureScheme); } else { /* Use ssl_hash_none to represent the MD5+SHA1 combo. */ hashAlg = ssl_hash_none; } rv = ssl3_ComputeECDHKeyHash(hashAlg, ec_params, pubKey->u.ec.publicValue, &ss->ssl3.hs.client_random, &ss->ssl3.hs.server_random, &hashes); if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); goto loser; } isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); rv = ssl3_SignHashes(ss, &hashes, ss->sec.serverCert->serverKeyPair->privKey, &signed_hash); if (rv != SECSuccess) { goto loser; /* ssl3_SignHashes has set err. */ } if (signed_hash.data == NULL) { /* how can this happen and rv == SECSuccess ?? */ PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); goto loser; } length = ec_params.len + 1 + pubKey->u.ec.publicValue.len + (isTLS12 ? 2 : 0) + 2 + signed_hash.len; rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length); if (rv != SECSuccess) { goto loser; /* err set by AppendHandshake. */ } rv = ssl3_AppendHandshake(ss, ec_params.data, ec_params.len); if (rv != SECSuccess) { goto loser; /* err set by AppendHandshake. */ } rv = ssl3_AppendHandshakeVariable(ss, pubKey->u.ec.publicValue.data, pubKey->u.ec.publicValue.len, 1); if (rv != SECSuccess) { goto loser; /* err set by AppendHandshake. */ } if (isTLS12) { rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.signatureScheme, 2); if (rv != SECSuccess) { goto loser; /* err set by AppendHandshake. */ } } rv = ssl3_AppendHandshakeVariable(ss, signed_hash.data, signed_hash.len, 2); if (rv != SECSuccess) { goto loser; /* err set by AppendHandshake. */ } PORT_Free(signed_hash.data); return SECSuccess; loser: if (signed_hash.data != NULL) PORT_Free(signed_hash.data); return SECFailure; }
/* Send our Supported Groups extension. */ PRInt32 ssl_SendSupportedGroupsXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes) { PRInt32 extension_length; unsigned char enabledGroups[64]; unsigned int enabledGroupsLen = 0; unsigned int i; PRBool ec; PRBool ff = PR_FALSE; if (!ss) return 0; /* We only send FF supported groups if we require DH named groups * or if TLS 1.3 is a possibility. */ if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) { ec = ssl_IsECCEnabled(ss); if (ss->opt.requireDHENamedGroups) { ff = ssl_IsDHEEnabled(ss); } if (!ec && !ff) return 0; } else { ec = ff = PR_TRUE; } PORT_Assert(sizeof(enabledGroups) > SSL_NAMED_GROUP_COUNT * 2); for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) { const sslNamedGroupDef *group = ss->namedGroupPreferences[i]; if (!group) { continue; } if (group->keaType == ssl_kea_ecdh && !ec) { continue; } if (group->keaType == ssl_kea_dh && !ff) { continue; } if (append) { (void)ssl_EncodeUintX(group->name, 2, &enabledGroups[enabledGroupsLen]); } enabledGroupsLen += 2; } if (enabledGroupsLen == 0) { return 0; } extension_length = 2 /* extension type */ + 2 /* extension length */ + 2 /* enabled groups length */ + enabledGroupsLen; if (maxBytes < (PRUint32)extension_length) { return 0; } if (append) { SECStatus rv; rv = ssl3_AppendHandshakeNumber(ss, ssl_supported_groups_xtn, 2); if (rv != SECSuccess) return -1; rv = ssl3_AppendHandshakeNumber(ss, extension_length - 4, 2); if (rv != SECSuccess) return -1; rv = ssl3_AppendHandshakeVariable(ss, enabledGroups, enabledGroupsLen, 2); if (rv != SECSuccess) return -1; if (!ss->sec.isServer) { TLSExtensionData *xtnData = &ss->xtnData; xtnData->advertised[xtnData->numAdvertised++] = ssl_supported_groups_xtn; } } return extension_length; }
SECStatus ssl3_ExtAppendHandshakeNumber(const sslSocket *ss, PRInt32 num, PRInt32 lenSize) { return ssl3_AppendHandshakeNumber((sslSocket *)ss, num, lenSize); }