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