diff options
| -rw-r--r-- | gpgmeplug/ChangeLog | 6 | ||||
| -rw-r--r-- | gpgmeplug/cryptplug.h | 58 | ||||
| -rw-r--r-- | gpgmeplug/gpgmeplug.c | 330 | 
3 files changed, 379 insertions, 15 deletions
| diff --git a/gpgmeplug/ChangeLog b/gpgmeplug/ChangeLog index ebecd989..b7627a17 100644 --- a/gpgmeplug/ChangeLog +++ b/gpgmeplug/ChangeLog @@ -1,3 +1,9 @@ +2002-05-30  Steffen Hansen  <[email protected]> + +	* 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  <[email protected]>  	* gpgmeplug.c: Converted it to real C; i.e. use standard comments - diff --git a/gpgmeplug/cryptplug.h b/gpgmeplug/cryptplug.h index 72cfdf40..0c00f3c4 100644 --- a/gpgmeplug/cryptplug.h +++ b/gpgmeplug/cryptplug.h @@ -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 diff --git a/gpgmeplug/gpgmeplug.c b/gpgmeplug/gpgmeplug.c index 43312d4f..67416791 100644 --- a/gpgmeplug/gpgmeplug.c +++ b/gpgmeplug/gpgmeplug.c @@ -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 ); +} | 
