"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/cms.c" between
libksba-1.5.1.tar.bz2 and libksba-1.6.0.tar.bz2

About: KSBA is a library to make the tasks of working with X.509 certificates, CMS data and related objects more easy.

cms.c  (libksba-1.5.1.tar.bz2):cms.c  (libksba-1.6.0.tar.bz2)
skipping to change at line 32 skipping to change at line 32
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details. * License for more details.
* *
* You should have received a copies of the GNU General Public License * You should have received a copies of the GNU General Public License
* and the GNU Lesser General Public License along with this program; * and the GNU Lesser General Public License along with this program;
* if not, see <http://www.gnu.org/licenses/>. * if not, see <http://www.gnu.org/licenses/>.
*/ */
/* References: /* References:
* RFC-5083 := CMS - Authenticated-Enveloped-Data
* RFC-5084 := CMS - AES-GCM
* RFC-5652 := Cryptographic Message Syntax (CMS) (aka STD0070) * RFC-5652 := Cryptographic Message Syntax (CMS) (aka STD0070)
* SPHINX := CMS profile developed by the German BSI. * SPHINX := CMS profile developed by the German BSI.
* (see also https://lwn.net/2001/1011/a/german-smime.php3) * (see also https://lwn.net/2001/1011/a/german-smime.php3)
* PKCS#7 := Original specification of CMS * PKCS#7 := Original specification of CMS
*/ */
#include <config.h> #include <config.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
skipping to change at line 55 skipping to change at line 57
#include "util.h" #include "util.h"
#include "cms.h" #include "cms.h"
#include "convert.h" #include "convert.h"
#include "keyinfo.h" #include "keyinfo.h"
#include "der-encoder.h" #include "der-encoder.h"
#include "ber-help.h" #include "ber-help.h"
#include "sexp-parse.h" #include "sexp-parse.h"
#include "cert.h" #include "cert.h"
#include "der-builder.h" #include "der-builder.h"
#include "stringbuf.h"
static gpg_error_t ct_parse_data (ksba_cms_t cms); static gpg_error_t ct_parse_data (ksba_cms_t cms);
static gpg_error_t ct_parse_signed_data (ksba_cms_t cms); static gpg_error_t ct_parse_signed_data (ksba_cms_t cms);
static gpg_error_t ct_parse_enveloped_data (ksba_cms_t cms); static gpg_error_t ct_parse_enveloped_data (ksba_cms_t cms);
static gpg_error_t ct_parse_digested_data (ksba_cms_t cms); static gpg_error_t ct_parse_digested_data (ksba_cms_t cms);
static gpg_error_t ct_parse_encrypted_data (ksba_cms_t cms); static gpg_error_t ct_parse_encrypted_data (ksba_cms_t cms);
static gpg_error_t ct_build_data (ksba_cms_t cms); static gpg_error_t ct_build_data (ksba_cms_t cms);
static gpg_error_t ct_build_signed_data (ksba_cms_t cms); static gpg_error_t ct_build_signed_data (ksba_cms_t cms);
static gpg_error_t ct_build_enveloped_data (ksba_cms_t cms); static gpg_error_t ct_build_enveloped_data (ksba_cms_t cms);
static gpg_error_t ct_build_digested_data (ksba_cms_t cms); static gpg_error_t ct_build_digested_data (ksba_cms_t cms);
skipping to change at line 79 skipping to change at line 82
ksba_content_type_t ct; ksba_content_type_t ct;
gpg_error_t (*parse_handler)(ksba_cms_t); gpg_error_t (*parse_handler)(ksba_cms_t);
gpg_error_t (*build_handler)(ksba_cms_t); gpg_error_t (*build_handler)(ksba_cms_t);
} content_handlers[] = { } content_handlers[] = {
{ "1.2.840.113549.1.7.1", KSBA_CT_DATA, { "1.2.840.113549.1.7.1", KSBA_CT_DATA,
ct_parse_data , ct_build_data }, ct_parse_data , ct_build_data },
{ "1.2.840.113549.1.7.2", KSBA_CT_SIGNED_DATA, { "1.2.840.113549.1.7.2", KSBA_CT_SIGNED_DATA,
ct_parse_signed_data , ct_build_signed_data }, ct_parse_signed_data , ct_build_signed_data },
{ "1.2.840.113549.1.7.3", KSBA_CT_ENVELOPED_DATA, { "1.2.840.113549.1.7.3", KSBA_CT_ENVELOPED_DATA,
ct_parse_enveloped_data, ct_build_enveloped_data }, ct_parse_enveloped_data, ct_build_enveloped_data },
{ "1.2.840.113549.1.9.16.1.23", KSBA_CT_AUTHENVELOPED_DATA,
ct_parse_enveloped_data, ct_build_enveloped_data },
{ "1.2.840.113549.1.7.5", KSBA_CT_DIGESTED_DATA, { "1.2.840.113549.1.7.5", KSBA_CT_DIGESTED_DATA,
ct_parse_digested_data , ct_build_digested_data }, ct_parse_digested_data , ct_build_digested_data },
{ "1.2.840.113549.1.7.6", KSBA_CT_ENCRYPTED_DATA, { "1.2.840.113549.1.7.6", KSBA_CT_ENCRYPTED_DATA,
ct_parse_encrypted_data, ct_build_encrypted_data }, ct_parse_encrypted_data, ct_build_encrypted_data },
{ "1.2.840.113549.1.9.16.1.2", KSBA_CT_AUTH_DATA }, { "1.2.840.113549.1.9.16.1.2", KSBA_CT_AUTH_DATA },
{ "1.3.6.1.4.1.311.2.1.4", KSBA_CT_SPC_IND_DATA_CTX, { "1.3.6.1.4.1.311.2.1.4", KSBA_CT_SPC_IND_DATA_CTX,
ct_parse_data , ct_build_data }, ct_parse_data , ct_build_data },
{ "1.3.6.1.4.1.11591.2.3.1", KSBA_CT_OPENPGP_KEYBLOCK, { "1.3.6.1.4.1.11591.2.3.1", KSBA_CT_OPENPGP_KEYBLOCK,
ct_parse_data , ct_build_data }, ct_parse_data , ct_build_data },
{ NULL } { NULL }
skipping to change at line 593 skipping to change at line 598
struct certlist_s *cl = cms->cert_info_list->next; struct certlist_s *cl = cms->cert_info_list->next;
ksba_cert_release (cms->cert_info_list->cert); ksba_cert_release (cms->cert_info_list->cert);
xfree (cms->cert_info_list->enc_val.algo); xfree (cms->cert_info_list->enc_val.algo);
xfree (cms->cert_info_list->enc_val.value); xfree (cms->cert_info_list->enc_val.value);
xfree (cms->cert_info_list); xfree (cms->cert_info_list);
cms->cert_info_list = cl; cms->cert_info_list = cl;
} }
xfree (cms->inner_cont_oid); xfree (cms->inner_cont_oid);
xfree (cms->encr_algo_oid); xfree (cms->encr_algo_oid);
xfree (cms->encr_iv); xfree (cms->encr_iv);
xfree (cms->data.digest); xfree (cms->authdata.mac);
xfree (cms->authdata.attr);
while (cms->signer_info) while (cms->signer_info)
{ {
struct signer_info_s *tmp = cms->signer_info->next; struct signer_info_s *tmp = cms->signer_info->next;
_ksba_asn_release_nodes (cms->signer_info->root); _ksba_asn_release_nodes (cms->signer_info->root);
xfree (cms->signer_info->image); xfree (cms->signer_info->image);
xfree (cms->signer_info->cache.digest_algo); xfree (cms->signer_info->cache.digest_algo);
xfree (cms->signer_info); xfree (cms->signer_info);
cms->signer_info = tmp; cms->signer_info = tmp;
} }
release_value_tree (cms->recp_info); release_value_tree (cms->recp_info);
skipping to change at line 750 skipping to change at line 756
if (!what) if (!what)
return cms->content.oid; return cms->content.oid;
if (what == 1) if (what == 1)
return cms->inner_cont_oid; return cms->inner_cont_oid;
if (what == 2) if (what == 2)
return cms->encr_algo_oid; return cms->encr_algo_oid;
return NULL; return NULL;
} }
/* Copy the initialization vector into iv and its len into ivlen. /* Copy the initialization vector into iv and its len into ivlen.
The caller should provide a suitable large buffer */ The caller should proncrvide a suitable large buffer */
gpg_error_t gpg_error_t
ksba_cms_get_content_enc_iv (ksba_cms_t cms, void *iv, ksba_cms_get_content_enc_iv (ksba_cms_t cms, void *iv,
size_t maxivlen, size_t *ivlen) size_t maxivlen, size_t *ivlen)
{ {
if (!cms || !iv || !ivlen) if (!cms || !iv || !ivlen)
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE);
if (!cms->encr_ivlen) if (!cms->encr_ivlen)
return gpg_error (GPG_ERR_NO_DATA); return gpg_error (GPG_ERR_NO_DATA);
if (cms->encr_ivlen > maxivlen) if (cms->encr_ivlen > maxivlen)
return gpg_error (GPG_ERR_BUFFER_TOO_SHORT); return gpg_error (GPG_ERR_BUFFER_TOO_SHORT);
memcpy (iv, cms->encr_iv, cms->encr_ivlen); memcpy (iv, cms->encr_iv, cms->encr_ivlen);
*ivlen = cms->encr_ivlen; *ivlen = cms->encr_ivlen;
return 0; return 0;
} }
/** /**
* ksba_cert_get_digest_algo_list: * ksba_cert_get_digest_algo_list:
* @cert: Initialized certificate object * @cms: CMS object
* @idx: enumerator * @idx: enumerator
* *
* Figure out the the digest algorithm used for the signature and * Figure out the the digest algorithm used for the signature and
* return its OID. Note that the algos returned are just hints on * return its OID. Note that the algos returned are just hints on
* what to hash. * what to hash.
* *
* Return value: NULL for no more algorithms or a string valid as long * Return value: NULL for no more algorithms or a string valid as long
* as the the cms object is valid. * as the the cms object is valid.
**/ **/
const char * const char *
skipping to change at line 805 skipping to change at line 811
* @cms: CMS object * @cms: CMS object
* @idx: index number * @idx: index number
* @r_issuer: returns the issuer * @r_issuer: returns the issuer
* @r_serial: returns the serial number * @r_serial: returns the serial number
* *
* This functions returns the issuer and serial number either from the * This functions returns the issuer and serial number either from the
* sid or the rid elements of a CMS object. * sid or the rid elements of a CMS object.
* *
* Return value: 0 on success or an error code. An error code of -1 * Return value: 0 on success or an error code. An error code of -1
* is returned to indicate that there is no issuer with that idx, * is returned to indicate that there is no issuer with that idx,
* GPG_ERR_No_Data is returned to indicate that there is no issuer at * GPG_ERR_NO_DATA is returned to indicate that there is no issuer at
* all. * all.
**/ **/
gpg_error_t gpg_error_t
ksba_cms_get_issuer_serial (ksba_cms_t cms, int idx, ksba_cms_get_issuer_serial (ksba_cms_t cms, int idx,
char **r_issuer, ksba_sexp_t *r_serial) char **r_issuer, ksba_sexp_t *r_serial)
{ {
gpg_error_t err; gpg_error_t err;
const char *issuer_path, *serial_path; const char *issuer_path, *serial_path;
AsnNode root; AsnNode root;
const unsigned char *image; const unsigned char *image;
skipping to change at line 875 skipping to change at line 881
} }
else if (!strcmp (n->name, "kari")) else if (!strcmp (n->name, "kari"))
{ {
issuer_path = ("kari..recipientEncryptedKeys" issuer_path = ("kari..recipientEncryptedKeys"
"..rid.issuerAndSerialNumber.issuer"); "..rid.issuerAndSerialNumber.issuer");
serial_path = ("kari..recipientEncryptedKeys" serial_path = ("kari..recipientEncryptedKeys"
"..rid.issuerAndSerialNumber.serialNumber"); "..rid.issuerAndSerialNumber.serialNumber");
} }
else if (!strcmp (n->name, "kekri")) else if (!strcmp (n->name, "kekri"))
return gpg_error (GPG_ERR_UNSUPPORTED_CMS_OBJ); return gpg_error (GPG_ERR_UNSUPPORTED_CMS_OBJ);
else if (!strcmp (n->name, "pwri"))
return gpg_error (GPG_ERR_UNSUPPORTED_CMS_OBJ);
else else
return gpg_error (GPG_ERR_INV_CMS_OBJ); return gpg_error (GPG_ERR_INV_CMS_OBJ);
root = n; root = n;
} }
if (r_issuer) if (r_issuer)
{ {
n = _ksba_asn_find_node (root, issuer_path); n = _ksba_asn_find_node (root, issuer_path);
if (!n || !n->down) if (!n || !n->down)
return gpg_error (GPG_ERR_NO_VALUE); return gpg_error (GPG_ERR_NO_VALUE);
skipping to change at line 1003 skipping to change at line 1011
for (cl=cms->cert_list; cl && idx; cl = cl->next, idx--) for (cl=cms->cert_list; cl && idx; cl = cl->next, idx--)
; ;
if (!cl) if (!cl)
return NULL; return NULL;
ksba_cert_ref (cl->cert); ksba_cert_ref (cl->cert);
return cl->cert; return cl->cert;
} }
/* /*
Return the extension attribute messageDigest * Return the extension attribute messageDigest
*/ * or for authenvelopeddata the MAC.
*/
gpg_error_t gpg_error_t
ksba_cms_get_message_digest (ksba_cms_t cms, int idx, ksba_cms_get_message_digest (ksba_cms_t cms, int idx,
char **r_digest, size_t *r_digest_len) char **r_digest, size_t *r_digest_len)
{ {
AsnNode nsiginfo, n; AsnNode nsiginfo, n;
struct signer_info_s *si; struct signer_info_s *si;
if (!cms || !r_digest || !r_digest_len) if (!cms || !r_digest || !r_digest_len)
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE);
/* Hack to return the MAC/authtag value or the authAttr. */
if (cms->content.ct == KSBA_CT_AUTHENVELOPED_DATA)
{
if (!idx) /* Return authtag. */
{
if (!cms->authdata.mac || !cms->authdata.mac_len)
return gpg_error (GPG_ERR_NO_DATA);
*r_digest = xtrymalloc (cms->authdata.mac_len);
if (!*r_digest)
return gpg_error_from_syserror ();
memcpy (*r_digest, cms->authdata.mac, cms->authdata.mac_len);
*r_digest_len = cms->authdata.mac_len;
}
else if (idx == 1) /* Return authAttr. */
{
if (!cms->authdata.attr || !cms->authdata.attr_len)
return gpg_error (GPG_ERR_NO_DATA);
*r_digest = xtrymalloc (cms->authdata.attr_len);
if (!*r_digest)
return gpg_error_from_syserror ();
memcpy (*r_digest, cms->authdata.attr, cms->authdata.attr_len);
*r_digest_len = cms->authdata.attr_len;
}
else
return gpg_error (GPG_ERR_INV_INDEX);
return 0;
}
if (!cms->signer_info) if (!cms->signer_info)
return gpg_error (GPG_ERR_NO_DATA); return gpg_error (GPG_ERR_NO_DATA);
if (idx < 0) if (idx < 0)
return gpg_error (GPG_ERR_INV_INDEX); return gpg_error (GPG_ERR_INV_INDEX);
for (si=cms->signer_info; si && idx; si = si->next, idx-- ) for (si=cms->signer_info; si && idx; si = si->next, idx-- )
; ;
if (!si) if (!si)
return -1; return -1;
skipping to change at line 1349 skipping to change at line 1390
* format suitable to be used as input to Libgcrypt's decryption * format suitable to be used as input to Libgcrypt's decryption
* function. The caller must free the returned string. * function. The caller must free the returned string.
* *
* Return value: NULL or a string with a S-Exp. * Return value: NULL or a string with a S-Exp.
**/ **/
ksba_sexp_t ksba_sexp_t
ksba_cms_get_enc_val (ksba_cms_t cms, int idx) ksba_cms_get_enc_val (ksba_cms_t cms, int idx)
{ {
AsnNode root, n, n2; AsnNode root, n, n2;
gpg_error_t err; gpg_error_t err;
ksba_sexp_t string; ksba_sexp_t string = NULL;
struct value_tree_s *vt; struct value_tree_s *vt;
char *keyencralgo = NULL; /* Key encryption algo. */ char *keyencralgo = NULL; /* Key encryption algo. */
char *parm = NULL; /* Helper to get the parms of kencralgo. */ char *parm = NULL; /* Helper to get the parms of kencralgo. */
size_t parmlen; size_t parmlen;
char *parm2 = NULL;
size_t parm2len;
char *parm3 = NULL;
size_t parm3len;
char *keywrapalgo = NULL; /* Key wrap algo. */ char *keywrapalgo = NULL; /* Key wrap algo. */
char *keyderivealgo = NULL; /* Key derive algo. */
struct tag_info ti; struct tag_info ti;
const unsigned char *der; const unsigned char *der;
size_t derlen; size_t derlen;
if (!cms) if (!cms)
return NULL; return NULL;
if (!cms->recp_info) if (!cms->recp_info)
return NULL; return NULL;
if (idx < 0) if (idx < 0)
return NULL; return NULL;
skipping to change at line 1450 skipping to change at line 1496
keyencralgo, keywrapalgo, der, derlen, keyencralgo, keywrapalgo, der, derlen,
&string); &string);
if (err) if (err)
goto leave; goto leave;
/* gpgrt_log_debug ("%s: encryptedKey:\n", __func__); */ /* gpgrt_log_debug ("%s: encryptedKey:\n", __func__); */
/* dbg_print_sexp (string); */ /* dbg_print_sexp (string); */
} }
else if (!strcmp (root->name, "kekri")) else if (!strcmp (root->name, "kekri"))
return NULL; /*GPG_ERR_UNSUPPORTED_CMS_OBJ*/ return NULL; /*GPG_ERR_UNSUPPORTED_CMS_OBJ*/
else if (!strcmp (root->name, "pwri"))
{
/* _ksba_asn_node_dump_all (root, stderr); */
n = _ksba_asn_find_node (root, "pwri..keyEncryptionAlgorithm");
if (!n || n->off == -1)
{
err = gpg_error (GPG_ERR_INV_KEYINFO);
goto leave;
}
err = _ksba_parse_algorithm_identifier2 (vt->image + n->off,
n->nhdr + n->len, NULL,
&keyencralgo, &parm, &parmlen);
if (err)
goto leave;
if (strcmp (keyencralgo, "1.2.840.113549.1.9.16.3.9"))
{
/* pwri requires this and only this OID. */
err = gpg_error (GPG_ERR_INV_CMS_OBJ);
goto leave;
}
if (!parm)
{
err = gpg_error (GPG_ERR_INV_KEYINFO);
goto leave;
}
/* gpgrt_log_printhex (parm, parmlen, "parms"); */
err = _ksba_parse_algorithm_identifier2 (parm, parmlen, NULL,
&keywrapalgo, &parm2, &parm2len);
if (err)
goto leave;
/* gpgrt_log_debug ("%s: keywrapalgo='%s'\n", __func__, keywrapalgo); */
/* gpgrt_log_printhex (parm2, parm2len, "parm:"); */
n = _ksba_asn_find_node (root, "pwri..keyDerivationAlgorithm");
if (!n || n->off == -1)
{
/* Not found but that is okay becuase it is optional. */
}
else
{
err = _ksba_parse_algorithm_identifier3 (vt->image + n->off,
n->nhdr + n->len, 0xa0, NULL,
&keyderivealgo,
&parm3, &parm3len, NULL);
if (err)
goto leave;
}
n = _ksba_asn_find_node (root, "pwri..encryptedKey");
if (!n || n->off == -1)
{
err = gpg_error (GPG_ERR_INV_KEYINFO);
goto leave;
}
der = vt->image + n->off;
derlen = n->nhdr + n->len;
err = parse_octet_string (&der, &derlen, &ti);
if (err)
goto leave;
derlen = ti.length;
/* gpgrt_log_printhex (der, derlen, "encryptedKey:"); */
/* Build the s-expression:
* (enc-val
* (pwri
* (derive-algo <oid>) --| both are optional
* (derive-parm <der>) --|
* (encr-algo <oid>)
* (encr-parm <iv>)
* (encr-key <key>))) -- this is the encrypted session key
*/
{
struct stringbuf sb;
init_stringbuf (&sb, 200);
put_stringbuf (&sb, "(7:enc-val(4:pwri");
if (keyderivealgo && parm3)
{
put_stringbuf (&sb, "(11:derive-algo");
put_stringbuf_sexp (&sb, keyderivealgo);
put_stringbuf (&sb, ")(11:derive-parm");
put_stringbuf_mem_sexp (&sb, parm3, parm3len);
put_stringbuf (&sb, ")");
}
put_stringbuf (&sb, "(9:encr-algo");
put_stringbuf_sexp (&sb, keywrapalgo);
put_stringbuf (&sb, ")(9:encr-parm");
put_stringbuf_mem_sexp (&sb, parm2, parm2len);
put_stringbuf (&sb, ")(8:encr-key");
put_stringbuf_mem_sexp (&sb, der, derlen);
put_stringbuf (&sb, ")))");
string = get_stringbuf (&sb);
if (!string)
err = gpg_error_from_syserror ();
}
}
else else
return NULL; /*GPG_ERR_INV_CMS_OBJ*/ return NULL; /*GPG_ERR_INV_CMS_OBJ*/
leave: leave:
xfree (keyencralgo); xfree (keyencralgo);
xfree (keywrapalgo); xfree (keywrapalgo);
xfree (keyderivealgo);
xfree (parm); xfree (parm);
xfree (parm2);
xfree (parm3);
if (err) if (err)
{ {
/* gpgrt_log_debug ("%s: error: %s\n", __func__, gpg_strerror (err)); */ /* gpgrt_log_debug ("%s: error: %s\n", __func__, gpg_strerror (err)); */
return NULL; return NULL;
} }
return string; return string;
} }
/* Provide a hash function so that we are able to hash the data */ /* Provide a hash function so that we are able to hash the data */
void void
skipping to change at line 2280 skipping to change at line 2429
err = read_and_hash_cont (cms); err = read_and_hash_cont (cms);
else else
err = gpg_error (GPG_ERR_INV_STATE); err = gpg_error (GPG_ERR_INV_STATE);
if (err) if (err)
return err; return err;
/* Calculate new stop reason */ /* Calculate new stop reason */
if (state == sSTART) if (state == sSTART)
{ {
if (cms->detached_data && !cms->data.digest) if (cms->detached_data)
{ /* We use this stop reason to inform the caller about a { /* We use this stop reason to inform the caller about a
detached signatures. Actually there is no need for him detached signatures. Actually there is no need for him
to hash the data now, he can do this also later. */ to hash the data now, he can do this also later. */
stop_reason = KSBA_SR_NEED_HASH; stop_reason = KSBA_SR_NEED_HASH;
} }
else else
{ /* The user must now provide a hash function so that we can { /* The user must now provide a hash function so that we can
hash the data in the next round */ hash the data in the next round */
stop_reason = KSBA_SR_BEGIN_DATA; stop_reason = KSBA_SR_BEGIN_DATA;
} }
 End of changes. 17 change blocks. 
8 lines changed or deleted 157 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)