Chromium Code Reviews| OLD | NEW | 
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "content/renderer/webcrypto_impl.h" | 5 #include "content/renderer/webcrypto_impl.h" | 
| 6 | 6 | 
| 7 #include <pk11pub.h> | |
| 7 #include <sechash.h> | 8 #include <sechash.h> | 
| 8 | 9 | 
| 9 #include "base/logging.h" | 10 #include "base/logging.h" | 
| 10 #include "crypto/nss_util.h" | 11 #include "crypto/nss_util.h" | 
| 12 #include "crypto/scoped_nss_types.h" | |
| 11 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" | 13 #include "third_party/WebKit/public/platform/WebArrayBuffer.h" | 
| 12 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" | 14 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" | 
| 15 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" | |
| 13 | 16 | 
| 14 namespace content { | 17 namespace content { | 
| 15 | 18 | 
| 19 namespace { | |
| 20 | |
| 21 class SymKeyHandle : public WebKit::WebCryptoKeyHandle { | |
| 22 public: | |
| 23 SymKeyHandle() {} | |
| 24 | |
| 25 void set_key(crypto::ScopedPK11SymKey key) { | |
| 
 
eroman
2013/09/13 00:48:38
This could be an argument to the ctor instead
 
Bryan Eyler
2013/09/13 20:37:36
Done.
 
 | |
| 26 DCHECK(!key_.get()); | |
| 27 key_ = key.Pass(); | |
| 28 } | |
| 29 | |
| 30 PK11SymKey* key() { return key_.get(); } | |
| 31 | |
| 32 private: | |
| 33 crypto::ScopedPK11SymKey key_; | |
| 34 | |
| 35 DISALLOW_COPY_AND_ASSIGN(SymKeyHandle); | |
| 36 }; | |
| 37 | |
| 38 HASH_HashType WebCryptoAlgorithmToNSSHashType( | |
| 39 const WebKit::WebCryptoAlgorithm& algorithm) { | |
| 40 switch (algorithm.id()) { | |
| 41 case WebKit::WebCryptoAlgorithmIdSha1: | |
| 42 return HASH_AlgSHA1; | |
| 43 case WebKit::WebCryptoAlgorithmIdSha224: | |
| 44 return HASH_AlgSHA224; | |
| 45 case WebKit::WebCryptoAlgorithmIdSha256: | |
| 46 return HASH_AlgSHA256; | |
| 47 case WebKit::WebCryptoAlgorithmIdSha384: | |
| 48 return HASH_AlgSHA384; | |
| 49 case WebKit::WebCryptoAlgorithmIdSha512: | |
| 50 return HASH_AlgSHA512; | |
| 51 default: | |
| 52 // Not a digest algorithm. | |
| 53 return HASH_AlgNULL; | |
| 54 } | |
| 55 } | |
| 56 | |
| 57 CK_MECHANISM_TYPE WebCryptoAlgorithmToHMACMechanism( | |
| 58 const WebKit::WebCryptoAlgorithm& algorithm) { | |
| 59 switch (algorithm.id()) { | |
| 60 case WebKit::WebCryptoAlgorithmIdSha1: | |
| 61 return CKM_SHA_1_HMAC; | |
| 62 case WebKit::WebCryptoAlgorithmIdSha256: | |
| 63 return CKM_SHA256_HMAC; | |
| 64 default: | |
| 65 // Not a supported algorithm. | |
| 66 return CKM_INVALID_MECHANISM; | |
| 67 } | |
| 68 } | |
| 69 | |
| 70 } // namespace | |
| 71 | |
| 16 void WebCryptoImpl::Init() { | 72 void WebCryptoImpl::Init() { | 
| 17 crypto::EnsureNSSInit(); | 73 crypto::EnsureNSSInit(); | 
| 18 } | 74 } | 
| 19 | 75 | 
| 20 bool WebCryptoImpl::DigestInternal( | 76 bool WebCryptoImpl::DigestInternal( | 
| 21 const WebKit::WebCryptoAlgorithm& algorithm, | 77 const WebKit::WebCryptoAlgorithm& algorithm, | 
| 22 const unsigned char* data, | 78 const unsigned char* data, | 
| 23 unsigned data_size, | 79 unsigned data_size, | 
| 24 WebKit::WebArrayBuffer* buffer) { | 80 WebKit::WebArrayBuffer* buffer) { | 
| 25 HASH_HashType hash_type = HASH_AlgNULL; | 81 HASH_HashType hash_type = WebCryptoAlgorithmToNSSHashType(algorithm); | 
| 26 | 82 if (hash_type == HASH_AlgNULL) { | 
| 27 switch (algorithm.id()) { | 83 return false; | 
| 28 case WebKit::WebCryptoAlgorithmIdSha1: | |
| 29 hash_type = HASH_AlgSHA1; | |
| 30 break; | |
| 31 case WebKit::WebCryptoAlgorithmIdSha224: | |
| 32 hash_type = HASH_AlgSHA224; | |
| 33 break; | |
| 34 case WebKit::WebCryptoAlgorithmIdSha256: | |
| 35 hash_type = HASH_AlgSHA256; | |
| 36 break; | |
| 37 case WebKit::WebCryptoAlgorithmIdSha384: | |
| 38 hash_type = HASH_AlgSHA384; | |
| 39 break; | |
| 40 case WebKit::WebCryptoAlgorithmIdSha512: | |
| 41 hash_type = HASH_AlgSHA512; | |
| 42 break; | |
| 43 default: | |
| 44 // Not a digest algorithm. | |
| 45 return false; | |
| 46 } | 84 } | 
| 47 | 85 | 
| 48 HASHContext* context = HASH_Create(hash_type); | 86 HASHContext* context = HASH_Create(hash_type); | 
| 49 if (!context) { | 87 if (!context) { | 
| 50 return false; | 88 return false; | 
| 51 } | 89 } | 
| 52 | 90 | 
| 53 HASH_Begin(context); | 91 HASH_Begin(context); | 
| 54 | 92 | 
| 55 HASH_Update(context, data, data_size); | 93 HASH_Update(context, data, data_size); | 
| 56 | 94 | 
| 57 size_t hash_result_length = HASH_ResultLenContext(context); | 95 unsigned hash_result_length = HASH_ResultLenContext(context); | 
| 58 DCHECK_LE(hash_result_length, static_cast<size_t>(HASH_LENGTH_MAX)); | 96 DCHECK_LE(hash_result_length, static_cast<size_t>(HASH_LENGTH_MAX)); | 
| 59 | 97 | 
| 60 *buffer = WebKit::WebArrayBuffer::create(hash_result_length, 1); | 98 *buffer = WebKit::WebArrayBuffer::create(hash_result_length, 1); | 
| 61 | 99 | 
| 62 unsigned char* digest = reinterpret_cast<unsigned char*>(buffer->data()); | 100 unsigned char* digest = reinterpret_cast<unsigned char*>(buffer->data()); | 
| 63 | 101 | 
| 64 uint32 result_length = 0; | 102 unsigned result_length = 0; | 
| 65 HASH_End(context, digest, &result_length, hash_result_length); | 103 HASH_End(context, digest, &result_length, hash_result_length); | 
| 66 | 104 | 
| 67 HASH_Destroy(context); | 105 HASH_Destroy(context); | 
| 68 | 106 | 
| 69 return result_length == hash_result_length; | 107 return result_length == hash_result_length; | 
| 70 } | 108 } | 
| 71 | 109 | 
| 110 bool WebCryptoImpl::ImportKeyInternal( | |
| 111 WebKit::WebCryptoKeyFormat format, | |
| 112 const unsigned char* key_data, | |
| 113 unsigned key_data_size, | |
| 114 const WebKit::WebCryptoAlgorithm& algorithm, | |
| 115 WebKit::WebCryptoKeyUsageMask usage_mask, | |
| 116 scoped_ptr<WebKit::WebCryptoKeyHandle>* handle, | |
| 117 WebKit::WebCryptoKeyType* type) { | |
| 118 switch (algorithm.id()) { | |
| 119 case WebKit::WebCryptoAlgorithmIdHmac: | |
| 120 *type = WebKit::WebCryptoKeyTypeSecret; | |
| 121 break; | |
| 122 // TODO(bryaneyler): Support more key types. | |
| 123 default: | |
| 124 return false; | |
| 125 } | |
| 126 | |
| 127 // TODO(bryaneyler): Need to split handling for symmetric and asymmetric keys. | |
| 128 // Currently only supporting symmetric. | |
| 129 scoped_ptr<SymKeyHandle> sym_key(new SymKeyHandle()); | |
| 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 sym_key->set_key(pk11_sym_key.Pass()); | |
| 180 if (!sym_key->key()) { | |
| 
 
eroman
2013/09/13 00:48:38
I think it would be more readable to do this test
 
Bryan Eyler
2013/09/13 20:37:36
Done.
 
 | |
| 181 NOTREACHED(); | |
| 182 return false; | |
| 183 } | |
| 184 | |
| 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 = | |
| 206 const_cast<SymKeyHandle*>( | |
| 
 
eroman
2013/09/13 00:48:38
no need for the const-cast; just don't add "const"
 
Bryan Eyler
2013/09/13 20:37:36
Done.
 
 | |
| 207 reinterpret_cast<const SymKeyHandle*>(key.handle())); | |
| 208 | |
| 209 DCHECK_EQ(PK11_GetMechanism(sym_key->key()), | |
| 210 WebCryptoAlgorithmToHMACMechanism(params->hash())); | |
| 211 DCHECK_NE(0, key.usages() & WebKit::WebCryptoKeyUsageSign); | |
| 212 | |
| 213 SECItem param_item = { siBuffer, NULL, 0 }; | |
| 214 SECItem data_item = { | |
| 215 siBuffer, | |
| 216 const_cast<unsigned char*>(data), | |
| 217 data_size | |
| 218 }; | |
| 219 // First call is to figure out the length. | |
| 220 SECItem signature_item = { siBuffer, NULL, 0 }; | |
| 221 | |
| 222 if (PK11_SignWithSymKey(sym_key->key(), | |
| 223 PK11_GetMechanism(sym_key->key()), | |
| 224 ¶m_item, | |
| 225 &signature_item, | |
| 226 &data_item) != SECSuccess) { | |
| 227 NOTREACHED(); | |
| 228 return false; | |
| 229 } | |
| 230 | |
| 231 DCHECK_LT(0u, signature_item.len); | |
| 
 
eroman
2013/09/13 00:48:38
This check can never fail: signature_item.len is u
 
Bryan Eyler
2013/09/13 20:37:36
This is DCHECK_LT, not DCHECK_LE.  I'm validating
 
 | |
| 232 | |
| 233 result = WebKit::WebArrayBuffer::create(signature_item.len, 1); | |
| 234 signature_item.data = reinterpret_cast<unsigned char*>(result.data()); | |
| 235 | |
| 236 if (PK11_SignWithSymKey(sym_key->key(), | |
| 237 PK11_GetMechanism(sym_key->key()), | |
| 238 ¶m_item, | |
| 239 &signature_item, | |
| 240 &data_item) != SECSuccess) { | |
| 241 NOTREACHED(); | |
| 242 return false; | |
| 243 } | |
| 244 | |
| 245 DCHECK_EQ(result.byteLength(), signature_item.len); | |
| 246 | |
| 247 break; | |
| 248 } | |
| 249 default: | |
| 250 return false; | |
| 251 } | |
| 252 | |
| 253 *buffer = result; | |
| 254 return true; | |
| 255 } | |
| 256 | |
| 72 } // namespace content | 257 } // namespace content | 
| OLD | NEW |