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 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 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