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>
30 static bool log_to_stderr
= TRUE
;
32 static bool log_to_syslog
= TRUE
;
34 static level_t default_loglevel
= 1;
36 /* global variables */
42 * logging function for tpm_extendpcr
44 static void tpm_extendpcr_dbg(debug_t group
, level_t level
, char *fmt
, ...)
48 if (level
<= default_loglevel
)
53 vfprintf(stderr
, fmt
, args
);
55 fprintf(stderr
, "\n");
61 char *current
= buffer
, *next
;
63 /* write in memory buffer first */
65 vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
68 /* do a syslog with every line */
71 next
= strchr(current
, '\n');
76 syslog(LOG_INFO
, "%s\n", current
);
80 #endif /* HAVE_SYSLOG*/
85 * Initialize logging to stderr/syslog
87 static void init_log(const char *program
)
89 dbg
= tpm_extendpcr_dbg
;
98 openlog(program
, LOG_CONS
| LOG_NDELAY
| LOG_PID
, LOG_AUTHPRIV
);
100 #endif /* HAVE_SYSLOG */
104 * @brief exit tpm_extendpcr
106 * @param status 0 = OK, -1 = general discomfort
108 static void exit_tpm_extendpcr(err_t message
, ...)
114 chunk_free(&pcr_value
);
116 /* print any error message to stderr */
117 if (message
!= NULL
&& *message
!= '\0')
122 va_start(args
, message
);
123 vsnprintf(m
, sizeof(m
), message
, args
);
126 fprintf(stderr
, "tpm_extendpcr error: %s\n", m
);
133 * @brief prints the usage of the program to the stderr output
135 * If message is set, program is exited with 1 (error)
136 * @param message message in case of an error
138 static void usage(const char *message
)
141 "Usage: tpm_extendpcr [--alg <name>] --pcr <nr> --digest <hex>|--in"
143 " [--hash] [--out <file>] [--quiet]"
144 " [--debug <level>]\n"
145 " tpm_extendpcr --help\n"
148 " --alg (-a) hash algorithm (sha1|sha256)\n"
149 " --pcr (-p) platform configuration register (0..23)\n"
150 " --digest (-d) digest in hex format to be extended\n"
151 " --in (-i) binary input file with digest to be extended\n"
152 " --hash (-x) prehash the input file to create digest\n"
153 " --out (-o) binary output file with updated PCR value\n"
154 " --help (-h) show usage and exit\n"
156 "Debugging output:\n"
157 " --debug (-l) changes the log level (-1..4, default: 1)\n"
158 " --quiet (-q) do not write log output to stderr\n"
160 exit_tpm_extendpcr(message
);
164 * @brief main of tpm_extendpcr which extends digest into a PCR
166 * @param argc number of arguments
167 * @param argv pointer to the argument values
169 int main(int argc
, char *argv
[])
171 hash_algorithm_t alg
= HASH_SHA1
;
172 hasher_t
*hasher
= NULL
;
173 char *infile
= NULL
, *outfile
= NULL
;
177 if (!library_init(NULL
, "tpm_extendpcr"))
179 exit(SS_RC_LIBSTRONGSWAN_INTEGRITY
);
181 atexit(library_deinit
);
182 if (lib
->integrity
&&
183 !lib
->integrity
->check_file(lib
->integrity
, "tpm_extendpcr", argv
[0]))
185 fprintf(stderr
, "integrity check of tpm_extendpcr failed\n");
186 exit(SS_RC_DAEMON_INTEGRITY
);
188 if (!libtpmtss_init())
190 fprintf(stderr
, "libtpmtss initialization failed\n");
191 exit(SS_RC_INITIALIZATION_FAILED
);
193 atexit(libtpmtss_deinit
);
197 static const struct option long_opts
[] = {
198 /* name, has_arg, flag, val */
199 { "help", no_argument
, NULL
, 'h' },
200 { "alg", required_argument
, NULL
, 'a' },
201 { "pcr", required_argument
, NULL
, 'p' },
202 { "digest", required_argument
, NULL
, 'd' },
203 { "in", required_argument
, NULL
, 'i' },
204 { "hash", no_argument
, NULL
, 'x' },
205 { "out", required_argument
, NULL
, 'o' },
206 { "quiet", no_argument
, NULL
, 'q' },
207 { "debug", required_argument
, NULL
, 'l' },
211 /* parse next option */
212 int c
= getopt_long(argc
, argv
, "ha:p:d:i:xo:ql:", long_opts
, NULL
);
216 case EOF
: /* end of flags */
219 case 'h': /* --help */
222 case 'a': /* --alg <name> */
223 if (!enum_from_name(hash_algorithm_short_names
, optarg
, &alg
))
225 usage("unsupported hash algorithm");
228 case 'p': /* --pcr <nr> */
232 case 'd': /* --digest <hex> */
233 digest
= chunk_from_hex(chunk_from_str(optarg
), NULL
);
236 case 'i': /* --in <file> */
240 case 'x': /* --hash */
244 case 'o': /* --out <file> */
248 case 'q': /* --quiet */
249 log_to_stderr
= FALSE
;
252 case 'l': /* --debug <level> */
253 default_loglevel
= atoi(optarg
);
257 usage("unknown option");
259 /* break from loop */
263 init_log("tpm_extendpcr");
265 if (!lib
->plugins
->load(lib
->plugins
,
266 lib
->settings
->get_str(lib
->settings
, "tpm_extendpcr.load",
269 exit_tpm_extendpcr("plugin loading failed");
272 /* try to find a TPM */
273 tpm
= tpm_tss_probe(TPM_VERSION_ANY
);
276 exit_tpm_extendpcr("no TPM found");
279 /* read digest from file */
286 exit_tpm_extendpcr("--digest or --in option required");
288 chunk
= chunk_map(infile
, FALSE
);
291 exit_tpm_extendpcr("reading input file failed");
295 hasher
= lib
->crypto
->create_hasher(lib
->crypto
, alg
);
296 if (!hasher
|| !hasher
->allocate_hash(hasher
, *chunk
, &digest
))
300 exit_tpm_extendpcr("prehashing infile failed");
302 hasher
->destroy(hasher
);
306 digest
= chunk_clone(*chunk
);
310 DBG1(DBG_PTS
, "Digest: %#B", &digest
);
312 /* extend digest into PCR */
313 if (!tpm
->extend_pcr(tpm
, pcr
, &pcr_value
, digest
, alg
))
315 exit_tpm_extendpcr("extending PCR failed");
317 DBG1(DBG_PTS
, "PCR %02u: %#B", pcr
, &pcr_value
);
319 /* write PCR value to file */
322 if (!chunk_write(pcr_value
, outfile
, 022, TRUE
))
324 DBG1(DBG_PTS
, "writing '%s' failed", outfile
);
327 chunk_free(&pcr_value
);
329 exit_tpm_extendpcr(NULL
);
330 return -1; /* should never be reached */