xref: /minix/external/bsd/pkg_install/dist/lib/gpgsig.c (revision 0a6a1f1d)
1 /*	$NetBSD: gpgsig.c,v 1.1.1.2 2009/08/06 16:55:27 joerg Exp $	*/
2 #if HAVE_CONFIG_H
3 #include "config.h"
4 #endif
5 #include <nbcompat.h>
6 #if HAVE_SYS_CDEFS_H
7 #include <sys/cdefs.h>
8 #endif
9 
10 __RCSID("$NetBSD: gpgsig.c,v 1.1.1.2 2009/08/06 16:55:27 joerg Exp $");
11 
12 /*-
13  * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>.
14  * All rights reserved.
15  *
16  * Redistribution and use in source and binary forms, with or without
17  * modification, are permitted provided that the following conditions
18  * are met:
19  *
20  * 1. Redistributions of source code must retain the above copyright
21  *    notice, this list of conditions and the following disclaimer.
22  * 2. Redistributions in binary form must reproduce the above copyright
23  *    notice, this list of conditions and the following disclaimer in
24  *    the documentation and/or other materials provided with the
25  *    distribution.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
30  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
31  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
32  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
33  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
34  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
35  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
36  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
37  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  */
40 
41 #include <sys/wait.h>
42 #ifndef NETBSD
43 #include <nbcompat/err.h>
44 #else
45 #include <err.h>
46 #endif
47 #ifndef NETBSD
48 #include <nbcompat/stdlib.h>
49 #else
50 #include <stdlib.h>
51 #endif
52 
53 #include "lib.h"
54 
55 static void
56 verify_signature(const char *input, size_t input_len, const char *keyring,
57     const char *detached_signature)
58 {
59 	const char *argv[8], **argvp;
60 	pid_t child;
61 	int fd[2], status;
62 
63 	if (pipe(fd) == -1)
64 		err(EXIT_FAILURE, "cannot create input pipes");
65 
66 	child = vfork();
67 	if (child == -1)
68 		err(EXIT_FAILURE, "cannot fork GPG process");
69 	if (child == 0) {
70 		close(fd[1]);
71 		close(STDIN_FILENO);
72 		if (dup2(fd[0], STDIN_FILENO) == -1) {
73 			static const char err_msg[] =
74 			    "cannot redirect stdin of GPG process\n";
75 			write(STDERR_FILENO, err_msg, sizeof(err_msg) - 1);
76 			_exit(255);
77 		}
78 		close(fd[0]);
79 		argvp = argv;
80 		*argvp++ = gpg_cmd;
81 		*argvp++ = "--verify";
82 		if (keyring != NULL) {
83 			*argvp++ = "--no-default-keyring";
84 			*argvp++ = "--keyring";
85 			*argvp++ = keyring;
86 		}
87 
88 		if (detached_signature != NULL)
89 			*argvp++ = detached_signature;
90 		*argvp++ = "-";
91 
92 		*argvp = NULL;
93 
94 		execvp(gpg_cmd, __UNCONST(argv));
95 		_exit(255);
96 	}
97 	close(fd[0]);
98 	if (write(fd[1], input, input_len) != (ssize_t)input_len)
99 		errx(EXIT_FAILURE, "Short read from GPG");
100 	close(fd[1]);
101 	waitpid(child, &status, 0);
102 	if (status)
103 		errx(EXIT_FAILURE, "GPG could not verify the signature");
104 }
105 
106 int
107 inline_gpg_verify(const char *content, size_t len, const char *keyring)
108 {
109 	verify_signature(content, len, keyring, NULL);
110 
111 	return 0;
112 }
113 
114 int
115 detached_gpg_verify(const char *content, size_t len,
116     const char *signature, size_t signature_len, const char *keyring)
117 {
118 	int fd;
119 	const char *tmpdir;
120 	char *tempsig;
121 	ssize_t ret;
122 
123 	if (gpg_cmd == NULL) {
124 		warnx("GPG variable not set, failing signature check");
125 		return -1;
126 	}
127 
128 	if ((tmpdir = getenv("TMPDIR")) == NULL)
129 		tmpdir = "/tmp";
130 	tempsig = xasprintf("%s/pkg_install.XXXXXX", tmpdir);
131 
132 	fd = mkstemp(tempsig);
133 	if (fd == -1) {
134 		warnx("Creating temporary file for GPG signature failed");
135 		return -1;
136 	}
137 
138 	while (signature_len) {
139 		ret = write(fd, signature, signature_len);
140 		if (ret == -1)
141 			err(EXIT_FAILURE, "Write to GPG failed");
142 		if (ret == 0)
143 			errx(EXIT_FAILURE, "Short write to GPG");
144 		signature_len -= ret;
145 		signature += ret;
146 	}
147 
148 	verify_signature(content, len, keyring, tempsig);
149 
150 	unlink(tempsig);
151 	close(fd);
152 	free(tempsig);
153 
154 	return 0;
155 }
156 
157 int
158 detached_gpg_sign(const char *content, size_t len, char **sig, size_t *sig_len,
159     const char *keyring, const char *user)
160 {
161 	const char *argv[12], **argvp;
162 	pid_t child;
163 	int fd_in[2], fd_out[2], status;
164 	size_t allocated;
165 	ssize_t ret;
166 
167 	if (gpg_cmd == NULL)
168 		errx(EXIT_FAILURE, "GPG variable not set");
169 
170 	if (pipe(fd_in) == -1)
171 		err(EXIT_FAILURE, "cannot create input pipes");
172 	if (pipe(fd_out) == -1)
173 		err(EXIT_FAILURE, "cannot create output pipes");
174 
175 	child = fork();
176 	if (child == -1)
177 		err(EXIT_FAILURE, "cannot fork GPG process");
178 	if (child == 0) {
179 		close(fd_in[1]);
180 		close(STDIN_FILENO);
181 		if (dup2(fd_in[0], STDIN_FILENO) == -1) {
182 			static const char err_msg[] =
183 			    "cannot redirect stdin of GPG process\n";
184 			write(STDERR_FILENO, err_msg, sizeof(err_msg) - 1);
185 			_exit(255);
186 		}
187 		close(fd_in[0]);
188 
189 		close(fd_out[0]);
190 		close(STDOUT_FILENO);
191 		if (dup2(fd_out[1], STDOUT_FILENO) == -1) {
192 			static const char err_msg[] =
193 			    "cannot redirect stdout of GPG process\n";
194 			write(STDERR_FILENO, err_msg, sizeof(err_msg) - 1);
195 			_exit(255);
196 		}
197 		close(fd_out[1]);
198 
199 		argvp = argv;
200 		*argvp++ = gpg_cmd;
201 		*argvp++ = "--detach-sign";
202 		*argvp++ = "--armor";
203 		*argvp++ = "--output";
204 		*argvp++ = "-";
205 		if (user != NULL) {
206 			*argvp++ = "--local-user";
207 			*argvp++ = user;
208 		}
209 		if (keyring != NULL) {
210 			*argvp++ = "--no-default-keyring";
211 			*argvp++ = "--secret-keyring";
212 			*argvp++ = keyring;
213 		}
214 
215 		*argvp++ = "-";
216 		*argvp = NULL;
217 
218 		execvp(gpg_cmd, __UNCONST(argv));
219 		_exit(255);
220 	}
221 	close(fd_in[0]);
222 	if (write(fd_in[1], content, len) != (ssize_t)len)
223 		errx(EXIT_FAILURE, "Short read from GPG");
224 	close(fd_in[1]);
225 
226 	allocated = 1024;
227 	*sig = xmalloc(allocated);
228 	*sig_len = 0;
229 
230 	close(fd_out[1]);
231 
232 	while ((ret = read(fd_out[0], *sig + *sig_len,
233 	    allocated - *sig_len)) > 0) {
234 		*sig_len += ret;
235 		if (*sig_len == allocated) {
236 			allocated *= 2;
237 			*sig = xrealloc(*sig, allocated);
238 		}
239 	}
240 
241 	close(fd_out[0]);
242 
243 	waitpid(child, &status, 0);
244 	if (status)
245 		errx(EXIT_FAILURE, "GPG could not create signature");
246 
247 	return 0;
248 }
249