Kea 2.7.7
openssl_hmac.cc
Go to the documentation of this file.
1// Copyright (C) 2014-2025 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
18#include <cstring>
19
20namespace isc {
21namespace cryptolink {
22
25class HMACImpl {
26public:
34 explicit HMACImpl(const void* secret, size_t secret_len,
35 const HashAlgorithm hash_algorithm)
36 : hash_algorithm_(hash_algorithm), md_(), digest_() {
37 const EVP_MD* algo = ossl::getHashAlgorithm(hash_algorithm);
38 if (algo == 0) {
40 "Unknown hash algorithm: " <<
41 static_cast<int>(hash_algorithm));
42 }
43 if (secret_len == 0) {
44 isc_throw(BadKey, "Bad HMAC secret length: 0");
45 }
46
47 md_ = EVP_MD_CTX_new();
48 if (md_ == 0) {
49 isc_throw(LibraryError, "OpenSSL EVP_MD_CTX_new() failed");
50 }
51
52 EVP_PKEY* pkey =
53 EVP_PKEY_new_raw_private_key(EVP_PKEY_HMAC, NULL,
54 reinterpret_cast<const unsigned char*>(secret),
55 secret_len);
56
57 if (pkey == 0) {
59 "OpenSSL EVP_PKEY_new_raw_private_key() failed");
60 }
61
62 if (!EVP_DigestSignInit(md_, NULL, algo, NULL, pkey)) {
63 EVP_PKEY_free(pkey);
64 isc_throw(LibraryError, "OpenSSL EVP_DigestSignInit() failed");
65 }
66
67 EVP_PKEY_free(pkey);
68 }
69
72 if (md_) {
73 EVP_MD_CTX_free(md_);
74 }
75 md_ = 0;
76 }
77
80 return (hash_algorithm_);
81 }
82
86 size_t getOutputLength() const {
87 return (EVP_MD_CTX_size(md_));
88 }
89
93 void update(const void* data, const size_t len) {
94 if (len == 0) {
95 return;
96 }
97
98 if (!EVP_DigestSignUpdate(md_, data, len)) {
99 isc_throw(LibraryError, "OpenSSL EVP_DigestSignUpdate() failed");
100 }
101 }
102
106 void sign(isc::util::OutputBuffer& result, size_t len) {
107 size_t size = getOutputLength();
109 size_t digest_len = size;
110 if (!EVP_DigestSignFinal(md_, &digest[0], &digest_len)) {
111 isc_throw(LibraryError, "OpenSSL EVP_DigestSignFinal() failed");
112 }
113 if (digest_len != size) {
114 isc_throw(LibraryError, "OpenSSL partial EVP_DigestSignFinal()");
115 }
116 if (len > size) {
117 len = size;
118 }
119 result.writeData(&digest[0], len);
120 }
121
125 void sign(void* result, size_t len) {
126 size_t size = getOutputLength();
128 size_t digest_len = size;
129 if (!EVP_DigestSignFinal(md_, &digest[0], &digest_len)) {
130 isc_throw(LibraryError, "OpenSSL EVP_DigestSignFinal() failed");
131 }
132 if (digest_len != size) {
133 isc_throw(LibraryError, "OpenSSL partial EVP_DigestSignFinal()");
134 }
135 if (len > size) {
136 len = size;
137 }
138 std::memcpy(result, &digest[0], len);
139 }
140
144 std::vector<uint8_t> sign(size_t len) {
145 size_t size = getOutputLength();
147 size_t digest_len = size;
148 if (!EVP_DigestSignFinal(md_, &digest[0], &digest_len)) {
149 isc_throw(LibraryError, "OpenSSL EVP_DigestSignFinal() failed");
150 }
151 if (digest_len != size) {
152 isc_throw(LibraryError, "OpenSSL partial EVP_DigestSignFinal()");
153 }
154 if (len < size) {
155 digest.resize(len);
156 }
157 return (std::vector<uint8_t>(digest.begin(), digest.end()));
158 }
159
163 bool verify(const void* sig, size_t len) {
164 // Check the length
165 size_t size = getOutputLength();
166 if (len < 10 || len < size / 2) {
167 return (false);
168 }
169 if (digest_.size() == 0) {
170 digest_.resize(size);
171 size_t digest_len = size;
172 if (!EVP_DigestSignFinal(md_, &digest_[0], &digest_len)) {
173 isc_throw(LibraryError, "OpenSSL EVP_DigestSignFinal() failed");
174 }
175 if (digest_len != size) {
176 isc_throw(LibraryError, "OpenSSL partial EVP_DigestSignFinal()");
177 }
178 }
179 if (len > size) {
180 len = size;
181 }
182 return (digest_.same(sig, len));
183 }
184
185private:
187 HashAlgorithm hash_algorithm_;
188
190 EVP_MD_CTX* md_;
191
194};
195
196HMAC::HMAC(const void* secret, size_t secret_length,
197 const HashAlgorithm hash_algorithm)
198{
199 impl_ = new HMACImpl(secret, secret_length, hash_algorithm);
200}
201
202HMAC::~HMAC() {
203 delete impl_;
204}
205
208 return (impl_->getHashAlgorithm());
209}
210
211size_t
212HMAC::getOutputLength() const {
213 return (impl_->getOutputLength());
214}
215
216void
217HMAC::update(const void* data, const size_t len) {
218 impl_->update(data, len);
219}
220
221void
222HMAC::sign(isc::util::OutputBuffer& result, size_t len) {
223 impl_->sign(result, len);
224}
225
226void
227HMAC::sign(void* result, size_t len) {
228 impl_->sign(result, len);
229}
230
231std::vector<uint8_t>
232HMAC::sign(size_t len) {
233 return impl_->sign(len);
234}
235
236bool
237HMAC::verify(const void* sig, const size_t len) {
238 return (impl_->verify(sig, len));
239}
240
241} // namespace cryptolink
242} // namespace isc
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition buffer.h:346
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
Definition buffer.h:559
#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.