diff options
author | Werner Koch <[email protected]> | 2023-11-07 19:07:45 +0000 |
---|---|---|
committer | Werner Koch <[email protected]> | 2023-11-07 19:38:27 +0000 |
commit | 387ee7dcbd77d19687af967901ed4818cbdb8b3c (patch) | |
tree | 3fc63cd303b2d07454794064e4e6528df2dbf42c /sm | |
parent | doc: Use the em dash to mark a break in a sentence. (diff) | |
parent | w32: Use utf8 for the asctimestamp function. (diff) | |
download | gnupg-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.c | 14 | ||||
-rw-r--r-- | sm/certlist.c | 8 | ||||
-rw-r--r-- | sm/decrypt.c | 9 | ||||
-rw-r--r-- | sm/encrypt.c | 10 | ||||
-rw-r--r-- | sm/export.c | 2 | ||||
-rw-r--r-- | sm/fingerprint.c | 11 | ||||
-rw-r--r-- | sm/gpgsm.c | 13 | ||||
-rw-r--r-- | sm/gpgsm.h | 15 | ||||
-rw-r--r-- | sm/keylist.c | 12 | ||||
-rw-r--r-- | sm/minip12.c | 1040 | ||||
-rw-r--r-- | sm/server.c | 21 | ||||
-rw-r--r-- | sm/sign.c | 9 | ||||
-rw-r--r-- | sm/t-minip12.c | 12 | ||||
-rw-r--r-- | sm/verify.c | 4 |
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"); @@ -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]; |