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.
6 #include <openssl/evp.h>
7 #include <openssl/sha.h>
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"
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
{
31 explicit DigestorOpenSsl(blink::WebCryptoAlgorithmId algorithm_id
)
32 : initialized_(false),
33 digest_context_(EVP_MD_CTX_create()),
34 algorithm_id_(algorithm_id
) {}
36 bool consume(const unsigned char* data
, unsigned int size
) override
{
37 return ConsumeWithStatus(data
, size
).IsSuccess();
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())
46 if (!EVP_DigestUpdate(digest_context_
.get(), data
, size
))
47 return Status::OperationError();
49 return Status::Success();
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())
57 result_data
= 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
);
72 return Status::Success();
74 const EVP_MD
* digest_algorithm
= GetDigest(algorithm_id_
);
75 if (!digest_algorithm
)
76 return Status::ErrorUnsupported();
78 if (!digest_context_
.get())
79 return Status::OperationError();
81 if (!EVP_DigestInit_ex(digest_context_
.get(), digest_algorithm
, NULL
))
82 return Status::OperationError();
85 return Status::Success();
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())
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
);
99 if (!EVP_DigestFinal_ex(digest_context_
.get(), result
, result_size
) ||
100 static_cast<int>(*result_size
) != hash_expected_size
)
101 return Status::OperationError();
103 return Status::Success();
107 crypto::ScopedEVP_MD_CTX digest_context_
;
108 blink::WebCryptoAlgorithmId algorithm_id_
;
109 unsigned char result_
[EVP_MAX_MD_SIZE
];
112 class ShaImplementation
: public AlgorithmImplementation
{
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())
123 return digestor
.FinishWithVectorAndStatus(buffer
);
129 AlgorithmImplementation
* CreatePlatformShaImplementation() {
130 return new ShaImplementation();
133 scoped_ptr
<blink::WebCryptoDigestor
> CreatePlatformDigestor(
134 blink::WebCryptoAlgorithmId algorithm
) {
135 return scoped_ptr
<blink::WebCryptoDigestor
>(new DigestorOpenSsl(algorithm
));
138 } // namespace webcrypto
140 } // namespace content