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/KeyAlgorithm.h" 37 #include "platform/CryptoResult.h" 38 #include "public/platform/WebCryptoAlgorithmParams.h" 39 #include "public/platform/WebString.h" 40 41 namespace WebCore { 42 43 namespace { 44 45 const char* keyTypeToString(blink::WebCryptoKeyType type) 46 { 47 switch (type) { 48 case blink::WebCryptoKeyTypeSecret: 49 return "secret"; 50 case blink::WebCryptoKeyTypePublic: 51 return "public"; 52 case blink::WebCryptoKeyTypePrivate: 53 return "private"; 54 } 55 ASSERT_NOT_REACHED(); 56 return 0; 57 } 58 59 struct KeyUsageMapping { 60 blink::WebCryptoKeyUsage value; 61 const char* const name; 62 }; 63 64 // The order of this array is the same order that will appear in Key.usages. It 65 // must be kept ordered as described by the Web Crypto spec. 66 const KeyUsageMapping keyUsageMappings[] = { 67 { blink::WebCryptoKeyUsageEncrypt, "encrypt" }, 68 { blink::WebCryptoKeyUsageDecrypt, "decrypt" }, 69 { blink::WebCryptoKeyUsageSign, "sign" }, 70 { blink::WebCryptoKeyUsageVerify, "verify" }, 71 { blink::WebCryptoKeyUsageDeriveKey, "deriveKey" }, 72 { blink::WebCryptoKeyUsageDeriveBits, "deriveBits" }, 73 { blink::WebCryptoKeyUsageWrapKey, "wrapKey" }, 74 { blink::WebCryptoKeyUsageUnwrapKey, "unwrapKey" }, 75 }; 76 77 COMPILE_ASSERT(blink::EndOfWebCryptoKeyUsage == (1 << 7) + 1, update_keyUsageMappings); 78 79 const char* keyUsageToString(blink::WebCryptoKeyUsage usage) 80 { 81 for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyUsageMappings); ++i) { 82 if (keyUsageMappings[i].value == usage) 83 return keyUsageMappings[i].name; 84 } 85 ASSERT_NOT_REACHED(); 86 return 0; 87 } 88 89 blink::WebCryptoKeyUsageMask keyUsageStringToMask(const String& usageString) 90 { 91 for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyUsageMappings); ++i) { 92 if (keyUsageMappings[i].name == usageString) 93 return keyUsageMappings[i].value; 94 } 95 return 0; 96 } 97 98 blink::WebCryptoKeyUsageMask toKeyUsage(blink::WebCryptoOperation operation) 99 { 100 switch (operation) { 101 case blink::WebCryptoOperationEncrypt: 102 return blink::WebCryptoKeyUsageEncrypt; 103 case blink::WebCryptoOperationDecrypt: 104 return blink::WebCryptoKeyUsageDecrypt; 105 case blink::WebCryptoOperationSign: 106 return blink::WebCryptoKeyUsageSign; 107 case blink::WebCryptoOperationVerify: 108 return blink::WebCryptoKeyUsageVerify; 109 case blink::WebCryptoOperationDeriveKey: 110 return blink::WebCryptoKeyUsageDeriveKey; 111 case blink::WebCryptoOperationDeriveBits: 112 return blink::WebCryptoKeyUsageDeriveBits; 113 case blink::WebCryptoOperationWrapKey: 114 return blink::WebCryptoKeyUsageWrapKey; 115 case blink::WebCryptoOperationUnwrapKey: 116 return blink::WebCryptoKeyUsageUnwrapKey; 117 case blink::WebCryptoOperationDigest: 118 case blink::WebCryptoOperationGenerateKey: 119 case blink::WebCryptoOperationImportKey: 120 break; 121 } 122 123 ASSERT_NOT_REACHED(); 124 return 0; 125 } 126 127 } // namespace 128 129 Key::~Key() 130 { 131 } 132 133 Key::Key(const blink::WebCryptoKey& key) 134 : m_key(key) 135 { 136 ScriptWrappable::init(this); 137 } 138 139 String Key::type() const 140 { 141 return keyTypeToString(m_key.type()); 142 } 143 144 bool Key::extractable() const 145 { 146 return m_key.extractable(); 147 } 148 149 KeyAlgorithm* Key::algorithm() 150 { 151 if (!m_algorithm) 152 m_algorithm = KeyAlgorithm::create(m_key.algorithm()); 153 return m_algorithm.get(); 154 } 155 156 // FIXME: This creates a new javascript array each time. What should happen 157 // instead is return the same (immutable) array. (Javascript callers can 158 // distinguish this by doing an == test on the arrays and seeing they are 159 // different). 160 Vector<String> Key::usages() const 161 { 162 Vector<String> result; 163 for (size_t i = 0; i < WTF_ARRAY_LENGTH(keyUsageMappings); ++i) { 164 blink::WebCryptoKeyUsage usage = keyUsageMappings[i].value; 165 if (m_key.usages() & usage) 166 result.append(keyUsageToString(usage)); 167 } 168 return result; 169 } 170 171 bool Key::canBeUsedForAlgorithm(const blink::WebCryptoAlgorithm& algorithm, blink::WebCryptoOperation op, CryptoResult* result) const 172 { 173 if (!(m_key.usages() & toKeyUsage(op))) { 174 result->completeWithError(blink::WebCryptoErrorTypeInvalidAccess, "key.usages does not permit this operation"); 175 return false; 176 } 177 178 if (m_key.algorithm().id() != algorithm.id()) { 179 result->completeWithError(blink::WebCryptoErrorTypeInvalidAccess, "key.algorithm does not match that of operation"); 180 return false; 181 } 182 183 return true; 184 } 185 186 bool Key::parseFormat(const String& formatString, blink::WebCryptoKeyFormat& format, CryptoResult* result) 187 { 188 // There are few enough values that testing serially is fast enough. 189 if (formatString == "raw") { 190 format = blink::WebCryptoKeyFormatRaw; 191 return true; 192 } 193 if (formatString == "pkcs8") { 194 format = blink::WebCryptoKeyFormatPkcs8; 195 return true; 196 } 197 if (formatString == "spki") { 198 format = blink::WebCryptoKeyFormatSpki; 199 return true; 200 } 201 if (formatString == "jwk") { 202 format = blink::WebCryptoKeyFormatJwk; 203 return true; 204 } 205 206 result->completeWithError(blink::WebCryptoErrorTypeSyntax, "Invalid keyFormat argument"); 207 return false; 208 } 209 210 bool Key::parseUsageMask(const Vector<String>& usages, blink::WebCryptoKeyUsageMask& mask, CryptoResult* result) 211 { 212 mask = 0; 213 for (size_t i = 0; i < usages.size(); ++i) { 214 blink::WebCryptoKeyUsageMask usage = keyUsageStringToMask(usages[i]); 215 if (!usage) { 216 result->completeWithError(blink::WebCryptoErrorTypeSyntax, "Invalid keyUsages argument"); 217 return false; 218 } 219 mask |= usage; 220 } 221 return true; 222 } 223 224 void Key::trace(Visitor* visitor) 225 { 226 visitor->trace(m_algorithm); 227 } 228 229 } // namespace WebCore 230