1
0
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:
Werner Koch 2023-11-07 20:07:45 +01:00
commit 387ee7dcbd
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
67 changed files with 3281 additions and 2337 deletions

7
NEWS
View File

@ -1,6 +1,9 @@
Noteworthy changes in version 2.5.0 (unreleased) 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: 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: 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 * wkd: Use export-clean for gpg-wks-client's --mirror and --create
commands. [rG2c7f7a5a27] commands. [rG2c7f7a5a27]
@ -70,6 +76,7 @@ Noteworthy changes in version 2.5.0 (unreleased)
Release dates of 2.4 versions 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.3 (2023-07-04) https://dev.gnupg.org/T6509
Version 2.4.2 (2023-05-30) https://dev.gnupg.org/T6506 Version 2.4.2 (2023-05-30) https://dev.gnupg.org/T6506
Version 2.4.1 (2023-04-28) https://dev.gnupg.org/T6454 Version 2.4.1 (2023-04-28) https://dev.gnupg.org/T6454

View File

@ -175,6 +175,7 @@ unlock_pinentry (ctrl_t ctrl, gpg_error_t rc)
case GPG_ERR_NO_PASSPHRASE: case GPG_ERR_NO_PASSPHRASE:
case GPG_ERR_BAD_PASSPHRASE: case GPG_ERR_BAD_PASSPHRASE:
case GPG_ERR_BAD_PIN: case GPG_ERR_BAD_PIN:
case GPG_ERR_BAD_RESET_CODE:
break; break;
case GPG_ERR_CORRUPTED_PROTECTION: case GPG_ERR_CORRUPTED_PROTECTION:
@ -1610,12 +1611,13 @@ agent_askpin (ctrl_t ctrl,
&& (pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE)) && (pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
return unlock_pinentry (ctrl, rc); 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) if (pininfo->cb_errtext)
errtext = pininfo->cb_errtext; errtext = pininfo->cb_errtext;
else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE else
|| gpg_err_code (rc) == GPG_ERR_BAD_PIN)
errtext = (is_pin? L_("Bad PIN") : L_("Bad Passphrase")); errtext = (is_pin? L_("Bad PIN") : L_("Bad Passphrase"));
} }
else if (rc) else if (rc)
@ -1883,12 +1885,13 @@ agent_get_passphrase (ctrl_t ctrl,
if (rc && (pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE)) if (rc && (pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
return unlock_pinentry (ctrl, rc); 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) if (pininfo->cb_errtext)
errtext = pininfo->cb_errtext; errtext = pininfo->cb_errtext;
else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE else
|| gpg_err_code (rc) == GPG_ERR_BAD_PIN)
errtext = (is_pin? L_("Bad PIN") : L_("Bad Passphrase")); errtext = (is_pin? L_("Bad PIN") : L_("Bad Passphrase"));
} }
else if (rc) else if (rc)

View File

@ -282,6 +282,7 @@ AUTHENTICODE_FILES= \
gpgtar.exe \ gpgtar.exe \
gpgv.exe \ gpgv.exe \
gpg-card.exe \ gpg-card.exe \
keyboxd.exe \
libassuan-0.dll \ libassuan-0.dll \
libgcrypt-20.dll \ libgcrypt-20.dll \
libgpg-error-0.dll \ libgpg-error-0.dll \

View File

