mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
Merge branch 'STABLE-BRANCH-2-4'
* common/b64dec.c (b64decode): Move to ... * common/miscellaneous.c: here. * common/t-b64.c: Re-inroduce and keep only the b64decode test code.
This commit is contained in:
commit
387ee7dcbd
7
NEWS
7
NEWS
@ -1,6 +1,9 @@
|
||||
Noteworthy changes in version 2.5.0 (unreleased)
|
||||
------------------------------------------------
|
||||
|
||||
Changes also found in 2.4.3:
|
||||
|
||||
* Fix garbled time output in non-English Windows. [T6741]
|
||||
|
||||
Changes also found in 2.4.3:
|
||||
|
||||
@ -33,6 +36,9 @@ Noteworthy changes in version 2.5.0 (unreleased)
|
||||
|
||||
* dirmngr: New option --ignore-crl-extensions. [T6545]
|
||||
|
||||
* dirmngr: Support config value "none" to disable the default
|
||||
keyserver. [T6708]
|
||||
|
||||
* wkd: Use export-clean for gpg-wks-client's --mirror and --create
|
||||
commands. [rG2c7f7a5a27]
|
||||
|
||||
@ -70,6 +76,7 @@ Noteworthy changes in version 2.5.0 (unreleased)
|
||||
Release dates of 2.4 versions
|
||||
-----------------------------
|
||||
|
||||
Version 2.4.4 (unreleased) https://dev.gnupg.org/T6578
|
||||
Version 2.4.3 (2023-07-04) https://dev.gnupg.org/T6509
|
||||
Version 2.4.2 (2023-05-30) https://dev.gnupg.org/T6506
|
||||
Version 2.4.1 (2023-04-28) https://dev.gnupg.org/T6454
|
||||
|
@ -175,6 +175,7 @@ unlock_pinentry (ctrl_t ctrl, gpg_error_t rc)
|
||||
case GPG_ERR_NO_PASSPHRASE:
|
||||
case GPG_ERR_BAD_PASSPHRASE:
|
||||
case GPG_ERR_BAD_PIN:
|
||||
case GPG_ERR_BAD_RESET_CODE:
|
||||
break;
|
||||
|
||||
case GPG_ERR_CORRUPTED_PROTECTION:
|
||||
@ -1610,12 +1611,13 @@ agent_askpin (ctrl_t ctrl,
|
||||
&& (pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
|
||||
return unlock_pinentry (ctrl, rc);
|
||||
|
||||
if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE)
|
||||
if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
|
||||
|| gpg_err_code (rc) == GPG_ERR_BAD_PIN
|
||||
|| gpg_err_code (rc) == GPG_ERR_BAD_RESET_CODE)
|
||||
{
|
||||
if (pininfo->cb_errtext)
|
||||
errtext = pininfo->cb_errtext;
|
||||
else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
|
||||
|| gpg_err_code (rc) == GPG_ERR_BAD_PIN)
|
||||
else
|
||||
errtext = (is_pin? L_("Bad PIN") : L_("Bad Passphrase"));
|
||||
}
|
||||
else if (rc)
|
||||
@ -1883,12 +1885,13 @@ agent_get_passphrase (ctrl_t ctrl,
|
||||
if (rc && (pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
|
||||
return unlock_pinentry (ctrl, rc);
|
||||
|
||||
if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE)
|
||||
if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
|
||||
|| gpg_err_code (rc) == GPG_ERR_BAD_PIN
|
||||
|| gpg_err_code (rc) == GPG_ERR_BAD_RESET_CODE)
|
||||
{
|
||||
if (pininfo->cb_errtext)
|
||||
errtext = pininfo->cb_errtext;
|
||||
else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
|
||||
|| gpg_err_code (rc) == GPG_ERR_BAD_PIN)
|
||||
else
|
||||
errtext = (is_pin? L_("Bad PIN") : L_("Bad Passphrase"));
|
||||
}
|
||||
else if (rc)
|
||||
|
@ -282,6 +282,7 @@ AUTHENTICODE_FILES= \
|
||||
gpgtar.exe \
|
||||
gpgv.exe \
|
||||
gpg-card.exe \
|
||||
keyboxd.exe \
|
||||
libassuan-0.dll \
|
||||
libgcrypt-20.dll \
|
||||
libgpg-error-0.dll \
|
||||
|
@ -58,7 +58,7 @@ common_sources = \
|
||||
openpgpdefs.h \
|
||||
gc-opt-flags.h \
|
||||
sexp-parse.h \
|
||||
tlv.c tlv.h tlv-builder.c \
|
||||
tlv.c tlv.h tlv-builder.c tlv-parser.c \
|
||||
init.c init.h \
|
||||
sexputil.c \
|
||||
sysutils.c sysutils.h \
|
||||
@ -160,8 +160,9 @@ endif
|
||||
module_tests = t-stringhelp t-timestuff \
|
||||
t-convert t-percent t-gettime t-sysutils t-sexputil \
|
||||
t-session-env t-openpgp-oid t-ssh-utils \
|
||||
t-mapstrings t-zb32 t-mbox-util t-iobuf t-strlist \
|
||||
t-mapstrings t-zb32 t-mbox-util t-iobuf t-strlist t-b64 \
|
||||
t-name-value t-ccparray t-recsel t-w32-cmdline t-exechelp
|
||||
|
||||
if HAVE_W32_SYSTEM
|
||||
module_tests += t-w32-reg
|
||||
else
|
||||
@ -209,6 +210,7 @@ t_zb32_LDADD = $(t_common_ldadd)
|
||||
t_mbox_util_LDADD = $(t_common_ldadd)
|
||||
t_iobuf_LDADD = $(t_common_ldadd)
|
||||
t_strlist_LDADD = $(t_common_ldadd)
|
||||
t_b64_LDADD = $(t_common_ldadd)
|
||||
t_name_value_LDADD = $(t_common_ldadd)
|
||||
t_ccparray_LDADD = $(t_common_ldadd)
|
||||
t_recsel_LDADD = $(t_common_ldadd)
|
||||
|
254
common/b64dec.c
254
common/b64dec.c
@ -1,254 +0,0 @@
|
||||
/* b64dec.c - Simple Base64 decoder.
|
||||
* Copyright (C) 2008, 2011 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2008, 2011, 2016 g10 Code GmbH
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This file 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.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "i18n.h"
|
||||
#include "util.h"
|
||||
|
||||
|
||||
/* The reverse base-64 list used for base-64 decoding. */
|
||||
static unsigned char const asctobin[128] =
|
||||
{
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
|
||||
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
|
||||
0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
|
||||
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
|
||||
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
|
||||
0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
|
||||
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
|
||||
0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
|
||||
0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
|
||||
enum decoder_states
|
||||
{
|
||||
s_init, s_idle, s_lfseen, s_beginseen, s_waitheader, s_waitblank, s_begin,
|
||||
s_b64_0, s_b64_1, s_b64_2, s_b64_3,
|
||||
s_waitendtitle, s_waitend
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Initialize the context for the base64 decoder. If TITLE is NULL a
|
||||
plain base64 decoding is done. If it is the empty string the
|
||||
decoder will skip everything until a "-----BEGIN " line has been
|
||||
seen, decoding ends at a "----END " line. */
|
||||
gpg_error_t
|
||||
b64dec_start (struct b64state *state, const char *title)
|
||||
{
|
||||
memset (state, 0, sizeof *state);
|
||||
if (title)
|
||||
{
|
||||
state->title = xtrystrdup (title);
|
||||
if (!state->title)
|
||||
state->lasterr = gpg_error_from_syserror ();
|
||||
else
|
||||
state->idx = s_init;
|
||||
}
|
||||
else
|
||||
state->idx = s_b64_0;
|
||||
return state->lasterr;
|
||||
}
|
||||
|
||||
|
||||
/* Do in-place decoding of base-64 data of LENGTH in BUFFER. Stores the
|
||||
new length of the buffer at R_NBYTES. */
|
||||
gpg_error_t
|
||||
b64dec_proc (struct b64state *state, void *buffer, size_t length,
|
||||
size_t *r_nbytes)
|
||||
{
|
||||
enum decoder_states ds = state->idx;
|
||||
unsigned char val = state->radbuf[0];
|
||||
int pos = state->quad_count;
|
||||
char *d, *s;
|
||||
|
||||
if (state->lasterr)
|
||||
return state->lasterr;
|
||||
|
||||
if (state->stop_seen)
|
||||
{
|
||||
*r_nbytes = 0;
|
||||
state->lasterr = gpg_error (GPG_ERR_EOF);
|
||||
xfree (state->title);
|
||||
state->title = NULL;
|
||||
return state->lasterr;
|
||||
}
|
||||
|
||||
for (s=d=buffer; length && !state->stop_seen; length--, s++)
|
||||
{
|
||||
again:
|
||||
switch (ds)
|
||||
{
|
||||
case s_idle:
|
||||
if (*s == '\n')
|
||||
{
|
||||
ds = s_lfseen;
|
||||
pos = 0;
|
||||
}
|
||||
break;
|
||||
case s_init:
|
||||
ds = s_lfseen;
|
||||
/* fall through */
|
||||
case s_lfseen:
|
||||
if (*s != "-----BEGIN "[pos])
|
||||
{
|
||||
ds = s_idle;
|
||||
goto again;
|
||||
}
|
||||
else if (pos == 10)
|
||||
{
|
||||
pos = 0;
|
||||
ds = s_beginseen;
|
||||
}
|
||||
else
|
||||
pos++;
|
||||
break;
|
||||
case s_beginseen:
|
||||
if (*s != "PGP "[pos])
|
||||
ds = s_begin; /* Not a PGP armor. */
|
||||
else if (pos == 3)
|
||||
ds = s_waitheader;
|
||||
else
|
||||
pos++;
|
||||
break;
|
||||
case s_waitheader:
|
||||
if (*s == '\n')
|
||||
ds = s_waitblank;
|
||||
break;
|
||||
case s_waitblank:
|
||||
if (*s == '\n')
|
||||
ds = s_b64_0; /* blank line found. */
|
||||
else if (*s == ' ' || *s == '\r' || *s == '\t')
|
||||
; /* Ignore spaces. */
|
||||
else
|
||||
{
|
||||
/* Armor header line. Note that we don't care that our
|
||||
* FSM accepts a header prefixed with spaces. */
|
||||
ds = s_waitheader; /* Wait for next header. */
|
||||
}
|
||||
break;
|
||||
case s_begin:
|
||||
if (*s == '\n')
|
||||
ds = s_b64_0;
|
||||
break;
|
||||
case s_b64_0:
|
||||
case s_b64_1:
|
||||
case s_b64_2:
|
||||
case s_b64_3:
|
||||
{
|
||||
int c;
|
||||
|
||||
if (*s == '-' && state->title)
|
||||
{
|
||||
/* Not a valid Base64 character: assume end
|
||||
header. */
|
||||
ds = s_waitend;
|
||||
}
|
||||
else if (*s == '=')
|
||||
{
|
||||
/* Pad character: stop */
|
||||
if (ds == s_b64_1)
|
||||
*d++ = val;
|
||||
ds = state->title? s_waitendtitle : s_waitend;
|
||||
}
|
||||
else if (*s == '\n' || *s == ' ' || *s == '\r' || *s == '\t')
|
||||
; /* Skip white spaces. */
|
||||
else if ( (*s & 0x80)
|
||||
|| (c = asctobin[*(unsigned char *)s]) == 255)
|
||||
{
|
||||
/* Skip invalid encodings. */
|
||||
state->invalid_encoding = 1;
|
||||
}
|
||||
else if (ds == s_b64_0)
|
||||
{
|
||||
val = c << 2;
|
||||
ds = s_b64_1;
|
||||
}
|
||||
else if (ds == s_b64_1)
|
||||
{
|
||||
val |= (c>>4)&3;
|
||||
*d++ = val;
|
||||
val = (c<<4)&0xf0;
|
||||
ds = s_b64_2;
|
||||
}
|
||||
else if (ds == s_b64_2)
|
||||
{
|
||||
val |= (c>>2)&15;
|
||||
*d++ = val;
|
||||
val = (c<<6)&0xc0;
|
||||
ds = s_b64_3;
|
||||
}
|
||||
else
|
||||
{
|
||||
val |= c&0x3f;
|
||||
*d++ = val;
|
||||
ds = s_b64_0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case s_waitendtitle:
|
||||
if (*s == '-')
|
||||
ds = s_waitend;
|
||||
break;
|
||||
case s_waitend:
|
||||
if ( *s == '\n')
|
||||
state->stop_seen = 1;
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
state->idx = ds;
|
||||
state->radbuf[0] = val;
|
||||
state->quad_count = pos;
|
||||
*r_nbytes = (d -(char*) buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* This function needs to be called before releasing the decoder
|
||||
state. It may return an error code in case an encoding error has
|
||||
been found during decoding. */
|
||||
gpg_error_t
|
||||
b64dec_finish (struct b64state *state)
|
||||
{
|
||||
xfree (state->title);
|
||||
state->title = NULL;
|
||||
|
||||
if (state->lasterr)
|
||||
return state->lasterr;
|
||||
|
||||
return state->invalid_encoding? gpg_error(GPG_ERR_BAD_DATA): 0;
|
||||
}
|
422
common/b64enc.c
422
common/b64enc.c
@ -1,422 +0,0 @@
|
||||
/* b64enc.c - Simple Base64 encoder.
|
||||
* Copyright (C) 2001, 2003, 2004, 2008, 2010,
|
||||
* 2011 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2001, 2003, 2004, 2008, 2010,
|
||||
* 2011 g10 Code GmbH
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This file 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.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "i18n.h"
|
||||
#include "util.h"
|
||||
|
||||
#define B64ENC_DID_HEADER 1
|
||||
#define B64ENC_DID_TRAILER 2
|
||||
#define B64ENC_NO_LINEFEEDS 16
|
||||
#define B64ENC_USE_PGPCRC 32
|
||||
|
||||
/* The base-64 character list */
|
||||
static unsigned char bintoasc[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
|
||||
/* Stuff required to create the OpenPGP CRC. This crc_table has been
|
||||
created using this code:
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define CRCPOLY 0x864CFB
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
int i, j;
|
||||
uint32_t t;
|
||||
uint32_t crc_table[256];
|
||||
|
||||
crc_table[0] = 0;
|
||||
for (i=j=0; j < 128; j++ )
|
||||
{
|
||||
t = crc_table[j];
|
||||
if ( (t & 0x00800000) )
|
||||
{
|
||||
t <<= 1;
|
||||
crc_table[i++] = t ^ CRCPOLY;
|
||||
crc_table[i++] = t;
|
||||
}
|
||||
else
|
||||
{
|
||||
t <<= 1;
|
||||
crc_table[i++] = t;
|
||||
crc_table[i++] = t ^ CRCPOLY;
|
||||
}
|
||||
}
|
||||
|
||||
puts ("static const u32 crc_table[256] = {");
|
||||
for (i=j=0; i < 256; i++)
|
||||
{
|
||||
printf ("%s 0x%08lx", j? "":" ", (unsigned long)crc_table[i]);
|
||||
if (i != 255)
|
||||
{
|
||||
putchar (',');
|
||||
if ( ++j > 5)
|
||||
{
|
||||
j = 0;
|
||||
putchar ('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
puts ("\n};");
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
#define CRCINIT 0xB704CE
|
||||
static const u32 crc_table[256] = {
|
||||
0x00000000, 0x00864cfb, 0x018ad50d, 0x010c99f6, 0x0393e6e1, 0x0315aa1a,
|
||||
0x021933ec, 0x029f7f17, 0x07a18139, 0x0727cdc2, 0x062b5434, 0x06ad18cf,
|
||||
0x043267d8, 0x04b42b23, 0x05b8b2d5, 0x053efe2e, 0x0fc54e89, 0x0f430272,
|
||||
0x0e4f9b84, 0x0ec9d77f, 0x0c56a868, 0x0cd0e493, 0x0ddc7d65, 0x0d5a319e,
|
||||
0x0864cfb0, 0x08e2834b, 0x09ee1abd, 0x09685646, 0x0bf72951, 0x0b7165aa,
|
||||
0x0a7dfc5c, 0x0afbb0a7, 0x1f0cd1e9, 0x1f8a9d12, 0x1e8604e4, 0x1e00481f,
|
||||
0x1c9f3708, 0x1c197bf3, 0x1d15e205, 0x1d93aefe, 0x18ad50d0, 0x182b1c2b,
|
||||
0x192785dd, 0x19a1c926, 0x1b3eb631, 0x1bb8faca, 0x1ab4633c, 0x1a322fc7,
|
||||
0x10c99f60, 0x104fd39b, 0x11434a6d, 0x11c50696, 0x135a7981, 0x13dc357a,
|
||||
0x12d0ac8c, 0x1256e077, 0x17681e59, 0x17ee52a2, 0x16e2cb54, 0x166487af,
|
||||
0x14fbf8b8, 0x147db443, 0x15712db5, 0x15f7614e, 0x3e19a3d2, 0x3e9fef29,
|
||||
0x3f9376df, 0x3f153a24, 0x3d8a4533, 0x3d0c09c8, 0x3c00903e, 0x3c86dcc5,
|
||||
0x39b822eb, 0x393e6e10, 0x3832f7e6, 0x38b4bb1d, 0x3a2bc40a, 0x3aad88f1,
|
||||
0x3ba11107, 0x3b275dfc, 0x31dced5b, 0x315aa1a0, 0x30563856, 0x30d074ad,
|
||||
0x324f0bba, 0x32c94741, 0x33c5deb7, 0x3343924c, 0x367d6c62, 0x36fb2099,
|
||||
0x37f7b96f, 0x3771f594, 0x35ee8a83, 0x3568c678, 0x34645f8e, 0x34e21375,
|
||||
0x2115723b, 0x21933ec0, 0x209fa736, 0x2019ebcd, 0x228694da, 0x2200d821,
|
||||
0x230c41d7, 0x238a0d2c, 0x26b4f302, 0x2632bff9, 0x273e260f, 0x27b86af4,
|
||||
0x252715e3, 0x25a15918, 0x24adc0ee, 0x242b8c15, 0x2ed03cb2, 0x2e567049,
|
||||
0x2f5ae9bf, 0x2fdca544, 0x2d43da53, 0x2dc596a8, 0x2cc90f5e, 0x2c4f43a5,
|
||||
0x2971bd8b, 0x29f7f170, 0x28fb6886, 0x287d247d, 0x2ae25b6a, 0x2a641791,
|
||||
0x2b688e67, 0x2beec29c, 0x7c3347a4, 0x7cb50b5f, 0x7db992a9, 0x7d3fde52,
|
||||
0x7fa0a145, 0x7f26edbe, 0x7e2a7448, 0x7eac38b3, 0x7b92c69d, 0x7b148a66,
|
||||
0x7a181390, 0x7a9e5f6b, 0x7801207c, 0x78876c87, 0x798bf571, 0x790db98a,
|
||||
0x73f6092d, 0x737045d6, 0x727cdc20, 0x72fa90db, 0x7065efcc, 0x70e3a337,
|
||||
0x71ef3ac1, 0x7169763a, 0x74578814, 0x74d1c4ef, 0x75dd5d19, 0x755b11e2,
|
||||
0x77c46ef5, 0x7742220e, 0x764ebbf8, 0x76c8f703, 0x633f964d, 0x63b9dab6,
|
||||
0x62b54340, 0x62330fbb, 0x60ac70ac, 0x602a3c57, 0x6126a5a1, 0x61a0e95a,
|
||||
0x649e1774, 0x64185b8f, 0x6514c279, 0x65928e82, 0x670df195, 0x678bbd6e,
|
||||
0x66872498, 0x66016863, 0x6cfad8c4, 0x6c7c943f, 0x6d700dc9, 0x6df64132,
|
||||
0x6f693e25, 0x6fef72de, 0x6ee3eb28, 0x6e65a7d3, 0x6b5b59fd, 0x6bdd1506,
|
||||
0x6ad18cf0, 0x6a57c00b, 0x68c8bf1c, 0x684ef3e7, 0x69426a11, 0x69c426ea,
|
||||
0x422ae476, 0x42aca88d, 0x43a0317b, 0x43267d80, 0x41b90297, 0x413f4e6c,
|
||||
0x4033d79a, 0x40b59b61, 0x458b654f, 0x450d29b4, 0x4401b042, 0x4487fcb9,
|
||||
0x461883ae, 0x469ecf55, 0x479256a3, 0x47141a58, 0x4defaaff, 0x4d69e604,
|
||||
0x4c657ff2, 0x4ce33309, 0x4e7c4c1e, 0x4efa00e5, 0x4ff69913, 0x4f70d5e8,
|
||||
0x4a4e2bc6, 0x4ac8673d, 0x4bc4fecb, 0x4b42b230, 0x49ddcd27, 0x495b81dc,
|
||||
0x4857182a, 0x48d154d1, 0x5d26359f, 0x5da07964, 0x5cace092, 0x5c2aac69,
|
||||
0x5eb5d37e, 0x5e339f85, 0x5f3f0673, 0x5fb94a88, 0x5a87b4a6, 0x5a01f85d,
|
||||
0x5b0d61ab, 0x5b8b2d50, 0x59145247, 0x59921ebc, 0x589e874a, 0x5818cbb1,
|
||||
0x52e37b16, 0x526537ed, 0x5369ae1b, 0x53efe2e0, 0x51709df7, 0x51f6d10c,
|
||||
0x50fa48fa, 0x507c0401, 0x5542fa2f, 0x55c4b6d4, 0x54c82f22, 0x544e63d9,
|
||||
0x56d11cce, 0x56575035, 0x575bc9c3, 0x57dd8538
|
||||
};
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
enc_start (struct b64state *state, FILE *fp, estream_t stream,
|
||||
const char *title)
|
||||
{
|
||||
memset (state, 0, sizeof *state);
|
||||
state->fp = fp;
|
||||
state->stream = stream;
|
||||
state->lasterr = 0;
|
||||
if (title && !*title)
|
||||
state->flags |= B64ENC_NO_LINEFEEDS;
|
||||
else if (title)
|
||||
{
|
||||
if (!strncmp (title, "PGP ", 4))
|
||||
{
|
||||
state->flags |= B64ENC_USE_PGPCRC;
|
||||
state->crc = CRCINIT;
|
||||
}
|
||||
state->title = xtrystrdup (title);
|
||||
if (!state->title)
|
||||
state->lasterr = gpg_error_from_syserror ();
|
||||
}
|
||||
return state->lasterr;
|
||||
}
|
||||
|
||||
|
||||
/* Prepare for base-64 writing to the stream FP. If TITLE is not NULL
|
||||
and not an empty string, this string will be used as the title for
|
||||
the armor lines, with TITLE being an empty string, we don't write
|
||||
the header lines and furthermore even don't write any linefeeds.
|
||||
If TITLE starts with "PGP " the OpenPGP CRC checksum will be
|
||||
written as well. With TITLE being NULL, we merely don't write
|
||||
header but make sure that lines are not too long. Note, that we
|
||||
don't write any output unless at least one byte get written using
|
||||
b64enc_write. */
|
||||
gpg_error_t
|
||||
b64enc_start (struct b64state *state, FILE *fp, const char *title)
|
||||
{
|
||||
return enc_start (state, fp, NULL, title);
|
||||
}
|
||||
|
||||
/* Same as b64enc_start but takes an estream. */
|
||||
gpg_error_t
|
||||
b64enc_start_es (struct b64state *state, estream_t fp, const char *title)
|
||||
{
|
||||
return enc_start (state, NULL, fp, title);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
my_fputs (const char *string, struct b64state *state)
|
||||
{
|
||||
if (state->stream)
|
||||
return es_fputs (string, state->stream);
|
||||
else
|
||||
return fputs (string, state->fp);
|
||||
}
|
||||
|
||||
|
||||
/* Write NBYTES from BUFFER to the Base 64 stream identified by
|
||||
STATE. With BUFFER and NBYTES being 0, merely do a fflush on the
|
||||
stream. */
|
||||
gpg_error_t
|
||||
b64enc_write (struct b64state *state, const void *buffer, size_t nbytes)
|
||||
{
|
||||
unsigned char radbuf[4];
|
||||
int idx, quad_count;
|
||||
const unsigned char *p;
|
||||
|
||||
if (state->lasterr)
|
||||
return state->lasterr;
|
||||
|
||||
if (!nbytes)
|
||||
{
|
||||
if (buffer)
|
||||
if (state->stream? es_fflush (state->stream) : fflush (state->fp))
|
||||
goto write_error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(state->flags & B64ENC_DID_HEADER))
|
||||
{
|
||||
if (state->title)
|
||||
{
|
||||
if ( my_fputs ("-----BEGIN ", state) == EOF
|
||||
|| my_fputs (state->title, state) == EOF
|
||||
|| my_fputs ("-----\n", state) == EOF)
|
||||
goto write_error;
|
||||
if ( (state->flags & B64ENC_USE_PGPCRC)
|
||||
&& my_fputs ("\n", state) == EOF)
|
||||
goto write_error;
|
||||
}
|
||||
|
||||
state->flags |= B64ENC_DID_HEADER;
|
||||
}
|
||||
|
||||
idx = state->idx;
|
||||
quad_count = state->quad_count;
|
||||
assert (idx < 4);
|
||||
memcpy (radbuf, state->radbuf, idx);
|
||||
|
||||
if ( (state->flags & B64ENC_USE_PGPCRC) )
|
||||
{
|
||||
size_t n;
|
||||
u32 crc = state->crc;
|
||||
|
||||
for (p=buffer, n=nbytes; n; p++, n-- )
|
||||
crc = ((u32)crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ *p];
|
||||
state->crc = (crc & 0x00ffffff);
|
||||
}
|
||||
|
||||
for (p=buffer; nbytes; p++, nbytes--)
|
||||
{
|
||||
radbuf[idx++] = *p;
|
||||
if (idx > 2)
|
||||
{
|
||||
char tmp[4];
|
||||
|
||||
tmp[0] = bintoasc[(*radbuf >> 2) & 077];
|
||||
tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
|
||||
tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
|
||||
tmp[3] = bintoasc[radbuf[2]&077];
|
||||
if (state->stream)
|
||||
{
|
||||
for (idx=0; idx < 4; idx++)
|
||||
es_putc (tmp[idx], state->stream);
|
||||
idx = 0;
|
||||
if (es_ferror (state->stream))
|
||||
goto write_error;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (idx=0; idx < 4; idx++)
|
||||
putc (tmp[idx], state->fp);
|
||||
idx = 0;
|
||||
if (ferror (state->fp))
|
||||
goto write_error;
|
||||
}
|
||||
if (++quad_count >= (64/4))
|
||||
{
|
||||
quad_count = 0;
|
||||
if (!(state->flags & B64ENC_NO_LINEFEEDS)
|
||||
&& my_fputs ("\n", state) == EOF)
|
||||
goto write_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
memcpy (state->radbuf, radbuf, idx);
|
||||
state->idx = idx;
|
||||
state->quad_count = quad_count;
|
||||
return 0;
|
||||
|
||||
write_error:
|
||||
state->lasterr = gpg_error_from_syserror ();
|
||||
if (state->title)
|
||||
{
|
||||
xfree (state->title);
|
||||
state->title = NULL;
|
||||
}
|
||||
return state->lasterr;
|
||||
}
|
||||
|
||||
|
||||
gpg_error_t
|
||||
b64enc_finish (struct b64state *state)
|
||||
{
|
||||
gpg_error_t err = 0;
|
||||
unsigned char radbuf[4];
|
||||
int idx, quad_count;
|
||||
char tmp[4];
|
||||
|
||||
if (state->lasterr)
|
||||
return state->lasterr;
|
||||
|
||||
if (!(state->flags & B64ENC_DID_HEADER))
|
||||
goto cleanup;
|
||||
|
||||
/* Flush the base64 encoding */
|
||||
idx = state->idx;
|
||||
quad_count = state->quad_count;
|
||||
assert (idx < 4);
|
||||
memcpy (radbuf, state->radbuf, idx);
|
||||
|
||||
if (idx)
|
||||
{
|
||||
tmp[0] = bintoasc[(*radbuf>>2)&077];
|
||||
if (idx == 1)
|
||||
{
|
||||
tmp[1] = bintoasc[((*radbuf << 4) & 060) & 077];
|
||||
tmp[2] = '=';
|
||||
tmp[3] = '=';
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
|
||||
tmp[2] = bintoasc[((radbuf[1] << 2) & 074) & 077];
|
||||
tmp[3] = '=';
|
||||
}
|
||||
if (state->stream)
|
||||
{
|
||||
for (idx=0; idx < 4; idx++)
|
||||
es_putc (tmp[idx], state->stream);
|
||||
if (es_ferror (state->stream))
|
||||
goto write_error;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (idx=0; idx < 4; idx++)
|
||||
putc (tmp[idx], state->fp);
|
||||
if (ferror (state->fp))
|
||||
goto write_error;
|
||||
}
|
||||
|
||||
if (++quad_count >= (64/4))
|
||||
{
|
||||
quad_count = 0;
|
||||
if (!(state->flags & B64ENC_NO_LINEFEEDS)
|
||||
&& my_fputs ("\n", state) == EOF)
|
||||
goto write_error;
|
||||
}
|
||||
}
|
||||
|
||||
/* Finish the last line and write the trailer. */
|
||||
if (quad_count
|
||||
&& !(state->flags & B64ENC_NO_LINEFEEDS)
|
||||
&& my_fputs ("\n", state) == EOF)
|
||||
goto write_error;
|
||||
|
||||
if ( (state->flags & B64ENC_USE_PGPCRC) )
|
||||
{
|
||||
/* Write the CRC. */
|
||||
my_fputs ("=", state);
|
||||
radbuf[0] = state->crc >>16;
|
||||
radbuf[1] = state->crc >> 8;
|
||||
radbuf[2] = state->crc;
|
||||
tmp[0] = bintoasc[(*radbuf>>2)&077];
|
||||
tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
|
||||
tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
|
||||
tmp[3] = bintoasc[radbuf[2]&077];
|
||||
if (state->stream)
|
||||
{
|
||||
for (idx=0; idx < 4; idx++)
|
||||
es_putc (tmp[idx], state->stream);
|
||||
if (es_ferror (state->stream))
|
||||
goto write_error;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (idx=0; idx < 4; idx++)
|
||||
putc (tmp[idx], state->fp);
|
||||
if (ferror (state->fp))
|
||||
goto write_error;
|
||||
}
|
||||
if (!(state->flags & B64ENC_NO_LINEFEEDS)
|
||||
&& my_fputs ("\n", state) == EOF)
|
||||
goto write_error;
|
||||
}
|
||||
|
||||
if (state->title)
|
||||
{
|
||||
if ( my_fputs ("-----END ", state) == EOF
|
||||
|| my_fputs (state->title, state) == EOF
|
||||
|| my_fputs ("-----\n", state) == EOF)
|
||||
goto write_error;
|
||||
}
|
||||
|
||||
goto cleanup;
|
||||
|
||||
write_error:
|
||||
err = gpg_error_from_syserror ();
|
||||
|
||||
cleanup:
|
||||
if (state->title)
|
||||
{
|
||||
xfree (state->title);
|
||||
state->title = NULL;
|
||||
}
|
||||
state->fp = NULL;
|
||||
state->stream = NULL;
|
||||
state->lasterr = err;
|
||||
return err;
|
||||
}
|
@ -1011,6 +1011,48 @@ dotlock_destroy (dotlock_t h)
|
||||
}
|
||||
|
||||
|
||||
/* Return true if H has been taken. */
|
||||
int
|
||||
dotlock_is_locked (dotlock_t h)
|
||||
{
|
||||
return h && !!h->locked;
|
||||
}
|
||||
|
||||
|
||||
/* Return the next interval to wait. WTIME and TIMEOUT are pointers
|
||||
* to the current state and are updated by this function. The
|
||||
* returned value might be different from the value of WTIME. */
|
||||
static int
|
||||
next_wait_interval (int *wtime, long *timeout)
|
||||
{
|
||||
int result;
|
||||
|
||||
/* Wait until lock has been released. We use retry intervals of 4,
|
||||
* 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 512, 1024, 2048ms, and
|
||||
* so on. If wait-forever was requested we add a small random value
|
||||
* to have different timeouts per process. */
|
||||
if (!*wtime)
|
||||
*wtime = 4;
|
||||
else if (*wtime < 2048)
|
||||
*wtime *= 2;
|
||||
else
|
||||
*wtime = 512;
|
||||
|
||||
result = *wtime;
|
||||
if (*wtime > 8 && *timeout < 0)
|
||||
result += ((unsigned int)getpid() % 37);
|
||||
|
||||
if (*timeout > 0)
|
||||
{
|
||||
if (result > *timeout)
|
||||
result = *timeout;
|
||||
*timeout -= result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef HAVE_POSIX_SYSTEM
|
||||
/* Unix specific code of make_dotlock. Returns 0 on success and -1 on
|
||||
@ -1170,27 +1212,14 @@ dotlock_take_unix (dotlock_t h, long timeout)
|
||||
if (timeout)
|
||||
{
|
||||
struct timeval tv;
|
||||
int wtimereal;
|
||||
|
||||
/* Wait until lock has been released. We use increasing retry
|
||||
intervals of 50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s
|
||||
but reset it if the lock owner meanwhile changed. */
|
||||
if (!wtime || ownerchanged)
|
||||
wtime = 50;
|
||||
else if (wtime < 800)
|
||||
wtime *= 2;
|
||||
else if (wtime == 800)
|
||||
wtime = 2000;
|
||||
else if (wtime < 8000)
|
||||
wtime *= 2;
|
||||
if (ownerchanged)
|
||||
wtime = 0; /* Reset because owner chnaged. */
|
||||
|
||||
if (timeout > 0)
|
||||
{
|
||||
if (wtime > timeout)
|
||||
wtime = timeout;
|
||||
timeout -= wtime;
|
||||
}
|
||||
wtimereal = next_wait_interval (&wtime, &timeout);
|
||||
|
||||
sumtime += wtime;
|
||||
sumtime += wtimereal;
|
||||
if (sumtime >= 1500)
|
||||
{
|
||||
sumtime = 0;
|
||||
@ -1198,9 +1227,8 @@ dotlock_take_unix (dotlock_t h, long timeout)
|
||||
pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):"");
|
||||
}
|
||||
|
||||
|
||||
tv.tv_sec = wtime / 1000;
|
||||
tv.tv_usec = (wtime % 1000) * 1000;
|
||||
tv.tv_sec = wtimereal / 1000;
|
||||
tv.tv_usec = (wtimereal % 1000) * 1000;
|
||||
select (0, NULL, NULL, NULL, &tv);
|
||||
goto again;
|
||||
}
|
||||
@ -1242,28 +1270,14 @@ dotlock_take_w32 (dotlock_t h, long timeout)
|
||||
|
||||
if (timeout)
|
||||
{
|
||||
/* Wait until lock has been released. We use retry intervals of
|
||||
50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s. */
|
||||
if (!wtime)
|
||||
wtime = 50;
|
||||
else if (wtime < 800)
|
||||
wtime *= 2;
|
||||
else if (wtime == 800)
|
||||
wtime = 2000;
|
||||
else if (wtime < 8000)
|
||||
wtime *= 2;
|
||||
int wtimereal;
|
||||
|
||||
if (timeout > 0)
|
||||
{
|
||||
if (wtime > timeout)
|
||||
wtime = timeout;
|
||||
timeout -= wtime;
|
||||
}
|
||||
wtimereal = next_wait_interval (&wtime, &timeout);
|
||||
|
||||
if (wtime >= 800)
|
||||
my_info_1 (_("waiting for lock %s...\n"), h->lockname);
|
||||
|
||||
Sleep (wtime);
|
||||
Sleep (wtimereal);
|
||||
goto again;
|
||||
}
|
||||
|
||||
|
264
common/gettime.c
264
common/gettime.c
@ -37,6 +37,11 @@
|
||||
#ifdef HAVE_LANGINFO_H
|
||||
#include <langinfo.h>
|
||||
#endif
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <windows.h>
|
||||
#endif /*!HAVE_W32_SYSTEM*/
|
||||
#include <stdint.h> /* We use uint64_t. */
|
||||
|
||||
#include "util.h"
|
||||
#include "i18n.h"
|
||||
@ -61,6 +66,111 @@ static enum { NORMAL = 0, FROZEN, FUTURE, PAST } timemode;
|
||||
#define JD_DIFF 1721060L
|
||||
|
||||
|
||||
|
||||
/*
|
||||
timegm() is a GNU function that might not be available everywhere.
|
||||
It's basically the inverse of gmtime() - you give it a struct tm,
|
||||
and get back a time_t. It differs from mktime() in that it handles
|
||||
the case where the struct tm is UTC and the local environment isn't.
|
||||
|
||||
Note, that this replacement implementation might not be thread-safe!
|
||||
|
||||
Some BSDs don't handle the putenv("foo") case properly, so we use
|
||||
unsetenv if the platform has it to remove environment variables.
|
||||
*/
|
||||
#ifndef HAVE_TIMEGM
|
||||
time_t
|
||||
timegm (struct tm *tm)
|
||||
{
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
uint64_t val = timegm_u64 (tm);
|
||||
if (val == (uint64_t)(-1))
|
||||
return (time_t)(-1);
|
||||
return (time_t)val;
|
||||
#else /* (Non thread safe implementation!) */
|
||||
|
||||
time_t answer;
|
||||
char *zone;
|
||||
|
||||
zone=getenv("TZ");
|
||||
putenv("TZ=UTC");
|
||||
tzset();
|
||||
answer=mktime(tm);
|
||||
if(zone)
|
||||
{
|
||||
static char *old_zone;
|
||||
|
||||
if (!old_zone)
|
||||
{
|
||||
old_zone = malloc(3+strlen(zone)+1);
|
||||
if (old_zone)
|
||||
{
|
||||
strcpy(old_zone,"TZ=");
|
||||
strcat(old_zone,zone);
|
||||
}
|
||||
}
|
||||
if (old_zone)
|
||||
putenv (old_zone);
|
||||
}
|
||||
else
|
||||
gnupg_unsetenv("TZ");
|
||||
|
||||
tzset();
|
||||
return answer;
|
||||
#endif
|
||||
}
|
||||
#endif /*!HAVE_TIMEGM*/
|
||||
|
||||
|
||||
/* Version of the GNU timegm which returns an unsigned 64 bit integer
|
||||
* instead of the usually signed time_t. On error (uint64_t)(-1) is
|
||||
* returned. This function is mostly here becuase on 32 bit Windows
|
||||
* we have an internal API to get the system time even after
|
||||
* 2023-01-19. For 32 bit Unix we need to suffer from the too short
|
||||
* time_t and no system function to construct the time from a tm. */
|
||||
uint64_t
|
||||
timegm_u64 (struct tm *tm)
|
||||
{
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
/* This one is thread safe. */
|
||||
SYSTEMTIME st;
|
||||
FILETIME ft;
|
||||
unsigned long long cnsecs;
|
||||
|
||||
st.wYear = tm->tm_year + 1900;
|
||||
st.wMonth = tm->tm_mon + 1;
|
||||
st.wDay = tm->tm_mday;
|
||||
st.wHour = tm->tm_hour;
|
||||
st.wMinute = tm->tm_min;
|
||||
st.wSecond = tm->tm_sec;
|
||||
st.wMilliseconds = 0; /* Not available. */
|
||||
st.wDayOfWeek = 0; /* Ignored. */
|
||||
|
||||
/* System time is UTC thus the conversion is pretty easy. */
|
||||
if (!SystemTimeToFileTime (&st, &ft))
|
||||
{
|
||||
gpg_err_set_errno (EINVAL);
|
||||
return (uint64_t)(-1);
|
||||
}
|
||||
|
||||
cnsecs = (((unsigned long long)ft.dwHighDateTime << 32)
|
||||
| ft.dwLowDateTime);
|
||||
cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01. */
|
||||
return (uint64_t)(cnsecs / 10000000ULL);
|
||||
|
||||
#else /*Unix*/
|
||||
|
||||
time_t t = timegm (tm);
|
||||
if (t == (time_t)(-1))
|
||||
return (uint64_t)(-1);
|
||||
if ((int64_t)t < 0)
|
||||
return (uint64_t)(-1);
|
||||
return (uint64_t)t;
|
||||
|
||||
#endif /*Unix*/
|
||||
}
|
||||
|
||||
|
||||
/* Wrapper for the time(3). We use this here so we can fake the time
|
||||
for tests */
|
||||
time_t
|
||||
@ -172,6 +282,28 @@ make_timestamp (void)
|
||||
}
|
||||
|
||||
|
||||
/* Specialized version of atoi which returns an u32 instead of an int
|
||||
* and caps the result at 2^32-2. Leading white space is skipped,
|
||||
* scanning stops at at the first non-convertable byte. Note that we
|
||||
* do not cap at 2^32-1 because that value is often used as error
|
||||
* return. */
|
||||
u32
|
||||
scan_secondsstr (const char *string)
|
||||
{
|
||||
uint64_t value = 0;
|
||||
|
||||
while (*string == ' ' || *string == '\t')
|
||||
string++;
|
||||
for (; *string >= '0' && *string <= '9'; string++)
|
||||
{
|
||||
value *= 10;
|
||||
value += atoi_1 (string);
|
||||
if (value >= (u32)(-1))
|
||||
return (u32)(-1) - 1;
|
||||
}
|
||||
return (u32)value;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
* Scan a date string and return a timestamp.
|
||||
@ -208,7 +340,21 @@ scan_isodatestr( const char *string )
|
||||
tmbuf.tm_isdst = -1;
|
||||
stamp = mktime( &tmbuf );
|
||||
if( stamp == (time_t)-1 )
|
||||
return 0;
|
||||
{
|
||||
/* mktime did not work. Construct an ISO timestring for noon
|
||||
* of the given day instead. We keep the use of mktime for 64
|
||||
* bit system to limit the risk of regressions. */
|
||||
gnupg_isotime_t isobuf;
|
||||
uint64_t tmp64;
|
||||
|
||||
snprintf (isobuf, 16, "%04d%02d%02dT120000", year, month, day);
|
||||
tmp64 = isotime2epoch_u64 (isobuf);
|
||||
if (tmp64 == (uint64_t)(-1))
|
||||
return 0; /* Error. */
|
||||
if (tmp64 >= (u32)(-1))
|
||||
return 0; /* Error. */
|
||||
return (u32)tmp64;
|
||||
}
|
||||
return stamp;
|
||||
}
|
||||
|
||||
@ -363,18 +509,14 @@ string2isotime (gnupg_isotime_t atime, const char *string)
|
||||
}
|
||||
|
||||
|
||||
/* Scan an ISO timestamp and return an Epoch based timestamp. The
|
||||
only supported format is "yyyymmddThhmmss[Z]" delimited by white
|
||||
space, nul, a colon or a comma. Returns (time_t)(-1) for an
|
||||
invalid string. */
|
||||
time_t
|
||||
isotime2epoch (const char *string)
|
||||
/* Helper for isotime2epoch. Returns 0 on success. */
|
||||
static int
|
||||
isotime_make_tm (const char *string, struct tm *tmbuf)
|
||||
{
|
||||
int year, month, day, hour, minu, sec;
|
||||
struct tm tmbuf;
|
||||
|
||||
if (!isotime_p (string))
|
||||
return (time_t)(-1);
|
||||
return -1;
|
||||
|
||||
year = atoi_4 (string);
|
||||
month = atoi_2 (string + 4);
|
||||
@ -386,20 +528,48 @@ isotime2epoch (const char *string)
|
||||
/* Basic checks. */
|
||||
if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31
|
||||
|| hour > 23 || minu > 59 || sec > 61 )
|
||||
return -1;
|
||||
|
||||
memset (tmbuf, 0, sizeof *tmbuf);
|
||||
tmbuf->tm_sec = sec;
|
||||
tmbuf->tm_min = minu;
|
||||
tmbuf->tm_hour = hour;
|
||||
tmbuf->tm_mday = day;
|
||||
tmbuf->tm_mon = month-1;
|
||||
tmbuf->tm_year = year - 1900;
|
||||
tmbuf->tm_isdst = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Scan an ISO timestamp and return an Epoch based timestamp. The
|
||||
only supported format is "yyyymmddThhmmss[Z]" delimited by white
|
||||
space, nul, a colon or a comma. Returns (time_t)(-1) for an
|
||||
invalid string. */
|
||||
time_t
|
||||
isotime2epoch (const char *string)
|
||||
{
|
||||
struct tm tmbuf;
|
||||
|
||||
if (isotime_make_tm (string, &tmbuf))
|
||||
return (time_t)(-1);
|
||||
|
||||
memset (&tmbuf, 0, sizeof tmbuf);
|
||||
tmbuf.tm_sec = sec;
|
||||
tmbuf.tm_min = minu;
|
||||
tmbuf.tm_hour = hour;
|
||||
tmbuf.tm_mday = day;
|
||||
tmbuf.tm_mon = month-1;
|
||||
tmbuf.tm_year = year - 1900;
|
||||
tmbuf.tm_isdst = -1;
|
||||
return timegm (&tmbuf);
|
||||
}
|
||||
|
||||
|
||||
uint64_t
|
||||
isotime2epoch_u64 (const char *string)
|
||||
{
|
||||
struct tm tmbuf;
|
||||
|
||||
if (isotime_make_tm (string, &tmbuf))
|
||||
return (uint64_t)(-1);
|
||||
|
||||
return timegm_u64 (&tmbuf);
|
||||
}
|
||||
|
||||
|
||||
/* Convert an Epoch time to an iso time stamp. */
|
||||
void
|
||||
epoch2isotime (gnupg_isotime_t timebuf, time_t atime)
|
||||
@ -453,41 +623,6 @@ isodate_human_to_tm (const char *string, struct tm *t)
|
||||
}
|
||||
|
||||
|
||||
/* This function is a copy of gpgme/src/conversion.c:_gpgme_timegm.
|
||||
If you change it, then update the other one too. */
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
static time_t
|
||||
_win32_timegm (struct tm *tm)
|
||||
{
|
||||
/* This one is thread safe. */
|
||||
SYSTEMTIME st;
|
||||
FILETIME ft;
|
||||
unsigned long long cnsecs;
|
||||
|
||||
st.wYear = tm->tm_year + 1900;
|
||||
st.wMonth = tm->tm_mon + 1;
|
||||
st.wDay = tm->tm_mday;
|
||||
st.wHour = tm->tm_hour;
|
||||
st.wMinute = tm->tm_min;
|
||||
st.wSecond = tm->tm_sec;
|
||||
st.wMilliseconds = 0; /* Not available. */
|
||||
st.wDayOfWeek = 0; /* Ignored. */
|
||||
|
||||
/* System time is UTC thus the conversion is pretty easy. */
|
||||
if (!SystemTimeToFileTime (&st, &ft))
|
||||
{
|
||||
gpg_err_set_errno (EINVAL);
|
||||
return (time_t)(-1);
|
||||
}
|
||||
|
||||
cnsecs = (((unsigned long long)ft.dwHighDateTime << 32)
|
||||
| ft.dwLowDateTime);
|
||||
cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01. */
|
||||
return (time_t)(cnsecs / 10000000ULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Parse the string TIMESTAMP into a time_t. The string may either be
|
||||
seconds since Epoch or in the ISO 8601 format like
|
||||
"20390815T143012". Returns 0 for an empty string or seconds since
|
||||
@ -496,7 +631,11 @@ _win32_timegm (struct tm *tm)
|
||||
|
||||
This function is a copy of
|
||||
gpgme/src/conversion.c:_gpgme_parse_timestamp. If you change it,
|
||||
then update the other one too. */
|
||||
then update the other one too.
|
||||
|
||||
FIXME: Replace users of this function by one of the more modern
|
||||
functions or change the return type to u64.
|
||||
*/
|
||||
time_t
|
||||
parse_timestamp (const char *timestamp, char **endp)
|
||||
{
|
||||
@ -532,24 +671,7 @@ parse_timestamp (const char *timestamp, char **endp)
|
||||
buf.tm_min = atoi_2 (timestamp+11);
|
||||
buf.tm_sec = atoi_2 (timestamp+13);
|
||||
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
return _win32_timegm (&buf);
|
||||
#else
|
||||
#ifdef HAVE_TIMEGM
|
||||
return timegm (&buf);
|
||||
#else
|
||||
{
|
||||
time_t tim;
|
||||
|
||||
putenv ("TZ=UTC");
|
||||
tim = mktime (&buf);
|
||||
#ifdef __GNUC__
|
||||
#warning fixme: we must somehow reset TZ here. It is not threadsafe anyway.
|
||||
#endif
|
||||
return tim;
|
||||
}
|
||||
#endif /* !HAVE_TIMEGM */
|
||||
#endif /* !HAVE_W32_SYSTEM */
|
||||
}
|
||||
else
|
||||
return (time_t)strtoul (timestamp, endp, 10);
|
||||
@ -728,7 +850,7 @@ asctimestamp (u32 stamp)
|
||||
* 2018 has a lot of additional support but that will for sure
|
||||
* break other things. We should move to ISO strings to get
|
||||
* rid of such problems. */
|
||||
setlocale (LC_TIME, "");
|
||||
setlocale (LC_TIME, ".UTF8");
|
||||
done = 1;
|
||||
/* log_debug ("LC_ALL now '%s'\n", setlocale (LC_ALL, NULL)); */
|
||||
/* log_debug ("LC_TIME now '%s'\n", setlocale (LC_TIME, NULL)); */
|
||||
|
@ -32,7 +32,7 @@
|
||||
|
||||
#include <time.h> /* We need time_t. */
|
||||
#include <gpg-error.h> /* We need gpg_error_t. */
|
||||
|
||||
#include <stdint.h> /* We use uint64_t. */
|
||||
|
||||
/* A type to hold the ISO time. Note that this is the same as
|
||||
the KSBA type ksba_isotime_t. */
|
||||
@ -43,6 +43,11 @@ typedef char gnupg_isotime_t[16];
|
||||
#define GNUPG_ISOTIME_NONE \
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
|
||||
#ifndef HAVE_TIMEGM
|
||||
time_t timegm (struct tm *tm);
|
||||
#endif /*!HAVE_TIMEGM*/
|
||||
uint64_t timegm_u64 (struct tm *tm);
|
||||
|
||||
time_t gnupg_get_time (void);
|
||||
struct tm *gnupg_gmtime (const time_t *timep, struct tm *result);
|
||||
void gnupg_get_isotime (gnupg_isotime_t timebuf);
|
||||
@ -51,11 +56,13 @@ int gnupg_faked_time_p (void);
|
||||
u32 make_timestamp (void);
|
||||
char *elapsed_time_string (time_t since, time_t now);
|
||||
|
||||
u32 scan_secondsstr (const char *string);
|
||||
u32 scan_isodatestr (const char *string);
|
||||
int isotime_p (const char *string);
|
||||
int isotime_human_p (const char *string, int date_only);
|
||||
size_t string2isotime (gnupg_isotime_t atime, const char *string);
|
||||
time_t isotime2epoch (const char *string);
|
||||
uint64_t isotime2epoch_u64 (const char *string);
|
||||
void epoch2isotime (gnupg_isotime_t timebuf, time_t atime);
|
||||
int isodate_human_to_tm (const char *string, struct tm *t);
|
||||
time_t parse_timestamp (const char *timestamp, char **endp);
|
||||
|
@ -57,35 +57,6 @@ mem_count_chr (const void *buffer, int c, size_t length)
|
||||
}
|
||||
|
||||
|
||||
/* This is a case-sensitive version of our memistr. I wonder why no
|
||||
standard function memstr exists but I better do not use the name
|
||||
memstr to avoid future conflicts. */
|
||||
static const char *
|
||||
my_memstr (const void *buffer, size_t buflen, const char *sub)
|
||||
{
|
||||
const unsigned char *buf = buffer;
|
||||
const unsigned char *t = (const unsigned char *)buf;
|
||||
const unsigned char *s = (const unsigned char *)sub;
|
||||
size_t n = buflen;
|
||||
|
||||
for ( ; n ; t++, n-- )
|
||||
{
|
||||
if (*t == *s)
|
||||
{
|
||||
for (buf = t++, buflen = n--, s++; n && *t ==*s; t++, s++, n--)
|
||||
;
|
||||
if (!*s)
|
||||
return (const char*)buf;
|
||||
t = (const unsigned char *)buf;
|
||||
s = (const unsigned char *)sub ;
|
||||
n = buflen;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
string_has_ctrl_or_space (const char *string)
|
||||
{
|
||||
@ -159,7 +130,7 @@ is_valid_mailbox_mem (const void *name_arg, size_t namelen)
|
||||
|| *name == '@'
|
||||
|| name[namelen-1] == '@'
|
||||
|| name[namelen-1] == '.'
|
||||
|| my_memstr (name, namelen, ".."));
|
||||
|| gnupg_memstr (name, namelen, ".."));
|
||||
}
|
||||
|
||||
|
||||
|
@ -687,3 +687,53 @@ parse_compatibility_flags (const char *string, unsigned int *flagvar,
|
||||
*flagvar |= result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Convert STRING consisting of base64 characters into its binary
|
||||
* representation and store the result in a newly allocated buffer at
|
||||
* R_BUFFER with its length at R_BUFLEN. If TITLE is NULL a plain
|
||||
* base64 decoding is done. If it is the empty string the decoder
|
||||
* will skip everything until a "-----BEGIN " line has been seen,
|
||||
* decoding then ends at a "----END " line. On failure the function
|
||||
* returns an error code and sets R_BUFFER to NULL. If the decoded
|
||||
* data has a length of 0 a dummy buffer will still be allocated and
|
||||
* the length is set to 0. */
|
||||
gpg_error_t
|
||||
b64decode (const char *string, const char *title,
|
||||
void **r_buffer, size_t *r_buflen)
|
||||
{
|
||||
gpg_error_t err;
|
||||
gpgrt_b64state_t state;
|
||||
size_t nbytes;
|
||||
char *buffer;
|
||||
|
||||
*r_buffer = NULL;
|
||||
*r_buflen = 0;
|
||||
|
||||
buffer = xtrystrdup (string);
|
||||
if (!buffer)
|
||||
return gpg_error_from_syserror();
|
||||
|
||||
state = gpgrt_b64dec_start (title);
|
||||
if (!state)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
xfree (buffer);
|
||||
return err;
|
||||
}
|
||||
err = gpgrt_b64dec_proc (state, buffer, strlen (buffer), &nbytes);
|
||||
if (!err)
|
||||
{
|
||||
err = gpgrt_b64dec_finish (state);
|
||||
state = NULL;
|
||||
}
|
||||
if (err)
|
||||
xfree (buffer);
|
||||
else
|
||||
{
|
||||
*r_buffer = buffer;
|
||||
*r_buflen = nbytes;
|
||||
}
|
||||
gpgrt_b64dec_finish (state); /* Make sure it is released. */
|
||||
return err;
|
||||
}
|
||||
|
@ -126,80 +126,3 @@ same_file_p (const char *name1, const char *name2)
|
||||
}
|
||||
return yes;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
timegm() is a GNU function that might not be available everywhere.
|
||||
It's basically the inverse of gmtime() - you give it a struct tm,
|
||||
and get back a time_t. It differs from mktime() in that it handles
|
||||
the case where the struct tm is UTC and the local environment isn't.
|
||||
|
||||
Note, that this replacement implementation might not be thread-safe!
|
||||
|
||||
Some BSDs don't handle the putenv("foo") case properly, so we use
|
||||
unsetenv if the platform has it to remove environment variables.
|
||||
*/
|
||||
#ifndef HAVE_TIMEGM
|
||||
time_t
|
||||
timegm (struct tm *tm)
|
||||
{
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
/* This one is thread safe. */
|
||||
SYSTEMTIME st;
|
||||
FILETIME ft;
|
||||
unsigned long long cnsecs;
|
||||
|
||||
st.wYear = tm->tm_year + 1900;
|
||||
st.wMonth = tm->tm_mon + 1;
|
||||
st.wDay = tm->tm_mday;
|
||||
st.wHour = tm->tm_hour;
|
||||
st.wMinute = tm->tm_min;
|
||||
st.wSecond = tm->tm_sec;
|
||||
st.wMilliseconds = 0; /* Not available. */
|
||||
st.wDayOfWeek = 0; /* Ignored. */
|
||||
|
||||
/* System time is UTC thus the conversion is pretty easy. */
|
||||
if (!SystemTimeToFileTime (&st, &ft))
|
||||
{
|
||||
gpg_err_set_errno (EINVAL);
|
||||
return (time_t)(-1);
|
||||
}
|
||||
|
||||
cnsecs = (((unsigned long long)ft.dwHighDateTime << 32)
|
||||
| ft.dwLowDateTime);
|
||||
cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01. */
|
||||
return (time_t)(cnsecs / 10000000ULL);
|
||||
|
||||
#else /* (Non thread safe implementation!) */
|
||||
|
||||
time_t answer;
|
||||
char *zone;
|
||||
|
||||
zone=getenv("TZ");
|
||||
putenv("TZ=UTC");
|
||||
tzset();
|
||||
answer=mktime(tm);
|
||||
if(zone)
|
||||
{
|
||||
static char *old_zone;
|
||||
|
||||
if (!old_zone)
|
||||
{
|
||||
old_zone = malloc(3+strlen(zone)+1);
|
||||
if (old_zone)
|
||||
{
|
||||
strcpy(old_zone,"TZ=");
|
||||
strcat(old_zone,zone);
|
||||
}
|
||||
}
|
||||
if (old_zone)
|
||||
putenv (old_zone);
|
||||
}
|
||||
else
|
||||
gnupg_unsetenv("TZ");
|
||||
|
||||
tzset();
|
||||
return answer;
|
||||
#endif
|
||||
}
|
||||
#endif /*!HAVE_TIMEGM*/
|
||||
|
@ -38,12 +38,6 @@
|
||||
int same_file_p (const char *name1, const char *name2);
|
||||
|
||||
|
||||
#ifndef HAVE_TIMEGM
|
||||
#include <time.h>
|
||||
time_t timegm (struct tm *tm);
|
||||
#endif /*!HAVE_TIMEGM*/
|
||||
|
||||
|
||||
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
|
||||
#define DIMof(type,member) DIM(((type *)0)->member)
|
||||
|
||||
|
@ -85,37 +85,6 @@ my_error (gpg_err_code_t ec)
|
||||
}
|
||||
|
||||
|
||||
/* This is a case-sensitive version of our memistr. I wonder why no
|
||||
* standard function memstr exists but I better do not use the name
|
||||
* memstr to avoid future conflicts.
|
||||
*
|
||||
* FIXME: Move this to a stringhelp.c
|
||||
*/
|
||||
static const char *
|
||||
my_memstr (const void *buffer, size_t buflen, const char *sub)
|
||||
{
|
||||
const unsigned char *buf = buffer;
|
||||
const unsigned char *t = (const unsigned char *)buf;
|
||||
const unsigned char *s = (const unsigned char *)sub;
|
||||
size_t n = buflen;
|
||||
|
||||
for ( ; n ; t++, n-- )
|
||||
{
|
||||
if (*t == *s)
|
||||
{
|
||||
for (buf = t++, buflen = n--, s++; n && *t ==*s; t++, s++, n--)
|
||||
;
|
||||
if (!*s)
|
||||
return (const char*)buf;
|
||||
t = (const unsigned char *)buf;
|
||||
s = (const unsigned char *)sub ;
|
||||
n = buflen;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Return a pointer to the next logical connection operator or NULL if
|
||||
* none. */
|
||||
static char *
|
||||
@ -560,7 +529,7 @@ recsel_select (recsel_expr_t selector,
|
||||
break;
|
||||
case SELECT_SUB:
|
||||
if (se->xcase)
|
||||
result = !!my_memstr (value, valuelen, se->value);
|
||||
result = !!gnupg_memstr (value, valuelen, se->value);
|
||||
else
|
||||
result = !!memistr (value, valuelen, se->value);
|
||||
break;
|
||||
|
@ -161,6 +161,35 @@ ascii_memistr ( const void *buffer, size_t buflen, const char *sub )
|
||||
}
|
||||
|
||||
|
||||
/* This is a case-sensitive version of our memistr. I wonder why no
|
||||
* standard function memstr exists but we better do not use the name
|
||||
* memstr to avoid future conflicts.
|
||||
*/
|
||||
const char *
|
||||
gnupg_memstr (const void *buffer, size_t buflen, const char *sub)
|
||||
{
|
||||
const unsigned char *buf = buffer;
|
||||
const unsigned char *t = (const unsigned char *)buf;
|
||||
const unsigned char *s = (const unsigned char *)sub;
|
||||
size_t n = buflen;
|
||||
|
||||
for ( ; n ; t++, n-- )
|
||||
{
|
||||
if (*t == *s)
|
||||
{
|
||||
for (buf = t++, buflen = n--, s++; n && *t ==*s; t++, s++, n--)
|
||||
;
|
||||
if (!*s)
|
||||
return (const char*)buf;
|
||||
t = (const unsigned char *)buf;
|
||||
s = (const unsigned char *)sub ;
|
||||
n = buflen;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* This function is similar to strncpy(). However it won't copy more
|
||||
* than N - 1 characters and makes sure that a '\0' is appended. With
|
||||
* N given as 0, nothing will happen. With DEST given as NULL, memory
|
||||
@ -696,7 +725,7 @@ compare_filenames (const char *a, const char *b)
|
||||
|
||||
/* Convert a base-10 number in STRING into a 64 bit unsigned int
|
||||
* value. Leading white spaces are skipped but no error checking is
|
||||
* done. Thus it is similar to atoi(). */
|
||||
* done. Thus it is similar to atoi(). See also scan_secondsstr. */
|
||||
uint64_t
|
||||
string_to_u64 (const char *string)
|
||||
{
|
||||
|
@ -40,6 +40,7 @@
|
||||
char *has_leading_keyword (const char *string, const char *keyword);
|
||||
|
||||
const char *memistr (const void *buf, size_t buflen, const char *sub);
|
||||
const char *gnupg_memstr (const void *buffer, size_t buflen, const char *sub);
|
||||
char *mem2str( char *, const void *, size_t);
|
||||
char *trim_spaces( char *string );
|
||||
char *ascii_trim_spaces (char *string);
|
||||
|
@ -933,6 +933,11 @@ gnupg_remove (const char *fname)
|
||||
return -1;
|
||||
return 0;
|
||||
#else
|
||||
/* It is common to use /dev/null for testing. We better don't
|
||||
* remove that file. */
|
||||
if (fname && !strcmp (fname, "/dev/null"))
|
||||
return 0;
|
||||
else
|
||||
return remove (fname);
|
||||
#endif
|
||||
}
|
||||
|
221
common/t-b64.c
221
common/t-b64.c
@ -1,30 +1,23 @@
|
||||
/* t-b64.c - Module tests for b64enc.c and b64dec.c
|
||||
* Copyright (C) 2008 Free Software Foundation, Inc.
|
||||
/* t-b64.c - Module tests for b64decodec
|
||||
* Copyright (C) 2023 g10 Code GmbH
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* This file 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
As of now this is only a test program for manual tests.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -36,121 +29,117 @@
|
||||
__FILE__,__LINE__, (a)); \
|
||||
errcount++; \
|
||||
} while(0)
|
||||
#define oops() do { fprintf (stderr, "%s:%d: ooops\n", \
|
||||
__FILE__,__LINE__); \
|
||||
exit (2); \
|
||||
} while(0)
|
||||
|
||||
static int verbose;
|
||||
static int errcount;
|
||||
|
||||
static void
|
||||
test_b64enc_pgp (const char *string)
|
||||
|
||||
/* Convert STRING consisting of hex characters into its binary
|
||||
* representation and return it as an allocated buffer. The valid
|
||||
* length of the buffer is returned at R_LENGTH. The string is
|
||||
* delimited by end of string. The function returns NULL on
|
||||
* error. */
|
||||
static void *
|
||||
hex2buffer (const char *string, size_t *r_length)
|
||||
{
|
||||
gpg_error_t err;
|
||||
struct b64state state;
|
||||
const char *s;
|
||||
unsigned char *buffer;
|
||||
size_t length;
|
||||
|
||||
if (!string)
|
||||
string = "a";
|
||||
|
||||
err = b64enc_start (&state, stdout, "PGP MESSAGE");
|
||||
if (err)
|
||||
fail (1);
|
||||
|
||||
err = b64enc_write (&state, string, strlen (string));
|
||||
if (err)
|
||||
fail (2);
|
||||
|
||||
err = b64enc_finish (&state);
|
||||
if (err)
|
||||
fail (3);
|
||||
|
||||
pass ();
|
||||
buffer = xmalloc (strlen(string)/2+1);
|
||||
length = 0;
|
||||
for (s=string; *s; s +=2 )
|
||||
{
|
||||
if (!hexdigitp (s) || !hexdigitp (s+1))
|
||||
return NULL; /* Invalid hex digits. */
|
||||
((unsigned char*)buffer)[length++] = xtoi_2 (s);
|
||||
}
|
||||
*r_length = length;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
test_b64enc_file (const char *fname)
|
||||
test_b64decode (void)
|
||||
{
|
||||
static struct {
|
||||
const char *string; /* String to test. */
|
||||
const char *title; /* title parameter. */
|
||||
gpg_error_t err; /* expected error. */
|
||||
const char *datastr; /* Expected data (hex encoded) */
|
||||
} tests[] = {
|
||||
{ "YQ==", NULL, 0,
|
||||
"61" },
|
||||
{ "YWE==", NULL, 0,
|
||||
"6161" },
|
||||
{ "YWFh", NULL, 0,
|
||||
"616161" },
|
||||
{ "YWFhYQ==", NULL, 0,
|
||||
"61616161" },
|
||||
{ "YWJjZA==", NULL, 0,
|
||||
"61626364" },
|
||||
{ "AA=", NULL, 0,
|
||||
"00" },
|
||||
{ "AAEA=", NULL, 0,
|
||||
"000100" },
|
||||
{ "/w==", NULL, 0,
|
||||
"ff" },
|
||||
{ "oRQwEqADCgEDoQsGCSqGSIL3EgECAg==", NULL, 0,
|
||||
"a1143012a0030a0103a10b06092a864882f712010202" },
|
||||
{ "oRQwEqADCgEDoQsGCSqGSIL3EgECA-==", NULL, GPG_ERR_BAD_DATA,
|
||||
"a1143012a0030a0103a10b06092a864882f712010202" },
|
||||
{ "oRQwEqADCgEDoQsGCSqGSIL3EgECAg==", "", 0,
|
||||
"" },
|
||||
{ "-----BEGIN PGP\n\n"
|
||||
"oRQwEqADCgEDoQsGCSqGSIL3EgECAg==\n"
|
||||
"-----END PGP\n", "", 0,
|
||||
"a1143012a0030a0103a10b06092a864882f712010202" },
|
||||
|
||||
{ "", NULL, 0,
|
||||
"" }
|
||||
};
|
||||
int tidx;
|
||||
gpg_error_t err;
|
||||
struct b64state state;
|
||||
FILE *fp;
|
||||
char buffer[50];
|
||||
size_t nread;
|
||||
void *data = NULL;
|
||||
size_t datalen;
|
||||
char *wantdata = NULL;
|
||||
size_t wantdatalen;
|
||||
|
||||
fp = fname ? fopen (fname, "r") : stdin;
|
||||
if (!fp)
|
||||
for (tidx = 0; tidx < DIM(tests); tidx++)
|
||||
{
|
||||
fprintf (stderr, "%s:%d: can't open '%s': %s\n",
|
||||
__FILE__, __LINE__, fname? fname:"[stdin]", strerror (errno));
|
||||
fail (0);
|
||||
}
|
||||
|
||||
err = b64enc_start (&state, stdout, "DATA");
|
||||
if (err)
|
||||
fail (1);
|
||||
|
||||
while ( (nread = fread (buffer, 1, sizeof buffer, fp)) )
|
||||
{
|
||||
err = b64enc_write (&state, buffer, nread);
|
||||
if (err)
|
||||
fail (2);
|
||||
}
|
||||
|
||||
err = b64enc_finish (&state);
|
||||
if (err)
|
||||
fail (3);
|
||||
|
||||
fclose (fp);
|
||||
xfree (wantdata);
|
||||
if (!(wantdata = hex2buffer (tests[tidx].datastr, &wantdatalen)))
|
||||
oops ();
|
||||
xfree (data);
|
||||
err = b64decode (tests[tidx].string, tests[tidx].title, &data, &datalen);
|
||||
if (verbose)
|
||||
fprintf (stderr, "%s:%d: test %d, err=%d, datalen=%zu\n",
|
||||
__FILE__, __LINE__, tidx, err, datalen);
|
||||
if (gpg_err_code (err) != tests[tidx].err)
|
||||
fail (tidx);
|
||||
else if (err)
|
||||
pass ();
|
||||
else if (wantdatalen != datalen)
|
||||
fail (tidx);
|
||||
else if (memcmp (wantdata, data, datalen))
|
||||
fail (tidx);
|
||||
else
|
||||
pass ();
|
||||
}
|
||||
|
||||
static void
|
||||
test_b64dec_file (const char *fname)
|
||||
{
|
||||
gpg_error_t err;
|
||||
struct b64state state;
|
||||
FILE *fp;
|
||||
char buffer[50];
|
||||
size_t nread, nbytes;
|
||||
|
||||
fp = fname ? fopen (fname, "r") : stdin;
|
||||
if (!fp)
|
||||
{
|
||||
fprintf (stderr, "%s:%d: can't open '%s': %s\n",
|
||||
__FILE__, __LINE__, fname? fname:"[stdin]", strerror (errno));
|
||||
fail (0);
|
||||
xfree (wantdata);
|
||||
xfree (data);
|
||||
}
|
||||
|
||||
err = b64dec_start (&state, "");
|
||||
if (err)
|
||||
fail (1);
|
||||
|
||||
while ( (nread = fread (buffer, 1, sizeof buffer, fp)) )
|
||||
{
|
||||
err = b64dec_proc (&state, buffer, nread, &nbytes);
|
||||
if (err)
|
||||
{
|
||||
if (gpg_err_code (err) == GPG_ERR_EOF)
|
||||
break;
|
||||
fail (2);
|
||||
}
|
||||
else if (nbytes)
|
||||
fwrite (buffer, 1, nbytes, stdout);
|
||||
}
|
||||
|
||||
err = b64dec_finish (&state);
|
||||
if (err)
|
||||
fail (3);
|
||||
|
||||
fclose (fp);
|
||||
pass ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int do_encode = 0;
|
||||
int do_decode = 0;
|
||||
|
||||
if (argc)
|
||||
{ argc--; argv++; }
|
||||
if (argc && !strcmp (argv[0], "--verbose"))
|
||||
@ -159,23 +148,7 @@ main (int argc, char **argv)
|
||||
argc--; argv++;
|
||||
}
|
||||
|
||||
if (argc && !strcmp (argv[0], "--encode"))
|
||||
{
|
||||
do_encode = 1;
|
||||
argc--; argv++;
|
||||
}
|
||||
else if (argc && !strcmp (argv[0], "--decode"))
|
||||
{
|
||||
do_decode = 1;
|
||||
argc--; argv++;
|
||||
}
|
||||
|
||||
if (do_encode)
|
||||
test_b64enc_file (argc? *argv: NULL);
|
||||
else if (do_decode)
|
||||
test_b64dec_file (argc? *argv: NULL);
|
||||
else
|
||||
test_b64enc_pgp (argc? *argv: NULL);
|
||||
test_b64decode ();
|
||||
|
||||
return !!errcount;
|
||||
}
|
||||
|
@ -43,6 +43,56 @@ static int errcount;
|
||||
#define INVALID ((time_t)(-1))
|
||||
|
||||
|
||||
static void
|
||||
test_scan_secondsstr (void)
|
||||
{
|
||||
struct { const char *string; u32 expected; } array [] = {
|
||||
{ "", 0 },
|
||||
{ "0", 0 },
|
||||
{ " 0", 0 },
|
||||
{ " 0x", 0 },
|
||||
{ " 1", 1 },
|
||||
{ "-1", 0 },
|
||||
{ " -1", 0 },
|
||||
{ "2", 2 },
|
||||
{ "11", 11 },
|
||||
{ "011", 11 },
|
||||
{ "3600 ", 3600 },
|
||||
{ "65535", 65535 },
|
||||
{ "65536", 65536 },
|
||||
{ "65537", 65537 },
|
||||
{ "4294967289", 4294967289 },
|
||||
{ "4294967290", 4294967290 },
|
||||
{ "4294967293", 4294967293 },
|
||||
{ "4294967295", 4294967294 },
|
||||
{ "4294967296", 4294967294 },
|
||||
{ "4294967297", 4294967294 },
|
||||
{ "4294967298", 4294967294 },
|
||||
{ "4294967299", 4294967294 },
|
||||
{ "4294967300", 4294967294 },
|
||||
{ "5294967300", 4294967294 },
|
||||
{ "9999999999", 4294967294 },
|
||||
{ "99999999999",4294967294 },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
int idx;
|
||||
u32 val;
|
||||
|
||||
for (idx=0; array[idx].string; idx++)
|
||||
{
|
||||
val = scan_secondsstr (array[idx].string);
|
||||
if (val != array[idx].expected )
|
||||
{
|
||||
fail (idx);
|
||||
if (verbose)
|
||||
fprintf (stderr, "string '%s' exp: %ld got: %ld\n",
|
||||
array[idx].string, (unsigned long)array[idx].expected,
|
||||
(unsigned long)val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
test_isotime2epoch (void)
|
||||
{
|
||||
@ -103,7 +153,6 @@ test_isotime2epoch (void)
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
test_string2isotime (void)
|
||||
{
|
||||
@ -269,6 +318,7 @@ main (int argc, char **argv)
|
||||
if (argc > 1 && !strcmp (argv[1], "--verbose"))
|
||||
verbose = 1;
|
||||
|
||||
test_scan_secondsstr ();
|
||||
test_isotime2epoch ();
|
||||
test_string2isotime ();
|
||||
test_isodate_human_to_tm ();
|
||||
|
788
common/tlv-parser.c
Normal file
788
common/tlv-parser.c
Normal file
@ -0,0 +1,788 @@
|
||||
/* tlv-parser.c - Parse BER encoded objects
|
||||
* Copyright (C) 2023 g10 Code GmbH
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* This file is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This file 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.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <gpg-error.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "tlv.h"
|
||||
|
||||
|
||||
#define TLV_MAX_DEPTH 25
|
||||
|
||||
|
||||
struct bufferlist_s
|
||||
{
|
||||
struct bufferlist_s *next;
|
||||
char *buffer;
|
||||
};
|
||||
|
||||
|
||||
/* An object to control the ASN.1 parsing. */
|
||||
struct tlv_parser_s
|
||||
{
|
||||
/* The orginal buffer with the entire pkcs#12 object and its length. */
|
||||
const unsigned char *origbuffer;
|
||||
size_t origbufsize;
|
||||
|
||||
/* The current buffer we are working on and its length. */
|
||||
const unsigned char *buffer;
|
||||
size_t bufsize;
|
||||
|
||||
int in_ndef; /* Flag indicating that we are in a NDEF. */
|
||||
int pending; /* The last tlv_next has not yet been processed. */
|
||||
|
||||
struct tag_info ti; /* The current tag. */
|
||||
gpg_error_t lasterr; /* Last error from tlv function. */
|
||||
const char *lastfunc;/* Name of last called function. */
|
||||
int verbosity; /* Arg from tlv_parser_new. */
|
||||
|
||||
struct bufferlist_s *bufferlist; /* To keep track of malloced buffers. */
|
||||
|
||||
unsigned int stacklen; /* Used size of the stack. */
|
||||
struct {
|
||||
const unsigned char *buffer; /* Saved value of BUFFER. */
|
||||
size_t bufsize; /* Saved value of BUFSIZE. */
|
||||
size_t length; /* Length of the container (ti.length). */
|
||||
int in_ndef; /* Saved IN_NDEF flag (ti.ndef). */
|
||||
} stack[TLV_MAX_DEPTH];
|
||||
};
|
||||
|
||||
|
||||
static unsigned char *cram_octet_string (const unsigned char *input,
|
||||
size_t length, size_t *r_newlength);
|
||||
static int need_octet_string_cramming (const unsigned char *input,
|
||||
size_t length);
|
||||
|
||||
|
||||
|
||||
void
|
||||
_tlv_parser_dump_tag (const char *text, int lno, tlv_parser_t tlv)
|
||||
{
|
||||
struct tag_info *ti;
|
||||
|
||||
if (!tlv || tlv->verbosity < 2)
|
||||
return;
|
||||
|
||||
ti = &tlv->ti;
|
||||
|
||||
log_debug ("p12_parse:%s:%d: @%04zu class=%d tag=%lu len=%zu nhdr=%zu %s%s\n",
|
||||
text, lno,
|
||||
(size_t)(tlv->buffer - tlv->origbuffer) - ti->nhdr,
|
||||
ti->class, ti->tag, ti->length, ti->nhdr,
|
||||
ti->is_constructed?" cons":"",
|
||||
ti->ndef?" ndef":"");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_tlv_parser_dump_state (const char *text, const char *text2,
|
||||
int lno, tlv_parser_t tlv)
|
||||
{
|
||||
if (!tlv || tlv->verbosity < 2)
|
||||
return;
|
||||
|
||||
log_debug ("p12_parse:%s%s%s:%d: @%04zu lvl=%u %s\n",
|
||||
text,
|
||||
text2? "/":"", text2? text2:"",
|
||||
lno,
|
||||
(size_t)(tlv->buffer - tlv->origbuffer),
|
||||
tlv->stacklen,
|
||||
tlv->in_ndef? " in-ndef":"");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Parse the buffer at the address BUFFER which is of SIZE and return
|
||||
* the tag and the length part from the TLV triplet. Update BUFFER
|
||||
* and SIZE on success. Checks that the encoded length does not
|
||||
* exhaust the length of the provided buffer. */
|
||||
static int
|
||||
parse_tag (unsigned char const **buffer, size_t *size, struct tag_info *ti)
|
||||
{
|
||||
gpg_error_t err;
|
||||
int tag;
|
||||
|
||||
err = parse_ber_header (buffer, size,
|
||||
&ti->class, &tag,
|
||||
&ti->is_constructed, &ti->ndef,
|
||||
&ti->length, &ti->nhdr);
|
||||
if (err)
|
||||
return err;
|
||||
if (tag < 0)
|
||||
return gpg_error (GPG_ERR_EOVERFLOW);
|
||||
ti->tag = tag;
|
||||
|
||||
if (ti->length > *size)
|
||||
return gpg_error (GPG_ERR_BUFFER_TOO_SHORT); /* data larger than buffer. */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Public version of parse_tag. */
|
||||
gpg_error_t
|
||||
tlv_parse_tag (unsigned char const **buffer, size_t *size, struct tag_info *ti)
|
||||
{
|
||||
return parse_tag (buffer, size, ti);
|
||||
}
|
||||
|
||||
|
||||
/* Create a new TLV object. */
|
||||
tlv_parser_t
|
||||
tlv_parser_new (const unsigned char *buffer, size_t bufsize, int verbosity)
|
||||
{
|
||||
tlv_parser_t tlv;
|
||||
tlv = xtrycalloc (1, sizeof *tlv);
|
||||
if (tlv)
|
||||
{
|
||||
tlv->origbuffer = buffer;
|
||||
tlv->origbufsize = bufsize;
|
||||
tlv->buffer = buffer;
|
||||
tlv->bufsize = bufsize;
|
||||
tlv->verbosity = verbosity;
|
||||
}
|
||||
return tlv;
|
||||
}
|
||||
|
||||
|
||||
/* This function can be used to store a malloced buffer into the TLV
|
||||
* object. Ownership of BUFFER is thus transferred to TLV. This
|
||||
* buffer will then only be released by tlv_release. */
|
||||
static gpg_error_t
|
||||
register_buffer (tlv_parser_t tlv, char *buffer)
|
||||
{
|
||||
struct bufferlist_s *item;
|
||||
|
||||
item = xtrycalloc (1, sizeof *item);
|
||||
if (!item)
|
||||
return gpg_error_from_syserror ();
|
||||
item->buffer = buffer;
|
||||
item->next = tlv->bufferlist;
|
||||
tlv->bufferlist = item;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
tlv_parser_release (tlv_parser_t tlv)
|
||||
{
|
||||
if (!tlv)
|
||||
return;
|
||||
while (tlv->bufferlist)
|
||||
{
|
||||
struct bufferlist_s *save = tlv->bufferlist->next;
|
||||
xfree (tlv->bufferlist->buffer);
|
||||
xfree (tlv->bufferlist);
|
||||
tlv->bufferlist = save;
|
||||
}
|
||||
xfree (tlv);
|
||||
}
|
||||
|
||||
|
||||
/* Helper for the tlv_peek functions. */
|
||||
static gpg_error_t
|
||||
_tlv_peek (tlv_parser_t tlv, struct tag_info *ti)
|
||||
{
|
||||
const unsigned char *p;
|
||||
size_t n;
|
||||
|
||||
/* Note that we want to peek ahead of any current container but of
|
||||
* course not beyond our entire buffer. */
|
||||
p = tlv->buffer;
|
||||
if ((p - tlv->origbuffer) > tlv->origbufsize)
|
||||
return gpg_error (GPG_ERR_BUG);
|
||||
n = tlv->origbufsize - (p - tlv->origbuffer);
|
||||
return parse_tag (&p, &n, ti);
|
||||
}
|
||||
|
||||
|
||||
/* Look for the next tag and return true if it matches CLASS and TAG.
|
||||
* Otherwise return false. No state is changed. */
|
||||
int
|
||||
_tlv_parser_peek (tlv_parser_t tlv, int class, int tag)
|
||||
{
|
||||
struct tag_info ti;
|
||||
|
||||
return (!_tlv_peek (tlv, &ti)
|
||||
&& ti.class == class && ti.tag == tag);
|
||||
}
|
||||
|
||||
|
||||
/* Look for the next tag and return true if it is the Null tag.
|
||||
* Otherwise return false. No state is changed. */
|
||||
int
|
||||
_tlv_parser_peek_null (tlv_parser_t tlv)
|
||||
{
|
||||
struct tag_info ti;
|
||||
|
||||
return (!_tlv_peek (tlv, &ti)
|
||||
&& ti.class == CLASS_UNIVERSAL && ti.tag == TAG_NULL
|
||||
&& !ti.is_constructed && !ti.length);
|
||||
}
|
||||
|
||||
|
||||
/* Helper for tlv_expect_sequence and tlv_expect_context_tag. */
|
||||
static gpg_error_t
|
||||
_tlv_push (tlv_parser_t tlv)
|
||||
{
|
||||
/* Right now our pointer is at the value of the current container.
|
||||
* We push that info onto the stack. */
|
||||
if (tlv->stacklen >= TLV_MAX_DEPTH)
|
||||
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_MANY));
|
||||
tlv->stack[tlv->stacklen].buffer = tlv->buffer;
|
||||
tlv->stack[tlv->stacklen].bufsize = tlv->bufsize;
|
||||
tlv->stack[tlv->stacklen].in_ndef = tlv->in_ndef;
|
||||
tlv->stack[tlv->stacklen].length = tlv->ti.length;
|
||||
tlv->stacklen++;
|
||||
|
||||
tlv->in_ndef = tlv->ti.ndef;
|
||||
|
||||
/* We set the size of the buffer to the TLV length if it is known or
|
||||
* else to the size of the remaining entire buffer. */
|
||||
if (tlv->in_ndef)
|
||||
{
|
||||
if ((tlv->buffer - tlv->origbuffer) > tlv->origbufsize)
|
||||
return (tlv->lasterr = gpg_error (GPG_ERR_BUG));
|
||||
tlv->bufsize = tlv->origbufsize - (tlv->buffer - tlv->origbuffer);
|
||||
}
|
||||
else
|
||||
tlv->bufsize = tlv->ti.length;
|
||||
|
||||
_tlv_parser_dump_state (__func__, NULL, 0, tlv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Helper for tlv_next. */
|
||||
static gpg_error_t
|
||||
_tlv_pop (tlv_parser_t tlv)
|
||||
{
|
||||
size_t lastlen;
|
||||
|
||||
/* We reached the end of a container, either due to the size limit
|
||||
* or due to an end tag. Now we pop the last container so that we
|
||||
* are positioned at the value of the last container. */
|
||||
if (!tlv->stacklen)
|
||||
return gpg_error (GPG_ERR_EOF);
|
||||
|
||||
tlv->stacklen--;
|
||||
tlv->in_ndef = tlv->stack[tlv->stacklen].in_ndef;
|
||||
if (tlv->in_ndef)
|
||||
{
|
||||
/* We keep buffer but adjust bufsize to the end of the origbuffer. */
|
||||
if ((tlv->buffer - tlv->origbuffer) > tlv->origbufsize)
|
||||
return (tlv->lasterr = gpg_error (GPG_ERR_BUG));
|
||||
tlv->bufsize = tlv->origbufsize - (tlv->buffer - tlv->origbuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
lastlen = tlv->stack[tlv->stacklen].length;
|
||||
tlv->buffer = tlv->stack[tlv->stacklen].buffer;
|
||||
tlv->bufsize = tlv->stack[tlv->stacklen].bufsize;
|
||||
if (lastlen > tlv->bufsize)
|
||||
{
|
||||
log_debug ("%s: container length larger than buffer (%zu/%zu)\n",
|
||||
__func__, lastlen, tlv->bufsize);
|
||||
return gpg_error (GPG_ERR_INV_BER);
|
||||
}
|
||||
tlv->buffer += lastlen;
|
||||
tlv->bufsize -= lastlen;
|
||||
}
|
||||
|
||||
_tlv_parser_dump_state (__func__, NULL, 0, tlv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Parse the next tag and value. Also detect the end of a
|
||||
* container. The caller should use the tlv_next macro. */
|
||||
gpg_error_t
|
||||
_tlv_parser_next (tlv_parser_t tlv, int lno)
|
||||
{
|
||||
gpg_error_t err;
|
||||
|
||||
tlv->lasterr = 0;
|
||||
tlv->lastfunc = __func__;
|
||||
|
||||
if (tlv->pending)
|
||||
{
|
||||
tlv->pending = 0;
|
||||
if (tlv->verbosity > 1)
|
||||
log_debug ("%s: skipped\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tlv->verbosity > 1)
|
||||
log_debug ("%s: called\n", __func__);
|
||||
/* If we are at the end of an ndef container pop the stack. */
|
||||
if (!tlv->in_ndef && !tlv->bufsize)
|
||||
{
|
||||
do
|
||||
err = _tlv_pop (tlv);
|
||||
while (!err && !tlv->in_ndef && !tlv->bufsize);
|
||||
if (err)
|
||||
return (tlv->lasterr = err);
|
||||
if (tlv->verbosity > 1)
|
||||
log_debug ("%s: container(s) closed due to size\n", __func__);
|
||||
}
|
||||
|
||||
again:
|
||||
/* Get the next tag. */
|
||||
err = parse_tag (&tlv->buffer, &tlv->bufsize, &tlv->ti);
|
||||
if (err)
|
||||
{
|
||||
if (tlv->verbosity > 1)
|
||||
log_debug ("%s: reading tag returned err=%d\n", __func__, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* If there is an end tag in an ndef container pop the stack. Also
|
||||
* pop other containers which are fully consumed. */
|
||||
if (tlv->in_ndef && (tlv->ti.class == CLASS_UNIVERSAL
|
||||
&& !tlv->ti.tag && !tlv->ti.is_constructed))
|
||||
{
|
||||
do
|
||||
err = _tlv_pop (tlv);
|
||||
while (!err && !tlv->in_ndef && !tlv->bufsize);
|
||||
if (err)
|
||||
return (tlv->lasterr = err);
|
||||
if (tlv->verbosity > 1)
|
||||
log_debug ("%s: container(s) closed due to end tag\n", __func__);
|
||||
goto again;
|
||||
}
|
||||
|
||||
_tlv_parser_dump_tag (__func__, lno, tlv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Return the current neting level of the TLV object. */
|
||||
unsigned int
|
||||
tlv_parser_level (tlv_parser_t tlv)
|
||||
{
|
||||
return tlv? tlv->stacklen : 0;
|
||||
}
|
||||
|
||||
/* Returns the current offset of the parser. */
|
||||
size_t
|
||||
tlv_parser_offset (tlv_parser_t tlv)
|
||||
{
|
||||
return tlv? (size_t)(tlv->buffer - tlv->origbuffer) : 0;
|
||||
}
|
||||
|
||||
|
||||
/* Return a string with the last function used. If TLV is NULL an
|
||||
* empty string is returned. */
|
||||
const char *
|
||||
tlv_parser_lastfunc (tlv_parser_t tlv)
|
||||
{
|
||||
return tlv? tlv->lastfunc:"";
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
tlv_parser_lasterrstr (tlv_parser_t tlv)
|
||||
{
|
||||
return tlv? gpg_strerror (tlv->lasterr) : "tlv parser not yet initialized";
|
||||
}
|
||||
|
||||
|
||||
/* Set a flag to indicate that the last tlv_next has not yet been
|
||||
* consumed. */
|
||||
void
|
||||
tlv_parser_set_pending (tlv_parser_t tlv)
|
||||
{
|
||||
tlv->pending = 1;
|
||||
}
|
||||
|
||||
|
||||
/* Return the length of the last read tag. If with_header is 1 the
|
||||
* lengtb of the header is added to the returned length. */
|
||||
size_t
|
||||
tlv_parser_tag_length (tlv_parser_t tlv, int with_header)
|
||||
{
|
||||
if (with_header)
|
||||
return tlv->ti.length + tlv->ti.nhdr;
|
||||
else
|
||||
return tlv->ti.length;
|
||||
}
|
||||
|
||||
|
||||
/* Skip over the value of the current tag. Does not yet work for ndef
|
||||
* containers. */
|
||||
void
|
||||
tlv_parser_skip (tlv_parser_t tlv)
|
||||
{
|
||||
tlv->lastfunc = __func__;
|
||||
log_assert (tlv->bufsize >= tlv->ti.length);
|
||||
tlv->buffer += tlv->ti.length;
|
||||
tlv->bufsize -= tlv->ti.length;
|
||||
}
|
||||
|
||||
|
||||
/* Expect that the current tag is a sequence and setup the context for
|
||||
* processing. */
|
||||
gpg_error_t
|
||||
tlv_expect_sequence (tlv_parser_t tlv)
|
||||
{
|
||||
tlv->lastfunc = __func__;
|
||||
if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_SEQUENCE
|
||||
&& tlv->ti.is_constructed))
|
||||
return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
|
||||
return _tlv_push (tlv);
|
||||
}
|
||||
|
||||
|
||||
/* Expect that the current tag is a context tag and setup the context
|
||||
* for processing. The tag of the context is returned at R_TAG. */
|
||||
gpg_error_t
|
||||
tlv_expect_context_tag (tlv_parser_t tlv, int *r_tag)
|
||||
{
|
||||
tlv->lastfunc = __func__;
|
||||
if (!(tlv->ti.class == CLASS_CONTEXT && tlv->ti.is_constructed))
|
||||
return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
|
||||
*r_tag = tlv->ti.tag;
|
||||
return _tlv_push (tlv);
|
||||
}
|
||||
|
||||
|
||||
/* Expect that the current tag is a SET and setup the context for
|
||||
* processing. */
|
||||
gpg_error_t
|
||||
tlv_expect_set (tlv_parser_t tlv)
|
||||
{
|
||||
tlv->lastfunc = __func__;
|
||||
if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_SET
|
||||
&& tlv->ti.is_constructed))
|
||||
return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
|
||||
return _tlv_push (tlv);
|
||||
}
|
||||
|
||||
|
||||
/* Expect an object of CLASS with TAG and store its value at
|
||||
* (R_DATA,R_DATALEN). Then skip over its value to the next tag.
|
||||
* Note that the stored value is not allocated but points into
|
||||
* TLV. */
|
||||
gpg_error_t
|
||||
tlv_expect_object (tlv_parser_t tlv, int class, int tag,
|
||||
unsigned char const **r_data, size_t *r_datalen)
|
||||
{
|
||||
gpg_error_t err;
|
||||
const unsigned char *p;
|
||||
size_t n;
|
||||
int needpush = 0;
|
||||
|
||||
tlv->lastfunc = __func__;
|
||||
if (!(tlv->ti.class == class && tlv->ti.tag == tag))
|
||||
return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
|
||||
p = tlv->buffer;
|
||||
n = tlv->ti.length;
|
||||
if (!n && tlv->ti.ndef)
|
||||
{
|
||||
n = tlv->bufsize;
|
||||
needpush = 1;
|
||||
}
|
||||
else if (!tlv->ti.length)
|
||||
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
|
||||
|
||||
if (class == CLASS_CONTEXT && tag == 0 && tlv->ti.is_constructed
|
||||
&& need_octet_string_cramming (p, n))
|
||||
{
|
||||
char *newbuffer;
|
||||
|
||||
newbuffer = cram_octet_string (p, n, r_datalen);
|
||||
if (!newbuffer)
|
||||
return (tlv->lasterr = gpg_error (GPG_ERR_BAD_BER));
|
||||
err = register_buffer (tlv, newbuffer);
|
||||
if (err)
|
||||
{
|
||||
xfree (newbuffer);
|
||||
return (tlv->lasterr = err);
|
||||
}
|
||||
*r_data = newbuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
*r_data = p;
|
||||
*r_datalen = n;
|
||||
}
|
||||
if (needpush)
|
||||
return _tlv_push (tlv);
|
||||
|
||||
if (!(tlv->bufsize >= tlv->ti.length))
|
||||
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
|
||||
tlv->buffer += tlv->ti.length;
|
||||
tlv->bufsize -= tlv->ti.length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Expect that the current tag is an object string and store its value
|
||||
* at (R_DATA,R_DATALEN). Then skip over its value to the next tag.
|
||||
* Note that the stored value are not allocated but point into TLV.
|
||||
* If ENCAPSULATES is set the octet string is used as a new
|
||||
* container. R_DATA and R_DATALEN are optional. */
|
||||
gpg_error_t
|
||||
tlv_expect_octet_string (tlv_parser_t tlv, int encapsulates,
|
||||
unsigned char const **r_data, size_t *r_datalen)
|
||||
{
|
||||
gpg_error_t err;
|
||||
const unsigned char *p;
|
||||
size_t n;
|
||||
|
||||
tlv->lastfunc = __func__;
|
||||
if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_OCTET_STRING
|
||||
&& (!tlv->ti.is_constructed || encapsulates)))
|
||||
return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
|
||||
p = tlv->buffer;
|
||||
if (!(n=tlv->ti.length) && !tlv->ti.ndef)
|
||||
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
|
||||
|
||||
if (encapsulates && tlv->ti.is_constructed
|
||||
&& need_octet_string_cramming (p, n))
|
||||
{
|
||||
char *newbuffer;
|
||||
|
||||
newbuffer = cram_octet_string (p, n, r_datalen);
|
||||
if (!newbuffer)
|
||||
return (tlv->lasterr = gpg_error (GPG_ERR_BAD_BER));
|
||||
err = register_buffer (tlv, newbuffer);
|
||||
if (err)
|
||||
{
|
||||
xfree (newbuffer);
|
||||
return (tlv->lasterr = err);
|
||||
}
|
||||
*r_data = newbuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (r_data)
|
||||
*r_data = p;
|
||||
if (r_datalen)
|
||||
*r_datalen = tlv->ti.length;
|
||||
}
|
||||
if (encapsulates)
|
||||
return _tlv_push (tlv);
|
||||
|
||||
if (!(tlv->bufsize >= tlv->ti.length))
|
||||
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
|
||||
tlv->buffer += tlv->ti.length;
|
||||
tlv->bufsize -= tlv->ti.length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Expect that the current tag is an integer and return its value at
|
||||
* R_VALUE. Then skip over its value to the next tag. */
|
||||
gpg_error_t
|
||||
tlv_expect_integer (tlv_parser_t tlv, int *r_value)
|
||||
{
|
||||
const unsigned char *p;
|
||||
size_t n;
|
||||
int value;
|
||||
|
||||
tlv->lastfunc = __func__;
|
||||
if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_INTEGER
|
||||
&& !tlv->ti.is_constructed))
|
||||
return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
|
||||
p = tlv->buffer;
|
||||
if (!(n=tlv->ti.length))
|
||||
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
|
||||
|
||||
/* We currently support only positive values. */
|
||||
if ((*p & 0x80))
|
||||
return (tlv->lasterr = gpg_error (GPG_ERR_ERANGE));
|
||||
|
||||
for (value = 0; n; n--)
|
||||
{
|
||||
value <<= 8;
|
||||
value |= (*p++) & 0xff;
|
||||
if (value < 0)
|
||||
return (tlv->lasterr = gpg_error (GPG_ERR_EOVERFLOW));
|
||||
}
|
||||
*r_value = value;
|
||||
if (!(tlv->bufsize >= tlv->ti.length))
|
||||
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
|
||||
tlv->buffer += tlv->ti.length;
|
||||
tlv->bufsize -= tlv->ti.length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Variant of tlv_expect_integer which returns an MPI. If IGNORE_ZERO
|
||||
* is set a value of 0 is ignored and R_VALUE not changed and the
|
||||
* function returns GPG_ERR_FALSE. No check for negative encoded
|
||||
* integers is done because the old code here worked the same and we
|
||||
* can't foreclose invalid encoded PKCS#12 stuff - after all it is
|
||||
* PKCS#12 see https://www.cs.auckland.ac.nz/~pgut001/pubs/pfx.html */
|
||||
#ifdef GCRYPT_VERSION
|
||||
gpg_error_t
|
||||
tlv_expect_mpinteger (tlv_parser_t tlv, int ignore_zero,
|
||||
gcry_mpi_t *r_value)
|
||||
{
|
||||
const unsigned char *p;
|
||||
size_t n;
|
||||
|
||||
tlv->lastfunc = __func__;
|
||||
if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_INTEGER
|
||||
&& !tlv->ti.is_constructed))
|
||||
return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
|
||||
p = tlv->buffer;
|
||||
if (!(n=tlv->ti.length))
|
||||
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
|
||||
|
||||
if (!(tlv->bufsize >= tlv->ti.length))
|
||||
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
|
||||
tlv->buffer += tlv->ti.length;
|
||||
tlv->bufsize -= tlv->ti.length;
|
||||
if (ignore_zero && n == 1 && !*p)
|
||||
return gpg_error (GPG_ERR_FALSE);
|
||||
|
||||
return gcry_mpi_scan (r_value, GCRYMPI_FMT_USG, p, n, NULL);
|
||||
}
|
||||
#endif /*GCRYPT_VERSION*/
|
||||
|
||||
|
||||
/* Expect that the current tag is an object id and store its value at
|
||||
* (R_OID,R_OIDLEN). Then skip over its value to the next tag. Note
|
||||
* that the stored value is not allocated but points into TLV. */
|
||||
gpg_error_t
|
||||
tlv_expect_object_id (tlv_parser_t tlv,
|
||||
unsigned char const **r_oid, size_t *r_oidlen)
|
||||
{
|
||||
const unsigned char *p;
|
||||
size_t n;
|
||||
|
||||
tlv->lastfunc = __func__;
|
||||
if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_OBJECT_ID
|
||||
&& !tlv->ti.is_constructed))
|
||||
return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
|
||||
p = tlv->buffer;
|
||||
if (!(n=tlv->ti.length))
|
||||
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
|
||||
|
||||
*r_oid = p;
|
||||
*r_oidlen = tlv->ti.length;
|
||||
if (!(tlv->bufsize >= tlv->ti.length))
|
||||
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
|
||||
tlv->buffer += tlv->ti.length;
|
||||
tlv->bufsize -= tlv->ti.length;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Given an ASN.1 chunk of a structure like:
|
||||
*
|
||||
* 24 NDEF: OCTET STRING -- This is not passed to us
|
||||
* 04 1: OCTET STRING -- INPUT point s to here
|
||||
* : 30
|
||||
* 04 1: OCTET STRING
|
||||
* : 80
|
||||
* [...]
|
||||
* 04 2: OCTET STRING
|
||||
* : 00 00
|
||||
* : } -- This denotes a Null tag and are the last
|
||||
* -- two bytes in INPUT.
|
||||
*
|
||||
* The example is from Mozilla Firefox 1.0.4 which actually exports
|
||||
* certs as single byte chunks of octet strings.
|
||||
*
|
||||
* Create a new buffer with the content of that octet string. INPUT
|
||||
* is the original buffer with a LENGTH. Returns
|
||||
* NULL on error or a new malloced buffer with its actual used length
|
||||
* stored at R_NEWLENGTH. */
|
||||
static unsigned char *
|
||||
cram_octet_string (const unsigned char *input, size_t length,
|
||||
size_t *r_newlength)
|
||||
{
|
||||
const unsigned char *s = input;
|
||||
size_t n = length;
|
||||
unsigned char *output, *d;
|
||||
struct tag_info ti;
|
||||
|
||||
/* Allocate output buf. We know that it won't be longer than the
|
||||
input buffer. */
|
||||
d = output = xtrymalloc (length);
|
||||
if (!output)
|
||||
goto bailout;
|
||||
|
||||
while (n)
|
||||
{
|
||||
if (parse_tag (&s, &n, &ti))
|
||||
goto bailout;
|
||||
if (ti.class == CLASS_UNIVERSAL && ti.tag == TAG_OCTET_STRING
|
||||
&& !ti.ndef && !ti.is_constructed)
|
||||
{
|
||||
memcpy (d, s, ti.length);
|
||||
s += ti.length;
|
||||
d += ti.length;
|
||||
n -= ti.length;
|
||||
}
|
||||
else if (ti.class == CLASS_UNIVERSAL && !ti.tag && !ti.is_constructed)
|
||||
break; /* Ready */
|
||||
else
|
||||
goto bailout;
|
||||
}
|
||||
|
||||
|
||||
*r_newlength = d - output;
|
||||
return output;
|
||||
|
||||
bailout:
|
||||
xfree (output);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* Return true if (INPUT,LENGTH) is a structure which should be passed
|
||||
* to cram_octet_string. This is basically the same loop as in
|
||||
* cram_octet_string but without any actual copying. */
|
||||
static int
|
||||
need_octet_string_cramming (const unsigned char *input, size_t length)
|
||||
{
|
||||
const unsigned char *s = input;
|
||||
size_t n = length;
|
||||
struct tag_info ti;
|
||||
|
||||
if (!length)
|
||||
return 0;
|
||||
|
||||
while (n)
|
||||
{
|
||||
if (parse_tag (&s, &n, &ti))
|
||||
return 0;
|
||||
if (ti.class == CLASS_UNIVERSAL && ti.tag == TAG_OCTET_STRING
|
||||
&& !ti.ndef && !ti.is_constructed)
|
||||
{
|
||||
s += ti.length;
|
||||
n -= ti.length;
|
||||
}
|
||||
else if (ti.class == CLASS_UNIVERSAL && !ti.tag && !ti.is_constructed)
|
||||
break; /* Ready */
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
67
common/tlv.h
67
common/tlv.h
@ -71,10 +71,22 @@ enum tlv_tag_type {
|
||||
TAG_BMP_STRING = 30
|
||||
};
|
||||
|
||||
struct tag_info
|
||||
{
|
||||
int class;
|
||||
int is_constructed;
|
||||
unsigned long tag;
|
||||
size_t length; /* length part of the TLV */
|
||||
size_t nhdr;
|
||||
int ndef; /* It is an indefinite length */
|
||||
};
|
||||
|
||||
struct tlv_builder_s;
|
||||
typedef struct tlv_builder_s *tlv_builder_t;
|
||||
|
||||
struct tlv_parser_s;
|
||||
typedef struct tlv_parser_s *tlv_parser_t;
|
||||
|
||||
/*-- tlv.c --*/
|
||||
|
||||
/* Locate a TLV encoded data object in BUFFER of LENGTH and return a
|
||||
@ -94,7 +106,7 @@ const unsigned char *find_tlv_unchecked (const unsigned char *buffer,
|
||||
|
||||
/* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag
|
||||
and the length part from the TLV triplet. Update BUFFER and SIZE
|
||||
on success. */
|
||||
on success. See also tlv_parse_tag. */
|
||||
gpg_error_t parse_ber_header (unsigned char const **buffer, size_t *size,
|
||||
int *r_class, int *r_tag,
|
||||
int *r_constructed,
|
||||
@ -137,6 +149,59 @@ void put_tlv_to_membuf (membuf_t *membuf, int class, int tag,
|
||||
size_t get_tlv_length (int class, int tag, int constructed, size_t length);
|
||||
|
||||
|
||||
/*-- tlv-parser.c --*/
|
||||
|
||||
tlv_parser_t tlv_parser_new (const unsigned char *buffer, size_t bufsize,
|
||||
int verbosity);
|
||||
void tlv_parser_release (tlv_parser_t tlv);
|
||||
|
||||
void _tlv_parser_dump_tag (const char *text, int lno, tlv_parser_t tlv);
|
||||
void _tlv_parser_dump_state (const char *text, const char *text2,
|
||||
int lno, tlv_parser_t tlv);
|
||||
|
||||
int _tlv_parser_peek (tlv_parser_t tlv, int class, int tag);
|
||||
int _tlv_parser_peek_null (tlv_parser_t tlv);
|
||||
gpg_error_t _tlv_parser_next (tlv_parser_t tlv, int lno);
|
||||
|
||||
unsigned int tlv_parser_level (tlv_parser_t tlv);
|
||||
size_t tlv_parser_offset (tlv_parser_t tlv);
|
||||
const char *tlv_parser_lastfunc (tlv_parser_t tlv);
|
||||
const char *tlv_parser_lasterrstr (tlv_parser_t tlv);
|
||||
void tlv_parser_set_pending (tlv_parser_t tlv);
|
||||
size_t tlv_parser_tag_length (tlv_parser_t tlv, int with_header);
|
||||
|
||||
void tlv_parser_skip (tlv_parser_t tlv);
|
||||
|
||||
gpg_error_t tlv_expect_sequence (tlv_parser_t tlv);
|
||||
gpg_error_t tlv_expect_context_tag (tlv_parser_t tlv, int *r_tag);
|
||||
gpg_error_t tlv_expect_set (tlv_parser_t tlv);
|
||||
gpg_error_t tlv_expect_object (tlv_parser_t tlv, int class, int tag,
|
||||
unsigned char const **r_data,
|
||||
size_t *r_datalen);
|
||||
gpg_error_t tlv_expect_octet_string (tlv_parser_t tlv, int encapsulates,
|
||||
unsigned char const **r_data,
|
||||
size_t *r_datalen);
|
||||
gpg_error_t tlv_expect_integer (tlv_parser_t tlv, int *r_value);
|
||||
#ifdef GCRYPT_VERSION
|
||||
gpg_error_t tlv_expect_mpinteger (tlv_parser_t tlv, int ignore_zero,
|
||||
gcry_mpi_t *r_value);
|
||||
#endif
|
||||
gpg_error_t tlv_expect_object_id (tlv_parser_t tlv,
|
||||
unsigned char const **r_oid,
|
||||
size_t *r_oidlen);
|
||||
|
||||
/* Easier to use wrapper around parse_ber_header. */
|
||||
gpg_error_t tlv_parse_tag (unsigned char const **buffer,
|
||||
size_t *size, struct tag_info *ti);
|
||||
|
||||
/* Convenience macro and macros to include the line number. */
|
||||
#define tlv_parser_dump_tag(a,b) _tlv_parser_dump_tag ((a),__LINE__,(b))
|
||||
#define tlv_parser_dump_state(a,b,c) \
|
||||
_tlv_parser_dump_state ((a),(b),__LINE__,(c))
|
||||
#define tlv_peek(a,b,c) _tlv_parser_peek ((a),(b),(c))
|
||||
#define tlv_peek_null(a) _tlv_parser_peek_null ((a))
|
||||
#define tlv_next(a) _tlv_parser_next ((a), __LINE__)
|
||||
|
||||
|
||||
|
||||
#endif /* SCD_TLV_H */
|
||||
|
@ -39,6 +39,11 @@
|
||||
* libgpg-error version. Define them here.
|
||||
* Example: (#if GPG_ERROR_VERSION_NUMBER < 0x011500 // 1.21)
|
||||
*/
|
||||
#if GPG_ERROR_VERSION_NUMBER < 0x012f00 /* 1.47 */
|
||||
# define GPG_ERR_BAD_PUK 320
|
||||
# define GPG_ERR_NO_RESET_CODE 321
|
||||
# define GPG_ERR_BAD_RESET_CODE 322
|
||||
#endif
|
||||
|
||||
#ifndef EXTERN_UNLESS_MAIN_MODULE
|
||||
# if !defined (INCLUDED_BY_MAIN_MODULE)
|
||||
@ -143,6 +148,7 @@ ssize_t read_line (FILE *fp,
|
||||
char **addr_of_buffer, size_t *length_of_buffer,
|
||||
size_t *max_length);
|
||||
|
||||
|
||||
/*-- sexputil.c */
|
||||
char *canon_sexp_to_string (const unsigned char *canon, size_t canonlen);
|
||||
void log_printcanon (const char *text,
|
||||
@ -352,6 +358,10 @@ struct compatibility_flags_s
|
||||
int parse_compatibility_flags (const char *string, unsigned int *flagvar,
|
||||
const struct compatibility_flags_s *flags);
|
||||
|
||||
gpg_error_t b64decode (const char *string, const char *title,
|
||||
void **r_buffer, size_t *r_buflen);
|
||||
|
||||
|
||||
|
||||
/*-- Simple replacement functions. */
|
||||
|
||||
|
@ -67,13 +67,13 @@ NEED_KSBA_API=1
|
||||
NEED_KSBA_VERSION=1.6.3
|
||||
|
||||
NEED_NTBTLS_API=1
|
||||
NEED_NTBTLS_VERSION=0.1.0
|
||||
NEED_NTBTLS_VERSION=0.2.0
|
||||
|
||||
NEED_NPTH_API=1
|
||||
NEED_NPTH_VERSION=1.2
|
||||
|
||||
|
||||
NEED_GNUTLS_VERSION=3.0
|
||||
NEED_GNUTLS_VERSION=3.2
|
||||
|
||||
NEED_SQLITE_VERSION=3.27
|
||||
|
||||
|
@ -68,6 +68,7 @@ AM_CFLAGS = $(USE_C99_CFLAGS) \
|
||||
|
||||
if HAVE_W32_SYSTEM
|
||||
ldap_url = ldap-url.h ldap-url.c
|
||||
NETLIBS += -lwinhttp -lsecurity
|
||||
else
|
||||
ldap_url =
|
||||
endif
|
||||
|
@ -2046,6 +2046,7 @@ dirmngr_sighup_action (void)
|
||||
crl_cache_deinit ();
|
||||
cert_cache_init (hkp_cacert_filenames);
|
||||
crl_cache_init ();
|
||||
http_reinitialize ();
|
||||
reload_dns_stuff (0);
|
||||
ks_hkp_reload ();
|
||||
}
|
||||
|
@ -22,4 +22,6 @@
|
||||
|
||||
const char *get_default_keyserver (int name_only);
|
||||
|
||||
void http_reinitialize (void);
|
||||
|
||||
#endif /* HTTP_COMMON_H */
|
||||
|
1598
dirmngr/http.c
1598
dirmngr/http.c
File diff suppressed because it is too large
Load Diff
@ -132,9 +132,11 @@ typedef gpg_error_t (*http_verify_cb_t) (void *opaque,
|
||||
|
||||
void http_set_verbose (int verbose, int debug);
|
||||
|
||||
/* The next three functions are only used with GNUTLS. */
|
||||
void http_register_tls_callback (gpg_error_t (*cb)(http_t,http_session_t,int));
|
||||
void http_register_tls_ca (const char *fname);
|
||||
void http_register_cfg_ca (const char *fname);
|
||||
|
||||
void http_register_netactivity_cb (void (*cb)(void));
|
||||
|
||||
|
||||
@ -193,7 +195,7 @@ estream_t http_get_read_ptr (http_t hd);
|
||||
estream_t http_get_write_ptr (http_t hd);
|
||||
unsigned int http_get_status_code (http_t hd);
|
||||
const char *http_get_tls_info (http_t hd, const char *what);
|
||||
const char *http_get_header (http_t hd, const char *name);
|
||||
const char *http_get_header (http_t hd, const char *name, unsigned int skip);
|
||||
const char **http_get_header_names (http_t hd);
|
||||
gpg_error_t http_verify_server_credentials (http_session_t sess);
|
||||
|
||||
|
@ -1327,7 +1327,7 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
|
||||
{
|
||||
xfree (request_buffer);
|
||||
err = http_prepare_redirect (&redirinfo, http_get_status_code (http),
|
||||
http_get_header (http, "Location"),
|
||||
http_get_header (http, "Location", 0),
|
||||
&request_buffer);
|
||||
if (err)
|
||||
goto leave;
|
||||
@ -1340,18 +1340,17 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
|
||||
}
|
||||
goto once_more;
|
||||
|
||||
case 501:
|
||||
err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
||||
goto leave;
|
||||
|
||||
case 413: /* Payload too large */
|
||||
err = gpg_error (GPG_ERR_TOO_LARGE);
|
||||
goto leave;
|
||||
|
||||
default:
|
||||
log_error (_("error accessing '%s': http status %u\n"),
|
||||
request, http_get_status_code (http));
|
||||
err = gpg_error (GPG_ERR_NO_DATA);
|
||||
switch (http_get_status_code (http))
|
||||
{
|
||||
case 401: err = gpg_error (GPG_ERR_NO_AUTH); break;
|
||||
case 407: err = gpg_error (GPG_ERR_BAD_AUTH); break;
|
||||
case 413: err = gpg_error (GPG_ERR_TOO_LARGE); break;
|
||||
case 501: err = gpg_error (GPG_ERR_NOT_IMPLEMENTED); break;
|
||||
default: err = gpg_error (GPG_ERR_NO_DATA); break;
|
||||
}
|
||||
goto leave;
|
||||
}
|
||||
|
||||
|
@ -180,7 +180,7 @@ ks_http_fetch (ctrl_t ctrl, const char *url, unsigned int flags,
|
||||
{
|
||||
xfree (request_buffer);
|
||||
err = http_prepare_redirect (&redirinfo, http_get_status_code (http),
|
||||
http_get_header (http, "Location"),
|
||||
http_get_header (http, "Location", 0),
|
||||
&request_buffer);
|
||||
if (err)
|
||||
goto leave;
|
||||
@ -193,14 +193,16 @@ ks_http_fetch (ctrl_t ctrl, const char *url, unsigned int flags,
|
||||
}
|
||||
goto once_more;
|
||||
|
||||
case 413: /* Payload too large */
|
||||
err = gpg_error (GPG_ERR_TOO_LARGE);
|
||||
goto leave;
|
||||
|
||||
default:
|
||||
log_error (_("error accessing '%s': http status %u\n"),
|
||||
url, http_get_status_code (http));
|
||||
err = gpg_error (GPG_ERR_NO_DATA);
|
||||
switch (http_get_status_code (http))
|
||||
{
|
||||
case 401: err = gpg_error (GPG_ERR_NO_AUTH); break;
|
||||
case 407: err = gpg_error (GPG_ERR_BAD_AUTH); break;
|
||||
case 413: err = gpg_error (GPG_ERR_TOO_LARGE); break;
|
||||
default: err = gpg_error (GPG_ERR_NO_DATA); break;
|
||||
}
|
||||
goto leave;
|
||||
}
|
||||
|
||||
|
@ -380,13 +380,14 @@ rfc4517toisotime (gnupg_isotime_t timebuf, const char *string)
|
||||
int year, month, day, hour, minu, sec;
|
||||
const char *s;
|
||||
|
||||
/* Sample value: "20230823141623Z"; */
|
||||
for (i=0, s=string; i < 10; i++, s++) /* Need yyyymmddhh */
|
||||
if (!digitp (s))
|
||||
return gpg_error (GPG_ERR_INV_TIME);
|
||||
year = atoi_4 (string);
|
||||
month = atoi_2 (string + 4);
|
||||
day = atoi_2 (string + 6);
|
||||
hour = atoi_2 (string + 9);
|
||||
hour = atoi_2 (string + 8);
|
||||
minu = 0;
|
||||
sec = 0;
|
||||
if (digitp (s) && digitp (s+1))
|
||||
|
@ -227,7 +227,7 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp,
|
||||
case 301:
|
||||
case 302:
|
||||
{
|
||||
const char *s = http_get_header (http, "Location");
|
||||
const char *s = http_get_header (http, "Location", 0);
|
||||
|
||||
log_info (_("URL '%s' redirected to '%s' (%u)\n"),
|
||||
url, s?s:"[none]", http_get_status_code (http));
|
||||
|
@ -2202,6 +2202,7 @@ ensure_keyserver (ctrl_t ctrl)
|
||||
uri_item_t plain_items = NULL;
|
||||
uri_item_t ui;
|
||||
strlist_t sl;
|
||||
int none_seen = 1;
|
||||
|
||||
if (ctrl->server_local->keyservers)
|
||||
return 0; /* Already set for this session. */
|
||||
@ -2214,6 +2215,15 @@ ensure_keyserver (ctrl_t ctrl)
|
||||
|
||||
for (sl = opt.keyserver; sl; sl = sl->next)
|
||||
{
|
||||
/* Frontends like Kleopatra may prefix option values without a
|
||||
* scheme with "hkps://". Thus we need to check that too.
|
||||
* Nobody will be mad enough to call a machine "none". */
|
||||
if (!strcmp (sl->d, "none") || !strcmp (sl->d, "hkp://none")
|
||||
|| !strcmp (sl->d, "hkps://none"))
|
||||
{
|
||||
none_seen = 1;
|
||||
continue;
|
||||
}
|
||||
err = make_keyserver_item (sl->d, &item);
|
||||
if (err)
|
||||
goto leave;
|
||||
@ -2229,6 +2239,12 @@ ensure_keyserver (ctrl_t ctrl)
|
||||
}
|
||||
}
|
||||
|
||||
if (none_seen && !plain_items && !onion_items)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_NO_KEYSERVER);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Decide which to use. Note that the session has no keyservers
|
||||
yet set. */
|
||||
if (onion_items && !onion_items->next && plain_items && !plain_items->next)
|
||||
@ -2299,8 +2315,7 @@ cmd_keyserver (assuan_context_t ctx, char *line)
|
||||
gpg_error_t err = 0;
|
||||
int clear_flag, add_flag, help_flag, host_flag, resolve_flag;
|
||||
int dead_flag, alive_flag;
|
||||
uri_item_t item = NULL; /* gcc 4.4.5 is not able to detect that it
|
||||
is always initialized. */
|
||||
uri_item_t item = NULL;
|
||||
|
||||
clear_flag = has_option (line, "--clear");
|
||||
help_flag = has_option (line, "--help");
|
||||
@ -2366,13 +2381,17 @@ cmd_keyserver (assuan_context_t ctx, char *line)
|
||||
|
||||
if (add_flag)
|
||||
{
|
||||
if (!strcmp (line, "none") || !strcmp (line, "hkp://none")
|
||||
|| !strcmp (line, "hkps://none"))
|
||||
err = 0;
|
||||
else
|
||||
err = make_keyserver_item (line, &item);
|
||||
if (err)
|
||||
goto leave;
|
||||
}
|
||||
if (clear_flag)
|
||||
release_ctrl_keyservers (ctrl);
|
||||
if (add_flag)
|
||||
if (add_flag && item)
|
||||
{
|
||||
item->next = ctrl->server_local->keyservers;
|
||||
ctrl->server_local->keyservers = item;
|
||||
|
@ -288,6 +288,11 @@ main (int argc, char **argv)
|
||||
my_http_flags |= HTTP_FLAG_FORCE_TOR;
|
||||
argc--; argv++;
|
||||
}
|
||||
else if (!strcmp (*argv, "--try-proxy"))
|
||||
{
|
||||
my_http_flags |= HTTP_FLAG_TRY_PROXY;
|
||||
argc--; argv++;
|
||||
}
|
||||
else if (!strcmp (*argv, "--no-out"))
|
||||
{
|
||||
no_out = 1;
|
||||
@ -458,7 +463,7 @@ main (int argc, char **argv)
|
||||
log_fatal ("http_get_header_names failed: %s\n",
|
||||
gpg_strerror (gpg_error_from_syserror ()));
|
||||
for (i = 0; names[i]; i++)
|
||||
printf ("HDR: %s: %s\n", names[i], http_get_header (hd, names[i]));
|
||||
printf ("HDR: %s: %s\n", names[i], http_get_header (hd, names[i], 0));
|
||||
xfree (names);
|
||||
}
|
||||
fflush (stdout);
|
||||
@ -484,7 +489,7 @@ main (int argc, char **argv)
|
||||
case 301:
|
||||
case 302:
|
||||
case 307:
|
||||
log_info ("Redirected to: %s\n", http_get_header (hd, "Location"));
|
||||
log_info ("Redirected to: %s\n", http_get_header (hd, "Location", 0));
|
||||
break;
|
||||
}
|
||||
http_close (hd, 0);
|
||||
|
65
doc/ad-query-hints.org
Normal file
65
doc/ad-query-hints.org
Normal file
@ -0,0 +1,65 @@
|
||||
|
||||
|
||||
* Examples
|
||||
|
||||
** List the DNs of all users in our QAUsers group
|
||||
|
||||
: ad_query --subst --attr=dn
|
||||
: ^OU=QAUsers,$domain&sub&(&(objectcategory=person)(objectclass=user))
|
||||
|
||||
** List the DN using the user's mail address
|
||||
|
||||
: ad_query --subst --attr=dn,userAccountControl
|
||||
: (&(objectcategory=person)(objectclass=user)
|
||||
: (|(userPrincipalName=dd9jn@w32demo.g10code.de)
|
||||
: (mail=dd9jn@w32demo.g10code.de)))
|
||||
|
||||
After that the userControlFlags should be checked - see below for
|
||||
the bit flags. For a non-disabled user use:
|
||||
|
||||
: if ((userControlFlags & 0x0212) == 0x200))
|
||||
: use_this_user()
|
||||
|
||||
|
||||
* Useful attributes
|
||||
|
||||
** userAccountControl
|
||||
|
||||
These are bit flags. For details see
|
||||
https://learn.microsoft.com/en-us/windows/win32/api/iads/ne-iads-ads_user_flag_enum
|
||||
|
||||
- 0x00000002 :: ADS_UF_ACCOUNTDISABLE, the account is disabled.
|
||||
- 0x00000010 :: ADS_UF_LOCKOUT, the account is temporarily locked out.
|
||||
- 0x00000100 :: ADS_UF_TEMP_DUPLICATE_ACCOUNT, this is an account for
|
||||
a user whose primary account is in another domain.
|
||||
- 0x00000200 :: ADS_UF_NORMAL_ACCOUNT, the default account type that
|
||||
represents a typical user.
|
||||
- 0x00000800 :: ADS_UF_INTERDOMAIN_TRUST_ACCOUNT, the account for a
|
||||
domain-to-domain trust.
|
||||
- 0x00001000 :: ADS_UF_WORKSTATION_ACCOUNT, the computer account for a
|
||||
computer that is a member of this domain.
|
||||
- 0x00002000 :: ADS_UF_SERVER_TRUST_ACCOUNT, the computer account for
|
||||
a DC.
|
||||
- 0x00010000 :: ADS_UF_DONT_EXPIRE_PASSWD, the password will not expire.
|
||||
- 0x04000000 :: ADS_UF_PARTIAL_SECRETS_ACCOUNT, the computer account
|
||||
for an RODC.
|
||||
|
||||
For example to select only user accounts which are not disabled or
|
||||
are locked out could naivly be used:
|
||||
|
||||
: (userAccountControl:1.2.840.113556.1.4.803:=512)
|
||||
|
||||
1.2.840.113556.1.4.803 is bit wise AND, 1.2.840.113556.1.4.804 is bit
|
||||
wise OR. However, because a mask can't be specified, this is not really
|
||||
useful. Thus the above needs to be replaced by explicit checks; i.e.
|
||||
|
||||
: (&(userAccountControl:1.2.840.113556.1.4.804:=512)
|
||||
: (!(userAccountControl:1.2.840.113556.1.4.804:=2))
|
||||
: (!(userAccountControl:1.2.840.113556.1.4.804:=16)))
|
||||
|
||||
I'd suggest to also add explict checks on the returned data.
|
||||
|
||||
|
||||
* Resources
|
||||
|
||||
- https://qa.social.technet.microsoft.com/wiki/contents/articles/5392.active-directory-ldap-syntax-filters.aspx
|
@ -180,7 +180,7 @@ available flags the sole word "help" can be used.
|
||||
This option is only useful for testing; it sets the system time back or
|
||||
forth to @var{epoch} which is the number of seconds elapsed since the year
|
||||
1970. Alternatively @var{epoch} may be given as a full ISO time string
|
||||
(e.g., "20070924T154812").
|
||||
(e.g. "20070924T154812").
|
||||
|
||||
@item --debug-level @var{level}
|
||||
@opindex debug-level
|
||||
@ -344,7 +344,8 @@ whether Tor is locally running or not. The check for a running Tor is
|
||||
done for each new connection.
|
||||
|
||||
If no keyserver is explicitly configured, dirmngr will use the
|
||||
built-in default of @code{https://keyserver.ubuntu.com}.
|
||||
built-in default of @code{https://keyserver.ubuntu.com}. To avoid the
|
||||
use of a default keyserver the value @code{none} can be used.
|
||||
|
||||
Windows users with a keyserver running on their Active Directory
|
||||
may use the short form @code{ldap:///} for @var{name} to access this directory.
|
||||
@ -426,7 +427,9 @@ force the use of the default responder.
|
||||
@item --honor-http-proxy
|
||||
@opindex honor-http-proxy
|
||||
If the environment variable @env{http_proxy} has been set, use its
|
||||
value to access HTTP servers.
|
||||
value to access HTTP servers. If on Windows the option is used but
|
||||
the environment variable is not set, the proxy settings are taken
|
||||
from the system.
|
||||
|
||||
@item --http-proxy @var{host}[:@var{port}]
|
||||
@opindex http-proxy
|
||||
|
@ -2715,6 +2715,12 @@ The available properties are:
|
||||
second is the same but given as an ISO date string,
|
||||
e.g., "2016-08-17". (drop-sig)
|
||||
|
||||
@item sig_expires
|
||||
@itemx sig_expires_d
|
||||
The expiration time of a signature packet or 0 if it does not
|
||||
expire. The second is the same but given as an ISO date string or
|
||||
an empty string e.g. "2038-01-19".
|
||||
|
||||
@item sig_algo
|
||||
A number with the public key algorithm of a signature packet. (drop-sig)
|
||||
|
||||
|
@ -732,6 +732,13 @@ instead to make sure that the gpgsm process exits with a failure if
|
||||
the compliance rules are not fulfilled. Note that this option has
|
||||
currently an effect only in "de-vs" mode.
|
||||
|
||||
@item --always-trust
|
||||
@opindex always-trust
|
||||
Force encryption to the specified certificates without any validation
|
||||
of the certificate chain. The only requirement is that the
|
||||
certificate is capable of encryption. Note that this option is
|
||||
ineffective if @option{--require-compliance} is used.
|
||||
|
||||
@item --ignore-cert-with-oid @var{oid}
|
||||
@opindex ignore-cert-with-oid
|
||||
Add @var{oid} to the list of OIDs to be checked while reading
|
||||
@ -1621,6 +1628,10 @@ The leading two dashes usually used with @var{opt} shall not be given.
|
||||
Return OK if the connection is in offline mode. This may be either
|
||||
due to a @code{OPTION offline=1} or due to @command{gpgsm} being
|
||||
started with option @option{--disable-dirmngr}.
|
||||
@item always-trust
|
||||
Returns OK of the connection is in always-trust mode. That is either
|
||||
@option{--always-trust} or @option{GPGSM OPTION always-trust} are
|
||||
active.
|
||||
@end table
|
||||
|
||||
@node GPGSM OPTION
|
||||
@ -1727,6 +1738,15 @@ If @var{value} is true or @var{value} is not given all network access
|
||||
is disabled for this session. This is the same as the command line
|
||||
option @option{--disable-dirmngr}.
|
||||
|
||||
@item always-trust
|
||||
If @var{value} is true or @var{value} is not given encryption to the
|
||||
specified certificates is forced without any validation of the
|
||||
certificate chain. The only requirement is that the certificates are
|
||||
capable of encryption. If set to false the standard behaviour is
|
||||
re-established. This option is cleared by a RESET and after each
|
||||
encrypt operation. Note that this option is ignored if
|
||||
@option{--always-trust} or @option{--require-compliance} are used.
|
||||
|
||||
@item input-size-hint
|
||||
This is the same as the @option{--input-size-hint} command line option.
|
||||
|
||||
|
@ -130,6 +130,7 @@ status_sc_op_failure (int rc)
|
||||
write_status_text (STATUS_SC_OP_FAILURE, "1");
|
||||
break;
|
||||
case GPG_ERR_BAD_PIN:
|
||||
case GPG_ERR_BAD_RESET_CODE:
|
||||
write_status_text (STATUS_SC_OP_FAILURE, "2");
|
||||
break;
|
||||
default:
|
||||
|
@ -56,6 +56,7 @@ write_sc_op_status (gpg_error_t err)
|
||||
write_status_text (STATUS_SC_OP_FAILURE, "1");
|
||||
break;
|
||||
case GPG_ERR_BAD_PIN:
|
||||
case GPG_ERR_BAD_RESET_CODE:
|
||||
write_status_text (STATUS_SC_OP_FAILURE, "2");
|
||||
break;
|
||||
default:
|
||||
|
@ -3486,7 +3486,7 @@ main (int argc, char **argv)
|
||||
break;
|
||||
case oUtf8Strings: utf8_strings = 1; break;
|
||||
case oNoUtf8Strings:
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
#ifndef HAVE_W32_SYSTEM
|
||||
utf8_strings = 0;
|
||||
#endif
|
||||
break;
|
||||
|
14
g10/import.c
14
g10/import.c
@ -1509,6 +1509,20 @@ impex_filter_getval (void *cookie, const char *propname)
|
||||
{
|
||||
result = dateonlystr_from_sig (sig);
|
||||
}
|
||||
else if (!strcmp (propname, "sig_expires"))
|
||||
{
|
||||
snprintf (numbuf, sizeof numbuf, "%lu", (ulong)sig->expiredate);
|
||||
result = numbuf;
|
||||
}
|
||||
else if (!strcmp (propname, "sig_expires_d"))
|
||||
{
|
||||
static char exdatestr[MK_DATESTR_SIZE];
|
||||
|
||||
if (sig->expiredate)
|
||||
result = mk_datestr (exdatestr, sizeof exdatestr, sig->expiredate);
|
||||
else
|
||||
result = "";
|
||||
}
|
||||
else if (!strcmp (propname, "sig_algo"))
|
||||
{
|
||||
snprintf (numbuf, sizeof numbuf, "%d", sig->pubkey_algo);
|
||||
|
41
g10/keygen.c
41
g10/keygen.c
@ -2748,6 +2748,7 @@ parse_expire_string_with_ct (const char *string, u32 creation_time)
|
||||
u32 seconds;
|
||||
u32 abs_date = 0;
|
||||
time_t tt;
|
||||
uint64_t tmp64;
|
||||
u32 curtime;
|
||||
|
||||
if (creation_time == (u32)-1)
|
||||
@ -2759,14 +2760,26 @@ parse_expire_string_with_ct (const char *string, u32 creation_time)
|
||||
|| !strcmp (string, "never") || !strcmp (string, "-"))
|
||||
seconds = 0;
|
||||
else if (!strncmp (string, "seconds=", 8))
|
||||
seconds = atoi (string+8);
|
||||
seconds = scan_secondsstr (string+8);
|
||||
else if ((abs_date = scan_isodatestr(string))
|
||||
&& (abs_date+86400/2) > curtime)
|
||||
seconds = (abs_date+86400/2) - curtime;
|
||||
else if ((tt = isotime2epoch (string)) != (time_t)(-1))
|
||||
seconds = (u32)tt - curtime;
|
||||
else if ((tt = isotime2epoch_u64 (string)) != (uint64_t)(-1))
|
||||
{
|
||||
tmp64 = tt - curtime;
|
||||
if (tmp64 >= (u32)(-1))
|
||||
seconds = (u32)(-1) - 1; /* cap value. */
|
||||
else
|
||||
seconds = (u32)tmp64;
|
||||
}
|
||||
else if ((mult = check_valid_days (string)))
|
||||
seconds = atoi (string) * 86400L * mult;
|
||||
{
|
||||
tmp64 = scan_secondsstr (string) * 86400L * mult;
|
||||
if (tmp64 >= (u32)(-1))
|
||||
seconds = (u32)(-1) - 1; /* cap value. */
|
||||
else
|
||||
seconds = (u32)tmp64;
|
||||
}
|
||||
else
|
||||
seconds = (u32)(-1);
|
||||
|
||||
@ -2790,11 +2803,16 @@ parse_creation_string (const char *string)
|
||||
if (!*string)
|
||||
seconds = 0;
|
||||
else if ( !strncmp (string, "seconds=", 8) )
|
||||
seconds = atoi (string+8);
|
||||
seconds = scan_secondsstr (string+8);
|
||||
else if ( !(seconds = scan_isodatestr (string)))
|
||||
{
|
||||
time_t tmp = isotime2epoch (string);
|
||||
seconds = (tmp == (time_t)(-1))? 0 : tmp;
|
||||
uint64_t tmp = isotime2epoch_u64 (string);
|
||||
if (tmp == (uint64_t)(-1))
|
||||
seconds = 0;
|
||||
else if (tmp > (u32)(-1))
|
||||
seconds = 0;
|
||||
else
|
||||
seconds = tmp;
|
||||
}
|
||||
return seconds;
|
||||
}
|
||||
@ -5395,17 +5413,26 @@ card_store_key_with_backup (ctrl_t ctrl, PKT_public_key *sub_psk,
|
||||
{
|
||||
ecdh_param_str = ecdh_param_str_from_pk (sk);
|
||||
if (!ecdh_param_str)
|
||||
{
|
||||
free_public_key (sk);
|
||||
return gpg_error_from_syserror ();
|
||||
}
|
||||
}
|
||||
|
||||
err = hexkeygrip_from_pk (sk, &hexgrip);
|
||||
if (err)
|
||||
{
|
||||
xfree (ecdh_param_str);
|
||||
free_public_key (sk);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
memset(&info, 0, sizeof (info));
|
||||
rc = agent_scd_getattr ("SERIALNO", &info);
|
||||
if (rc)
|
||||
{
|
||||
xfree (ecdh_param_str);
|
||||
free_public_key (sk);
|
||||
err = (gpg_error_t)rc;
|
||||
goto leave;
|
||||
}
|
||||
|
@ -983,6 +983,7 @@ update_min_ownertrust (ctrl_t ctrl, u32 *kid, unsigned int new_trust)
|
||||
|
||||
/*
|
||||
* Clear the ownertrust and min_ownertrust values.
|
||||
* Also schedule a revalidation if a stale validity record exists.
|
||||
*
|
||||
* Return: True if a change actually happened.
|
||||
*/
|
||||
@ -1016,6 +1017,26 @@ tdb_clear_ownertrusts (ctrl_t ctrl, PKT_public_key *pk)
|
||||
do_sync ();
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check whether we have a stale RECTYPE_VALID for that key
|
||||
* and if its validity ist set, schedule a revalidation. */
|
||||
ulong recno = rec.r.trust.validlist;
|
||||
while (recno)
|
||||
{
|
||||
read_record (recno, &rec, RECTYPE_VALID);
|
||||
if (rec.r.valid.validity)
|
||||
break;
|
||||
recno = rec.r.valid.next;
|
||||
}
|
||||
if (recno)
|
||||
{
|
||||
if (DBG_TRUST)
|
||||
log_debug ("stale validity value detected"
|
||||
" - scheduling check\n");
|
||||
tdb_revalidation_mark (ctrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (gpg_err_code (err) != GPG_ERR_NOT_FOUND)
|
||||
{
|
||||
|
@ -23,6 +23,9 @@ AC_DEFUN([AB_INIT],
|
||||
if test "$hostname"; then
|
||||
AC_MSG_NOTICE([autobuild hostname... $hostname])
|
||||
fi
|
||||
if test "$EMAIL"; then
|
||||
AC_MSG_NOTICE([autobuild username... $EMAIL])
|
||||
fi
|
||||
ifelse([$1],[],,[AC_MSG_NOTICE([autobuild mode... $1])])
|
||||
date=`date +%Y%m%d-%H%M%S`
|
||||
if test "$?" != 0; then
|
||||
|
@ -3453,7 +3453,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
|
||||
if (!remaining)
|
||||
{
|
||||
log_error (_("Reset Code not or not anymore available\n"));
|
||||
rc = gpg_error (GPG_ERR_BAD_PIN);
|
||||
rc = gpg_error (GPG_ERR_NO_RESET_CODE);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
@ -3470,7 +3470,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
|
||||
{
|
||||
log_info (_("Reset Code is too short; minimum length is %d\n"),
|
||||
minlen);
|
||||
rc = gpg_error (GPG_ERR_BAD_PIN);
|
||||
rc = gpg_error (GPG_ERR_BAD_RESET_CODE);
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
@ -3538,7 +3538,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
|
||||
if (bufferlen != 0 && bufferlen < 8)
|
||||
{
|
||||
log_error (_("Reset Code is too short; minimum length is %d\n"), 8);
|
||||
rc = gpg_error (GPG_ERR_BAD_PIN);
|
||||
rc = gpg_error (GPG_ERR_BAD_RESET_CODE);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2199,6 +2199,12 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime,
|
||||
|
||||
memset (&rootca_flags, 0, sizeof rootca_flags);
|
||||
|
||||
if ((flags & VALIDATE_FLAG_BYPASS))
|
||||
{
|
||||
*retflags |= VALIDATE_FLAG_BYPASS;
|
||||
rc = 0;
|
||||
}
|
||||
else
|
||||
rc = do_validate_chain (ctrl, cert, checktime,
|
||||
r_exptime, listmode, listfp, flags,
|
||||
&rootca_flags);
|
||||
@ -2223,6 +2229,8 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime,
|
||||
|
||||
if (opt.verbose)
|
||||
do_list (0, listmode, listfp, _("validation model used: %s"),
|
||||
(*retflags & VALIDATE_FLAG_BYPASS)?
|
||||
"bypass" :
|
||||
(*retflags & VALIDATE_FLAG_STEED)?
|
||||
"steed" :
|
||||
(*retflags & VALIDATE_FLAG_CHAIN_MODEL)?
|
||||
|
@ -448,6 +448,11 @@ gpgsm_add_to_certlist (ctrl_t ctrl, const char *name, int secret,
|
||||
|
||||
if (!rc && !is_cert_in_certlist (cert, *listaddr))
|
||||
{
|
||||
unsigned int valflags = 0;
|
||||
|
||||
if (!secret && (opt.always_trust || ctrl->always_trust))
|
||||
valflags |= VALIDATE_FLAG_BYPASS;
|
||||
|
||||
if (!rc && secret)
|
||||
{
|
||||
char *p;
|
||||
@ -461,9 +466,10 @@ gpgsm_add_to_certlist (ctrl_t ctrl, const char *name, int secret,
|
||||
xfree (p);
|
||||
}
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
rc = gpgsm_validate_chain (ctrl, cert, GNUPG_ISOTIME_NONE, NULL,
|
||||
0, NULL, 0, NULL);
|
||||
0, NULL, valflags, NULL);
|
||||
if (!rc)
|
||||
{
|
||||
certlist_t cl = xtrycalloc (1, sizeof *cl);
|
||||
|
@ -1064,6 +1064,7 @@ gpgsm_decrypt (ctrl_t ctrl, estream_t in_fp, estream_t out_fp)
|
||||
KEYDB_HANDLE kh;
|
||||
int recp;
|
||||
struct decrypt_filter_parm_s dfparm;
|
||||
char *curve = NULL;
|
||||
|
||||
memset (&dfparm, 0, sizeof dfparm);
|
||||
|
||||
@ -1300,14 +1301,15 @@ gpgsm_decrypt (ctrl_t ctrl, estream_t in_fp, estream_t out_fp)
|
||||
|
||||
pkfpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
|
||||
pkalgostr = gpgsm_pubkey_algo_string (cert, NULL);
|
||||
pk_algo = gpgsm_get_key_algo_info (cert, &nbits);
|
||||
xfree (curve);
|
||||
pk_algo = gpgsm_get_key_algo_info (cert, &nbits, &curve);
|
||||
if (!opt.quiet)
|
||||
log_info (_("encrypted to %s key %s\n"), pkalgostr, pkfpr);
|
||||
|
||||
/* Check compliance. */
|
||||
if (!gnupg_pk_is_allowed (opt.compliance,
|
||||
PK_USE_DECRYPTION,
|
||||
pk_algo, 0, NULL, nbits, NULL))
|
||||
pk_algo, 0, NULL, nbits, curve))
|
||||
{
|
||||
char kidstr[10+1];
|
||||
|
||||
@ -1325,7 +1327,7 @@ gpgsm_decrypt (ctrl_t ctrl, estream_t in_fp, estream_t out_fp)
|
||||
dfparm.is_de_vs =
|
||||
(dfparm.is_de_vs
|
||||
&& gnupg_pk_is_compliant (CO_DE_VS, pk_algo, 0,
|
||||
NULL, nbits, NULL));
|
||||
NULL, nbits, curve));
|
||||
|
||||
oops:
|
||||
if (rc)
|
||||
@ -1503,6 +1505,7 @@ gpgsm_decrypt (ctrl_t ctrl, estream_t in_fp, estream_t out_fp)
|
||||
log_error ("message decryption failed: %s <%s>\n",
|
||||
gpg_strerror (rc), gpg_strsource (rc));
|
||||
}
|
||||
xfree (curve);
|
||||
ksba_cms_release (cms);
|
||||
gnupg_ksba_destroy_reader (b64reader);
|
||||
gnupg_ksba_destroy_writer (b64writer);
|
||||
|
10
sm/encrypt.c
10
sm/encrypt.c
@ -749,11 +749,12 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
|
||||
unsigned char *encval;
|
||||
unsigned int nbits;
|
||||
int pk_algo;
|
||||
char *curve = NULL;
|
||||
|
||||
/* Check compliance. */
|
||||
pk_algo = gpgsm_get_key_algo_info (cl->cert, &nbits);
|
||||
pk_algo = gpgsm_get_key_algo_info (cl->cert, &nbits, &curve);
|
||||
if (!gnupg_pk_is_compliant (opt.compliance, pk_algo, 0,
|
||||
NULL, nbits, NULL))
|
||||
NULL, nbits, curve))
|
||||
{
|
||||
char kidstr[10+1];
|
||||
|
||||
@ -768,9 +769,12 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
|
||||
/* Fixme: When adding ECC we need to provide the curvename and
|
||||
* the key to gnupg_pk_is_compliant. */
|
||||
if (compliant
|
||||
&& !gnupg_pk_is_compliant (CO_DE_VS, pk_algo, 0, NULL, nbits, NULL))
|
||||
&& !gnupg_pk_is_compliant (CO_DE_VS, pk_algo, 0, NULL, nbits, curve))
|
||||
compliant = 0;
|
||||
|
||||
xfree (curve);
|
||||
curve = NULL;
|
||||
|
||||
rc = encrypt_dek (dek, cl->cert, pk_algo, &encval);
|
||||
if (rc)
|
||||
{
|
||||
|
@ -430,7 +430,7 @@ gpgsm_p12_export (ctrl_t ctrl, const char *name, estream_t stream, int rawmode)
|
||||
|
||||
if (rawmode == 0)
|
||||
ctrl->pem_name = "PKCS12";
|
||||
else if (gpgsm_get_key_algo_info (cert, NULL) == GCRY_PK_ECC)
|
||||
else if (gpgsm_get_key_algo_info (cert, NULL, NULL) == GCRY_PK_ECC)
|
||||
ctrl->pem_name = "EC PRIVATE KEY";
|
||||
else if (rawmode == 1)
|
||||
ctrl->pem_name = "PRIVATE KEY";
|
||||
|
@ -222,7 +222,7 @@ gpgsm_get_keygrip_hexstring (ksba_cert_t cert)
|
||||
* algorithm is used the name or OID of the curve is stored there; the
|
||||
* caller needs to free this value. */
|
||||
int
|
||||
gpgsm_get_key_algo_info2 (ksba_cert_t cert, unsigned int *nbits, char **r_curve)
|
||||
gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits, char **r_curve)
|
||||
{
|
||||
gcry_sexp_t s_pkey;
|
||||
int rc;
|
||||
@ -299,18 +299,11 @@ gpgsm_get_key_algo_info2 (ksba_cert_t cert, unsigned int *nbits, char **r_curve)
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits)
|
||||
{
|
||||
return gpgsm_get_key_algo_info2 (cert, nbits, NULL);
|
||||
}
|
||||
|
||||
|
||||
/* Return true if CERT is an ECC key. */
|
||||
int
|
||||
gpgsm_is_ecc_key (ksba_cert_t cert)
|
||||
{
|
||||
return GCRY_PK_ECC == gpgsm_get_key_algo_info2 (cert, NULL, NULL);
|
||||
return GCRY_PK_ECC == gpgsm_get_key_algo_info (cert, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
13
sm/gpgsm.c
13
sm/gpgsm.c
@ -215,6 +215,7 @@ enum cmd_and_opt_values {
|
||||
oRequireCompliance,
|
||||
oCompatibilityFlags,
|
||||
oKbxBufferSize,
|
||||
oAlwaysTrust,
|
||||
oNoAutostart
|
||||
};
|
||||
|
||||
@ -417,6 +418,7 @@ static gpgrt_opt_t opts[] = {
|
||||
ARGPARSE_s_n (oIgnoreTimeConflict, "ignore-time-conflict", "@"),
|
||||
ARGPARSE_s_n (oNoRandomSeedFile, "no-random-seed-file", "@"),
|
||||
ARGPARSE_s_n (oRequireCompliance, "require-compliance", "@"),
|
||||
ARGPARSE_s_n (oAlwaysTrust, "always-trust", "@"),
|
||||
|
||||
ARGPARSE_header (NULL, N_("Options for unattended use")),
|
||||
|
||||
@ -1494,6 +1496,7 @@ main ( int argc, char **argv)
|
||||
case oMinRSALength: opt.min_rsa_length = pargs.r.ret_ulong; break;
|
||||
|
||||
case oRequireCompliance: opt.require_compliance = 1; break;
|
||||
case oAlwaysTrust: opt.always_trust = 1; break;
|
||||
|
||||
case oKbxBufferSize:
|
||||
keybox_set_buffersize (pargs.r.ret_ulong, 0);
|
||||
@ -1583,10 +1586,20 @@ main ( int argc, char **argv)
|
||||
if (may_coredump && !opt.quiet)
|
||||
log_info (_("WARNING: program may create a core file!\n"));
|
||||
|
||||
if (opt.require_compliance && opt.always_trust)
|
||||
{
|
||||
opt.always_trust = 0;
|
||||
if (opt.quiet)
|
||||
log_info (_("WARNING: %s overrides %s\n"),
|
||||
"--require-compliance","--always-trust");
|
||||
}
|
||||
|
||||
|
||||
npth_init ();
|
||||
gpgrt_set_syscall_clamp (npth_unprotect, npth_protect);
|
||||
assuan_control (ASSUAN_CONTROL_REINIT_SYSCALL_CLAMP, NULL);
|
||||
|
||||
|
||||
/* if (opt.qualsig_approval && !opt.quiet) */
|
||||
/* log_info (_("This software has officially been approved to " */
|
||||
/* "create and verify\n" */
|
||||
|
13
sm/gpgsm.h
13
sm/gpgsm.h
@ -116,8 +116,6 @@ struct
|
||||
int extra_digest_algo; /* A digest algorithm also used for
|
||||
verification of signatures. */
|
||||
|
||||
int always_trust; /* Trust the given keys even if there is no
|
||||
valid certification chain */
|
||||
int skip_verify; /* do not check signatures on data */
|
||||
|
||||
int lock_once; /* Keep lock once they are set */
|
||||
@ -164,6 +162,10 @@ struct
|
||||
* mode. */
|
||||
int require_compliance;
|
||||
|
||||
/* Enable always-trust mode - note that there is also server option
|
||||
* for this. */
|
||||
int always_trust;
|
||||
|
||||
/* Enable creation of authenticode signatures. */
|
||||
int authenticode;
|
||||
|
||||
@ -269,6 +271,9 @@ struct server_control_s
|
||||
2 := STEED model. */
|
||||
int offline; /* If true gpgsm won't do any network access. */
|
||||
|
||||
int always_trust; /* True in always-trust mode; see also
|
||||
* opt.always-trust. */
|
||||
|
||||
/* The current time. Used as a helper in certchain.c. */
|
||||
ksba_isotime_t current_time;
|
||||
|
||||
@ -334,8 +339,7 @@ unsigned long gpgsm_get_short_fingerprint (ksba_cert_t cert,
|
||||
unsigned long *r_high);
|
||||
unsigned char *gpgsm_get_keygrip (ksba_cert_t cert, unsigned char *array);
|
||||
char *gpgsm_get_keygrip_hexstring (ksba_cert_t cert);
|
||||
int gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits);
|
||||
int gpgsm_get_key_algo_info2 (ksba_cert_t cert, unsigned int *nbits,
|
||||
int gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits,
|
||||
char **r_curve);
|
||||
int gpgsm_is_ecc_key (ksba_cert_t cert);
|
||||
char *gpgsm_pubkey_algo_string (ksba_cert_t cert, int *r_algoid);
|
||||
@ -388,6 +392,7 @@ int gpgsm_create_cms_signature (ctrl_t ctrl,
|
||||
#define VALIDATE_FLAG_NO_DIRMNGR 1
|
||||
#define VALIDATE_FLAG_CHAIN_MODEL 2
|
||||
#define VALIDATE_FLAG_STEED 4
|
||||
#define VALIDATE_FLAG_BYPASS 8 /* No actual validation. */
|
||||
|
||||
gpg_error_t gpgsm_walk_cert_chain (ctrl_t ctrl,
|
||||
ksba_cert_t start, ksba_cert_t *r_next);
|
||||
|
12
sm/keylist.c
12
sm/keylist.c
@ -54,7 +54,7 @@ struct list_external_parm_s
|
||||
#define OID_FLAG_SKIP 1
|
||||
/* The extension is a simple UTF8String and should be printed. */
|
||||
#define OID_FLAG_UTF8 2
|
||||
/* The extension can be trnted as a hex string. */
|
||||
/* The extension can be printed as a hex string. */
|
||||
#define OID_FLAG_HEX 4
|
||||
/* Define if this specififies a key purpose. */
|
||||
#define OID_FLAG_KP 8
|
||||
@ -208,6 +208,8 @@ static struct
|
||||
{ "1.3.6.1.4.1.311.21.6", "ms-keyRecovery", OID_FLAG_KP },
|
||||
{ "1.3.6.1.4.1.311.21.19", "ms-dsEmailReplication", OID_FLAG_KP },
|
||||
|
||||
/* BSI policies. */
|
||||
|
||||
/* Other vendor extensions. */
|
||||
{ "1.3.6.1.4.1.30205.13.1.1", "trusted-disk", OID_FLAG_KP },
|
||||
{ "1.2.840.113583.1.1.5", "pdfAuthenticDocumentsTrust", OID_FLAG_KP },
|
||||
@ -428,7 +430,7 @@ email_kludge (const char *name)
|
||||
* number. NBITS is the length of the key in bits. */
|
||||
static void
|
||||
print_compliance_flags (ksba_cert_t cert, int algo, unsigned int nbits,
|
||||
estream_t fp)
|
||||
const char *curvename, estream_t fp)
|
||||
{
|
||||
int indent = 0;
|
||||
int hashalgo;
|
||||
@ -436,7 +438,7 @@ print_compliance_flags (ksba_cert_t cert, int algo, unsigned int nbits,
|
||||
/* Note that we do not need to test for PK_ALGO_FLAG_RSAPSS because
|
||||
* that is not a property of the key but one of the created
|
||||
* signature. */
|
||||
if (gnupg_pk_is_compliant (CO_DE_VS, algo, 0, NULL, nbits, NULL))
|
||||
if (gnupg_pk_is_compliant (CO_DE_VS, algo, 0, NULL, nbits, curvename))
|
||||
{
|
||||
hashalgo = gcry_md_map_name (ksba_cert_get_digest_algo (cert));
|
||||
if (gnupg_digest_is_compliant (CO_DE_VS, hashalgo))
|
||||
@ -560,7 +562,7 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
|
||||
if (*truststring)
|
||||
es_fputs (truststring, fp);
|
||||
|
||||
algo = gpgsm_get_key_algo_info2 (cert, &nbits, &curve);
|
||||
algo = gpgsm_get_key_algo_info (cert, &nbits, &curve);
|
||||
es_fprintf (fp, ":%u:%d:%s:", nbits, algo, fpr+24);
|
||||
|
||||
ksba_cert_get_validity (cert, 0, t);
|
||||
@ -627,7 +629,7 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
|
||||
if (curve)
|
||||
es_fputs (curve, fp);
|
||||
es_putc (':', fp); /* End of field 17. */
|
||||
print_compliance_flags (cert, algo, nbits, fp);
|
||||
print_compliance_flags (cert, algo, nbits, curve, fp);
|
||||
es_putc (':', fp); /* End of field 18. */
|
||||
es_putc ('\n', fp);
|
||||
|
||||
|
1022
sm/minip12.c
1022
sm/minip12.c
File diff suppressed because it is too large
Load Diff
21
sm/server.c
21
sm/server.c
@ -287,6 +287,17 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
|
||||
ctrl->offline = i;
|
||||
}
|
||||
}
|
||||
else if (!strcmp (key, "always-trust"))
|
||||
{
|
||||
/* We ignore this option if gpgsm has been started with
|
||||
--always-trust (which also sets offline) and if
|
||||
--require-compliance is active */
|
||||
if (!opt.always_trust && !opt.require_compliance)
|
||||
{
|
||||
int i = *value? !!atoi (value) : 1;
|
||||
ctrl->always_trust = i;
|
||||
}
|
||||
}
|
||||
else if (!strcmp (key, "request-origin"))
|
||||
{
|
||||
if (!opt.request_origin)
|
||||
@ -320,6 +331,7 @@ reset_notify (assuan_context_t ctx, char *line)
|
||||
gpgsm_release_certlist (ctrl->server_local->signerlist);
|
||||
ctrl->server_local->recplist = NULL;
|
||||
ctrl->server_local->signerlist = NULL;
|
||||
ctrl->always_trust = 0;
|
||||
close_message_fp (ctrl);
|
||||
assuan_close_input_fd (ctx);
|
||||
assuan_close_output_fd (ctx);
|
||||
@ -495,6 +507,7 @@ cmd_encrypt (assuan_context_t ctx, char *line)
|
||||
|
||||
gpgsm_release_certlist (ctrl->server_local->recplist);
|
||||
ctrl->server_local->recplist = NULL;
|
||||
ctrl->always_trust = 0;
|
||||
/* Close and reset the fp and the fds */
|
||||
close_message_fp (ctrl);
|
||||
assuan_close_input_fd (ctx);
|
||||
@ -1221,7 +1234,8 @@ static const char hlp_getinfo[] =
|
||||
" agent-check - Return success if the agent is running.\n"
|
||||
" cmd_has_option CMD OPT\n"
|
||||
" - Returns OK if the command CMD implements the option OPT.\n"
|
||||
" offline - Returns OK if the connection is in offline mode.";
|
||||
" offline - Returns OK if the connection is in offline mode."
|
||||
" always-trust- Returns OK if the connection is in always-trust mode.";
|
||||
static gpg_error_t
|
||||
cmd_getinfo (assuan_context_t ctx, char *line)
|
||||
{
|
||||
@ -1280,6 +1294,11 @@ cmd_getinfo (assuan_context_t ctx, char *line)
|
||||
{
|
||||
rc = ctrl->offline? 0 : gpg_error (GPG_ERR_FALSE);
|
||||
}
|
||||
else if (!strcmp (line, "always-trust"))
|
||||
{
|
||||
rc = (ctrl->always_trust || opt.always_trust)? 0
|
||||
/**/ : gpg_error (GPG_ERR_FALSE);
|
||||
}
|
||||
else
|
||||
rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
|
||||
|
||||
|
@ -622,6 +622,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
||||
certlist_t cl;
|
||||
int release_signerlist = 0;
|
||||
int binary_detached = detached && !ctrl->create_pem && !ctrl->create_base64;
|
||||
char *curve = NULL;
|
||||
|
||||
audit_set_type (ctrl->audit, AUDIT_TYPE_SIGN);
|
||||
|
||||
@ -760,7 +761,8 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
||||
unsigned int nbits;
|
||||
int pk_algo;
|
||||
|
||||
pk_algo = gpgsm_get_key_algo_info (cl->cert, &nbits);
|
||||
xfree (curve);
|
||||
pk_algo = gpgsm_get_key_algo_info (cl->cert, &nbits, &curve);
|
||||
cl->pk_algo = pk_algo;
|
||||
|
||||
if (opt.forced_digest_algo)
|
||||
@ -821,7 +823,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
||||
}
|
||||
|
||||
if (!gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pk_algo, 0,
|
||||
NULL, nbits, NULL))
|
||||
NULL, nbits, curve))
|
||||
{
|
||||
char kidstr[10+1];
|
||||
|
||||
@ -1187,6 +1189,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
|
||||
gpg_strerror (rc), gpg_strsource (rc) );
|
||||
if (release_signerlist)
|
||||
gpgsm_release_certlist (signerlist);
|
||||
xfree (curve);
|
||||
ksba_cms_release (cms);
|
||||
gnupg_ksba_destroy_writer (b64writer);
|
||||
keydb_release (kh);
|
||||
|
@ -559,13 +559,21 @@ run_one_test (const char *name, const char *desc, const char *pass,
|
||||
else if (!certexpected && certstr)
|
||||
printresult ("FAIL: %s - no certs expected but got one\n", name);
|
||||
else if (certexpected && certstr && strcmp (certexpected, certstr))
|
||||
{
|
||||
printresult ("FAIL: %s - certs not as expected\n", name);
|
||||
inf ("cert(exp)=%s", certexpected);
|
||||
inf ("cert(got)=%s", certstr? certstr:"[null]");
|
||||
}
|
||||
else if (keyexpected && !resulthash)
|
||||
printresult ("FAIL: %s - expected key but got none\n", name);
|
||||
else if (!keyexpected && resulthash)
|
||||
printresult ("FAIL: %s - key not expected but got one\n", name);
|
||||
else if (keyexpected && resulthash && strcmp (keyexpected, resulthash))
|
||||
{
|
||||
printresult ("FAIL: %s - keys not as expected\n", name);
|
||||
inf ("key(exp)=%s", keyexpected);
|
||||
inf ("key(got)=%s", resulthash? resulthash:"[null]");
|
||||
}
|
||||
else
|
||||
{
|
||||
printresult ("PASS: %s\n", name);
|
||||
|
@ -450,7 +450,7 @@ gpgsm_verify (ctrl_t ctrl, estream_t in_fp, estream_t data_fp,
|
||||
|
||||
pkfpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
|
||||
pkalgostr = gpgsm_pubkey_algo_string (cert, NULL);
|
||||
pkalgo = gpgsm_get_key_algo_info2 (cert, &nbits, &pkcurve);
|
||||
pkalgo = gpgsm_get_key_algo_info (cert, &nbits, &pkcurve);
|
||||
/* Remap the ECC algo to the algo we use. Note that EdDSA has
|
||||
* already been mapped. */
|
||||
if (pkalgo == GCRY_PK_ECC)
|
||||
@ -486,7 +486,7 @@ gpgsm_verify (ctrl_t ctrl, estream_t in_fp, estream_t data_fp,
|
||||
|
||||
/* Check compliance. */
|
||||
if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION,
|
||||
pkalgo, pkalgoflags, NULL, nbits, NULL))
|
||||
pkalgo, pkalgoflags, NULL, nbits, pkcurve))
|
||||
{
|
||||
char kidstr[10+1];
|
||||
|
||||
|
@ -99,6 +99,8 @@ EXTRA_DIST = $(XTESTS) $(KEYS) $(CERTS) $(TEST_FILES) \
|
||||
samplekeys/opensc-test.p12 \
|
||||
samplekeys/t5793-openssl.pfx \
|
||||
samplekeys/t5793-test.pfx \
|
||||
samplekeys/edward.tester@demo.gnupg.com.p12 \
|
||||
samplekeys/nistp256-openssl-self-signed.p12 \
|
||||
samplemsgs/pwri-sample.cbc.p7m \
|
||||
samplemsgs/pwri-sample.cbc-2.p7m \
|
||||
samplemsgs/pwri-sample.gcm.p7m \
|
||||
|
@ -1,4 +1,6 @@
|
||||
# Description-p12 - Machine readable description of our P12 test vectors
|
||||
# The Cert line gives the SHA1 fingerprint of the certificate
|
||||
# The Key line gives a hash of the key parameters as returned by minip12.c
|
||||
|
||||
Name: ov-user.p12
|
||||
Desc: Private test key from www.openvalidation.org
|
||||
@ -30,3 +32,23 @@ Desc: QuaVadis format of t5793-openssl
|
||||
Pass: test
|
||||
Cert: 80348a438e4b803b99e708da0b7fdd0659dedd15
|
||||
Key: c271e44ab4fb19ca1aae71102ea4d7292ccc981d
|
||||
|
||||
Name: edward.tester@demo.gnupg.com.p12
|
||||
Desc: GnuPG exported Brainpool certificate
|
||||
Pass: abc,123456
|
||||
Cert: ff810b9281a43c394aa138e9c7fd4c0193216fa6
|
||||
Key: 94c6d0b067370a8f2a09ae43cfe8d700bbd61e75
|
||||
|
||||
Name: nistp256-openssl-self-signed.p12
|
||||
Desc: OpenSSL generated self-signed nistp256 key+cert
|
||||
Pass: abc
|
||||
Cert: 5cea0c5bf09ccd92535267c662fc098f6c81c27e
|
||||
Key: 3cb2fba95d1976df69eb7aa8c65ac5354e15af32
|
||||
|
||||
Name: t6752-ov-user-ff.p12
|
||||
Desc: Mozilla generated with a surplus octet string container
|
||||
Pass: start
|
||||
Cert: 4753a910e0c8b4caa8663ca0e4273a884eb5397d
|
||||
Key: 93be89edd11214ab74280d988a665b6beef876c5
|
||||
|
||||
# eof #
|
||||
|
BIN
tests/cms/samplekeys/edward.tester@demo.gnupg.com.p12
Normal file
BIN
tests/cms/samplekeys/edward.tester@demo.gnupg.com.p12
Normal file
Binary file not shown.
BIN
tests/cms/samplekeys/nistp256-openssl-self-signed.p12
Normal file
BIN
tests/cms/samplekeys/nistp256-openssl-self-signed.p12
Normal file
Binary file not shown.
BIN
tests/cms/samplekeys/t6752-ov-user-ff.p12
Normal file
BIN
tests/cms/samplekeys/t6752-ov-user-ff.p12
Normal file
Binary file not shown.
@ -235,6 +235,7 @@ status_sc_op_failure (gpg_error_t err)
|
||||
gnupg_status_printf (STATUS_SC_OP_FAILURE, "1");
|
||||
break;
|
||||
case GPG_ERR_BAD_PIN:
|
||||
case GPG_ERR_BAD_RESET_CODE:
|
||||
gnupg_status_printf (STATUS_SC_OP_FAILURE, "2");
|
||||
break;
|
||||
default:
|
||||
|
@ -332,6 +332,8 @@ yubikey_commands (card_info_t info, estream_t fp, int argc, const char *argv[])
|
||||
cmd = ykDISABLE;
|
||||
else
|
||||
{
|
||||
log_info ("Please use \"%s\" to list the available sub-commands\n",
|
||||
"help yubikey");
|
||||
err = gpg_error (GPG_ERR_UNKNOWN_COMMAND);
|
||||
goto leave;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user