1/* 2 * Copyright (C) 2013 Google 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 are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "config.h" 32#include "modules/crypto/Key.h" 33 34#include "bindings/v8/ExceptionState.h" 35#include "core/dom/ExceptionCode.h" 36#include "modules/crypto/Algorithm.h" 37#include "public/platform/WebCryptoAlgorithmParams.h" 38 39namespace WebCore { 40 41namespace { 42 43const char* keyTypeToString(blink::WebCryptoKeyType type) 44{ 45 switch (type) { 46 case blink::WebCryptoKeyTypeSecret: 47 return "secret"; 48 case blink::WebCryptoKeyTypePublic: 49 return "public"; 50 case blink::WebCryptoKeyTypePrivate: 51 return "private"; 52 } 53 ASSERT_NOT_REACHED(); 54 return 0; 55} 56 57struct KeyUsageMapping { 58 blink::WebCryptoKeyUsage value; 59 const char* const name; 60}; 61 62// Keep this array sorted. 63const KeyUsageMapping keyUsageMappings[] = { 64 { blink::WebCryptoKeyUsageDecrypt, "decrypt" }, 65 { blink::WebCryptoKeyUsageDeriveKey, "deriveKey" }, 66 { blink::WebCryptoKeyUsageEncrypt, "encrypt" }, 67 { blink::WebCryptoKeyUsageSign, "sign" }, 68 { blink::WebCryptoKeyUsageUnwrapKey, "unwrapKey" }, 69 { blink::WebCryptoKeyUsageVerify, "verify" }, 70 { blink::WebCryptoKeyUsageWrapKey, "wrapKey" }, 71}; 72 73COMPILE_ASSERT(blink::EndOfWebCryptoKeyUsage == (1 << 6) + 1, update_keyUsageMappings); 74 75const char* keyUsageToString(blink::WebCryptoKeyUsage usage) 76{ 77 for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyUsageMappings); ++i) { 78 if (keyUsageMappings[i].value == usage) 79 return keyUsageMappings[i].name; 80 } 81 ASSERT_NOT_REACHED(); 82 return 0; 83} 84 85blink::WebCryptoKeyUsageMask keyUsageStringToMask(const String& usageString) 86{ 87 for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyUsageMappings); ++i) { 88 if (keyUsageMappings[i].name == usageString) 89 return keyUsageMappings[i].value; 90 } 91 return 0; 92} 93 94blink::WebCryptoKeyUsageMask toKeyUsage(AlgorithmOperation operation) 95{ 96 switch (operation) { 97 case Encrypt: 98 return blink::WebCryptoKeyUsageEncrypt; 99 case Decrypt: 100 return blink::WebCryptoKeyUsageDecrypt; 101 case Sign: 102 return blink::WebCryptoKeyUsageSign; 103 case Verify: 104 return blink::WebCryptoKeyUsageVerify; 105 case DeriveKey: 106 return blink::WebCryptoKeyUsageDeriveKey; 107 case WrapKey: 108 return blink::WebCryptoKeyUsageWrapKey; 109 case UnwrapKey: 110 return blink::WebCryptoKeyUsageUnwrapKey; 111 case Digest: 112 case GenerateKey: 113 case ImportKey: 114 break; 115 } 116 117 ASSERT_NOT_REACHED(); 118 return 0; 119} 120 121bool getHmacHashId(const blink::WebCryptoAlgorithm& algorithm, blink::WebCryptoAlgorithmId& hashId) 122{ 123 if (algorithm.hmacParams()) { 124 hashId = algorithm.hmacParams()->hash().id(); 125 return true; 126 } 127 if (algorithm.hmacKeyParams()) { 128 hashId = algorithm.hmacKeyParams()->hash().id(); 129 return true; 130 } 131 return false; 132} 133 134} // namespace 135 136Key::~Key() 137{ 138} 139 140Key::Key(const blink::WebCryptoKey& key) 141 : m_key(key) 142{ 143 ScriptWrappable::init(this); 144} 145 146String Key::type() const 147{ 148 return keyTypeToString(m_key.type()); 149} 150 151bool Key::extractable() const 152{ 153 return m_key.extractable(); 154} 155 156Algorithm* Key::algorithm() 157{ 158 if (!m_algorithm) 159 m_algorithm = Algorithm::create(m_key.algorithm()); 160 return m_algorithm.get(); 161} 162 163// FIXME: This creates a new javascript array each time. What should happen 164// instead is return the same (immutable) array. (Javascript callers can 165// distinguish this by doing an == test on the arrays and seeing they are 166// different). 167Vector<String> Key::usages() const 168{ 169 Vector<String> result; 170 for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyUsageMappings); ++i) { 171 blink::WebCryptoKeyUsage usage = keyUsageMappings[i].value; 172 if (m_key.usages() & usage) 173 result.append(keyUsageToString(usage)); 174 } 175 return result; 176} 177 178bool Key::canBeUsedForAlgorithm(const blink::WebCryptoAlgorithm& algorithm, AlgorithmOperation op, ExceptionState& exceptionState) const 179{ 180 if (!(m_key.usages() & toKeyUsage(op))) { 181 exceptionState.throwDOMException(NotSupportedError, "key.usages does not permit this operation"); 182 return false; 183 } 184 185 if (m_key.algorithm().id() != algorithm.id()) { 186 exceptionState.throwDOMException(NotSupportedError, "key.algorithm does not match that of operation"); 187 return false; 188 } 189 190 // Verify that the algorithm-specific parameters for the key conform to the 191 // algorithm. 192 // FIXME: Verify that this is complete. 193 194 if (m_key.algorithm().id() == blink::WebCryptoAlgorithmIdHmac) { 195 blink::WebCryptoAlgorithmId keyHash; 196 blink::WebCryptoAlgorithmId algorithmHash; 197 if (!getHmacHashId(m_key.algorithm(), keyHash) || !getHmacHashId(algorithm, algorithmHash) || keyHash != algorithmHash) { 198 exceptionState.throwDOMException(NotSupportedError, "key.algorithm does not match that of operation (HMAC's hash differs)"); 199 return false; 200 } 201 } 202 203 return true; 204} 205 206bool Key::parseFormat(const String& formatString, blink::WebCryptoKeyFormat& format, ExceptionState& exceptionState) 207{ 208 // There are few enough values that testing serially is fast enough. 209 if (formatString == "raw") { 210 format = blink::WebCryptoKeyFormatRaw; 211 return true; 212 } 213 if (formatString == "pkcs8") { 214 format = blink::WebCryptoKeyFormatPkcs8; 215 return true; 216 } 217 if (formatString == "spki") { 218 format = blink::WebCryptoKeyFormatSpki; 219 return true; 220 } 221 if (formatString == "jwk") { 222 format = blink::WebCryptoKeyFormatJwk; 223 return true; 224 } 225 226 exceptionState.throwTypeError("Invalid keyFormat argument"); 227 return false; 228} 229 230bool Key::parseUsageMask(const Vector<String>& usages, blink::WebCryptoKeyUsageMask& mask, ExceptionState& exceptionState) 231{ 232 mask = 0; 233 for (size_t i = 0; i < usages.size(); ++i) { 234 blink::WebCryptoKeyUsageMask usage = keyUsageStringToMask(usages[i]); 235 if (!usage) { 236 exceptionState.throwTypeError("Invalid keyUsages argument"); 237 return false; 238 } 239 mask |= usage; 240 } 241 return true; 242} 243 244} // namespace WebCore 245