@ -58,7 +58,7 @@ common_sources = \
openpgpdefs.h \ openpgpdefs.h \
gc-opt-flags.h \ gc-opt-flags.h \
sexp-parse.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 \ init.c init.h \
sexputil.c \ sexputil.c \
sysutils.c sysutils.h \ sysutils.c sysutils.h \
@ -160,8 +160,9 @@ endif
module_tests = t-stringhelp t-timestuff \ module_tests = t-stringhelp t-timestuff \
t-convert t-percent t-gettime t-sysutils t-sexputil \ t-convert t-percent t-gettime t-sysutils t-sexputil \
t-session-env t-openpgp-oid t-ssh-utils \ 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 t-name-value t-ccparray t-recsel t-w32-cmdline t-exechelp
if HAVE_W32_SYSTEM if HAVE_W32_SYSTEM
module_tests += t-w32-reg module_tests += t-w32-reg
else else
@ -209,6 +210,7 @@ t_zb32_LDADD = $(t_common_ldadd)
t_mbox_util_LDADD = $(t_common_ldadd) t_mbox_util_LDADD = $(t_common_ldadd)
t_iobuf_LDADD = $(t_common_ldadd) t_iobuf_LDADD = $(t_common_ldadd)
t_strlist_LDADD = $(t_common_ldadd) t_strlist_LDADD = $(t_common_ldadd)
t_b64_LDADD = $(t_common_ldadd)
t_name_value_LDADD = $(t_common_ldadd) t_name_value_LDADD = $(t_common_ldadd)
t_ccparray_LDADD = $(t_common_ldadd) t_ccparray_LDADD = $(t_common_ldadd)
t_recsel_LDADD = $(t_common_ldadd) t_recsel_LDADD = $(t_common_ldadd)

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 #ifdef HAVE_POSIX_SYSTEM
/* Unix specific code of make_dotlock. Returns 0 on success and -1 on /* 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) if (timeout)
{ {
struct timeval tv; struct timeval tv;
int wtimereal;
/* Wait until lock has been released. We use increasing retry if (ownerchanged)
intervals of 50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s wtime = 0; /* Reset because owner chnaged. */
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 (timeout > 0) wtimereal = next_wait_interval (&wtime, &timeout);
{
if (wtime > timeout)
wtime = timeout;
timeout -= wtime;
}
sumtime += wtime; sumtime += wtimereal;
if (sumtime >= 1500) if (sumtime >= 1500)
{ {
sumtime = 0; sumtime = 0;
@ -1198,9 +1227,8 @@ dotlock_take_unix (dotlock_t h, long timeout)
pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):""); pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):"");
} }
tv.tv_sec = wtimereal / 1000;
tv.tv_sec = wtime / 1000; tv.tv_usec = (wtimereal % 1000) * 1000;
tv.tv_usec = (wtime % 1000) * 1000;
select (0, NULL, NULL, NULL, &tv); select (0, NULL, NULL, NULL, &tv);
goto again; goto again;
} }
@ -1242,28 +1270,14 @@ dotlock_take_w32 (dotlock_t h, long timeout)
if (timeout) if (timeout)
{ {
/* Wait until lock has been released. We use retry intervals of int wtimereal;
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;
if (timeout > 0) wtimereal = next_wait_interval (&wtime, &timeout);
{
if (wtime > timeout)
wtime = timeout;
timeout -= wtime;
}
if (wtime >= 800) if (wtime >= 800)
my_info_1 (_("waiting for lock %s...\n"), h->lockname); my_info_1 (_("waiting for lock %s...\n"), h->lockname);
Sleep (wtime); Sleep (wtimereal);
goto again; goto again;
} }

View File

@ -37,6 +37,11 @@
#ifdef HAVE_LANGINFO_H #ifdef HAVE_LANGINFO_H
#include <langinfo.h> #include <langinfo.h>
#endif #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 "util.h"
#include "i18n.h" #include "i18n.h"
@ -61,6 +66,111 @@ static enum { NORMAL = 0, FROZEN, FUTURE, PAST } timemode;
#define JD_DIFF 1721060L #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 /* Wrapper for the time(3). We use this here so we can fake the time
for tests */ for tests */
time_t 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. * Scan a date string and return a timestamp.
@ -208,7 +340,21 @@ scan_isodatestr( const char *string )
tmbuf.tm_isdst = -1; tmbuf.tm_isdst = -1;
stamp = mktime( &tmbuf ); stamp = mktime( &tmbuf );
if( stamp == (time_t)-1 ) 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; 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 /* Helper for isotime2epoch. Returns 0 on success. */
only supported format is "yyyymmddThhmmss[Z]" delimited by white static int
space, nul, a colon or a comma. Returns (time_t)(-1) for an isotime_make_tm (const char *string, struct tm *tmbuf)
invalid string. */
time_t
isotime2epoch (const char *string)
{ {
int year, month, day, hour, minu, sec; int year, month, day, hour, minu, sec;
struct tm tmbuf;
if (!isotime_p (string)) if (!isotime_p (string))
return (time_t)(-1); return -1;
year = atoi_4 (string); year = atoi_4 (string);
month = atoi_2 (string + 4); month = atoi_2 (string + 4);
@ -386,20 +528,48 @@ isotime2epoch (const char *string)
/* Basic checks. */ /* Basic checks. */
if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31
|| hour > 23 || minu > 59 || sec > 61 ) || 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); 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); 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. */ /* Convert an Epoch time to an iso time stamp. */
void void
epoch2isotime (gnupg_isotime_t timebuf, time_t atime) 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 /* Parse the string TIMESTAMP into a time_t. The string may either be
seconds since Epoch or in the ISO 8601 format like seconds since Epoch or in the ISO 8601 format like
"20390815T143012". Returns 0 for an empty string or seconds since "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 This function is a copy of
gpgme/src/conversion.c:_gpgme_parse_timestamp. If you change it, 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 time_t
parse_timestamp (const char *timestamp, char **endp) 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_min = atoi_2 (timestamp+11);
buf.tm_sec = atoi_2 (timestamp+13); buf.tm_sec = atoi_2 (timestamp+13);
#ifdef HAVE_W32_SYSTEM
return _win32_timegm (&buf);
#else
#ifdef HAVE_TIMEGM
return timegm (&buf); 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 else
return (time_t)strtoul (timestamp, endp, 10); 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 * 2018 has a lot of additional support but that will for sure
* break other things. We should move to ISO strings to get * break other things. We should move to ISO strings to get
* rid of such problems. */ * rid of such problems. */
setlocale (LC_TIME, ""); setlocale (LC_TIME, ".UTF8");
done = 1; done = 1;
/* log_debug ("LC_ALL now '%s'\n", setlocale (LC_ALL, NULL)); */ /* log_debug ("LC_ALL now '%s'\n", setlocale (LC_ALL, NULL)); */
/* log_debug ("LC_TIME now '%s'\n", setlocale (LC_TIME, NULL)); */ /* log_debug ("LC_TIME now '%s'\n", setlocale (LC_TIME, NULL)); */

View File

@ -32,7 +32,7 @@
#include <time.h> /* We need time_t. */ #include <time.h> /* We need time_t. */
#include <gpg-error.h> /* We need gpg_error_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 /* A type to hold the ISO time. Note that this is the same as
the KSBA type ksba_isotime_t. */ the KSBA type ksba_isotime_t. */
@ -43,6 +43,11 @@ typedef char gnupg_isotime_t[16];
#define GNUPG_ISOTIME_NONE \ #define GNUPG_ISOTIME_NONE \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\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); time_t gnupg_get_time (void);
struct tm *gnupg_gmtime (const time_t *timep, struct tm *result); struct tm *gnupg_gmtime (const time_t *timep, struct tm *result);
void gnupg_get_isotime (gnupg_isotime_t timebuf); void gnupg_get_isotime (gnupg_isotime_t timebuf);
@ -51,11 +56,13 @@ int gnupg_faked_time_p (void);
u32 make_timestamp (void); u32 make_timestamp (void);
char *elapsed_time_string (time_t since, time_t now); char *elapsed_time_string (time_t since, time_t now);
u32 scan_secondsstr (const char *string);
u32 scan_isodatestr (const char *string); u32 scan_isodatestr (const char *string);
int isotime_p (const char *string); int isotime_p (const char *string);
int isotime_human_p (const char *string, int date_only); int isotime_human_p (const char *string, int date_only);
size_t string2isotime (gnupg_isotime_t atime, const char *string); size_t string2isotime (gnupg_isotime_t atime, const char *string);
time_t isotime2epoch (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); void epoch2isotime (gnupg_isotime_t timebuf, time_t atime);
int isodate_human_to_tm (const char *string, struct tm *t); int isodate_human_to_tm (const char *string, struct tm *t);
time_t parse_timestamp (const char *timestamp, char **endp); time_t parse_timestamp (const char *timestamp, char **endp);

View File

@ -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 static int
string_has_ctrl_or_space (const char *string) 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 == '@'
|| name[namelen-1] == '@' || name[namelen-1] == '@'
|| name[namelen-1] == '.' || name[namelen-1] == '.'
|| my_memstr (name, namelen, "..")); || gnupg_memstr (name, namelen, ".."));
} }

View File

@ -687,3 +687,53 @@ parse_compatibility_flags (const char *string, unsigned int *flagvar,
*flagvar |= result; *flagvar |= result;
return 0; 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;
}

View File

@ -126,80 +126,3 @@ same_file_p (const char *name1, const char *name2)
} }
return yes; 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*/

View File

@ -38,12 +38,6 @@
int same_file_p (const char *name1, const char *name2); 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 DIM(v) (sizeof(v)/sizeof((v)[0]))
#define DIMof(type,member) DIM(((type *)0)->member) #define DIMof(type,member) DIM(((type *)0)->member)

View File

