* cryptplug.h, gpgmeplug.c: Added certificate info listing functions.
authorSteffen Hansen <hansen@kde.org>
Thu, 30 May 2002 06:24:19 +0000 (06:24 +0000)
committerSteffen Hansen <hansen@kde.org>
Thu, 30 May 2002 06:24:19 +0000 (06:24 +0000)
Not yet complete.
Converted more C99 style comments to "classic" style.

gpgmeplug/ChangeLog
gpgmeplug/cryptplug.h
gpgmeplug/gpgmeplug.c

index ebecd98..b7627a1 100644 (file)
@@ -1,3 +1,9 @@
+2002-05-30  Steffen Hansen  <steffen@hrhansen.dk>
+
+       * cryptplug.h, gpgmeplug.c: Added certificate info listing functions. 
+       Not yet complete. 
+       Converted more C99 style comments to "classic" style.
+
 2002-03-23  Werner Koch  <wk@gnupg.org>
 
        * gpgmeplug.c: Converted it to real C; i.e. use standard comments -
index 72cfdf4..0c00f3c 100644 (file)
@@ -32,9 +32,6 @@ typedef char bool;
 #endif
 
 #include <stdlib.h>
-//#include <string.h>
-//#include <ctype.h>
-
 
 /*! \file cryptplug.h
     \brief Common API header for CRYPTPLUG.
@@ -160,6 +157,9 @@ typedef char bool;
     plugin <b>you should ignore this</b> section!
 */
 
