Home | History | Annotate | Line # | Download | only in lib
      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 (at) 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