@ -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 /* Return a pointer to the next logical connection operator or NULL if
* none. */ * none. */
static char * static char *
@ -560,7 +529,7 @@ recsel_select (recsel_expr_t selector,
break; break;
case SELECT_SUB: case SELECT_SUB:
if (se->xcase) if (se->xcase)
result = !!my_memstr (value, valuelen, se->value); result = !!gnupg_memstr (value, valuelen, se->value);
else else
result = !!memistr (value, valuelen, se->value); result = !!memistr (value, valuelen, se->value);
break; break;

View File

@ -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 /* 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 * 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 * 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 /* Convert a base-10 number in STRING into a 64 bit unsigned int
* value. Leading white spaces are skipped but no error checking is * 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 uint64_t
string_to_u64 (const char *string) string_to_u64 (const char *string)
{ {

View File

@ -40,6 +40,7 @@
char *has_leading_keyword (const char *string, const char *keyword); char *has_leading_keyword (const char *string, const char *keyword);
const char *memistr (const void *buf, size_t buflen, const char *sub); 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 *mem2str( char *, const void *, size_t);
char *trim_spaces( char *string ); char *trim_spaces( char *string );
char *ascii_trim_spaces (char *string); char *ascii_trim_spaces (char *string);

View File

@ -933,7 +933,12 @@ gnupg_remove (const char *fname)
return -1; return -1;
return 0; return 0;
#else #else
return remove (fname); /* 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 #endif
} }

View File

@ -1,30 +1,23 @@
/* t-b64.c - Module tests for b64enc.c and b64dec.c /* t-b64.c - Module tests for b64decodec
* Copyright (C) 2008 Free Software Foundation, Inc. * Copyright (C) 2023 g10 Code GmbH
* *
* This file is part of GnuPG. * This file is part of GnuPG.
* *
* GnuPG is free software; you can redistribute it and/or modify * This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU Lesser General Public License as
* the Free Software Foundation; either version 3 of the License, or * published by the Free Software Foundation; either version 2.1 of
* (at your option) any later version. * 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 * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * 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/>. * 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 <config.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -36,121 +29,117 @@
__FILE__,__LINE__, (a)); \ __FILE__,__LINE__, (a)); \
errcount++; \ errcount++; \
} while(0) } while(0)
#define oops() do { fprintf (stderr, "%s:%d: ooops\n", \
__FILE__,__LINE__); \
exit (2); \
} while(0)
static int verbose; static int verbose;
static int errcount; 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; const char *s;
struct b64state state; unsigned char *buffer;
size_t length;
if (!string) buffer = xmalloc (strlen(string)/2+1);
string = "a"; length = 0;
for (s=string; *s; s +=2 )
err = b64enc_start (&state, stdout, "PGP MESSAGE"); {
if (err) if (!hexdigitp (s) || !hexdigitp (s+1))
fail (1); return NULL; /* Invalid hex digits. */
((unsigned char*)buffer)[length++] = xtoi_2 (s);
err = b64enc_write (&state, string, strlen (string)); }
if (err) *r_length = length;
fail (2); return buffer;
err = b64enc_finish (&state);
if (err)
fail (3);
pass ();
} }
static void 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; gpg_error_t err;
struct b64state state; void *data = NULL;
FILE *fp; size_t datalen;
char buffer[50]; char *wantdata = NULL;
size_t nread; size_t wantdatalen;
fp = fname ? fopen (fname, "r") : stdin; for (tidx = 0; tidx < DIM(tests); tidx++)
if (!fp)
{ {
fprintf (stderr, "%s:%d: can't open '%s': %s\n", xfree (wantdata);
__FILE__, __LINE__, fname? fname:"[stdin]", strerror (errno)); if (!(wantdata = hex2buffer (tests[tidx].datastr, &wantdatalen)))
fail (0); 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 ();
} }
xfree (wantdata);
err = b64enc_start (&state, stdout, "DATA"); xfree (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);
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);
}
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 int
main (int argc, char **argv) main (int argc, char **argv)
{ {
int do_encode = 0;
int do_decode = 0;
if (argc) if (argc)
{ argc--; argv++; } { argc--; argv++; }
if (argc && !strcmp (argv[0], "--verbose")) if (argc && !strcmp (argv[0], "--verbose"))
@ -159,23 +148,7 @@ main (int argc, char **argv)
argc--; argv++; argc--; argv++;
} }
if (argc && !strcmp (argv[0], "--encode")) test_b64decode ();
{
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);
return !!errcount; return !!errcount;
} }

View File

