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 39 namespace WebCore { 40 41 namespace { 42 43 const 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 57 struct KeyUsageMapping { 58 blink::WebCryptoKeyUsage value; 59 const char* const name; 60 }; 61 62 // Keep this array sorted. 63 const 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 73 COMPILE_ASSERT(blink::EndOfWebCryptoKeyUsage == (1 << 6) + 1, update_keyUsageMappings); 74 75 const 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 85 blink::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 94 blink::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 121 bool 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 136 Key::~Key() 137 { 138 } 139 140 Key::Key(const blink::WebCryptoKey& key) 141 : m_key(key) 142 { 143 ScriptWrappable::init(this); 144 } 145 146 String Key::type() const 147 { 148 return keyTypeToString(m_key.type()); 149 } 150 151 bool Key::extractable() const 152 { 153 return m_key.extractable(); 154 } 155 156 Algorithm* 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). 167 Vector<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 178 bool 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 206 bool 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 230 bool 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