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