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