From b63a3e56321237851a1b996d37f32f2f507dc774 Mon Sep 17 00:00:00 2001 From: Steffen Hansen Date: Thu, 30 May 2002 06:24:19 +0000 Subject: [PATCH] * cryptplug.h, gpgmeplug.c: Added certificate info listing functions. Not yet complete. Converted more C99 style comments to "classic" style. --- trunk/gpgmeplug/ChangeLog | 6 + trunk/gpgmeplug/cryptplug.h | 58 +++++-- trunk/gpgmeplug/gpgmeplug.c | 330 +++++++++++++++++++++++++++++++++++- 3 files changed, 379 insertions(+), 15 deletions(-) diff --git a/trunk/gpgmeplug/ChangeLog b/trunk/gpgmeplug/ChangeLog index ebecd98..b7627a1 100644 --- a/trunk/gpgmeplug/ChangeLog +++ b/trunk/gpgmeplug/ChangeLog @@ -1,3 +1,9 @@ +2002-05-30 Steffen Hansen + + * 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 * gpgmeplug.c: Converted it to real C; i.e. use standard comments - diff --git a/trunk/gpgmeplug/cryptplug.h b/trunk/gpgmeplug/cryptplug.h index 72cfdf4..0c00f3c 100644 --- a/trunk/gpgmeplug/cryptplug.h +++ b/trunk/gpgmeplug/cryptplug.h @@ -32,9 +32,6 @@ typedef char bool; #endif #include -//#include -//#include - /*! \file cryptplug.h \brief Common API header for CRYPTPLUG. @@ -160,6 +157,9 @@ typedef char bool; plugin you should ignore this 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.)
@@ -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/trunk/gpgmeplug/gpgmeplug.c b/trunk/gpgmeplug/gpgmeplug.c index 43312d4..6741679 100644 --- a/trunk/gpgmeplug/gpgmeplug.c +++ b/trunk/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 ); +} -- 2.26.2