OpenVPN 3 Core Library
Loading...
Searching...
No Matches
mac.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12// Wrap the OpenSSL HMAC API defined in <openssl/hmac.h> so
13// that it can be used as part of the crypto layer of the OpenVPN core.
14
15#pragma once
16
17#include <string>
18
19/* The HMAC_* methods are deprecated in OpenSSL 3.0 and the EVP_MAC methods
20 * do no exist in OpenSSL 1.1 yet. So use two distinct implementations */
21#if OPENSSL_VERSION_NUMBER < 0x30000000L
23#else
24
28
29#include <openssl/params.h>
30
31
32namespace openvpn::OpenSSLCrypto {
33class HMACContext
34{
35 HMACContext(const HMACContext &) = delete;
36 HMACContext &operator=(const HMACContext &) = delete;
37
38 public:
40 {
41 erase();
42 ctx = rhs.ctx;
43 rhs.ctx = nullptr;
44 return *this;
45 }
46
47 OPENVPN_SIMPLE_EXCEPTION(openssl_mac_uninitialized);
48 OPENVPN_EXCEPTION(openssl_mac_error);
49
50 enum
51 {
52 MAX_HMAC_SIZE = EVP_MAX_MD_SIZE
53 };
54
55 HMACContext() = default;
56
57 HMACContext(const CryptoAlgs::Type digest, const unsigned char *key, const size_t key_size)
58 {
59 init(digest, key, key_size);
60 }
61
63 {
64 erase();
65 }
66
67 void init(const CryptoAlgs::Type digest, const unsigned char *key, const size_t key_size)
68 {
69 erase();
70 EVP_MAC *hmac = EVP_MAC_fetch(NULL, "HMAC", NULL);
71 ctx = EVP_MAC_CTX_new(hmac);
72 EVP_MAC_free(hmac);
73
74 /* Save key since the caller might clear it */
75 std::memcpy(this->key, key, key_size);
76
77 /* Lookup/setting of parameters in OpenSSL 3.0 are string based */
78 /* The OSSL_PARAM_construct_utf8_string needs a non const str even
79 * though it does not modify the string */
80 params[0] = OSSL_PARAM_construct_utf8_string("digest", const_cast<char *>(CryptoAlgs::name(digest)), 0);
81 params[1] = OSSL_PARAM_construct_octet_string("key", this->key, key_size);
82 params[2] = OSSL_PARAM_construct_end();
83
84 if (!EVP_MAC_init(ctx, NULL, 0, params))
85 {
87 EVP_MAC_CTX_free(ctx);
88 ctx = nullptr;
89 throw openssl_mac_error("EVP_MAC_init (init)");
90 }
91 }
92
93 void reset()
94 {
96 if (!EVP_MAC_init(ctx, nullptr, 0, params))
97 {
99 throw openssl_mac_error("EVP_HMAC_Init (reset)");
100 }
101 }
102
103
104 void update(const unsigned char *in, const size_t size)
105 {
107
108 if (!EVP_MAC_update(ctx, in, size))
109 {
111 throw openssl_mac_error("EVP_MAC_Update");
112 }
113 }
114
115 /* TODO: This function currently assumes that out has a length of MAX_HMAC_SIZE */
116 size_t final(unsigned char *out)
117 {
119 size_t outlen;
120 if (!EVP_MAC_final(ctx, out, &outlen, MAX_HMAC_SIZE))
121 {
123 throw openssl_mac_error("HMAC_Final");
124 }
125 return outlen;
126 }
127
128 size_t size() const
129 {
131 return size_();
132 }
133
134 bool is_initialized() const
135 {
136 return ctx != nullptr;
137 }
138
139 private:
140 void erase()
141 {
142 EVP_MAC_CTX_free(ctx);
143 ctx = nullptr;
144 }
145
146 size_t size_() const
147 {
148 return EVP_MAC_CTX_get_mac_size(ctx);
149 }
150
151 void check_initialized() const
152 {
153#ifdef OPENVPN_ENABLE_ASSERT
154 if (!ctx)
155 throw openssl_mac_uninitialized();
156#endif
157 }
158
159 OSSL_PARAM params[3];
160 uint8_t key[EVP_MAX_MD_SIZE];
161 EVP_MAC_CTX *ctx = nullptr;
162};
163} // namespace openvpn::OpenSSLCrypto
164
165#endif
void update(const unsigned char *in, const size_t size)
void init(const CryptoAlgs::Type digest, const unsigned char *key, const size_t key_size)
HMACContext & operator=(const HMACContext &)=delete
#define OPENVPN_SIMPLE_EXCEPTION(C)
Definition exception.hpp:75
#define OPENVPN_EXCEPTION(C)
const char * name(const KeyDerivation kd)
void openssl_clear_error_stack()
Definition error.hpp:247
static std::stringstream out
Definition test_path.cpp:10