* cms.c (ksba_cms_add_smime_capability): New.
authorWerner Koch <wk@gnupg.org>
Wed, 24 Mar 2004 14:26:11 +0000 (14:26 +0000)
committerWerner Koch <wk@gnupg.org>
Wed, 24 Mar 2004 14:26:11 +0000 (14:26 +0000)
(ksba_cms_release): Free the capability list.
(store_smime_capability_sequence): New.
(build_signed_data_attributes): Include the smime capabilities.
* cms.h (oidparmlist_s): New.
(ksba_cms_s): Add element CAPABILITY_LIST.
* der-encoder.c (_ksba_der_store_sequence): New.
* asn1-func.c (_ksba_asn_is_primitive): New dummy type PRE_SEQUENCE.
* der-encoder.c (set_nhdr_and_len, copy_nhdr_and_len): Support it.

NEWS
src/ChangeLog
src/asn1-func.c
src/asn1-func.h
src/cms.c
src/cms.h
src/der-encoder.c
src/der-encoder.h
src/ksba.h
src/libksba.vers

diff --git a/NEWS b/NEWS
index 1ad71dc..d103cee 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,7 @@ ksba_ocsp_get_responder_id           NEW.
 ksba_ocsp_get_cert                   NEW.
 ksba_cert_get_authority_info_access  NEW.
 ksba_cert_get_subject_info_access    NEW.
+ksba_cms_add_smime_capability        NEW.
  
 
 Noteworthy changes in version 0.9.4 (2004-02-20)
index c23e7c1..5c00642 100644 (file)
@@ -1,3 +1,15 @@
+2004-03-24  Werner Koch  <wk@gnupg.org>
+
+       * cms.c (ksba_cms_add_smime_capability): New.
+       (ksba_cms_release): Free the capability list.
+       (store_smime_capability_sequence): New.
+       (build_signed_data_attributes): Include the smime capabilities.
+       * cms.h (oidparmlist_s): New.
+       (ksba_cms_s): Add element CAPABILITY_LIST.
+       * der-encoder.c (_ksba_der_store_sequence): New.
+       * asn1-func.c (_ksba_asn_is_primitive): New dummy type PRE_SEQUENCE.
+       * der-encoder.c (set_nhdr_and_len, copy_nhdr_and_len): Support it.
+
 2004-03-17  Werner Koch  <wk@gnupg.org>
 
        * ber-help.c (_ksba_ber_parse_tl): Check for length overflow.
index 06613be..3b0c8c9 100755 (executable)
@@ -92,6 +92,7 @@ _ksba_asn_is_primitive (node_type_t type)
     case TYPE_UNIVERSAL_STRING:                      
     case TYPE_CHARACTER_STRING:                      
     case TYPE_BMP_STRING:                            
+    case TYPE_PRE_SEQUENCE:
       return 1;
     default:
       return 0;
@@ -429,6 +430,7 @@ _ksba_asn_node_dump (AsnNode p, FILE *fp)
     case TYPE_GENERALIZED_TIME: typestr = "GENERALIZEDTIME"; break;
     case TYPE_BOOLEAN:     typestr = "BOOLEAN"; break;
     case TYPE_SEQUENCE:            typestr = "SEQUENCE"; break;
+    case TYPE_PRE_SEQUENCE: typestr = "PRE_SEQUENCE"; break;
     case TYPE_BIT_STRING:   typestr = "BIT_STR"; break;
     case TYPE_OCTET_STRING: typestr = "OCT_STR"; break;
     case TYPE_TAG:         typestr = "TAG"; break;
index ad2081f..6fbe087 100755 (executable)
@@ -63,7 +63,8 @@ typedef enum {
   TYPE_SET_OF,
   TYPE_DEFINITIONS,
   TYPE_CHOICE,
-  TYPE_IMPORTS
+  TYPE_IMPORTS,
+  TYPE_PRE_SEQUENCE  /* premanufactured Seqences as used by the DER encoder. */
 } node_type_t;
 
 
