"Fossies" - the Fresh Open Source Software Archive 
Member "tin-2.6.2/libcanlock/src/canlock.c" (23 Aug 2021, 11731 Bytes) of package /linux/misc/tin-2.6.2.tar.xz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "canlock.c" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
2.4.5_vs_2.6.0.
1 /*
2 * COPYRIGHT AND PERMISSION NOTICE
3 *
4 * Copyright (c) 2017 Dennis Preiser
5 * Copyright (c) 2003 G.J. Andruk
6 *
7 * All rights reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining
10 * a copy of this software and associated documentation files (the
11 * "Software"), to deal in the Software without restriction, including
12 * without limitation the rights to use, copy, modify, merge, publish,
13 * distribute, and/or sell copies of the Software, and to permit persons
14 * to whom the Software is furnished to do so, provided that the above
15 * copyright notice(s) and this permission notice appear in all copies of
16 * the Software and that both the above copyright notice(s) and this
17 * permission notice appear in supporting documentation.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
22 * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY
24 * SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER
25 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
26 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
27 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
28 *
29 * Except as contained in this notice, the name of a copyright holder
30 * shall not be used in advertising or otherwise to promote the sale, use
31 * or other dealings in this Software without prior written authorization
32 * of the copyright holder.
33 */
34
35 /* C99 */
36 #include <ctype.h>
37 #include <limits.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include "base64.h"
42
43 /* Local */
44 #include "sha.h"
45 #include "canlock.h"
46
47
48 /* Map external hash type 'cl_hash_version' to local SHA implementation */
49 static enum SHAversion which_cl_hash(int which_hash)
50 {
51 switch (which_hash)
52 {
53 case CL_SHA1:
54 return SHA1;
55 case CL_SHA224:
56 return SHA224;
57 case CL_SHA384:
58 return SHA384;
59 case CL_SHA512:
60 return SHA512;
61
62 /* Mandatory algorithm */
63 case CL_SHA256:
64 default:
65 return SHA256;
66 }
67 }
68
69
70 /*
71 * Portable replacement for 'strdup()'
72 *
73 * 'strdup()' requires SUSv2, XSI extension or POSIX.1-2008
74 * https://pubs.opengroup.org/onlinepubs/007908799/xsh/strdup.html
75 * https://pubs.opengroup.org/onlinepubs/009695399/functions/strdup.html
76 * https://pubs.opengroup.org/onlinepubs/9699919799/functions/strdup.html
77 *
78 * Note:
79 * 'malloc()' already gives the correct return (and 'errno') values required by
80 * POSIX.
81 */
82 static char *my_strdup(const char *s)
83 {
84 char *res;
85 size_t len;
86
87 len = strlen(s);
88 res = (char *) malloc(len + (size_t) 1);
89 if (NULL != res)
90 {
91 strncpy(res, s, len);
92 res[len] = 0;
93 }
94
95 return res;
96 }
97
98
99 /*
100 * Extract a <c-lock-string> or <c-key-string> element respectively from 'key'
101 * (that is, with the <scheme>: prefix removed)
102 *
103 * The <scheme> is written to 'type' on success, else empty string on failure.
104 * The caller must ensure that the provided buffer is large enough.
105 *
106 * Returns a malloc()'d buffer on success, that the caller will need to free().
107 * Returns NULL (on failure).
108 */
109 #if ! CL_API_V2
110 static
111 #endif /* CL_API_V2 */
112 char *lock_strip_alpha(char *key, char *type)
113 {
114 char *ret;
115 int offset;
116
117 /* Strip scheme and write it to 'type' */
118 do
119 {
120 *type = (char) tolower((int) (unsigned char) *key);
121 type++;
122 key++;
123 } while (*key && *key != ':');
124 *type = '\0';
125
126 key++; /* Skip colon */
127
128 /* Copy <c-lock-string> or <c-key-string> respectively */
129 ret = my_strdup(key);
130 if (NULL != ret)
131 {
132 /*
133 * Strip potential trailing <clue-string> element
134 * (that is, a :xx suffix is removed).
135 *
136 * Note:
137 * This element was removed from an early draft, but could still be
138 * present.
139 */
140 offset = 0;
141 while (ret[offset] && ret[offset] != ':')
142 offset++;
143 ret[offset] = '\0';
144 }
145 return ret;
146 }
147
148
149 #if CL_API_V2
150 char *lock_strip(char *key, char *type)
151 {
152 return lock_strip_alpha(key, type);
153 }
154 #endif /* CL_API_V2 */
155
156
157 /*
158 * Split a <c-lock> or <c-key> element respectively
159 *
160 * 'input' is split on the first colon into <scheme> and <c-lock-string> or
161 * <c-key-string> elements respectively.
162 *
163 * If scheme is supported, the corresponding ID is returned.
164 *
165 * A pointer to <c-lock-string> or <c-key-string> respectively is written to
166 * the location pointed to by 'klstring' (no memory is allocated, the address
167 * points to the memory used for 'input').
168 *
169 * Returns the hash algorithm ID for scheme (on success).
170 * Returns CL_INVALID (on failure, NULL was written to 'klstring' in this case).
171 */
172 int cl_split(char *input, char **klstring)
173 {
174 int hash = CL_INVALID;
175 char *scheme, *junk;
176
177 *klstring = strchr(input, (int) ':');
178 if (NULL != *klstring)
179 {
180 (*klstring)++; /* Skip colon */
181 scheme = (char *) malloc(strlen(input) + (size_t) 1);
182 if (NULL == scheme) { *klstring = NULL; }
183 else
184 {
185 junk = lock_strip_alpha(input, scheme);
186 if (NULL != junk)
187 {
188 if (!strcmp(scheme, "sha1")) { hash = CL_SHA1; }
189 else if (!strcmp(scheme, "sha224")) { hash = CL_SHA224; }
190 else if (!strcmp(scheme, "sha256")) { hash = CL_SHA256; }
191 else if (!strcmp(scheme, "sha384")) { hash = CL_SHA384; }
192 else if (!strcmp(scheme, "sha512")) { hash = CL_SHA512; }
193 free((void *) junk);
194 }
195 free((void *) scheme);
196 }
197 }
198 return hash;
199 }
200
201
202 #if CL_API_V2
203 /*
204 * Generate a SHA1 cancel key
205 * Returns a malloc()'d buffer that the caller will need to free() (on success).
206 * Returns NULL (on failure).
207 */
208 char *sha_key(const unsigned char *secret, size_t seclen,
209 const unsigned char *message, size_t msglen)
210 {
211 return cl_get_key(CL_SHA1, secret, seclen, message, msglen);
212 }
213 #endif /* CL_API_V2 */
214
215
216 /*
217 * Generate a cancel key
218 * Returns a malloc()'d buffer that the caller will need to free() (on success).
219 * Returns NULL (on failure).
220 */
221 char *cl_get_key(int which_hash, const unsigned char *secret, size_t seclen,
222 const unsigned char *message, size_t msglen)
223 {
224 char *cankey[1], *tmp;
225 const char *scheme;
226 enum SHAversion which_sha;
227 size_t keysize, scheme_len;
228 uint8_t hmacbuff[USHAMaxHashSize];
229
230 which_sha = which_cl_hash(which_hash);
231
232 /* Ensure that size data from external caller can be represented as 'int' */
233 if ((size_t) INT_MAX < msglen || (size_t) INT_MAX < seclen)
234 return NULL;
235
236 if (RFC2104Hmac(which_sha, message, (int) msglen, secret, (int) seclen,
237 hmacbuff)
238 != shaSuccess)
239 return NULL;
240
241 if (!(keysize = base64_encode(hmacbuff, USHAHashSize(which_sha), cankey)))
242 return NULL;
243
244 switch (which_sha)
245 {
246 case SHA1:
247 scheme = "sha1:";
248 break;
249 case SHA224:
250 scheme = "sha224:";
251 break;
252 case SHA256:
253 scheme = "sha256:";
254 break;
255 case SHA384:
256 scheme = "sha384:";
257 break;
258 case SHA512:
259 scheme = "sha512:";
260 break;
261 default:
262 return NULL;
263 }
264
265 scheme_len = strlen(scheme);
266
267 tmp = (char *) realloc((void *) *cankey, keysize + scheme_len + 1);
268 if (NULL != tmp) { *cankey = tmp; }
269 else
270 {
271 free((void *) *cankey);
272 return NULL;
273 }
274
275 memmove((void *) (*cankey + scheme_len), (void *) *cankey, keysize + 1);
276 strncpy(*cankey, scheme, scheme_len);
277 return (*cankey);
278 }
279
280
281 #if CL_API_V2
282 /*
283 * Generate a SHA1 cancel lock
284 * Returns a malloc()'d buffer that the caller will need to free() (on success).
285 * Returns NULL (on failure).
286 */
287 char *sha_lock(const unsigned char *secret, size_t seclen,
288 const unsigned char *message, size_t msglen)
289 {
290 return cl_get_lock(CL_SHA1, secret, seclen, message, msglen);
291 }
292 #endif /* CL_API_V2 */
293
294
295 /*
296 * Generate cancel lock
297 * Returns a malloc()'d buffer that the caller will need to free() (on success).
298 * Returns NULL (on failure).
299 */
300 char *cl_get_lock(int which_hash, const unsigned char *secret, size_t seclen,
301 const unsigned char *message, size_t msglen)
302 {
303 USHAContext hash_ctx;
304 char *canlock[1], *tmp, *junk;
305 const char *scheme;
306 enum SHAversion which_sha;
307 size_t hash_size, locksize, scheme_len;
308 uint8_t *cankey, hmacbuff[USHAMaxHashSize];
309
310 which_sha = which_cl_hash(which_hash);
311
312 /* The function 'USHAHashSize()' never returns negative values */
313 hash_size = (size_t) USHAHashSize(which_sha);
314
315 if (!(tmp = cl_get_key(which_hash, secret, seclen, message, msglen)))
316 return NULL;
317
318 if (!(junk = malloc(hash_size + 1)))
319 {
320 free(tmp);
321 return NULL;
322 }
323
324 cankey = (unsigned char *) lock_strip_alpha(tmp, junk);
325
326 free(tmp);
327 free(junk);
328
329 if (USHAReset(&hash_ctx, which_sha) != shaSuccess)
330 {
331 free(cankey);
332 return NULL;
333 }
334
335 if (USHAInput(&hash_ctx, cankey, (unsigned int) strlen((char *) cankey))
336 != shaSuccess)
337 {
338 free(cankey);
339 return NULL;
340 }
341
342 free(cankey);
343
344 if (USHAResult(&hash_ctx, hmacbuff) != shaSuccess)
345 return NULL;
346
347 if (!(locksize = base64_encode(hmacbuff, (int) hash_size, canlock)))
348 return NULL;
349
350 switch (which_sha)
351 {
352 case SHA1:
353 scheme = "sha1:";
354 break;
355 case SHA224:
356 scheme = "sha224:";
357 break;
358 case SHA256:
359 scheme = "sha256:";
360 break;
361 case SHA384:
362 scheme = "sha384:";
363 break;
364 case SHA512:
365 scheme = "sha512:";
366 break;
367 default:
368 return NULL;
369 }
370
371 scheme_len = strlen(scheme);
372
373 tmp = (char *) realloc((void *) *canlock, locksize + scheme_len + 1);
374 if (NULL != tmp) { *canlock = tmp; }
375 else
376 {
377 free((void *) *canlock);
378 return NULL;
379 }
380
381 memmove((void *) (*canlock + scheme_len), (void *) *canlock, locksize + 1);
382 strncpy(*canlock, scheme, scheme_len);
383 return (*canlock);
384 }
385
386
387 #if CL_API_V2
388 /*
389 * Verify a SHA1 cancel key against a cancel lock
390 * Returns 0 on success, nonzero on failure.
391 */
392 int sha_verify(const char *key, const char *lock)
393 {
394 return cl_verify(CL_SHA1, key, lock);
395 }
396 #endif /* CL_API_V2 */
397
398
399 /*
400 * Verify a cancel key against a cancel lock
401 * Returns 0 on success, nonzero on failure.
402 */
403 int cl_verify(int which_hash, const char *key, const char *lock)
404 {
405 int res;
406 USHAContext hash_ctx;
407 char *templock[1];
408 enum SHAversion which_sha;
409 size_t key_size, hash_size;
410 uint8_t hashbuff[USHAMaxHashSize];
411
412 /* Defeat the fallback to SHA256 default */
413 if (CL_INVALID == which_hash)
414 return -1;
415
416 /*
417 * Ensure that key length is supported
418 * Currently the maximum length is for base64 encoded SHA512: 88
419 * Theoretical limit: UINT_MAX
420 * (must always be representable as 'unsigned int')
421 */
422 key_size = strlen(key);
423 if ((size_t) 88 < key_size)
424 return -1;
425
426 which_sha = which_cl_hash(which_hash);
427
428 /* The function 'USHAHashSize()' never returns negative values */
429 hash_size = (size_t) USHAHashSize(which_sha);
430
431 if (USHAReset(&hash_ctx, which_sha) != shaSuccess)
432 return -1;
433
434 if (USHAInput(&hash_ctx, (const uint8_t *) key, (unsigned int) key_size)
435 != shaSuccess)
436 return -1;
437
438 if (USHAResult(&hash_ctx, hashbuff) != shaSuccess)
439 return -1;
440
441 if (!base64_encode(hashbuff, (int) hash_size, templock))
442 return -1;
443
444 res = strcmp(*templock, lock);
445 free((void*) *templock);
446
447 return res;
448 }