Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / child / webcrypto / openssl / sha_openssl.cc
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.
4
5 #include <vector>
6 #include <openssl/evp.h>
7 #include <openssl/sha.h>
8
9 #include "base/logging.h"
10 #include "base/stl_util.h"
11 #include "content/child/webcrypto/algorithm_implementation.h"
12 #include "content/child/webcrypto/crypto_data.h"
13 #include "content/child/webcrypto/openssl/util_openssl.h"
14 #include "content/child/webcrypto/status.h"
15 #include "content/child/webcrypto/webcrypto_util.h"
16 #include "crypto/openssl_util.h"
17 #include "crypto/scoped_openssl_types.h"
18
19 namespace content {
20
21 namespace webcrypto {
22
23 namespace {
24
25 // Implementation of blink::WebCryptoDigester, an internal Blink detail not
26 // part of WebCrypto, that allows chunks of data to be streamed in before
27 // computing a SHA-* digest (as opposed to ShaImplementation, which computes
28 // digests over complete messages)
29 class DigestorOpenSsl : public blink::WebCryptoDigestor {
30  public:
31   explicit DigestorOpenSsl(blink::WebCryptoAlgorithmId algorithm_id)
32       : initialized_(false),
33         digest_context_(EVP_MD_CTX_create()),
34         algorithm_id_(algorithm_id) {}
35
36   bool consume(const unsigned char* data, unsigned int size) override {
37     return ConsumeWithStatus(data, size).IsSuccess();
38   }
39
40   Status ConsumeWithStatus(const unsigned char* data, unsigned int size) {
41     crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
42     Status error = Init();
43     if (!error.IsSuccess())
44       return error;
45
46     if (!EVP_DigestUpdate(digest_context_.get(), data, size))
47       return Status::OperationError();
48
49     return Status::Success();
50   }
51
52   bool finish(unsigned char*& result_data,
53               unsigned int& result_data_size) override {
54     Status error = FinishInternal(result_, &result_data_size);
55     if (!error.IsSuccess())
56       return false;
57     result_data = result_;
58     return true;
59   }
60
61   Status FinishWithVectorAndStatus(std::vector<uint8_t>* result) {
62     const int hash_expected_size = EVP_MD_CTX_size(digest_context_.get());
63     result->resize(hash_expected_size);
64     unsigned char* const hash_buffer = vector_as_array(result);
65     unsigned int hash_buffer_size;  // ignored
66     return FinishInternal(hash_buffer, &hash_buffer_size);
67   }
68
69  private:
70   Status Init() {
71     if (initialized_)
72       return Status::Success();
73
74     const EVP_MD* digest_algorithm = GetDigest(algorithm_id_);
75     if (!digest_algorithm)
76       return Status::ErrorUnexpected();
77
78     if (!digest_context_.get())
79       return Status::OperationError();
80
81     if (!EVP_DigestInit_ex(digest_context_.get(), digest_algorithm, NULL))
82       return Status::OperationError();
83
84     initialized_ = true;
85     return Status::Success();
86   }
87
88   Status FinishInternal(unsigned char* result, unsigned int* result_size) {
89     crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
90     Status error = Init();
91     if (!error.IsSuccess())
92       return error;
93
94     const int hash_expected_size = EVP_MD_CTX_size(digest_context_.get());
95     if (hash_expected_size <= 0)
96       return Status::ErrorUnexpected();
97     DCHECK_LE(hash_expected_size, EVP_MAX_MD_SIZE);
98
99     if (!EVP_DigestFinal_ex(digest_context_.get(), result, result_size) ||
100         static_cast<int>(*result_size) != hash_expected_size)
101       return Status::OperationError();
102
103     return Status::Success();
104   }
105
106   bool initialized_;
107   crypto::ScopedEVP_MD_CTX digest_context_;
108   blink::WebCryptoAlgorithmId algorithm_id_;
109   unsigned char result_[EVP_MAX_MD_SIZE];
110 };
111
112 class ShaImplementation : public AlgorithmImplementation {
113  public:
114   Status Digest(const blink::WebCryptoAlgorithm& algorithm,
115                 const CryptoData& data,
116                 std::vector<uint8_t>* buffer) const override {
117     DigestorOpenSsl digestor(algorithm.id());
118     Status error = digestor.ConsumeWithStatus(data.bytes(), data.byte_length());
119     // http://crbug.com/366427: the spec does not define any other failures for
120     // digest, so none of the subsequent errors are spec compliant.
121     if (!error.IsSuccess())
122       return error;
123     return digestor.FinishWithVectorAndStatus(buffer);
124   }
125 };
126
127 }  // namespace
128
129 AlgorithmImplementation* CreatePlatformShaImplementation() {
130   return new ShaImplementation();
131 }
132
133 scoped_ptr<blink::WebCryptoDigestor> CreatePlatformDigestor(
134     blink::WebCryptoAlgorithmId algorithm) {
135   return scoped_ptr<blink::WebCryptoDigestor>(new DigestorOpenSsl(algorithm));
136 }
137
138 }  // namespace webcrypto
139
140 }  // namespace content