"Fossies" - the Fresh Open Source Software Archive 
Member "tin-2.6.2/libcanlock/util/canlock.c" (23 Aug 2021, 14702 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.
1 /* ========================================================================== */
2 /* Copyright (c) 2017 Michael Baeuerle
3 *
4 * All rights reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, and/or sell copies of the Software, and to permit persons
11 * to whom the Software is furnished to do so, provided that the above
12 * copyright notice(s) and this permission notice appear in all copies of
13 * the Software and that both the above copyright notice(s) and this
14 * permission notice appear in supporting documentation.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
19 * OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
20 * HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY
21 * SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER
22 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
23 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
24 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25 *
26 * Except as contained in this notice, the name of a copyright holder
27 * shall not be used in advertising or otherwise to promote the sale, use
28 * or other dealings in this Software without prior written authorization
29 * of the copyright holder.
30 */
31
32 /* GNU autoconf */
33 #include <config.h>
34
35 /* C99 */
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 /* Local */
41 #include "canlock.h"
42
43
44 /* ========================================================================== */
45 /* Constants */
46
47 /*! Size of buffer for secret data */
48 #define SEC_DATA_SIZE_MAX (size_t) 1024
49
50
51 /* ========================================================================== */
52 /*! \brief Print program version information */
53
54 static void print_version(void)
55 {
56 const char* p = PACKAGE_STRING;
57
58 printf("%s\n", &p[3]);
59 printf("%s\n", "Command line frontend for libcanlock.");
60
61 return;
62 }
63
64
65 /* ========================================================================== */
66 /*! \brief Print help */
67
68 static void print_help(void)
69 {
70 const char* p = PACKAGE_NAME;
71
72 printf("Usage: %s %s\n", &p[3], "[options]\n" "Options:\n"
73 " -a scheme Use <scheme> as hash algorithm for -k and -l "
74 "options\n"
75 " (must be specified first)\n"
76 " -q Suppress output to stdout for -c and -o "
77 "options\n"
78 " (must be specified first)\n"
79 "The following options are mutually exclusive:\n"
80 " -c c-key,c-lock Check Cancel-Key <c-key> against "
81 "Cancel-Lock <c-lock>\n"
82 " -h Print this help message to stdout and exit\n"
83 " (must be the only option)\n"
84 " -k [uid]mid Get Cancel-Key for Message-ID <mid>\n"
85 " and an optional User-ID <uid>\n"
86 " (secret is read from stdin)\n"
87 " -l [uid]mid Get Cancel-Lock for Message-ID <mid>\n"
88 " and an optional User-ID <uid>\n"
89 " (secret is read from stdin)\n"
90 " -o Print memory overwrite info to stdout and exit\n"
91 " (must be the only option)\n"
92 " -v Print version information to stdout and exit\n"
93 " (must be the only option)\n"
94 "(See manual page for details)"
95 );
96
97 return;
98 }
99
100
101 /* ========================================================================== */
102 /*! \brief Check scheme for supported hash algorithm
103 *
104 * \param[in] scheme String with scheme in lowercase
105 *
106 * \return
107 * - Hash algorithm ID on success
108 * - \c CL_INVALID on error
109 */
110
111 static cl_hash_version get_hash(const char *scheme)
112 {
113 cl_hash_version hash = CL_INVALID;
114
115 if (!strcmp(scheme, "sha1")) { hash = CL_SHA1; }
116 else if (!strcmp(scheme, "sha224")) { hash = CL_SHA224; }
117 else if (!strcmp(scheme, "sha256")) { hash = CL_SHA256; }
118 else if (!strcmp(scheme, "sha384")) { hash = CL_SHA384; }
119 else if (!strcmp(scheme, "sha512")) { hash = CL_SHA512; }
120
121 if (CL_INVALID == hash)
122 {
123 fprintf(stderr, "%s\n", "Hash algorithm not supported");
124 }
125
126 return (hash);
127 }
128
129
130 /* ========================================================================== */
131 /*! \brief Read secret data from stdin
132 *
133 * \param[out] sec_size Pointer to size of secret data
134 * \param[out] buf_size Pointer to size of buffer
135 *
136 * Secret data is read until EOF.
137 * Hitting the buffer size limit \c SEC_DATA_SIZE_MAX is treated as an error.
138 *
139 * \attention
140 * The caller must not call \c free() for the returned pointer but should call
141 * \ref cl_clear_secret() instead.
142 *
143 * \return
144 * - Pointer to secret data on success
145 * - \c NULL on error (nothing was written to \e secsize and \e bufsize )
146 */
147
148 static unsigned char *get_secret(size_t *sec_size, size_t *buf_size)
149 {
150 static unsigned char buf[SEC_DATA_SIZE_MAX];
151 unsigned char *res = buf;
152 int rv = 0;
153 size_t i = 0;
154
155 while (EOF != rv)
156 {
157 if (SEC_DATA_SIZE_MAX <= i)
158 {
159 res = NULL;
160 break;
161 }
162 rv = fgetc(stdin);
163 if (EOF != rv) { buf[i++] = (unsigned char) rv; }
164 }
165 cl_clear_secret((void *) &rv, sizeof(int), sizeof(int));
166 if (NULL == res)
167 {
168 cl_clear_secret((void *) buf, SEC_DATA_SIZE_MAX, SEC_DATA_SIZE_MAX);
169 }
170 else
171 {
172 /* Return size of buffer and size of secret data */
173 *buf_size = SEC_DATA_SIZE_MAX;
174 *sec_size = i;
175 }
176
177 return (res);
178 }
179
180
181 /* ========================================================================== */
182 /*! \brief Execute request
183 *
184 * \param[in] hash Hash algorithm ID
185 * \param[in] quiet Suppress result on stdout for check operation
186 * \param[in] opt Pointer to option string
187 * \param[in] opt_value Pointer to option value string
188 *
189 * \attention
190 * The caller must ensure that \e opt and \e opt_val are not \c NULL .
191 *
192 * \return
193 * - 0 on success
194 * - -1 on error
195 */
196
197 static int exec_request(cl_hash_version hash, int quiet,
198 const char *opt, const char *opt_value)
199 {
200 int res = 0;
201 enum { UK, KEY, LOCK, CHECK, OMEM } op = UK;
202 unsigned char *sec = NULL;
203 size_t sec_size = 0, buf_size = 0;
204 const unsigned char *mid;
205 const char *out = NULL;
206 char *key, *key_string, *lock, *lock_string;
207 cl_hash_version key_hash, lock_hash;
208 int memtest = 1;
209
210 if (NULL == opt) { return (-1); }
211 if (strcmp(opt, "-o") && NULL == opt_value) { return (-1); }
212
213 if (!strcmp(opt, "-k")) { op = KEY; }
214 if (!strcmp(opt, "-l")) { op = LOCK; }
215 if (!strcmp(opt, "-c")) { op = CHECK; }
216 if (!strcmp(opt, "-o")) { op = OMEM; }
217 switch (op)
218 {
219 case KEY:
220 case LOCK:
221 /* Read secret data */
222 sec = get_secret(&sec_size, &buf_size);
223 if (NULL == sec) { res = -1; }
224 else
225 {
226 mid = (unsigned char *) opt_value;
227 if (KEY == op)
228 {
229 out = cl_get_key(hash, sec, sec_size, mid, strlen(opt_value));
230 }
231 else
232 {
233 out = cl_get_lock(hash, sec, sec_size, mid, strlen(opt_value));
234 }
235 /* Remove secret data from memory */
236 res = cl_clear_secret((void *) sec, sec_size, buf_size);
237 if (0 > res)
238 {
239 fprintf(stderr, "%s\n", "Failed to overwrite secret data (bug)");
240 res = -1;
241 }
242 else
243 {
244 if (0 < res)
245 {
246 fprintf(stderr, "%s\n",
247 "Warning: Overwriting secret data was not reliable");
248 }
249 printf("%s\n", out);
250 res = 0;
251 }
252 free((void *) out);
253 }
254 break;
255 case CHECK:
256 /* Split option value into key and lock part */
257 key = (char *) malloc(strlen(opt_value) + (size_t) 1);
258 if (NULL == key) { res = -1; }
259 else
260 {
261 strcpy(key, opt_value);
262 lock = strchr(key, (int) ',');
263 if (NULL == lock)
264 {
265 fprintf(stderr, "%s\n", "Field separator not found (bug)");
266 res = -1;
267 }
268 else { *lock++ = 0; }
269 /* Check for colon after scheme ("-a" option is ignored) */
270 if (NULL == strchr(key, (int) ':')
271 || NULL == strchr(lock, (int) ':'))
272 {
273 fprintf(stderr, "%s\n", "Colon missing after scheme");
274 res = -1;
275 }
276 else
277 {
278 /* Check whether key matches lock */
279 key_hash = cl_split(key, &key_string);
280 lock_hash = cl_split(lock, &lock_string);
281 if (CL_INVALID == key_hash || CL_INVALID == lock_hash)
282 {
283 fprintf(stderr, "%s\n", "Extracting scheme failed");
284 res = -1;
285 }
286 else
287 {
288 if (key_hash != lock_hash)
289 {
290 /* Different scheme */
291 if(!quiet) { printf("%s\n", "Scheme mismatch"); }
292 res = -1;
293 }
294 else
295 {
296 if(cl_verify(key_hash, key_string, lock_string))
297 {
298 if(!quiet) { printf("%s\n", "Mismatch"); }
299 res = -1;
300 }
301 else
302 {
303 if(!quiet) { printf("%s\n", "Good"); }
304 }
305 }
306 }
307 }
308 free((void *) key);
309 }
310 break;
311 case OMEM:
312 /* Check whether memory overwrite support is available */
313 if (cl_clear_secret((void *) &memtest, sizeof(int), sizeof(int)))
314 {
315 if(!quiet)
316 {
317 printf("%s\n", "Memory overwrite support not available");
318 }
319 res = -1;
320 }
321 else
322 {
323 /* Available */
324 if(!quiet) { printf("%s\n", "Memory overwrite support available"); }
325 }
326 break;
327 case UK:
328 default:
329 fprintf(stderr, "%s\n", "Unknown operation (bug)");
330 res = -1;
331 break;
332 }
333
334 return (res);
335 }
336
337
338 /* ========================================================================== */
339 /*! \brief CLI utility
340 *
341 * \param[in] argc Number of command line arguments
342 * \param[in] argv Array containing command line argument strings
343 *
344 * \return
345 * - \c EXIT_SUCCESS on success
346 * - \c EXIT_FAILURE on error
347 */
348
349 int main(int argc, char **argv)
350 {
351 int rv;
352 enum { OK, ERROR, ABORT } rv2 = ERROR;
353 unsigned int i;
354 char option = 0; /* Flag indicating option value will follow */
355 cl_hash_version hash = CL_SHA256; /* Mandatory algorithm as default */
356 int quiet = 0;
357 const char *opt = NULL;
358 const char *opt_value = NULL;
359
360 if (argc)
361 {
362 for (i = 1; i < (unsigned int) argc; i++)
363 {
364 if (option)
365 {
366 /* Process value of former option */
367 opt_value = argv[i];
368 if ('-' == opt_value[0])
369 {
370 fprintf(stderr, "%s\n", "Option value missing");
371 break;
372 }
373 /* Accept option value */
374 if (!strcmp(opt, "-a"))
375 {
376 hash = get_hash(opt_value);
377 if (CL_INVALID == hash)
378 {
379 break;
380 }
381 option = 0;
382 /* Additional option must follow */
383 }
384 else
385 {
386 rv2 = OK;
387 break;
388 }
389 }
390 if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version"))
391 {
392 /* Print version information and report success */
393 print_version();
394 rv2 = ABORT;
395 break;
396 }
397 else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help"))
398 {
399 /* Print help and report success */
400 print_help();
401 rv2 = ABORT;
402 break;
403 }
404 else if (!strcmp(argv[i], "-q"))
405 {
406 /* The "-c" or "-o" option should not print the result to stdout */
407 quiet = 1;
408 /* Additional option must follow */
409 }
410 else if (!strcmp(argv[i], "-o"))
411 {
412 opt = argv[i];
413 rv2 = OK;
414 break;
415 }
416 else if (!strcmp(argv[i], "-a")
417 || !strcmp(argv[i], "-c")
418 || !strcmp(argv[i], "-k")
419 || !strcmp(argv[i], "-l"))
420 {
421 /* Option value must follow */
422 opt = argv[i];
423 option = 1;
424 }
425 else if ('-' == argv[i][0])
426 {
427 /* Unknown option */
428 fprintf(stderr, "%s\n", "Unknown option");
429 break;
430 }
431 }
432 if (ERROR == rv2)
433 {
434 fprintf(stderr, "%s\n", "Use '-h' or read the man page for help");
435 }
436 }
437
438 /* Check options */
439 switch (rv2)
440 {
441 case OK:
442 {
443 /* Check option value */
444 if (strcmp(opt, "-o") && NULL == opt_value)
445 {
446 fprintf(stderr, "%s\n", "Option value missing (bug)");
447 rv = EXIT_FAILURE;
448 break;
449 }
450 else if (!strcmp(opt, "-c"))
451 {
452 if (NULL == strchr(opt_value, (int) ','))
453 {
454 fprintf(stderr, "%s\n", "Comma missing in option value");
455 rv = EXIT_FAILURE;
456 break;
457 }
458 }
459 /* Execute requested operation */
460 if (exec_request(hash, quiet, opt, opt_value)) { rv = EXIT_FAILURE; }
461 else { rv = EXIT_SUCCESS; }
462 break;
463 }
464 case ABORT:
465 {
466 /* Nothing more to do, but no error */
467 rv = EXIT_SUCCESS;
468 break;
469 }
470 case ERROR:
471 default:
472 {
473 /* Error */
474 rv = EXIT_FAILURE;
475 break;
476 }
477 }
478
479 exit(rv);
480 }
481
482
483 /* EOF */