1 /*
2  * Copyright (C) 2018 Rafael Ostertag
3  *
4  * This file is part of YAPET.
5  *
6  * YAPET is free software: you can redistribute it and/or modify it under the
7  * terms of the GNU General Public License as published by the Free Software
8  * Foundation, either version 3 of the License, or (at your option) any later
9  * version.
10  *
11  * YAPET is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
14  * details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * YAPET.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  * Additional permission under GNU GPL version 3 section 7
20  *
21  * If you modify this program, or any covered work, by linking or combining it
22  * with the OpenSSL project's OpenSSL library (or a modified version of that
23  * library), containing parts covered by the terms of the OpenSSL or SSLeay
24  * licenses, Rafael Ostertag grants you additional permission to convey the
25  * resulting work.  Corresponding Source for a non-source form of such a
26  * combination shall include the source code for the parts of OpenSSL used as
27  * well as that of the covered work.
28  */
29 
30 #include <cstdio>
31 #include <cstring>
32 #include <limits>
33 #include <stdexcept>
34 
35 #include "consts.h"
36 #include "intl.h"
37 #include "securearray.hh"
38 
39 using namespace yapet;
40 
41 namespace {
castToSizeTypeOrThrow(size_t otherSize)42 inline SecureArray::size_type castToSizeTypeOrThrow(size_t otherSize) {
43     int maxSize = std::numeric_limits<SecureArray::size_type>::max();
44     size_t castedMaxSize = static_cast<size_t>(maxSize);
45     if (otherSize > castedMaxSize) {
46         throw std::invalid_argument(
47             _("Provided size exceeds maximum size of SecureArray"));
48     }
49 
50     return static_cast<SecureArray::size_type>(otherSize);
51 }
52 }  // namespace
53 
indexInRangeOrThrow(size_type index) const54 void SecureArray::indexInRangeOrThrow(size_type index) const {
55     if (index >= _size || index < 0) {
56         char msg[YAPET::Consts::EXCEPTION_MESSAGE_BUFFER_SIZE];
57         std::snprintf(msg, YAPET::Consts::EXCEPTION_MESSAGE_BUFFER_SIZE,
58                       _("Index out of range: %d"), index);
59         throw std::out_of_range{msg};
60     }
61 }
62 
SecureArray(size_type size)63 SecureArray::SecureArray(size_type size) : _size{size}, _array{nullptr} {
64     if (_size < 0) {
65         throw std::invalid_argument{_("Size must not be negative")};
66     }
67 
68     if (_size != 0) {
69         _array = new std::uint8_t[_size];
70     }
71 }
72 
~SecureArray()73 SecureArray::~SecureArray() {
74     clearMemory();
75     freeMemory();
76 }
77 
SecureArray(const SecureArray & other)78 SecureArray::SecureArray(const SecureArray& other)
79     : _size{other._size}, _array{nullptr} {
80     if (_size != 0) {
81         _array = new std::uint8_t[_size];
82         std::memcpy(_array, other._array, _size);
83     }
84 }
85 
operator =(const SecureArray & other)86 SecureArray& SecureArray::operator=(const SecureArray& other) {
87     if (this == &other) {
88         return *this;
89     }
90 
91     clearMemory();
92     freeMemory();
93 
94     _size = other._size;
95     if (_size == 0) {
96         _array = other._array;
97     } else {
98         _array = new std::uint8_t[_size];
99         std::memcpy(_array, other._array, _size);
100     }
101 
102     return *this;
103 }
104 
SecureArray(SecureArray && other)105 SecureArray::SecureArray(SecureArray&& other)
106     : _size{other._size}, _array{other._array} {
107     other._array = nullptr;
108     other._size = 0;
109 }
110 
operator =(SecureArray && other)111 SecureArray& SecureArray::operator=(SecureArray&& other) {
112     if (this == &other) {
113         return *this;
114     }
115 
116     clearMemory();
117     freeMemory();
118 
119     _size = other._size;
120     _array = other._array;
121     other._array = nullptr;
122     other._size = 0;
123 
124     return *this;
125 }
126 
clearMemory()127 inline void SecureArray::clearMemory() {
128     if (_array == nullptr) return;
129 
130     std::memset(_array, 0, _size);
131 }
132 
freeMemory()133 inline void SecureArray::freeMemory() {
134     if (_array == nullptr) return;
135     delete[] _array;
136 }
137 
operator *() const138 const std::uint8_t* SecureArray::operator*() const { return _array; }
139 
operator *()140 std::uint8_t* SecureArray::operator*() { return _array; }
141 
operator [](size_type index) const142 std::uint8_t SecureArray::operator[](size_type index) const {
143     indexInRangeOrThrow(index);
144     return _array[index];
145 }
146 
operator [](size_type index)147 std::uint8_t& SecureArray::operator[](size_type index) {
148     indexInRangeOrThrow(index);
149     return _array[index];
150 }
151 
operator ==(const SecureArray & other) const152 bool SecureArray::operator==(const SecureArray& other) const {
153     if (other._size != _size) return false;
154 
155     if (other._array == nullptr && _array == nullptr) return true;
156 
157     return std::memcmp(_array, other._array, _size) == 0;
158 }
159 
operator <<(const SecureArray & source)160 SecureArray& SecureArray::operator<<(const SecureArray& source) {
161     if (this == &source) return *this;
162 
163     if (source._size == 0 || _size == 0) {
164         return *this;
165     }
166 
167     if (source._size > _size) {
168         std::memcpy(_array, source._array, _size);
169         return *this;
170     }
171 
172     clearMemory();
173     freeMemory();
174 
175     _array = new std::uint8_t[source._size];
176     _size = source._size;
177     std::memcpy(_array, source._array, _size);
178 
179     return *this;
180 }
181 
toSecureArray(const char * str)182 SecureArray yapet::toSecureArray(const char* str) {
183     auto len = std::strlen(str) + 1;
184     if (len == 0) {
185         return SecureArray{};
186     }
187 
188     auto castedSize = castToSizeTypeOrThrow(len);
189 
190     SecureArray result{castedSize};
191     std::memcpy(*result, str, len);
192 
193     return result;
194 }
195 
toSecureArray(const std::string & str)196 SecureArray yapet::toSecureArray(const std::string& str) {
197     return toSecureArray(str.c_str());
198 }
199 
toSecureArray(const std::uint8_t * ptr,SecureArray::size_type size)200 SecureArray yapet::toSecureArray(const std::uint8_t* ptr,
201                                  SecureArray::size_type size) {
202     if (ptr == nullptr) {
203         throw std::invalid_argument(_("Pointer must not be null"));
204     }
205 
206     SecureArray secureArray{size};
207     std::memcpy(*secureArray, ptr, size);
208 
209     return secureArray;
210 }
211 
operator +(const SecureArray & a,const SecureArray & b)212 SecureArray yapet::operator+(const SecureArray& a, const SecureArray& b) {
213     auto aSize = a.size();
214     auto bSize = b.size();
215     SecureArray result{aSize + bSize};
216 
217     std::memcpy(*result, *a, aSize);
218     auto ptrToBDest = *result + aSize;
219     std::memcpy(ptrToBDest, *b, bSize);
220 
221     return result;
222 }
223