@ -43,6 +43,56 @@ static int errcount;
#define INVALID ((time_t)(-1)) #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 static void
test_isotime2epoch (void) test_isotime2epoch (void)
{ {
@ -103,7 +153,6 @@ test_isotime2epoch (void)
} }
static void static void
test_string2isotime (void) test_string2isotime (void)
{ {
@ -269,6 +318,7 @@ main (int argc, char **argv)
if (argc > 1 && !strcmp (argv[1], "--verbose")) if (argc > 1 && !strcmp (argv[1], "--verbose"))
verbose = 1; verbose = 1;
test_scan_secondsstr ();
test_isotime2epoch (); test_isotime2epoch ();
test_string2isotime (); test_string2isotime ();
test_isodate_human_to_tm (); test_isodate_human_to_tm ();

788
common/tlv-parser.c Normal file
View 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;
}

View File

@ -71,10 +71,22 @@ enum tlv_tag_type {
TAG_BMP_STRING = 30 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; struct tlv_builder_s;
typedef struct tlv_builder_s *tlv_builder_t; typedef struct tlv_builder_s *tlv_builder_t;
struct tlv_parser_s;
typedef struct tlv_parser_s *tlv_parser_t;
/*-- tlv.c --*/ /*-- tlv.c --*/
/* Locate a TLV encoded data object in BUFFER of LENGTH and return a /* 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 /* 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 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, gpg_error_t parse_ber_header (unsigned char const **buffer, size_t *size,
int *r_class, int *r_tag, int *r_class, int *r_tag,
int *r_constructed, 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); 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 */ #endif /* SCD_TLV_H */

View File

@ -39,6 +39,11 @@
* libgpg-error version. Define them here. * libgpg-error version. Define them here.
* Example: (#if GPG_ERROR_VERSION_NUMBER < 0x011500 // 1.21) * 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 #ifndef EXTERN_UNLESS_MAIN_MODULE
# if !defined (INCLUDED_BY_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, char **addr_of_buffer, size_t *length_of_buffer,
size_t *max_length); size_t *max_length);
/*-- sexputil.c */ /*-- sexputil.c */
char *canon_sexp_to_string (const unsigned char *canon, size_t canonlen); char *canon_sexp_to_string (const unsigned char *canon, size_t canonlen);
void log_printcanon (const char *text, void log_printcanon (const char *text,
@ -352,6 +358,10 @@ struct compatibility_flags_s
int parse_compatibility_flags (const char *string, unsigned int *flagvar, int parse_compatibility_flags (const char *string, unsigned int *flagvar,
const struct compatibility_flags_s *flags); 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. */ /*-- Simple replacement functions. */

View File

@ -67,13 +67,13 @@ NEED_KSBA_API=1
NEED_KSBA_VERSION=1.6.3 NEED_KSBA_VERSION=1.6.3
NEED_NTBTLS_API=1 NEED_NTBTLS_API=1
NEED_NTBTLS_VERSION=0.1.0 NEED_NTBTLS_VERSION=0.2.0
NEED_NPTH_API=1 NEED_NPTH_API=1
NEED_NPTH_VERSION=1.2 NEED_NPTH_VERSION=1.2
NEED_GNUTLS_VERSION=3.0 NEED_GNUTLS_VERSION=3.2
NEED_SQLITE_VERSION=3.27 NEED_SQLITE_VERSION=3.27

View File

@ -68,6 +68,7 @@ AM_CFLAGS = $(USE_C99_CFLAGS) \
if HAVE_W32_SYSTEM if HAVE_W32_SYSTEM
ldap_url = ldap-url.h ldap-url.c ldap_url = ldap-url.h ldap-url.c
NETLIBS += -lwinhttp -lsecurity
else else
ldap_url = ldap_url =
endif endif

View File

@ -2046,6 +2046,7 @@ dirmngr_sighup_action (void)
crl_cache_deinit (); crl_cache_deinit ();
cert_cache_init (hkp_cacert_filenames); cert_cache_init (hkp_cacert_filenames);
crl_cache_init (); crl_cache_init ();
http_reinitialize ();
reload_dns_stuff (0); reload_dns_stuff (0);
ks_hkp_reload (); ks_hkp_reload ();
} }

View File

@ -22,4 +22,6 @@
const char *get_default_keyserver (int name_only); const char *get_default_keyserver (int name_only);
void http_reinitialize (void);
#endif /* HTTP_COMMON_H */ #endif /* HTTP_COMMON_H */

File diff suppressed because it is too large Load Diff

View File

@ -132,9 +132,11 @@ typedef gpg_error_t (*http_verify_cb_t) (void *opaque,
void http_set_verbose (int verbose, int debug); 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_callback (gpg_error_t (*cb)(http_t,http_session_t,int));
void http_register_tls_ca (const char *fname); void http_register_tls_ca (const char *fname);
void http_register_cfg_ca (const char *fname); void http_register_cfg_ca (const char *fname);
void http_register_netactivity_cb (void (*cb)(void)); 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); estream_t http_get_write_ptr (http_t hd);
unsigned int http_get_status_code (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_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); const char **http_get_header_names (http_t hd);
gpg_error_t http_verify_server_credentials (http_session_t sess); gpg_error_t http_verify_server_credentials (http_session_t sess);

View File

@ -1327,7 +1327,7 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
{ {
xfree (request_buffer); xfree (request_buffer);
err = http_prepare_redirect (&redirinfo, http_get_status_code (http), err = http_prepare_redirect (&redirinfo, http_get_status_code (http),
http_get_header (http, "Location"), http_get_header (http, "Location", 0),
&request_buffer); &request_buffer);
if (err) if (err)
goto leave; goto leave;
@ -1340,18 +1340,17 @@ send_request (ctrl_t ctrl, const char *request, const char *hostportstr,
} }
goto once_more; 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: default:
log_error (_("error accessing '%s': http status %u\n"), log_error (_("error accessing '%s': http status %u\n"),
request, http_get_status_code (http)); 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; goto leave;
} }

View File

@ -180,7 +180,7 @@ ks_http_fetch (ctrl_t ctrl, const char *url, unsigned int flags,
{ {
xfree (request_buffer); xfree (request_buffer);
err = http_prepare_redirect (&redirinfo, http_get_status_code (http), err = http_prepare_redirect (&redirinfo, http_get_status_code (http),
http_get_header (http, "Location"), http_get_header (http, "Location", 0),
&request_buffer); &request_buffer);
if (err) if (err)
goto leave; goto leave;
@ -193,14 +193,16 @@ ks_http_fetch (ctrl_t ctrl, const char *url, unsigned int flags,
} }
goto once_more; goto once_more;
case 413: /* Payload too large */
err = gpg_error (GPG_ERR_TOO_LARGE);
goto leave;
default: default:
log_error (_("error accessing '%s': http status %u\n"), log_error (_("error accessing '%s': http status %u\n"),
url, http_get_status_code (http)); 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; goto leave;
} }

View File

@ -380,13 +380,14 @@ rfc4517toisotime (gnupg_isotime_t timebuf, const char *string)
int year, month, day, hour, minu, sec; int year, month, day, hour, minu, sec;
const char *s; const char *s;
/* Sample value: "20230823141623Z"; */
for (i=0, s=string; i < 10; i++, s++) /* Need yyyymmddhh */ for (i=0, s=string; i < 10; i++, s++) /* Need yyyymmddhh */
if (!digitp (s)) if (!digitp (s))
return gpg_error (GPG_ERR_INV_TIME); return gpg_error (GPG_ERR_INV_TIME);
year = atoi_4 (string); year = atoi_4 (string);
month = atoi_2 (string + 4); month = atoi_2 (string + 4);
day = atoi_2 (string + 6); day = atoi_2 (string + 6);
hour = atoi_2 (string + 9); hour = atoi_2 (string + 8);
minu = 0; minu = 0;
sec = 0; sec = 0;
if (digitp (s) && digitp (s+1)) if (digitp (s) && digitp (s+1))

View File

@ -227,7 +227,7 @@ do_ocsp_request (ctrl_t ctrl, ksba_ocsp_t ocsp,
case 301: case 301:
case 302: 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"), log_info (_("URL '%s' redirected to '%s' (%u)\n"),
url, s?s:"[none]", http_get_status_code (http)); url, s?s:"[none]", http_get_status_code (http));

View File

@ -2202,6 +2202,7 @@ ensure_keyserver (ctrl_t ctrl)
uri_item_t plain_items = NULL; uri_item_t plain_items = NULL;
uri_item_t ui; uri_item_t ui;
strlist_t sl; strlist_t sl;
int none_seen = 1;
if (ctrl->server_local->keyservers) if (ctrl->server_local->keyservers)
return 0; /* Already set for this session. */ return 0; /* Already set for this session. */
@ -2214,6 +2215,15 @@ ensure_keyserver (ctrl_t ctrl)
for (sl = opt.keyserver; sl; sl = sl->next) 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); err = make_keyserver_item (sl->d, &item);
if (err) if (err)
goto leave; 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 /* Decide which to use. Note that the session has no keyservers
yet set. */ yet set. */
if (onion_items && !onion_items->next && plain_items && !plain_items->next) 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; gpg_error_t err = 0;
int clear_flag, add_flag, help_flag, host_flag, resolve_flag; int clear_flag, add_flag, help_flag, host_flag, resolve_flag;
int dead_flag, alive_flag; int dead_flag, alive_flag;
uri_item_t item = NULL; /* gcc 4.4.5 is not able to detect that it uri_item_t item = NULL;
is always initialized. */
clear_flag = has_option (line, "--clear"); clear_flag = has_option (line, "--clear");
help_flag = has_option (line, "--help"); help_flag = has_option (line, "--help");
@ -2366,13 +2381,17 @@ cmd_keyserver (assuan_context_t ctx, char *line)
if (add_flag) if (add_flag)
{ {
err = make_keyserver_item (line, &item); if (!strcmp (line, "none") || !strcmp (line, "hkp://none")
|| !strcmp (line, "hkps://none"))
err = 0;
else
err = make_keyserver_item (line, &item);
if (err) if (err)
goto leave; goto leave;
} }
if (clear_flag) if (clear_flag)
release_ctrl_keyservers (ctrl); release_ctrl_keyservers (ctrl);
if (add_flag) if (add_flag && item)
{ {
item->next = ctrl->server_local->keyservers; item->next = ctrl->server_local->keyservers;
ctrl->server_local->keyservers = item; ctrl->server_local->keyservers = item;

View File

@ -288,6 +288,11 @@ main (int argc, char **argv)
my_http_flags |= HTTP_FLAG_FORCE_TOR; my_http_flags |= HTTP_FLAG_FORCE_TOR;
argc--; argv++; argc--; argv++;
} }
else if (!strcmp (*argv, "--try-proxy"))
{
my_http_flags |= HTTP_FLAG_TRY_PROXY;
argc--; argv++;
}
else if (!strcmp (*argv, "--no-out")) else if (!strcmp (*argv, "--no-out"))
{ {
no_out = 1; no_out = 1;
@ -458,7 +463,7 @@ main (int argc, char **argv)
log_fatal ("http_get_header_names failed: %s\n", log_fatal ("http_get_header_names failed: %s\n",
gpg_strerror (gpg_error_from_syserror ())); gpg_strerror (gpg_error_from_syserror ()));
for (i = 0; names[i]; i++) 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); xfree (names);
} }
fflush (stdout); fflush (stdout);
@ -484,7 +489,7 @@ main (int argc, char **argv)
case 301: case 301:
case 302: case 302:
case 307: 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; break;
} }
http_close (hd, 0); http_close (hd, 0);

65
doc/ad-query-hints.org Normal file
View 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

View File

