c104c0a2d208b9403f8d845e69145e8a3b39964b
[dragonfly.git] / usr.sbin / pkg_install / sign / sha1.c
1 /*-
2  * Copyright (c) 1999 Marc Espie.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  * 3. All advertising materials mentioning features or use of this software
13  *    must display the following acknowledgement:
14  *      This product includes software developed by Marc Espie for the OpenBSD
15  * Project.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS 
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
20  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OPENBSD
21  * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
23  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * $OpenBSD: sha1.c,v 1.1 1999/10/04 21:46:29 espie Exp $
30  * $FreeBSD: src/usr.sbin/pkg_install/sign/sha1.c,v 1.5 2004/06/29 19:06:42 eik Exp $
31  * $DragonFly: src/usr.sbin/pkg_install/sign/Attic/sha1.c,v 1.3 2004/07/30 04:46:14 dillon Exp $
32  */
33
34 #include <sys/types.h>
35 #include <sys/wait.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <stdio.h>
39 #include <assert.h>
40 #include <sha.h>
41 #include "stand.h"
42 #include "gzip.h"
43 #include "extern.h"
44
45 /* private context for sha1 signature checker */
46 struct sha1_checker {
47         SHA_CTX context;
48         const char *id;
49         const char *filename;
50 };
51
52
53 #define SHA1_TEMPLATE "SHA1 (%s) = "
54 #define BUFSIZE (MAXID+sizeof(SHA1_TEMPLATE)+2*SHA_DIGEST_LENGTH+1)
55
56 /*
57  * Finalize SHA1 checksum for our sha1_context into result 
58  * (size at least BUFSIZE).  Returns the length of the checksum
59  * marker, e.g.,   SHA1 (id) = xxxxxxxxx
60  *                             ^here 
61  * Return 0 for errors.
62  */
63 size_t 
64 sha1_build_checksum(result, n)
65         char *result;
66         struct sha1_checker *n;
67 {
68         size_t length;
69
70         snprintf(result, BUFSIZE-2*SHA_DIGEST_LENGTH-1, SHA1_TEMPLATE, n->id);
71         length = strlen(result);
72         SHA1_End(&n->context, result + length);
73         strcat(result, "\n");
74         free(n);        
75         return length;
76 }
77
78 void *
79 new_sha1_checker(h, sign, userid, envp, filename)
80         struct mygzip_header *h;
81         struct signature *sign;
82         const char *userid;     
83         char *envp[];
84         /*@observer@*/const char *filename;
85 {
86         struct sha1_checker *n;
87
88         assert(sign->type == TAG_SHA1);
89         /* make sure data conforms to what we can handle */
90         if (sign->length > MAXID || sign->data[sign->length-1] != '\0') {
91                 warnx("Corrupted SHA1 header in %s", filename);
92                 return 0;
93         }
94
95         n = malloc(sizeof *n);
96         if (n == NULL) {
97                 warnx("Can't allocate sha1_checker");
98                 return NULL;
99         }
100         SHA1_Init(&n->context);
101         n->id = sign->data;
102         n->filename = filename;
103
104         /* copy header, as this is a checksum, we don't strip our own marker */
105         if (gzip_copy_header(h, sign, sha1_add, n) == 0) {
106                 warnx("Unexpected header in %s", filename);
107                 free(n);
108                 return 0;
109         }
110         return n;
111 }
112         
113 void 
114 sha1_add(arg, buffer, length)
115         void *arg;
116         const char *buffer;
117         size_t length;
118 {
119         struct sha1_checker *n = arg;
120         SHA1_Update(&n->context, buffer, length);
121 }
122
123 int
124 sha1_sign_ok(arg)
125         void *arg;
126 {
127         struct sha1_checker *n = arg;
128         char buffer[BUFSIZE];
129         char scan[BUFSIZE];
130         size_t length;
131         FILE *f;
132         int tag_found;
133
134         length = sha1_build_checksum(buffer, n);
135         f= fopen(SHA1_DB_NAME, "r");
136         tag_found = 0;
137
138         if (f == NULL) {
139                 warn("Can't access checksum file %s", SHA1_DB_NAME);
140                 return PKG_BADSIG;
141         }
142         while (fgets(scan, sizeof(scan), f) != NULL) {
143                 if (strcmp(scan, buffer) == 0) {
144                         fprintf(stderr, "Checksum ok\n");
145                         return PKG_GOODSIG;
146                 }
147                 if (strncmp(scan, buffer, length) == 0)
148                         tag_found = 1;
149         }
150
151         if (tag_found) {
152                 warnx("Checksum incorrect for %s (%s)", n->filename, n->id);
153                 return PKG_BADSIG;
154         } else {
155                 warnx("No checksum found for %s (%s)", n->filename, n->id);
156                 return PKG_SIGUNKNOWN;
157         }
158 }
159
160 int 
161 retrieve_sha1_marker(filename, sign, userid)
162         const char *filename;
163         struct signature **sign;
164         const char *userid;
165 {
166         struct signature *n;
167         struct mygzip_header h;
168         FILE *f;
169         char buffer[1024];
170         char result[BUFSIZE];
171         ssize_t length = -1;
172         struct sha1_checker *checker;
173
174         *sign = NULL;
175         if (userid == NULL)
176                 return 0;
177
178         /*
179          * Create a blank signature and fill it with the userid.
180          */
181         n = malloc(sizeof *n);
182         if (n == NULL) 
183                 return 0;
184         n->length = strlen(userid)+1;
185         n->data = malloc(n->length);
186         if (n->data == NULL) {
187                 free(n);
188                 return 0;
189         }
190         memcpy(n->data, userid, n->length);
191         n->type = TAG_SHA1;
192         memcpy(n->tag, sha1tag, sizeof sha1tag);
193         sign_fill_tag(n);
194
195         /*
196          * Read the gzip header and add our "userid" signature to it.
197          */
198         f = fopen(filename, "r");
199         if (f == NULL) {
200                 free(n);
201                 return 0;
202         }
203         if (gzip_read_header(f, &h, sign) == GZIP_NOT_GZIP) {
204                 warnx("File %s is not a gzip file\n", filename);
205                 fclose(f);
206                 free(n);
207                 return 0;
208         }
209         n->next = *sign;
210         *sign = n;
211
212         /*
213          * Calculate the SHA1 of the remaining data and write it to stderr.
214          */
215         checker = new_sha1_checker(&h, *sign, NULL, NULL, filename);
216         if (checker) 
217                 while ((length = fread(buffer, 1, sizeof buffer, f)) > 0)
218                         sha1_add(checker, buffer, length);
219         if (fclose(f) != 0 || length == -1) {
220                 warn("Problem checksumming %s", filename);
221                 *sign = n->next;
222                 free(n);
223                 return 0;
224         }
225
226         (void)sha1_build_checksum(result, checker);
227         fputs(result, stderr);
228         return 1;
229 }
230