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