@ -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 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 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 1970. Alternatively @var{epoch} may be given as a full ISO time string
(e.g., "20070924T154812"). (e.g. "20070924T154812").
@item --debug-level @var{level} @item --debug-level @var{level}
@opindex debug-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. done for each new connection.
If no keyserver is explicitly configured, dirmngr will use the 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 Windows users with a keyserver running on their Active Directory
may use the short form @code{ldap:///} for @var{name} to access this 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 @item --honor-http-proxy
@opindex honor-http-proxy @opindex honor-http-proxy
If the environment variable @env{http_proxy} has been set, use its 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}] @item --http-proxy @var{host}[:@var{port}]
@opindex http-proxy @opindex http-proxy

View File

@ -2715,6 +2715,12 @@ The available properties are:
second is the same but given as an ISO date string, second is the same but given as an ISO date string,
e.g., "2016-08-17". (drop-sig) 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 @item sig_algo
A number with the public key algorithm of a signature packet. (drop-sig) A number with the public key algorithm of a signature packet. (drop-sig)

View File

@ -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 the compliance rules are not fulfilled. Note that this option has
currently an effect only in "de-vs" mode. 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} @item --ignore-cert-with-oid @var{oid}
@opindex ignore-cert-with-oid @opindex ignore-cert-with-oid
Add @var{oid} to the list of OIDs to be checked while reading 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 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 due to a @code{OPTION offline=1} or due to @command{gpgsm} being
started with option @option{--disable-dirmngr}. 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 @end table
@node GPGSM OPTION @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 is disabled for this session. This is the same as the command line
option @option{--disable-dirmngr}. 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 @item input-size-hint
This is the same as the @option{--input-size-hint} command line option. This is the same as the @option{--input-size-hint} command line option.

View File

@ -130,6 +130,7 @@ status_sc_op_failure (int rc)
write_status_text (STATUS_SC_OP_FAILURE, "1"); write_status_text (STATUS_SC_OP_FAILURE, "1");
break; break;
case GPG_ERR_BAD_PIN: case GPG_ERR_BAD_PIN:
case GPG_ERR_BAD_RESET_CODE:
write_status_text (STATUS_SC_OP_FAILURE, "2"); write_status_text (STATUS_SC_OP_FAILURE, "2");
break; break;
default: default:

View File

@ -56,6 +56,7 @@ write_sc_op_status (gpg_error_t err)
write_status_text (STATUS_SC_OP_FAILURE, "1"); write_status_text (STATUS_SC_OP_FAILURE, "1");
break; break;
case GPG_ERR_BAD_PIN: case GPG_ERR_BAD_PIN:
case GPG_ERR_BAD_RESET_CODE:
write_status_text (STATUS_SC_OP_FAILURE, "2"); write_status_text (STATUS_SC_OP_FAILURE, "2");
break; break;
default: default:

View File

@ -3486,7 +3486,7 @@ main (int argc, char **argv)
break; break;
case oUtf8Strings: utf8_strings = 1; break; case oUtf8Strings: utf8_strings = 1; break;
case oNoUtf8Strings: case oNoUtf8Strings:
#ifdef HAVE_W32_SYSTEM #ifndef HAVE_W32_SYSTEM
utf8_strings = 0; utf8_strings = 0;
#endif #endif
break; break;

View File

@ -1509,6 +1509,20 @@ impex_filter_getval (void *cookie, const char *propname)
{ {
result = dateonlystr_from_sig (sig); 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")) else if (!strcmp (propname, "sig_algo"))
{ {
snprintf (numbuf, sizeof numbuf, "%d", sig->pubkey_algo); snprintf (numbuf, sizeof numbuf, "%d", sig->pubkey_algo);

View File

@ -2748,6 +2748,7 @@ parse_expire_string_with_ct (const char *string, u32 creation_time)
u32 seconds; u32 seconds;
u32 abs_date = 0; u32 abs_date = 0;
time_t tt; time_t tt;
uint64_t tmp64;
u32 curtime; u32 curtime;
if (creation_time == (u32)-1) 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, "-")) || !strcmp (string, "never") || !strcmp (string, "-"))
seconds = 0; seconds = 0;
else if (!strncmp (string, "seconds=", 8)) else if (!strncmp (string, "seconds=", 8))
seconds = atoi (string+8); seconds = scan_secondsstr (string+8);
else if ((abs_date = scan_isodatestr(string)) else if ((abs_date = scan_isodatestr(string))
&& (abs_date+86400/2) > curtime) && (abs_date+86400/2) > curtime)
seconds = (abs_date+86400/2) - curtime; seconds = (abs_date+86400/2) - curtime;
else if ((tt = isotime2epoch (string)) != (time_t)(-1)) else if ((tt = isotime2epoch_u64 (string)) != (uint64_t)(-1))
seconds = (u32)tt - curtime; {
tmp64 = tt - curtime;
if (tmp64 >= (u32)(-1))
seconds = (u32)(-1) - 1; /* cap value. */
else
seconds = (u32)tmp64;
}
else if ((mult = check_valid_days (string))) 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 else
seconds = (u32)(-1); seconds = (u32)(-1);
@ -2790,11 +2803,16 @@ parse_creation_string (const char *string)
if (!*string) if (!*string)
seconds = 0; seconds = 0;
else if ( !strncmp (string, "seconds=", 8) ) else if ( !strncmp (string, "seconds=", 8) )
seconds = atoi (string+8); seconds = scan_secondsstr (string+8);
else if ( !(seconds = scan_isodatestr (string))) else if ( !(seconds = scan_isodatestr (string)))
{ {
time_t tmp = isotime2epoch (string); uint64_t tmp = isotime2epoch_u64 (string);
seconds = (tmp == (time_t)(-1))? 0 : tmp; if (tmp == (uint64_t)(-1))
seconds = 0;
else if (tmp > (u32)(-1))
seconds = 0;
else
seconds = tmp;
} }
return seconds; 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); ecdh_param_str = ecdh_param_str_from_pk (sk);
if (!ecdh_param_str) if (!ecdh_param_str)
return gpg_error_from_syserror (); {
free_public_key (sk);
return gpg_error_from_syserror ();
}
} }
err = hexkeygrip_from_pk (sk, &hexgrip); err = hexkeygrip_from_pk (sk, &hexgrip);
if (err) if (err)
goto leave; {
xfree (ecdh_param_str);
free_public_key (sk);
goto leave;
}
memset(&info, 0, sizeof (info)); memset(&info, 0, sizeof (info));
rc = agent_scd_getattr ("SERIALNO", &info); rc = agent_scd_getattr ("SERIALNO", &info);
if (rc) if (rc)
{ {
xfree (ecdh_param_str);
free_public_key (sk);
err = (gpg_error_t)rc; err = (gpg_error_t)rc;
goto leave; goto leave;
} }

View File

