Annotation of src/usr.bin/gzsig/sign.c, Revision 1.9
1.9 ! jasper 1: /* $OpenBSD: sign.c,v 1.8 2007/09/11 15:47:17 gilles 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>
1.4 djm 49: #include <err.h>
1.1 marius 50:
51: #include "extern.h"
52: #include "gzip.h"
53: #include "key.h"
54: #include "util.h"
55:
1.4 djm 56: static char *passphrase_file = NULL;
1.1 marius 57:
58: static int
59: embed_signature(struct key *key, FILE *fin, FILE *fout)
60: {
61: struct gzip_header gh;
62: struct gzip_xfield *gx;
63: struct gzsig_data *gd;
64: u_char *sig, digest[20], buf[8192];
65: SHA_CTX ctx;
66: int i, siglen;
67: long offset;
68:
69: /* Read gzip header. */
70: if (fread((u_char *)&gh, 1, sizeof(gh), fin) != sizeof(gh)) {
71: fprintf(stderr, "Error reading gzip header: %s\n",
72: strerror(errno));
73: return (-1);
74: }
75: /* Verify gzip header. */
76: if (memcmp(gh.magic, GZIP_MAGIC, sizeof(gh.magic)) != 0) {
77: fprintf(stderr, "Invalid gzip file\n");
78: return (-1);
79: }
80: if (gh.flags & GZIP_FCONT) {
81: fprintf(stderr, "Multi-part gzip files not supported\n");
82: return (-1);
83: }
84: /* Skip over any existing signature. */
85: if (gh.flags & GZIP_FEXTRA) {
86: gx = (struct gzip_xfield *)buf;
87: gd = (struct gzsig_data *)(gx + 1);
88:
89: if (fread((u_char *)gx, 1, sizeof(*gx), fin) != sizeof(*gx)) {
90: fprintf(stderr, "Error reading extra field: %s\n",
91: strerror(errno));
92: return (-1);
93: }
94: if (memcmp(gx->subfield.id, GZSIG_ID, 2) != 0) {
95: fprintf(stderr, "Unknown extra field\n");
96: return (-1);
97: }
98: gx->subfield.len = letoh16(gx->subfield.len);
99:
100: if (gx->subfield.len < sizeof(*gd) ||
101: gx->subfield.len > sizeof(buf) - sizeof(*gx)) {
102: fprintf(stderr, "Invalid signature length\n");
103: return (-1);
104: }
105: if (fread((u_char *)gd, 1, gx->subfield.len, fin) !=
106: gx->subfield.len) {
107: fprintf(stderr, "Error reading signature: %s\n",
108: strerror(errno));
109: return (-1);
110: }
111: fprintf(stderr, "Overwriting existing signature\n");
112: }
113: /* Skip over any options. */
114: offset = ftell(fin);
115:
116: if (gh.flags & GZIP_FNAME) {
117: while (getc(fin) != '\0')
118: ;
119: }
120: if (gh.flags & GZIP_FCOMMENT) {
121: while (getc(fin) != '\0')
122: ;
123: }
124: if (gh.flags & GZIP_FENCRYPT) {
125: if (fread(buf, 1, GZIP_FENCRYPT_LEN, fin) != GZIP_FENCRYPT_LEN)
126: return (-1);
127: }
128: /* Compute checksum over compressed data and trailer. */
129: SHA1_Init(&ctx);
130:
131: while ((i = fread(buf, 1, sizeof(buf), fin)) > 0) {
132: SHA1_Update(&ctx, buf, i);
133: }
134: SHA1_Final(digest, &ctx);
135:
136: /* Generate signature. */
137: gx = (struct gzip_xfield *)buf;
138: gd = (struct gzsig_data *)(gx + 1);
139: sig = (u_char *)(gd + 1);
140:
141: siglen = key_sign(key, digest, sizeof(digest), sig,
142: sizeof(buf) - (sig - buf));
143:
144: if (siglen < 0) {
145: fprintf(stderr, "Error signing checksum\n");
146: return (-1);
147: }
148: i = sizeof(*gd) + siglen;
149: gx->subfield.len = htole16(i);
150: gx->len = htole16(sizeof(gx->subfield) + i);
151: memcpy(gx->subfield.id, GZSIG_ID, sizeof(gx->subfield.id));
152: gd->version = GZSIG_VERSION;
153:
154: /* Write out gzip header. */
155: gh.flags |= GZIP_FEXTRA;
156:
157: if (fwrite((u_char *)&gh, 1, sizeof(gh), fout) != sizeof(gh)) {
158: fprintf(stderr, "Error writing output: %s\n", strerror(errno));
159: return (-1);
160: }
161: /* Write out signature. */
162: if (fwrite(buf, 1, sizeof(*gx) + i, fout) != sizeof(*gx) + i) {
163: fprintf(stderr, "Error writing output: %s\n", strerror(errno));
164: return (-1);
165: }
166: /* Write out options, compressed data, and trailer. */
167: if (fseek(fin, offset, SEEK_SET) < 0) {
168: fprintf(stderr, "Error writing output: %s\n", strerror(errno));
169: return (-1);
170: }
171: while ((i = fread(buf, 1, sizeof(buf), fin)) > 0) {
172: if (fwrite(buf, 1, i, fout) != i) {
173: fprintf(stderr, "Error writing output: %s\n",
174: strerror(errno));
175: return (-1);
176: }
177: }
178: if (ferror(fin)) {
179: fprintf(stderr, "Error reading input: %s\n", strerror(errno));
180: return (-1);
181: }
182: return (0);
183: }
184:
185: void
186: sign_usage(void)
187: {
1.9 ! jasper 188: fprintf(stderr, "Usage: %s sign [-q] [-f secret_file] privkey [file ...]\n",
! 189: __progname);
1.1 marius 190: }
191:
192: int
193: sign_passwd_cb(char *buf, int size, int rwflag, void *u)
194: {
195: char *p;
1.4 djm 196: FILE *f;
1.1 marius 197:
1.4 djm 198: if (passphrase_file != NULL) {
199: if ((f = fopen(passphrase_file, "r")) == NULL)
200: err(1, "fopen(%.64s)", passphrase_file);
201: if (fgets(buf, size, f) == NULL)
202: err(1, "fgets(%.64s)", passphrase_file);
203: fclose(f);
1.8 gilles 204: buf[strcspn(buf, "\n")] = '\0';
1.1 marius 205: } else {
206: p = getpass("Enter passphrase: ");
207: if (strlcpy(buf, p, size) >= size)
208: errx(1, "Passphrase too long");
209: memset(p, 0, strlen(p));
210: }
211:
212: return (strlen(buf));
213: }
214:
215: void
216: sign(int argc, char *argv[])
217: {
218: struct key *key;
1.5 djm 219: char *gzipfile, tmppath[MAXPATHLEN];
1.1 marius 220: FILE *fin, *fout;
1.3 djm 221: int i, fd, error, qflag;
1.1 marius 222:
1.3 djm 223: qflag = 0;
1.1 marius 224:
1.7 moritz 225: while ((i = getopt(argc, argv, "qvf:")) != -1) {
1.1 marius 226: switch (i) {
1.3 djm 227: case 'q':
228: qflag = 1;
229: break;
1.1 marius 230: case 'v':
1.3 djm 231: qflag = 0;
1.1 marius 232: break;
1.4 djm 233: case 'f':
234: passphrase_file = optarg;
1.1 marius 235: break;
236: default:
237: sign_usage();
238: exit(1);
239: }
240: }
241: argc -= optind;
242: argv += optind;
243:
244: if (argc < 1) {
245: sign_usage();
246: exit(1);
247: }
248: OpenSSL_add_all_algorithms();
249:
250: if ((key = key_new()) == NULL)
251: fatal(1, "Couldn't initialize private key");
252:
253: if (key_load_private(key, argv[0]) < 0)
254: fatal(1, "Couldn't load private key");
255:
256: if (argc == 1 || *argv[1] == '-') {
257: argc = 0;
258:
259: if (embed_signature(key, stdin, stdout) == 0) {
1.3 djm 260: if (!qflag)
1.1 marius 261: fprintf(stderr, "Signed input\n");
262: } else
263: fatal(1, "Couldn't sign input");
264: }
265: for (i = 1; i < argc; i++) {
266: gzipfile = argv[i];
267:
268: if ((fin = fopen(gzipfile, "r+")) == NULL) {
269: fprintf(stderr, "Error opening %s: %s\n",
270: gzipfile, strerror(errno));
271: continue;
272: }
1.5 djm 273: snprintf(tmppath, sizeof(tmppath), "%s.XXXXXX", gzipfile);
1.1 marius 274:
1.5 djm 275: if ((fd = mkstemp(tmppath)) < 0) {
1.1 marius 276: fprintf(stderr, "Error creating %s: %s\n",
1.5 djm 277: tmppath, strerror(errno));
1.1 marius 278: fclose(fin);
279: continue;
280: }
281: if ((fout = fdopen(fd, "w")) == NULL) {
282: fprintf(stderr, "Error opening %s: %s\n",
1.5 djm 283: tmppath, strerror(errno));
1.1 marius 284: fclose(fin);
285: close(fd);
286: continue;
287: }
1.5 djm 288: if (copy_permissions(gzipfile, tmppath) < 0) {
1.1 marius 289: fprintf(stderr, "Error initializing %s: %s\n",
1.5 djm 290: tmppath, strerror(errno));
1.1 marius 291: fclose(fin);
292: fclose(fout);
293: continue;
294: }
295: error = embed_signature(key, fin, fout);
296:
297: fclose(fin);
298: fclose(fout);
299:
300: if (!error) {
1.5 djm 301: if (rename(tmppath, gzipfile) < 0) {
302: unlink(tmppath);
1.1 marius 303: fatal(1, "Couldn't sign %s", gzipfile);
304: }
1.3 djm 305: if (!qflag)
1.1 marius 306: fprintf(stderr, "Signed %s\n", gzipfile);
307: } else {
1.5 djm 308: unlink(tmppath);
1.1 marius 309: fatal(1, "Couldn't sign %s", gzipfile);
310: }
311: }
312: key_free(key);
313: }