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"
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 (sStart < signature.size() && !signature[sStart])
sStart++;
if (rStart >= keyLengthInBytes || sStart >= signature.size())
return false;
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;
}
ExceptionOr<Vector<uint8_t>> CryptoAlgorithmECDSA::platformSign(const CryptoAlgorithmEcdsaParams& parameters, const CryptoKeyEC& key, const Vector<uint8_t>& data)
{
return signECDSA(parameters.hashIdentifier, key.platformKey(), key.keySizeInBits() / 8, data);
}
ExceptionOr<bool> CryptoAlgorithmECDSA::platformVerify(const CryptoAlgorithmEcdsaParams& parameters, const CryptoKeyEC& key, const Vector<uint8_t>& signature, const Vector<uint8_t>& data)
{
return verifyECDSA(parameters.hashIdentifier, key.platformKey(), key.keySizeInBits() / 8, signature, data);
}
}
#endif // ENABLE(SUBTLE_CRYPTO)