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 <openssl/evp.h>
6 #include <openssl/sha.h>
9 #include "base/logging.h"
10 #include "base/stl_util.h"
11 #include "components/webcrypto/algorithm_implementation.h"
12 #include "components/webcrypto/algorithms/util_openssl.h"
13 #include "components/webcrypto/crypto_data.h"
14 #include "components/webcrypto/status.h"
15 #include "components/webcrypto/webcrypto_util.h"
16 #include "crypto/openssl_util.h"
17 #include "crypto/scoped_openssl_types.h"
23 // Implementation of blink::WebCryptoDigester, an internal Blink detail not
24 // part of WebCrypto, that allows chunks of data to be streamed in before
25 // computing a SHA-* digest (as opposed to ShaImplementation, which computes
26 // digests over complete messages)
27 class DigestorOpenSsl
: public blink::WebCryptoDigestor
{
29 explicit DigestorOpenSsl(blink::WebCryptoAlgorithmId algorithm_id
)
30 : initialized_(false),
31 digest_context_(EVP_MD_CTX_create()),
32 algorithm_id_(algorithm_id
) {}
34 bool consume(const unsigned char* data
, unsigned int size
) override
{
35 return ConsumeWithStatus(data
, size
).IsSuccess();
38 Status
ConsumeWithStatus(const unsigned char* data
, unsigned int size
) {
39 crypto::OpenSSLErrStackTracer
err_tracer(FROM_HERE
);
40 Status error
= Init();
41 if (!error
.IsSuccess())
44 if (!EVP_DigestUpdate(digest_context_
.get(), data
, size
))
45 return Status::OperationError();
47 return Status::Success();
50 bool finish(unsigned char*& result_data
,
51 unsigned int& result_data_size
) override
{
52 Status error
= FinishInternal(result_
, &result_data_size
);
53 if (!error
.IsSuccess())
55 result_data
= result_
;
59 Status
FinishWithVectorAndStatus(std::vector
<uint8_t>* result
) {
60 const int hash_expected_size
= EVP_MD_CTX_size(digest_context_
.get());
61 result
->resize(hash_expected_size
);
62 unsigned char* const hash_buffer
= vector_as_array(result
);
63 unsigned int hash_buffer_size
; // ignored
64 return FinishInternal(hash_buffer
, &hash_buffer_size
);
70 return Status::Success();
72 const EVP_MD
* digest_algorithm
= GetDigest(algorithm_id_
);
73 if (!digest_algorithm
)
74 return Status::ErrorUnsupported();
76 if (!digest_context_
.get())
77 return Status::OperationError();
79 if (!EVP_DigestInit_ex(digest_context_
.get(), digest_algorithm
, NULL
))
80 return Status::OperationError();
83 return Status::Success();
86 Status
FinishInternal(unsigned char* result
, unsigned int* result_size
) {
87 crypto::OpenSSLErrStackTracer
err_tracer(FROM_HERE
);
88 Status error
= Init();
89 if (!error
.IsSuccess())
92 const int hash_expected_size
= EVP_MD_CTX_size(digest_context_
.get());
93 if (hash_expected_size
<= 0)
94 return Status::ErrorUnexpected();
95 DCHECK_LE(hash_expected_size
, EVP_MAX_MD_SIZE
);
97 if (!EVP_DigestFinal_ex(digest_context_
.get(), result
, result_size
) ||
98 static_cast<int>(*result_size
) != hash_expected_size
)
99 return Status::OperationError();
101 return Status::Success();
105 crypto::ScopedEVP_MD_CTX digest_context_
;
106 blink::WebCryptoAlgorithmId algorithm_id_
;
107 unsigned char result_
[EVP_MAX_MD_SIZE
];
110 class ShaImplementation
: public AlgorithmImplementation
{
112 Status
Digest(const blink::WebCryptoAlgorithm
& algorithm
,
113 const CryptoData
& data
,
114 std::vector
<uint8_t>* buffer
) const override
{
115 DigestorOpenSsl
digestor(algorithm
.id());
116 Status error
= digestor
.ConsumeWithStatus(data
.bytes(), data
.byte_length());
117 // http://crbug.com/366427: the spec does not define any other failures for
118 // digest, so none of the subsequent errors are spec compliant.
119 if (!error
.IsSuccess())
121 return digestor
.FinishWithVectorAndStatus(buffer
);
127 scoped_ptr
<AlgorithmImplementation
> CreateShaImplementation() {
128 return make_scoped_ptr(new ShaImplementation());
131 scoped_ptr
<blink::WebCryptoDigestor
> CreateDigestorImplementation(
132 blink::WebCryptoAlgorithmId algorithm
) {
133 return scoped_ptr
<blink::WebCryptoDigestor
>(new DigestorOpenSsl(algorithm
));
136 } // namespace webcrypto