aboutsummaryrefslogtreecommitdiffstats
path: root/sm
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2023-11-07 19:07:45 +0000
committerWerner Koch <[email protected]>2023-11-07 19:38:27 +0000
commit387ee7dcbd77d19687af967901ed4818cbdb8b3c (patch)
tree3fc63cd303b2d07454794064e4e6528df2dbf42c /sm
parentdoc: Use the em dash to mark a break in a sentence. (diff)
parentw32: Use utf8 for the asctimestamp function. (diff)
downloadgnupg-387ee7dcbd77d19687af967901ed4818cbdb8b3c.tar.gz
gnupg-387ee7dcbd77d19687af967901ed4818cbdb8b3c.zip
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.
Diffstat (limited to 'sm')
-rw-r--r--sm/certchain.c14
-rw-r--r--sm/certlist.c8
-rw-r--r--sm/decrypt.c9
-rw-r--r--sm/encrypt.c10
-rw-r--r--sm/export.c2
-rw-r--r--sm/fingerprint.c11
-rw-r--r--sm/gpgsm.c13
-rw-r--r--sm/gpgsm.h15
-rw-r--r--sm/keylist.c12
-rw-r--r--sm/minip12.c1040
-rw-r--r--sm/server.c21
-rw-r--r--sm/sign.c9
-rw-r--r--sm/t-minip12.c12
-rw-r--r--sm/verify.c4
14 files changed, 409 insertions, 771 deletions
diff --git a/sm/certchain.c b/sm/certchain.c
index 84dbed696..9d0fe684b 100644
--- a/sm/certchain.c
+++ b/sm/certchain.c
@@ -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);
- rc = do_validate_chain (ctrl, cert, checktime,
- r_exptime, listmode, listfp, flags,
- &rootca_flags);
+ if ((flags & VALIDATE_FLAG_BYPASS))
+ {
+ *retflags |= VALIDATE_FLAG_BYPASS;
+ rc = 0;
+ }
+ else
+ rc = do_validate_chain (ctrl, cert, checktime,
+ r_exptime, listmode, listfp, flags,
+ &rootca_flags);
if (!rc && (flags & 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)
do_list (0, listmode, listfp, _("validation model used: %s"),
+ (*retflags & VALIDATE_FLAG_BYPASS)?
+ "bypass" :
(*retflags & VALIDATE_FLAG_STEED)?
"steed" :
(*retflags & VALIDATE_FLAG_CHAIN_MODEL)?
diff --git a/sm/certlist.c b/sm/certlist.c
index fdf31a198..53d90ac30 100644
--- a/sm/certlist.c
+++ b/sm/certlist.c
@@ -448,6 +448,11 @@ gpgsm_add_to_certlist (ctrl_t ctrl, const char *name, int secret,
if (!rc && !is_cert_in_certlist (cert, *listaddr))
{
+ unsigned int valflags = 0;
+
+ if (!secret && (opt.always_trust || ctrl->always_trust))
+ valflags |= VALIDATE_FLAG_BYPASS;
+
if (!rc && secret)
{
char *p;
@@ -461,9 +466,10 @@ gpgsm_add_to_certlist (ctrl_t ctrl, const char *name, int secret,
xfree (p);
}
}
+
if (!rc)
rc = gpgsm_validate_chain (ctrl, cert, GNUPG_ISOTIME_NONE, NULL,
- 0, NULL, 0, NULL);
+ 0, NULL, valflags, NULL);
if (!rc)
{
certlist_t cl = xtrycalloc (1, sizeof *cl);
diff --git a/sm/decrypt.c b/sm/decrypt.c
index a30eafc55..6121fd278 100644
--- a/sm/decrypt.c
+++ b/sm/decrypt.c
@@ -1064,6 +1064,7 @@ gpgsm_decrypt (ctrl_t ctrl, estream_t in_fp, estream_t out_fp)
KEYDB_HANDLE kh;
int recp;
struct decrypt_filter_parm_s dfparm;
+ char *curve = NULL;
memset (&dfparm, 0, sizeof dfparm);
@@ -1300,14 +1301,15 @@ gpgsm_decrypt (ctrl_t ctrl, estream_t in_fp, estream_t out_fp)
pkfpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
pkalgostr = gpgsm_pubkey_algo_string (cert, NULL);
- pk_algo = gpgsm_get_key_algo_info (cert, &nbits);
+ xfree (curve);
+ pk_algo = gpgsm_get_key_algo_info (cert, &nbits, &curve);
if (!opt.quiet)
log_info (_("encrypted to %s key %s\n"), pkalgostr, pkfpr);
/* Check compliance. */
if (!gnupg_pk_is_allowed (opt.compliance,
PK_USE_DECRYPTION,
- pk_algo, 0, NULL, nbits, NULL))
+ pk_algo, 0, NULL, nbits, curve))
{
char kidstr[10+1];
@@ -1325,7 +1327,7 @@ gpgsm_decrypt (ctrl_t ctrl, estream_t in_fp, estream_t out_fp)
dfparm.is_de_vs =
(dfparm.is_de_vs
&& gnupg_pk_is_compliant (CO_DE_VS, pk_algo, 0,
- NULL, nbits, NULL));
+ NULL, nbits, curve));
oops:
if (rc)
@@ -1503,6 +1505,7 @@ gpgsm_decrypt (ctrl_t ctrl, estream_t in_fp, estream_t out_fp)
log_error ("message decryption failed: %s <%s>\n",
gpg_strerror (rc), gpg_strsource (rc));
}
+ xfree (curve);
ksba_cms_release (cms);
gnupg_ksba_destroy_reader (b64reader);
gnupg_ksba_destroy_writer (b64writer);
diff --git a/sm/encrypt.c b/sm/encrypt.c
index 923fdfd99..9113028db 100644
--- a/sm/encrypt.c
+++ b/sm/encrypt.c
@@ -749,11 +749,12 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
unsigned char *encval;
unsigned int nbits;
int pk_algo;
+ char *curve = NULL;
/* Check compliance. */
- pk_algo = gpgsm_get_key_algo_info (cl->cert, &nbits);
+ pk_algo = gpgsm_get_key_algo_info (cl->cert, &nbits, &curve);
if (!gnupg_pk_is_compliant (opt.compliance, pk_algo, 0,
- NULL, nbits, NULL))
+ NULL, nbits, curve))
{
char kidstr[10+1];
@@ -768,9 +769,12 @@ gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, estream_t data_fp,
/* Fixme: When adding ECC we need to provide the curvename and
* the key to gnupg_pk_is_compliant. */
if (compliant
- && !gnupg_pk_is_compliant (CO_DE_VS, pk_algo, 0, NULL, nbits, NULL))
+ && !gnupg_pk_is_compliant (CO_DE_VS, pk_algo, 0, NULL, nbits, curve))
compliant = 0;
+ xfree (curve);
+ curve = NULL;
+
rc = encrypt_dek (dek, cl->cert, pk_algo, &encval);
if (rc)
{
diff --git a/sm/export.c b/sm/export.c
index 54893b54d..a6ba40f5d 100644
--- a/sm/export.c
+++ b/sm/export.c
@@ -430,7 +430,7 @@ gpgsm_p12_export (ctrl_t ctrl, const char *name, estream_t stream, int rawmode)
if (rawmode == 0)
ctrl->pem_name = "PKCS12";
- else if (gpgsm_get_key_algo_info (cert, NULL) == GCRY_PK_ECC)
+ else if (gpgsm_get_key_algo_info (cert, NULL, NULL) == GCRY_PK_ECC)
ctrl->pem_name = "EC PRIVATE KEY";
else if (rawmode == 1)
ctrl->pem_name = "PRIVATE KEY";
diff --git a/sm/fingerprint.c b/sm/fingerprint.c
index 5f3f6f51f..375a8647e 100644
--- a/sm/fingerprint.c
+++ b/sm/fingerprint.c
@@ -222,7 +222,7 @@ gpgsm_get_keygrip_hexstring (ksba_cert_t cert)
* algorithm is used the name or OID of the curve is stored there; the
* caller needs to free this value. */
int
-gpgsm_get_key_algo_info2 (ksba_cert_t cert, unsigned int *nbits, char **r_curve)
+gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits, char **r_curve)
{
gcry_sexp_t s_pkey;
int rc;
@@ -299,18 +299,11 @@ gpgsm_get_key_algo_info2 (ksba_cert_t cert, unsigned int *nbits, char **r_curve)
}
-int
-gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits)
-{
- return gpgsm_get_key_algo_info2 (cert, nbits, NULL);
-}
-
-
/* Return true if CERT is an ECC key. */
int
gpgsm_is_ecc_key (ksba_cert_t cert)
{
- return GCRY_PK_ECC == gpgsm_get_key_algo_info2 (cert, NULL, NULL);
+ return GCRY_PK_ECC == gpgsm_get_key_algo_info (cert, NULL, NULL);
}
diff --git a/sm/gpgsm.c b/sm/gpgsm.c
index 74d23e5c1..4b6c353a0 100644
--- a/sm/gpgsm.c
+++ b/sm/gpgsm.c
@@ -215,6 +215,7 @@ enum cmd_and_opt_values {
oRequireCompliance,
oCompatibilityFlags,
oKbxBufferSize,
+ oAlwaysTrust,
oNoAutostart
};
@@ -417,6 +418,7 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_s_n (oIgnoreTimeConflict, "ignore-time-conflict", "@"),
ARGPARSE_s_n (oNoRandomSeedFile, "no-random-seed-file", "@"),
ARGPARSE_s_n (oRequireCompliance, "require-compliance", "@"),
+ ARGPARSE_s_n (oAlwaysTrust, "always-trust", "@"),
ARGPARSE_header (NULL, N_("Options for unattended use")),
@@ -1494,6 +1496,7 @@ main ( int argc, char **argv)
case oMinRSALength: opt.min_rsa_length = pargs.r.ret_ulong; break;
case oRequireCompliance: opt.require_compliance = 1; break;
+ case oAlwaysTrust: opt.always_trust = 1; break;
case oKbxBufferSize:
keybox_set_buffersize (pargs.r.ret_ulong, 0);
@@ -1583,10 +1586,20 @@ main ( int argc, char **argv)
if (may_coredump && !opt.quiet)
log_info (_("WARNING: program may create a core file!\n"));
+ if (opt.require_compliance && opt.always_trust)
+ {
+ opt.always_trust = 0;
+ if (opt.quiet)
+ log_info (_("WARNING: %s overrides %s\n"),
+ "--require-compliance","--always-trust");
+ }
+
+
npth_init ();
gpgrt_set_syscall_clamp (npth_unprotect, npth_protect);
assuan_control (ASSUAN_CONTROL_REINIT_SYSCALL_CLAMP, NULL);
+
/* if (opt.qualsig_approval && !opt.quiet) */
/* log_info (_("This software has officially been approved to " */
/* "create and verify\n" */
diff --git a/sm/gpgsm.h b/sm/gpgsm.h
index 93a80631f..eb9ba9f17 100644
--- a/sm/gpgsm.h
+++ b/sm/gpgsm.h
@@ -116,8 +116,6 @@ struct
int extra_digest_algo; /* A digest algorithm also used for
verification of signatures. */
- int always_trust; /* Trust the given keys even if there is no
- valid certification chain */
int skip_verify; /* do not check signatures on data */
int lock_once; /* Keep lock once they are set */
@@ -164,6 +162,10 @@ struct
* mode. */
int require_compliance;
+ /* Enable always-trust mode - note that there is also server option
+ * for this. */
+ int always_trust;
+
/* Enable creation of authenticode signatures. */
int authenticode;
@@ -269,6 +271,9 @@ struct server_control_s
2 := STEED model. */
int offline; /* If true gpgsm won't do any network access. */
+ int always_trust; /* True in always-trust mode; see also
+ * opt.always-trust. */
+
/* The current time. Used as a helper in certchain.c. */
ksba_isotime_t current_time;
@@ -334,9 +339,8 @@ unsigned long gpgsm_get_short_fingerprint (ksba_cert_t cert,
unsigned long *r_high);
unsigned char *gpgsm_get_keygrip (ksba_cert_t cert, unsigned char *array);
char *gpgsm_get_keygrip_hexstring (ksba_cert_t cert);
-int gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits);
-int gpgsm_get_key_algo_info2 (ksba_cert_t cert, unsigned int *nbits,
- char **r_curve);
+int gpgsm_get_key_algo_info (ksba_cert_t cert, unsigned int *nbits,
+ char **r_curve);
int gpgsm_is_ecc_key (ksba_cert_t cert);
char *gpgsm_pubkey_algo_string (ksba_cert_t cert, int *r_algoid);
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_CHAIN_MODEL 2
#define VALIDATE_FLAG_STEED 4
+#define VALIDATE_FLAG_BYPASS 8 /* No actual validation. */
gpg_error_t gpgsm_walk_cert_chain (ctrl_t ctrl,
ksba_cert_t start, ksba_cert_t *r_next);
diff --git a/sm/keylist.c b/sm/keylist.c
index fabd82224..ed1b74729 100644
--- a/sm/keylist.c
+++ b/sm/keylist.c
@@ -54,7 +54,7 @@ struct list_external_parm_s
#define OID_FLAG_SKIP 1
/* The extension is a simple UTF8String and should be printed. */
#define OID_FLAG_UTF8 2
-/* The extension can be trnted as a hex string. */
+/* The extension can be printed as a hex string. */
#define OID_FLAG_HEX 4
/* Define if this specififies a key purpose. */
#define OID_FLAG_KP 8
@@ -208,6 +208,8 @@ static struct
{ "1.3.6.1.4.1.311.21.6", "ms-keyRecovery", OID_FLAG_KP },
{ "1.3.6.1.4.1.311.21.19", "ms-dsEmailReplication", OID_FLAG_KP },
+ /* BSI policies. */
+
/* Other vendor extensions. */
{ "1.3.6.1.4.1.30205.13.1.1", "trusted-disk", OID_FLAG_KP },
{ "1.2.840.113583.1.1.5", "pdfAuthenticDocumentsTrust", OID_FLAG_KP },
@@ -428,7 +430,7 @@ email_kludge (const char *name)
* number. NBITS is the length of the key in bits. */
static void
print_compliance_flags (ksba_cert_t cert, int algo, unsigned int nbits,
- estream_t fp)
+ const char *curvename, estream_t fp)
{
int indent = 0;
int hashalgo;
@@ -436,7 +438,7 @@ print_compliance_flags (ksba_cert_t cert, int algo, unsigned int nbits,
/* Note that we do not need to test for PK_ALGO_FLAG_RSAPSS because
* that is not a property of the key but one of the created
* signature. */
- if (gnupg_pk_is_compliant (CO_DE_VS, algo, 0, NULL, nbits, NULL))
+ if (gnupg_pk_is_compliant (CO_DE_VS, algo, 0, NULL, nbits, curvename))
{
hashalgo = gcry_md_map_name (ksba_cert_get_digest_algo (cert));
if (gnupg_digest_is_compliant (CO_DE_VS, hashalgo))
@@ -560,7 +562,7 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
if (*truststring)
es_fputs (truststring, fp);
- algo = gpgsm_get_key_algo_info2 (cert, &nbits, &curve);
+ algo = gpgsm_get_key_algo_info (cert, &nbits, &curve);
es_fprintf (fp, ":%u:%d:%s:", nbits, algo, fpr+24);
ksba_cert_get_validity (cert, 0, t);
@@ -627,7 +629,7 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
if (curve)
es_fputs (curve, fp);
es_putc (':', fp); /* End of field 17. */
- print_compliance_flags (cert, algo, nbits, fp);
+ print_compliance_flags (cert, algo, nbits, curve, fp);
es_putc (':', fp); /* End of field 18. */
es_putc ('\n', fp);
diff --git a/sm/minip12.c b/sm/minip12.c
index 265243f3e..ae81d821b 100644
--- a/sm/minip12.c
+++ b/sm/minip12.c
@@ -50,6 +50,8 @@
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
#endif
+/* Enable the next macro to dump stuff for debugging. */
+#undef ENABLE_DER_STRUCT_DUMPING
static unsigned char const oid_data[9] = {
@@ -81,6 +83,17 @@ static unsigned char const oid_aes128_CBC[9] = {
static unsigned char const oid_aes256_CBC[9] = {
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x2A };
+static unsigned char const oid_hmacWithSHA1[8] = {
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x07 };
+static unsigned char const oid_hmacWithSHA224[8] = {
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x08 };
+static unsigned char const oid_hmacWithSHA256[8] = {
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x09 };
+static unsigned char const oid_hmacWithSHA384[8] = {
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x0A };
+static unsigned char const oid_hmacWithSHA512[8] = {
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x0B };
+
static unsigned char const oid_rsaEncryption[9] = {
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 };
static unsigned char const oid_pcPublicKey[7] = {
@@ -111,6 +124,8 @@ static unsigned char const data_mactemplate[51] = {
#define DATA_MACTEMPLATE_MAC_OFF 17
#define DATA_MACTEMPLATE_SALT_OFF 39
+/* Note that the BMP String in this template reads:
+ * "GnuPG exported certificate ffffffff" */
static unsigned char const data_attrtemplate[106] = {
0x31, 0x7c, 0x30, 0x55, 0x06, 0x09, 0x2a, 0x86,
0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x14, 0x31,
@@ -135,55 +150,6 @@ struct buffer_s
};
-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 */
-};
-
-
-#define TLV_MAX_DEPTH 20
-
-
-struct bufferlist_s
-{
- struct bufferlist_s *next;
- char *buffer;
-};
-
-
-/* An object to control the ASN.1 parsing. */
-struct tlv_ctx_s
-{
- /* The current buffer we are working on and its length. */
- const unsigned char *buffer;
- size_t bufsize;
-
- size_t offset; /* The current offset into this buffer. */
- 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. */
-
- struct bufferlist_s *bufferlist; /* To keep track of amlloced buffers. */
-
- unsigned int pop_count;/* Number of pops by tlv_next. */
- 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 offset; /* Saved value of OFFSET. */
- int in_ndef; /* Saved IN_NDEF flag. */
- } stack[TLV_MAX_DEPTH];
-};
-
-
/* Parser communication object. */
struct p12_parse_ctx_s
{
@@ -208,9 +174,6 @@ struct p12_parse_ctx_s
static int opt_verbose;
-static unsigned char *cram_octet_string (const unsigned char *input,
- size_t length, size_t *r_newlength);
-
@@ -223,15 +186,29 @@ p12_set_verbosity (int verbose, int debug)
}
-static void
-dump_tag_info (const char *text, struct tag_info *ti)
+static int
+digest_algo_from_oid (unsigned char const *oid, size_t oidlen)
{
- if (opt_verbose > 1)
- log_debug ("p12_parse(%s): ti.class=%d tag=%lu len=%zu nhdr=%zu %s%s\n",
- text,
- ti->class, ti->tag, ti->length, ti->nhdr,
- ti->is_constructed?" cons":"",
- ti->ndef?" ndef":"");
+ int algo;
+
+ if (oidlen == DIM(oid_hmacWithSHA1) &&
+ !memcmp (oid, oid_hmacWithSHA1, oidlen))
+ algo = GCRY_MD_SHA1;
+ else if (oidlen == DIM(oid_hmacWithSHA224) &&
+ !memcmp (oid, oid_hmacWithSHA224, oidlen))
+ algo = GCRY_MD_SHA224;
+ else if (oidlen == DIM(oid_hmacWithSHA256) &&
+ !memcmp (oid, oid_hmacWithSHA256, oidlen))
+ algo = GCRY_MD_SHA256;
+ else if (oidlen == DIM(oid_hmacWithSHA384) &&
+ !memcmp (oid, oid_hmacWithSHA384, oidlen))
+ algo = GCRY_MD_SHA384;
+ else if (oidlen == DIM(oid_hmacWithSHA512) &&
+ !memcmp (oid, oid_hmacWithSHA512, oidlen))
+ algo = GCRY_MD_SHA512;
+ else
+ algo = 0;
+ return algo;
}
@@ -327,538 +304,6 @@ builder_add_mpi (tlv_builder_t tb, int class, int tag, gcry_mpi_t mpi,
}
-
-/* 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;
-}
-
-
-/* Create a new TLV object. */
-static struct tlv_ctx_s *
-tlv_new (const unsigned char *buffer, size_t bufsize)
-{
- struct tlv_ctx_s *tlv;
- tlv = xtrycalloc (1, sizeof *tlv);
- if (tlv)
- {
- tlv->buffer = buffer;
- tlv->bufsize = bufsize;
- }
- 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
-tlv_register_buffer (struct tlv_ctx_s *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;
-}
-
-
-static void
-tlv_release (struct tlv_ctx_s *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 tlv_next and tlv_peek. */
-static gpg_error_t
-_tlv_peek (struct tlv_ctx_s *tlv, size_t *r_n)
-{
- const unsigned char *p;
-
- if (tlv->offset > tlv->bufsize)
- return gpg_error (GPG_ERR_BUG);
- p = tlv->buffer + tlv->offset;
- *r_n = tlv->bufsize - tlv->offset;
- return parse_tag (&p, r_n, &tlv->ti);
-}
-
-
-/* Helper for tlv_expect_sequence and tlv_expect_context_tag. */
-static gpg_error_t
-_tlv_push (struct tlv_ctx_s *tlv)
-{
- 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].offset = tlv->offset;
- tlv->stack[tlv->stacklen].in_ndef = tlv->in_ndef;
- tlv->stacklen++;
- tlv->buffer += tlv->offset;
- tlv->bufsize = tlv->ti.length;
- tlv->offset = 0;
- tlv->in_ndef = tlv->ti.ndef;
- return 0;
-}
-
-
-/* Helper for tlv_next. */
-static gpg_error_t
-_tlv_pop (struct tlv_ctx_s *tlv)
-{
- size_t saveoff;
-
- if (!tlv->stacklen)
- return gpg_error (GPG_ERR_EOF);
-
- saveoff = tlv->offset;
-
- tlv->stacklen--;
- tlv->buffer = tlv->stack[tlv->stacklen].buffer;
- tlv->bufsize = tlv->stack[tlv->stacklen].bufsize;
- tlv->offset = tlv->stack[tlv->stacklen].offset;
- tlv->in_ndef = tlv->stack[tlv->stacklen].in_ndef;
-
- /* Move offset of the container to the end of the container. */
- tlv->offset += saveoff;
- if (tlv->offset > tlv->bufsize)
- return gpg_error (GPG_ERR_INV_BER);
-
- tlv->pop_count++;
- return 0;
-}
-
-
-/* Parse the next tag and value. Also detect the end of a container;
- * tlv_popped() can be used to detect this. */
-static gpg_error_t
-tlv_next (struct tlv_ctx_s *tlv)
-{
- gpg_error_t err;
- size_t n;
-
- tlv->pop_count = 0;
- tlv->lasterr = 0;
- tlv->lastfunc = __func__;
- if (tlv->pending)
- {
- tlv->pending = 0;
- return 0;
- }
-
- if (!tlv->in_ndef && tlv->offset == tlv->bufsize)
- {
- /* We are at the end of a container. Pop the stack. */
- do
- err = _tlv_pop (tlv);
- while (!err && !tlv->in_ndef && tlv->offset == tlv->bufsize);
- if (err)
- return (tlv->lasterr = err);
- }
-
- err = _tlv_peek (tlv, &n);
- if (err)
- return err;
- if (tlv->in_ndef && (tlv->ti.class == CLASS_UNIVERSAL
- && !tlv->ti.tag && !tlv->ti.is_constructed))
- {
- /* End tag while in ndef container. Skip the tag, and pop. */
- tlv->offset += n - (tlv->bufsize - tlv->offset);
- err = _tlv_pop (tlv);
- /* FIXME: We need to peek whether there is another end tag and
- * pop again. We can't modify the TLV object, though. */
- if (err)
- return (tlv->lasterr = err);
- }
-
- /* Set offset to the value of the TLV. */
- tlv->offset += tlv->bufsize - tlv->offset - n;
- dump_tag_info ("tlv_next", &tlv->ti);
- return 0;
-}
-
-
-/* Return the current neting level of the TLV object. */
-static unsigned int
-tlv_level (struct tlv_ctx_s *tlv)
-{
- return tlv->stacklen;
-}
-
-
-/* If called right after tlv_next the number of container levels
- * popped are returned. */
-static unsigned int
-tlv_popped (struct tlv_ctx_s *tlv)
-{
- return tlv->pop_count;
-}
-
-
-/* Set a flag to indicate that the last tlv_next has not yet been
- * consumed. */
-static void
-tlv_set_pending (struct tlv_ctx_s *tlv)
-{
- tlv->pending = 1;
-}
-
-
-/* Skip over the value of the current tag. */
-static void
-tlv_skip (struct tlv_ctx_s *tlv)
-{
- tlv->lastfunc = __func__;
- tlv->offset += tlv->ti.length;
-}
-
-
-/* Expect that the current tag is a sequence and setup the context for
- * processing. */
-static gpg_error_t
-tlv_expect_sequence (struct tlv_ctx_s *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);
-}
-
-/* Variant of tlv_expect_sequence to be used for the ouyter sequence
- * of an object which might have padding after the ASN.1 data. */
-static gpg_error_t
-tlv_expect_top_sequence (struct tlv_ctx_s *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));
- tlv->bufsize = tlv->ti.nhdr + tlv->ti.length;
- 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. */
-static gpg_error_t
-tlv_expect_context_tag (struct tlv_ctx_s *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. */
-static gpg_error_t
-tlv_expect_set (struct tlv_ctx_s *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. */
-static gpg_error_t
-tlv_expect_object (struct tlv_ctx_s *tlv, int class, int tag,
- unsigned char const **r_data, size_t *r_datalen)
-{
- gpg_error_t err;
- const unsigned char *p;
-
- tlv->lastfunc = __func__;
- if (!(tlv->ti.class == class && tlv->ti.tag == tag))
- return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
- p = tlv->buffer + tlv->offset;
- if (!tlv->ti.length)
- return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
-
- if (class == CLASS_CONTEXT && tag == 0 && tlv->ti.is_constructed)
- {
- char *newbuffer;
-
- newbuffer = cram_octet_string (p, tlv->ti.length, r_datalen);
- if (!newbuffer)
- return (tlv->lasterr = gpg_error (GPG_ERR_BAD_BER));
- err = tlv_register_buffer (tlv, newbuffer);
- if (err)
- {
- xfree (newbuffer);
- return (tlv->lasterr = err);
- }
- *r_data = newbuffer;
- }
- else
- {
- *r_data = p;
- *r_datalen = tlv->ti.length;
- }
-
- tlv->offset += 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. */
-static gpg_error_t
-tlv_expect_octet_string (struct tlv_ctx_s *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 + tlv->offset;
- if (!(n=tlv->ti.length))
- return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
-
- if (encapsulates && tlv->ti.is_constructed)
- {
- char *newbuffer;
-
- newbuffer = cram_octet_string (p, n, r_datalen);
- if (!newbuffer)
- return (tlv->lasterr = gpg_error (GPG_ERR_BAD_BER));
- err = tlv_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);
-
- tlv->offset += tlv->ti.length;
- return 0;
-}
-
-
-/* Expect a NULL tag. */
-static gpg_error_t
-tlv_expect_null (struct tlv_ctx_s *tlv)
-{
- tlv->lastfunc = __func__;
- if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_NULL
- && !tlv->ti.is_constructed && !tlv->ti.length))
- return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
- 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. */
-static gpg_error_t
-tlv_expect_integer (struct tlv_ctx_s *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 + tlv->offset;
- 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;
- tlv->offset += 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 doe 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 */
-static gpg_error_t
-tlv_expect_mpinteger (struct tlv_ctx_s *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 + tlv->offset;
- if (!(n=tlv->ti.length))
- return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
-
- tlv->offset += 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);
-}
-
-
-/* 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. */
-static gpg_error_t
-tlv_expect_object_id (struct tlv_ctx_s *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 + tlv->offset;
- if (!(n=tlv->ti.length))
- return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
-
- *r_oid = p;
- *r_oidlen = tlv->ti.length;
- tlv->offset += 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 = gcry_malloc (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:
- gcry_free (output);
- return NULL;
-}
-
-
static int
string_to_key (int id, char *salt, size_t saltlen, int iter, const char *pw,
int req_keylen, unsigned char *keybuf)
@@ -988,13 +433,14 @@ set_key_iv (gcry_cipher_hd_t chd, char *salt, size_t saltlen, int iter,
static int
set_key_iv_pbes2 (gcry_cipher_hd_t chd, char *salt, size_t saltlen, int iter,
- const void *iv, size_t ivlen, const char *pw, int algo)
+ const void *iv, size_t ivlen, const char *pw,
+ int cipher_algo, int digest_algo)
{
unsigned char *keybuf;
size_t keylen;
int rc;
- keylen = gcry_cipher_get_algo_keylen (algo);
+ keylen = gcry_cipher_get_algo_keylen (cipher_algo);
if (!keylen)
return -1;
keybuf = gcry_malloc_secure (keylen);
@@ -1002,7 +448,7 @@ set_key_iv_pbes2 (gcry_cipher_hd_t chd, char *salt, size_t saltlen, int iter,
return -1;
rc = gcry_kdf_derive (pw, strlen (pw),
- GCRY_KDF_PBKDF2, GCRY_MD_SHA1,
+ GCRY_KDF_PBKDF2, digest_algo,
salt, saltlen, iter, keylen, keybuf);
if (rc)
{
@@ -1033,7 +479,7 @@ set_key_iv_pbes2 (gcry_cipher_hd_t chd, char *salt, size_t saltlen, int iter,
static void
crypt_block (unsigned char *buffer, size_t length, char *salt, size_t saltlen,
int iter, const void *iv, size_t ivlen,
- const char *pw, int cipher_algo, int encrypt)
+ const char *pw, int cipher_algo, int digest_algo, int encrypt)
{
gcry_cipher_hd_t chd;
int rc;
@@ -1047,7 +493,8 @@ crypt_block (unsigned char *buffer, size_t length, char *salt, size_t saltlen,
}
if ((cipher_algo == GCRY_CIPHER_AES128 || cipher_algo == GCRY_CIPHER_AES256)
- ? set_key_iv_pbes2 (chd, salt, saltlen, iter, iv, ivlen, pw, cipher_algo)
+ ? set_key_iv_pbes2 (chd, salt, saltlen, iter, iv, ivlen, pw,
+ cipher_algo, digest_algo)
: set_key_iv (chd, salt, saltlen, iter, pw,
cipher_algo == GCRY_CIPHER_RFC2268_40? 5:24))
{
@@ -1078,13 +525,13 @@ crypt_block (unsigned char *buffer, size_t length, char *salt, size_t saltlen,
and CIPHER_ALGO is the algorithm id to use. CHECK_FNC is a
function called with the plaintext and used to check whether the
decryption succeeded; i.e. that a correct passphrase has been
- given. That function shall return true if the decryption has likely
- succeeded. */
-static void
+ given. The function returns the length of the unpadded plaintext
+ or 0 on error. */
+static size_t
decrypt_block (const void *ciphertext, unsigned char *plaintext, size_t length,
char *salt, size_t saltlen,
int iter, const void *iv, size_t ivlen,
- const char *pw, int cipher_algo,
+ const char *pw, int cipher_algo, int digest_algo,
int (*check_fnc) (const void *, size_t))
{
static const char * const charsets[] = {
@@ -1109,6 +556,7 @@ decrypt_block (const void *ciphertext, unsigned char *plaintext, size_t length,
int charsetidx = 0;
char *convertedpw = NULL; /* Malloced and converted password or NULL. */
size_t convertedpwsize = 0; /* Allocated length. */
+ size_t plainlen = 0;
for (charsetidx=0; charsets[charsetidx]; charsetidx++)
{
@@ -1156,11 +604,33 @@ decrypt_block (const void *ciphertext, unsigned char *plaintext, size_t length,
}
memcpy (plaintext, ciphertext, length);
crypt_block (plaintext, length, salt, saltlen, iter, iv, ivlen,
- convertedpw? convertedpw:pw, cipher_algo, 0);
+ convertedpw? convertedpw:pw, cipher_algo, digest_algo, 0);
if (check_fnc (plaintext, length))
- break; /* Decryption succeeded. */
+ {
+ /* Strip the pkcs#7 padding. */
+ if (length)
+ {
+ int n, i;
+
+ n = plaintext[length-1];
+ if (n >= length || n > 16)
+ log_info ("decryption failed; invalid padding size\n");
+ else
+ {
+ for (i=1; i < n; i++)
+ if (plaintext[length-i-1] != n)
+ break;
+ if (i < n)
+ log_info ("decryption failed; invalid padding octet\n");
+ else
+ plainlen = length - n;
+ }
+ }
+ break; /* Decryption probably succeeded. */
+ }
}
gcry_free (convertedpw);
+ return plainlen;
}
@@ -1173,19 +643,21 @@ bag_decrypted_data_p (const void *plaintext, size_t length)
const unsigned char *p = plaintext;
size_t n = length;
- /* { */
- /* # warning debug code is enabled */
- /* FILE *fp = fopen ("tmp-minip12-plain-data.der", "wb"); */
- /* if (!fp || fwrite (p, n, 1, fp) != 1) */
- /* exit (2); */
- /* fclose (fp); */
- /* } */
-
- if (parse_tag (&p, &n, &ti))
+#ifdef ENABLE_DER_STRUCT_DUMPING
+ {
+ # warning debug code is enabled
+ FILE *fp = fopen ("tmp-minip12-plain-data.der", "wb");
+ if (!fp || fwrite (p, n, 1, fp) != 1)
+ exit (2);
+ fclose (fp);
+ }
+#endif /*ENABLE_DER_STRUCT_DUMPING*/
+
+ if (tlv_parse_tag (&p, &n, &ti))
return 0;
if (ti.class || ti.tag != TAG_SEQUENCE)
return 0;
- if (parse_tag (&p, &n, &ti))
+ if (tlv_parse_tag (&p, &n, &ti))
return 0;
return 1;
@@ -1193,7 +665,7 @@ bag_decrypted_data_p (const void *plaintext, size_t length)
static int
-parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
+parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, tlv_parser_t tlv)
{
gpg_error_t err = 0;
const char *where;
@@ -1213,7 +685,8 @@ parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
int keyelem_count;
int renewed_tlv = 0;
int loopcount;
- unsigned int startlevel;
+ unsigned int startlevel, startlevel2;
+ int digest_algo = GCRY_MD_SHA1;
where = "bag.encryptedData";
if (opt_verbose)
@@ -1283,6 +756,8 @@ parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
/*FIXME: This code is duplicated in parse_shrouded_key_bag. */
if (is_pbes2)
{
+ size_t parmlen; /* Remaining length of the parameter sequence. */
+
where = "pkcs5PBES2-params";
if (tlv_next (tlv))
goto bailout;
@@ -1309,11 +784,13 @@ parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
goto bailout;
if (tlv_expect_sequence (tlv))
goto bailout;
+ parmlen = tlv_parser_tag_length (tlv, 0);
if (tlv_next (tlv))
goto bailout;
if (tlv_expect_octet_string (tlv, 0, &data, &datalen))
goto bailout;
+ parmlen -= tlv_parser_tag_length (tlv, 1);
if (datalen < 8 || datalen > sizeof salt)
{
log_info ("bad length of salt (%zu)\n", datalen);
@@ -1327,6 +804,7 @@ parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
goto bailout;
if ((err = tlv_expect_integer (tlv, &intval)))
goto bailout;
+ parmlen -= tlv_parser_tag_length (tlv, 1);
if (!intval) /* Not a valid iteration count. */
{
err = gpg_error (GPG_ERR_INV_VALUE);
@@ -1334,8 +812,36 @@ parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
}
iter = intval;
- /* Note: We don't support the optional parameters but assume
- that the algorithmIdentifier follows. */
+ if (parmlen > 2) /* There is the optional prf. */
+ {
+ if (tlv_next (tlv))
+ goto bailout;
+ if (tlv_expect_sequence (tlv))
+ goto bailout;
+ if (tlv_next (tlv))
+ goto bailout;
+ if (tlv_expect_object_id (tlv, &oid, &oidlen))
+ goto bailout;
+ digest_algo = digest_algo_from_oid (oid, oidlen);
+ if (!digest_algo)
+ {
+ gpgrt_log_printhex (oid, oidlen, "kdf digest algo:");
+ err = gpg_error (GPG_ERR_DIGEST_ALGO);
+ goto bailout;
+ }
+ if (opt_verbose > 1)
+ log_debug ("kdf digest algo = %d\n", digest_algo);
+
+ if (tlv_peek_null (tlv))
+ {
+ /* Read the optional Null tag. */
+ if (tlv_next (tlv))
+ goto bailout;
+ }
+ }
+ else
+ digest_algo = GCRY_MD_SHA1;
+
if (tlv_next (tlv))
goto bailout;
if (tlv_expect_sequence (tlv))
@@ -1421,15 +927,21 @@ parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
log_error ("error allocating decryption buffer\n");
goto bailout;
}
- decrypt_block (data, plain, datalen, salt, saltlen, iter,
+ datalen = decrypt_block (data, plain, datalen, salt, saltlen, iter,
iv, is_pbes2?16:0, ctx->password,
is_pbes2 ? (is_aes256?GCRY_CIPHER_AES256:GCRY_CIPHER_AES128) :
is_3des ? GCRY_CIPHER_3DES : GCRY_CIPHER_RFC2268_40,
+ digest_algo,
bag_decrypted_data_p);
+ if (!datalen)
+ {
+ err = gpg_error (GPG_ERR_DECRYPT_FAILED);
+ goto bailout;
+ }
/* We do not need the TLV anymore and allocated a new one. */
where = "bag.encryptedData.decrypted-text";
- tlv = tlv_new (plain, datalen);
+ tlv = tlv_parser_new (plain, datalen, opt_verbose);
if (!tlv)
{
err = gpg_error_from_syserror ();
@@ -1442,7 +954,7 @@ parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
ctx->badpass = 1;
goto bailout;
}
- if (tlv_expect_top_sequence (tlv))
+ if (tlv_expect_sequence (tlv))
{
ctx->badpass = 1;
goto bailout;
@@ -1450,8 +962,8 @@ parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
/* Loop over all certificates inside the bag. */
loopcount = 0;
- startlevel = tlv_level (tlv);
- while (!(err = tlv_next (tlv)) && tlv_level (tlv) == startlevel)
+ startlevel = tlv_parser_level (tlv);
+ while (!(err = tlv_next (tlv)) && tlv_parser_level (tlv) == startlevel)
{
int iscrlbag = 0;
int iskeybag = 0;
@@ -1564,7 +1076,8 @@ parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
where = "reading.keybag.key-parameters";
keyelem_count = 0;
- while (!(err = tlv_next (tlv)) && !tlv_popped (tlv))
+ startlevel2 = tlv_parser_level (tlv);
+ while (!(err = tlv_next (tlv)) && tlv_parser_level (tlv) == startlevel2)
{
if (keyelem_count >= 9)
{
@@ -1586,7 +1099,9 @@ parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
log_debug ("RSA key parameter %d found\n", keyelem_count);
keyelem_count++;
}
- if (err && gpg_err_code (err) != GPG_ERR_EOF)
+ if (!err)
+ tlv_parser_set_pending (tlv);
+ else if (err && gpg_err_code (err) != GPG_ERR_EOF)
goto bailout;
err = 0;
}
@@ -1635,24 +1150,21 @@ parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
/* Skip the optional SET with the pkcs12 cert attributes. */
where = "bag.attribute_set";
- err = tlv_next (tlv);
- if (gpg_err_code (err) == GPG_ERR_EOF)
- break;
- if (err)
- goto bailout;
- err = tlv_expect_set (tlv);
- if (!err)
- { /* This is the optional set of attributes. Skip it. */
- tlv_skip (tlv);
+ if (tlv_peek (tlv, CLASS_UNIVERSAL, TAG_SET))
+ {
+ if (tlv_next (tlv))
+ goto bailout;
+ err = tlv_expect_set (tlv);
+ if (err)
+ goto bailout;
+ tlv_parser_skip (tlv);
if (opt_verbose)
- log_info ("skipping bag.attribute_set\n");
+ log_info ("skipping %s\n", where);
}
- else if (gpg_err_code (err) == GPG_ERR_INV_OBJ)
- tlv_set_pending (tlv); /* The next tlv_next will be skipped. */
- else
- goto bailout;
}
- if (err && gpg_err_code (err) != GPG_ERR_EOF)
+ if (!err)
+ tlv_parser_set_pending (tlv);
+ else if (err && gpg_err_code (err) != GPG_ERR_EOF)
{
if (!loopcount) /* The first while(tlv_next) failed. */
ctx->badpass = 1;
@@ -1662,7 +1174,7 @@ parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
leave:
if (renewed_tlv)
- tlv_release (tlv);
+ tlv_parser_release (tlv);
gcry_free (plain);
if (ctx->badpass)
{
@@ -1676,12 +1188,11 @@ parse_bag_encrypted_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
bailout:
if (!err)
err = gpg_error (GPG_ERR_GENERAL);
- log_error ("%s(%s): offset %u.%zu (%s): %s - %s\n",
+ log_error ("%s(%s): lvl=%u (%s): %s - %s\n",
__func__, where,
- tlv? tlv->stacklen : 0,
- tlv? tlv->offset : 0,
- tlv? tlv->lastfunc : "",
- tlv ? gpg_strerror (tlv->lasterr) : "init failed",
+ tlv_parser_level (tlv),
+ tlv_parser_lastfunc (tlv),
+ tlv_parser_lasterrstr (tlv),
gpg_strerror (err));
goto leave;
}
@@ -1696,17 +1207,19 @@ bag_data_p (const void *plaintext, size_t length)
const unsigned char *p = plaintext;
size_t n = length;
-/* { */
-/* # warning debug code is enabled */
-/* FILE *fp = fopen ("tmp-minip12-plain-key.der", "wb"); */
-/* if (!fp || fwrite (p, n, 1, fp) != 1) */
-/* exit (2); */
-/* fclose (fp); */
-/* } */
-
- if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE)
+#ifdef ENABLE_DER_STRUCT_DUMPING
+ {
+# warning debug code is enabled
+ FILE *fp = fopen ("tmp-minip12-plain-key.der", "wb");
+ if (!fp || fwrite (p, n, 1, fp) != 1)
+ exit (2);
+ fclose (fp);
+ }
+#endif /*ENABLE_DER_STRUCT_DUMPING*/
+
+ if (tlv_parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE)
return 0;
- if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_INTEGER
+ if (tlv_parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_INTEGER
|| ti.length != 1 || *p)
return 0;
@@ -1715,7 +1228,7 @@ bag_data_p (const void *plaintext, size_t length)
static gpg_error_t
-parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
+parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, tlv_parser_t tlv)
{
gpg_error_t err = 0;
const char *where;
@@ -1728,11 +1241,12 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
size_t saltlen;
char iv[16];
unsigned int iter;
- struct tlv_ctx_s *saved_tlv = NULL;
+ tlv_parser_t saved_tlv = NULL;
int renewed_tlv = 0; /* True if the TLV must be released. */
unsigned char *plain = NULL;
int is_pbes2 = 0;
int is_aes256 = 0;
+ int digest_algo = GCRY_MD_SHA1;
where = "shrouded_key_bag";
if (opt_verbose)
@@ -1774,6 +1288,8 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
if (is_pbes2)
{
+ size_t parmlen; /* Remaining length of the parameter sequence. */
+
where = "shrouded_key_bag.pkcs5PBES2-params";
if (tlv_next (tlv))
goto bailout;
@@ -1797,11 +1313,13 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
goto bailout;
if (tlv_expect_sequence (tlv))
goto bailout;
+ parmlen = tlv_parser_tag_length (tlv, 0);
if (tlv_next (tlv))
goto bailout;
if (tlv_expect_octet_string (tlv, 0, &data, &datalen))
goto bailout;
+ parmlen -= tlv_parser_tag_length (tlv, 1);
if (datalen < 8 || datalen > sizeof salt)
{
log_info ("bad length of salt (%zu) for AES\n", datalen);
@@ -1815,6 +1333,7 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
goto bailout;
if ((err = tlv_expect_integer (tlv, &intval)))
goto bailout;
+ parmlen -= tlv_parser_tag_length (tlv, 1);
if (!intval) /* Not a valid iteration count. */
{
err = gpg_error (GPG_ERR_INV_VALUE);
@@ -1822,8 +1341,36 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
}
iter = intval;
- /* Note: We don't support the optional parameters but assume
- that the algorithmIdentifier follows. */
+ if (parmlen > 2) /* There is the optional prf. */
+ {
+ if (tlv_next (tlv))
+ goto bailout;
+ if (tlv_expect_sequence (tlv))
+ goto bailout;
+ if (tlv_next (tlv))
+ goto bailout;
+ if (tlv_expect_object_id (tlv, &oid, &oidlen))
+ goto bailout;
+ digest_algo = digest_algo_from_oid (oid, oidlen);
+ if (!digest_algo)
+ {
+ gpgrt_log_printhex (oid, oidlen, "kdf digest algo:");
+ err = gpg_error (GPG_ERR_DIGEST_ALGO);
+ goto bailout;
+ }
+ if (opt_verbose > 1)
+ log_debug ("kdf digest algo = %d\n", digest_algo);
+
+ if (tlv_peek_null (tlv))
+ {
+ /* Read the optional Null tag. */
+ if (tlv_next (tlv))
+ goto bailout;
+ }
+ }
+ else
+ digest_algo = GCRY_MD_SHA1;
+
if (tlv_next (tlv))
goto bailout;
if (tlv_expect_sequence (tlv))
@@ -1905,17 +1452,22 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
log_error ("error allocating decryption buffer\n");
goto bailout;
}
- decrypt_block (data, plain, datalen, salt, saltlen, iter,
+ datalen = decrypt_block (data, plain, datalen, salt, saltlen, iter,
iv, is_pbes2? 16:0, ctx->password,
is_pbes2 ? (is_aes256?GCRY_CIPHER_AES256:GCRY_CIPHER_AES128)
: GCRY_CIPHER_3DES,
+ digest_algo,
bag_data_p);
-
+ if (!datalen)
+ {
+ err = gpg_error (GPG_ERR_DECRYPT_FAILED);
+ goto bailout;
+ }
/* We do not need the TLV anymore and allocated a new one. */
where = "shrouded_key_bag.decrypted-text";
saved_tlv = tlv;
- tlv = tlv_new (plain, datalen);
+ tlv = tlv_parser_new (plain, datalen, opt_verbose);
if (!tlv)
{
err = gpg_error_from_syserror ();
@@ -1930,7 +1482,7 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
ctx->badpass = 1;
goto bailout;
}
- if (tlv_expect_top_sequence (tlv))
+ if (tlv_expect_sequence (tlv))
{
ctx->badpass = 1;
goto bailout;
@@ -1967,10 +1519,13 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
{
if (opt_verbose > 1)
log_debug ("RSA parameters\n");
- if (tlv_next (tlv))
- goto bailout;
- if (tlv_expect_null (tlv))
- tlv_set_pending (tlv); /* NULL tag missing - ignore this. */
+
+ if (tlv_peek_null (tlv))
+ {
+ /* Read the optional Null tag. */
+ if (tlv_next (tlv))
+ goto bailout;
+ }
}
else if (oidlen == DIM(oid_pcPublicKey)
&& !memcmp (oid, oid_pcPublicKey, oidlen))
@@ -2055,8 +1610,9 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
{
int keyelem_count = 0;
int firstparam = 1;
+ unsigned int startlevel = tlv_parser_level (tlv);
- while (!(err = tlv_next (tlv)) && !tlv_popped (tlv))
+ while (!(err = tlv_next (tlv)) && tlv_parser_level (tlv) == startlevel)
{
if (keyelem_count >= 9)
{
@@ -2082,41 +1638,39 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
}
firstparam = 0;
}
- if (err && gpg_err_code (err) != GPG_ERR_EOF)
+ if (!err)
+ tlv_parser_set_pending (tlv);
+ else if (err && gpg_err_code (err) != GPG_ERR_EOF)
goto bailout;
err = 0;
}
if (opt_verbose > 1)
log_debug ("restoring parser context\n");
- tlv_release (tlv);
+ tlv_parser_release (tlv);
renewed_tlv = 0;
tlv = saved_tlv;
where = "shrouded_key_bag.attribute_set";
- err = tlv_next (tlv);
- if (gpg_err_code (err) == GPG_ERR_EOF)
- goto leave;
- if (err)
- goto bailout;
- err = tlv_expect_set (tlv);
- if (!err)
- { /* This is the optional set of attributes. Skip it. */
- tlv_skip (tlv);
+ /* Check for an optional set of attributes. */
+ if (tlv_peek (tlv, CLASS_UNIVERSAL, TAG_SET))
+ {
+ if (tlv_next (tlv))
+ goto bailout;
+ err = tlv_expect_set (tlv);
+ if (err)
+ goto bailout;
+ tlv_parser_skip (tlv);
if (opt_verbose)
log_info ("skipping %s\n", where);
}
- else if (gpg_err_code (err) == GPG_ERR_INV_OBJ)
- tlv_set_pending (tlv); /* The next tlv_next will be skipped. */
- else /* Other error. */
- goto bailout;
leave:
gcry_free (plain);
if (renewed_tlv)
{
- tlv_release (tlv);
+ tlv_parser_release (tlv);
if (opt_verbose > 1)
log_debug ("parser context released\n");
}
@@ -2125,19 +1679,18 @@ parse_shrouded_key_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
bailout:
if (!err)
err = gpg_error (GPG_ERR_GENERAL);
- log_error ("%s(%s): offset %u.%zu (%s): %s - %s\n",
+ log_error ("%s(%s): lvl=%u (%s): %s - %s\n",
__func__, where,
- tlv? tlv->stacklen : 0,
- tlv? tlv->offset : 0,
- tlv? tlv->lastfunc : "",
- tlv ? gpg_strerror (tlv->lasterr) : "init failed",
+ tlv_parser_level (tlv),
+ tlv_parser_lastfunc (tlv),
+ tlv_parser_lasterrstr (tlv),
gpg_strerror (err));
goto leave;
}
static gpg_error_t
-parse_cert_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
+parse_cert_bag (struct p12_parse_ctx_s *ctx, tlv_parser_t tlv)
{
gpg_error_t err = 0;
const char *where;
@@ -2204,30 +1757,29 @@ parse_cert_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
* SEQUENCE -- we actually ignore this.
*/
where = "certbag.attribute_set";
- if (tlv_next (tlv))
- goto bailout;
- err = tlv_expect_set (tlv);
- if (!err)
- { /* This is the optional set of attributes. Skip it. */
- tlv_skip (tlv);
+ /* Check for an optional set of attributes. */
+ if (tlv_peek (tlv, CLASS_UNIVERSAL, TAG_SET))
+ {
+ if (tlv_next (tlv))
+ goto bailout;
+ err = tlv_expect_set (tlv);
+ if (err)
+ goto bailout;
+ tlv_parser_skip (tlv);
if (opt_verbose)
- log_info ("skipping certbag.attribute_set\n");
+ log_info ("skipping %s\n", where);
}
- else if (gpg_err_code (err) == GPG_ERR_INV_OBJ)
- tlv_set_pending (tlv); /* The next tlv_next will be skipped. */
- else
- goto bailout;
+
leave:
return err;
bailout:
- log_error ("%s(%s): offset %u.%zu (%s): %s - %s\n",
+ log_error ("%s(%s): lvl=%u (%s): %s - %s\n",
__func__, where,
- tlv? tlv->stacklen : 0,
- tlv? tlv->offset : 0,
- tlv? tlv->lastfunc : "",
- tlv ? gpg_strerror (tlv->lasterr) : "init failed",
+ tlv_parser_level (tlv),
+ tlv_parser_lastfunc (tlv),
+ tlv_parser_lasterrstr (tlv),
gpg_strerror (err));
if (!err)
err = gpg_error (GPG_ERR_GENERAL);
@@ -2236,7 +1788,7 @@ parse_cert_bag (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
static gpg_error_t
-parse_bag_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
+parse_bag_data (struct p12_parse_ctx_s *ctx, tlv_parser_t tlv)
{
gpg_error_t err = 0;
const char *where;
@@ -2263,6 +1815,14 @@ parse_bag_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
if (tlv_expect_octet_string (tlv, 1, NULL, NULL))
goto bailout;
+ if (tlv_peek (tlv, CLASS_UNIVERSAL, TAG_OCTET_STRING))
+ {
+ if (tlv_next (tlv))
+ goto bailout;
+ err = tlv_expect_octet_string (tlv, 1, NULL, NULL);
+ if (err)
+ goto bailout;
+ }
/* Expect:
* SEQUENCE
@@ -2273,8 +1833,9 @@ parse_bag_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
if (tlv_expect_sequence (tlv))
goto bailout;
- startlevel = tlv_level (tlv);
- while (!(err = tlv_next (tlv)) && tlv_level (tlv) == startlevel)
+ startlevel = tlv_parser_level (tlv);
+ tlv_parser_dump_state ("data.outerseqs", "beginloop", tlv);
+ while (!(err = tlv_next (tlv)) && tlv_parser_level (tlv) == startlevel)
{
/* Expect:
* SEQUENCE
@@ -2308,15 +1869,16 @@ parse_bag_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
}
else
{
- tlv_skip (tlv);
+ tlv_parser_skip (tlv);
log_info ("unknown inner data type - skipped\n");
}
}
- if (err && gpg_err_code (err) != GPG_ERR_EOF)
+ tlv_parser_dump_state ("data.outerseqs", "endloop", tlv);
+ if (!err)
+ tlv_parser_set_pending (tlv);
+ else if (err && gpg_err_code (err) != GPG_ERR_EOF)
goto bailout;
err = 0;
- if (tlv_popped (tlv))
- tlv_set_pending (tlv);
leave:
return err;
@@ -2324,12 +1886,11 @@ parse_bag_data (struct p12_parse_ctx_s *ctx, struct tlv_ctx_s *tlv)
bailout:
if (!err)
err = gpg_error (GPG_ERR_GENERAL);
- log_error ("%s(%s): offset %u.%zu (%s): %s - %s\n",
+ log_error ("%s(%s): lvl=%u (%s): %s - %s\n",
__func__, where,
- tlv? tlv->stacklen : 0,
- tlv? tlv->offset : 0,
- tlv? tlv->lastfunc : "",
- tlv ? gpg_strerror (tlv->lasterr) : "init failed",
+ tlv_parser_level (tlv),
+ tlv_parser_lastfunc (tlv),
+ tlv_parser_lasterrstr (tlv),
gpg_strerror (err));
goto leave;
}
@@ -2349,7 +1910,7 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
{
gpg_error_t err;
const char *where = "";
- struct tlv_ctx_s *tlv;
+ tlv_parser_t tlv;
struct p12_parse_ctx_s ctx = { NULL };
const unsigned char *oid;
size_t oidlen;
@@ -2362,7 +1923,7 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
ctx.certcbarg = certcbarg;
ctx.password = pw;
- tlv = tlv_new (buffer, length);
+ tlv = tlv_parser_new (buffer, length, opt_verbose);
if (!tlv)
{
err = gpg_error_from_syserror ();
@@ -2404,6 +1965,14 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
if (tlv_expect_octet_string (tlv, 1, NULL, NULL))
goto bailout;
+ if (tlv_peek (tlv, CLASS_UNIVERSAL, TAG_OCTET_STRING))
+ {
+ if (tlv_next (tlv))
+ goto bailout;
+ err = tlv_expect_octet_string (tlv, 1, NULL, NULL);
+ if (err)
+ goto bailout;
+ }
where = "bags";
if (tlv_next (tlv))
@@ -2411,10 +1980,12 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
if (tlv_expect_sequence (tlv))
goto bailout;
- startlevel = tlv_level (tlv);
- while (!(err = tlv_next (tlv)) && tlv_level (tlv) == startlevel)
+ startlevel = tlv_parser_level (tlv);
+ tlv_parser_dump_state ("bags", "beginloop", tlv);
+ while (!(err = tlv_next (tlv)) && tlv_parser_level (tlv) == startlevel)
{
where = "bag-sequence";
+ tlv_parser_dump_state (where, NULL, tlv);
if (tlv_expect_sequence (tlv))
goto bailout;
@@ -2447,15 +2018,18 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
}
else
{
- tlv_skip (tlv);
+ tlv_parser_skip (tlv);
log_info ("unknown outer bag type - skipped\n");
}
}
- if (err && gpg_err_code (err) != GPG_ERR_EOF)
+ tlv_parser_dump_state ("bags", "endloop", tlv);
+ if (!err)
+ tlv_parser_set_pending (tlv);
+ else if (err && gpg_err_code (err) != GPG_ERR_EOF)
goto bailout;
err = 0;
- tlv_release (tlv);
+ tlv_parser_release (tlv);
if (r_curve)
*r_curve = ctx.curve;
else
@@ -2465,12 +2039,12 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
bailout:
*r_badpass = ctx.badpass;
- log_error ("%s(%s): offset %u.%zu (%s): %s - %s\n",
+ log_error ("%s(%s): @%04zu lvl=%u %s: %s - %s\n",
__func__, where,
- tlv? tlv->stacklen : 0,
- tlv? tlv->offset : 0,
- tlv? tlv->lastfunc : "",
- tlv ? gpg_strerror (tlv->lasterr) : "init failed",
+ tlv_parser_offset (tlv),
+ tlv_parser_level (tlv),
+ tlv_parser_lastfunc (tlv),
+ tlv_parser_lasterrstr (tlv),
gpg_strerror (err));
if (ctx.privatekey)
{
@@ -2481,7 +2055,7 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
gcry_free (ctx.privatekey);
ctx.privatekey = NULL;
}
- tlv_release (tlv);
+ tlv_parser_release (tlv);
gcry_free (ctx.curve);
if (r_curve)
*r_curve = NULL;
@@ -3423,7 +2997,7 @@ p12_build (gcry_mpi_t *kparms, const void *cert, size_t certlen,
/* Encrypt it. */
gcry_randomize (salt, 8, GCRY_STRONG_RANDOM);
crypt_block (buffer, buflen, salt, 8, 2048, NULL, 0, pw,
- GCRY_CIPHER_RFC2268_40, 1);
+ GCRY_CIPHER_RFC2268_40, GCRY_MD_SHA1, 1);
/* Encode the encrypted stuff into a bag. */
seqlist[seqlistidx].buffer = build_cert_bag (buffer, buflen, salt, &n);
@@ -3455,7 +3029,7 @@ p12_build (gcry_mpi_t *kparms, const void *cert, size_t certlen,
/* Encrypt it. */
gcry_randomize (salt, 8, GCRY_STRONG_RANDOM);
crypt_block (buffer, buflen, salt, 8, 2048, NULL, 0,
- pw, GCRY_CIPHER_3DES, 1);
+ pw, GCRY_CIPHER_3DES, GCRY_MD_SHA1, 1);
/* Encode the encrypted stuff into a bag. */
if (cert && certlen)
diff --git a/sm/server.c b/sm/server.c
index 3ebf47299..f00b70d38 100644
--- a/sm/server.c
+++ b/sm/server.c
@@ -287,6 +287,17 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
ctrl->offline = i;
}
}
+ else if (!strcmp (key, "always-trust"))
+ {
+ /* We ignore this option if gpgsm has been started with
+ --always-trust (which also sets offline) and if
+ --require-compliance is active */
+ if (!opt.always_trust && !opt.require_compliance)
+ {
+ int i = *value? !!atoi (value) : 1;
+ ctrl->always_trust = i;
+ }
+ }
else if (!strcmp (key, "request-origin"))
{
if (!opt.request_origin)
@@ -320,6 +331,7 @@ reset_notify (assuan_context_t ctx, char *line)
gpgsm_release_certlist (ctrl->server_local->signerlist);
ctrl->server_local->recplist = NULL;
ctrl->server_local->signerlist = NULL;
+ ctrl->always_trust = 0;
close_message_fp (ctrl);
assuan_close_input_fd (ctx);
assuan_close_output_fd (ctx);
@@ -495,6 +507,7 @@ cmd_encrypt (assuan_context_t ctx, char *line)
gpgsm_release_certlist (ctrl->server_local->recplist);
ctrl->server_local->recplist = NULL;
+ ctrl->always_trust = 0;
/* Close and reset the fp and the fds */
close_message_fp (ctrl);
assuan_close_input_fd (ctx);
@@ -1221,7 +1234,8 @@ static const char hlp_getinfo[] =
" agent-check - Return success if the agent is running.\n"
" cmd_has_option CMD OPT\n"
" - Returns OK if the command CMD implements the option OPT.\n"
- " offline - Returns OK if the connection is in offline mode.";
+ " offline - Returns OK if the connection is in offline mode."
+ " always-trust- Returns OK if the connection is in always-trust mode.";
static gpg_error_t
cmd_getinfo (assuan_context_t ctx, char *line)
{
@@ -1280,6 +1294,11 @@ cmd_getinfo (assuan_context_t ctx, char *line)
{
rc = ctrl->offline? 0 : gpg_error (GPG_ERR_FALSE);
}
+ else if (!strcmp (line, "always-trust"))
+ {
+ rc = (ctrl->always_trust || opt.always_trust)? 0
+ /**/ : gpg_error (GPG_ERR_FALSE);
+ }
else
rc = set_error (GPG_ERR_ASS_PARAMETER, "unknown value for WHAT");
diff --git a/sm/sign.c b/sm/sign.c
index 39ff2b58f..8fd111a7d 100644
--- a/sm/sign.c
+++ b/sm/sign.c
@@ -622,6 +622,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
certlist_t cl;
int release_signerlist = 0;
int binary_detached = detached && !ctrl->create_pem && !ctrl->create_base64;
+ char *curve = NULL;
audit_set_type (ctrl->audit, AUDIT_TYPE_SIGN);
@@ -760,7 +761,8 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
unsigned int nbits;
int pk_algo;
- pk_algo = gpgsm_get_key_algo_info (cl->cert, &nbits);
+ xfree (curve);
+ pk_algo = gpgsm_get_key_algo_info (cl->cert, &nbits, &curve);
cl->pk_algo = pk_algo;
if (opt.forced_digest_algo)
@@ -820,8 +822,8 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
goto leave;
}
- if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pk_algo, 0,
- NULL, nbits, NULL))
+ if (!gnupg_pk_is_allowed (opt.compliance, PK_USE_SIGNING, pk_algo, 0,
+ NULL, nbits, curve))
{
char kidstr[10+1];
@@ -1187,6 +1189,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
gpg_strerror (rc), gpg_strsource (rc) );
if (release_signerlist)
gpgsm_release_certlist (signerlist);
+ xfree (curve);
ksba_cms_release (cms);
gnupg_ksba_destroy_writer (b64writer);
keydb_release (kh);
diff --git a/sm/t-minip12.c b/sm/t-minip12.c
index de6b7e5cc..bf3177ea0 100644
--- a/sm/t-minip12.c
+++ b/sm/t-minip12.c
@@ -559,13 +559,21 @@ run_one_test (const char *name, const char *desc, const char *pass,
else if (!certexpected && certstr)
printresult ("FAIL: %s - no certs expected but got one\n", name);
else if (certexpected && certstr && strcmp (certexpected, certstr))
- printresult ("FAIL: %s - certs not as expected\n", name);
+ {
+ printresult ("FAIL: %s - certs not as expected\n", name);
+ inf ("cert(exp)=%s", certexpected);
+ inf ("cert(got)=%s", certstr? certstr:"[null]");
+ }
else if (keyexpected && !resulthash)
printresult ("FAIL: %s - expected key but got none\n", name);
else if (!keyexpected && resulthash)
printresult ("FAIL: %s - key not expected but got one\n", name);
else if (keyexpected && resulthash && strcmp (keyexpected, resulthash))
- printresult ("FAIL: %s - keys not as expected\n", name);
+ {
+ printresult ("FAIL: %s - keys not as expected\n", name);
+ inf ("key(exp)=%s", keyexpected);
+ inf ("key(got)=%s", resulthash? resulthash:"[null]");
+ }
else
{
printresult ("PASS: %s\n", name);
diff --git a/sm/verify.c b/sm/verify.c
index de407bf16..9c012596d 100644
--- a/sm/verify.c
+++ b/sm/verify.c
@@ -450,7 +450,7 @@ gpgsm_verify (ctrl_t ctrl, estream_t in_fp, estream_t data_fp,
pkfpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
pkalgostr = gpgsm_pubkey_algo_string (cert, NULL);
- pkalgo = gpgsm_get_key_algo_info2 (cert, &nbits, &pkcurve);
+ pkalgo = gpgsm_get_key_algo_info (cert, &nbits, &pkcurve);
/* Remap the ECC algo to the algo we use. Note that EdDSA has
* already been mapped. */
if (pkalgo == GCRY_PK_ECC)
@@ -486,7 +486,7 @@ gpgsm_verify (ctrl_t ctrl, estream_t in_fp, estream_t data_fp,
/* Check compliance. */
if (! gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION,
- pkalgo, pkalgoflags, NULL, nbits, NULL))
+ pkalgo, pkalgoflags, NULL, nbits, pkcurve))
{
char kidstr[10+1];