Kea  1.9.9-git
openssl_hmac.cc
Go to the documentation of this file.
1 // Copyright (C) 2014-2017 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/hmac.h>
15 
17 #define KEA_HMAC
19 
20 #include <cstring>
21 
22 namespace isc {
23 namespace cryptolink {
24 
27 class HMACImpl {
28 public:
36  explicit HMACImpl(const void* secret, size_t secret_len,
37  const HashAlgorithm hash_algorithm)
38  : hash_algorithm_(hash_algorithm), md_() {
39  const EVP_MD* algo = ossl::getHashAlgorithm(hash_algorithm);
40  if (algo == 0) {
42  "Unknown hash algorithm: " <<
43  static_cast<int>(hash_algorithm));
44  }
45  if (secret_len == 0) {
46  isc_throw(BadKey, "Bad HMAC secret length: 0");
47  }
48 
49  md_ = HMAC_CTX_new();
50  if (md_ == 0) {
51  isc_throw(LibraryError, "OpenSSL HMAC_CTX_new() failed");
52  }
53 
54  if (!HMAC_Init_ex(md_, secret,
55  static_cast<int>(secret_len),
56  algo, NULL)) {
57  isc_throw(LibraryError, "OpenSSL HMAC_Init_ex() failed");
58  }
59  }
60 
63  if (md_) {
64  HMAC_CTX_free(md_);
65  }
66  md_ = 0;
67  }
68 
71  return (hash_algorithm_);
72  }
73 
77  size_t getOutputLength() const {
78  int size = HMAC_size(md_);
79  if (size < 0) {
80  isc_throw(LibraryError, "OpenSSL HMAC_size() failed");
81  }
82  return (static_cast<size_t>(size));
83  }
84 
88  void update(const void* data, const size_t len) {
89  if (!HMAC_Update(md_,
90  static_cast<const unsigned char*>(data),
91  len)) {
92  isc_throw(LibraryError, "OpenSSLHMAC_Update() failed");
93  }
94  }
95 
99  void sign(isc::util::OutputBuffer& result, size_t len) {
100  size_t size = getOutputLength();
102  if (!HMAC_Final(md_, &digest[0], NULL)) {
103  isc_throw(LibraryError, "OpenSSL HMAC_Final() failed");
104  }
105  if (len > size) {
106  len = size;
107  }
108  result.writeData(&digest[0], len);
109  }
110 
114  void sign(void* result, size_t len) {
115  size_t size = getOutputLength();
117  if (!HMAC_Final(md_, &digest[0], NULL)) {
118  isc_throw(LibraryError, "OpenSSL HMAC_Final() failed");
119  }
120  if (len > size) {
121  len = size;
122  }
123  std::memcpy(result, &digest[0], len);
124  }
125 
129  std::vector<uint8_t> sign(size_t len) {
130  size_t size = getOutputLength();
132  if (!HMAC_Final(md_, &digest[0], NULL)) {
133  isc_throw(LibraryError, "OpenSSL HMAC_Final() failed");
134  }
135  if (len < size) {
136  digest.resize(len);
137  }
138  return (std::vector<uint8_t>(digest.begin(), digest.end()));
139  }
140 
144  bool verify(const void* sig, size_t len) {
145  // Check the length
146  size_t size = getOutputLength();
147  if (len < 10 || len < size / 2) {
148  return (false);
149  }
150  // Get the digest from a copy of the context
151  HMAC_CTX* tmp = HMAC_CTX_new();
152  if (tmp == 0) {
153  isc_throw(LibraryError, "OpenSSL HMAC_CTX_new() failed");
154  }
155  if (!HMAC_CTX_copy(tmp, md_)) {
156  HMAC_CTX_free(tmp);
157  isc_throw(LibraryError, "OpenSSL HMAC_CTX_copy() failed");
158  }
160  if (!HMAC_Final(tmp, &digest[0], NULL)) {
161  HMAC_CTX_free(tmp);
162  isc_throw(LibraryError, "OpenSSL HMAC_Final() failed");
163  }
164  HMAC_CTX_free(tmp);
165  if (len > size) {
166  len = size;
167  }
168  return (digest.same(sig, len));
169  }
170 
171 private:
173  HashAlgorithm hash_algorithm_;
174 
176  HMAC_CTX* md_;
177 };
178 
179 HMAC::HMAC(const void* secret, size_t secret_length,
180  const HashAlgorithm hash_algorithm)
181 {
182  impl_ = new HMACImpl(secret, secret_length, hash_algorithm);
183 }
184 
185 HMAC::~HMAC() {
186  delete impl_;
187 }
188 
190 HMAC::getHashAlgorithm() const {
191  return (impl_->getHashAlgorithm());
192 }
193 
194 size_t
195 HMAC::getOutputLength() const {
196  return (impl_->getOutputLength());
197 }
198 
199 void
200 HMAC::update(const void* data, const size_t len) {
201  impl_->update(data, len);
202 }
203 
204 void
205 HMAC::sign(isc::util::OutputBuffer& result, size_t len) {
206  impl_->sign(result, len);
207 }
208 
209 void
210 HMAC::sign(void* result, size_t len) {
211  impl_->sign(result, len);
212 }
213 
214 std::vector<uint8_t>
215 HMAC::sign(size_t len) {
216  return impl_->sign(len);
217 }
218 
219 bool
220 HMAC::verify(const void* sig, const size_t len) {
221  return (impl_->verify(sig, len));
222 }
223 
224 } // namespace cryptolink
225 } // namespace isc
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.
The OutputBuffer class is a buffer abstraction for manipulating mutable data.
Definition: buffer.h:294
Defines the logger used by the top-level component of kea-dhcp-ddns.