1/*
2 * Copyright (C) 2014 Igalia S.L.
3 * Copyright (C) 2016 SoftAtHome
4 * Copyright (C) 2016 Apple Inc.
5 * Copyright (C) 2016 Yusuke Suzuki <utatane.tea@gmail.com>.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 * THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include "config.h"
30#include "CryptoAlgorithmHMAC.h"
31
32#if ENABLE(WEB_CRYPTO)
33
34#include "CryptoKeyHMAC.h"
35#include <pal/crypto/gcrypt/Handle.h>
36#include <wtf/CryptographicUtilities.h>
37
38namespace WebCore {
39
40static int getGCryptDigestAlgorithm(CryptoAlgorithmIdentifier hashFunction)
41{
42 switch (hashFunction) {
43 case CryptoAlgorithmIdentifier::SHA_1:
44 return GCRY_MAC_HMAC_SHA1;
45 case CryptoAlgorithmIdentifier::SHA_224:
46 return GCRY_MAC_HMAC_SHA224;
47 case CryptoAlgorithmIdentifier::SHA_256:
48 return GCRY_MAC_HMAC_SHA256;
49 case CryptoAlgorithmIdentifier::SHA_384:
50 return GCRY_MAC_HMAC_SHA384;
51 case CryptoAlgorithmIdentifier::SHA_512:
52 return GCRY_MAC_HMAC_SHA512;
53 default:
54 return GCRY_MAC_NONE;
55 }
56}
57
58static Optional<Vector<uint8_t>> calculateSignature(int algorithm, const Vector<uint8_t>& key, const uint8_t* data, size_t dataLength)
59{
60 const void* keyData = key.data() ? key.data() : reinterpret_cast<const uint8_t*>("");
61
62 PAL::GCrypt::Handle<gcry_mac_hd_t> hd;
63 gcry_error_t err = gcry_mac_open(&hd, algorithm, 0, nullptr);
64 if (err)
65 return WTF::nullopt;
66
67 err = gcry_mac_setkey(hd, keyData, key.size());
68 if (err)
69 return WTF::nullopt;
70
71 err = gcry_mac_write(hd, data, dataLength);
72 if (err)
73 return WTF::nullopt;
74
75 size_t digestLength = gcry_mac_get_algo_maclen(algorithm);
76 Vector<uint8_t> signature(digestLength);
77 err = gcry_mac_read(hd, signature.data(), &digestLength);
78 if (err)
79 return WTF::nullopt;
80
81 signature.resize(digestLength);
82 return signature;
83}
84
85ExceptionOr<Vector<uint8_t>> CryptoAlgorithmHMAC::platformSign(const CryptoKeyHMAC& key, const Vector<uint8_t>& data)
86{
87 auto algorithm = getGCryptDigestAlgorithm(key.hashAlgorithmIdentifier());
88 if (algorithm == GCRY_MAC_NONE)
89 return Exception { OperationError };
90
91 auto result = calculateSignature(algorithm, key.key(), data.data(), data.size());
92 if (!result)
93 return Exception { OperationError };
94 return WTFMove(*result);
95}
96
97ExceptionOr<bool> CryptoAlgorithmHMAC::platformVerify(const CryptoKeyHMAC& key, const Vector<uint8_t>& signature, const Vector<uint8_t>& data)
98{
99 auto algorithm = getGCryptDigestAlgorithm(key.hashAlgorithmIdentifier());
100 if (algorithm == GCRY_MAC_NONE)
101 return Exception { OperationError };
102
103 auto expectedSignature = calculateSignature(algorithm, key.key(), data.data(), data.size());
104 if (!expectedSignature)
105 return Exception { OperationError };
106 // Using a constant time comparison to prevent timing attacks.
107 return signature.size() == expectedSignature->size() && !constantTimeMemcmp(expectedSignature->data(), signature.data(), expectedSignature->size());
108}
109
110}
111
112#endif // ENABLE(WEB_CRYPTO)
113