blob: 81f7a27605fb60d4e1a43fda3c52ad015ebf0c94 [file] [log] [blame]
Yingdi Yud12fb972015-08-01 17:38:49 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesavento87039532017-09-16 15:15:39 -04002/*
3 * Copyright (c) 2013-2017 Regents of the University of California.
Yingdi Yud12fb972015-08-01 17:38:49 -07004 *
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 "hmac-filter.hpp"
23#include "../detail/openssl-helper.hpp"
24
Davide Pesavento9219f582017-09-17 13:58:29 -040025#include <boost/lexical_cast.hpp>
26
Yingdi Yud12fb972015-08-01 17:38:49 -070027namespace ndn {
28namespace security {
29namespace transform {
30
31class HmacFilter::Impl
32{
33public:
Davide Pesavento9219f582017-09-17 13:58:29 -040034 Impl() noexcept
35 : key(nullptr)
36 {
Alexander Afanasyev02948ec2016-09-12 18:04:50 -070037#if OPENSSL_VERSION_NUMBER < 0x1010000fL
Davide Pesavento9219f582017-09-17 13:58:29 -040038 ctx = EVP_MD_CTX_create();
Alexander Afanasyev02948ec2016-09-12 18:04:50 -070039#else
Davide Pesavento9219f582017-09-17 13:58:29 -040040 ctx = EVP_MD_CTX_new();
41#endif
Alexander Afanasyev02948ec2016-09-12 18:04:50 -070042 }
43
44 ~Impl()
45 {
Davide Pesavento9219f582017-09-17 13:58:29 -040046#if OPENSSL_VERSION_NUMBER < 0x1010000fL
47 EVP_MD_CTX_destroy(ctx);
48#else
49 EVP_MD_CTX_free(ctx);
50#endif
51 EVP_PKEY_free(key);
Alexander Afanasyev02948ec2016-09-12 18:04:50 -070052 }
53
Davide Pesavento9219f582017-09-17 13:58:29 -040054public:
55 EVP_MD_CTX* ctx;
56 EVP_PKEY* key;
Yingdi Yud12fb972015-08-01 17:38:49 -070057};
58
Davide Pesavento8aad3722017-09-16 20:57:28 -040059
Yingdi Yud12fb972015-08-01 17:38:49 -070060HmacFilter::HmacFilter(DigestAlgorithm algo, const uint8_t* key, size_t keyLen)
Davide Pesavento8aad3722017-09-16 20:57:28 -040061 : m_impl(make_unique<Impl>())
Yingdi Yud12fb972015-08-01 17:38:49 -070062{
63 BOOST_ASSERT(key != nullptr);
64 BOOST_ASSERT(keyLen > 0);
65
Davide Pesavento9219f582017-09-17 13:58:29 -040066 const EVP_MD* md = detail::digestAlgorithmToEvpMd(algo);
67 if (md == nullptr)
68 BOOST_THROW_EXCEPTION(Error(getIndex(), "Unsupported digest algorithm " +
69 boost::lexical_cast<std::string>(algo)));
Yingdi Yud12fb972015-08-01 17:38:49 -070070
Davide Pesavento9219f582017-09-17 13:58:29 -040071 m_impl->key = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, nullptr, key, static_cast<int>(keyLen));
72 if (m_impl->key == nullptr)
73 BOOST_THROW_EXCEPTION(Error(getIndex(), "Failed to create HMAC key"));
74
75 if (EVP_DigestSignInit(m_impl->ctx, nullptr, md, nullptr, m_impl->key) != 1)
76 BOOST_THROW_EXCEPTION(Error(getIndex(), "Failed to initialize HMAC context with " +
77 boost::lexical_cast<std::string>(algo) + " digest"));
Yingdi Yud12fb972015-08-01 17:38:49 -070078}
79
Davide Pesavento8aad3722017-09-16 20:57:28 -040080HmacFilter::~HmacFilter() = default;
81
Yingdi Yud12fb972015-08-01 17:38:49 -070082size_t
83HmacFilter::convert(const uint8_t* buf, size_t size)
84{
Davide Pesavento9219f582017-09-17 13:58:29 -040085 if (EVP_DigestSignUpdate(m_impl->ctx, buf, size) != 1)
86 BOOST_THROW_EXCEPTION(Error(getIndex(), "Failed to accept more input"));
Yingdi Yud12fb972015-08-01 17:38:49 -070087
88 return size;
89}
90
91void
92HmacFilter::finalize()
93{
94 auto buffer = make_unique<OBuffer>(EVP_MAX_MD_SIZE);
Davide Pesavento9219f582017-09-17 13:58:29 -040095 size_t hmacLen = 0;
Yingdi Yud12fb972015-08-01 17:38:49 -070096
Davide Pesavento9219f582017-09-17 13:58:29 -040097 if (EVP_DigestSignFinal(m_impl->ctx, buffer->data(), &hmacLen) != 1)
Yingdi Yud12fb972015-08-01 17:38:49 -070098 BOOST_THROW_EXCEPTION(Error(getIndex(), "Failed to finalize HMAC"));
99
Davide Pesavento9219f582017-09-17 13:58:29 -0400100 buffer->erase(buffer->begin() + hmacLen, buffer->end());
Yingdi Yud12fb972015-08-01 17:38:49 -0700101 setOutputBuffer(std::move(buffer));
102
103 flushAllOutput();
104}
105
106unique_ptr<Transform>
107hmacFilter(DigestAlgorithm algo, const uint8_t* key, size_t keyLen)
108{
109 return make_unique<HmacFilter>(algo, key, keyLen);
110}
111
112} // namespace transform
113} // namespace security
114} // namespace ndn