xref: /netbsd-src/external/bsd/pkg_install/dist/lib/gpgsig.c (revision f46918ca2125b9b1e7ca5a22c07d1414c618e467)
1 /*	$NetBSD: gpgsig.c,v 1.3 2021/04/10 19:49:59 nia 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.3 2021/04/10 19:49:59 nia 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 <netpgp/verify.h>
54 
55 #include "lib.h"
56 
57 int
gpg_verify(const char * content,size_t len,const char * keyring,const char * sig,size_t sig_len)58 gpg_verify(const char *content, size_t len, const char *keyring,
59     const char *sig, size_t sig_len)
60 {
61 	pgpv_t *pgp;
62 	pgpv_cursor_t *cursor;
63 	static const char hdr1[] = "-----BEGIN PGP SIGNED MESSAGE-----\n";
64 	static const char hdr2[] = "Hash: SHA512\n\n";
65 	ssize_t buflen;
66 	char *allocated_buf;
67 	const char *buf;
68 
69 	/*
70 	 * If there is a detached signature we need to construct a format that
71 	 * netpgp can parse, otherwise use as-is.
72 	 */
73 	if (sig_len) {
74 		buf = allocated_buf = xasprintf("%s%s%s%s", hdr1, hdr2, content, sig);
75 		buflen = strlen(buf);
76 	} else {
77 		buf = content;
78 		allocated_buf = NULL;
79 		buflen = len;
80 	}
81 
82 	pgp = pgpv_new();
83 	cursor = pgpv_new_cursor();
84 
85 	if (!pgpv_read_pubring(pgp, keyring, -1))
86 		err(EXIT_FAILURE, "cannot read keyring");
87 
88 	if (!pgpv_verify(cursor, pgp, buf, buflen))
89 		errx(EXIT_FAILURE, "unable to verify signature: %s",
90 		    pgpv_get_cursor_str(cursor, "why"));
91 
92 	pgpv_close(pgp);
93 
94 	free(allocated_buf);
95 
96 	return 0;
97 }
98 
99 int
detached_gpg_sign(const char * content,size_t len,char ** sig,size_t * sig_len,const char * keyring,const char * user)100 detached_gpg_sign(const char *content, size_t len, char **sig, size_t *sig_len,
101     const char *keyring, const char *user)
102 {
103 	const char *argv[12], **argvp;
104 	pid_t child;
105 	int fd_in[2], fd_out[2], status;
106 	size_t allocated;
107 	ssize_t ret;
108 
109 	if (gpg_cmd == NULL)
110 		errx(EXIT_FAILURE, "GPG variable not set");
111 
112 	if (pipe(fd_in) == -1)
113 		err(EXIT_FAILURE, "cannot create input pipes");
114 	if (pipe(fd_out) == -1)
115 		err(EXIT_FAILURE, "cannot create output pipes");
116 
117 	child = fork();
118 	if (child == -1)
119 		err(EXIT_FAILURE, "cannot fork GPG process");
120 	if (child == 0) {
121 		close(fd_in[1]);
122 		close(STDIN_FILENO);
123 		if (dup2(fd_in[0], STDIN_FILENO) == -1) {
124 			static const char err_msg[] =
125 			    "cannot redirect stdin of GPG process\n";
126 			write(STDERR_FILENO, err_msg, sizeof(err_msg) - 1);
127 			_exit(255);
128 		}
129 		close(fd_in[0]);
130 
131 		close(fd_out[0]);
132 		close(STDOUT_FILENO);
133 		if (dup2(fd_out[1], STDOUT_FILENO) == -1) {
134 			static const char err_msg[] =
135 			    "cannot redirect stdout of GPG process\n";
136 			write(STDERR_FILENO, err_msg, sizeof(err_msg) - 1);
137 			_exit(255);
138 		}
139 		close(fd_out[1]);
140 
141 		argvp = argv;
142 		*argvp++ = gpg_cmd;
143 		*argvp++ = "--detach-sign";
144 		*argvp++ = "--armor";
145 		*argvp++ = "--output";
146 		*argvp++ = "-";
147 		if (user != NULL) {
148 			*argvp++ = "--local-user";
149 			*argvp++ = user;
150 		}
151 		if (keyring != NULL) {
152 			*argvp++ = "--no-default-keyring";
153 			*argvp++ = "--secret-keyring";
154 			*argvp++ = keyring;
155 		}
156 
157 		*argvp++ = "-";
158 		*argvp = NULL;
159 
160 		execvp(gpg_cmd, __UNCONST(argv));
161 		_exit(255);
162 	}
163 	close(fd_in[0]);
164 	if (write(fd_in[1], content, len) != (ssize_t)len)
165 		errx(EXIT_FAILURE, "Short read from GPG");
166 	close(fd_in[1]);
167 
168 	allocated = 1024;
169 	*sig = xmalloc(allocated);
170 	*sig_len = 0;
171 
172 	close(fd_out[1]);
173 
174 	while ((ret = read(fd_out[0], *sig + *sig_len,
175 	    allocated - *sig_len)) > 0) {
176 		*sig_len += ret;
177 		if (*sig_len == allocated) {
178 			allocated *= 2;
179 			*sig = xrealloc(*sig, allocated);
180 		}
181 	}
182 
183 	close(fd_out[0]);
184 
185 	waitpid(child, &status, 0);
186 	if (status)
187 		errx(EXIT_FAILURE, "GPG could not create signature");
188 
189 	return 0;
190 }
191