1/* 2 * Copyright 2014 The Chromium OS Authors. All rights reserved. 3 * Use of this source code is governed by a BSD-style license that can be 4 * found in the LICENSE file. 5 */ 6 7#include <ctype.h> 8#include <getopt.h> 9#include <stdint.h> 10#include <stdio.h> 11#include <string.h> 12 13#include "futility.h" 14 15static const char usage[] = "\n" 16 "Usage: " MYNAME " %s [OPTIONS] DIGEST [...]\n" 17 "\n" 18 "This simulates a TPM PCR extension, to determine the expected output\n" 19 "\n" 20 "Each DIGEST arg should be a hex string (spaces optional) of the\n" 21 "appropriate length. The PCR is extended with each digest in turn\n" 22 "and the new value displayed.\n" 23 "\n" 24 "Options:\n" 25 " -i Initialize the PCR with the first DIGEST argument\n" 26 " (the default is to start with all zeros)\n" 27 " -2 Use sha256 DIGESTS (the default is sha1)\n" 28 "\n" 29 "Examples:\n" 30 "\n" 31 " " MYNAME " %s b52791126f96a21a8ba4d511c6f25a1c1eb6dc9e\n" 32 " " MYNAME " %s " 33 "'b5 27 91 12 6f 96 a2 1a 8b a4 d5 11 c6 f2 5a 1c 1e b6 dc 9e'\n" 34 "\n"; 35 36static void help_and_quit(const char *prog) 37{ 38 printf(usage, prog, prog, prog); 39} 40 41static int parse_hex(uint8_t *val, const char *str) 42{ 43 uint8_t v = 0; 44 char c; 45 int digit; 46 47 for (digit = 0; digit < 2; digit++) { 48 c = *str; 49 if (!c) 50 return 0; 51 if (!isxdigit(c)) 52 return 0; 53 c = tolower(c); 54 if (c >= '0' && c <= '9') 55 v += c - '0'; 56 else 57 v += 10 + c - 'a'; 58 if (!digit) 59 v <<= 4; 60 str++; 61 } 62 63 *val = v; 64 return 1; 65} 66 67static void parse_digest_or_die(uint8_t *buf, int len, const char *str) 68{ 69 const char *s = str; 70 int i; 71 72 for (i = 0; i < len; i++) { 73 /* skip whitespace */ 74 while (*s && isspace(*s)) 75 s++; 76 if (!*s) 77 break; 78 if (!parse_hex(buf, s)) 79 break; 80 81 /* on to the next byte */ 82 s += 2; 83 buf++; 84 } 85 86 if (i != len) { 87 fprintf(stderr, "Invalid DIGEST \"%s\"\n", str); 88 exit(1); 89 } 90} 91 92static void print_digest(const uint8_t *buf, int len) 93{ 94 int i; 95 for (i = 0; i < len; i++) 96 printf("%02x", buf[i]); 97} 98 99 100static int do_pcr(int argc, char *argv[]) 101{ 102 uint8_t accum[SHA256_DIGEST_SIZE * 2]; 103 uint8_t pcr[SHA256_DIGEST_SIZE]; 104 int digest_alg = SHA1_DIGEST_ALGORITHM; 105 int digest_size = SHA1_DIGEST_SIZE; 106 int opt_init = 0; 107 int errorcnt = 0; 108 uint8_t *digest; 109 int i; 110 111 opterr = 0; /* quiet, you */ 112 while ((i = getopt(argc, argv, ":i2")) != -1) { 113 switch (i) { 114 case 'i': 115 opt_init = 1; 116 break; 117 case '2': 118 digest_alg = SHA256_DIGEST_ALGORITHM; 119 digest_size = SHA256_DIGEST_SIZE; 120 break; 121 case '?': 122 if (optopt) 123 fprintf(stderr, "Unrecognized option: -%c\n", 124 optopt); 125 else 126 fprintf(stderr, "Unrecognized option\n"); 127 errorcnt++; 128 break; 129 case ':': 130 fprintf(stderr, "Missing argument to -%c\n", optopt); 131 errorcnt++; 132 break; 133 default: 134 DIE; 135 } 136 } 137 138 if (errorcnt) { 139 help_and_quit(argv[0]); 140 return 1; 141 } 142 143 if (argc - optind < 1 + opt_init) { 144 fprintf(stderr, "You must extend at least one DIGEST\n"); 145 help_and_quit(argv[0]); 146 return 1; 147 } 148 149 memset(pcr, 0, sizeof(pcr)); 150 151 if (opt_init) { 152 parse_digest_or_die(pcr, digest_size, argv[optind]); 153 optind++; 154 } 155 156 printf("PCR: "); 157 print_digest(pcr, digest_size); 158 printf("\n"); 159 160 for (i = optind; i < argc; i++) { 161 memcpy(accum, pcr, sizeof(pcr)); 162 parse_digest_or_die(accum + digest_size, digest_size, argv[i]); 163 164 printf(" + "); 165 print_digest(accum + digest_size, digest_size); 166 printf("\n"); 167 168 digest = DigestBuf(accum, digest_size * 2, digest_alg); 169 if (!digest) { 170 fprintf(stderr, "Error computing digest!\n"); 171 return 1; 172 } 173 memcpy(pcr, digest, digest_size); 174 free(digest); 175 176 printf("PCR: "); 177 print_digest(pcr, digest_size); 178 printf("\n"); 179 } 180 181 return 0; 182} 183 184DECLARE_FUTIL_COMMAND(pcr, do_pcr, 185 VBOOT_VERSION_ALL, 186 "Simulate a TPM PCR extension operation", 187 help_and_quit); 188