| OLD | NEW |
| (Empty) |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "content/renderer/webcrypto_impl.h" | |
| 6 | |
| 7 #include <pk11pub.h> | |
| 8 #include <sechash.h> | |
| 9 | |
| 10 #include <vector> | |
| 11 | |
| 12 #include "base/logging.h" | |
| 13 #include "crypto/nss_util.h" | |
| 14 #include "crypto/scoped_nss_types.h" | |
| 15 #include "crypto/secure_util.h" | |
| 16 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" | |
| 17 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" | |
| 18 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" | |
| 19 | |
| 20 namespace content { | |
| 21 | |
| 22 namespace { | |
| 23 | |
| 24 class SymKeyHandle : public WebKit::WebCryptoKeyHandle { | |
| 25 public: | |
| 26 explicit SymKeyHandle(crypto::ScopedPK11SymKey key) { | |
| 27 DCHECK(!key_.get()); | |
| 28 key_ = key.Pass(); | |
| 29 } | |
| 30 | |
| 31 PK11SymKey* key() { return key_.get(); } | |
| 32 | |
| 33 private: | |
| 34 crypto::ScopedPK11SymKey key_; | |
| 35 | |
| 36 DISALLOW_COPY_AND_ASSIGN(SymKeyHandle); | |
| 37 }; | |
| 38 | |
| 39 HASH_HashType WebCryptoAlgorithmToNSSHashType( | |
| 40 const WebKit::WebCryptoAlgorithm& algorithm) { | |
| 41 switch (algorithm.id()) { | |
| 42 case WebKit::WebCryptoAlgorithmIdSha1: | |
| 43 return HASH_AlgSHA1; | |
| 44 case WebKit::WebCryptoAlgorithmIdSha224: | |
| 45 return HASH_AlgSHA224; | |
| 46 case WebKit::WebCryptoAlgorithmIdSha256: | |
| 47 return HASH_AlgSHA256; | |
| 48 case WebKit::WebCryptoAlgorithmIdSha384: | |
| 49 return HASH_AlgSHA384; | |
| 50 case WebKit::WebCryptoAlgorithmIdSha512: | |
| 51 return HASH_AlgSHA512; | |
| 52 default: | |
| 53 // Not a digest algorithm. | |
| 54 return HASH_AlgNULL; | |
| 55 } | |
| 56 } | |
| 57 | |
| 58 CK_MECHANISM_TYPE WebCryptoAlgorithmToHMACMechanism( | |
| 59 const WebKit::WebCryptoAlgorithm& algorithm) { | |
| 60 switch (algorithm.id()) { | |
| 61 case WebKit::WebCryptoAlgorithmIdSha1: | |
| 62 return CKM_SHA_1_HMAC; | |
| 63 case WebKit::WebCryptoAlgorithmIdSha256: | |
| 64 return CKM_SHA256_HMAC; | |
| 65 default: | |
| 66 // Not a supported algorithm. | |
| 67 return CKM_INVALID_MECHANISM; | |
| 68 } | |
| 69 } | |
| 70 | |
| 71 } // namespace | |
| 72 | |
| 73 void WebCryptoImpl::Init() { | |
| 74 crypto::EnsureNSSInit(); | |
| 75 } | |
| 76 | |
| 77 bool WebCryptoImpl::DigestInternal( | |
| 78 const WebKit::WebCryptoAlgorithm& algorithm, | |
| 79 const unsigned char* data, | |
| 80 unsigned data_size, | |
| 81 WebKit::WebArrayBuffer* buffer) { | |
| 82 HASH_HashType hash_type = WebCryptoAlgorithmToNSSHashType(algorithm); | |
| 83 if (hash_type == HASH_AlgNULL) { | |
| 84 return false; | |
| 85 } | |
| 86 | |
| 87 HASHContext* context = HASH_Create(hash_type); | |
| 88 if (!context) { | |
| 89 return false; | |
| 90 } | |
| 91 | |
| 92 HASH_Begin(context); | |
| 93 | |
| 94 HASH_Update(context, data, data_size); | |
| 95 | |
| 96 unsigned hash_result_length = HASH_ResultLenContext(context); | |
| 97 DCHECK_LE(hash_result_length, static_cast<size_t>(HASH_LENGTH_MAX)); | |
| 98 | |
| 99 *buffer = WebKit::WebArrayBuffer::create(hash_result_length, 1); | |
| 100 | |
| 101 unsigned char* digest = reinterpret_cast<unsigned char*>(buffer->data()); | |
| 102 | |
| 103 unsigned result_length = 0; | |
| 104 HASH_End(context, digest, &result_length, hash_result_length); | |
| 105 | |
| 106 HASH_Destroy(context); | |
| 107 | |
| 108 return result_length == hash_result_length; | |
| 109 } | |
| 110 | |
| 111 bool WebCryptoImpl::ImportKeyInternal( | |
| 112 WebKit::WebCryptoKeyFormat format, | |
| 113 const unsigned char* key_data, | |
| 114 unsigned key_data_size, | |
| 115 const WebKit::WebCryptoAlgorithm& algorithm, | |
| 116 WebKit::WebCryptoKeyUsageMask usage_mask, | |
| 117 scoped_ptr<WebKit::WebCryptoKeyHandle>* handle, | |
| 118 WebKit::WebCryptoKeyType* type) { | |
| 119 switch (algorithm.id()) { | |
| 120 case WebKit::WebCryptoAlgorithmIdHmac: | |
| 121 *type = WebKit::WebCryptoKeyTypeSecret; | |
| 122 break; | |
| 123 // TODO(bryaneyler): Support more key types. | |
| 124 default: | |
| 125 return false; | |
| 126 } | |
| 127 | |
| 128 // TODO(bryaneyler): Need to split handling for symmetric and asymmetric keys. | |
| 129 // Currently only supporting symmetric. | |
| 130 CK_MECHANISM_TYPE mechanism = CKM_INVALID_MECHANISM; | |
| 131 // Flags are verified at the Blink layer; here the flags are set to all | |
| 132 // possible operations for this key type. | |
| 133 CK_FLAGS flags = 0; | |
| 134 | |
| 135 switch(algorithm.id()) { | |
| 136 case WebKit::WebCryptoAlgorithmIdHmac: { | |
| 137 const WebKit::WebCryptoHmacParams* params = algorithm.hmacParams(); | |
| 138 if (!params) { | |
| 139 return false; | |
| 140 } | |
| 141 | |
| 142 mechanism = WebCryptoAlgorithmToHMACMechanism(params->hash()); | |
| 143 if (mechanism == CKM_INVALID_MECHANISM) { | |
| 144 return false; | |
| 145 } | |
| 146 | |
| 147 flags |= CKF_SIGN | CKF_VERIFY; | |
| 148 | |
| 149 break; | |
| 150 } | |
| 151 default: | |
| 152 return false; | |
| 153 } | |
| 154 | |
| 155 DCHECK_NE(CKM_INVALID_MECHANISM, mechanism); | |
| 156 DCHECK_NE(0ul, flags); | |
| 157 | |
| 158 SECItem key_item = { siBuffer, NULL, 0 }; | |
| 159 | |
| 160 switch (format) { | |
| 161 case WebKit::WebCryptoKeyFormatRaw: | |
| 162 key_item.data = const_cast<unsigned char*>(key_data); | |
| 163 key_item.len = key_data_size; | |
| 164 break; | |
| 165 // TODO(bryaneyler): Handle additional formats. | |
| 166 default: | |
| 167 return false; | |
| 168 } | |
| 169 | |
| 170 crypto::ScopedPK11SymKey pk11_sym_key( | |
| 171 PK11_ImportSymKeyWithFlags(PK11_GetInternalSlot(), | |
| 172 mechanism, | |
| 173 PK11_OriginUnwrap, | |
| 174 CKA_FLAGS_ONLY, | |
| 175 &key_item, | |
| 176 flags, | |
| 177 false, | |
| 178 NULL)); | |
| 179 if (!pk11_sym_key.get()) { | |
| 180 NOTREACHED(); | |
| 181 return false; | |
| 182 } | |
| 183 | |
| 184 scoped_ptr<SymKeyHandle> sym_key(new SymKeyHandle(pk11_sym_key.Pass())); | |
| 185 *handle = sym_key.Pass(); | |
| 186 | |
| 187 return true; | |
| 188 } | |
| 189 | |
| 190 bool WebCryptoImpl::SignInternal( | |
| 191 const WebKit::WebCryptoAlgorithm& algorithm, | |
| 192 const WebKit::WebCryptoKey& key, | |
| 193 const unsigned char* data, | |
| 194 unsigned data_size, | |
| 195 WebKit::WebArrayBuffer* buffer) { | |
| 196 WebKit::WebArrayBuffer result; | |
| 197 | |
| 198 switch (algorithm.id()) { | |
| 199 case WebKit::WebCryptoAlgorithmIdHmac: { | |
| 200 const WebKit::WebCryptoHmacParams* params = algorithm.hmacParams(); | |
| 201 if (!params) { | |
| 202 return false; | |
| 203 } | |
| 204 | |
| 205 SymKeyHandle* sym_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | |
| 206 | |
| 207 DCHECK_EQ(PK11_GetMechanism(sym_key->key()), | |
| 208 WebCryptoAlgorithmToHMACMechanism(params->hash())); | |
| 209 DCHECK_NE(0, key.usages() & WebKit::WebCryptoKeyUsageSign); | |
| 210 | |
| 211 SECItem param_item = { siBuffer, NULL, 0 }; | |
| 212 SECItem data_item = { | |
| 213 siBuffer, | |
| 214 const_cast<unsigned char*>(data), | |
| 215 data_size | |
| 216 }; | |
| 217 // First call is to figure out the length. | |
| 218 SECItem signature_item = { siBuffer, NULL, 0 }; | |
| 219 | |
| 220 if (PK11_SignWithSymKey(sym_key->key(), | |
| 221 PK11_GetMechanism(sym_key->key()), | |
| 222 ¶m_item, | |
| 223 &signature_item, | |
| 224 &data_item) != SECSuccess) { | |
| 225 NOTREACHED(); | |
| 226 return false; | |
| 227 } | |
| 228 | |
| 229 DCHECK_NE(0u, signature_item.len); | |
| 230 | |
| 231 result = WebKit::WebArrayBuffer::create(signature_item.len, 1); | |
| 232 signature_item.data = reinterpret_cast<unsigned char*>(result.data()); | |
| 233 | |
| 234 if (PK11_SignWithSymKey(sym_key->key(), | |
| 235 PK11_GetMechanism(sym_key->key()), | |
| 236 ¶m_item, | |
| 237 &signature_item, | |
| 238 &data_item) != SECSuccess) { | |
| 239 NOTREACHED(); | |
| 240 return false; | |
| 241 } | |
| 242 | |
| 243 DCHECK_EQ(result.byteLength(), signature_item.len); | |
| 244 | |
| 245 break; | |
| 246 } | |
| 247 default: | |
| 248 return false; | |
| 249 } | |
| 250 | |
| 251 *buffer = result; | |
| 252 return true; | |
| 253 } | |
| 254 | |
| 255 bool WebCryptoImpl::VerifySignatureInternal( | |
| 256 const WebKit::WebCryptoAlgorithm& algorithm, | |
| 257 const WebKit::WebCryptoKey& key, | |
| 258 const unsigned char* signature, | |
| 259 unsigned signature_size, | |
| 260 const unsigned char* data, | |
| 261 unsigned data_size, | |
| 262 bool* signature_match) { | |
| 263 switch (algorithm.id()) { | |
| 264 case WebKit::WebCryptoAlgorithmIdHmac: { | |
| 265 WebKit::WebArrayBuffer result; | |
| 266 if (!SignInternal(algorithm, key, data, data_size, &result)) { | |
| 267 return false; | |
| 268 } | |
| 269 | |
| 270 // Handling of truncated signatures is underspecified in the WebCrypto | |
| 271 // spec, so here we fail verification if a truncated signature is being | |
| 272 // verified. | |
| 273 // See https://www.w3.org/Bugs/Public/show_bug.cgi?id=23097 | |
| 274 *signature_match = | |
| 275 result.byteLength() == signature_size && | |
| 276 crypto::SecureMemEqual(result.data(), signature, signature_size); | |
| 277 | |
| 278 break; | |
| 279 } | |
| 280 default: | |
| 281 return false; | |
| 282 } | |
| 283 | |
| 284 return true; | |
| 285 } | |
| 286 | |
| 287 } // namespace content | |
| OLD | NEW |