@ -730,7 +730,7 @@ tdb_check_or_update (ctrl_t ctrl)
if (opt.interactive) if (opt.interactive)
update_trustdb (ctrl); update_trustdb (ctrl);
else if (!opt.no_auto_check_trustdb) else if (!opt.no_auto_check_trustdb)
check_trustdb (ctrl); check_trustdb (ctrl);
} }
} }
@ -983,6 +983,7 @@ update_min_ownertrust (ctrl_t ctrl, u32 *kid, unsigned int new_trust)
/* /*
* Clear the ownertrust and min_ownertrust values. * Clear the ownertrust and min_ownertrust values.
* Also schedule a revalidation if a stale validity record exists.
* *
* Return: True if a change actually happened. * Return: True if a change actually happened.
*/ */
@ -1016,6 +1017,26 @@ tdb_clear_ownertrusts (ctrl_t ctrl, PKT_public_key *pk)
do_sync (); do_sync ();
return 1; 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) else if (gpg_err_code (err) != GPG_ERR_NOT_FOUND)
{ {

View File

@ -23,6 +23,9 @@ AC_DEFUN([AB_INIT],
if test "$hostname"; then if test "$hostname"; then
AC_MSG_NOTICE([autobuild hostname... $hostname]) AC_MSG_NOTICE([autobuild hostname... $hostname])
fi fi
if test "$EMAIL"; then
AC_MSG_NOTICE([autobuild username... $EMAIL])
fi
ifelse([$1],[],,[AC_MSG_NOTICE([autobuild mode... $1])]) ifelse([$1],[],,[AC_MSG_NOTICE([autobuild mode... $1])])
date=`date +%Y%m%d-%H%M%S` date=`date +%Y%m%d-%H%M%S`
if test "$?" != 0; then if test "$?" != 0; then

View File

@ -3453,7 +3453,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
if (!remaining) if (!remaining)
{ {
log_error (_("Reset Code not or not anymore available\n")); 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; 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"), log_info (_("Reset Code is too short; minimum length is %d\n"),
minlen); minlen);
rc = gpg_error (GPG_ERR_BAD_PIN); rc = gpg_error (GPG_ERR_BAD_RESET_CODE);
goto leave; goto leave;
} }
} }
@ -3538,7 +3538,7 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
if (bufferlen != 0 && bufferlen < 8) if (bufferlen != 0 && bufferlen < 8)
{ {
log_error (_("Reset Code is too short; minimum length is %d\n"), 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 else
{ {

View File

@ -2199,9 +2199,15 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime,
memset (&rootca_flags, 0, sizeof rootca_flags); memset (&rootca_flags, 0, sizeof rootca_flags);
rc = do_validate_chain (ctrl, cert, checktime, if ((flags & VALIDATE_FLAG_BYPASS))
r_exptime, listmode, listfp, flags, {
&rootca_flags); *retflags |= VALIDATE_FLAG_BYPASS;
rc = 0;
}
else
rc = do_validate_chain (ctrl, cert, checktime,
r_exptime, listmode, listfp, flags,
&rootca_flags);
if (!rc && (flags & VALIDATE_FLAG_STEED)) if (!rc && (flags & VALIDATE_FLAG_STEED))
{ {
*retflags |= VALIDATE_FLAG_STEED; *retflags |= VALIDATE_FLAG_STEED;
@ -2223,6 +2229,8 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime,
if (opt.verbose) if (opt.verbose)
do_list (0, listmode, listfp, _("validation model used: %s"), do_list (0, listmode, listfp, _("validation model used: %s"),
(*retflags & VALIDATE_FLAG_BYPASS)?
"bypass" :
(*retflags & VALIDATE_FLAG_STEED)? (*retflags & VALIDATE_FLAG_STEED)?
"steed" : "steed" :
(*retflags & VALIDATE_FLAG_CHAIN_MODEL)? (*retflags & VALIDATE_FLAG_CHAIN_MODEL)?

View File

@ -448,6 +448,11 @@ gpgsm_add_to_certlist (ctrl_t ctrl, const char *name, int secret,
if (!rc && !is_cert_in_certlist (cert, *listaddr)) 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) if (!rc && secret)
{ {
char *p; char *p;
@ -461,9 +466,10 @@ gpgsm_add_to_certlist (ctrl_t ctrl, const char *name, int secret,
xfree (p); xfree (p);
} }
} }
if (!rc) if (!rc)
rc = gpgsm_validate_chain (ctrl, cert, GNUPG_ISOTIME_NONE, NULL, rc = gpgsm_validate_chain (ctrl, cert, GNUPG_ISOTIME_NONE, NULL,
0, NULL, 0, NULL); 0, NULL, valflags, NULL);
if (!rc) if (!rc)
{ {
certlist_t cl = xtrycalloc (1, sizeof *cl); certlist_t cl = xtrycalloc (1, sizeof *cl);

View File

@ -1064,6 +1064,7 @@ gpgsm_decrypt (ctrl_t ctrl, estream_t in_fp, estream_t out_fp)
KEYDB_HANDLE kh; KEYDB_HANDLE kh;
int recp; int recp;
struct decrypt_filter_parm_s dfparm; struct decrypt_filter_parm_s dfparm;
char *curve = NULL;
memset (&dfparm, 0, sizeof dfparm); 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); pkfpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
pkalgostr = gpgsm_pubkey_algo_string (cert, NULL); 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) if (!opt.quiet)
log_info (_("encrypted to %s key %s\n"), pkalgostr, pkfpr); log_info (_("encrypted to %s key %s\n"), pkalgostr, pkfpr);
/* Check compliance. */ /* Check compliance. */
if (!gnupg_pk_is_allowed (opt.compliance, if (!gnupg_pk_is_allowed (opt.compliance,
PK_USE_DECRYPTION, PK_USE_DECRYPTION,
pk_algo, 0, NULL, nbits, NULL)) pk_algo, 0, NULL, nbits, curve))
{ {
char kidstr[10+1]; 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 =
(dfparm.is_de_vs (dfparm.is_de_vs
&& gnupg_pk_is_compliant (CO_DE_VS, pk_algo, 0, && gnupg_pk_is_compliant (CO_DE_VS, pk_algo, 0,
NULL, nbits, NULL)); NULL, nbits, curve));
oops: oops:
if (rc) 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", log_error ("message decryption failed: %s <%s>\n",
gpg_strerror (rc), gpg_strsource (rc)); gpg_strerror (rc), gpg_strsource (rc));
} }
xfree (curve);
ksba_cms_release (cms); ksba_cms_release (cms);
gnupg_ksba_destroy_reader (b64reader); gnupg_ksba_destroy_reader (b64reader);
gnupg_ksba_destroy_writer (b64writer); gnupg_ksba_destroy_writer (b64writer);

View File

@ -749,11 +749,12 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
unsigned char *encval; unsigned char *encval;
unsigned int nbits; unsigned int nbits;
int pk_algo; int pk_algo;
char *curve = NULL;
/* Check compliance. */ /* 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, if (!gnupg_pk_is_compliant (opt.compliance, pk_algo, 0,
NULL, nbits, NULL)) NULL, nbits, curve))
{ {
char kidstr[10+1]; 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 /* Fixme: When adding ECC we need to provide the curvename and
* the key to gnupg_pk_is_compliant. */ * the key to gnupg_pk_is_compliant. */
if (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; compliant = 0;
xfree (curve);
curve = NULL;
rc = encrypt_dek (dek, cl->cert, pk_algo, &encval); rc = encrypt_dek (dek, cl->cert, pk_algo, &encval);
if (rc) if (rc)
{ {

View File

@ -430,7 +430,7 @@ gpgsm_p12_export (ctrl_t ctrl, const char *name, estream_t stream, int rawmode)
if (rawmode == 0) if (rawmode == 0)
ctrl->pem_name = "PKCS12"; 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"; ctrl->pem_name = "EC PRIVATE KEY";
else if (rawmode == 1) else if (rawmode == 1)
ctrl->pem_name = "PRIVATE KEY"; ctrl->pem_name = "PRIVATE KEY";

View File

@ -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 * algorithm is used the name or OID of the curve is stored there; the
* caller needs to free this value. */ * caller needs to free this value. */
int 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; gcry_sexp_t s_pkey;
int rc; 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. */ /* Return true if CERT is an ECC key. */
int int
gpgsm_is_ecc_key (ksba_cert_t cert) 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);
} }

View File

@ -215,6 +215,7 @@ enum cmd_and_opt_values {
oRequireCompliance, oRequireCompliance,
oCompatibilityFlags, oCompatibilityFlags,
oKbxBufferSize, oKbxBufferSize,
oAlwaysTrust,
oNoAutostart oNoAutostart
}; };
@ -417,6 +418,7 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_s_n (oIgnoreTimeConflict, "ignore-time-conflict", "@"), ARGPARSE_s_n (oIgnoreTimeConflict, "ignore-time-conflict", "@"),
ARGPARSE_s_n (oNoRandomSeedFile, "no-random-seed-file", "@"), ARGPARSE_s_n (oNoRandomSeedFile, "no-random-seed-file", "@"),
ARGPARSE_s_n (oRequireCompliance, "require-compliance", "@"), ARGPARSE_s_n (oRequireCompliance, "require-compliance", "@"),
ARGPARSE_s_n (oAlwaysTrust, "always-trust", "@"),
ARGPARSE_header (NULL, N_("Options for unattended use")), 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 oMinRSALength: opt.min_rsa_length = pargs.r.ret_ulong; break;
case oRequireCompliance: opt.require_compliance = 1; break; case oRequireCompliance: opt.require_compliance = 1; break;
case oAlwaysTrust: opt.always_trust = 1; break;
case oKbxBufferSize: case oKbxBufferSize:
keybox_set_buffersize (pargs.r.ret_ulong, 0); keybox_set_buffersize (pargs.r.ret_ulong, 0);
@ -1583,10 +1586,20 @@ main ( int argc, char **argv)
if (may_coredump && !opt.quiet) if (may_coredump && !opt.quiet)
log_info (_("WARNING: program may create a core file!\n")); 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 (); npth_init ();
gpgrt_set_syscall_clamp (npth_unprotect, npth_protect); gpgrt_set_syscall_clamp (npth_unprotect, npth_protect);
assuan_control (ASSUAN_CONTROL_REINIT_SYSCALL_CLAMP, NULL); assuan_control (ASSUAN_CONTROL_REINIT_SYSCALL_CLAMP, NULL);
/* if (opt.qualsig_approval && !opt.quiet) */ /* if (opt.qualsig_approval && !opt.quiet) */
/* log_info (_("This software has officially been approved to " */ /* log_info (_("This software has officially been approved to " */
/* "create and verify\n" */ /* "create and verify\n" */

View File

@ -116,8 +116,6 @@ struct
int extra_digest_algo; /* A digest algorithm also used for int extra_digest_algo; /* A digest algorithm also used for
verification of signatures. */ 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 skip_verify; /* do not check signatures on data */
int lock_once; /* Keep lock once they are set */ int lock_once; /* Keep lock once they are set */
@ -164,6 +162,10 @@ struct
* mode. */ * mode. */
int require_compliance; int require_compliance;
/* Enable always-trust mode - note that there is also server option
* for this. */
int always_trust;
/* Enable creation of authenticode signatures. */ /* Enable creation of authenticode signatures. */
int authenticode; int authenticode;
@ -269,6 +271,9 @@ struct server_control_s
2 := STEED model. */ 2 := STEED model. */
int offline; /* If true gpgsm won't do any network access. */ 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. */ /* The current time. Used as a helper in certchain.c. */
ksba_isotime_t current_time; ksba_isotime_t current_time;
@ -334,9 +339,8 @@ unsigned long gpgsm_get_short_fingerprint (ksba_cert_t cert,
unsigned long *r_high); unsigned long *r_high);
unsigned char *gpgsm_get_keygrip (ksba_cert_t cert, unsigned char *array); unsigned char *gpgsm_get_keygrip (ksba_cert_t cert, unsigned char *array);
char *gpgsm_get_keygrip_hexstring (ksba_cert_t cert); 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_info (ksba_cert_t cert, unsigned int *nbits,
int gpgsm_get_key_algo_info2 (ksba_cert_t cert, unsigned int *nbits, char **r_curve);
char **r_curve);
int gpgsm_is_ecc_key (ksba_cert_t cert); int gpgsm_is_ecc_key (ksba_cert_t cert);
char *gpgsm_pubkey_algo_string (ksba_cert_t cert, int *r_algoid); char *gpgsm_pubkey_algo_string (ksba_cert_t cert, int *r_algoid);
gcry_mpi_t gpgsm_get_rsa_modulus (ksba_cert_t cert); gcry_mpi_t gpgsm_get_rsa_modulus (ksba_cert_t cert);
@ -388,6 +392,7 @@ int gpgsm_create_cms_signature (ctrl_t ctrl,
#define VALIDATE_FLAG_NO_DIRMNGR 1 #define VALIDATE_FLAG_NO_DIRMNGR 1
#define VALIDATE_FLAG_CHAIN_MODEL 2 #define VALIDATE_FLAG_CHAIN_MODEL 2
#define VALIDATE_FLAG_STEED 4 #define VALIDATE_FLAG_STEED 4
#define VALIDATE_FLAG_BYPASS 8 /* No actual validation. */
gpg_error_t gpgsm_walk_cert_chain (ctrl_t ctrl, gpg_error_t gpgsm_walk_cert_chain (ctrl_t ctrl,
ksba_cert_t start, ksba_cert_t *r_next); ksba_cert_t start, ksba_cert_t *r_next);

View File

@ -54,7 +54,7 @@ struct list_external_parm_s
#define OID_FLAG_SKIP 1 #define OID_FLAG_SKIP 1
/* The extension is a simple UTF8String and should be printed. */ /* The extension is a simple UTF8String and should be printed. */
#define OID_FLAG_UTF8 2 #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 OID_FLAG_HEX 4
/* Define if this specififies a key purpose. */ /* Define if this specififies a key purpose. */
#define OID_FLAG_KP 8 #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.6", "ms-keyRecovery", OID_FLAG_KP },
{ "1.3.6.1.4.1.311.21.19", "ms-dsEmailReplication", OID_FLAG_KP }, { "1.3.6.1.4.1.311.21.19", "ms-dsEmailReplication", OID_FLAG_KP },
/* BSI policies. */
/* Other vendor extensions. */ /* Other vendor extensions. */
{ "1.3.6.1.4.1.30205.13.1.1", "trusted-disk", OID_FLAG_KP }, { "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 }, { "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. */ * number. NBITS is the length of the key in bits. */
static void static void
print_compliance_flags (ksba_cert_t cert, int algo, unsigned int nbits, 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 indent = 0;
int hashalgo; 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 /* 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 * that is not a property of the key but one of the created
* signature. */ * 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)); hashalgo = gcry_md_map_name (ksba_cert_get_digest_algo (cert));
if (gnupg_digest_is_compliant (CO_DE_VS, hashalgo)) 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) if (*truststring)
es_fputs (truststring, fp); 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); es_fprintf (fp, ":%u:%d:%s:", nbits, algo, fpr+24);
ksba_cert_get_validity (cert, 0, t); 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) if (curve)
es_fputs (curve, fp); es_fputs (curve, fp);
es_putc (':', fp); /* End of field 17. */ 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 (':', fp); /* End of field 18. */
es_putc ('\n', fp); es_putc ('\n', fp);

File diff suppressed because it is too large Load Diff

View File

@ -287,6 +287,17 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
ctrl->offline = i; 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")) else if (!strcmp (key, "request-origin"))
{ {
if (!opt.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); gpgsm_release_certlist (ctrl->server_local->signerlist);
ctrl->server_local->recplist = NULL; ctrl->server_local->recplist = NULL;
ctrl->server_local->signerlist = NULL; ctrl->server_local->signerlist = NULL;
ctrl->always_trust = 0;
close_message_fp (ctrl); close_message_fp (ctrl);
assuan_close_input_fd (ctx); assuan_close_input_fd (ctx);
assuan_close_output_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); gpgsm_release_certlist (ctrl->server_local->recplist);
ctrl->server_local->recplist = NULL; ctrl->server_local->recplist = NULL;
ctrl->always_trust = 0;
/* Close and reset the fp and the fds */ /* Close and reset the fp and the fds */
close_message_fp (ctrl); close_message_fp (ctrl);
assuan_close_input_fd (ctx); assuan_close_input_fd (ctx);
@ -1221,7 +1234,8 @@ static const char hlp_getinfo[] =
" agent-check - Return success if the agent is running.\n" " agent-check - Return success if the agent is running.\n"
" cmd_has_option CMD OPT\n" " cmd_has_option CMD OPT\n"
" - Returns OK if the command CMD implements the option 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 static gpg_error_t
cmd_getinfo (assuan_context_t ctx, char *line) 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); 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 else
rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT"); rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");

View File

@ -622,6 +622,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
certlist_t cl; certlist_t cl;
int release_signerlist = 0; int release_signerlist = 0;
int binary_detached = detached && !ctrl->create_pem && !ctrl->create_base64; int binary_detached = detached && !ctrl->create_pem && !ctrl->create_base64;
char *curve = NULL;
audit_set_type (ctrl->audit, AUDIT_TYPE_SIGN); audit_set_type (ctrl->audit, AUDIT_TYPE_SIGN);
@ -760,7 +761,8 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
unsigned int nbits; unsigned int nbits;
int pk_algo; 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; cl->pk_algo = pk_algo;
if (opt.forced_digest_algo) if (opt.forced_digest_algo)
@ -820,8 +822,8 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
goto leave; goto leave;
} }
if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pk_algo, 0, if (!gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pk_algo, 0,
NULL, nbits, NULL)) NULL, nbits, curve))
{ {
char kidstr[10+1]; char kidstr[10+1];
@ -1187,6 +1189,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
gpg_strerror (rc), gpg_strsource (rc) ); gpg_strerror (rc), gpg_strsource (rc) );
if (release_signerlist) if (release_signerlist)
gpgsm_release_certlist (signerlist); gpgsm_release_certlist (signerlist);
xfree (curve);
ksba_cms_release (cms); ksba_cms_release (cms);
gnupg_ksba_destroy_writer (b64writer); gnupg_ksba_destroy_writer (b64writer);
keydb_release (kh); keydb_release (kh);