+/*! \defgroup certList Certificate Info listing functions
+ */
+
 
 typedef enum {
   Feature_undef             = 0,
@@ -179,10 +179,11 @@ typedef enum {
   Feature_StoreMessagesEncrypted = 13,
   Feature_CheckCertificatePath = 14,
   Feature_CertificateDirectoryService = 15,
-  Feature_CRLDirectoryService = 16
+  Feature_CRLDirectoryService = 16,
+  Feature_CertificateInfo     = 17
 } Feature;
 
-// dummy values
+/* dummy values */
 typedef enum {
   PinRequest_undef            = 0,
 
@@ -193,7 +194,7 @@ typedef enum {
   PinRequest_AfterMinutes     = 5
 } PinRequests;
 
-// dummy values:
+/* dummy values: */
 typedef enum {
   SendCert_undef              = 0,
 
@@ -203,7 +204,7 @@ typedef enum {
   SendCert_SendChainWithRoot  = 4
 } SendCertificates;
 
-// dummy values:
+/* dummy values: */
 typedef enum {
   SignAlg_undef               = 0,
 
@@ -1212,7 +1213,7 @@ struct StructuringInfo {
                                   FALSE) */
   bool  makeMimeObject;      /*!< specifies whether we should create a MIME
                                   object or a flat text message body */
-  // the following are used for MIME messages only
+  /* the following are used for MIME messages only */
   bool  makeMultiMime;       /*!< specifies whether we should create a
                                   'Multipart' MIME object or a single part
                                   object, if FALSE only \c contentTypeMain,
@@ -1279,7 +1280,7 @@ struct StructuringInfo {
                                   \c makeMimeObject or \c makeMultiMime
                                   is FALSE or if \c contentTypeCode does
                                   not return a non-zero-length string) */
-  // the following are used for flat non-MIME messages only
+  /* the following are used for flat non-MIME messages only */
   char* flatTextPrefix;      /*!< text to preceed the main text (or the
                                   code bloc containing the encrypted main
                                   text, resp.)<br>
@@ -1323,7 +1324,7 @@ struct StructuringInfo {
     \see free_StructuringInfo, StructuringInfo
     \see signMessage, encryptMessage, encryptAndSignMessage
 */
-  void init_StructuringInfo( struct StructuringInfo* s )
+  static void init_StructuringInfo( struct StructuringInfo* s )
   {
     if( ! s ) return;
 
@@ -1364,7 +1365,7 @@ struct StructuringInfo {
 
     \see StructuringInfo
 */
-  void free_StructuringInfo( struct StructuringInfo* s )
+  static void free_StructuringInfo( struct StructuringInfo* s )
   {
     if( ! s ) return;
     if( s->contentTypeMain )    free( s->contentTypeMain );
@@ -1691,6 +1692,41 @@ const char* displayCRL( void );
 */
 void updateCRL( void );
 
+struct CertIterator;
+
+struct DnPair {
+    char *key;
+    char *value;
+};
+
+struct CertificateInfo {
+  char** userid;
+  char** issuer;
+  struct DnPair *dnarray;
+};
+
+/*! \function struct CertIterator*  startListCertificates( void );
+    \function struct CertificateInfo*  nextCertificate( struct CertIterator* );
+    \function void endListCertificates( struct CertIterator* );
+
+    \ingroup certList
+  Example:
+\verbatim
+  struct CertificateInfo* info;
+  struct CertIterator* it = startListCertificates();
+  while( info = nextCertificate( it ) ) {
+    do something with info.
+    dont free() it, the struct will be reused
+    by the next call to nextCertificate()
+  }
+  endListCertificates( it );
+\endverbatim
+*/
+struct CertIterator*  startListCertificates( void );
+struct CertificateInfo*  nextCertificate( struct CertIterator* );
+void endListCertificates( struct CertIterator* );
+
+
 #ifdef __cplusplus
 }
 #endif
index 43312d4..6741679 100644 (file)
@@ -249,6 +249,7 @@ bool hasFeature( Feature flag )
   case Feature_CheckCertificatePath:      return true;
   case Feature_CertificateDirectoryService: return true;
   case Feature_CRLDirectoryService:       return true;
+  case Feature_CertificateInfo:           return true;
   /* undefined or not yet implemented: */
   case Feature_undef:                     return false;
   default:                                      return false;
@@ -452,7 +453,7 @@ bool signatureCertificateExpiryNearWarning( void )
 
 int signatureCertificateDaysLeftToExpiry( const char* certificate )
 {
-  // pending (khz): make this work!
+  /* pending (khz): make this work! */
   /*
   GpgmeCtx ctx;
   GpgmeError err;
@@ -1608,8 +1609,8 @@ bool requestDecentralCertificate( const char* certparms,
     }
 
     gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
-    // Don't ASCII-armor, the MUA will use base64 encoding
-    //    gpgme_set_armor (ctx, 1);
+    /* Don't ASCII-armor, the MUA will use base64 encoding */
+    /*    gpgme_set_armor (ctx, 1); */
     err = gpgme_op_genkey (ctx, certparms, pub, NULL );
     fprintf( stderr,  "3: gpgme returned %d\n", err );
     if( err != GPGME_No_Error ) {
@@ -1623,7 +1624,7 @@ bool requestDecentralCertificate( const char* certparms,
     *length = len;
 
     /* The buffer generatedKey contains the LEN bytes you want */
-    // Caller is responsible for freeing
+    /* Caller is responsible for freeing */
     return true;
 }
 
@@ -1648,3 +1649,324 @@ bool archiveCertificate( const char* certificate ){ return true; }
 const char* displayCRL(){ return 0; }
 
 void updateCRL(){}
+
+/*
+ * Copyright (C) 2002 g10 Code GmbH
+ * 
+ *     This program is free software; you can redistribute it
+ *     and/or modify it under the terms of the GNU General Public
+ *     License as published by the Free Software Foundation; either
+ *     version 2 of the License, or (at your option) any later
+ *     version.
+ * 
+ *     This program is distributed in the hope that it will be
+ *     useful, but WITHOUT ANY WARRANTY; without even the implied
+ *     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ *     PURPOSE.  See the GNU General Public License for more
+ *     details.
+ * 
+ *     You should have received a copy of the GNU General Public
+ *     License along with this program; if not, write to the Free
+ *     Software Foundation, Inc., 59 Temple Place - Suite 330,
+ *     Boston, MA  02111, USA.
+ */
+
+/* some macros to replace ctype ones and avoid locale problems */
+#define spacep(p)   (*(p) == ' ' || *(p) == '\t')
+#define digitp(p)   (*(p) >= '0' && *(p) <= '9')
+#define hexdigitp(a) (digitp (a)                     \
+                      || (*(a) >= 'A' && *(a) <= 'F')  \
+                      || (*(a) >= 'a' && *(a) <= 'f'))
+/* the atoi macros assume that the buffer has only valid digits */
+#define atoi_1(p)   (*(p) - '0' )
+#define atoi_2(p)   ((atoi_1(p) * 10) + atoi_1((p)+1))
+#define atoi_4(p)   ((atoi_2(p) * 100) + atoi_2((p)+2))
+#define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
+                     *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
+#define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
+
+#define safe_malloc( x ) malloc( x )
+
+static void safe_free( void** x ) 
+{
+  free( *x );
+  *x = 0;
+}
+/*#define safe_free( x ) free( x )*/
+
+
+struct dn_array_s {
+  char *key;
+  char *value;
+};
+
+
+/* Parse a DN and return an array-ized one.  This is not a validating
+   parser and it does not support any old-stylish syntax; gpgme is
+   expected to return only rfc2253 compatible strings. */
+static const unsigned char *
+parse_dn_part (struct dn_array_s *array, const unsigned char *string)
+{
+  const unsigned char *s, *s1;
+  size_t n;
+  unsigned char *p;
+
+  /* parse attributeType */
+  for (s = string+1; *s && *s != '='; s++)
+    ;
+  if (!*s)
+    return NULL; /* error */
+  n = s - string;
+  if (!n)
+    return NULL; /* empty key */
+  array->key = p = safe_malloc (n+1);
+  memcpy (p, string, n); /* fixme: trim trailing spaces */
+  p[n] = 0;
+  string = s + 1;
+
+  if (*string == '#')
+    { /* hexstring */
+      string++;
+      for (s=string; hexdigitp (s); s++)
+        s++;
+      n = s - string;
+      if (!n || (n & 1))
+        return NULL; /* empty or odd number of digits */
+      n /= 2;
+      array->value = p = safe_malloc (n+1);
+      for (s1=string; n; s1 += 2, n--)
+        *p++ = xtoi_2 (s1);
+      *p = 0;
+   }
+  else
+    { /* regular v3 quoted string */
+      for (n=0, s=string; *s; s++)
+        {
+          if (*s == '\\')
+            { /* pair */
+              s++;
+              if (*s == ',' || *s == '=' || *s == '+'
+                  || *s == '<' || *s == '>' || *s == '#' || *s == ';' 
+                  || *s == '\\' || *s == '\"' || *s == ' ')
+                n++;
+              else if (hexdigitp (s) && hexdigitp (s+1))
+                {
+                  s++;
+                  n++;
+                }
+              else
+                return NULL; /* invalid escape sequence */
+            }
+          else if (*s == '\"')
+            return NULL; /* invalid encoding */
+          else if (*s == ',' || *s == '=' || *s == '+'
+                   || *s == '<' || *s == '>' || *s == '#' || *s == ';' )
+            break; 
+          else
+            n++;
+        }
+
+      array->value = p = safe_malloc (n+1);
+      for (s=string; n; s++, n--)
+        {
+          if (*s == '\\')
+            { 
+              s++;
+              if (hexdigitp (s))
+                {
+                  *p++ = xtoi_2 (s);
+                  s++;
+                }
+              else
+                *p++ = *s;
+            }
+          else
+            *p++ = *s;
+        }
+      *p = 0;
+    }
+  return s;
+}
+
+
+/* Parse a DN and return an array-ized one.  This is not a validating
+   parser and it does not support any old-stylish syntax; gpgme is
+   expected to return only rfc2253 compatible strings. */
+static struct dn_array_s *
+parse_dn (const unsigned char *string)
+{
+  struct dn_array_s *array;
+  size_t arrayidx, arraysize;
+  int i;
+
+  arraysize = 7; /* C,ST,L,O,OU,CN,email */
+  array = safe_malloc ((arraysize+1) * sizeof *array);
+  arrayidx = 0;
+  while (*string)
+    {
+      while (*string == ' ')
+        string++;
+      if (!*string)
+        break; /* ready */
+      if (arrayidx >= arraysize)
+        { /* mutt lacks a real safe_realoc - so we need to copy */
+          struct dn_array_s *a2;
+
+          arraysize += 5;
+          a2 = safe_malloc ((arraysize+1) * sizeof *array);
+          for (i=0; i < arrayidx; i++)
+            {
+              a2[i].key = array[i].key;
+              a2[i].value = array[i].value;
+            }
+          safe_free ((void **)&array);
+          array = a2;
+        }
+      array[arrayidx].key = NULL;
+      array[arrayidx].value = NULL;
+      string = parse_dn_part (array+arrayidx, string);
+      arrayidx++;
+      if (!string)
+        goto failure;
+      while (*string == ' ')
+        string++;
+      if (*string && *string != ',' && *string != ';' && *string != '+')
+        goto failure; /* invalid delimiter */
+      if (*string)
+        string++;
+    }
+  array[arrayidx].key = NULL;
+  array[arrayidx].value = NULL;
+  return array;
+
+ failure:
+  for (i=0; i < arrayidx; i++)
+    {
+      safe_free ((void**)&array[i].key);
+      safe_free ((void**)&array[i].value);
+    }
+  safe_free ((void**)&array);
+  return NULL;
+}
+
+
+
+struct CertIterator {
+  GpgmeCtx ctx;  
+  struct CertificateInfo info;
+};
+
+struct CertIterator* startListCertificates( void )
+{
+    GpgmeError err;
+    struct CertIterator* it;
+    /*fprintf( stderr,  "startListCertificates()" );*/
+
+    it = (struct CertIterator*)safe_malloc( sizeof( struct CertIterator ) );
+
+    err = gpgme_new (&(it->ctx));
+    /*fprintf( stderr,  "2: gpgme returned %d\n", err );*/
+    if( err != GPGME_No_Error ) {
+      free( it );
+      return NULL;
+    }
+
+    gpgme_set_protocol (it->ctx, GPGME_PROTOCOL_CMS);
+    err =  gpgme_op_keylist_start ( it->ctx, NULL, 0);
+    if( err != GPGME_No_Error ) {
+      endListCertificates( it );
+      return NULL;
+    }
+    memset( &(it->info), 0, sizeof( struct CertificateInfo ) );
+    return it;
+}
+
+#define MAX_GPGME_IDX 20
+
+static void freeStringArray( char** c )
+{
+    char** _c = c;
+    while( c && *c ) {
+      /*fprintf( stderr, "freeing \"%s\"\n", *c );*/
+      safe_free( (void**)&(*c) );
+      ++c;
+    }
+    safe_free( (void**)&_c );
+}
+
+static void freeInfo( struct CertificateInfo* info )
+{
+  struct DnPair* a = info->dnarray;
+  assert( info );
+  /*fprintf( stderr, "freeing info->userid\n" );*/
+  if( info->userid ) freeStringArray( info->userid );
+  /*fprintf( stderr, "freeing info->issuer\n" );*/
+  if( info->issuer ) freeStringArray( info->issuer );
+  /*fprintf( stderr, "freed\n" );*/
+  while( a && a->key && a->value ) {
+    /*fprintf( stderr, "freeing %s\n", a->key );*/
+    safe_free ((void**)&(a->key));
+    safe_free ((void**)&(a->value));
+    ++a;
+  }
+  if( info->dnarray ) safe_free ((void**)&(info->dnarray));
+  memset( info, 0, sizeof( *info ) );
+}
+
+#define xstrdup( x ) (x)?strdup(x):0
+
+struct CertificateInfo* nextCertificate( struct CertIterator* it )
+{
+  GpgmeError err;
+  GpgmeKey   key;
+  assert( it );
+  err = gpgme_op_keylist_next ( it->ctx, &key);
+  if( err != GPGME_EOF ) {   
+    int idx;
+    const char* s;
+    char* names[MAX_GPGME_IDX+1];
+    memset( names, 0, sizeof( names ) );
+    freeInfo( &(it->info) );
+
+    for( idx = 0; (s = gpgme_key_get_string_attr (key, GPGME_ATTR_USERID, 0, idx)) && idx < MAX_GPGME_IDX; 
+        ++idx ) {
+      names[idx] = xstrdup( s );
+    }
+    
+    it->info.userid = safe_malloc( sizeof( char* ) * (idx+1) );
+    memset( it->info.userid, 0, sizeof( char* ) * (idx+1) );
+    it->info.dnarray = 0;
+    for( idx = 0; names[idx] != 0; ++idx ) {
+      struct DnPair* a = parse_dn( names[idx] ); 
+      it->info.userid[idx] = names[idx];
+      it->info.dnarray = a;
+    }
+    it->info.userid[idx] = 0;
+
+    memset( names, 0, sizeof( names ) );
+    for( idx = 0; (s = gpgme_key_get_string_attr (key, GPGME_ATTR_ISSUER, 0, idx)) && idx < MAX_GPGME_IDX; 
+        ++idx ) {
+      /*fprintf(stderr, "Got issuer \"%s\"\n", s );*/
+      names[idx] = xstrdup( s );
+    }
+    it->info.issuer = safe_malloc( sizeof( char* ) * (idx+1) );
+    memset( it->info.issuer, 0, sizeof( char* ) * (idx+1) );
+    for( idx = 0; names[idx] != 0; ++idx ) {
+      it->info.issuer[idx] = names[idx];
+    }
+    it->info.issuer[idx] = 0;
+
+    gpgme_key_release (key);
+    return &(it->info);
+  } else return NULL;
+}
+
+void endListCertificates( struct CertIterator* it )
+{
+  /*fprintf( stderr,  "endListCertificates()\n" );*/
+  assert(it);
+  freeInfo( &(it->info) );
+  gpgme_op_keylist_end(it->ctx);
+  gpgme_release (it->ctx);
+  free( it );
+}