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
hash_gen(int in_fd,const wbku_key_attr_t * ka,const uint8_t * hmac_key)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
usage(const char * cmd)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
main(int argc,char ** argv)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