1/*
2 * Copyright (C) 2013 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "CryptoKeyHMAC.h"
28
29#if ENABLE(WEB_CRYPTO)
30
31#include "CryptoAlgorithmHmacKeyParams.h"
32#include "CryptoAlgorithmRegistry.h"
33#include "ExceptionOr.h"
34#include "JsonWebKey.h"
35#include <wtf/text/Base64.h>
36#include <wtf/text/WTFString.h>
37
38namespace WebCore {
39
40static size_t getKeyLengthFromHash(CryptoAlgorithmIdentifier hash)
41{
42 switch (hash) {
43 case CryptoAlgorithmIdentifier::SHA_1:
44 case CryptoAlgorithmIdentifier::SHA_224:
45 case CryptoAlgorithmIdentifier::SHA_256:
46 return 512;
47 case CryptoAlgorithmIdentifier::SHA_384:
48 case CryptoAlgorithmIdentifier::SHA_512:
49 return 1024;
50 default:
51 ASSERT_NOT_REACHED();
52 return 0;
53 }
54}
55
56CryptoKeyHMAC::CryptoKeyHMAC(const Vector<uint8_t>& key, CryptoAlgorithmIdentifier hash, bool extractable, CryptoKeyUsageBitmap usage)
57 : CryptoKey(CryptoAlgorithmIdentifier::HMAC, CryptoKeyType::Secret, extractable, usage)
58 , m_hash(hash)
59 , m_key(key)
60{
61}
62
63CryptoKeyHMAC::CryptoKeyHMAC(Vector<uint8_t>&& key, CryptoAlgorithmIdentifier hash, bool extractable, CryptoKeyUsageBitmap usage)
64 : CryptoKey(CryptoAlgorithmIdentifier::HMAC, CryptoKeyType::Secret, extractable, usage)
65 , m_hash(hash)
66 , m_key(WTFMove(key))
67{
68}
69
70CryptoKeyHMAC::~CryptoKeyHMAC() = default;
71
72RefPtr<CryptoKeyHMAC> CryptoKeyHMAC::generate(size_t lengthBits, CryptoAlgorithmIdentifier hash, bool extractable, CryptoKeyUsageBitmap usages)
73{
74 if (!lengthBits) {
75 lengthBits = getKeyLengthFromHash(hash);
76 if (!lengthBits)
77 return nullptr;
78 }
79 // CommonHMAC only supports key length that is a multiple of 8. Therefore, here we are a little bit different
80 // from the spec as of 11 December 2014: https://www.w3.org/TR/WebCryptoAPI/#hmac-operations
81 if (lengthBits % 8)
82 return nullptr;
83
84 return adoptRef(new CryptoKeyHMAC(randomData(lengthBits / 8), hash, extractable, usages));
85}
86
87RefPtr<CryptoKeyHMAC> CryptoKeyHMAC::importRaw(size_t lengthBits, CryptoAlgorithmIdentifier hash, Vector<uint8_t>&& keyData, bool extractable, CryptoKeyUsageBitmap usages)
88{
89 size_t length = keyData.size() * 8;
90 if (!length)
91 return nullptr;
92 // CommonHMAC only supports key length that is a multiple of 8. Therefore, here we are a little bit different
93 // from the spec as of 11 December 2014: https://www.w3.org/TR/WebCryptoAPI/#hmac-operations
94 if (lengthBits && lengthBits != length)
95 return nullptr;
96
97 return adoptRef(new CryptoKeyHMAC(WTFMove(keyData), hash, extractable, usages));
98}
99
100RefPtr<CryptoKeyHMAC> CryptoKeyHMAC::importJwk(size_t lengthBits, CryptoAlgorithmIdentifier hash, JsonWebKey&& keyData, bool extractable, CryptoKeyUsageBitmap usages, CheckAlgCallback&& callback)
101{
102 if (keyData.kty != "oct")
103 return nullptr;
104 if (keyData.k.isNull())
105 return nullptr;
106 Vector<uint8_t> octetSequence;
107 if (!base64URLDecode(keyData.k, octetSequence))
108 return nullptr;
109 if (!callback(hash, keyData.alg))
110 return nullptr;
111 if (usages && !keyData.use.isNull() && keyData.use != "sig")
112 return nullptr;
113 if (keyData.key_ops && ((keyData.usages & usages) != usages))
114 return nullptr;
115 if (keyData.ext && !keyData.ext.value() && extractable)
116 return nullptr;
117
118 return CryptoKeyHMAC::importRaw(lengthBits, hash, WTFMove(octetSequence), extractable, usages);
119}
120
121JsonWebKey CryptoKeyHMAC::exportJwk() const
122{
123 JsonWebKey result;
124 result.kty = "oct";
125 result.k = base64URLEncode(m_key);
126 result.key_ops = usages();
127 result.ext = extractable();
128 return result;
129}
130
131ExceptionOr<size_t> CryptoKeyHMAC::getKeyLength(const CryptoAlgorithmParameters& parameters)
132{
133 auto& aesParameters = downcast<CryptoAlgorithmHmacKeyParams>(parameters);
134
135 size_t result = aesParameters.length ? *(aesParameters.length) : getKeyLengthFromHash(aesParameters.hashIdentifier);
136 if (result)
137 return result;
138
139 return Exception { TypeError };
140}
141
142auto CryptoKeyHMAC::algorithm() const -> KeyAlgorithm
143{
144 CryptoHmacKeyAlgorithm result;
145 result.name = CryptoAlgorithmRegistry::singleton().name(algorithmIdentifier());
146 result.hash.name = CryptoAlgorithmRegistry::singleton().name(m_hash);
147 result.length = m_key.size() * 8;
148 return result;
149}
150
151} // namespace WebCore
152
153#endif // ENABLE(WEB_CRYPTO)
154