blob: 7b731a0528ec44a678092f7b2ed183b5874964e8 [file] [log] [blame]
Yingdi Yu38317e52015-07-22 13:58:02 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesavento8aad3722017-09-16 20:57:28 -04002/*
Davide Pesavento765abc92021-12-27 00:44:04 -05003 * Copyright (c) 2013-2021 Regents of the University of California.
Yingdi Yu38317e52015-07-22 13:58:02 -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
Davide Pesavento7e780642018-11-24 15:51:34 -050022#include "ndn-cxx/security/transform/base64-decode.hpp"
Junxiao Shi24c5a002018-12-12 04:47:15 +000023#include "ndn-cxx/security/impl/openssl.hpp"
Yingdi Yu38317e52015-07-22 13:58:02 -070024
25namespace ndn {
26namespace security {
27namespace transform {
28
Davide Pesavento765abc92021-12-27 00:44:04 -050029class Base64Decode::Impl : boost::noncopyable
Yingdi Yu38317e52015-07-22 13:58:02 -070030{
31public:
32 Impl()
33 : m_base64(BIO_new(BIO_f_base64()))
34 , m_source(BIO_new(BIO_s_mem()))
35 {
36 // Input may not be written in a single time.
37 // Do not return EOF when source is empty unless explicitly requested
38 BIO_set_mem_eof_return(m_source, -1);
39
40 // connect base64 transform to the data source.
41 BIO_push(m_base64, m_source);
42 }
43
44 ~Impl()
45 {
Junxiao Shi1b0f4862016-09-10 17:45:04 +000046 BIO_free_all(m_base64);
Yingdi Yu38317e52015-07-22 13:58:02 -070047 }
48
49public:
50 BIO* m_base64;
51 BIO* m_source; // BIO_f_base64 alone does not work without a source
52};
53
Yingdi Yu38317e52015-07-22 13:58:02 -070054
55Base64Decode::Base64Decode(bool expectNewlineEvery64Bytes)
Davide Pesavento8aad3722017-09-16 20:57:28 -040056 : m_impl(make_unique<Impl>())
Yingdi Yu38317e52015-07-22 13:58:02 -070057{
58 if (!expectNewlineEvery64Bytes)
59 BIO_set_flags(m_impl->m_base64, BIO_FLAGS_BASE64_NO_NL);
60}
61
Davide Pesavento8aad3722017-09-16 20:57:28 -040062Base64Decode::~Base64Decode() = default;
63
Yingdi Yu38317e52015-07-22 13:58:02 -070064void
65Base64Decode::preTransform()
66{
67 while (isOutputBufferEmpty()) {
68 fillOutputBuffer();
69 if (isOutputBufferEmpty()) // nothing to read from BIO, return
70 return;
71
72 flushOutputBuffer();
73 }
74}
75
76size_t
Davide Pesavento765abc92021-12-27 00:44:04 -050077Base64Decode::convert(span<const uint8_t> buf)
Yingdi Yu38317e52015-07-22 13:58:02 -070078{
Davide Pesavento765abc92021-12-27 00:44:04 -050079 int wLen = BIO_write(m_impl->m_source, buf.data(), buf.size());
Yingdi Yu38317e52015-07-22 13:58:02 -070080
81 if (wLen <= 0) { // fail to write data
82 if (!BIO_should_retry(m_impl->m_source)) {
83 // we haven't written everything but some error happens, and we cannot retry
Davide Pesavento923ba442019-02-12 22:00:38 -050084 NDN_THROW(Error(getIndex(), "Failed to accept more input"));
Yingdi Yu38317e52015-07-22 13:58:02 -070085 }
86 return 0;
87 }
88 else { // update number of bytes written
89 return wLen;
90 }
91}
92
93void
94Base64Decode::finalize()
95{
96 BIO_set_mem_eof_return(m_impl->m_source, 0);
97
98 fillOutputBuffer();
99
100 while (!isOutputBufferEmpty()) {
101 flushOutputBuffer();
102 if (isOutputBufferEmpty())
103 fillOutputBuffer();
104 }
105}
106
107void
108Base64Decode::fillOutputBuffer()
109{
110 // OpenSSL base64 BIO cannot give us the number bytes of partial decoded result,
111 // so we just try to read a chunk.
Davide Pesavento765abc92021-12-27 00:44:04 -0500112 auto buffer = make_unique<OBuffer>(1024);
Davide Pesavento8aad3722017-09-16 20:57:28 -0400113 int rLen = BIO_read(m_impl->m_base64, buffer->data(), buffer->size());
Yingdi Yu38317e52015-07-22 13:58:02 -0700114 if (rLen <= 0)
115 return;
116
117 if (static_cast<size_t>(rLen) < buffer->size())
118 buffer->erase(buffer->begin() + rLen, buffer->end());
119
120 setOutputBuffer(std::move(buffer));
121}
122
123unique_ptr<Transform>
124base64Decode(bool expectNewlineEvery64Bytes)
125{
126 return make_unique<Base64Decode>(expectNewlineEvery64Bytes);
127}
128
129} // namespace transform
130} // namespace security
131} // namespace ndn