1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <unistd.h> 31 #include <fcntl.h> 32 #include <libintl.h> 33 #include <locale.h> 34 #include <string.h> 35 #include <errno.h> 36 #include <wanbootutil.h> 37 #include <sys/wanboot_impl.h> 38 39 /* Return codes */ 40 #define HMAC_SUCCESS 0 41 #define HMAC_NOKEY 1 42 #define HMAC_ERROR 2 43 44 /* Private buffer length */ 45 #define HMAC_BUF_LEN 1024 46 47 /* 48 * This routine is used to compute a hash digest for the file represented 49 * by the file descirptor, 'fd'. The key, 'hmac_key', and key type, 'ka', 50 * will be provided by the caller. The resulting hash digest will be 51 * written to stdout. 52 * 53 * Returns: 54 * HMAC_SUCCESS or HMAC_ERROR. 55 */ 56 static int 57 hash_gen(int in_fd, const wbku_key_attr_t *ka, const uint8_t *hmac_key) 58 { 59 SHA1_CTX ctx; 60 uint8_t buf[HMAC_BUF_LEN]; 61 ssize_t i; 62 uint8_t digest[HMAC_DIGEST_LEN]; 63 64 /* 65 * Initialize the computation. 66 */ 67 HMACInit(&ctx, hmac_key, ka->ka_len); 68 69 /* 70 * Read the data to hash. 71 */ 72 while ((i = read(in_fd, buf, HMAC_BUF_LEN)) > 0) { 73 HMACUpdate(&ctx, buf, i); 74 } 75 if (i < 0) { 76 wbku_printerr("Cannot read input_file"); 77 return (HMAC_ERROR); 78 } 79 80 /* 81 * Finalize the digest. 82 */ 83 HMACFinal(&ctx, hmac_key, ka->ka_len, digest); 84 85 /* 86 * Write the digest to stdout. 87 */ 88 if (wbio_nwrite(STDOUT_FILENO, digest, sizeof (digest)) != 0) { 89 wbku_printerr("Cannot output digest"); 90 return (HMAC_ERROR); 91 } 92 93 /* 94 * Success. 95 */ 96 return (HMAC_SUCCESS); 97 } 98 99 /* 100 * Prints usage(). 101 */ 102 static void 103 usage(const char *cmd) 104 { 105 (void) fprintf(stderr, 106 gettext("Usage: %s [-i input_file] -k key_file\n"), cmd); 107 } 108 109 /* 110 * This program is used to compute a hash digest for data read in from 111 * stdin or optionally, a file. The resulting hash digest will be written 112 * to stdout. 113 * 114 * Returns: 115 * HMAC_SUCCESS, HMAC_ERROR or HMAC_NOKEY. 116 */ 117 int 118 main(int argc, char **argv) 119 { 120 uint8_t hmac_key[WANBOOT_HMAC_KEY_SIZE]; 121 int c; 122 char *infile_name = NULL; 123 char *keyfile_name = NULL; 124 int in_fd = -1; 125 FILE *key_fp = NULL; 126 wbku_key_attr_t ka; 127 wbku_retcode_t wbkuret; 128 int ret = HMAC_ERROR; 129 130 /* 131 * Do the necessary magic for localization support. 132 */ 133 (void) setlocale(LC_ALL, ""); 134 #if !defined(TEXT_DOMAIN) 135 #define TEXT_DOMAIN "SYS_TEST" 136 #endif 137 (void) textdomain(TEXT_DOMAIN); 138 139 /* 140 * Initialize program name for use by wbku_printerr(). 141 */ 142 wbku_errinit(argv[0]); 143 144 /* 145 * Should be at least three arguments. 146 */ 147 if (argc < 3) { 148 usage(argv[0]); 149 return (HMAC_ERROR); 150 } 151 152 /* 153 * Parse the options. 154 */ 155 while ((c = getopt(argc, argv, "i:k:")) != EOF) { 156 switch (c) { 157 case 'i': 158 /* 159 * Optional input file. 160 */ 161 infile_name = optarg; 162 break; 163 case 'k': 164 /* 165 * Path to key file. 166 */ 167 keyfile_name = optarg; 168 break; 169 default: 170 usage(argv[0]); 171 return (HMAC_ERROR); 172 } 173 } 174 175 /* 176 * A key file must be defined. 177 */ 178 if (keyfile_name == NULL) { 179 wbku_printerr("Must specify the key_file\n"); 180 return (HMAC_ERROR); 181 } 182 183 /* 184 * If the user did not provide an input file for the data, 185 * then use stdin as the source. 186 */ 187 if (infile_name == NULL) { 188 in_fd = STDIN_FILENO; 189 } else { 190 in_fd = open(infile_name, O_RDONLY); 191 if (in_fd < 0) { 192 wbku_printerr("Cannot open input_file"); 193 return (HMAC_ERROR); 194 } 195 } 196 197 /* 198 * Open the key file for reading. 199 */ 200 if ((key_fp = fopen(keyfile_name, "r")) == NULL) { 201 wbku_printerr("Cannot open %s", keyfile_name); 202 goto out; 203 } 204 205 /* 206 * Create a SHA1 key attribute structure. It's the only hash 207 * type we support. 208 */ 209 wbkuret = wbku_str_to_keyattr(WBKU_KW_HMAC_SHA1, &ka, WBKU_HASH_KEY); 210 if (wbkuret != WBKU_SUCCESS) { 211 wbku_printerr("%s\n", wbku_retmsg(wbkuret)); 212 goto out; 213 } 214 215 /* 216 * Find the client key, if it exists. 217 */ 218 wbkuret = wbku_find_key(key_fp, NULL, &ka, hmac_key, B_FALSE); 219 if (wbkuret != WBKU_SUCCESS) { 220 wbku_printerr("%s\n", wbku_retmsg(wbkuret)); 221 ret = (wbkuret == WBKU_NOKEY) ? HMAC_NOKEY : HMAC_ERROR; 222 } else { 223 ret = hash_gen(in_fd, &ka, hmac_key); 224 } 225 out: 226 /* 227 * Cleanup. 228 */ 229 if (in_fd != -1) { 230 (void) close(in_fd); 231 } 232 if (key_fp != NULL) { 233 (void) fclose(key_fp); 234 } 235 236 return (ret); 237 } 238