1*a824f5a1SJean-Baptiste Boric /*	$NetBSD: pkg_signature.c,v 1.2 2013/09/11 12:59:19 khorben Exp $	*/
2*a824f5a1SJean-Baptiste Boric 
3*a824f5a1SJean-Baptiste Boric #if HAVE_CONFIG_H
4*a824f5a1SJean-Baptiste Boric #include "config.h"
5*a824f5a1SJean-Baptiste Boric #endif
6*a824f5a1SJean-Baptiste Boric #include <nbcompat.h>
7*a824f5a1SJean-Baptiste Boric #if HAVE_SYS_CDEFS_H
8*a824f5a1SJean-Baptiste Boric #include <sys/cdefs.h>
9*a824f5a1SJean-Baptiste Boric #endif
10*a824f5a1SJean-Baptiste Boric __RCSID("$NetBSD: pkg_signature.c,v 1.2 2013/09/11 12:59:19 khorben Exp $");
11*a824f5a1SJean-Baptiste Boric 
12*a824f5a1SJean-Baptiste Boric /*-
13*a824f5a1SJean-Baptiste Boric  * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>.
14*a824f5a1SJean-Baptiste Boric  * All rights reserved.
15*a824f5a1SJean-Baptiste Boric  *
16*a824f5a1SJean-Baptiste Boric  * Redistribution and use in source and binary forms, with or without
17*a824f5a1SJean-Baptiste Boric  * modification, are permitted provided that the following conditions
18*a824f5a1SJean-Baptiste Boric  * are met:
19*a824f5a1SJean-Baptiste Boric  *
20*a824f5a1SJean-Baptiste Boric  * 1. Redistributions of source code must retain the above copyright
21*a824f5a1SJean-Baptiste Boric  *    notice, this list of conditions and the following disclaimer.
22*a824f5a1SJean-Baptiste Boric  * 2. Redistributions in binary form must reproduce the above copyright
23*a824f5a1SJean-Baptiste Boric  *    notice, this list of conditions and the following disclaimer in
24*a824f5a1SJean-Baptiste Boric  *    the documentation and/or other materials provided with the
25*a824f5a1SJean-Baptiste Boric  *    distribution.
26*a824f5a1SJean-Baptiste Boric  *
27*a824f5a1SJean-Baptiste Boric  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28*a824f5a1SJean-Baptiste Boric  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29*a824f5a1SJean-Baptiste Boric  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
30*a824f5a1SJean-Baptiste Boric  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
31*a824f5a1SJean-Baptiste Boric  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
32*a824f5a1SJean-Baptiste Boric  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
33*a824f5a1SJean-Baptiste Boric  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
34*a824f5a1SJean-Baptiste Boric  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
35*a824f5a1SJean-Baptiste Boric  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
36*a824f5a1SJean-Baptiste Boric  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
37*a824f5a1SJean-Baptiste Boric  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38*a824f5a1SJean-Baptiste Boric  * SUCH DAMAGE.
39*a824f5a1SJean-Baptiste Boric  */
40*a824f5a1SJean-Baptiste Boric 
41*a824f5a1SJean-Baptiste Boric #if HAVE_SYS_WAIT_H
42*a824f5a1SJean-Baptiste Boric #include <sys/wait.h>
43*a824f5a1SJean-Baptiste Boric #endif
44*a824f5a1SJean-Baptiste Boric #include <ctype.h>
45*a824f5a1SJean-Baptiste Boric #if HAVE_ERR_H
46*a824f5a1SJean-Baptiste Boric #include <err.h>
47*a824f5a1SJean-Baptiste Boric #endif
48*a824f5a1SJean-Baptiste Boric #include <errno.h>
49*a824f5a1SJean-Baptiste Boric #include <fcntl.h>
50*a824f5a1SJean-Baptiste Boric #include <stdlib.h>
51*a824f5a1SJean-Baptiste Boric #ifndef NETBSD
52*a824f5a1SJean-Baptiste Boric #include <nbcompat/sha2.h>
53*a824f5a1SJean-Baptiste Boric #else
54*a824f5a1SJean-Baptiste Boric #include <sha2.h>
55*a824f5a1SJean-Baptiste Boric #endif
56*a824f5a1SJean-Baptiste Boric #include <signal.h>
57*a824f5a1SJean-Baptiste Boric #ifdef NETBSD
58*a824f5a1SJean-Baptiste Boric #include <unistd.h>
59*a824f5a1SJean-Baptiste Boric #else
60*a824f5a1SJean-Baptiste Boric #include <nbcompat/unistd.h>
61*a824f5a1SJean-Baptiste Boric #endif
62*a824f5a1SJean-Baptiste Boric 
63*a824f5a1SJean-Baptiste Boric #include <archive.h>
64*a824f5a1SJean-Baptiste Boric #include <archive_entry.h>
65*a824f5a1SJean-Baptiste Boric 
66*a824f5a1SJean-Baptiste Boric #include "lib.h"
67*a824f5a1SJean-Baptiste Boric 
68*a824f5a1SJean-Baptiste Boric #define HASH_FNAME "+PKG_HASH"
69*a824f5a1SJean-Baptiste Boric #define SIGNATURE_FNAME "+PKG_SIGNATURE"
70*a824f5a1SJean-Baptiste Boric #define GPG_SIGNATURE_FNAME "+PKG_GPG_SIGNATURE"
71*a824f5a1SJean-Baptiste Boric 
72*a824f5a1SJean-Baptiste Boric struct signature_archive {
73*a824f5a1SJean-Baptiste Boric 	struct archive *archive;
74*a824f5a1SJean-Baptiste Boric 	off_t pkg_size;
75*a824f5a1SJean-Baptiste Boric 	size_t sign_block_len, sign_block_number, sign_cur_block;
76*a824f5a1SJean-Baptiste Boric 	char **sign_blocks;
77*a824f5a1SJean-Baptiste Boric 	unsigned char *sign_buf;
78*a824f5a1SJean-Baptiste Boric };
79*a824f5a1SJean-Baptiste Boric 
80*a824f5a1SJean-Baptiste Boric static void
hash_block(unsigned char * buf,size_t buf_len,char hash[SHA512_DIGEST_STRING_LENGTH])81*a824f5a1SJean-Baptiste Boric hash_block(unsigned char *buf, size_t buf_len,
82*a824f5a1SJean-Baptiste Boric     char hash[SHA512_DIGEST_STRING_LENGTH])
83*a824f5a1SJean-Baptiste Boric {
84*a824f5a1SJean-Baptiste Boric 	unsigned char digest[SHA512_DIGEST_LENGTH];
85*a824f5a1SJean-Baptiste Boric 	SHA512_CTX hash_ctx;
86*a824f5a1SJean-Baptiste Boric 	int i;
87*a824f5a1SJean-Baptiste Boric 
88*a824f5a1SJean-Baptiste Boric 	SHA512_Init(&hash_ctx);
89*a824f5a1SJean-Baptiste Boric 	SHA512_Update(&hash_ctx, buf, buf_len);
90*a824f5a1SJean-Baptiste Boric 	SHA512_Final(digest, &hash_ctx);
91*a824f5a1SJean-Baptiste Boric 	for (i = 0; i < SHA512_DIGEST_LENGTH; ++i) {
92*a824f5a1SJean-Baptiste Boric 		unsigned char c;
93*a824f5a1SJean-Baptiste Boric 
94*a824f5a1SJean-Baptiste Boric 		c = digest[i] / 16;
95*a824f5a1SJean-Baptiste Boric 		if (c < 10)
96*a824f5a1SJean-Baptiste Boric 			hash[2 * i] = '0' + c;
97*a824f5a1SJean-Baptiste Boric 		else
98*a824f5a1SJean-Baptiste Boric 			hash[2 * i] = 'a' - 10 + c;
99*a824f5a1SJean-Baptiste Boric 
100*a824f5a1SJean-Baptiste Boric 		c = digest[i] % 16;
101*a824f5a1SJean-Baptiste Boric 		if (c < 10)
102*a824f5a1SJean-Baptiste Boric 			hash[2 * i + 1] = '0' + c;
103*a824f5a1SJean-Baptiste Boric 		else
104*a824f5a1SJean-Baptiste Boric 			hash[2 * i + 1] = 'a' - 10 + c;
105*a824f5a1SJean-Baptiste Boric 	}
106*a824f5a1SJean-Baptiste Boric 	hash[2 * i] = '\0';
107*a824f5a1SJean-Baptiste Boric }
108*a824f5a1SJean-Baptiste Boric 
109*a824f5a1SJean-Baptiste Boric static ssize_t
verify_signature_read_cb(struct archive * archive,void * cookie,const void ** buf)110*a824f5a1SJean-Baptiste Boric verify_signature_read_cb(struct archive *archive, void *cookie, const void **buf)
111*a824f5a1SJean-Baptiste Boric {
112*a824f5a1SJean-Baptiste Boric 	struct signature_archive *state = cookie;
113*a824f5a1SJean-Baptiste Boric 	char hash[SHA512_DIGEST_STRING_LENGTH];
114*a824f5a1SJean-Baptiste Boric 	ssize_t len, expected;
115*a824f5a1SJean-Baptiste Boric 
116*a824f5a1SJean-Baptiste Boric 	if (state->sign_cur_block >= state->sign_block_number)
117*a824f5a1SJean-Baptiste Boric 		return 0;
118*a824f5a1SJean-Baptiste Boric 
119*a824f5a1SJean-Baptiste Boric 	/* The following works for sign_block_len > 1 */
120*a824f5a1SJean-Baptiste Boric 	if (state->sign_cur_block + 1 == state->sign_block_number)
121*a824f5a1SJean-Baptiste Boric 		expected = state->pkg_size % state->sign_block_len;
122*a824f5a1SJean-Baptiste Boric 	else
123*a824f5a1SJean-Baptiste Boric 		expected = state->sign_block_len;
124*a824f5a1SJean-Baptiste Boric 
125*a824f5a1SJean-Baptiste Boric 	len = archive_read_data(state->archive, state->sign_buf, expected);
126*a824f5a1SJean-Baptiste Boric 	if (len != expected) {
127*a824f5a1SJean-Baptiste Boric 		warnx("Short read from package");
128*a824f5a1SJean-Baptiste Boric 		return -1;
129*a824f5a1SJean-Baptiste Boric 	}
130*a824f5a1SJean-Baptiste Boric 
131*a824f5a1SJean-Baptiste Boric 	hash_block(state->sign_buf, len, hash);
132*a824f5a1SJean-Baptiste Boric 
133*a824f5a1SJean-Baptiste Boric 	if (strcmp(hash, state->sign_blocks[state->sign_cur_block]) != 0) {
134*a824f5a1SJean-Baptiste Boric 		warnx("Invalid signature of block %llu",
135*a824f5a1SJean-Baptiste Boric 		    (unsigned long long)state->sign_cur_block);
136*a824f5a1SJean-Baptiste Boric 		return -1;
137*a824f5a1SJean-Baptiste Boric 	}
138*a824f5a1SJean-Baptiste Boric 	++state->sign_cur_block;
139*a824f5a1SJean-Baptiste Boric 	*buf = state->sign_buf;
140*a824f5a1SJean-Baptiste Boric 	return len;
141*a824f5a1SJean-Baptiste Boric }
142*a824f5a1SJean-Baptiste Boric 
143*a824f5a1SJean-Baptiste Boric static void
free_signature_int(struct signature_archive * state)144*a824f5a1SJean-Baptiste Boric free_signature_int(struct signature_archive *state)
145*a824f5a1SJean-Baptiste Boric {
146*a824f5a1SJean-Baptiste Boric 	size_t i;
147*a824f5a1SJean-Baptiste Boric 
148*a824f5a1SJean-Baptiste Boric 	if (state->sign_blocks != NULL) {
149*a824f5a1SJean-Baptiste Boric 		for (i = 0; i < state->sign_block_number; ++i)
150*a824f5a1SJean-Baptiste Boric 			free(state->sign_blocks[i]);
151*a824f5a1SJean-Baptiste Boric 	}
152*a824f5a1SJean-Baptiste Boric 	free(state->sign_blocks);
153*a824f5a1SJean-Baptiste Boric 	free(state->sign_buf);
154*a824f5a1SJean-Baptiste Boric 	free(state);
155*a824f5a1SJean-Baptiste Boric }
156*a824f5a1SJean-Baptiste Boric 
157*a824f5a1SJean-Baptiste Boric static int
verify_signature_close_cb(struct archive * archive,void * cookie)158*a824f5a1SJean-Baptiste Boric verify_signature_close_cb(struct archive *archive, void *cookie)
159*a824f5a1SJean-Baptiste Boric {
160*a824f5a1SJean-Baptiste Boric 	struct signature_archive *state = cookie;
161*a824f5a1SJean-Baptiste Boric 
162*a824f5a1SJean-Baptiste Boric 	archive_read_finish(state->archive);
163*a824f5a1SJean-Baptiste Boric 	free_signature_int(state);
164*a824f5a1SJean-Baptiste Boric 	return 0;
165*a824f5a1SJean-Baptiste Boric }
166*a824f5a1SJean-Baptiste Boric 
167*a824f5a1SJean-Baptiste Boric static int
read_file_from_archive(const char * archive_name,struct archive * archive,struct archive_entry ** entry,const char * fname,char ** content,size_t * len)168*a824f5a1SJean-Baptiste Boric read_file_from_archive(const char *archive_name, struct archive *archive,
169*a824f5a1SJean-Baptiste Boric     struct archive_entry **entry,
170*a824f5a1SJean-Baptiste Boric     const char *fname, char **content, size_t *len)
171*a824f5a1SJean-Baptiste Boric {
172*a824f5a1SJean-Baptiste Boric 	int r;
173*a824f5a1SJean-Baptiste Boric 
174*a824f5a1SJean-Baptiste Boric 	*content = NULL;
175*a824f5a1SJean-Baptiste Boric 	*len = 0;
176*a824f5a1SJean-Baptiste Boric 
177*a824f5a1SJean-Baptiste Boric retry:
178*a824f5a1SJean-Baptiste Boric 	if (*entry == NULL &&
179*a824f5a1SJean-Baptiste Boric 	    (r = archive_read_next_header(archive, entry)) != ARCHIVE_OK) {
180*a824f5a1SJean-Baptiste Boric 		if (r == ARCHIVE_FATAL) {
181*a824f5a1SJean-Baptiste Boric 			warnx("Cannot read from archive `%s': %s",
182*a824f5a1SJean-Baptiste Boric 			    archive_name, archive_error_string(archive));
183*a824f5a1SJean-Baptiste Boric 		} else {
184*a824f5a1SJean-Baptiste Boric 			warnx("Premature end of archive `%s'", archive_name);
185*a824f5a1SJean-Baptiste Boric 		}
186*a824f5a1SJean-Baptiste Boric 		*entry = NULL;
187*a824f5a1SJean-Baptiste Boric 		return -1;
188*a824f5a1SJean-Baptiste Boric 	}
189*a824f5a1SJean-Baptiste Boric 	if (strcmp(archive_entry_pathname(*entry), "//") == 0) {
190*a824f5a1SJean-Baptiste Boric 		archive_read_data_skip(archive);
191*a824f5a1SJean-Baptiste Boric 		*entry = NULL;
192*a824f5a1SJean-Baptiste Boric 		goto retry;
193*a824f5a1SJean-Baptiste Boric 	}
194*a824f5a1SJean-Baptiste Boric 
195*a824f5a1SJean-Baptiste Boric 	if (strcmp(fname, archive_entry_pathname(*entry)) != 0)
196*a824f5a1SJean-Baptiste Boric 		return 1;
197*a824f5a1SJean-Baptiste Boric 
198*a824f5a1SJean-Baptiste Boric 	if (archive_entry_size(*entry) > SSIZE_MAX - 1) {
199*a824f5a1SJean-Baptiste Boric 		warnx("Signature of archive `%s' too large to process",
200*a824f5a1SJean-Baptiste Boric 		    archive_name);
201*a824f5a1SJean-Baptiste Boric 		return 1;
202*a824f5a1SJean-Baptiste Boric 	}
203*a824f5a1SJean-Baptiste Boric 	*len = archive_entry_size(*entry);
204*a824f5a1SJean-Baptiste Boric 	*content = xmalloc(*len + 1);
205*a824f5a1SJean-Baptiste Boric 
206*a824f5a1SJean-Baptiste Boric 	if (archive_read_data(archive, *content, *len) != (ssize_t)*len) {
207*a824f5a1SJean-Baptiste Boric 		warnx("Cannot read complete %s from archive `%s'", fname,
208*a824f5a1SJean-Baptiste Boric 		    archive_name);
209*a824f5a1SJean-Baptiste Boric 		free(*content);
210*a824f5a1SJean-Baptiste Boric 		*len = 0;
211*a824f5a1SJean-Baptiste Boric 		*content = NULL;
212*a824f5a1SJean-Baptiste Boric 		return 1;
213*a824f5a1SJean-Baptiste Boric 	}
214*a824f5a1SJean-Baptiste Boric 	(*content)[*len] = '\0';
215*a824f5a1SJean-Baptiste Boric 	*entry = NULL;
216*a824f5a1SJean-Baptiste Boric 
217*a824f5a1SJean-Baptiste Boric 	return 0;
218*a824f5a1SJean-Baptiste Boric }
219*a824f5a1SJean-Baptiste Boric 
220*a824f5a1SJean-Baptiste Boric static int
parse_hash_file(const char * hash_file,char ** pkgname,struct signature_archive * state)221*a824f5a1SJean-Baptiste Boric parse_hash_file(const char *hash_file, char **pkgname,
222*a824f5a1SJean-Baptiste Boric     struct signature_archive *state)
223*a824f5a1SJean-Baptiste Boric {
224*a824f5a1SJean-Baptiste Boric 	static const char block1[] = "pkgsrc signature\n\nversion: 1\npkgname: ";
225*a824f5a1SJean-Baptiste Boric 	static const char block2[] = "algorithm: SHA512\nblock size: ";
226*a824f5a1SJean-Baptiste Boric 	static const char block3[] = "file size: ";
227*a824f5a1SJean-Baptiste Boric 	static const char block4[] = "end pkgsrc signature\n";
228*a824f5a1SJean-Baptiste Boric 	char *next;
229*a824f5a1SJean-Baptiste Boric 	size_t i, len;
230*a824f5a1SJean-Baptiste Boric 
231*a824f5a1SJean-Baptiste Boric 	*pkgname = NULL;
232*a824f5a1SJean-Baptiste Boric 
233*a824f5a1SJean-Baptiste Boric 	if (strncmp(hash_file, block1, strlen(block1)) != 0)
234*a824f5a1SJean-Baptiste Boric 		goto cleanup;
235*a824f5a1SJean-Baptiste Boric 	hash_file += strlen(block1);
236*a824f5a1SJean-Baptiste Boric 
237*a824f5a1SJean-Baptiste Boric 	len = strcspn(hash_file, "\n");
238*a824f5a1SJean-Baptiste Boric 	*pkgname = xmalloc(len + 1);
239*a824f5a1SJean-Baptiste Boric 	memcpy(*pkgname, hash_file, len);
240*a824f5a1SJean-Baptiste Boric 	(*pkgname)[len] = '\0';
241*a824f5a1SJean-Baptiste Boric 	for (i = 0; i < len; ++i) {
242*a824f5a1SJean-Baptiste Boric 		if (!isgraph((unsigned char)(*pkgname)[i]))
243*a824f5a1SJean-Baptiste Boric 			goto cleanup;
244*a824f5a1SJean-Baptiste Boric 	}
245*a824f5a1SJean-Baptiste Boric 	hash_file += len + 1;
246*a824f5a1SJean-Baptiste Boric 
247*a824f5a1SJean-Baptiste Boric 	if (strncmp(hash_file, block2, strlen(block2)) != 0)
248*a824f5a1SJean-Baptiste Boric 		goto cleanup;
249*a824f5a1SJean-Baptiste Boric 	hash_file += strlen(block2);
250*a824f5a1SJean-Baptiste Boric 
251*a824f5a1SJean-Baptiste Boric 	errno = 0;
252*a824f5a1SJean-Baptiste Boric 	if (!isdigit((unsigned char)*hash_file))
253*a824f5a1SJean-Baptiste Boric 		goto cleanup;
254*a824f5a1SJean-Baptiste Boric 	state->sign_block_len = strtoul(hash_file, &next, 10);
255*a824f5a1SJean-Baptiste Boric 	hash_file = next;
256*a824f5a1SJean-Baptiste Boric 
257*a824f5a1SJean-Baptiste Boric 	/* Assert sane minimum block size of 1KB */
258*a824f5a1SJean-Baptiste Boric 	if (*hash_file++ != '\n' || errno == ERANGE || state->sign_block_len < 1024)
259*a824f5a1SJean-Baptiste Boric 		goto cleanup;
260*a824f5a1SJean-Baptiste Boric 
261*a824f5a1SJean-Baptiste Boric 	if (strncmp(hash_file, block3, strlen(block3)) != 0)
262*a824f5a1SJean-Baptiste Boric 		goto cleanup;
263*a824f5a1SJean-Baptiste Boric 	hash_file += strlen(block3);
264*a824f5a1SJean-Baptiste Boric 
265*a824f5a1SJean-Baptiste Boric 	errno = 0;
266*a824f5a1SJean-Baptiste Boric 	if (!isdigit((unsigned char)*hash_file))
267*a824f5a1SJean-Baptiste Boric 		goto cleanup;
268*a824f5a1SJean-Baptiste Boric 	if (/* CONSTCOND */sizeof(off_t) >= sizeof(long long))
269*a824f5a1SJean-Baptiste Boric 		state->pkg_size = strtoll(hash_file, &next, 10);
270*a824f5a1SJean-Baptiste Boric 	else
271*a824f5a1SJean-Baptiste Boric 		state->pkg_size = strtol(hash_file, &next, 10);
272*a824f5a1SJean-Baptiste Boric 	hash_file = next;
273*a824f5a1SJean-Baptiste Boric 	if (*hash_file++ != '\n' || errno == ERANGE || state->pkg_size < 1)
274*a824f5a1SJean-Baptiste Boric 		goto cleanup;
275*a824f5a1SJean-Baptiste Boric 
276*a824f5a1SJean-Baptiste Boric 	if (*hash_file++ != '\n')
277*a824f5a1SJean-Baptiste Boric 		goto cleanup;
278*a824f5a1SJean-Baptiste Boric 
279*a824f5a1SJean-Baptiste Boric 	if (state->pkg_size / state->sign_block_len > SSIZE_MAX)
280*a824f5a1SJean-Baptiste Boric 		goto cleanup;
281*a824f5a1SJean-Baptiste Boric 	state->sign_block_number = (state->pkg_size +
282*a824f5a1SJean-Baptiste Boric 	    state->sign_block_len - 1) / state->sign_block_len;
283*a824f5a1SJean-Baptiste Boric 
284*a824f5a1SJean-Baptiste Boric 	state->sign_buf = xmalloc(state->sign_block_len);
285*a824f5a1SJean-Baptiste Boric 	state->sign_blocks = xcalloc(state->sign_block_number, sizeof(char *));
286*a824f5a1SJean-Baptiste Boric 
287*a824f5a1SJean-Baptiste Boric 	for (i = 0; i < state->sign_block_number; ++i) {
288*a824f5a1SJean-Baptiste Boric 		len = strspn(hash_file, "01234567889abcdef");
289*a824f5a1SJean-Baptiste Boric 		if (len != SHA512_DIGEST_LENGTH * 2 || hash_file[len] != '\n')
290*a824f5a1SJean-Baptiste Boric 			goto cleanup_hashes;
291*a824f5a1SJean-Baptiste Boric 		state->sign_blocks[i] = xmalloc(len + 1);
292*a824f5a1SJean-Baptiste Boric 		memcpy(state->sign_blocks[i], hash_file, len);
293*a824f5a1SJean-Baptiste Boric 		state->sign_blocks[i][len] = '\0';
294*a824f5a1SJean-Baptiste Boric 		hash_file += len + 1;
295*a824f5a1SJean-Baptiste Boric 	}
296*a824f5a1SJean-Baptiste Boric 
297*a824f5a1SJean-Baptiste Boric 	if (strcmp(hash_file, block4) != 0)
298*a824f5a1SJean-Baptiste Boric 		goto cleanup_hashes;
299*a824f5a1SJean-Baptiste Boric 
300*a824f5a1SJean-Baptiste Boric 	return 0;
301*a824f5a1SJean-Baptiste Boric 
302*a824f5a1SJean-Baptiste Boric cleanup_hashes:
303*a824f5a1SJean-Baptiste Boric 	for (i = 0; i < state->sign_block_number; ++i)
304*a824f5a1SJean-Baptiste Boric 		free(state->sign_blocks[i]);
305*a824f5a1SJean-Baptiste Boric 	free(state->sign_blocks);
306*a824f5a1SJean-Baptiste Boric 	state->sign_blocks = NULL;
307*a824f5a1SJean-Baptiste Boric 
308*a824f5a1SJean-Baptiste Boric cleanup:
309*a824f5a1SJean-Baptiste Boric 	warnx("Unknown format of hash file");
310*a824f5a1SJean-Baptiste Boric 	free(*pkgname);
311*a824f5a1SJean-Baptiste Boric 	*pkgname = NULL;
312*a824f5a1SJean-Baptiste Boric 	return -1;
313*a824f5a1SJean-Baptiste Boric }
314*a824f5a1SJean-Baptiste Boric 
315*a824f5a1SJean-Baptiste Boric int
pkg_verify_signature(const char * archive_name,struct archive ** archive,struct archive_entry ** entry,char ** pkgname)316*a824f5a1SJean-Baptiste Boric pkg_verify_signature(const char *archive_name, struct archive **archive,
317*a824f5a1SJean-Baptiste Boric     struct archive_entry **entry, char **pkgname)
318*a824f5a1SJean-Baptiste Boric {
319*a824f5a1SJean-Baptiste Boric 	struct signature_archive *state;
320*a824f5a1SJean-Baptiste Boric 	struct archive_entry *my_entry;
321*a824f5a1SJean-Baptiste Boric 	struct archive *a;
322*a824f5a1SJean-Baptiste Boric 	char *hash_file, *signature_file;
323*a824f5a1SJean-Baptiste Boric 	size_t hash_len, signature_len;
324*a824f5a1SJean-Baptiste Boric 	int r, has_sig;
325*a824f5a1SJean-Baptiste Boric 
326*a824f5a1SJean-Baptiste Boric 	*pkgname = NULL;
327*a824f5a1SJean-Baptiste Boric 
328*a824f5a1SJean-Baptiste Boric 	state = xcalloc(sizeof(*state), 1);
329*a824f5a1SJean-Baptiste Boric 
330*a824f5a1SJean-Baptiste Boric 	r = read_file_from_archive(archive_name, *archive, entry, HASH_FNAME,
331*a824f5a1SJean-Baptiste Boric 	    &hash_file, &hash_len);
332*a824f5a1SJean-Baptiste Boric 	if (r == -1) {
333*a824f5a1SJean-Baptiste Boric 		archive_read_finish(*archive);
334*a824f5a1SJean-Baptiste Boric 		*archive = NULL;
335*a824f5a1SJean-Baptiste Boric 		free(state);
336*a824f5a1SJean-Baptiste Boric 		goto no_valid_signature;
337*a824f5a1SJean-Baptiste Boric 	} else if (r == 1) {
338*a824f5a1SJean-Baptiste Boric 		free(state);
339*a824f5a1SJean-Baptiste Boric 		goto no_valid_signature;
340*a824f5a1SJean-Baptiste Boric 	}
341*a824f5a1SJean-Baptiste Boric 
342*a824f5a1SJean-Baptiste Boric 	if (parse_hash_file(hash_file, pkgname, state))
343*a824f5a1SJean-Baptiste Boric 		goto no_valid_signature;
344*a824f5a1SJean-Baptiste Boric 
345*a824f5a1SJean-Baptiste Boric 	r = read_file_from_archive(archive_name, *archive, entry, SIGNATURE_FNAME,
346*a824f5a1SJean-Baptiste Boric 	    &signature_file, &signature_len);
347*a824f5a1SJean-Baptiste Boric 	if (r == -1) {
348*a824f5a1SJean-Baptiste Boric 		archive_read_finish(*archive);
349*a824f5a1SJean-Baptiste Boric 		*archive = NULL;
350*a824f5a1SJean-Baptiste Boric 		free(state);
351*a824f5a1SJean-Baptiste Boric 		free(hash_file);
352*a824f5a1SJean-Baptiste Boric 		goto no_valid_signature;
353*a824f5a1SJean-Baptiste Boric 	} else if (r != 0) {
354*a824f5a1SJean-Baptiste Boric 		if (*entry != NULL)
355*a824f5a1SJean-Baptiste Boric 			r = read_file_from_archive(archive_name, *archive,
356*a824f5a1SJean-Baptiste Boric 			    entry, GPG_SIGNATURE_FNAME,
357*a824f5a1SJean-Baptiste Boric 			    &signature_file, &signature_len);
358*a824f5a1SJean-Baptiste Boric 		if (r == -1) {
359*a824f5a1SJean-Baptiste Boric 			archive_read_finish(*archive);
360*a824f5a1SJean-Baptiste Boric 			*archive = NULL;
361*a824f5a1SJean-Baptiste Boric 			free(state);
362*a824f5a1SJean-Baptiste Boric 			free(hash_file);
363*a824f5a1SJean-Baptiste Boric 			goto no_valid_signature;
364*a824f5a1SJean-Baptiste Boric 		} else if (r != 0) {
365*a824f5a1SJean-Baptiste Boric 			free(hash_file);
366*a824f5a1SJean-Baptiste Boric 			free(state);
367*a824f5a1SJean-Baptiste Boric 			goto no_valid_signature;
368*a824f5a1SJean-Baptiste Boric 		}
369*a824f5a1SJean-Baptiste Boric 		has_sig = !detached_gpg_verify(hash_file, hash_len,
370*a824f5a1SJean-Baptiste Boric 		    signature_file, signature_len, gpg_keyring_verify);
371*a824f5a1SJean-Baptiste Boric 
372*a824f5a1SJean-Baptiste Boric 		free(signature_file);
373*a824f5a1SJean-Baptiste Boric 	} else {
374*a824f5a1SJean-Baptiste Boric #ifdef HAVE_SSL
375*a824f5a1SJean-Baptiste Boric 		has_sig = !easy_pkcs7_verify(hash_file, hash_len, signature_file,
376*a824f5a1SJean-Baptiste Boric 		    signature_len, certs_packages, 1);
377*a824f5a1SJean-Baptiste Boric 
378*a824f5a1SJean-Baptiste Boric 		free(signature_file);
379*a824f5a1SJean-Baptiste Boric #else
380*a824f5a1SJean-Baptiste Boric 		warnx("No OpenSSL support compiled in, skipping signature");
381*a824f5a1SJean-Baptiste Boric 		has_sig = 0;
382*a824f5a1SJean-Baptiste Boric 		free(signature_file);
383*a824f5a1SJean-Baptiste Boric #endif
384*a824f5a1SJean-Baptiste Boric 	}
385*a824f5a1SJean-Baptiste Boric 
386*a824f5a1SJean-Baptiste Boric 	r = archive_read_next_header(*archive, &my_entry);
387*a824f5a1SJean-Baptiste Boric 	if (r != ARCHIVE_OK) {
388*a824f5a1SJean-Baptiste Boric 		warnx("Cannot read inner package: %s",
389*a824f5a1SJean-Baptiste Boric 		    archive_error_string(*archive));
390*a824f5a1SJean-Baptiste Boric 		free_signature_int(state);
391*a824f5a1SJean-Baptiste Boric 		goto no_valid_signature;
392*a824f5a1SJean-Baptiste Boric 	}
393*a824f5a1SJean-Baptiste Boric 
394*a824f5a1SJean-Baptiste Boric 	if (archive_entry_size(my_entry) != state->pkg_size) {
395*a824f5a1SJean-Baptiste Boric 		warnx("Package size doesn't match signature");
396*a824f5a1SJean-Baptiste Boric 		free_signature_int(state);
397*a824f5a1SJean-Baptiste Boric 		goto no_valid_signature;
398*a824f5a1SJean-Baptiste Boric 	}
399*a824f5a1SJean-Baptiste Boric 
400*a824f5a1SJean-Baptiste Boric 	state->archive = *archive;
401*a824f5a1SJean-Baptiste Boric 
402*a824f5a1SJean-Baptiste Boric 	a = archive_read_new();
403*a824f5a1SJean-Baptiste Boric 	archive_read_support_compression_all(a);
404*a824f5a1SJean-Baptiste Boric 	archive_read_support_format_all(a);
405*a824f5a1SJean-Baptiste Boric 	if (archive_read_open(a, state, NULL, verify_signature_read_cb,
406*a824f5a1SJean-Baptiste Boric 	    verify_signature_close_cb)) {
407*a824f5a1SJean-Baptiste Boric 		warnx("Can't open signed package file");
408*a824f5a1SJean-Baptiste Boric 		archive_read_finish(a);
409*a824f5a1SJean-Baptiste Boric 		goto no_valid_signature;
410*a824f5a1SJean-Baptiste Boric 	}
411*a824f5a1SJean-Baptiste Boric 	*archive = a;
412*a824f5a1SJean-Baptiste Boric 	*entry = NULL;
413*a824f5a1SJean-Baptiste Boric 
414*a824f5a1SJean-Baptiste Boric 	return has_sig ? 0 : -1;
415*a824f5a1SJean-Baptiste Boric 
416*a824f5a1SJean-Baptiste Boric no_valid_signature:
417*a824f5a1SJean-Baptiste Boric 	return -1;
418*a824f5a1SJean-Baptiste Boric }
419*a824f5a1SJean-Baptiste Boric 
420*a824f5a1SJean-Baptiste Boric int
pkg_full_signature_check(const char * archive_name,struct archive ** archive)421*a824f5a1SJean-Baptiste Boric pkg_full_signature_check(const char *archive_name, struct archive **archive)
422*a824f5a1SJean-Baptiste Boric {
423*a824f5a1SJean-Baptiste Boric 	struct archive_entry *entry = NULL;
424*a824f5a1SJean-Baptiste Boric 	char *pkgname;
425*a824f5a1SJean-Baptiste Boric 	int r;
426*a824f5a1SJean-Baptiste Boric 
427*a824f5a1SJean-Baptiste Boric 	if (pkg_verify_signature(archive_name, archive, &entry, &pkgname))
428*a824f5a1SJean-Baptiste Boric 		return -1;
429*a824f5a1SJean-Baptiste Boric 	if (pkgname == NULL)
430*a824f5a1SJean-Baptiste Boric 		return 0;
431*a824f5a1SJean-Baptiste Boric 
432*a824f5a1SJean-Baptiste Boric 	/* XXX read PLIST and compare pkgname */
433*a824f5a1SJean-Baptiste Boric 	while ((r = archive_read_next_header(*archive, &entry)) == ARCHIVE_OK)
434*a824f5a1SJean-Baptiste Boric 		archive_read_data_skip(*archive);
435*a824f5a1SJean-Baptiste Boric 
436*a824f5a1SJean-Baptiste Boric 	free(pkgname);
437*a824f5a1SJean-Baptiste Boric 	return r == ARCHIVE_EOF ? 0 : -1;
438*a824f5a1SJean-Baptiste Boric }
439*a824f5a1SJean-Baptiste Boric 
440*a824f5a1SJean-Baptiste Boric static char *
extract_pkgname(int fd)441*a824f5a1SJean-Baptiste Boric extract_pkgname(int fd)
442*a824f5a1SJean-Baptiste Boric {
443*a824f5a1SJean-Baptiste Boric 	package_t plist;
444*a824f5a1SJean-Baptiste Boric 	plist_t *p;
445*a824f5a1SJean-Baptiste Boric 	struct archive *a;
446*a824f5a1SJean-Baptiste Boric 	struct archive_entry *entry;
447*a824f5a1SJean-Baptiste Boric 	char *buf;
448*a824f5a1SJean-Baptiste Boric 	ssize_t len;
449*a824f5a1SJean-Baptiste Boric 	int r;
450*a824f5a1SJean-Baptiste Boric 
451*a824f5a1SJean-Baptiste Boric 	a = archive_read_new();
452*a824f5a1SJean-Baptiste Boric 	archive_read_support_compression_all(a);
453*a824f5a1SJean-Baptiste Boric 	archive_read_support_format_all(a);
454*a824f5a1SJean-Baptiste Boric 	if (archive_read_open_fd(a, fd, 1024)) {
455*a824f5a1SJean-Baptiste Boric 		warnx("Cannot open binary package: %s",
456*a824f5a1SJean-Baptiste Boric 		    archive_error_string(a));
457*a824f5a1SJean-Baptiste Boric 		archive_read_finish(a);
458*a824f5a1SJean-Baptiste Boric 		return NULL;
459*a824f5a1SJean-Baptiste Boric 	}
460*a824f5a1SJean-Baptiste Boric 
461*a824f5a1SJean-Baptiste Boric 	r = archive_read_next_header(a, &entry);
462*a824f5a1SJean-Baptiste Boric 	if (r != ARCHIVE_OK) {
463*a824f5a1SJean-Baptiste Boric 		warnx("Cannot extract package name: %s",
464*a824f5a1SJean-Baptiste Boric 		    r == ARCHIVE_EOF ? "EOF" : archive_error_string(a));
465*a824f5a1SJean-Baptiste Boric 		archive_read_finish(a);
466*a824f5a1SJean-Baptiste Boric 		return NULL;
467*a824f5a1SJean-Baptiste Boric 	}
468*a824f5a1SJean-Baptiste Boric 	if (strcmp(archive_entry_pathname(entry), "+CONTENTS") != 0) {
469*a824f5a1SJean-Baptiste Boric 		warnx("Invalid binary package, doesn't start with +CONTENTS");
470*a824f5a1SJean-Baptiste Boric 		archive_read_finish(a);
471*a824f5a1SJean-Baptiste Boric 		return NULL;
472*a824f5a1SJean-Baptiste Boric 	}
473*a824f5a1SJean-Baptiste Boric 	if (archive_entry_size(entry) > SSIZE_MAX - 1) {
474*a824f5a1SJean-Baptiste Boric 		warnx("+CONTENTS too large to process");
475*a824f5a1SJean-Baptiste Boric 		archive_read_finish(a);
476*a824f5a1SJean-Baptiste Boric 		return NULL;
477*a824f5a1SJean-Baptiste Boric 	}
478*a824f5a1SJean-Baptiste Boric 
479*a824f5a1SJean-Baptiste Boric 	len = archive_entry_size(entry);
480*a824f5a1SJean-Baptiste Boric 	buf = xmalloc(len + 1);
481*a824f5a1SJean-Baptiste Boric 
482*a824f5a1SJean-Baptiste Boric 	if (archive_read_data(a, buf, len) != len) {
483*a824f5a1SJean-Baptiste Boric 		warnx("Short read when extracing +CONTENTS");
484*a824f5a1SJean-Baptiste Boric 		free(buf);
485*a824f5a1SJean-Baptiste Boric 		archive_read_finish(a);
486*a824f5a1SJean-Baptiste Boric 		return NULL;
487*a824f5a1SJean-Baptiste Boric 	}
488*a824f5a1SJean-Baptiste Boric 	buf[len] = '\0';
489*a824f5a1SJean-Baptiste Boric 
490*a824f5a1SJean-Baptiste Boric 	archive_read_finish(a);
491*a824f5a1SJean-Baptiste Boric 
492*a824f5a1SJean-Baptiste Boric 	parse_plist(&plist, buf);
493*a824f5a1SJean-Baptiste Boric 	free(buf);
494*a824f5a1SJean-Baptiste Boric 	p = find_plist(&plist, PLIST_NAME);
495*a824f5a1SJean-Baptiste Boric 	if (p != NULL) {
496*a824f5a1SJean-Baptiste Boric 		buf = xstrdup(p->name);
497*a824f5a1SJean-Baptiste Boric 	} else {
498*a824f5a1SJean-Baptiste Boric 		warnx("Invalid PLIST: missing @name");
499*a824f5a1SJean-Baptiste Boric 		buf = NULL;
500*a824f5a1SJean-Baptiste Boric 	}
501*a824f5a1SJean-Baptiste Boric 	free_plist(&plist);
502*a824f5a1SJean-Baptiste Boric 
503*a824f5a1SJean-Baptiste Boric 	if (lseek(fd, 0, SEEK_SET) != 0) {
504*a824f5a1SJean-Baptiste Boric 		warn("Cannot seek in archive");
505*a824f5a1SJean-Baptiste Boric 		free(buf);
506*a824f5a1SJean-Baptiste Boric 		return NULL;
507*a824f5a1SJean-Baptiste Boric 	}
508*a824f5a1SJean-Baptiste Boric 
509*a824f5a1SJean-Baptiste Boric 	return buf;
510*a824f5a1SJean-Baptiste Boric }
511*a824f5a1SJean-Baptiste Boric 
512*a824f5a1SJean-Baptiste Boric static const char hash_template[] =
513*a824f5a1SJean-Baptiste Boric "pkgsrc signature\n"
514*a824f5a1SJean-Baptiste Boric "\n"
515*a824f5a1SJean-Baptiste Boric "version: 1\n"
516*a824f5a1SJean-Baptiste Boric "pkgname: %s\n"
517*a824f5a1SJean-Baptiste Boric "algorithm: SHA512\n"
518*a824f5a1SJean-Baptiste Boric "block size: 65536\n"
519*a824f5a1SJean-Baptiste Boric "file size: %lld\n"
520*a824f5a1SJean-Baptiste Boric "\n";
521*a824f5a1SJean-Baptiste Boric 
522*a824f5a1SJean-Baptiste Boric static const char hash_trailer[] = "end pkgsrc signature\n";
523*a824f5a1SJean-Baptiste Boric 
524*a824f5a1SJean-Baptiste Boric #ifdef HAVE_SSL
525*a824f5a1SJean-Baptiste Boric void
pkg_sign_x509(const char * name,const char * output,const char * key_file,const char * cert_file)526*a824f5a1SJean-Baptiste Boric pkg_sign_x509(const char *name, const char *output, const char *key_file, const char *cert_file)
527*a824f5a1SJean-Baptiste Boric {
528*a824f5a1SJean-Baptiste Boric 	struct archive *pkg;
529*a824f5a1SJean-Baptiste Boric 	struct archive_entry *entry, *hash_entry, *sign_entry;
530*a824f5a1SJean-Baptiste Boric 	int fd;
531*a824f5a1SJean-Baptiste Boric 	struct stat sb;
532*a824f5a1SJean-Baptiste Boric 	char *hash_file, *signature_file, *tmp, *pkgname, hash[SHA512_DIGEST_STRING_LENGTH];
533*a824f5a1SJean-Baptiste Boric 	unsigned char block[65536];
534*a824f5a1SJean-Baptiste Boric 	off_t i, size;
535*a824f5a1SJean-Baptiste Boric 	size_t block_len, signature_len;
536*a824f5a1SJean-Baptiste Boric 
537*a824f5a1SJean-Baptiste Boric 	if ((fd = open(name, O_RDONLY)) == -1)
538*a824f5a1SJean-Baptiste Boric 		err(EXIT_FAILURE, "Cannot open binary package %s", name);
539*a824f5a1SJean-Baptiste Boric 	if (fstat(fd, &sb) == -1)
540*a824f5a1SJean-Baptiste Boric 		err(EXIT_FAILURE, "Cannot stat %s", name);
541*a824f5a1SJean-Baptiste Boric 
542*a824f5a1SJean-Baptiste Boric 	entry = archive_entry_new();
543*a824f5a1SJean-Baptiste Boric 	archive_entry_copy_stat(entry, &sb);
544*a824f5a1SJean-Baptiste Boric 
545*a824f5a1SJean-Baptiste Boric 	pkgname = extract_pkgname(fd);
546*a824f5a1SJean-Baptiste Boric 	hash_file = xasprintf(hash_template, pkgname,
547*a824f5a1SJean-Baptiste Boric 	    (long long)archive_entry_size(entry));
548*a824f5a1SJean-Baptiste Boric 	free(pkgname);
549*a824f5a1SJean-Baptiste Boric 
550*a824f5a1SJean-Baptiste Boric 	for (i = 0; i < archive_entry_size(entry); i += block_len) {
551*a824f5a1SJean-Baptiste Boric 		if (i + (off_t)sizeof(block) < archive_entry_size(entry))
552*a824f5a1SJean-Baptiste Boric 			block_len = sizeof(block);
553*a824f5a1SJean-Baptiste Boric 		else
554*a824f5a1SJean-Baptiste Boric 			block_len = archive_entry_size(entry) % sizeof(block);
555*a824f5a1SJean-Baptiste Boric 		if (read(fd, block, block_len) != (ssize_t)block_len)
556*a824f5a1SJean-Baptiste Boric 			err(2, "short read");
557*a824f5a1SJean-Baptiste Boric 		hash_block(block, block_len, hash);
558*a824f5a1SJean-Baptiste Boric 		tmp = xasprintf("%s%s\n", hash_file, hash);
559*a824f5a1SJean-Baptiste Boric 		free(hash_file);
560*a824f5a1SJean-Baptiste Boric 		hash_file = tmp;
561*a824f5a1SJean-Baptiste Boric 	}
562*a824f5a1SJean-Baptiste Boric 	tmp = xasprintf("%s%s", hash_file, hash_trailer);
563*a824f5a1SJean-Baptiste Boric 	free(hash_file);
564*a824f5a1SJean-Baptiste Boric 	hash_file = tmp;
565*a824f5a1SJean-Baptiste Boric 
566*a824f5a1SJean-Baptiste Boric 	if (easy_pkcs7_sign(hash_file, strlen(hash_file), &signature_file,
567*a824f5a1SJean-Baptiste Boric 	    &signature_len, key_file, cert_file))
568*a824f5a1SJean-Baptiste Boric 		err(EXIT_FAILURE, "Cannot sign hash file");
569*a824f5a1SJean-Baptiste Boric 
570*a824f5a1SJean-Baptiste Boric 	lseek(fd, 0, SEEK_SET);
571*a824f5a1SJean-Baptiste Boric 
572*a824f5a1SJean-Baptiste Boric 	sign_entry = archive_entry_clone(entry);
573*a824f5a1SJean-Baptiste Boric 	hash_entry = archive_entry_clone(entry);
574*a824f5a1SJean-Baptiste Boric 	pkgname = strrchr(name, '/');
575*a824f5a1SJean-Baptiste Boric 	archive_entry_set_pathname(entry, pkgname != NULL ? pkgname + 1 : name);
576*a824f5a1SJean-Baptiste Boric 	archive_entry_set_pathname(hash_entry, HASH_FNAME);
577*a824f5a1SJean-Baptiste Boric 	archive_entry_set_pathname(sign_entry, SIGNATURE_FNAME);
578*a824f5a1SJean-Baptiste Boric 	archive_entry_set_size(hash_entry, strlen(hash_file));
579*a824f5a1SJean-Baptiste Boric 	archive_entry_set_size(sign_entry, signature_len);
580*a824f5a1SJean-Baptiste Boric 
581*a824f5a1SJean-Baptiste Boric 	pkg = archive_write_new();
582*a824f5a1SJean-Baptiste Boric 	archive_write_set_compression_none(pkg);
583*a824f5a1SJean-Baptiste Boric 	archive_write_set_format_ar_bsd(pkg);
584*a824f5a1SJean-Baptiste Boric 	archive_write_open_filename(pkg, output);
585*a824f5a1SJean-Baptiste Boric 
586*a824f5a1SJean-Baptiste Boric 	archive_write_header(pkg, hash_entry);
587*a824f5a1SJean-Baptiste Boric 	archive_write_data(pkg, hash_file, strlen(hash_file));
588*a824f5a1SJean-Baptiste Boric 	archive_write_finish_entry(pkg);
589*a824f5a1SJean-Baptiste Boric 	archive_entry_free(hash_entry);
590*a824f5a1SJean-Baptiste Boric 
591*a824f5a1SJean-Baptiste Boric 	archive_write_header(pkg, sign_entry);
592*a824f5a1SJean-Baptiste Boric 	archive_write_data(pkg, signature_file, signature_len);
593*a824f5a1SJean-Baptiste Boric 	archive_write_finish_entry(pkg);
594*a824f5a1SJean-Baptiste Boric 	archive_entry_free(sign_entry);
595*a824f5a1SJean-Baptiste Boric 
596*a824f5a1SJean-Baptiste Boric 	size = archive_entry_size(entry);
597*a824f5a1SJean-Baptiste Boric 	archive_write_header(pkg, entry);
598*a824f5a1SJean-Baptiste Boric 
599*a824f5a1SJean-Baptiste Boric 	for (i = 0; i < size; i += block_len) {
600*a824f5a1SJean-Baptiste Boric 		if (i + (off_t)sizeof(block) < size)
601*a824f5a1SJean-Baptiste Boric 			block_len = sizeof(block);
602*a824f5a1SJean-Baptiste Boric 		else
603*a824f5a1SJean-Baptiste Boric 			block_len = size % sizeof(block);
604*a824f5a1SJean-Baptiste Boric 		if (read(fd, block, block_len) != (ssize_t)block_len)
605*a824f5a1SJean-Baptiste Boric 			err(2, "short read");
606*a824f5a1SJean-Baptiste Boric 		archive_write_data(pkg, block, block_len);
607*a824f5a1SJean-Baptiste Boric 	}
608*a824f5a1SJean-Baptiste Boric 	archive_write_finish_entry(pkg);
609*a824f5a1SJean-Baptiste Boric 	archive_entry_free(entry);
610*a824f5a1SJean-Baptiste Boric 
611*a824f5a1SJean-Baptiste Boric 	archive_write_finish(pkg);
612*a824f5a1SJean-Baptiste Boric 
613*a824f5a1SJean-Baptiste Boric 	close(fd);
614*a824f5a1SJean-Baptiste Boric 
615*a824f5a1SJean-Baptiste Boric 	exit(0);
616*a824f5a1SJean-Baptiste Boric }
617*a824f5a1SJean-Baptiste Boric #endif
618*a824f5a1SJean-Baptiste Boric 
619*a824f5a1SJean-Baptiste Boric void
pkg_sign_gpg(const char * name,const char * output)620*a824f5a1SJean-Baptiste Boric pkg_sign_gpg(const char *name, const char *output)
621*a824f5a1SJean-Baptiste Boric {
622*a824f5a1SJean-Baptiste Boric 	struct archive *pkg;
623*a824f5a1SJean-Baptiste Boric 	struct archive_entry *entry, *hash_entry, *sign_entry;
624*a824f5a1SJean-Baptiste Boric 	int fd;
625*a824f5a1SJean-Baptiste Boric 	struct stat sb;
626*a824f5a1SJean-Baptiste Boric 	char *hash_file, *signature_file, *tmp, *pkgname, hash[SHA512_DIGEST_STRING_LENGTH];
627*a824f5a1SJean-Baptiste Boric 	unsigned char block[65536];
628*a824f5a1SJean-Baptiste Boric 	off_t i, size;
629*a824f5a1SJean-Baptiste Boric 	size_t block_len, signature_len;
630*a824f5a1SJean-Baptiste Boric 
631*a824f5a1SJean-Baptiste Boric 	if ((fd = open(name, O_RDONLY)) == -1)
632*a824f5a1SJean-Baptiste Boric 		err(EXIT_FAILURE, "Cannot open binary package %s", name);
633*a824f5a1SJean-Baptiste Boric 	if (fstat(fd, &sb) == -1)
634*a824f5a1SJean-Baptiste Boric 		err(EXIT_FAILURE, "Cannot stat %s", name);
635*a824f5a1SJean-Baptiste Boric 
636*a824f5a1SJean-Baptiste Boric 	entry = archive_entry_new();
637*a824f5a1SJean-Baptiste Boric 	archive_entry_copy_stat(entry, &sb);
638*a824f5a1SJean-Baptiste Boric 
639*a824f5a1SJean-Baptiste Boric 	pkgname = extract_pkgname(fd);
640*a824f5a1SJean-Baptiste Boric 	hash_file = xasprintf(hash_template, pkgname,
641*a824f5a1SJean-Baptiste Boric 	    (long long)archive_entry_size(entry));
642*a824f5a1SJean-Baptiste Boric 	free(pkgname);
643*a824f5a1SJean-Baptiste Boric 
644*a824f5a1SJean-Baptiste Boric 	for (i = 0; i < archive_entry_size(entry); i += block_len) {
645*a824f5a1SJean-Baptiste Boric 		if (i + (off_t)sizeof(block) < archive_entry_size(entry))
646*a824f5a1SJean-Baptiste Boric 			block_len = sizeof(block);
647*a824f5a1SJean-Baptiste Boric 		else
648*a824f5a1SJean-Baptiste Boric 			block_len = archive_entry_size(entry) % sizeof(block);
649*a824f5a1SJean-Baptiste Boric 		if (read(fd, block, block_len) != (ssize_t)block_len)
650*a824f5a1SJean-Baptiste Boric 			err(2, "short read");
651*a824f5a1SJean-Baptiste Boric 		hash_block(block, block_len, hash);
652*a824f5a1SJean-Baptiste Boric 		tmp = xasprintf("%s%s\n", hash_file, hash);
653*a824f5a1SJean-Baptiste Boric 		free(hash_file);
654*a824f5a1SJean-Baptiste Boric 		hash_file = tmp;
655*a824f5a1SJean-Baptiste Boric 	}
656*a824f5a1SJean-Baptiste Boric 	tmp = xasprintf("%s%s", hash_file, hash_trailer);
657*a824f5a1SJean-Baptiste Boric 	free(hash_file);
658*a824f5a1SJean-Baptiste Boric 	hash_file = tmp;
659*a824f5a1SJean-Baptiste Boric 
660*a824f5a1SJean-Baptiste Boric 	if (detached_gpg_sign(hash_file, strlen(hash_file), &signature_file,
661*a824f5a1SJean-Baptiste Boric 	    &signature_len, gpg_keyring_sign, gpg_sign_as))
662*a824f5a1SJean-Baptiste Boric 		err(EXIT_FAILURE, "Cannot sign hash file");
663*a824f5a1SJean-Baptiste Boric 
664*a824f5a1SJean-Baptiste Boric 	lseek(fd, 0, SEEK_SET);
665*a824f5a1SJean-Baptiste Boric 
666*a824f5a1SJean-Baptiste Boric 	sign_entry = archive_entry_clone(entry);
667*a824f5a1SJean-Baptiste Boric 	hash_entry = archive_entry_clone(entry);
668*a824f5a1SJean-Baptiste Boric 	pkgname = strrchr(name, '/');
669*a824f5a1SJean-Baptiste Boric 	archive_entry_set_pathname(entry, pkgname != NULL ? pkgname + 1 : name);
670*a824f5a1SJean-Baptiste Boric 	archive_entry_set_pathname(hash_entry, HASH_FNAME);
671*a824f5a1SJean-Baptiste Boric 	archive_entry_set_pathname(sign_entry, GPG_SIGNATURE_FNAME);
672*a824f5a1SJean-Baptiste Boric 	archive_entry_set_size(hash_entry, strlen(hash_file));
673*a824f5a1SJean-Baptiste Boric 	archive_entry_set_size(sign_entry, signature_len);
674*a824f5a1SJean-Baptiste Boric 
675*a824f5a1SJean-Baptiste Boric 	pkg = archive_write_new();
676*a824f5a1SJean-Baptiste Boric 	archive_write_set_compression_none(pkg);
677*a824f5a1SJean-Baptiste Boric 	archive_write_set_format_ar_bsd(pkg);
678*a824f5a1SJean-Baptiste Boric 	archive_write_open_filename(pkg, output);
679*a824f5a1SJean-Baptiste Boric 
680*a824f5a1SJean-Baptiste Boric 	archive_write_header(pkg, hash_entry);
681*a824f5a1SJean-Baptiste Boric 	archive_write_data(pkg, hash_file, strlen(hash_file));
682*a824f5a1SJean-Baptiste Boric 	archive_write_finish_entry(pkg);
683*a824f5a1SJean-Baptiste Boric 	archive_entry_free(hash_entry);
684*a824f5a1SJean-Baptiste Boric 
685*a824f5a1SJean-Baptiste Boric 	archive_write_header(pkg, sign_entry);
686*a824f5a1SJean-Baptiste Boric 	archive_write_data(pkg, signature_file, signature_len);
687*a824f5a1SJean-Baptiste Boric 	archive_write_finish_entry(pkg);
688*a824f5a1SJean-Baptiste Boric 	archive_entry_free(sign_entry);
689*a824f5a1SJean-Baptiste Boric 
690*a824f5a1SJean-Baptiste Boric 	size = archive_entry_size(entry);
691*a824f5a1SJean-Baptiste Boric 	archive_write_header(pkg, entry);
692*a824f5a1SJean-Baptiste Boric 
693*a824f5a1SJean-Baptiste Boric 	for (i = 0; i < size; i += block_len) {
694*a824f5a1SJean-Baptiste Boric 		if (i + (off_t)sizeof(block) < size)
695*a824f5a1SJean-Baptiste Boric 			block_len = sizeof(block);
696*a824f5a1SJean-Baptiste Boric 		else
697*a824f5a1SJean-Baptiste Boric 			block_len = size % sizeof(block);
698*a824f5a1SJean-Baptiste Boric 		if (read(fd, block, block_len) != (ssize_t)block_len)
699*a824f5a1SJean-Baptiste Boric 			err(2, "short read");
700*a824f5a1SJean-Baptiste Boric 		archive_write_data(pkg, block, block_len);
701*a824f5a1SJean-Baptiste Boric 	}
702*a824f5a1SJean-Baptiste Boric 	archive_write_finish_entry(pkg);
703*a824f5a1SJean-Baptiste Boric 	archive_entry_free(entry);
704*a824f5a1SJean-Baptiste Boric 
705*a824f5a1SJean-Baptiste Boric 	archive_write_finish(pkg);
706*a824f5a1SJean-Baptiste Boric 
707*a824f5a1SJean-Baptiste Boric 	close(fd);
708*a824f5a1SJean-Baptiste Boric 
709*a824f5a1SJean-Baptiste Boric 	exit(0);
710*a824f5a1SJean-Baptiste Boric }
711