blob: 26d428fca8bfedca4efd1347a72f5cf34e434cc2 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/webcrypto/webcrypto_util.h"
#include "base/logging.h"
#include "components/webcrypto/status.h"
#include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
#include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
#include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
namespace webcrypto {
namespace {
// Converts a (big-endian) WebCrypto BigInteger, with or without leading zeros,
// to unsigned int.
bool BigIntegerToUint(const uint8_t* data,
size_t data_size,
unsigned int* result) {
if (data_size == 0)
return false;
*result = 0;
for (size_t i = 0; i < data_size; ++i) {
size_t reverse_i = data_size - i - 1;
if (reverse_i >= sizeof(*result) && data[i])
return false; // Too large for a uint.
*result |= data[i] << 8 * reverse_i;
}
return true;
}
} // namespace
blink::WebCryptoAlgorithm CreateAlgorithm(blink::WebCryptoAlgorithmId id) {
return blink::WebCryptoAlgorithm::adoptParamsAndCreate(id, NULL);
}
blink::WebCryptoAlgorithm CreateRsaHashedImportAlgorithm(
blink::WebCryptoAlgorithmId id,
blink::WebCryptoAlgorithmId hash_id) {
DCHECK(blink::WebCryptoAlgorithm::isHash(hash_id));
return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
id, new blink::WebCryptoRsaHashedImportParams(CreateAlgorithm(hash_id)));
}
blink::WebCryptoAlgorithm CreateEcImportAlgorithm(
blink::WebCryptoAlgorithmId id,
blink::WebCryptoNamedCurve named_curve) {
return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
id, new blink::WebCryptoEcKeyImportParams(named_curve));
}
bool ContainsKeyUsages(blink::WebCryptoKeyUsageMask a,
blink::WebCryptoKeyUsageMask b) {
return (a & b) == b;
}
Status CheckKeyCreationUsages(blink::WebCryptoKeyUsageMask all_possible_usages,
blink::WebCryptoKeyUsageMask actual_usages,
bool allow_empty_usages) {
if (!allow_empty_usages && actual_usages == 0)
return Status::ErrorCreateKeyEmptyUsages();
if (!ContainsKeyUsages(all_possible_usages, actual_usages))
return Status::ErrorCreateKeyBadUsages();
return Status::Success();
}
Status GetRsaKeyGenParameters(
const blink::WebCryptoRsaHashedKeyGenParams* params,
unsigned int* public_exponent,
unsigned int* modulus_length_bits) {
*modulus_length_bits = params->modulusLengthBits();
// Limit the RSA key sizes to:
// * Multiple of 8 bits
// * 256 bits to 16K bits
// This corresponds to the values that NSS would allow, which was relevant
// back when Chromium's WebCrypto supported both OpenSSL and NSS.
if (*modulus_length_bits < 256 || *modulus_length_bits > 16384 ||
(*modulus_length_bits % 8) != 0) {
return Status::ErrorGenerateRsaUnsupportedModulus();
}
if (!BigIntegerToUint(params->publicExponent().data(),
params->publicExponent().size(), public_exponent)) {
return Status::ErrorGenerateKeyPublicExponent();
}
// OpenSSL hangs when given bad public exponents. Use a whitelist to avoid
// feeding OpenSSL data that could hang.
if (*public_exponent != 3 && *public_exponent != 65537)
return Status::ErrorGenerateKeyPublicExponent();
return Status::Success();
}
Status VerifyUsagesBeforeImportAsymmetricKey(
blink::WebCryptoKeyFormat format,
blink::WebCryptoKeyUsageMask all_public_key_usages,
blink::WebCryptoKeyUsageMask all_private_key_usages,
blink::WebCryptoKeyUsageMask usages) {
switch (format) {
case blink::WebCryptoKeyFormatSpki:
return CheckKeyCreationUsages(all_public_key_usages, usages, true);
case blink::WebCryptoKeyFormatPkcs8:
return CheckKeyCreationUsages(all_private_key_usages, usages, false);
case blink::WebCryptoKeyFormatJwk: {
// The JWK could represent either a public key or private key. The usages
// must make sense for one of the two. The usages will be checked again by
// ImportKeyJwk() once the key type has been determined.
if (CheckKeyCreationUsages(all_public_key_usages, usages, true)
.IsError() &&
CheckKeyCreationUsages(all_private_key_usages, usages, false)
.IsError()) {
return Status::ErrorCreateKeyBadUsages();
}
return Status::Success();
}
default:
return Status::ErrorUnsupportedImportKeyFormat();
}
}
void TruncateToBitLength(size_t length_bits, std::vector<uint8_t>* bytes) {
size_t length_bytes = NumBitsToBytes(length_bits);
if (bytes->size() != length_bytes) {
CHECK_LT(length_bytes, bytes->size());
bytes->resize(length_bytes);
}
size_t remainder_bits = length_bits % 8;
// Zero any "unused bits" in the final byte
if (remainder_bits)
(*bytes)[bytes->size() - 1] &= ~((0xFF) >> remainder_bits);
}
Status GetUsagesForGenerateAsymmetricKey(
blink::WebCryptoKeyUsageMask combined_usages,
blink::WebCryptoKeyUsageMask all_public_usages,
blink::WebCryptoKeyUsageMask all_private_usages,
blink::WebCryptoKeyUsageMask* public_usages,
blink::WebCryptoKeyUsageMask* private_usages) {
Status status = CheckKeyCreationUsages(all_public_usages | all_private_usages,
combined_usages, true);
if (status.IsError())
return status;
*public_usages = combined_usages & all_public_usages;
*private_usages = combined_usages & all_private_usages;
if (*private_usages == 0)
return Status::ErrorCreateKeyEmptyUsages();
return Status::Success();
}
} // namespace webcrypto