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