View File

@ -559,13 +559,21 @@ run_one_test (const char *name, const char *desc, const char *pass,
else if (!certexpected && certstr) else if (!certexpected && certstr)
printresult ("FAIL: %s - no certs expected but got one\n", name); printresult ("FAIL: %s - no certs expected but got one\n", name);
else if (certexpected && certstr && strcmp (certexpected, certstr)) else if (certexpected && certstr && strcmp (certexpected, certstr))
printresult ("FAIL: %s - certs not as expected\n", name); {
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) else if (keyexpected && !resulthash)
printresult ("FAIL: %s - expected key but got none\n", name); printresult ("FAIL: %s - expected key but got none\n", name);
else if (!keyexpected && resulthash) else if (!keyexpected && resulthash)
printresult ("FAIL: %s - key not expected but got one\n", name); printresult ("FAIL: %s - key not expected but got one\n", name);
else if (keyexpected && resulthash && strcmp (keyexpected, resulthash)) else if (keyexpected && resulthash && strcmp (keyexpected, resulthash))
printresult ("FAIL: %s - keys not as expected\n", name); {
printresult ("FAIL: %s - keys not as expected\n", name);
inf ("key(exp)=%s", keyexpected);
inf ("key(got)=%s", resulthash? resulthash:"[null]");
}
else else
{ {
printresult ("PASS: %s\n", name); printresult ("PASS: %s\n", name);

View File

@ -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); pkfpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
pkalgostr = gpgsm_pubkey_algo_string (cert, NULL); 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 /* Remap the ECC algo to the algo we use. Note that EdDSA has
* already been mapped. */ * already been mapped. */
if (pkalgo == GCRY_PK_ECC) if (pkalgo == GCRY_PK_ECC)
@ -486,7 +486,7 @@ gpgsm_verify (ctrl_t ctrl, estream_t in_fp, estream_t data_fp,
/* Check compliance. */ /* Check compliance. */
if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION, if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION,
pkalgo, pkalgoflags, NULL, nbits, NULL)) pkalgo, pkalgoflags, NULL, nbits, pkcurve))
{ {
char kidstr[10+1]; char kidstr[10+1];

View File

@ -99,6 +99,8 @@ EXTRA_DIST = $(XTESTS) $(KEYS) $(CERTS) $(TEST_FILES) \
samplekeys/opensc-test.p12 \ samplekeys/opensc-test.p12 \
samplekeys/t5793-openssl.pfx \ samplekeys/t5793-openssl.pfx \
samplekeys/t5793-test.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.p7m \
samplemsgs/pwri-sample.cbc-2.p7m \ samplemsgs/pwri-sample.cbc-2.p7m \
samplemsgs/pwri-sample.gcm.p7m \ samplemsgs/pwri-sample.gcm.p7m \

View File

@ -1,4 +1,6 @@
# Description-p12 - Machine readable description of our P12 test vectors # 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 Name: ov-user.p12
Desc: Private test key from www.openvalidation.org Desc: Private test key from www.openvalidation.org
@ -30,3 +32,23 @@ Desc: QuaVadis format of t5793-openssl
Pass: test Pass: test
Cert: 80348a438e4b803b99e708da0b7fdd0659dedd15 Cert: 80348a438e4b803b99e708da0b7fdd0659dedd15
Key: c271e44ab4fb19ca1aae71102ea4d7292ccc981d 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 #

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -235,6 +235,7 @@ status_sc_op_failure (gpg_error_t err)
gnupg_status_printf (STATUS_SC_OP_FAILURE, "1"); gnupg_status_printf (STATUS_SC_OP_FAILURE, "1");
break; break;
case GPG_ERR_BAD_PIN: case GPG_ERR_BAD_PIN:
case GPG_ERR_BAD_RESET_CODE:
gnupg_status_printf (STATUS_SC_OP_FAILURE, "2"); gnupg_status_printf (STATUS_SC_OP_FAILURE, "2");
break; break;
default: default:

View File

@ -332,6 +332,8 @@ yubikey_commands (card_info_t info, estream_t fp, int argc, const char *argv[])
cmd = ykDISABLE; cmd = ykDISABLE;
else else
{ {
log_info ("Please use \"%s\" to list the available sub-commands\n",
"help yubikey");
err = gpg_error (GPG_ERR_UNKNOWN_COMMAND); err = gpg_error (GPG_ERR_UNKNOWN_COMMAND);
goto leave; goto leave;
} }