Kea 2.5.8
openssl_hmac.cc
Go to the documentation of this file.
1// Copyright (C) 2014-2022 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
9#include <cryptolink.h>
11
12#include <boost/scoped_ptr.hpp>
13
14#include <openssl/evp.h>
15
17#define KEA_HASH
18#define KEA_HMAC
20
21#include <cstring>
22
23namespace isc {
24namespace cryptolink {
25
28class HMACImpl {
29public:
37 explicit HMACImpl(const void* secret, size_t secret_len,
38 const HashAlgorithm hash_algorithm)
39 : hash_algorithm_(hash_algorithm), md_(), digest_() {
40 const EVP_MD* algo = ossl::getHashAlgorithm(hash_algorithm);
41 if (algo == 0) {
43 "Unknown hash algorithm: " <<
44 static_cast<int>(hash_algorithm));
45 }
46 if (secret_len == 0) {
47 isc_throw(BadKey, "Bad HMAC secret length: 0");
48 }
49
50 md_ = EVP_MD_CTX_new();
51 if (md_ == 0) {
52 isc_throw(LibraryError, "OpenSSL EVP_MD_CTX_new() failed");
53 }
54
55 EVP_PKEY* pkey =
56 EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL,
57 reinterpret_cast<const unsigned char*>(secret),
58 secret_len);
59
60 if (pkey == 0) {
62 "OpenSSL EVP_PKEY_new_raw_private_key() failed");
63 }
64
65 if (!EVP_DigestSignInit(md_, NULL, algo, NULL, pkey)) {
66 EVP_PKEY_free(pkey);
67 isc_throw(LibraryError, "OpenSSL EVP_DigestSignInit() failed");
68 }
69
70 EVP_PKEY_free(pkey);
71 }
72
75 if (md_) {
76 EVP_MD_CTX_free(md_);
77 }
78 md_ = 0;
79 }
80
83 return (hash_algorithm_);
84 }
85
89 size_t getOutputLength() const {
90 return (EVP_MD_CTX_size(md_));
91 }
92
96 void update(const void* data, const size_t len) {
97 if (len == 0) {
98 return;
99 }
100
101 if (!EVP_DigestSignUpdate(md_, data, len)) {
102 isc_throw(LibraryError, "OpenSSL EVP_DigestSignUpdate() failed");
103 }
104 }
105
109 void sign(isc::util::OutputBuffer& result, size_t len) {
110 size_t size = getOutputLength();
112 size_t digest_len = size;
113 if (!EVP_DigestSignFinal(md_, &digest[0], &digest_len)) {
114 isc_throw(LibraryError, "OpenSSL EVP_DigestSignFinal() failed");
115 }
116 if (digest_len != size) {
117 isc_throw(LibraryError, "OpenSSL partial EVP_DigestSignFinal()");
118 }
119 if (len > size) {
120 len = size;
121 }
122 result.writeData(&digest[0], len);
123 }
124
128 void sign(void* result, size_t len) {
129 size_t size = getOutputLength();
131 size_t digest_len = size;
132 if (!EVP_DigestSignFinal(md_, &digest[0], &digest_len)) {
133 isc_throw(LibraryError, "OpenSSL EVP_DigestSignFinal() failed");
134 }
135 if (digest_len != size) {
136 isc_throw(LibraryError, "OpenSSL partial EVP_DigestSignFinal()");
137 }
138 if (len > size) {
139 len = size;
140 }
141 std::memcpy(result, &digest[0], len);
142 }
143
147 std::vector<uint8_t> sign(size_t len) {
148 size_t size = getOutputLength();
150 size_t digest_len = size;
151 if (!EVP_DigestSignFinal(md_, &digest[0], &digest_len)) {
152 isc_throw(LibraryError, "OpenSSL EVP_DigestSignFinal() failed");
153 }
154 if (digest_len != size) {
155 isc_throw(LibraryError, "OpenSSL partial EVP_DigestSignFinal()");
156 }
157 if (len < size) {
158 digest.resize(len);
159 }
160 return (std::vector<uint8_t>(digest.begin(), digest.end()));
161 }
162
166 bool verify(const void* sig, size_t len) {
167 // Check the length
168 size_t size = getOutputLength();
169 if (len < 10 || len < size / 2) {
170 return (false);
171 }
172 if (digest_.size() == 0) {
173 digest_.resize(size);
174 size_t digest_len = size;
175 if (!EVP_DigestSignFinal(md_, &digest_[0], &digest_len)) {
176 isc_throw(LibraryError, "OpenSSL EVP_DigestSignFinal() failed");
177 }
178 if (digest_len != size) {
179 isc_throw(LibraryError, "OpenSSL partial EVP_DigestSignFinal()");
180 }
181 }
182 if (len > size) {
183 len = size;
184 }
185 return (digest_.same(sig, len));
186 }
187
188private:
190 HashAlgorithm hash_algorithm_;
191
193 EVP_MD_CTX* md_;
194
197};
198
199HMAC::HMAC(const void* secret, size_t secret_length,
200 const HashAlgorithm hash_algorithm)
201{
202 impl_ = new HMACImpl(secret, secret_length, hash_algorithm);
203}
204
205HMAC::~HMAC() {
206 delete impl_;
207}
208
211 return (impl_->getHashAlgorithm());
212}
213
214size_t
215HMAC::getOutputLength() const {
216 return (impl_->getOutputLength());
217}
218
219void
220HMAC::update(const void* data, const size_t len) {
221 impl_->update(data, len);
222}
223
224void
225HMAC::sign(isc::util::OutputBuffer& result, size_t len) {
226 impl_->sign(result, len);
227}
228
229void
230HMAC::sign(void* result, size_t len) {
231 impl_->sign(result, len);
232}
233
234std::vector<uint8_t>
235HMAC::sign(size_t len) {
236 return impl_->sign(len);
237}
238
239bool
240HMAC::verify(const void* sig, const size_t len) {
241 return (impl_->verify(sig, len));
242}
243
244} // namespace cryptolink
245} // namespace isc
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition: buffer.h:347
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
Definition: buffer.h:556
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Defines the logger used by the top-level component of kea-lfc.