index 76b6bf7..e153a02 100644 (file)
--- a/src/cms.c
+++ b/src/cms.c
@@ -68,11 +68,15 @@ static struct {
 
 static char oidstr_contentType[] = "1.2.840.113549.1.9.3";
 /*static char oid_contentType[9] = "\x2A\x86\x48\x86\xF7\x0D\x01\x09\x03";*/
+
 static char oidstr_messageDigest[] = "1.2.840.113549.1.9.4";
 static char oid_messageDigest[9] = "\x2A\x86\x48\x86\xF7\x0D\x01\x09\x04";
+
 static char oidstr_signingTime[] = "1.2.840.113549.1.9.5";
 static char oid_signingTime[9] = "\x2A\x86\x48\x86\xF7\x0D\x01\x09\x05";
 
+static char oidstr_smimeCapabilities[] = "1.2.840.113549.1.9.15";
+
 \f
 /* copy all the bytes from the reader to the writer and hash them if a
    a hash function has been set.  The writer may be NULL to just do
@@ -488,6 +492,14 @@ ksba_cms_release (ksba_cms_t cms)
       xfree (cms->sig_val->value);
       cms->sig_val = tmp;
     }
+  while (cms->capability_list)
+    { 
+      struct oidparmlist_s *tmp = cms->capability_list->next;
+      xfree (cms->capability_list->oid);
+      xfree (cms->capability_list);
+      cms->capability_list = tmp;
+    }
+
   xfree (cms);
 }
 
@@ -1385,6 +1397,52 @@ ksba_cms_add_cert (ksba_cms_t cms, ksba_cert_t cert)
 }
 
 
+/* Add an S/MIME capability as an extended attribute to the message.
+   This function is to be called for each capability in turn. The
+   first capability added will receive the highest priority.  CMS is
+   the context, OID the object identifier of the capability and if DER
+   is not NULL it is used as the DER-encoded parameters of the
+   capability; the length of that DER object is given in DERLEN.
+   DERLEN should be 0 if DER is NULL.
+
+   The function returns 0 on success or an error code.
+*/
+gpg_error_t
+ksba_cms_add_smime_capability (ksba_cms_t cms, const char *oid,
+                               const unsigned char *der, size_t derlen)
+{
+  gpg_error_t err;
+  struct oidparmlist_s *opl, *opl2;
+
+  if (!cms || !oid)
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  opl = xtrymalloc (sizeof *opl + derlen - 1);
+  if (!opl)
+    return gpg_error_from_errno (errno);
+  opl->next = NULL;
+  opl->oid = xtrystrdup (oid);
+  if (!opl->oid)
+    {
+      err = gpg_error_from_errno (errno);
+      xfree (opl);
+      return err;
+    }
+
+  /* Append it to maintain the desired order. */
+  if (!cms->capability_list)
+    cms->capability_list = opl;
+  else
+    {
+      for (opl2=cms->capability_list; opl2->next; opl2 = opl2->next)
+        ;
+      opl2->next = opl;
+    }
+
+  return 0;
+}
+
+
 
 /**
  * ksba_cms_set_message_digest:
@@ -1428,7 +1486,7 @@ ksba_cms_set_message_digest (ksba_cms_t cms, int idx,
  * ksba_cms_set_signing_time:
  * @cms: A CMS object
  * @idx: The index of the signer
- * @sigtime: a time or an emty value to use the current time
+ * @sigtime: a time or an empty value to use the current time
  * 
  * Set a signing time into the signedAttributes of the signer with
  * the index IDX.  The index of a signer is determined by the sequence
@@ -1451,7 +1509,7 @@ ksba_cms_set_signing_time (ksba_cms_t cms, int idx, const ksba_isotime_t sigtime
   if (!cl)
     return gpg_error (GPG_ERR_INV_INDEX); /* no certificate to store it */
   
-  /* Fixme: We might want to check the validity of the pased time
+  /* Fixme: We might want to check the validity of the passed time
      string. */
   if (!*sigtime)
     _ksba_current_time (cl->signing_time);
@@ -1460,6 +1518,7 @@ ksba_cms_set_signing_time (ksba_cms_t cms, int idx, const ksba_isotime_t sigtime
   return 0;
 }
 
+
 /*
   r_sig  = (sig-val
              (<algo>
@@ -2123,6 +2182,59 @@ set_issuer_serial (AsnNode info, ksba_cert_t cert, int mode)
 }
 
 
+/* Store the sequence of capabilities at NODE */
+static gpg_error_t
+store_smime_capability_sequence (AsnNode node,
+                                 struct oidparmlist_s *capabilities)
+{
+  gpg_error_t err;
+  struct oidparmlist_s *cap, *cap2;
+  unsigned char *value;
+  size_t valuelen;
+  ksba_writer_t tmpwrt;
+
+  err = ksba_writer_new (&tmpwrt);
+  if (err)
+    return err;
+  err = ksba_writer_set_mem (tmpwrt, 512);
+  if (err)
+    {
+      ksba_writer_release (tmpwrt);
+      return err;
+    }
+    
+  for (cap=capabilities; cap; cap = cap->next)
+    {
+      /* (avoid writing duplicates) */
+      for (cap2=capabilities; cap2 != cap; cap2 = cap2->next)
+        {
+          if (!strcmp (cap->oid, cap2->oid)
+              && cap->parmlen && cap->parmlen == cap2->parmlen
+              && !memcmp (cap->parm, cap2->parm, cap->parmlen))
+            break; /* Duplicate found. */
+        }
+      if (cap2 == cap)
+        {
+          err = _ksba_der_write_algorithm_identifier
+                 (tmpwrt, cap->oid, cap->parmlen?cap->parm:NULL, cap->parmlen);
+          if (err)
+            {
+              ksba_writer_release (tmpwrt);
+              return err;
+            }
+        }
+    }
+  
+  value = ksba_writer_snatch_mem (tmpwrt, &valuelen);
+  if (!value)
+    err = gpg_error (GPG_ERR_ENOMEM);
+  if (!err)
+    err = _ksba_der_store_sequence (node, value, valuelen);
+  xfree (value);
+  ksba_writer_release (tmpwrt);
+  return err;
+}
+
 
 /* An object used to construct the signed attributes. */
 struct attrarray_s {
@@ -2232,7 +2344,7 @@ build_signed_data_attributes (ksba_cms_t cms)
       unsigned char *image;
       size_t imagelen;
       int i;
-      struct attrarray_s attrarray[3]; 
+      struct attrarray_s attrarray[4]; 
       int attridx = 0;
 
       if (!digestlist)
@@ -2299,7 +2411,7 @@ build_signed_data_attributes (ksba_cms_t cms)
       if (certlist->signing_time)
         {
           attr = _ksba_asn_expand_tree (cms_tree->parse_tree, 
-                                        "CryptographicMessageSyntax.Attribute");
+                                     "CryptographicMessageSyntax.Attribute");
           if (!attr)
             return gpg_error (GPG_ERR_ELEMENT_NOT_FOUND);
           n = _ksba_asn_find_node (attr, "Attribute.attrType");
@@ -2325,6 +2437,36 @@ build_signed_data_attributes (ksba_cms_t cms)
           attridx++;
         }
 
+      /* Include the S/MIME capabilities with the first signer. */
+      if (cms->capability_list && !signer)
+        {
+          attr = _ksba_asn_expand_tree (cms_tree->parse_tree, 
+                                    "CryptographicMessageSyntax.Attribute");
+          if (!attr)
+            return gpg_error (GPG_ERR_ELEMENT_NOT_FOUND);
+          n = _ksba_asn_find_node (attr, "Attribute.attrType");
+          if (!n)
+            return gpg_error (GPG_ERR_ELEMENT_NOT_FOUND);
+          err = _ksba_der_store_oid (n, oidstr_smimeCapabilities);
+          if (err)
+            return err;
+          n = _ksba_asn_find_node (attr, "Attribute.attrValues");
+          if (!n || !n->down)
+            return gpg_error (GPG_ERR_ELEMENT_NOT_FOUND);
+          n = n->down; /* fixme: ugly hack */
+          err = store_smime_capability_sequence (n, cms->capability_list);
+          if (err)
+            return err;
+          err = _ksba_der_encode_tree (attr, &image, &imagelen);
+          if (err)
+            return err;
+          attrarray[attridx].root = attr;
+          attrarray[attridx].image = image;
+          attrarray[attridx].imagelen = imagelen;
+          attridx++;
+        }
+
+
       /* Arggh.  That silly ASN.1 DER encoding rules: We need to sort
          the SET values. */
       qsort (attrarray, attridx, sizeof (struct attrarray_s),
index 611b8a6..4750914 100644 (file)
--- a/src/cms.h
+++ b/src/cms.h
@@ -50,6 +50,15 @@ struct oidlist_s {
   char *oid;
 };
 
+/* A structure to store an OID and a parameter. */
+struct oidparmlist_s {
+  struct oidparmlist_s *next;
+  char *oid;
+  size_t parmlen;
+  unsigned char parm[1];
+};
+
+
 struct certlist_s {
   struct certlist_s *next;
   ksba_cert_t cert;
@@ -121,6 +130,8 @@ struct ksba_cms_s {
   struct certlist_s *cert_info_list; /* A list with certificates intended
                                         to be send with a signed message */
 
+  struct oidparmlist_s *capability_list; /* A list of S/MIME capabilities. */
+  
   struct signer_info_s *signer_info;
 
   struct value_tree_s *recp_info;
index 747501a..fe96188 100644 (file)
@@ -1,5 +1,5 @@
 /* der-decoder.c - Distinguished Encoding Rules Encoder
- *      Copyright (C) 2001 g10 Code GmbH
+ *      Copyright (C) 2001, 2004 g10 Code GmbH
  *
  * This file is part of KSBA.
  *
@@ -142,7 +142,7 @@ _ksba_der_write_algorithm_identifier (ksba_writer_t w, const char *oid,
 
   /* write the sequence */
   /* fixme: the the length to encode the TLV values are actually not
-     just 2 byte each but does prendend on the length of the values - for
+     just 2 byte each but depend on the length of the values - for
      our purposes the static values do work */
   err = _ksba_ber_write_tl (w, TYPE_SEQUENCE, CLASS_UNIVERSAL, 1,
                             4 + len + (parm? parmlen:0));
@@ -355,6 +355,22 @@ _ksba_der_store_octet_string (AsnNode node, const char *buf, size_t len)
     return gpg_error (GPG_ERR_INV_VALUE);
 }
 
+
+gpg_error_t
+_ksba_der_store_sequence (AsnNode node, const unsigned char *buf, size_t len)
+{
+  if (node->type == TYPE_ANY)
+    node->type = TYPE_PRE_SEQUENCE;
+
+  if (node->type == TYPE_SEQUENCE || node->type == TYPE_PRE_SEQUENCE)
+    {
+      return store_value (node, buf, len);
+    }
+  else
+    return gpg_error (GPG_ERR_INV_VALUE);
+}
+
+
 gpg_error_t
 _ksba_der_store_null (AsnNode node)
 {
@@ -387,7 +403,7 @@ set_nhdr_and_len (AsnNode node, unsigned long length)
     buflen++;
   else if (node->type == TYPE_TAG)
     buflen++; 
-  else if (node->type < 0x1f)
+  else if (node->type < 0x1f || node->type == TYPE_PRE_SEQUENCE)
     buflen++;
   else
     {
@@ -431,6 +447,8 @@ copy_nhdr_and_len (unsigned char *buffer, AsnNode node)
     tag = TYPE_SET;
   else if (tag == TYPE_SEQUENCE_OF)
     tag = TYPE_SEQUENCE;
+  else if (tag == TYPE_PRE_SEQUENCE)
+    tag = TYPE_SEQUENCE;
   else if (tag == TYPE_TAG)
     {
       class = CLASS_CONTEXT;  /* Hmmm: we no way to handle other classes */
@@ -461,7 +479,7 @@ copy_nhdr_and_len (unsigned char *buffer, AsnNode node)
       int i;
 
       /* fixme: if we know the sizeof an ulong we could support larger
-         objetcs - however this is pretty ridiculous */
+         objects - however this is pretty ridiculous */
       i = (length <= 0xff ? 1:
            length <= 0xffff ? 2: 
            length <= 0xffffff ? 3: 4);
@@ -587,14 +605,3 @@ _ksba_der_encode_tree (AsnNode root,
     *r_imagelen = imagelen;
   return 0;
 }
-
-
-
-
-
-
-
-
-
-
-
index 9026bdf..f6ecdc0 100644 (file)
@@ -51,6 +51,8 @@ gpg_error_t _ksba_der_store_integer (AsnNode node, const unsigned char *value);
 gpg_error_t _ksba_der_store_oid (AsnNode node, const char *oid);
 gpg_error_t _ksba_der_store_octet_string (AsnNode node,
                                         const char *buf, size_t len);
+gpg_error_t _ksba_der_store_sequence (AsnNode node,
+                                      const unsigned char *buf, size_t len);
 gpg_error_t _ksba_der_store_null (AsnNode node);
 
 
index 7a761c3..31b8c35 100644 (file)
@@ -342,6 +342,9 @@ gpg_error_t ksba_cms_set_content_type (ksba_cms_t cms, int what,
 gpg_error_t ksba_cms_add_digest_algo (ksba_cms_t cms, const char *oid);
 gpg_error_t ksba_cms_add_signer (ksba_cms_t cms, ksba_cert_t cert);
 gpg_error_t ksba_cms_add_cert (ksba_cms_t cms, ksba_cert_t cert);
+gpg_error_t ksba_cms_add_smime_capability (ksba_cms_t cms, const char *oid,
+                                           const unsigned char *der,
+                                           size_t derlen);
 gpg_error_t ksba_cms_set_message_digest (ksba_cms_t cms, int idx,
                                          const char *digest,
                                          size_t digest_len);
index ca815ad..75fa1b7 100644 (file)
@@ -55,6 +55,7 @@ KSBA_0.9 {
     ksba_cms_set_enc_val; ksba_cms_set_hash_function;
     ksba_cms_set_message_digest; ksba_cms_set_reader_writer;
     ksba_cms_set_sig_val; ksba_cms_set_signing_time;
+    ksba_cms_add_smime_capability;
 
     ksba_crl_get_digest_algo; ksba_crl_get_issuer; ksba_crl_get_item;
     ksba_crl_get_sig_val; ksba_crl_get_update_times; ksba_crl_new;