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/SubtleCrypto.h" 33 34 #include "bindings/v8/ExceptionState.h" 35 #include "core/dom/ExceptionCode.h" 36 #include "core/platform/NotImplemented.h" 37 #include "modules/crypto/CryptoOperation.h" 38 #include "modules/crypto/Key.h" 39 #include "modules/crypto/KeyOperation.h" 40 #include "modules/crypto/NormalizeAlgorithm.h" 41 #include "public/platform/Platform.h" 42 #include "public/platform/WebCrypto.h" 43 #include "public/platform/WebCryptoAlgorithmParams.h" 44 #include "wtf/ArrayBufferView.h" 45 46 namespace WebCore { 47 48 // FIXME: Outstanding KeyOperations and CryptoOperations should be aborted when 49 // tearing down SubtleCrypto (to avoid problems completing a 50 // ScriptPromiseResolver which is no longer valid). 51 52 namespace { 53 54 WebKit::WebCryptoKeyUsageMask toKeyUsage(AlgorithmOperation operation) 55 { 56 switch (operation) { 57 case Encrypt: 58 return WebKit::WebCryptoKeyUsageEncrypt; 59 case Decrypt: 60 return WebKit::WebCryptoKeyUsageDecrypt; 61 case Sign: 62 return WebKit::WebCryptoKeyUsageSign; 63 case Verify: 64 return WebKit::WebCryptoKeyUsageVerify; 65 case DeriveKey: 66 return WebKit::WebCryptoKeyUsageDeriveKey; 67 case WrapKey: 68 return WebKit::WebCryptoKeyUsageWrapKey; 69 case UnwrapKey: 70 return WebKit::WebCryptoKeyUsageUnwrapKey; 71 case Digest: 72 case GenerateKey: 73 case ImportKey: 74 case NumberOfAlgorithmOperations: 75 break; 76 } 77 78 ASSERT_NOT_REACHED(); 79 return 0; 80 } 81 82 bool keyCanBeUsedForAlgorithm(const WebKit::WebCryptoKey& key, const WebKit::WebCryptoAlgorithm& algorithm, AlgorithmOperation op) 83 { 84 if (!(key.usages() & toKeyUsage(op))) 85 return false; 86 87 if (key.algorithm().id() != algorithm.id()) 88 return false; 89 90 if (key.algorithm().paramsType() == WebKit::WebCryptoAlgorithmParamsTypeNone) 91 return true; 92 93 // Verify that the algorithm-specific parameters for the key conform to the 94 // algorithm. 95 96 if (key.algorithm().paramsType() == WebKit::WebCryptoAlgorithmParamsTypeHmacParams) { 97 return key.algorithm().hmacParams()->hash().id() == algorithm.hmacParams()->hash().id(); 98 } 99 100 ASSERT_NOT_REACHED(); 101 return false; 102 } 103 104 PassRefPtr<CryptoOperation> createCryptoOperation(const Dictionary& rawAlgorithm, Key* key, AlgorithmOperation operationType, ArrayBufferView* signature, ExceptionState& es) 105 { 106 WebKit::WebCrypto* platformCrypto = WebKit::Platform::current()->crypto(); 107 if (!platformCrypto) { 108 es.throwDOMException(NotSupportedError); 109 return 0; 110 } 111 112 WebKit::WebCryptoAlgorithm algorithm; 113 if (!normalizeAlgorithm(rawAlgorithm, operationType, algorithm, es)) 114 return 0; 115 116 // All operations other than Digest require a valid Key. 117 if (operationType != Digest) { 118 if (!key) { 119 es.throwTypeError(); 120 return 0; 121 } 122 123 if (!keyCanBeUsedForAlgorithm(key->key(), algorithm, operationType)) { 124 es.throwDOMException(NotSupportedError); 125 return 0; 126 } 127 } 128 129 // Only Verify takes a signature. 130 if (operationType == Verify && !signature) { 131 es.throwTypeError(); 132 return 0; 133 } 134 135 RefPtr<CryptoOperationImpl> opImpl = CryptoOperationImpl::create(); 136 WebKit::WebCryptoOperationResult result(opImpl.get()); 137 138 switch (operationType) { 139 case Encrypt: 140 platformCrypto->encrypt(algorithm, key->key(), result); 141 break; 142 case Decrypt: 143 platformCrypto->decrypt(algorithm, key->key(), result); 144 break; 145 case Sign: 146 platformCrypto->sign(algorithm, key->key(), result); 147 break; 148 case Verify: 149 platformCrypto->verifySignature(algorithm, key->key(), reinterpret_cast<const unsigned char*>(signature->baseAddress()), signature->byteLength(), result); 150 break; 151 case Digest: 152 platformCrypto->digest(algorithm, result); 153 break; 154 default: 155 ASSERT_NOT_REACHED(); 156 return 0; 157 } 158 159 if (opImpl->throwInitializationError(es)) 160 return 0; 161 return CryptoOperation::create(algorithm, opImpl.get()); 162 } 163 164 } // namespace 165 166 SubtleCrypto::SubtleCrypto() 167 { 168 ScriptWrappable::init(this); 169 } 170 171 PassRefPtr<CryptoOperation> SubtleCrypto::encrypt(const Dictionary& rawAlgorithm, Key* key, ExceptionState& es) 172 { 173 return createCryptoOperation(rawAlgorithm, key, Encrypt, 0, es); 174 } 175 176 PassRefPtr<CryptoOperation> SubtleCrypto::decrypt(const Dictionary& rawAlgorithm, Key* key, ExceptionState& es) 177 { 178 return createCryptoOperation(rawAlgorithm, key, Decrypt, 0, es); 179 } 180 181 PassRefPtr<CryptoOperation> SubtleCrypto::sign(const Dictionary& rawAlgorithm, Key* key, ExceptionState& es) 182 { 183 return createCryptoOperation(rawAlgorithm, key, Sign, 0, es); 184 } 185 186 PassRefPtr<CryptoOperation> SubtleCrypto::verifySignature(const Dictionary& rawAlgorithm, Key* key, ArrayBufferView* signature, ExceptionState& es) 187 { 188 return createCryptoOperation(rawAlgorithm, key, Verify, signature, es); 189 } 190 191 PassRefPtr<CryptoOperation> SubtleCrypto::digest(const Dictionary& rawAlgorithm, ExceptionState& es) 192 { 193 return createCryptoOperation(rawAlgorithm, 0, Digest, 0, es); 194 } 195 196 ScriptObject SubtleCrypto::generateKey(const Dictionary& rawAlgorithm, bool extractable, const Vector<String>& rawKeyUsages, ExceptionState& es) 197 { 198 WebKit::WebCrypto* platformCrypto = WebKit::Platform::current()->crypto(); 199 if (!platformCrypto) { 200 es.throwDOMException(NotSupportedError); 201 return ScriptObject(); 202 } 203 204 WebKit::WebCryptoKeyUsageMask keyUsages; 205 if (!Key::parseUsageMask(rawKeyUsages, keyUsages)) { 206 es.throwTypeError(); 207 return ScriptObject(); 208 } 209 210 WebKit::WebCryptoAlgorithm algorithm; 211 if (!normalizeAlgorithm(rawAlgorithm, GenerateKey, algorithm, es)) 212 return ScriptObject(); 213 214 RefPtr<KeyOperation> keyOp = KeyOperation::create(); 215 WebKit::WebCryptoKeyOperationResult result(keyOp.get()); 216 platformCrypto->generateKey(algorithm, extractable, keyUsages, result); 217 return keyOp->returnValue(es); 218 } 219 220 ScriptObject SubtleCrypto::importKey(const String& rawFormat, ArrayBufferView* keyData, const Dictionary& rawAlgorithm, bool extractable, const Vector<String>& rawKeyUsages, ExceptionState& es) 221 { 222 WebKit::WebCrypto* platformCrypto = WebKit::Platform::current()->crypto(); 223 if (!platformCrypto) { 224 es.throwDOMException(NotSupportedError); 225 return ScriptObject(); 226 } 227 228 if (!keyData) { 229 es.throwTypeError(); 230 return ScriptObject(); 231 } 232 233 WebKit::WebCryptoKeyUsageMask keyUsages; 234 if (!Key::parseUsageMask(rawKeyUsages, keyUsages)) { 235 es.throwTypeError(); 236 return ScriptObject(); 237 } 238 239 WebKit::WebCryptoKeyFormat format; 240 if (!Key::parseFormat(rawFormat, format)) { 241 es.throwTypeError(); 242 return ScriptObject(); 243 } 244 245 WebKit::WebCryptoAlgorithm algorithm; 246 if (!normalizeAlgorithm(rawAlgorithm, ImportKey, algorithm, es)) 247 return ScriptObject(); 248 249 const unsigned char* keyDataBytes = static_cast<unsigned char*>(keyData->baseAddress()); 250 251 RefPtr<KeyOperation> keyOp = KeyOperation::create(); 252 WebKit::WebCryptoKeyOperationResult result(keyOp.get()); 253 platformCrypto->importKey(format, keyDataBytes, keyData->byteLength(), algorithm, extractable, keyUsages, result); 254 return keyOp->returnValue(es); 255 } 256 257 } // namespace WebCore 258