252 lines
6.1 KiB
C
252 lines
6.1 KiB
C
/* $NetBSD: gpgsig.c,v 1.3 2009/08/02 17:56:45 joerg Exp $ */
|
|
#if HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
#ifndef __minix
|
|
#include <nbcompat.h>
|
|
#endif
|
|
#if HAVE_SYS_CDEFS_H
|
|
#include <sys/cdefs.h>
|
|
#endif
|
|
|
|
#ifndef __minix
|
|
__RCSID("$NetBSD: gpgsig.c,v 1.3 2009/08/02 17:56:45 joerg Exp $");
|
|
#endif
|
|
|
|
/*-
|
|
* Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <sys/wait.h>
|
|
#if !defined(NETBSD) && !defined(__minix)
|
|
#include <nbcompat/err.h>
|
|
#else
|
|
#include <err.h>
|
|
#endif
|
|
#if !defined(NETBSD) && !defined(__minix)
|
|
#include <nbcompat/stdlib.h>
|
|
#else
|
|
#include <stdlib.h>
|
|
#endif
|
|
|
|
#include "lib.h"
|
|
|
|
static void
|
|
verify_signature(const char *input, size_t input_len, const char *keyring,
|
|
const char *detached_signature)
|
|
{
|
|
const char *argv[8], **argvp;
|
|
pid_t child;
|
|
int fd[2], status;
|
|
|
|
if (pipe(fd) == -1)
|
|
err(EXIT_FAILURE, "cannot create input pipes");
|
|
|
|
child = vfork();
|
|
if (child == -1)
|
|
err(EXIT_FAILURE, "cannot fork GPG process");
|
|
if (child == 0) {
|
|
close(fd[1]);
|
|
close(STDIN_FILENO);
|
|
if (dup2(fd[0], STDIN_FILENO) == -1) {
|
|
static const char err_msg[] =
|
|
"cannot redirect stdin of GPG process\n";
|
|
write(STDERR_FILENO, err_msg, sizeof(err_msg) - 1);
|
|
_exit(255);
|
|
}
|
|
close(fd[0]);
|
|
argvp = argv;
|
|
*argvp++ = gpg_cmd;
|
|
*argvp++ = "--verify";
|
|
if (keyring != NULL) {
|
|
*argvp++ = "--no-default-keyring";
|
|
*argvp++ = "--keyring";
|
|
*argvp++ = keyring;
|
|
}
|
|
|
|
if (detached_signature != NULL)
|
|
*argvp++ = detached_signature;
|
|
*argvp++ = "-";
|
|
|
|
*argvp = NULL;
|
|
|
|
execvp(gpg_cmd, __UNCONST(argv));
|
|
_exit(255);
|
|
}
|
|
close(fd[0]);
|
|
if (write(fd[1], input, input_len) != (ssize_t)input_len)
|
|
errx(EXIT_FAILURE, "Short read from GPG");
|
|
close(fd[1]);
|
|
waitpid(child, &status, 0);
|
|
if (status)
|
|
errx(EXIT_FAILURE, "GPG could not verify the signature");
|
|
}
|
|
|
|
int
|
|
inline_gpg_verify(const char *content, size_t len, const char *keyring)
|
|
{
|
|
verify_signature(content, len, keyring, NULL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
detached_gpg_verify(const char *content, size_t len,
|
|
const char *signature, size_t signature_len, const char *keyring)
|
|
{
|
|
int fd;
|
|
const char *tmpdir;
|
|
char *tempsig;
|
|
ssize_t ret;
|
|
|
|
if (gpg_cmd == NULL) {
|
|
warnx("GPG variable not set, failing signature check");
|
|
return -1;
|
|
}
|
|
|
|
if ((tmpdir = getenv("TMPDIR")) == NULL)
|
|
tmpdir = "/tmp";
|
|
tempsig = xasprintf("%s/pkg_install.XXXXXX", tmpdir);
|
|
|
|
fd = mkstemp(tempsig);
|
|
if (fd == -1) {
|
|
warnx("Creating temporary file for GPG signature failed");
|
|
return -1;
|
|
}
|
|
|
|
while (signature_len) {
|
|
ret = write(fd, signature, signature_len);
|
|
if (ret == -1)
|
|
err(EXIT_FAILURE, "Write to GPG failed");
|
|
if (ret == 0)
|
|
errx(EXIT_FAILURE, "Short write to GPG");
|
|
signature_len -= ret;
|
|
signature += ret;
|
|
}
|
|
|
|
verify_signature(content, len, keyring, tempsig);
|
|
|
|
unlink(tempsig);
|
|
close(fd);
|
|
free(tempsig);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
detached_gpg_sign(const char *content, size_t len, char **sig, size_t *sig_len,
|
|
const char *keyring, const char *user)
|
|
{
|
|
const char *argv[12], **argvp;
|
|
pid_t child;
|
|
int fd_in[2], fd_out[2], status;
|
|
size_t allocated;
|
|
ssize_t ret;
|
|
|
|
if (gpg_cmd == NULL)
|
|
errx(EXIT_FAILURE, "GPG variable not set");
|
|
|
|
if (pipe(fd_in) == -1)
|
|
err(EXIT_FAILURE, "cannot create input pipes");
|
|
if (pipe(fd_out) == -1)
|
|
err(EXIT_FAILURE, "cannot create output pipes");
|
|
|
|
child = fork();
|
|
if (child == -1)
|
|
err(EXIT_FAILURE, "cannot fork GPG process");
|
|
if (child == 0) {
|
|
close(fd_in[1]);
|
|
close(STDIN_FILENO);
|
|
if (dup2(fd_in[0], STDIN_FILENO) == -1) {
|
|
static const char err_msg[] =
|
|
"cannot redirect stdin of GPG process\n";
|
|
write(STDERR_FILENO, err_msg, sizeof(err_msg) - 1);
|
|
_exit(255);
|
|
}
|
|
close(fd_in[0]);
|
|
|
|
close(fd_out[0]);
|
|
close(STDOUT_FILENO);
|
|
if (dup2(fd_out[1], STDOUT_FILENO) == -1) {
|
|
static const char err_msg[] =
|
|
"cannot redirect stdout of GPG process\n";
|
|
write(STDERR_FILENO, err_msg, sizeof(err_msg) - 1);
|
|
_exit(255);
|
|
}
|
|
close(fd_out[1]);
|
|
|
|
argvp = argv;
|
|
*argvp++ = gpg_cmd;
|
|
*argvp++ = "--detach-sign";
|
|
*argvp++ = "--armor";
|
|
*argvp++ = "--output";
|
|
*argvp++ = "-";
|
|
if (user != NULL) {
|
|
*argvp++ = "--local-user";
|
|
*argvp++ = user;
|
|
}
|
|
if (keyring != NULL) {
|
|
*argvp++ = "--no-default-keyring";
|
|
*argvp++ = "--secret-keyring";
|
|
*argvp++ = keyring;
|
|
}
|
|
|
|
*argvp++ = "-";
|
|
*argvp = NULL;
|
|
|
|
execvp(gpg_cmd, __UNCONST(argv));
|
|
_exit(255);
|
|
}
|
|
close(fd_in[0]);
|
|
if (write(fd_in[1], content, len) != (ssize_t)len)
|
|
errx(EXIT_FAILURE, "Short read from GPG");
|
|
close(fd_in[1]);
|
|
|
|
allocated = 1024;
|
|
*sig = xmalloc(allocated);
|
|
*sig_len = 0;
|
|
|
|
close(fd_out[1]);
|
|
|
|
while ((ret = read(fd_out[0], *sig + *sig_len,
|
|
allocated - *sig_len)) > 0) {
|
|
*sig_len += ret;
|
|
if (*sig_len == allocated) {
|
|
allocated *= 2;
|
|
*sig = xrealloc(*sig, allocated);
|
|
}
|
|
}
|
|
|
|
close(fd_out[0]);
|
|
|
|
waitpid(child, &status, 0);
|
|
if (status)
|
|
errx(EXIT_FAILURE, "GPG could not create signature");
|
|
|
|
return 0;
|
|
}
|