Roll src/third_party/WebKit f36d5e0:68b67cd (svn 193299:193303)
[chromium-blink-merge.git] / content / child / webcrypto / nss / sha_nss.cc
blob78a2ea041140765cc4a7c66575545690383f2340
1 // Copyright 2014 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.
5 #include <sechash.h>
6 #include <vector>
8 #include "base/stl_util.h"
9 #include "content/child/webcrypto/algorithm_implementation.h"
10 #include "content/child/webcrypto/crypto_data.h"
11 #include "content/child/webcrypto/nss/util_nss.h"
12 #include "content/child/webcrypto/status.h"
13 #include "content/child/webcrypto/webcrypto_util.h"
14 #include "crypto/nss_util.h"
15 #include "crypto/scoped_nss_types.h"
17 namespace content {
19 namespace webcrypto {
21 namespace {
23 HASH_HashType WebCryptoAlgorithmToNSSHashType(
24 blink::WebCryptoAlgorithmId algorithm) {
25 switch (algorithm) {
26 case blink::WebCryptoAlgorithmIdSha1:
27 return HASH_AlgSHA1;
28 case blink::WebCryptoAlgorithmIdSha256:
29 return HASH_AlgSHA256;
30 case blink::WebCryptoAlgorithmIdSha384:
31 return HASH_AlgSHA384;
32 case blink::WebCryptoAlgorithmIdSha512:
33 return HASH_AlgSHA512;
34 default:
35 // Not a digest algorithm.
36 return HASH_AlgNULL;
40 // Implementation of blink::WebCryptoDigester, an internal Blink detail not
41 // part of WebCrypto, that allows chunks of data to be streamed in before
42 // computing a SHA-* digest (as opposed to ShaImplementation, which computes
43 // digests over complete messages)
44 class DigestorNSS : public blink::WebCryptoDigestor {
45 public:
46 explicit DigestorNSS(blink::WebCryptoAlgorithmId algorithm_id)
47 : hash_context_(NULL), algorithm_id_(algorithm_id) {}
49 ~DigestorNSS() override {
50 if (!hash_context_)
51 return;
53 HASH_Destroy(hash_context_);
54 hash_context_ = NULL;
57 bool consume(const unsigned char* data, unsigned int size) override {
58 return ConsumeWithStatus(data, size).IsSuccess();
61 Status ConsumeWithStatus(const unsigned char* data, unsigned int size) {
62 // Initialize everything if the object hasn't been initialized yet.
63 if (!hash_context_) {
64 Status error = Init();
65 if (!error.IsSuccess())
66 return error;
69 HASH_Update(hash_context_, data, size);
71 return Status::Success();
74 bool finish(unsigned char*& result_data,
75 unsigned int& result_data_size) override {
76 Status error = FinishInternal(result_, &result_data_size);
77 if (!error.IsSuccess())
78 return false;
79 result_data = result_;
80 return true;
83 Status FinishWithVectorAndStatus(std::vector<uint8_t>* result) {
84 if (!hash_context_)
85 return Status::ErrorUnexpected();
87 unsigned int result_length = HASH_ResultLenContext(hash_context_);
88 result->resize(result_length);
89 unsigned char* digest = vector_as_array(result);
90 unsigned int digest_size; // ignored
91 return FinishInternal(digest, &digest_size);
94 private:
95 Status Init() {
96 HASH_HashType hash_type = WebCryptoAlgorithmToNSSHashType(algorithm_id_);
98 if (hash_type == HASH_AlgNULL)
99 return Status::ErrorUnsupported();
101 hash_context_ = HASH_Create(hash_type);
102 if (!hash_context_)
103 return Status::OperationError();
105 HASH_Begin(hash_context_);
107 return Status::Success();
110 Status FinishInternal(unsigned char* result, unsigned int* result_size) {
111 if (!hash_context_) {
112 Status error = Init();
113 if (!error.IsSuccess())
114 return error;
117 unsigned int hash_result_length = HASH_ResultLenContext(hash_context_);
118 DCHECK_LE(hash_result_length, static_cast<size_t>(HASH_LENGTH_MAX));
120 HASH_End(hash_context_, result, result_size, hash_result_length);
122 if (*result_size != hash_result_length)
123 return Status::ErrorUnexpected();
124 return Status::Success();
127 HASHContext* hash_context_;
128 blink::WebCryptoAlgorithmId algorithm_id_;
129 unsigned char result_[HASH_LENGTH_MAX];
132 class ShaImplementation : public AlgorithmImplementation {
133 public:
134 Status Digest(const blink::WebCryptoAlgorithm& algorithm,
135 const CryptoData& data,
136 std::vector<uint8_t>* buffer) const override {
137 DigestorNSS digestor(algorithm.id());
138 Status error = digestor.ConsumeWithStatus(data.bytes(), data.byte_length());
139 // http://crbug.com/366427: the spec does not define any other failures for
140 // digest, so none of the subsequent errors are spec compliant.
141 if (!error.IsSuccess())
142 return error;
143 return digestor.FinishWithVectorAndStatus(buffer);
147 } // namespace
149 AlgorithmImplementation* CreatePlatformShaImplementation() {
150 return new ShaImplementation();
153 scoped_ptr<blink::WebCryptoDigestor> CreatePlatformDigestor(
154 blink::WebCryptoAlgorithmId algorithm) {
155 return scoped_ptr<blink::WebCryptoDigestor>(new DigestorNSS(algorithm));
158 } // namespace webcrypto
160 } // namespace content