2 * Copyright (C) 2017 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 #include <crypto/hashers/hasher.h>
20 #include <utils/debug.h>
28 static bool log_to_stderr
= TRUE
;
29 static bool log_to_syslog
= TRUE
;
30 static level_t default_loglevel
= 1;
32 /* global variables */
38 * logging function for tpm_extendpcr
40 static void tpm_extendpcr_dbg(debug_t group
, level_t level
, char *fmt
, ...)
43 char *current
= buffer
, *next
;
46 if (level
<= default_loglevel
)
51 vfprintf(stderr
, fmt
, args
);
53 fprintf(stderr
, "\n");
57 /* write in memory buffer first */
59 vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
62 /* do a syslog with every line */
65 next
= strchr(current
, '\n');
70 syslog(LOG_INFO
, "%s\n", current
);
78 * Initialize logging to stderr/syslog
80 static void init_log(const char *program
)
82 dbg
= tpm_extendpcr_dbg
;
90 openlog(program
, LOG_CONS
| LOG_NDELAY
| LOG_PID
, LOG_AUTHPRIV
);
95 * @brief exit tpm_extendpcr
97 * @param status 0 = OK, -1 = general discomfort
99 static void exit_tpm_extendpcr(err_t message
, ...)
105 chunk_free(&pcr_value
);
107 /* print any error message to stderr */
108 if (message
!= NULL
&& *message
!= '\0')
113 va_start(args
, message
);
114 vsnprintf(m
, sizeof(m
), message
, args
);
117 fprintf(stderr
, "tpm_extendpcr error: %s\n", m
);
125 * @brief prints the usage of the program to the stderr output
127 * If message is set, program is exited with 1 (error)
128 * @param message message in case of an error
130 static void usage(const char *message
)
133 "Usage: tpm_extendpcr [--alg <name>] --pcr <nr> --digest <hex>|--in"
135 " [--hash] [--out <file>] [--quiet]"
136 " [--debug <level>]\n"
137 " tpm_extendpcr --help\n"
140 " --alg (-a) hash algorithm (sha1|sha256)\n"
141 " --pcr (-p) platform configuration register (0..23)\n"
142 " --digest (-d) digest in hex format to be extended\n"
143 " --in (-i) binary input file with digest to be extended\n"
144 " --hash (-x) prehash the input file to create digest\n"
145 " --out (-o) binary output file with updated PCR value\n"
146 " --help (-h) show usage and exit\n"
148 "Debugging output:\n"
149 " --debug (-l) changes the log level (-1..4, default: 1)\n"
150 " --quiet (-q) do not write log output to stderr\n"
152 exit_tpm_extendpcr(message
);
156 * @brief main of tpm_extendpcr which extends digest into a PCR
158 * @param argc number of arguments
159 * @param argv pointer to the argument values
161 int main(int argc
, char *argv
[])
163 hash_algorithm_t alg
= HASH_SHA1
;
164 hasher_t
*hasher
= NULL
;
165 char *infile
= NULL
, *outfile
= NULL
;
169 atexit(library_deinit
);
170 if (!library_init(NULL
, "tpm_extendpcr"))
172 exit(SS_RC_LIBSTRONGSWAN_INTEGRITY
);
174 if (lib
->integrity
&&
175 !lib
->integrity
->check_file(lib
->integrity
, "tpm_extendpcr", argv
[0]))
177 fprintf(stderr
, "integrity check of tpm_extendpcr failed\n");
178 exit(SS_RC_DAEMON_INTEGRITY
);
183 static const struct option long_opts
[] = {
184 /* name, has_arg, flag, val */
185 { "help", no_argument
, NULL
, 'h' },
186 { "alg", required_argument
, NULL
, 'a' },
187 { "pcr", required_argument
, NULL
, 'p' },
188 { "digest", required_argument
, NULL
, 'd' },
189 { "in", required_argument
, NULL
, 'i' },
190 { "hash", no_argument
, NULL
, 'x' },
191 { "out", required_argument
, NULL
, 'o' },
192 { "quiet", no_argument
, NULL
, 'q' },
193 { "debug", required_argument
, NULL
, 'l' },
197 /* parse next option */
198 int c
= getopt_long(argc
, argv
, "ha:p:d:i:xo:ql:", long_opts
, NULL
);
202 case EOF
: /* end of flags */
205 case 'h': /* --help */
208 case 'a': /* --alg <name> */
209 if (!enum_from_name(hash_algorithm_short_names
, optarg
, &alg
))
211 usage("unsupported hash algorithm");
214 case 'p': /* --pcr <nr> */
218 case 'd': /* --digest <hex> */
219 digest
= chunk_from_hex(chunk_from_str(optarg
), NULL
);
222 case 'i': /* --in <file> */
226 case 'x': /* --hash */
230 case 'o': /* --out <file> */
234 case 'q': /* --quiet */
235 log_to_stderr
= FALSE
;
238 case 'l': /* --debug <level> */
239 default_loglevel
= atoi(optarg
);
243 usage("unknown option");
245 /* break from loop */
249 init_log("tpm_extendpcr");
251 if (!lib
->plugins
->load(lib
->plugins
,
252 lib
->settings
->get_str(lib
->settings
, "tpm_extendpcr.load",
255 exit_tpm_extendpcr("plugin loading failed");
258 /* try to find a TPM */
259 tpm
= tpm_tss_probe(TPM_VERSION_ANY
);
262 exit_tpm_extendpcr("no TPM found");
265 /* read digest from file */
272 exit_tpm_extendpcr("--digest or --in option required");
274 chunk
= chunk_map(infile
, FALSE
);
277 exit_tpm_extendpcr("reading input file failed");
281 hasher
= lib
->crypto
->create_hasher(lib
->crypto
, alg
);
282 if (!hasher
|| !hasher
->allocate_hash(hasher
, *chunk
, &digest
))
286 exit_tpm_extendpcr("prehashing infile failed");
288 hasher
->destroy(hasher
);
292 digest
= chunk_clone(*chunk
);
296 DBG1(DBG_PTS
, "Digest: %#B", &digest
);
298 /* extend digest into PCR */
299 if (!tpm
->extend_pcr(tpm
, pcr
, &pcr_value
, digest
, alg
))
301 exit_tpm_extendpcr("extending PCR failed");
303 DBG1(DBG_PTS
, "PCR %02u: %#B", pcr
, &pcr_value
);
305 /* write PCR value to file */
308 if (!chunk_write(pcr_value
, outfile
, 022, TRUE
))
310 DBG1(DBG_PTS
, "writing '%s' failed", outfile
);
313 chunk_free(&pcr_value
);
315 exit_tpm_extendpcr(NULL
);
316 return -1; /* should never be reached */