Annotation of src/usr.bin/gzsig/sign.c, Revision 1.2
1.2 ! marius 1: /* $OpenBSD: sign.c,v 1.1.1.1 2005/05/28 01:57:30 marius Exp $ */
1.1 marius 2:
3: /*
4: * sign.c
5: *
6: * Copyright (c) 2001 Dug Song <dugsong@arbor.net>
7: * Copyright (c) 2001 Arbor Networks, Inc.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: *
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: * 3. The names of the copyright holders may not be used to endorse or
19: * promote products derived from this software without specific
20: * prior written permission.
21: *
22: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
23: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
24: * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
25: * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
28: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32: *
1.2 ! marius 33: * $Vendor: sign.c,v 1.2 2005/04/01 16:47:31 dugsong Exp $
1.1 marius 34: */
35:
36: #include <sys/param.h>
37: #include <sys/types.h>
38: #include <sys/stat.h>
39:
40: #include <openssl/ssl.h>
41: #include <openssl/evp.h>
42: #include <openssl/sha.h>
43:
44: #include <errno.h>
45: #include <stdio.h>
46: #include <stdlib.h>
47: #include <string.h>
48: #include <unistd.h>
49:
50: #include "extern.h"
51: #include "gzip.h"
52: #include "key.h"
53: #include "util.h"
54:
55: static char *passphrase = NULL;
56:
57: static int
58: embed_signature(struct key *key, FILE *fin, FILE *fout)
59: {
60: struct gzip_header gh;
61: struct gzip_xfield *gx;
62: struct gzsig_data *gd;
63: u_char *sig, digest[20], buf[8192];
64: SHA_CTX ctx;
65: int i, siglen;
66: long offset;
67:
68: /* Read gzip header. */
69: if (fread((u_char *)&gh, 1, sizeof(gh), fin) != sizeof(gh)) {
70: fprintf(stderr, "Error reading gzip header: %s\n",
71: strerror(errno));
72: return (-1);
73: }
74: /* Verify gzip header. */
75: if (memcmp(gh.magic, GZIP_MAGIC, sizeof(gh.magic)) != 0) {
76: fprintf(stderr, "Invalid gzip file\n");
77: return (-1);
78: }
79: if (gh.flags & GZIP_FCONT) {
80: fprintf(stderr, "Multi-part gzip files not supported\n");
81: return (-1);
82: }
83: /* Skip over any existing signature. */
84: if (gh.flags & GZIP_FEXTRA) {
85: gx = (struct gzip_xfield *)buf;
86: gd = (struct gzsig_data *)(gx + 1);
87:
88: if (fread((u_char *)gx, 1, sizeof(*gx), fin) != sizeof(*gx)) {
89: fprintf(stderr, "Error reading extra field: %s\n",
90: strerror(errno));
91: return (-1);
92: }
93: if (memcmp(gx->subfield.id, GZSIG_ID, 2) != 0) {
94: fprintf(stderr, "Unknown extra field\n");
95: return (-1);
96: }
97: gx->subfield.len = letoh16(gx->subfield.len);
98:
99: if (gx->subfield.len < sizeof(*gd) ||
100: gx->subfield.len > sizeof(buf) - sizeof(*gx)) {
101: fprintf(stderr, "Invalid signature length\n");
102: return (-1);
103: }
104: if (fread((u_char *)gd, 1, gx->subfield.len, fin) !=
105: gx->subfield.len) {
106: fprintf(stderr, "Error reading signature: %s\n",
107: strerror(errno));
108: return (-1);
109: }
110: fprintf(stderr, "Overwriting existing signature\n");
111: }
112: /* Skip over any options. */
113: offset = ftell(fin);
114:
115: if (gh.flags & GZIP_FNAME) {
116: while (getc(fin) != '\0')
117: ;
118: }
119: if (gh.flags & GZIP_FCOMMENT) {
120: while (getc(fin) != '\0')
121: ;
122: }
123: if (gh.flags & GZIP_FENCRYPT) {
124: if (fread(buf, 1, GZIP_FENCRYPT_LEN, fin) != GZIP_FENCRYPT_LEN)
125: return (-1);
126: }
127: /* Compute checksum over compressed data and trailer. */
128: SHA1_Init(&ctx);
129:
130: while ((i = fread(buf, 1, sizeof(buf), fin)) > 0) {
131: SHA1_Update(&ctx, buf, i);
132: }
133: SHA1_Final(digest, &ctx);
134:
135: /* Generate signature. */
136: gx = (struct gzip_xfield *)buf;
137: gd = (struct gzsig_data *)(gx + 1);
138: sig = (u_char *)(gd + 1);
139:
140: siglen = key_sign(key, digest, sizeof(digest), sig,
141: sizeof(buf) - (sig - buf));
142:
143: if (siglen < 0) {
144: fprintf(stderr, "Error signing checksum\n");
145: return (-1);
146: }
147: i = sizeof(*gd) + siglen;
148: gx->subfield.len = htole16(i);
149: gx->len = htole16(sizeof(gx->subfield) + i);
150: memcpy(gx->subfield.id, GZSIG_ID, sizeof(gx->subfield.id));
151: gd->version = GZSIG_VERSION;
152:
153: /* Write out gzip header. */
154: gh.flags |= GZIP_FEXTRA;
155:
156: if (fwrite((u_char *)&gh, 1, sizeof(gh), fout) != sizeof(gh)) {
157: fprintf(stderr, "Error writing output: %s\n", strerror(errno));
158: return (-1);
159: }
160: /* Write out signature. */
161: if (fwrite(buf, 1, sizeof(*gx) + i, fout) != sizeof(*gx) + i) {
162: fprintf(stderr, "Error writing output: %s\n", strerror(errno));
163: return (-1);
164: }
165: /* Write out options, compressed data, and trailer. */
166: if (fseek(fin, offset, SEEK_SET) < 0) {
167: fprintf(stderr, "Error writing output: %s\n", strerror(errno));
168: return (-1);
169: }
170: while ((i = fread(buf, 1, sizeof(buf), fin)) > 0) {
171: if (fwrite(buf, 1, i, fout) != i) {
172: fprintf(stderr, "Error writing output: %s\n",
173: strerror(errno));
174: return (-1);
175: }
176: }
177: if (ferror(fin)) {
178: fprintf(stderr, "Error reading input: %s\n", strerror(errno));
179: return (-1);
180: }
181: return (0);
182: }
183:
184: void
185: sign_usage(void)
186: {
187: fprintf(stderr, "Usage: gzsig sign [-v] privkey [file ...]\n");
188: }
189:
190: int
191: sign_passwd_cb(char *buf, int size, int rwflag, void *u)
192: {
193: char *p;
194:
195: if (passphrase != NULL) {
196: if (strlcpy(buf, passphrase, size) >= size)
197: errx(1, "Passphrase too long");
198: } else {
199: p = getpass("Enter passphrase: ");
200: if (strlcpy(buf, p, size) >= size)
201: errx(1, "Passphrase too long");
202: memset(p, 0, strlen(p));
203: }
204:
205: return (strlen(buf));
206: }
207:
208: void
209: sign(int argc, char *argv[])
210: {
211: struct key *key;
212: char *gzipfile, tmpfile[MAXPATHLEN];
213: FILE *fin, *fout;
214: int i, fd, error, vflag;
215:
216: vflag = 0;
217:
218: while ((i = getopt(argc, argv, "vh?p:")) != -1) {
219: switch (i) {
220: case 'v':
221: vflag = 1;
222: break;
223: case 'p':
224: passphrase = optarg;
225: break;
226: default:
227: sign_usage();
228: exit(1);
229: }
230: }
231: argc -= optind;
232: argv += optind;
233:
234: if (argc < 1) {
235: sign_usage();
236: exit(1);
237: }
238: OpenSSL_add_all_algorithms();
239:
240: if ((key = key_new()) == NULL)
241: fatal(1, "Couldn't initialize private key");
242:
243: if (key_load_private(key, argv[0]) < 0)
244: fatal(1, "Couldn't load private key");
245:
246: if (argc == 1 || *argv[1] == '-') {
247: argc = 0;
248:
249: if (embed_signature(key, stdin, stdout) == 0) {
250: if (vflag)
251: fprintf(stderr, "Signed input\n");
252: } else
253: fatal(1, "Couldn't sign input");
254: }
255: for (i = 1; i < argc; i++) {
256: gzipfile = argv[i];
257:
258: if ((fin = fopen(gzipfile, "r+")) == NULL) {
259: fprintf(stderr, "Error opening %s: %s\n",
260: gzipfile, strerror(errno));
261: continue;
262: }
263: snprintf(tmpfile, sizeof(tmpfile), "%s.XXXXXX", gzipfile);
264:
265: if ((fd = mkstemp(tmpfile)) < 0) {
266: fprintf(stderr, "Error creating %s: %s\n",
267: tmpfile, strerror(errno));
268: fclose(fin);
269: continue;
270: }
271: if ((fout = fdopen(fd, "w")) == NULL) {
272: fprintf(stderr, "Error opening %s: %s\n",
273: tmpfile, strerror(errno));
274: fclose(fin);
275: close(fd);
276: continue;
277: }
278: if (copy_permissions(gzipfile, tmpfile) < 0) {
279: fprintf(stderr, "Error initializing %s: %s\n",
280: tmpfile, strerror(errno));
281: fclose(fin);
282: fclose(fout);
283: continue;
284: }
285: error = embed_signature(key, fin, fout);
286:
287: fclose(fin);
288: fclose(fout);
289:
290: if (!error) {
291: if (rename(tmpfile, gzipfile) < 0) {
292: unlink(tmpfile);
293: fatal(1, "Couldn't sign %s", gzipfile);
294: }
295: if (vflag)
296: fprintf(stderr, "Signed %s\n", gzipfile);
297: } else {
298: unlink(tmpfile);
299: fatal(1, "Couldn't sign %s", gzipfile);
300: }
301: }
302: key_free(key);
303:
304: if (passphrase != NULL)
305: memset(passphrase, 0, strlen(passphrase));
306: }