• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
DigestorOpenSsl(blink::WebCryptoAlgorithmId algorithm_id)31   explicit DigestorOpenSsl(blink::WebCryptoAlgorithmId algorithm_id)
32       : initialized_(false),
33         digest_context_(EVP_MD_CTX_create()),
34         algorithm_id_(algorithm_id) {}
35 
consume(const unsigned char * data,unsigned int size)36   virtual bool consume(const unsigned char* data, unsigned int size) {
37     return ConsumeWithStatus(data, size).IsSuccess();
38   }
39 
ConsumeWithStatus(const unsigned char * data,unsigned int size)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 
finish(unsigned char * & result_data,unsigned int & result_data_size)52   virtual bool finish(unsigned char*& result_data,
53                       unsigned int& result_data_size) {
54     Status error = FinishInternal(result_, &result_data_size);
55     if (!error.IsSuccess())
56       return false;
57     result_data = result_;
58     return true;
59   }
60 
FinishWithVectorAndStatus(std::vector<uint8_t> * result)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:
Init()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 
FinishInternal(unsigned char * result,unsigned int * result_size)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:
Digest(const blink::WebCryptoAlgorithm & algorithm,const CryptoData & data,std::vector<uint8_t> * buffer) const114   virtual 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 
CreatePlatformShaImplementation()129 AlgorithmImplementation* CreatePlatformShaImplementation() {
130   return new ShaImplementation();
131 }
132 
CreatePlatformDigestor(blink::WebCryptoAlgorithmId algorithm)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
141