CryptoAlgorithmECDSAMac.cpp [plain text]
#include "config.h"
#include "CryptoAlgorithmECDSA.h"
#if ENABLE(SUBTLE_CRYPTO)
#include "CommonCryptoDERUtilities.h"
#include "CommonCryptoUtilities.h"
#include "CryptoAlgorithmEcdsaParams.h"
#include "CryptoDigestAlgorithm.h"
#include "CryptoKeyEC.h"
#include "ExceptionCode.h"
#include "ScriptExecutionContext.h"
namespace WebCore {
static ExceptionOr<Vector<uint8_t>> signECDSA(CryptoAlgorithmIdentifier hash, const PlatformECKey key, size_t keyLengthInBytes, const Vector<uint8_t>& data)
{
CCDigestAlgorithm digestAlgorithm;
if (!getCommonCryptoDigestAlgorithm(hash, digestAlgorithm))
return Exception { OperationError };
auto cryptoDigestAlgorithm = WebCore::cryptoDigestAlgorithm(hash);
if (!cryptoDigestAlgorithm)
return Exception { OperationError };
auto digest = PAL::CryptoDigest::create(*cryptoDigestAlgorithm);
if (!digest)
return Exception { OperationError };
digest->addBytes(data.data(), data.size());
auto digestData = digest->computeHash();
Vector<uint8_t> signature(8 + keyLengthInBytes * 2);
size_t signatureSize = signature.size();
CCCryptorStatus status = CCECCryptorSignHash(key, digestData.data(), digestData.size(), signature.data(), &signatureSize);
if (status)
return Exception { OperationError };
Vector<uint8_t> newSignature;
newSignature.reserveCapacity(keyLengthInBytes * 2);
size_t offset = 3;
size_t bytesToCopy = keyLengthInBytes;
if (signature[offset] < keyLengthInBytes) {
newSignature.resize(keyLengthInBytes - signature[offset]);
memset(newSignature.data(), InitialOctet, keyLengthInBytes - signature[offset]);
bytesToCopy = signature[offset];
} else if (signature[offset] > keyLengthInBytes) offset += signature[offset] - keyLengthInBytes;
offset++; ASSERT_WITH_SECURITY_IMPLICATION(signature.size() > offset + bytesToCopy);
newSignature.append(signature.data() + offset, bytesToCopy);
offset += bytesToCopy + 1;
bytesToCopy = keyLengthInBytes;
if (signature[offset] < keyLengthInBytes) {
size_t pos = newSignature.size();
newSignature.resize(pos + keyLengthInBytes - signature[offset]);
memset(newSignature.data() + pos, InitialOctet, keyLengthInBytes - signature[offset]);
bytesToCopy = signature[offset];
} else if (signature[offset] > keyLengthInBytes) offset += signature[offset] - keyLengthInBytes;
offset++; ASSERT_WITH_SECURITY_IMPLICATION(signature.size() >= offset + bytesToCopy);
newSignature.append(signature.data() + offset, bytesToCopy);
return WTFMove(newSignature);
}
static ExceptionOr<bool> verifyECDSA(CryptoAlgorithmIdentifier hash, const PlatformECKey key, size_t keyLengthInBytes, const Vector<uint8_t>& signature, const Vector<uint8_t> data)
{
CCDigestAlgorithm digestAlgorithm;
if (!getCommonCryptoDigestAlgorithm(hash, digestAlgorithm))
return Exception { OperationError };
auto cryptoDigestAlgorithm = WebCore::cryptoDigestAlgorithm(hash);
if (!cryptoDigestAlgorithm)
return Exception { OperationError };
auto digest = PAL::CryptoDigest::create(*cryptoDigestAlgorithm);
if (!digest)
return Exception { OperationError };
digest->addBytes(data.data(), data.size());
auto digestData = digest->computeHash();
if (signature.size() != keyLengthInBytes * 2)
return false;
size_t rStart = 0;
while (rStart < keyLengthInBytes && !signature[rStart])
rStart++;
size_t sStart = keyLengthInBytes;
while (rStart < signature.size() && !signature[sStart])
sStart++;
bool rNeedsInitialOctet = signature[rStart] >= 128;
bool sNeedsInitialOctet = signature[sStart] >= 128;
Vector<uint8_t> newSignature;
newSignature.reserveCapacity(6 + keyLengthInBytes * 3 + rNeedsInitialOctet + sNeedsInitialOctet - rStart - sStart);
newSignature.append(SequenceMark);
addEncodedASN1Length(newSignature, 4 + keyLengthInBytes * 3 + rNeedsInitialOctet + sNeedsInitialOctet - rStart - sStart);
newSignature.append(IntegerMark);
addEncodedASN1Length(newSignature, keyLengthInBytes + rNeedsInitialOctet - rStart);
if (rNeedsInitialOctet)
newSignature.append(InitialOctet);
newSignature.append(signature.data() + rStart, keyLengthInBytes - rStart);
newSignature.append(IntegerMark);
addEncodedASN1Length(newSignature, keyLengthInBytes * 2 + sNeedsInitialOctet - sStart);
if (sNeedsInitialOctet)
newSignature.append(InitialOctet);
newSignature.append(signature.data() + sStart, keyLengthInBytes * 2 - sStart);
uint32_t valid;
CCCryptorStatus status = CCECCryptorVerifyHash(key, digestData.data(), digestData.size(), newSignature.data(), newSignature.size(), &valid);
if (status)
return Exception { OperationError };
return valid;
}
void CryptoAlgorithmECDSA::platformSign(std::unique_ptr<CryptoAlgorithmParameters>&& parameters, Ref<CryptoKey>&& key, Vector<uint8_t>&& data, VectorCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext& context, WorkQueue& workQueue)
{
context.ref();
workQueue.dispatch([parameters = WTFMove(parameters), key = WTFMove(key), data = WTFMove(data), callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback), &context]() mutable {
auto& ecKey = downcast<CryptoKeyEC>(key.get());
auto& ecParameters = downcast<CryptoAlgorithmEcdsaParams>(*parameters);
auto result = signECDSA(ecParameters.hashIdentifier, ecKey.platformKey(), ecKey.keySizeInBits() / 8, data);
if (result.hasException()) {
context.postTask([exceptionCallback = WTFMove(exceptionCallback), ec = result.releaseException().code(), callback = WTFMove(callback)](ScriptExecutionContext& context) {
exceptionCallback(ec);
context.deref();
});
return;
}
context.postTask([callback = WTFMove(callback), result = result.releaseReturnValue(), exceptionCallback = WTFMove(exceptionCallback)](ScriptExecutionContext& context) {
callback(result);
context.deref();
});
});
}
void CryptoAlgorithmECDSA::platformVerify(std::unique_ptr<CryptoAlgorithmParameters>&& parameters, Ref<CryptoKey>&& key, Vector<uint8_t>&& signature, Vector<uint8_t>&& data, BoolCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext& context, WorkQueue& workQueue)
{
context.ref();
workQueue.dispatch([parameters = WTFMove(parameters), key = WTFMove(key), signature = WTFMove(signature), data = WTFMove(data), callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback), &context]() mutable {
auto& ecKey = downcast<CryptoKeyEC>(key.get());
auto& ecParameters = downcast<CryptoAlgorithmEcdsaParams>(*parameters);
auto result = verifyECDSA(ecParameters.hashIdentifier, ecKey.platformKey(), ecKey.keySizeInBits() / 8, signature, data);
if (result.hasException()) {
context.postTask([exceptionCallback = WTFMove(exceptionCallback), ec = result.releaseException().code(), callback = WTFMove(callback)](ScriptExecutionContext& context) {
exceptionCallback(ec);
context.deref();
});
return;
}
context.postTask([callback = WTFMove(callback), result = result.releaseReturnValue(), exceptionCallback = WTFMove(exceptionCallback)](ScriptExecutionContext& context) {
callback(result);
context.deref();
});
});
}
}
#endif // ENABLE(SUBTLE_CRYPTO)