xref: /minix3/external/bsd/pkg_install/dist/lib/gpgsig.c (revision a824f5a1008ee67499d167f8c48e64aae26960ca)
1*a824f5a1SJean-Baptiste Boric /*	$NetBSD: gpgsig.c,v 1.1.1.2 2009/08/06 16:55:27 joerg Exp $	*/
2*a824f5a1SJean-Baptiste Boric #if HAVE_CONFIG_H
3*a824f5a1SJean-Baptiste Boric #include "config.h"
4*a824f5a1SJean-Baptiste Boric #endif
5*a824f5a1SJean-Baptiste Boric #include <nbcompat.h>
6*a824f5a1SJean-Baptiste Boric #if HAVE_SYS_CDEFS_H
7*a824f5a1SJean-Baptiste Boric #include <sys/cdefs.h>
8*a824f5a1SJean-Baptiste Boric #endif
9*a824f5a1SJean-Baptiste Boric 
10*a824f5a1SJean-Baptiste Boric __RCSID("$NetBSD: gpgsig.c,v 1.1.1.2 2009/08/06 16:55:27 joerg 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 #include <sys/wait.h>
42*a824f5a1SJean-Baptiste Boric #ifndef NETBSD
43*a824f5a1SJean-Baptiste Boric #include <nbcompat/err.h>
44*a824f5a1SJean-Baptiste Boric #else
45*a824f5a1SJean-Baptiste Boric #include <err.h>
46*a824f5a1SJean-Baptiste Boric #endif
47*a824f5a1SJean-Baptiste Boric #ifndef NETBSD
48*a824f5a1SJean-Baptiste Boric #include <nbcompat/stdlib.h>
49*a824f5a1SJean-Baptiste Boric #else
50*a824f5a1SJean-Baptiste Boric #include <stdlib.h>
51*a824f5a1SJean-Baptiste Boric #endif
52*a824f5a1SJean-Baptiste Boric 
53*a824f5a1SJean-Baptiste Boric #include "lib.h"
54*a824f5a1SJean-Baptiste Boric 
55*a824f5a1SJean-Baptiste Boric static void
verify_signature(const char * input,size_t input_len,const char * keyring,const char * detached_signature)56*a824f5a1SJean-Baptiste Boric verify_signature(const char *input, size_t input_len, const char *keyring,
57*a824f5a1SJean-Baptiste Boric     const char *detached_signature)
58*a824f5a1SJean-Baptiste Boric {
59*a824f5a1SJean-Baptiste Boric 	const char *argv[8], **argvp;
60*a824f5a1SJean-Baptiste Boric 	pid_t child;
61*a824f5a1SJean-Baptiste Boric 	int fd[2], status;
62*a824f5a1SJean-Baptiste Boric 
63*a824f5a1SJean-Baptiste Boric 	if (pipe(fd) == -1)
64*a824f5a1SJean-Baptiste Boric 		err(EXIT_FAILURE, "cannot create input pipes");
65*a824f5a1SJean-Baptiste Boric 
66*a824f5a1SJean-Baptiste Boric 	child = vfork();
67*a824f5a1SJean-Baptiste Boric 	if (child == -1)
68*a824f5a1SJean-Baptiste Boric 		err(EXIT_FAILURE, "cannot fork GPG process");
69*a824f5a1SJean-Baptiste Boric 	if (child == 0) {
70*a824f5a1SJean-Baptiste Boric 		close(fd[1]);
71*a824f5a1SJean-Baptiste Boric 		close(STDIN_FILENO);
72*a824f5a1SJean-Baptiste Boric 		if (dup2(fd[0], STDIN_FILENO) == -1) {
73*a824f5a1SJean-Baptiste Boric 			static const char err_msg[] =
74*a824f5a1SJean-Baptiste Boric 			    "cannot redirect stdin of GPG process\n";
75*a824f5a1SJean-Baptiste Boric 			write(STDERR_FILENO, err_msg, sizeof(err_msg) - 1);
76*a824f5a1SJean-Baptiste Boric 			_exit(255);
77*a824f5a1SJean-Baptiste Boric 		}
78*a824f5a1SJean-Baptiste Boric 		close(fd[0]);
79*a824f5a1SJean-Baptiste Boric 		argvp = argv;
80*a824f5a1SJean-Baptiste Boric 		*argvp++ = gpg_cmd;
81*a824f5a1SJean-Baptiste Boric 		*argvp++ = "--verify";
82*a824f5a1SJean-Baptiste Boric 		if (keyring != NULL) {
83*a824f5a1SJean-Baptiste Boric 			*argvp++ = "--no-default-keyring";
84*a824f5a1SJean-Baptiste Boric 			*argvp++ = "--keyring";
85*a824f5a1SJean-Baptiste Boric 			*argvp++ = keyring;
86*a824f5a1SJean-Baptiste Boric 		}
87*a824f5a1SJean-Baptiste Boric 
88*a824f5a1SJean-Baptiste Boric 		if (detached_signature != NULL)
89*a824f5a1SJean-Baptiste Boric 			*argvp++ = detached_signature;
90*a824f5a1SJean-Baptiste Boric 		*argvp++ = "-";
91*a824f5a1SJean-Baptiste Boric 
92*a824f5a1SJean-Baptiste Boric 		*argvp = NULL;
93*a824f5a1SJean-Baptiste Boric 
94*a824f5a1SJean-Baptiste Boric 		execvp(gpg_cmd, __UNCONST(argv));
95*a824f5a1SJean-Baptiste Boric 		_exit(255);
96*a824f5a1SJean-Baptiste Boric 	}
97*a824f5a1SJean-Baptiste Boric 	close(fd[0]);
98*a824f5a1SJean-Baptiste Boric 	if (write(fd[1], input, input_len) != (ssize_t)input_len)
99*a824f5a1SJean-Baptiste Boric 		errx(EXIT_FAILURE, "Short read from GPG");
100*a824f5a1SJean-Baptiste Boric 	close(fd[1]);
101*a824f5a1SJean-Baptiste Boric 	waitpid(child, &status, 0);
102*a824f5a1SJean-Baptiste Boric 	if (status)
103*a824f5a1SJean-Baptiste Boric 		errx(EXIT_FAILURE, "GPG could not verify the signature");
104*a824f5a1SJean-Baptiste Boric }
105*a824f5a1SJean-Baptiste Boric 
106*a824f5a1SJean-Baptiste Boric int
inline_gpg_verify(const char * content,size_t len,const char * keyring)107*a824f5a1SJean-Baptiste Boric inline_gpg_verify(const char *content, size_t len, const char *keyring)
108*a824f5a1SJean-Baptiste Boric {
109*a824f5a1SJean-Baptiste Boric 	verify_signature(content, len, keyring, NULL);
110*a824f5a1SJean-Baptiste Boric 
111*a824f5a1SJean-Baptiste Boric 	return 0;
112*a824f5a1SJean-Baptiste Boric }
113*a824f5a1SJean-Baptiste Boric 
114*a824f5a1SJean-Baptiste Boric int
detached_gpg_verify(const char * content,size_t len,const char * signature,size_t signature_len,const char * keyring)115*a824f5a1SJean-Baptiste Boric detached_gpg_verify(const char *content, size_t len,
116*a824f5a1SJean-Baptiste Boric     const char *signature, size_t signature_len, const char *keyring)
117*a824f5a1SJean-Baptiste Boric {
118*a824f5a1SJean-Baptiste Boric 	int fd;
119*a824f5a1SJean-Baptiste Boric 	const char *tmpdir;
120*a824f5a1SJean-Baptiste Boric 	char *tempsig;
121*a824f5a1SJean-Baptiste Boric 	ssize_t ret;
122*a824f5a1SJean-Baptiste Boric 
123*a824f5a1SJean-Baptiste Boric 	if (gpg_cmd == NULL) {
124*a824f5a1SJean-Baptiste Boric 		warnx("GPG variable not set, failing signature check");
125*a824f5a1SJean-Baptiste Boric 		return -1;
126*a824f5a1SJean-Baptiste Boric 	}
127*a824f5a1SJean-Baptiste Boric 
128*a824f5a1SJean-Baptiste Boric 	if ((tmpdir = getenv("TMPDIR")) == NULL)
129*a824f5a1SJean-Baptiste Boric 		tmpdir = "/tmp";
130*a824f5a1SJean-Baptiste Boric 	tempsig = xasprintf("%s/pkg_install.XXXXXX", tmpdir);
131*a824f5a1SJean-Baptiste Boric 
132*a824f5a1SJean-Baptiste Boric 	fd = mkstemp(tempsig);
133*a824f5a1SJean-Baptiste Boric 	if (fd == -1) {
134*a824f5a1SJean-Baptiste Boric 		warnx("Creating temporary file for GPG signature failed");
135*a824f5a1SJean-Baptiste Boric 		return -1;
136*a824f5a1SJean-Baptiste Boric 	}
137*a824f5a1SJean-Baptiste Boric 
138*a824f5a1SJean-Baptiste Boric 	while (signature_len) {
139*a824f5a1SJean-Baptiste Boric 		ret = write(fd, signature, signature_len);
140*a824f5a1SJean-Baptiste Boric 		if (ret == -1)
141*a824f5a1SJean-Baptiste Boric 			err(EXIT_FAILURE, "Write to GPG failed");
142*a824f5a1SJean-Baptiste Boric 		if (ret == 0)
143*a824f5a1SJean-Baptiste Boric 			errx(EXIT_FAILURE, "Short write to GPG");
144*a824f5a1SJean-Baptiste Boric 		signature_len -= ret;
145*a824f5a1SJean-Baptiste Boric 		signature += ret;
146*a824f5a1SJean-Baptiste Boric 	}
147*a824f5a1SJean-Baptiste Boric 
148*a824f5a1SJean-Baptiste Boric 	verify_signature(content, len, keyring, tempsig);
149*a824f5a1SJean-Baptiste Boric 
150*a824f5a1SJean-Baptiste Boric 	unlink(tempsig);
151*a824f5a1SJean-Baptiste Boric 	close(fd);
152*a824f5a1SJean-Baptiste Boric 	free(tempsig);
153*a824f5a1SJean-Baptiste Boric 
154*a824f5a1SJean-Baptiste Boric 	return 0;
155*a824f5a1SJean-Baptiste Boric }
156*a824f5a1SJean-Baptiste Boric 
157*a824f5a1SJean-Baptiste Boric int
detached_gpg_sign(const char * content,size_t len,char ** sig,size_t * sig_len,const char * keyring,const char * user)158*a824f5a1SJean-Baptiste Boric detached_gpg_sign(const char *content, size_t len, char **sig, size_t *sig_len,
159*a824f5a1SJean-Baptiste Boric     const char *keyring, const char *user)
160*a824f5a1SJean-Baptiste Boric {
161*a824f5a1SJean-Baptiste Boric 	const char *argv[12], **argvp;
162*a824f5a1SJean-Baptiste Boric 	pid_t child;
163*a824f5a1SJean-Baptiste Boric 	int fd_in[2], fd_out[2], status;
164*a824f5a1SJean-Baptiste Boric 	size_t allocated;
165*a824f5a1SJean-Baptiste Boric 	ssize_t ret;
166*a824f5a1SJean-Baptiste Boric 
167*a824f5a1SJean-Baptiste Boric 	if (gpg_cmd == NULL)
168*a824f5a1SJean-Baptiste Boric 		errx(EXIT_FAILURE, "GPG variable not set");
169*a824f5a1SJean-Baptiste Boric 
170*a824f5a1SJean-Baptiste Boric 	if (pipe(fd_in) == -1)
171*a824f5a1SJean-Baptiste Boric 		err(EXIT_FAILURE, "cannot create input pipes");
172*a824f5a1SJean-Baptiste Boric 	if (pipe(fd_out) == -1)
173*a824f5a1SJean-Baptiste Boric 		err(EXIT_FAILURE, "cannot create output pipes");
174*a824f5a1SJean-Baptiste Boric 
175*a824f5a1SJean-Baptiste Boric 	child = fork();
176*a824f5a1SJean-Baptiste Boric 	if (child == -1)
177*a824f5a1SJean-Baptiste Boric 		err(EXIT_FAILURE, "cannot fork GPG process");
178*a824f5a1SJean-Baptiste Boric 	if (child == 0) {
179*a824f5a1SJean-Baptiste Boric 		close(fd_in[1]);
180*a824f5a1SJean-Baptiste Boric 		close(STDIN_FILENO);
181*a824f5a1SJean-Baptiste Boric 		if (dup2(fd_in[0], STDIN_FILENO) == -1) {
182*a824f5a1SJean-Baptiste Boric 			static const char err_msg[] =
183*a824f5a1SJean-Baptiste Boric 			    "cannot redirect stdin of GPG process\n";
184*a824f5a1SJean-Baptiste Boric 			write(STDERR_FILENO, err_msg, sizeof(err_msg) - 1);
185*a824f5a1SJean-Baptiste Boric 			_exit(255);
186*a824f5a1SJean-Baptiste Boric 		}
187*a824f5a1SJean-Baptiste Boric 		close(fd_in[0]);
188*a824f5a1SJean-Baptiste Boric 
189*a824f5a1SJean-Baptiste Boric 		close(fd_out[0]);
190*a824f5a1SJean-Baptiste Boric 		close(STDOUT_FILENO);
191*a824f5a1SJean-Baptiste Boric 		if (dup2(fd_out[1], STDOUT_FILENO) == -1) {
192*a824f5a1SJean-Baptiste Boric 			static const char err_msg[] =
193*a824f5a1SJean-Baptiste Boric 			    "cannot redirect stdout of GPG process\n";
194*a824f5a1SJean-Baptiste Boric 			write(STDERR_FILENO, err_msg, sizeof(err_msg) - 1);
195*a824f5a1SJean-Baptiste Boric 			_exit(255);
196*a824f5a1SJean-Baptiste Boric 		}
197*a824f5a1SJean-Baptiste Boric 		close(fd_out[1]);
198*a824f5a1SJean-Baptiste Boric 
199*a824f5a1SJean-Baptiste Boric 		argvp = argv;
200*a824f5a1SJean-Baptiste Boric 		*argvp++ = gpg_cmd;
201*a824f5a1SJean-Baptiste Boric 		*argvp++ = "--detach-sign";
202*a824f5a1SJean-Baptiste Boric 		*argvp++ = "--armor";
203*a824f5a1SJean-Baptiste Boric 		*argvp++ = "--output";
204*a824f5a1SJean-Baptiste Boric 		*argvp++ = "-";
205*a824f5a1SJean-Baptiste Boric 		if (user != NULL) {
206*a824f5a1SJean-Baptiste Boric 			*argvp++ = "--local-user";
207*a824f5a1SJean-Baptiste Boric 			*argvp++ = user;
208*a824f5a1SJean-Baptiste Boric 		}
209*a824f5a1SJean-Baptiste Boric 		if (keyring != NULL) {
210*a824f5a1SJean-Baptiste Boric 			*argvp++ = "--no-default-keyring";
211*a824f5a1SJean-Baptiste Boric 			*argvp++ = "--secret-keyring";
212*a824f5a1SJean-Baptiste Boric 			*argvp++ = keyring;
213*a824f5a1SJean-Baptiste Boric 		}
214*a824f5a1SJean-Baptiste Boric 
215*a824f5a1SJean-Baptiste Boric 		*argvp++ = "-";
216*a824f5a1SJean-Baptiste Boric 		*argvp = NULL;
217*a824f5a1SJean-Baptiste Boric 
218*a824f5a1SJean-Baptiste Boric 		execvp(gpg_cmd, __UNCONST(argv));
219*a824f5a1SJean-Baptiste Boric 		_exit(255);
220*a824f5a1SJean-Baptiste Boric 	}
221*a824f5a1SJean-Baptiste Boric 	close(fd_in[0]);
222*a824f5a1SJean-Baptiste Boric 	if (write(fd_in[1], content, len) != (ssize_t)len)
223*a824f5a1SJean-Baptiste Boric 		errx(EXIT_FAILURE, "Short read from GPG");
224*a824f5a1SJean-Baptiste Boric 	close(fd_in[1]);
225*a824f5a1SJean-Baptiste Boric 
226*a824f5a1SJean-Baptiste Boric 	allocated = 1024;
227*a824f5a1SJean-Baptiste Boric 	*sig = xmalloc(allocated);
228*a824f5a1SJean-Baptiste Boric 	*sig_len = 0;
229*a824f5a1SJean-Baptiste Boric 
230*a824f5a1SJean-Baptiste Boric 	close(fd_out[1]);
231*a824f5a1SJean-Baptiste Boric 
232*a824f5a1SJean-Baptiste Boric 	while ((ret = read(fd_out[0], *sig + *sig_len,
233*a824f5a1SJean-Baptiste Boric 	    allocated - *sig_len)) > 0) {
234*a824f5a1SJean-Baptiste Boric 		*sig_len += ret;
235*a824f5a1SJean-Baptiste Boric 		if (*sig_len == allocated) {
236*a824f5a1SJean-Baptiste Boric 			allocated *= 2;
237*a824f5a1SJean-Baptiste Boric 			*sig = xrealloc(*sig, allocated);
238*a824f5a1SJean-Baptiste Boric 		}
239*a824f5a1SJean-Baptiste Boric 	}
240*a824f5a1SJean-Baptiste Boric 
241*a824f5a1SJean-Baptiste Boric 	close(fd_out[0]);
242*a824f5a1SJean-Baptiste Boric 
243*a824f5a1SJean-Baptiste Boric 	waitpid(child, &status, 0);
244*a824f5a1SJean-Baptiste Boric 	if (status)
245*a824f5a1SJean-Baptiste Boric 		errx(EXIT_FAILURE, "GPG could not create signature");
246*a824f5a1SJean-Baptiste Boric 
247*a824f5a1SJean-Baptiste Boric 	return 0;
248*a824f5a1SJean-Baptiste Boric }
249