YARP
Yet Another Robot Platform
AuthHMAC.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2020 Istituto Italiano di Tecnologia (IIT)
3  * Copyright (C) 2010 Daniel Krieg <krieg@fias.uni-frankfurt.de>
4  * All rights reserved.
5  *
6  * This software may be modified and distributed under the terms of the
7  * BSD-3-Clause license. See the accompanying LICENSE file for details.
8  */
9 
10 #include <yarp/os/impl/AuthHMAC.h>
11 
12 #include <yarp/os/Bytes.h>
13 #include <yarp/os/Network.h>
14 #include <yarp/os/Property.h>
15 #include <yarp/os/ResourceFinder.h>
18 
19 #include <cstdio>
20 #include <cstdlib>
21 #include <cstring>
22 #include <ctime>
23 #include <random>
24 #include <string>
25 
26 namespace {
27 YARP_OS_LOG_COMPONENT(AUTHHMAC, "yarp.os.impl.AuthHMAC")
28 } // namespace
29 
30 void show_hmac_debug(unsigned char* hex, unsigned int length, const std::string& context)
31 {
32  char* buf;
33  int off = context.length();
34  buf = new char[length * 3 + off + 2];
35  strcpy(buf, context.c_str());
36  for (unsigned int i = 0; i < length; i++) {
37  sprintf(&(buf[off + i * 3]), "%X ", hex[i]);
38  }
39  yCDebug(AUTHHMAC, "%s\n", buf);
40  delete[] buf;
41 }
42 
43 using namespace yarp::os::impl;
44 using namespace yarp::os;
45 
47  authentication_enabled(false)
48 {
49  memset(&context, 0, sizeof(HMAC_CONTEXT));
50  static bool auth_warning_shown = false;
51  if (auth_warning_shown) {
52  // If the warning was already shown, we have nothing to do.
53  // return as soon as possible
54  return;
55  }
56  std::string key;
58  std::string fname;
59  Network::lock();
62  fname = rf.findFile("auth.conf", opt);
64 
65 
66  if (fname.empty()) {
67  yCDebug(AUTHHMAC, "Cannot find auth.conf file. Authentication disabled.\n");
68  auth_warning_shown = true;
69  return;
70  }
71 
72  Property config;
73  config.fromConfigFile(fname);
74  Bottle group = config.findGroup("AUTH");
75 
76  if (group.isNull()) {
77  yCWarning(AUTHHMAC, "No \"AUTH\" group found in auth.conf file. Authentication disabled.\n");
78  auth_warning_shown = true;
79  return;
80  }
81 
82  key = group.find("key").asString();
83  if (!(key.length() > 0)) {
84  yCWarning(AUTHHMAC, "No \"key\" found in \"AUTH\" group in auth.conf file. Authentication disabled.\n");
85  auth_warning_shown = true;
86  return;
87  }
88 
89  size_t key_len = key.length();
90  auto* tmp = new unsigned char[key_len];
91  strcpy(reinterpret_cast<char*>(tmp), key.c_str());
92  HMAC_INIT(&context, tmp, static_cast<unsigned int>(key_len));
93  delete[] tmp;
94  srand(static_cast<unsigned>(time(nullptr)));
95 
96  if (!authentication_enabled) {
97  yCInfo(AUTHHMAC, "Authentication enabled.\n");
98  authentication_enabled = true;
99  }
100 }
101 
102 
103 bool AuthHMAC::authSource(InputStream* streamIn, OutputStream* streamOut)
104 {
105 
106  if (!authentication_enabled) {
107  return true;
108  }
109 
110  /* ---------------
111  * 3-way auth
112  * Port A
113  * ---------------
114  */
115 
116  unsigned char nonce1[NONCE_LEN];
117  unsigned char nonce2[NONCE_LEN];
118  unsigned char nonce3[NONCE_LEN];
119 
120  unsigned char mac[DIGEST_SIZE];
121  unsigned char mac_check[DIGEST_SIZE];
122 
123  /* ---------------
124  * Send first msg: A->B
125  */
126  fill_nonce(nonce1);
127  HMAC_REINIT(&context);
128  HMAC_UPDATE(&context, nonce1, NONCE_LEN);
129  HMAC_FINAL(&context, mac, DIGEST_SIZE);
130  if (!send_hmac(streamOut, nonce1, mac)) {
131  return false;
132  }
133 
134  /* ---------------
135  * Receive and check second msg: B->A
136  */
137  if (!receive_hmac(streamIn, nonce2, mac)) {
138  return false;
139  }
140 
141  HMAC_REINIT(&context);
142  HMAC_UPDATE(&context, nonce1, NONCE_LEN);
143  HMAC_UPDATE(&context, nonce2, NONCE_LEN);
144  HMAC_FINAL(&context, mac_check, DIGEST_SIZE);
145  if (!check_hmac(mac, mac_check)) {
146  return false;
147  }
148  /* Authentication of B successful */
149 
150 
151  /* ---------------
152  * Send third msg: A->B
153  */
154  fill_nonce(nonce3);
155  HMAC_REINIT(&context);
156  HMAC_UPDATE(&context, nonce1, NONCE_LEN);
157  HMAC_UPDATE(&context, nonce2, NONCE_LEN);
158  HMAC_UPDATE(&context, nonce3, NONCE_LEN);
159  HMAC_FINAL(&context, mac, DIGEST_SIZE);
160  return send_hmac(streamOut, nonce3, mac);
161 }
162 bool AuthHMAC::authDest(InputStream* streamIn, OutputStream* streamOut)
163 {
164 
165  if (!authentication_enabled) {
166  return true;
167  }
168 
169  /* ---------------
170  * 3-way auth
171  * Port B
172  * ---------------
173  */
174 
175  unsigned char nonce1[NONCE_LEN];
176  unsigned char nonce2[NONCE_LEN];
177  unsigned char nonce3[NONCE_LEN];
178 
179  unsigned char mac[DIGEST_SIZE];
180  unsigned char mac_check[DIGEST_SIZE];
181 
182  /* ---------------
183  * Receive and check first msg: A->B
184  */
185  if (!receive_hmac(streamIn, nonce1, mac)) {
186  return false;
187  }
188  HMAC_REINIT(&context);
189  HMAC_UPDATE(&context, nonce1, NONCE_LEN);
190  HMAC_FINAL(&context, mac_check, DIGEST_SIZE);
191  if (!check_hmac(mac, mac_check)) {
192  return false;
193  }
194 
195  /* ---------------
196  * Send second msg: B->A
197  */
198  fill_nonce(nonce2);
199  HMAC_REINIT(&context);
200  HMAC_UPDATE(&context, nonce1, NONCE_LEN);
201  HMAC_UPDATE(&context, nonce2, NONCE_LEN);
202  HMAC_FINAL(&context, mac, DIGEST_SIZE);
203  if (!send_hmac(streamOut, nonce2, mac)) {
204  return false;
205  }
206 
207 
208  /* ---------------
209  * Receive and check third msg: A->B
210  */
211  if (!receive_hmac(streamIn, nonce3, mac)) {
212  return false;
213  }
214  HMAC_REINIT(&context);
215  HMAC_UPDATE(&context, nonce1, NONCE_LEN);
216  HMAC_UPDATE(&context, nonce2, NONCE_LEN);
217  HMAC_UPDATE(&context, nonce3, NONCE_LEN);
218  HMAC_FINAL(&context, mac_check, DIGEST_SIZE);
219  if (!check_hmac(mac, mac_check)) {
220  return false;
221  }
222  /* Authentication of A successful */
223 
224  return true;
225 }
226 
227 
228 bool AuthHMAC::send_hmac(OutputStream* stream, unsigned char* nonce, unsigned char* mac)
229 {
230  Bytes nonce_bytes(reinterpret_cast<char*>(nonce), NONCE_LEN);
231  Bytes mac_bytes(reinterpret_cast<char*>(mac), DIGEST_SIZE);
232  stream->write(nonce_bytes);
233  stream->write(mac_bytes);
234 
235  show_hmac_debug(nonce, NONCE_LEN, "send nonce ");
236  show_hmac_debug(mac, DIGEST_SIZE, "send digest ");
237 
238  return stream->isOk();
239 }
240 
241 bool AuthHMAC::receive_hmac(InputStream* stream, unsigned char* nonce, unsigned char* mac)
242 {
243  Bytes nonce_bytes(reinterpret_cast<char*>(nonce), NONCE_LEN);
244  Bytes mac_bytes(reinterpret_cast<char*>(mac), DIGEST_SIZE);
245  stream->read(nonce_bytes);
246  stream->read(mac_bytes);
247 
248  show_hmac_debug(nonce, NONCE_LEN, "got nonce ");
249  show_hmac_debug(mac, DIGEST_SIZE, "got digest ");
250 
251  return stream->isOk();
252 }
253 
254 bool AuthHMAC::check_hmac(unsigned char* mac, unsigned char* mac_check)
255 {
256  int cmp = memcmp(mac, mac_check, DIGEST_SIZE);
257 
258  std::string check = "digest check ";
259  if (cmp == 0) {
260  check += "successful";
261  } else {
262  check += "FAILED";
263  }
264  show_hmac_debug(mac_check, DIGEST_SIZE, check);
265 
266  return (cmp == 0);
267 }
268 
269 
270 void AuthHMAC::fill_nonce(unsigned char* nonce)
271 {
272  std::random_device rd;
273  std::mt19937 mt(rd());
274  std::uniform_int_distribution<int> dist(0, 255);
275  for (unsigned int i = 0; i < NONCE_LEN; i++) {
276  nonce[i] = static_cast<unsigned char>(dist(mt));
277  }
278 }
yarp::os::Bottle
A simple collection of objects that can be described and transmitted in a portable way.
Definition: Bottle.h:73
Network.h
DIGEST_SIZE
#define DIGEST_SIZE
Definition: AuthHMAC.h:18
yCWarning
#define yCWarning(component,...)
Definition: LogComponent.h:146
yarp::os::ResourceFinderOptions::ShowNone
@ ShowNone
Definition: ResourceFinderOptions.h:61
yarp::os::NetworkBase::lock
static void lock()
Call wait() on a global mutual-exclusion semaphore allocated by YARP.
Definition: Network.cpp:1462
yarp::os::OutputStream::write
virtual void write(char ch)
Write a single byte to the stream.
Definition: OutputStream.cpp:17
yarp::os::ResourceFinderOptions
These options are loosely based on http://wiki.icub.org/wiki/YARP_ResourceFinder.
Definition: ResourceFinderOptions.h:28
yarp::os::OutputStream
Simple specification of the minimum functions needed from output streams.
Definition: OutputStream.h:25
show_hmac_debug
void show_hmac_debug(unsigned char *hex, unsigned int length, const std::string &context)
Definition: AuthHMAC.cpp:30
LogComponent.h
yarp::os::Bottle::find
Value & find(const std::string &key) const override
Gets a value corresponding to a given keyword.
Definition: Bottle.cpp:290
yarp::os::impl::AuthHMAC::authSource
bool authSource(yarp::os::InputStream *streamIn, yarp::os::OutputStream *streamOut)
Definition: AuthHMAC.cpp:103
NONCE_LEN
#define NONCE_LEN
Definition: AuthHMAC.h:24
AuthHMAC.h
HMAC_UPDATE
#define HMAC_UPDATE
Definition: AuthHMAC.h:22
yarp::os::ResourceFinder::findFile
std::string findFile(const std::string &name)
Find the full path to a file.
Definition: ResourceFinder.cpp:847
HMAC_FINAL
#define HMAC_FINAL
Definition: AuthHMAC.h:23
Property.h
yarp::os::Value::asString
virtual std::string asString() const
Get string value.
Definition: Value.cpp:237
yarp::os::impl::AuthHMAC::AuthHMAC
AuthHMAC()
Constructor.
Definition: AuthHMAC.cpp:46
NameClient.h
yarp::os::ResourceFinderOptions::messageFilter
MessageFilter messageFilter
Definition: ResourceFinderOptions.h:72
yarp::os::InputStream::isOk
virtual bool isOk() const =0
Check if the stream is ok or in an error state.
yarp::os::Bytes
A simple abstraction for a block of bytes.
Definition: Bytes.h:28
yarp::os::Bottle::isNull
bool isNull() const override
Checks if the object is invalid.
Definition: Bottle.cpp:373
yarp::os::ResourceFinder::getResourceFinderSingleton
static ResourceFinder & getResourceFinderSingleton()
Access a ResourceFinder singleton whose lifetime will match that of the YARP library.
Definition: ResourceFinder.cpp:976
yarp::os::OutputStream::isOk
virtual bool isOk() const =0
Check if the stream is ok or in an error state.
yarp::os::Property::fromConfigFile
bool fromConfigFile(const std::string &fname, bool wipe=true)
Interprets a file as a list of properties.
Definition: Property.cpp:1081
yCInfo
#define yCInfo(component,...)
Definition: LogComponent.h:135
yarp::os::InputStream::read
virtual int read()
Read and return a single byte.
Definition: InputStream.cpp:23
yarp::os
An interface to the operating system, including Port based communication.
Definition: AbstractCarrier.h:17
yCDebug
#define yCDebug(component,...)
Definition: LogComponent.h:112
HMAC_INIT
#define HMAC_INIT
Definition: AuthHMAC.h:20
yarp::os::NetworkBase::unlock
static void unlock()
Call post() on a global mutual-exclusion semaphore allocated by YARP.
Definition: Network.cpp:1467
Bytes.h
yarp::os::Property::findGroup
Bottle & findGroup(const std::string &key) const override
Gets a list corresponding to a given keyword.
Definition: Property.cpp:1125
HMAC_REINIT
#define HMAC_REINIT
Definition: AuthHMAC.h:21
yarp::os::impl::AuthHMAC::authDest
bool authDest(yarp::os::InputStream *streamIn, yarp::os::OutputStream *streamOut)
Definition: AuthHMAC.cpp:162
HMAC_CONTEXT
#define HMAC_CONTEXT
Definition: AuthHMAC.h:19
yarp::os::InputStream
Simple specification of the minimum functions needed from input streams.
Definition: InputStream.h:29
YARP_OS_LOG_COMPONENT
#define YARP_OS_LOG_COMPONENT(name, name_string)
Definition: LogComponent.h:37
yarp::os::impl
The components from which ports and connections are built.
ResourceFinder.h
yarp::os::Property
A class for storing options and configuration information.
Definition: Property.h:37
yarp::os::ResourceFinder
Helper class for finding config files and other external resources.
Definition: ResourceFinder.h:33