Kea  2.5.3
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>
10 #include <cryptolink/crypto_hmac.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 
23 namespace isc {
24 namespace cryptolink {
25 
28 class HMACImpl {
29 public:
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 
188 private:
190  HashAlgorithm hash_algorithm_;
191 
193  EVP_MD_CTX* md_;
194 
197 };
198 
199 HMAC::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 
205 HMAC::~HMAC() {
206  delete impl_;
207 }
208 
210 HMAC::getHashAlgorithm() const {
211  return (impl_->getHashAlgorithm());
212 }
213 
214 size_t
215 HMAC::getOutputLength() const {
216  return (impl_->getOutputLength());
217 }
218 
219 void
220 HMAC::update(const void* data, const size_t len) {
221  impl_->update(data, len);
222 }
223 
224 void
225 HMAC::sign(isc::util::OutputBuffer& result, size_t len) {
226  impl_->sign(result, len);
227 }
228 
229 void
230 HMAC::sign(void* result, size_t len) {
231  impl_->sign(result, len);
232 }
233 
234 std::vector<uint8_t>
235 HMAC::sign(size_t len) {
236  return impl_->sign(len);
237 }
238 
239 bool
240 HMAC::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:294
void writeData(const void *data, size_t len)
Copy an arbitrary length of data into the buffer.
Definition: buffer.h:550
#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.