blob: 9fed4d265b8c9de8535e98d36a5900c6f3f3f2a4 [file] [log] [blame]
Yingdi Yuae734272015-07-04 17:38:48 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2013-2016 Regents of the University of California.
4 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
22#include "digest-filter.hpp"
23#include "../../encoding/buffer.hpp"
24#include "../detail/openssl-helper.hpp"
25
26namespace ndn {
27namespace security {
28namespace transform {
29
30/**
31 * @brief The implementation class which contains the internal state of
32 * the digest calculator which includes openssl specific structures.
33 */
34class DigestFilter::Impl
35{
36public:
37 Impl()
38 : m_md(BIO_new(BIO_f_md()))
39 , m_sink(BIO_new(BIO_s_null()))
40 {
41 BIO_push(m_md, m_sink);
42 }
43
44 ~Impl()
45 {
46 BIO_free_all(m_md);
47 }
48
49public:
50 BIO* m_md;
51 BIO* m_sink;
52};
53
54DigestFilter::DigestFilter(DigestAlgorithm algo)
55 : m_impl(new Impl)
56{
57 const EVP_MD* md = detail::toDigestEvpMd(algo);
58 if (md == nullptr) {
59 // @todo Add digest algorithm to the error message
60 BOOST_THROW_EXCEPTION(Error(getIndex(), "Unsupported digest algorithm"));
61 }
62
63 if (!BIO_set_md(m_impl->m_md, md)) {
64 // @todo Add digest algorithm to the error message
65 BOOST_THROW_EXCEPTION(Error(getIndex(), "Cannot set digest"));
66 }
67}
68
69size_t
70DigestFilter::convert(const uint8_t* buf, size_t size)
71{
72 int wLen = BIO_write(m_impl->m_md, buf, size);
73
74 if (wLen <= 0) { // fail to write data
75 if (!BIO_should_retry(m_impl->m_md)) {
76 // we haven't written everything but some error happens, and we cannot retry
77 BOOST_THROW_EXCEPTION(Error(getIndex(), "Failed to accept more input"));
78 }
79 return 0;
80 }
81 else { // update number of bytes written
82 return wLen;
83 }
84}
85
86void
87DigestFilter::finalize()
88{
89 auto buffer = make_unique<OBuffer>(EVP_MAX_MD_SIZE);
90
91 int mdLen = BIO_gets(m_impl->m_md, reinterpret_cast<char*>(&(*buffer)[0]), EVP_MAX_MD_SIZE);
92 if (mdLen <= 0)
93 BOOST_THROW_EXCEPTION(Error(getIndex(), "Failed to compute digest"));
94
95 buffer->erase(buffer->begin() + mdLen, buffer->end());
96 setOutputBuffer(std::move(buffer));
97
98 flushAllOutput();
99}
100
101unique_ptr<Transform>
102digestFilter(DigestAlgorithm algo)
103{
104 return make_unique<DigestFilter>(algo);
105}
106
107} // namespace transform
108} // namespace security
109} // namespace ndn