mirror of
https://git.gnunet.org/libmicrohttpd.git
synced 2026-10-07 04:02:18 +03:00
307 lines
6.9 KiB
C
307 lines
6.9 KiB
C
/* verify.c - Verify signatures
|
|
* Copyright (C) 2001, 2002, 2003, 2007 Timo Schulz
|
|
*
|
|
* This file is part of OpenCDK.
|
|
*
|
|
* OpenCDK is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* OpenCDK is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include "opencdk.h"
|
|
#include "main.h"
|
|
#include "filters.h"
|
|
#include "packet.h"
|
|
|
|
|
|
/* Table of all supported digest algorithms and their names. */
|
|
struct
|
|
{
|
|
const char *name;
|
|
int algo;
|
|
} digest_table[] =
|
|
{
|
|
{
|
|
"MD5", GCRY_MD_MD5},
|
|
{
|
|
"SHA1", GCRY_MD_SHA1},
|
|
{
|
|
"RIPEMD160", GCRY_MD_RMD160},
|
|
{
|
|
"SHA256", GCRY_MD_SHA256},
|
|
{
|
|
"SHA384", GCRY_MD_SHA384},
|
|
{
|
|
"SHA512", GCRY_MD_SHA512},
|
|
{
|
|
NULL, 0}
|
|
};
|
|
|
|
|
|
static int file_verify_clearsign (cdk_ctx_t, const char *, const char *);
|
|
|
|
|
|
/**
|
|
* cdk_stream_verify:
|
|
* @hd: session handle
|
|
* @inp: the input stream
|
|
* @data: for detached signatures, this is the data stream @inp is the sig
|
|
* @out: where the output shall be written.
|
|
*/
|
|
cdk_error_t
|
|
cdk_stream_verify (cdk_ctx_t hd, cdk_stream_t inp, cdk_stream_t data,
|
|
cdk_stream_t out)
|
|
{
|
|
/* FIXME: out is not currently used. */
|
|
if (cdk_armor_filter_use (inp))
|
|
cdk_stream_set_armor_flag (inp, 0);
|
|
return _cdk_proc_packets (hd, inp, data, NULL, NULL, NULL);
|
|
}
|
|
|
|
|
|
/**
|
|
* cdk_file_verify:
|
|
* @hd: the session handle
|
|
* @file: the input file
|
|
* @data_file: for detached signature this is the data file and @file is the sig.
|
|
* @output: the output file
|
|
*
|
|
* Verify a signature.
|
|
**/
|
|
cdk_error_t
|
|
cdk_file_verify (cdk_ctx_t hd, const char *file, const char *data_file,
|
|
const char *output)
|
|
{
|
|
struct stat stbuf;
|
|
cdk_stream_t inp, data;
|
|
char buf[4096];
|
|
int n;
|
|
cdk_error_t rc;
|
|
|
|
if (!hd || !file)
|
|
return CDK_Inv_Value;
|
|
if (output && !hd->opt.overwrite && !stat (output, &stbuf))
|
|
return CDK_Inv_Mode;
|
|
|
|
rc = cdk_stream_open (file, &inp);
|
|
if (rc)
|
|
return rc;
|
|
if (cdk_armor_filter_use (inp))
|
|
{
|
|
n = cdk_stream_peek (inp, (byte *) buf, DIM (buf) - 1);
|
|
if (!n || n == -1)
|
|
return CDK_EOF;
|
|
buf[n] = '\0';
|
|
if (strstr (buf, "BEGIN PGP SIGNED MESSAGE"))
|
|
{
|
|
cdk_stream_close (inp);
|
|
return file_verify_clearsign (hd, file, output);
|
|
}
|
|
cdk_stream_set_armor_flag (inp, 0);
|
|
}
|
|
|
|
if (data_file)
|
|
{
|
|
rc = cdk_stream_open (data_file, &data);
|
|
if (rc)
|
|
{
|
|
cdk_stream_close (inp);
|
|
return rc;
|
|
}
|
|
}
|
|
else
|
|
data = NULL;
|
|
|
|
rc = _cdk_proc_packets (hd, inp, data, NULL, NULL, NULL);
|
|
|
|
if (data != NULL)
|
|
cdk_stream_close (data);
|
|
cdk_stream_close (inp);
|
|
return rc;
|
|
}
|
|
|
|
|
|
void
|
|
_cdk_result_verify_free (cdk_verify_result_t res)
|
|
{
|
|
if (!res)
|
|
return;
|
|
cdk_free (res->policy_url);
|
|
cdk_free (res->sig_data);
|
|
cdk_free (res);
|
|
}
|
|
|
|
|
|
cdk_verify_result_t
|
|
_cdk_result_verify_new (void)
|
|
{
|
|
cdk_verify_result_t res;
|
|
|
|
res = cdk_calloc (1, sizeof *res);
|
|
if (!res)
|
|
return NULL;
|
|
return res;
|
|
}
|
|
|
|
|
|
static cdk_error_t
|
|
file_verify_clearsign (cdk_ctx_t hd, const char *file, const char *output)
|
|
{
|
|
cdk_stream_t inp = NULL, out = NULL, tmp = NULL;
|
|
gcry_md_hd_t md = NULL;
|
|
char buf[512], chk[512];
|
|
const char *s;
|
|
int i, is_signed = 0, nbytes;
|
|
int digest_algo = 0;
|
|
gcry_error_t err;
|
|
cdk_error_t rc;
|
|
|
|
if (output)
|
|
{
|
|
rc = cdk_stream_create (output, &out);
|
|
if (rc)
|
|
return rc;
|
|
}
|
|
|
|
rc = cdk_stream_open (file, &inp);
|
|
if (rc)
|
|
{
|
|
if (output)
|
|
cdk_stream_close (out);
|
|
return rc;
|
|
}
|
|
|
|
s = "-----BEGIN PGP SIGNED MESSAGE-----";
|
|
while (!cdk_stream_eof (inp))
|
|
{
|
|
nbytes = _cdk_stream_gets (inp, buf, DIM (buf) - 1);
|
|
if (!nbytes || nbytes == -1)
|
|
break;
|
|
if (!strncmp (buf, s, strlen (s)))
|
|
{
|
|
is_signed = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (cdk_stream_eof (inp) && !is_signed)
|
|
{
|
|
rc = CDK_Armor_Error;
|
|
goto leave;
|
|
}
|
|
|
|
while (!cdk_stream_eof (inp))
|
|
{
|
|
nbytes = _cdk_stream_gets (inp, buf, DIM (buf) - 1);
|
|
if (!nbytes || nbytes == -1)
|
|
break;
|
|
if (nbytes == 1) /* Empty line */
|
|
break;
|
|
else if (!strncmp (buf, "Hash: ", 6))
|
|
{
|
|
for (i = 0; digest_table[i].name; i++)
|
|
{
|
|
if (!strcmp (buf + 6, digest_table[i].name))
|
|
{
|
|
digest_algo = digest_table[i].algo;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (digest_algo && gcry_md_test_algo (digest_algo))
|
|
{
|
|
rc = CDK_Inv_Algo;
|
|
goto leave;
|
|
}
|
|
|
|
if (!digest_algo)
|
|
digest_algo = GCRY_MD_MD5;
|
|
|
|
err = gcry_md_open (&md, digest_algo, 0);
|
|
if (err)
|
|
{
|
|
rc = map_gcry_error (err);
|
|
goto leave;
|
|
}
|
|
|
|
s = "-----BEGIN PGP SIGNATURE-----";
|
|
while (!cdk_stream_eof (inp))
|
|
{
|
|
nbytes = _cdk_stream_gets (inp, buf, DIM (buf) - 1);
|
|
if (!nbytes || nbytes == -1)
|
|
break;
|
|
if (!strncmp (buf, s, strlen (s)))
|
|
break;
|
|
else
|
|
{
|
|
cdk_stream_peek (inp, (byte *) chk, DIM (chk) - 1);
|
|
i = strncmp (chk, s, strlen (s));
|
|
if (strlen (buf) == 0 && i == 0)
|
|
continue; /* skip last '\n' */
|
|
_cdk_trim_string (buf, i == 0 ? 0 : 1);
|
|
gcry_md_write (md, buf, strlen (buf));
|
|
}
|
|
if (!strncmp (buf, "- ", 2)) /* FIXME: handle it recursive. */
|
|
memmove (buf, buf + 2, nbytes - 2);
|
|
if (out)
|
|
{
|
|
if (strstr (buf, "\r\n"))
|
|
buf[strlen (buf) - 2] = '\0';
|
|
cdk_stream_write (out, buf, strlen (buf));
|
|
_cdk_stream_puts (out, _cdk_armor_get_lineend ());
|
|
}
|
|
}
|
|
|
|
/* We create a temporary stream object to store the
|
|
signature data in there. */
|
|
rc = cdk_stream_tmp_new (&tmp);
|
|
if (rc)
|
|
goto leave;
|
|
|
|
s = "-----BEGIN PGP SIGNATURE-----\n";
|
|
_cdk_stream_puts (tmp, s);
|
|
while (!cdk_stream_eof (inp))
|
|
{
|
|
nbytes = _cdk_stream_gets (inp, buf, DIM (buf) - 1);
|
|
if (!nbytes || nbytes == -1)
|
|
break;
|
|
if (nbytes < (DIM (buf) - 3))
|
|
{
|
|
buf[nbytes - 1] = '\n';
|
|
buf[nbytes] = '\0';
|
|
}
|
|
cdk_stream_write (tmp, buf, nbytes);
|
|
}
|
|
|
|
/* FIXME: This code is not very elegant. */
|
|
cdk_stream_tmp_set_mode (tmp, STREAMCTL_READ);
|
|
cdk_stream_seek (tmp, 0);
|
|
cdk_stream_set_armor_flag (tmp, 0);
|
|
cdk_stream_read (tmp, NULL, 0);
|
|
|
|
/* the digest handle will be closed there. */
|
|
rc = _cdk_proc_packets (hd, tmp, NULL, NULL, NULL, md);
|
|
|
|
leave:
|
|
gcry_md_close (md);
|
|
cdk_stream_close (out);
|
|
cdk_stream_close (tmp);
|
|
cdk_stream_close (inp);
|
|
return rc;
|
|
}
|