blob: 16d314662ed43a5278d5c1d955c93c47b572b0ac [file] [log] [blame]
Yingdi Yub263f152015-07-12 16:50:13 -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 "signer-filter.hpp"
23#include "../../encoding/buffer.hpp"
24#include "../detail/openssl.hpp"
25
26namespace ndn {
27namespace security {
28namespace transform {
29
30class SignerFilter::Impl
31{
32public:
33 Impl(const PrivateKey& key)
34 : m_key(key)
35 , m_md(BIO_new(BIO_f_md()))
36 , m_sink(BIO_new(BIO_s_null()))
37 {
38 BIO_push(m_md, m_sink);
39 }
40
41 ~Impl()
42 {
43 BIO_free_all(m_md);
44 }
45
46public:
47 const PrivateKey& m_key;
48
49 BIO* m_md;
50 BIO* m_sink;
51};
52
53SignerFilter::SignerFilter(DigestAlgorithm algo, const PrivateKey& key)
54 : m_impl(new Impl(key))
55{
56 switch (algo) {
57 case DigestAlgorithm::SHA256: {
58 if (!BIO_set_md(m_impl->m_md, EVP_sha256()))
59 BOOST_THROW_EXCEPTION(Error(getIndex(), "Cannot set digest"));
60 break;
61 }
62
63 default:
64 BOOST_THROW_EXCEPTION(Error(getIndex(), "Digest algorithm is not supported"));
65 }
66}
67
68size_t
69SignerFilter::convert(const uint8_t* buf, size_t size)
70{
71 int wLen = BIO_write(m_impl->m_md, buf, size);
72
73 if (wLen <= 0) { // fail to write data
74 if (!BIO_should_retry(m_impl->m_md)) {
75 // we haven't written everything but some error happens, and we cannot retry
76 BOOST_THROW_EXCEPTION(Error(getIndex(), "Failed to accept more input"));
77 }
78 return 0;
79 }
80 else { // update number of bytes written
81 return wLen;
82 }
83}
84
85void
86SignerFilter::finalize()
87{
88 EVP_PKEY* key = reinterpret_cast<EVP_PKEY*>(m_impl->m_key.getEvpPkey());
89 auto buffer = make_unique<OBuffer>(EVP_PKEY_size(key));
90 unsigned int sigLen = 0;
91
92 EVP_MD_CTX* ctx = nullptr;
93 BIO_get_md_ctx(m_impl->m_md, &ctx);
94 EVP_SignFinal(ctx, &(*buffer)[0], &sigLen, key); // should be ok, enough space is allocated in buffer
95
96 buffer->erase(buffer->begin() + sigLen, buffer->end());
97 setOutputBuffer(std::move(buffer));
98
99 flushAllOutput();
100}
101
102unique_ptr<Transform>
103signerFilter(DigestAlgorithm algo, const PrivateKey& key)
104{
105 return make_unique<SignerFilter>(algo, key);
106}
107
108} // namespace transform
109} // namespace security
110} // namespace ndn