Missing implementation bug fixed: Return both error id and error plain text from...
[gpgme.git] / gpgmeplug / gpgmeplug.c
1 /* -*- Mode: C -*-
2
3   $Id$
4
5   GPGMEPLUG - an GPGME based cryptography plug-in following
6               the common CRYPTPLUG specification.
7
8   Copyright (C) 2001 by Klarälvdalens Datakonsult AB
9
10   GPGMEPLUG is free software; you can redistribute it and/or modify
11   it under the terms of GNU General Public License as published by
12   the Free Software Foundation; version 2 of the License.
13
14   GPGMEPLUG is distributed in the hope that it will be useful,
15   it under the terms of GNU General Public License as published by
16   the Free Software Foundation; version 2 of the License
17   but WITHOUT ANY WARRANTY; without even the implied warranty of
18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   GNU General Public License for more details.
20
21   You should have received a copy of the GNU General Public License
22   along with this program; if not, write to the Free Software
23   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
24 */
25
26
27
28 /*! \file gpgmeplug.c
29     \brief GPGME implementation of CRYPTPLUG following the
30     specification located in common API header cryptplug.h.
31
32     CRYPTPLUG is an independent cryptography plug-in API
33     developed for Sphinx-enabeling KMail and Mutt.
34
35     CRYPTPLUG was designed for the Aegypten project, but it may
36     be used by 3rd party developers as well to design pluggable
37     crypto backends for the above mentioned MUAs.
38
39     \note All string parameters appearing in this API are to be
40     interpreted as UTF-8 encoded.
41
42     \see cryptplug.h
43 */
44
45 #ifdef HAVE_CONFIG_H
46 #include <config.h>
47 #endif
48 #include <stdio.h>
49 #include <string.h>
50 #include <assert.h>
51 #include <errno.h>
52 #include <time.h>
53 #include <ctype.h>
54
55 #ifndef BUG_URL
56 #define BUG_URL "http:://www.gnupg.org/aegypten/"
57 #endif
58
59 #include "gpgme.h"
60 #ifndef GPGMEPLUG_PROTOCOL
61 #define GPGMEPLUG_PROTOCOL GPGME_PROTOCOL_OpenPGP
62 #endif
63
64 /* definitions for signing */
65 // 1. opaque signatures (only used for S/MIME)
66 #ifndef GPGMEPLUG_OPA_SIGN_MAKE_MIME_OBJECT
67 #define GPGMEPLUG_OPA_SIGN_INCLUDE_CLEARTEXT false
68 #define GPGMEPLUG_OPA_SIGN_MAKE_MIME_OBJECT  false
69 #define GPGMEPLUG_OPA_SIGN_MAKE_MULTI_MIME   false
70 #define GPGMEPLUG_OPA_SIGN_CTYPE_MAIN        ""
71 #define GPGMEPLUG_OPA_SIGN_CDISP_MAIN        ""
72 #define GPGMEPLUG_OPA_SIGN_CTENC_MAIN        ""
73 #define GPGMEPLUG_OPA_SIGN_CTYPE_VERSION     ""
74 #define GPGMEPLUG_OPA_SIGN_CDISP_VERSION     ""
75 #define GPGMEPLUG_OPA_SIGN_CTENC_VERSION     ""
76 #define GPGMEPLUG_OPA_SIGN_BTEXT_VERSION     ""
77 #define GPGMEPLUG_OPA_SIGN_CTYPE_CODE        ""
78 #define GPGMEPLUG_OPA_SIGN_CDISP_CODE        ""
79 #define GPGMEPLUG_OPA_SIGN_CTENC_CODE        ""
80 #define GPGMEPLUG_OPA_SIGN_FLAT_PREFIX       ""
81 #define GPGMEPLUG_OPA_SIGN_FLAT_SEPARATOR    ""
82 #define GPGMEPLUG_OPA_SIGN_FLAT_POSTFIX      ""
83 #endif
84 // 2. detached signatures (used for S/MIME and for OpenPGP)
85 #ifndef GPGMEPLUG_DET_SIGN_MAKE_MIME_OBJECT
86 #define GPGMEPLUG_DET_SIGN_INCLUDE_CLEARTEXT true
87 #define GPGMEPLUG_DET_SIGN_MAKE_MIME_OBJECT  true
88 #define GPGMEPLUG_DET_SIGN_MAKE_MULTI_MIME   true
89 #define GPGMEPLUG_DET_SIGN_CTYPE_MAIN        "multipart/signed;protocol=application/pgp-signature;micalg=pgp-sha1"
90 #define GPGMEPLUG_DET_SIGN_CDISP_MAIN        ""
91 #define GPGMEPLUG_DET_SIGN_CTENC_MAIN        ""
92 #define GPGMEPLUG_DET_SIGN_CTYPE_VERSION     ""
93 #define GPGMEPLUG_DET_SIGN_CDISP_VERSION     ""
94 #define GPGMEPLUG_DET_SIGN_CTENC_VERSION     ""
95 #define GPGMEPLUG_DET_SIGN_BTEXT_VERSION     ""
96 #define GPGMEPLUG_DET_SIGN_CTYPE_CODE        "application/pgp-signature"
97 #define GPGMEPLUG_DET_SIGN_CDISP_CODE        ""
98 #define GPGMEPLUG_DET_SIGN_CTENC_CODE        ""
99 #define GPGMEPLUG_DET_SIGN_FLAT_PREFIX       ""
100 #define GPGMEPLUG_DET_SIGN_FLAT_SEPARATOR    ""
101 #define GPGMEPLUG_DET_SIGN_FLAT_POSTFIX      ""
102 #endif
103 // 3. common definitions for opaque and detached signing
104 #ifndef __GPGMEPLUG_SIGNATURE_CODE_IS_BINARY
105 #define __GPGMEPLUG_SIGNATURE_CODE_IS_BINARY false
106 #endif
107
108 #define __GPGMEPLUG_ERROR_CLEARTEXT_IS_ZERO "Error: Cannot run checkMessageSignature() with cleartext == 0"
109
110 /* definitions for encoding */
111 #ifndef GPGMEPLUG_ENC_MAKE_MIME_OBJECT
112 #define GPGMEPLUG_ENC_INCLUDE_CLEARTEXT  false
113 #define GPGMEPLUG_ENC_MAKE_MIME_OBJECT   true
114 #define GPGMEPLUG_ENC_MAKE_MULTI_MIME    true
115 #define GPGMEPLUG_ENC_CTYPE_MAIN         "multipart/encrypted; protocol=application/pgp-encrypted"
116 #define GPGMEPLUG_ENC_CDISP_MAIN         ""
117 #define GPGMEPLUG_ENC_CTENC_MAIN         ""
118 #define GPGMEPLUG_ENC_CTYPE_VERSION      "application/pgp-encrypted"
119 #define GPGMEPLUG_ENC_CDISP_VERSION      "attachment"
120 #define GPGMEPLUG_ENC_CTENC_VERSION      ""
121 #define GPGMEPLUG_ENC_BTEXT_VERSION      "Version: 1"
122 #define GPGMEPLUG_ENC_CTYPE_CODE         "application/octet-stream"
123 #define GPGMEPLUG_ENC_CDISP_CODE         "inline; filename=\"msg.asc\""
124 #define GPGMEPLUG_ENC_CTENC_CODE         ""
125 #define GPGMEPLUG_ENC_FLAT_PREFIX        ""
126 #define GPGMEPLUG_ENC_FLAT_SEPARATOR     ""
127 #define GPGMEPLUG_ENC_FLAT_POSTFIX       ""
128 #define __GPGMEPLUG_ENCRYPTED_CODE_IS_BINARY false
129 #endif
130 /* Note: The following specification will result in
131        function encryptAndSignMessage() producing
132        _empty_ mails.
133        This must be changed as soon as our plugin
134        is supporting the encryptAndSignMessage() function. */
135 #ifndef GPGMEPLUG_ENCSIGN_MAKE_MIME_OBJECT
136 #define GPGMEPLUG_ENCSIGN_INCLUDE_CLEARTEXT false
137 #define GPGMEPLUG_ENCSIGN_MAKE_MIME_OBJECT  false
138 #define GPGMEPLUG_ENCSIGN_MAKE_MULTI_MIME   false
139 #define GPGMEPLUG_ENCSIGN_CTYPE_MAIN        ""
140 #define GPGMEPLUG_ENCSIGN_CDISP_MAIN        ""
141 #define GPGMEPLUG_ENCSIGN_CTENC_MAIN        ""
142 #define GPGMEPLUG_ENCSIGN_CTYPE_VERSION     ""
143 #define GPGMEPLUG_ENCSIGN_CDISP_VERSION     ""
144 #define GPGMEPLUG_ENCSIGN_CTENC_VERSION     ""
145 #define GPGMEPLUG_ENCSIGN_BTEXT_VERSION     ""
146 #define GPGMEPLUG_ENCSIGN_CTYPE_CODE        ""
147 #define GPGMEPLUG_ENCSIGN_CDISP_CODE        ""
148 #define GPGMEPLUG_ENCSIGN_CTENC_CODE        ""
149 #define GPGMEPLUG_ENCSIGN_FLAT_PREFIX       ""
150 #define GPGMEPLUG_ENCSIGN_FLAT_SEPARATOR    ""
151 #define GPGMEPLUG_ENCSIGN_FLAT_POSTFIX      ""
152 #endif
153
154 #include "cryptplug.h"
155
156
157 typedef struct {
158   const char*             bugURL;
159   const char*             signatureKeyCertificate;
160   SignatureAlgorithm      signatureAlgorithm;
161   SignatureCompoundMode   signatureCompoundMode;
162   SendCertificates        sendCertificates;
163   SignEmail               signEmail;
164   bool                    saveSentSignatures;
165   bool                    warnNoCertificate;
166   PinRequests             numPINRequests;
167   bool                    checkSignatureCertificatePathToRoot;
168   bool                    signatureUseCRLs;
169   EncryptionAlgorithm     encryptionAlgorithm;
170   EncryptEmail            encryptEmail;
171   bool                    saveMessagesEncrypted;
172   bool                    checkEncryptionCertificatePathToRoot;
173   bool                    encryptionUseCRLs;
174   bool                    encryptionCRLExpiryNearWarning;
175   int                     encryptionCRLNearExpiryInterval;
176   struct DirectoryServer *directoryServers;
177   unsigned int            numDirectoryServers;
178   CertificateSource       certificateSource;
179   CertificateSource       cRLSource;
180   bool                    warnSendUnsigned;
181   int                     numPINRequestsInterval;
182   bool                    signatureCertificateExpiryNearWarning;
183   int                     signatureCertificateExpiryNearInterval;
184   bool                    cACertificateExpiryNearWarning;
185   int                     cACertificateExpiryNearInterval;
186   bool                    rootCertificateExpiryNearWarning;
187   int                     rootCertificateExpiryNearInterval;
188   bool                    warnSendUnencrypted;
189   bool                    checkCertificatePath;
190   bool                    receiverCertificateExpiryNearWarning;
191   int                     receiverCertificateExpiryNearWarningInterval;
192   bool                    certificateInChainExpiryNearWarning;
193   int                     certificateInChainExpiryNearWarningInterval;
194   bool                    receiverEmailAddressNotInCertificateWarning;
195   const char* libVersion; // a statically allocated string with the GPGME Version used
196 } Config;
197
198
199 Config config;
200
201 #define NEAR_EXPIRY 14
202
203 bool initialize()
204 {
205   config.bugURL                               = malloc( strlen( BUG_URL ) + 1 );
206   strcpy( (char* )config.bugURL,                BUG_URL );
207   config.signatureKeyCertificate              = malloc( 1 );
208   strcpy( (char* )config.signatureKeyCertificate, "" );
209   config.signatureAlgorithm                   = SignAlg_SHA1;
210   if( GPGMEPLUG_PROTOCOL == GPGME_PROTOCOL_CMS )
211     config.signatureCompoundMode              = SignatureCompoundMode_Opaque;
212   else
213     config.signatureCompoundMode              = SignatureCompoundMode_Detached;
214   config.sendCertificates                     = SendCert_SendChainWithRoot;
215   config.signEmail                            = SignEmail_SignAll;
216   config.saveSentSignatures                   = true;
217   config.warnNoCertificate                    = true;
218   config.numPINRequests                       = PinRequest_Always;
219   config.checkSignatureCertificatePathToRoot  = true;
220   config.signatureUseCRLs                     = true;
221   config.encryptionAlgorithm                  = EncryptAlg_RSA;
222   config.encryptEmail                         = EncryptEmail_Ask;
223   config.saveMessagesEncrypted                = true;
224   config.checkEncryptionCertificatePathToRoot = true;
225   config.encryptionUseCRLs                    = true;
226   config.encryptionCRLExpiryNearWarning       = true;
227   config.encryptionCRLNearExpiryInterval      = NEAR_EXPIRY;
228   config.directoryServers                     = NULL;
229   config.numDirectoryServers                  = 0;
230   config.certificateSource                    = CertSrc_Server;
231   config.cRLSource                            = CertSrc_Server;
232   config.warnSendUnsigned                             = true;
233   config.numPINRequestsInterval                       = NEAR_EXPIRY;
234   config.signatureCertificateExpiryNearWarning        = true;
235   config.signatureCertificateExpiryNearInterval       = NEAR_EXPIRY;
236   config.cACertificateExpiryNearWarning               = true;
237   config.cACertificateExpiryNearInterval              = NEAR_EXPIRY;
238   config.rootCertificateExpiryNearWarning             = true;
239   config.rootCertificateExpiryNearInterval            = NEAR_EXPIRY;
240   config.warnSendUnencrypted                          = false;
241   config.checkCertificatePath                         = true;
242   config.receiverCertificateExpiryNearWarning         = true;
243   config.receiverCertificateExpiryNearWarningInterval = NEAR_EXPIRY;
244   config.certificateInChainExpiryNearWarning          = true;
245   config.certificateInChainExpiryNearWarningInterval  = NEAR_EXPIRY;
246   config.receiverEmailAddressNotInCertificateWarning  = true;
247   config.libVersion = gpgme_check_version (NULL);
248   return (gpgme_engine_check_version (GPGMEPLUG_PROTOCOL) == GPGME_No_Error);
249 };
250
251
252 void deinitialize()
253 {
254   unsigned int i;
255   for( i = 0; i < config.numDirectoryServers; ++i ) {
256     free( (char *)config.directoryServers[i].servername );
257     free( (char *)config.directoryServers[i].description );
258   }
259   free( config.directoryServers );
260 }
261
262
263 bool hasFeature( Feature flag )
264 {
265   /* our own plugins are supposed to support everything */
266   switch ( flag ) {
267   case Feature_SignMessages:              return true;
268   case Feature_VerifySignatures:          return true;
269   case Feature_EncryptMessages:           return true;
270   case Feature_DecryptMessages:           return true;
271   case Feature_SendCertificates:          return true;
272   case Feature_WarnSignCertificateExpiry: return true;
273   case Feature_WarnSignEmailNotInCertificate: return true;
274   case Feature_PinEntrySettings:          return true;
275   case Feature_StoreMessagesWithSigs:     return true;
276   case Feature_EncryptionCRLs:            return true;
277   case Feature_WarnEncryptCertificateExpiry: return true;
278   case Feature_WarnEncryptEmailNotInCertificate: return true;
279   case Feature_StoreMessagesEncrypted:    return true;
280   case Feature_CheckCertificatePath:      return true;
281   case Feature_CertificateDirectoryService: return false;
282   case Feature_CRLDirectoryService:       return false;
283   /* undefined or not yet implemented: */
284   case Feature_undef:                     return false;
285   default:                                      return false;
286   }
287 }
288
289
290 const char* libVersion(){ return config.libVersion; }
291
292
293 const char* bugURL(){ return config.bugURL; }
294
295
296 void unsafeStationery( void** pixmap, const char** menutext, char* accel,
297           const char** tooltip, const char** statusbartext ){}
298
299 void signedStationery( void** pixmap, const char** menutext, char* accel,
300           const char** tooltip, const char** statusbartext ){}
301
302 void encryptedStationery( void** pixmap, const char**
303           menutext, char* accel,
304           const char** tooltip, const char** statusbartext ){}
305
306 void signedEncryptedStationery( void** pixmap, const char**
307           menutext, char* accel,
308           const char** tooltip, const char** statusbartext ){}
309
310 const char* signatureConfigurationDialog(){ return 0; }
311
312 const char* signatureKeySelectionDialog(){ return 0; }
313
314 const char* signatureAlgorithmDialog(){ return 0; }
315
316 const char* signatureHandlingDialog(){ return 0; }
317
318 void setSignatureKeyCertificate( const char* certificate )
319 {
320   config.signatureKeyCertificate = certificate;
321 }
322
323 const char* signatureKeyCertificate()
324 {
325   return config.signatureKeyCertificate;
326 }
327
328 void setSignatureAlgorithm( SignatureAlgorithm sigAlg )
329 {
330   config.signatureAlgorithm = sigAlg;
331 }
332
333 SignatureAlgorithm signatureAlgorithm()
334 {
335   return config.signatureAlgorithm;
336 }
337
338 void setSignatureCompoundMode( SignatureCompoundMode signComp )
339 {
340   config.signatureCompoundMode = signComp;
341 }
342
343 SignatureCompoundMode signatureCompoundMode()
344 {
345   return config.signatureCompoundMode;
346 }
347
348 void setSendCertificates( SendCertificates sendCert )
349 {
350   config.sendCertificates = sendCert;
351 }
352
353 SendCertificates sendCertificates()
354 {
355   return config.sendCertificates;
356 }
357
358 void setSignEmail( SignEmail signMail )
359 {
360   config.signEmail = signMail;
361 }
362
363 SignEmail signEmail()
364 {
365   return config.signEmail;
366 }
367
368
369
370
371
372 void setWarnSendUnsigned( bool flag )
373 {
374   config.warnSendUnsigned = flag;
375 }
376
377 bool warnSendUnsigned()
378 {
379   return config.warnSendUnsigned;
380 }
381
382
383
384
385
386
387 void setSaveSentSignatures( bool flag )
388 {
389   config.saveSentSignatures = flag;
390 }
391
392 bool saveSentSignatures()
393 {
394   return config.saveSentSignatures;
395 }
396
397 void setWarnNoCertificate( bool flag )
398 {
399   config.warnNoCertificate = flag;
400 }
401
402 bool warnNoCertificate()
403 {
404   return config.warnNoCertificate;
405 }
406
407
408 bool isEmailInCertificate( const char* email, const char* certificate )
409 {
410     /* PENDING(g10) this function should return true if the email
411        address passed as the first parameter is contained in the
412        certificate passed as the second parameter, and false
413        otherwise. This is used to alert the user if his own email
414        address is not contained in the certificate he uses for
415        signing.
416        Note that the parameter email can be anything that is allowed
417        in a From: line.
418        Another note: OK, OK, we'll handle that in the MUA. You can
419        assume that you only get the email address.
420     */
421   return false; /* dummy*/
422 }
423
424
425 void setNumPINRequests( PinRequests reqMode )
426 {
427   config.numPINRequests = reqMode;
428
429   /* PENDING(g10) Put this value into gpg and make it ask for the pin
430      according to this. Note that there is also
431      setNumPINRequestsInterval() which is only used if reqMode ==
432      PinRequest_AfterMinutes.
433   */
434 }
435
436 PinRequests numPINRequests()
437 {
438   return config.numPINRequests;
439 }
440
441
442
443 void setNumPINRequestsInterval( int interval )
444 {
445   config.numPINRequestsInterval = interval;
446
447   /* PENDING(g10) Put this value into gpg and make it ask for the pin
448      according to this. Note that this should only be used if
449      config.numPINRequests (set with setNumPINRequests()) has the
450      value PinRequest_AfterMinutes.
451   */
452 }
453
454 int numPINRequestsInterval()
455 {
456   return config.numPINRequestsInterval;
457 }
458
459
460
461 void setCheckSignatureCertificatePathToRoot( bool flag )
462 {
463   config.checkSignatureCertificatePathToRoot = flag;
464 }
465
466 bool checkSignatureCertificatePathToRoot()
467 {
468   return config.checkSignatureCertificatePathToRoot;
469 }
470
471 void setSignatureUseCRLs( bool flag )
472 {
473   config.signatureUseCRLs = flag;
474 }
475
476 bool signatureUseCRLs()
477 {
478   return config.signatureUseCRLs;
479 }
480
481
482
483
484
485
486 void setSignatureCertificateExpiryNearWarning( bool flag )
487 {
488   config.signatureCertificateExpiryNearWarning = flag;
489 }
490
491 bool signatureCertificateExpiryNearWarning( void )
492 {
493   return config.signatureCertificateExpiryNearWarning;
494 }
495
496
497 int signatureCertificateDaysLeftToExpiry( const char* certificate )
498 {
499   GpgmeCtx ctx;
500   GpgmeError err;
501   GpgmeKey rKey;
502   time_t daysLeft = 0;
503
504   gpgme_new( &ctx );
505   gpgme_set_protocol( ctx, GPGMEPLUG_PROTOCOL );
506
507   err = gpgme_op_keylist_start( ctx, certificate, 0 );
508   if ( GPGME_No_Error == err ) {
509     err = gpgme_op_keylist_next( ctx, &rKey );
510     gpgme_op_keylist_end( ctx );
511     if ( GPGME_No_Error == err ) {
512       time_t expire_time = gpgme_key_get_ulong_attr(
513                              rKey,GPGME_ATTR_EXPIRE, NULL, 0 );
514       time_t cur_time = time (NULL);
515       daysLeft = expire_time - cur_time;
516       // convert seconds into days
517       daysLeft /= 43200;
518       gpgme_key_release( rKey );
519     }
520   }
521   gpgme_release( ctx );
522     
523   /* 
524   fprintf( stderr, "gpgmeplug signatureCertificateDaysLeftToExpiry returned %d\n", daysLeft );
525   */
526
527   return daysLeft;
528 }
529
530
531 void setSignatureCertificateExpiryNearInterval( int interval )
532 {
533   config.signatureCertificateExpiryNearInterval = interval;
534 }
535
536 int signatureCertificateExpiryNearInterval( void )
537 {
538   return config.signatureCertificateExpiryNearInterval;
539 }
540
541 void setCACertificateExpiryNearWarning( bool flag )
542 {
543   config.cACertificateExpiryNearWarning = flag;
544 }
545
546 bool caCertificateExpiryNearWarning( void )
547 {
548   return config.cACertificateExpiryNearWarning;
549 }
550
551 int caCertificateDaysLeftToExpiry( const char* certificate )
552 {
553     /* PENDING(g10)
554        Please return the number of days that are left until the
555        CA certificate for the certificate specified in the parameter
556        certificate expires.
557     */
558   /*
559   GpgmeCtx ctx;
560   GpgmeError err;
561   GpgmeKey rKey;
562   time_t daysLeft = 0;
563
564   gpgme_new( &ctx );
565   gpgme_set_protocol( ctx, GPGMEPLUG_PROTOCOL );
566
567   err = gpgme_op_keylist_start( ctx, certificate, 0 );
568   if ( GPGME_No_Error == err ) {
569     err = gpgme_op_keylist_next( ctx, &rKey );
570     gpgme_op_keylist_end( ctx );
571     if ( GPGME_No_Error == err ) {
572       time_t expire_time = gpgme_key_get_ulong_attr(
573                              rKey,
574                              
575 ??????????????????????? GPGME_ATTR_EXPIRE,  ???????????????????????
576                              
577                              NULL, 0 );
578       time_t cur_time = time (NULL);
579       daysLeft = expire_time - cur_time;
580       // convert seconds into days
581       daysLeft /= 43200;
582       gpgme_key_release( rKey );
583     }
584   }
585   gpgme_release( ctx );
586     
587    
588   // fprintf( stderr, "gpgmeplug caCertificateDaysLeftToExpiry returned %d\n", daysLeft );
589   return daysLeft;
590   */
591   
592   return 10; /* dummy that triggers a warning in the MUA */
593 }
594
595 void setCACertificateExpiryNearInterval( int interval )
596 {
597   config.cACertificateExpiryNearInterval = interval;
598 }
599
600 int caCertificateExpiryNearInterval( void )
601 {
602   return config.cACertificateExpiryNearInterval;
603 }
604
605 void setRootCertificateExpiryNearWarning( bool flag )
606 {
607   config.rootCertificateExpiryNearWarning = flag;
608 }
609
610 bool rootCertificateExpiryNearWarning( void )
611 {
612   return config.rootCertificateExpiryNearWarning;
613 }
614
615 int rootCertificateDaysLeftToExpiry( const char* certificate )
616 {
617     /* PENDING(g10)
618        Please return the number of days that are left until the
619        root certificate for the certificate specified in the parameter
620        certificate expires.
621     */
622   /*
623   GpgmeCtx ctx;
624   GpgmeError err;
625   GpgmeKey rKey;
626   time_t daysLeft = 0;
627
628   gpgme_new( &ctx );
629   gpgme_set_protocol( ctx, GPGMEPLUG_PROTOCOL );
630
631   err = gpgme_op_keylist_start( ctx, certificate, 0 );
632   if ( GPGME_No_Error == err ) {
633     err = gpgme_op_keylist_next( ctx, &rKey );
634     gpgme_op_keylist_end( ctx );
635     if ( GPGME_No_Error == err ) {
636       time_t expire_time = gpgme_key_get_ulong_attr(
637                              rKey,
638                              
639 ??????????????????????? GPGME_ATTR_EXPIRE,  ???????????????????????
640                              
641                              NULL, 0 );
642       time_t cur_time = time (NULL);
643       daysLeft = expire_time - cur_time;
644       // convert seconds into days
645       daysLeft /= 43200;
646       gpgme_key_release( rKey );
647     }
648   }
649   gpgme_release( ctx );
650     
651    
652   // fprintf( stderr, "gpgmeplug rootCertificateDaysLeftToExpiry returned %d\n", daysLeft );
653   return daysLeft;
654   */
655   
656   return 10; /* dummy that triggers a warning in the MUA */
657 }
658
659
660 void setRootCertificateExpiryNearInterval( int interval )
661 {
662   config.rootCertificateExpiryNearInterval = interval;
663 }
664
665 int rootCertificateExpiryNearInterval( void )
666 {
667   return config.rootCertificateExpiryNearInterval;
668 }
669
670
671
672
673
674
675
676
677 const char* encryptionConfigurationDialog(){ return 0; }
678
679 const char* encryptionAlgorithmDialog(){ return 0; }
680
681 const char* encryptionHandlingDialog(){ return 0; }
682
683 const char* encryptionReceiverDialog(){ return 0; }
684
685 void setEncryptionAlgorithm( EncryptionAlgorithm cryptAlg )
686 {
687   config.encryptionAlgorithm = cryptAlg;
688 }
689
690 EncryptionAlgorithm encryptionAlgorithm()
691 {
692   return config.encryptionAlgorithm;
693 }
694
695 void setEncryptEmail( EncryptEmail cryptMode )
696 {
697   config.encryptEmail = cryptMode;
698 }
699
700 EncryptEmail encryptEmail()
701 {
702   return config.encryptEmail;
703 }
704
705
706
707
708
709
710 void setWarnSendUnencrypted( bool flag )
711 {
712   config.warnSendUnencrypted = flag;
713 }
714
715 bool warnSendUnencrypted()
716 {
717   return config.warnSendUnencrypted;
718 }
719
720
721
722
723
724
725
726
727
728 void setSaveMessagesEncrypted( bool flag )
729 {
730   config.saveMessagesEncrypted = flag;
731 }
732
733 bool saveMessagesEncrypted()
734 {
735   return config.saveMessagesEncrypted;
736 }
737
738
739
740
741
742
743
744 void setCheckCertificatePath( bool flag )
745 {
746   config.checkCertificatePath = flag;
747 }
748
749 bool checkCertificatePath()
750 {
751   return config.checkCertificatePath;
752 }
753
754
755
756
757
758
759
760
761 void setCheckEncryptionCertificatePathToRoot( bool flag )
762 {
763   config.checkEncryptionCertificatePathToRoot = flag;
764 }
765
766 bool checkEncryptionCertificatePathToRoot()
767 {
768   return config.checkEncryptionCertificatePathToRoot;
769 }
770
771
772
773
774
775
776
777 void setReceiverCertificateExpiryNearWarning( bool flag )
778 {
779   config.receiverCertificateExpiryNearWarning = flag;
780 }
781
782 bool receiverCertificateExpiryNearWarning()
783 {
784   return config.receiverCertificateExpiryNearWarning;
785 }
786
787
788 int receiverCertificateDaysLeftToExpiry( const char* certificate )
789 {
790   GpgmeCtx ctx;
791   GpgmeError err;
792   GpgmeKey rKey;
793   time_t daysLeft = 0;
794
795   gpgme_new( &ctx );
796   gpgme_set_protocol( ctx, GPGMEPLUG_PROTOCOL );
797
798   err = gpgme_op_keylist_start( ctx, certificate, 0 );
799   if ( GPGME_No_Error == err ) {
800     err = gpgme_op_keylist_next( ctx, &rKey );
801     gpgme_op_keylist_end( ctx );
802     if ( GPGME_No_Error == err ) {
803       time_t expire_time = gpgme_key_get_ulong_attr(
804                              rKey,GPGME_ATTR_EXPIRE, NULL, 0 );
805       time_t cur_time = time (NULL);
806       daysLeft = expire_time - cur_time;
807       // convert seconds into days
808       daysLeft /= 43200;
809       gpgme_key_release( rKey );
810     }
811   }
812   gpgme_release( ctx );
813     
814   /*
815   fprintf( stderr, "gpgmeplug receiverCertificateDaysLeftToExpiry returned %d\n", daysLeft );
816   */
817
818   return daysLeft;
819     
820     
821     
822     /* PENDING(g10)
823        Please return the number of days that are left until the
824        certificate specified in the parameter certificate expires.
825     */
826   return 10; /* dummy that triggers a warning in the MUA */
827 }
828
829
830 void setReceiverCertificateExpiryNearWarningInterval( int interval )
831 {
832   config.receiverCertificateExpiryNearWarningInterval = interval;
833 }
834
835 int receiverCertificateExpiryNearWarningInterval()
836 {
837   return config.receiverCertificateExpiryNearWarningInterval;
838 }
839
840 void setCertificateInChainExpiryNearWarning( bool flag )
841 {
842   config.certificateInChainExpiryNearWarning = flag;
843 }
844
845 bool certificateInChainExpiryNearWarning()
846 {
847   return config.certificateInChainExpiryNearWarning;
848 }
849
850
851 int certificateInChainDaysLeftToExpiry( const char* certificate )
852 {
853     /* PENDING(g10)
854        Please return the number of days that are left until the
855        the first certificate in the chain of the specified certificate
856        expires.
857     */
858   return 10; /* dummy that triggers a warning in the MUA */
859 }
860
861
862 void setCertificateInChainExpiryNearWarningInterval( int interval )
863 {
864   config.certificateInChainExpiryNearWarningInterval = interval;
865 }
866
867 int certificateInChainExpiryNearWarningInterval()
868 {
869   return config.certificateInChainExpiryNearWarningInterval;
870 }
871
872 void setReceiverEmailAddressNotInCertificateWarning( bool flag )
873 {
874   config.receiverEmailAddressNotInCertificateWarning = flag;
875 }
876
877 bool receiverEmailAddressNotInCertificateWarning()
878 {
879   return config.receiverEmailAddressNotInCertificateWarning;
880 }
881
882
883
884
885
886
887
888
889 void setEncryptionUseCRLs( bool flag )
890 {
891   config.encryptionUseCRLs = flag;
892
893   /* PENDING(g10) Store this setting in gpgme and use it. If true,
894      every certificate used for encryption should be checked against
895      applicable CRLs.
896   */
897 }
898
899 bool encryptionUseCRLs()
900 {
901   return config.encryptionUseCRLs;
902 }
903
904
905 int encryptionCRLsDaysLeftToExpiry()
906 {
907     /* PENDING(g10)
908        Please return the number of days that are left until the
909        CRL used for encryption expires.
910     */
911   return 10; /* dummy that triggers a warning in the MUA */
912 }
913
914 void setEncryptionCRLExpiryNearWarning( bool flag )
915 {
916   config.encryptionCRLExpiryNearWarning = flag;
917 }
918
919 bool encryptionCRLExpiryNearWarning()
920 {
921   return config.encryptionCRLExpiryNearWarning;
922 }
923
924 void setEncryptionCRLNearExpiryInterval( int interval )
925 {
926   config.encryptionCRLNearExpiryInterval = interval;
927 }
928
929 int encryptionCRLNearExpiryInterval()
930 {
931   return config.encryptionCRLNearExpiryInterval;
932 }
933
934
935 const char* directoryServiceConfigurationDialog(){ return 0; }
936
937 void appendDirectoryServer( const char* servername,
938                             int         port,
939                             const char* description )
940 {
941   struct DirectoryServer *newServers = NULL;
942   newServers = realloc( config.directoryServers,
943                         (1+config.numDirectoryServers) * sizeof *newServers );
944   if( newServers ) {
945     config.directoryServers = newServers;
946     newServers[ config.numDirectoryServers ].servername =
947       malloc( 1+strlen( servername ) );
948     if( newServers[ config.numDirectoryServers ].servername ) {
949       strcpy( (char *)newServers[ config.numDirectoryServers ].servername,
950         servername );
951       newServers[ config.numDirectoryServers ].description =
952         malloc( 1+strlen(  description ) );
953       if( newServers[ config.numDirectoryServers ].description ) {
954         strcpy( (char *)newServers[ config.numDirectoryServers ].description,
955           description );
956         newServers[ config.numDirectoryServers ].port = port;
957         config.numDirectoryServers += 1;
958       }
959     }
960   }
961 }
962
963 void setDirectoryServers( struct DirectoryServer server[], unsigned int size )
964 {
965   unsigned int i;
966   int oldSize = config.numDirectoryServers;
967   struct DirectoryServer *newServers = NULL;
968   newServers = calloc ( size, sizeof *newServers );
969   if( newServers ) {
970     for( i=0; i < oldSize; ++i ) {
971       free( (char *)config.directoryServers[i].servername );
972       free( (char *)config.directoryServers[i].description );
973     }
974     free( config.directoryServers );
975     for( i=0; i < size; ++i ) {
976       newServers[ i ].servername = malloc( 1+strlen( server[i].servername ) );
977       if( newServers[ i ].servername ) {
978         strcpy( (char *)newServers[ i ].servername, server[i].servername );
979         newServers[ i ].description = malloc( 1+strlen( server[i].description ) );
980         if( newServers[ i ].description ) {
981           strcpy( (char *)newServers[ i ].description, server[i].description );
982           newServers[ i ].port = server[i].port;
983         }
984       }
985     }
986     config.directoryServers = newServers;
987     config.numDirectoryServers = size;
988   }
989 }
990
991 struct DirectoryServer * directoryServers( int* numServers )
992 {
993   if( numServers )
994     *numServers = config.numDirectoryServers;
995   return config.directoryServers;
996 };
997
998 void setCertificateSource( CertificateSource source )
999 {
1000   config.certificateSource = source;
1001 }
1002
1003 CertificateSource certificateSource()
1004 {
1005   return config.certificateSource;
1006 }
1007
1008 void setCRLSource( CertificateSource source )
1009 {
1010   config.cRLSource = source;
1011 }
1012
1013 CertificateSource crlSource()
1014 {
1015   return config.cRLSource;
1016 }
1017
1018
1019 bool certificateValidity( const char* certificate,
1020                           int* level ){ return true; }
1021
1022
1023 void storeNewCharPtr( char** dest, const char* src )
1024 {
1025   int sLen = strlen( src );
1026   *dest = malloc( sLen + 1 );
1027   strcpy( *dest, src );
1028   (*dest)[sLen] = '\0';
1029 }
1030
1031
1032 bool signMessage( const char*  cleartext,
1033                   char** ciphertext,
1034                   const size_t* cipherLen,
1035                   const char*  certificate,
1036                   struct StructuringInfo* structuring,
1037                   int* errId,
1038                   char** errTxt )
1039 {
1040   bool bIsOpaque;
1041   GpgmeCtx ctx;
1042   GpgmeError err;
1043   GpgmeKey rKey;
1044   GpgmeData data,  sig;
1045   char* rSig  = 0;
1046   bool  bOk   = false;
1047   int sendCerts = 1;
1048
1049   init_StructuringInfo( structuring );
1050
1051   if( !ciphertext )
1052     return false;
1053
1054   err = gpgme_new (&ctx);
1055   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
1056
1057   gpgme_set_armor (ctx, __GPGMEPLUG_SIGNATURE_CODE_IS_BINARY ? 0 : 1);
1058   /*  gpgme_set_textmode (ctx, 1); */
1059
1060   switch ( config.sendCertificates ) {
1061     case SendCert_undef:
1062       break;
1063     case SendCert_DontSend:
1064       sendCerts = 0;
1065       break;
1066     case SendCert_SendOwn:
1067       sendCerts = 1;
1068       break;
1069     case SendCert_SendChainWithoutRoot:
1070       sendCerts = -2;
1071       break;
1072     case SendCert_SendChainWithRoot:
1073       sendCerts = -1;
1074       break;
1075     default:
1076       sendCerts = 0;
1077       break;
1078   }
1079   gpgme_set_include_certs (ctx, sendCerts);
1080
1081   /* select the signer's key if provided */
1082   if (certificate != 0) {
1083       err = gpgme_op_keylist_start(ctx, certificate, 0);
1084       if (err == GPGME_No_Error) {
1085           /* we only support one signer for now */
1086           err = gpgme_op_keylist_next(ctx, &rKey);
1087           if (err == GPGME_No_Error) {
1088               /* clear existing signers */
1089               gpgme_signers_clear(ctx);
1090               /* set the signing key */
1091               gpgme_signers_add(ctx, rKey);
1092           }
1093           gpgme_op_keylist_end(ctx);
1094       }
1095   }
1096
1097   /* PENDING(g10) Implement this
1098
1099      gpgme_set_signature_algorithm( ctx, config.signatureAlgorithm )
1100      --> This does not make sense.  The algorithm is a property of
1101      the certificate used [wk 2002-03-23] */
1102
1103   gpgme_data_new_from_mem (&data, cleartext,
1104                             strlen( cleartext ), 1 );
1105   gpgme_data_new ( &sig );
1106
1107   // NOTE: Currently we support Opaque signed messages only for S/MIME,
1108   //       but not for OpenPGP mode!
1109   if( GPGMEPLUG_PROTOCOL == GPGME_PROTOCOL_CMS )
1110     bIsOpaque = (SignatureCompoundMode_Opaque == signatureCompoundMode());
1111   else
1112     bIsOpaque = false;
1113
1114   err = gpgme_op_sign ( ctx,
1115                         data,
1116                         sig,
1117                         bIsOpaque
1118                         ? GPGME_SIG_MODE_NORMAL
1119                         : GPGME_SIG_MODE_DETACH );
1120
1121   if ( err == GPGME_No_Error ) {
1122     if( __GPGMEPLUG_SIGNATURE_CODE_IS_BINARY ) {
1123       *ciphertext = gpgme_data_release_and_get_mem( sig, (size_t*)cipherLen );
1124       bOk = true;
1125     }
1126     else {
1127       rSig = gpgme_data_release_and_get_mem( sig, (size_t*)cipherLen );
1128       *ciphertext = malloc( *cipherLen + 1 );
1129       if( *ciphertext ) {
1130         if( *cipherLen ) {
1131           bOk = true;
1132           strncpy((char*)*ciphertext, rSig, *cipherLen );
1133         }
1134         (*ciphertext)[*cipherLen] = '\0';
1135       }
1136       free( rSig );
1137     }
1138   }
1139   else {
1140     gpgme_data_release( sig );
1141 /*
1142 *ciphertext = malloc( 70 );
1143 strcpy((char*)*ciphertext, "xyz\nsig-dummy\nzyx" );
1144 (*ciphertext)[17] = '\0';
1145 err = 0;
1146 {
1147 */
1148     *ciphertext = 0;
1149     fprintf( stderr, "\n\n    gpgme_op_sign() returned this error code:  %i\n\n", err );
1150     if( errId )
1151       *errId = err;
1152     if( errTxt ) {
1153       const char* _errTxt = gpgme_strerror( err );
1154       *errTxt = malloc( strlen( _errTxt ) + 1 );
1155       if( *errTxt )
1156         strcpy(*errTxt, _errTxt );
1157     }
1158 /*
1159 }
1160 */
1161   }
1162   gpgme_data_release( data );
1163   gpgme_release (ctx);
1164
1165   if( bOk && structuring ) {
1166     if( bIsOpaque ) {
1167       structuring->includeCleartext = GPGMEPLUG_OPA_SIGN_INCLUDE_CLEARTEXT;
1168       structuring->makeMimeObject   = GPGMEPLUG_OPA_SIGN_MAKE_MIME_OBJECT;
1169       if( structuring->makeMimeObject ) {
1170         structuring->makeMultiMime  = GPGMEPLUG_OPA_SIGN_MAKE_MULTI_MIME;
1171         storeNewCharPtr( &structuring->contentTypeMain,
1172                         GPGMEPLUG_OPA_SIGN_CTYPE_MAIN );
1173         storeNewCharPtr( &structuring->contentDispMain,
1174                         GPGMEPLUG_OPA_SIGN_CDISP_MAIN );
1175         storeNewCharPtr( &structuring->contentTEncMain,
1176                         GPGMEPLUG_OPA_SIGN_CTENC_MAIN );
1177         if( structuring->makeMultiMime ) {
1178             storeNewCharPtr( &structuring->contentTypeVersion,
1179                             GPGMEPLUG_OPA_SIGN_CTYPE_VERSION );
1180             storeNewCharPtr( &structuring->contentDispVersion,
1181                             GPGMEPLUG_OPA_SIGN_CDISP_VERSION );
1182             storeNewCharPtr( &structuring->contentTEncVersion,
1183                             GPGMEPLUG_OPA_SIGN_CTENC_VERSION );
1184             storeNewCharPtr( &structuring->bodyTextVersion,
1185                             GPGMEPLUG_OPA_SIGN_BTEXT_VERSION );
1186             storeNewCharPtr( &structuring->contentTypeCode,
1187                             GPGMEPLUG_OPA_SIGN_CTYPE_CODE );
1188             storeNewCharPtr( &structuring->contentDispCode,
1189                             GPGMEPLUG_OPA_SIGN_CDISP_CODE );
1190             storeNewCharPtr( &structuring->contentTEncCode,
1191                             GPGMEPLUG_OPA_SIGN_CTENC_CODE );
1192         }
1193       } else {
1194         storeNewCharPtr( &structuring->flatTextPrefix,
1195                         GPGMEPLUG_OPA_SIGN_FLAT_PREFIX );
1196         storeNewCharPtr( &structuring->flatTextSeparator,
1197                         GPGMEPLUG_OPA_SIGN_FLAT_SEPARATOR );
1198         storeNewCharPtr( &structuring->flatTextPostfix,
1199                         GPGMEPLUG_OPA_SIGN_FLAT_POSTFIX );
1200       }
1201     } else {
1202       structuring->includeCleartext = GPGMEPLUG_DET_SIGN_INCLUDE_CLEARTEXT;
1203       structuring->makeMimeObject   = GPGMEPLUG_DET_SIGN_MAKE_MIME_OBJECT;
1204       if( structuring->makeMimeObject ) {
1205         structuring->makeMultiMime  = GPGMEPLUG_DET_SIGN_MAKE_MULTI_MIME;
1206         storeNewCharPtr( &structuring->contentTypeMain,
1207                         GPGMEPLUG_DET_SIGN_CTYPE_MAIN );
1208         storeNewCharPtr( &structuring->contentDispMain,
1209                         GPGMEPLUG_DET_SIGN_CDISP_MAIN );
1210         storeNewCharPtr( &structuring->contentTEncMain,
1211                         GPGMEPLUG_DET_SIGN_CTENC_MAIN );
1212         if( structuring->makeMultiMime ) {
1213             storeNewCharPtr( &structuring->contentTypeVersion,
1214                             GPGMEPLUG_DET_SIGN_CTYPE_VERSION );
1215             storeNewCharPtr( &structuring->contentDispVersion,
1216                             GPGMEPLUG_DET_SIGN_CDISP_VERSION );
1217             storeNewCharPtr( &structuring->contentTEncVersion,
1218                             GPGMEPLUG_DET_SIGN_CTENC_VERSION );
1219             storeNewCharPtr( &structuring->bodyTextVersion,
1220                             GPGMEPLUG_DET_SIGN_BTEXT_VERSION );
1221             storeNewCharPtr( &structuring->contentTypeCode,
1222                             GPGMEPLUG_DET_SIGN_CTYPE_CODE );
1223             storeNewCharPtr( &structuring->contentDispCode,
1224                             GPGMEPLUG_DET_SIGN_CDISP_CODE );
1225             storeNewCharPtr( &structuring->contentTEncCode,
1226                             GPGMEPLUG_DET_SIGN_CTENC_CODE );
1227         }
1228       } else {
1229         storeNewCharPtr( &structuring->flatTextPrefix,
1230                         GPGMEPLUG_DET_SIGN_FLAT_PREFIX );
1231         storeNewCharPtr( &structuring->flatTextSeparator,
1232                         GPGMEPLUG_DET_SIGN_FLAT_SEPARATOR );
1233         storeNewCharPtr( &structuring->flatTextPostfix,
1234                         GPGMEPLUG_DET_SIGN_FLAT_POSTFIX );
1235       }
1236     }
1237   }
1238   return bOk;
1239 }
1240
1241
1242 static const char*
1243 sig_status_to_string( GpgmeSigStat status )
1244 {
1245   const char *result;
1246
1247   switch (status) {
1248     case GPGME_SIG_STAT_NONE:
1249       result = "Oops: Signature not verified";
1250       break;
1251     case GPGME_SIG_STAT_NOSIG:
1252       result = "No signature found";
1253       break;
1254     case GPGME_SIG_STAT_GOOD:
1255       result = "Good signature";
1256       break;
1257     case GPGME_SIG_STAT_BAD:
1258       result = "BAD signature";
1259       break;
1260     case GPGME_SIG_STAT_NOKEY:
1261       result = "No public key to verify the signature";
1262       break;
1263     case GPGME_SIG_STAT_ERROR:
1264       result = "Error verifying the signature";
1265       break;
1266     case GPGME_SIG_STAT_DIFF:
1267       result = "Different results for signatures";
1268       break;
1269     default:
1270       result = "Error: Unknown status";
1271       break;
1272   }
1273
1274   return result;
1275 }
1276
1277
1278 bool checkMessageSignature( char** cleartext,
1279                             const char* signaturetext,
1280                             bool signatureIsBinary,
1281                             int signatureLen,
1282                             struct SignatureMetaData* sigmeta )
1283 {
1284   GpgmeCtx ctx;
1285   GpgmeSigStat status;
1286   unsigned long sumGPGME;
1287   SigStatusFlags sumPlug;
1288   GpgmeData datapart, sigpart;
1289   char* rClear = 0;
1290   size_t clearLen;
1291   GpgmeError err;
1292   GpgmeKey key;
1293   time_t created;
1294   int sig_idx = 0;
1295   const char* statusStr;
1296   const char* fpr;
1297   bool isOpaqueSigned;
1298
1299   if( !cleartext ) {
1300     if( sigmeta )
1301       storeNewCharPtr( &sigmeta->status,
1302                         __GPGMEPLUG_ERROR_CLEARTEXT_IS_ZERO );
1303
1304     return false;
1305   }
1306
1307   isOpaqueSigned = !*cleartext;
1308
1309   gpgme_new( &ctx );
1310   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
1311   gpgme_set_armor (ctx,    signatureIsBinary ? 0 : 1);
1312   /*  gpgme_set_textmode (ctx, signatureIsBinary ? 0 : 1); */
1313
1314   if( isOpaqueSigned )
1315     gpgme_data_new( &datapart );
1316   else
1317     gpgme_data_new_from_mem( &datapart, *cleartext,
1318                              strlen( *cleartext ), 1 );
1319
1320   gpgme_data_new_from_mem( &sigpart,
1321                            signaturetext,
1322                            signatureIsBinary
1323                            ? signatureLen
1324                            : strlen( signaturetext ),
1325                            1 );
1326
1327   gpgme_op_verify( ctx, sigpart, datapart, &status );
1328
1329   if( isOpaqueSigned ) {
1330     rClear = gpgme_data_release_and_get_mem( datapart, &clearLen );
1331     *cleartext = malloc( clearLen + 1 );
1332     if( *cleartext ) {
1333       if( clearLen )
1334         strncpy(*cleartext, rClear, clearLen );
1335       (*cleartext)[clearLen] = '\0';
1336     }
1337     free( rClear );
1338   }
1339   else
1340     gpgme_data_release( datapart );
1341
1342   gpgme_data_release( sigpart );
1343
1344   /* Provide information in the sigmeta struct */
1345   /* the status string */
1346   statusStr = sig_status_to_string( status );
1347   sigmeta->status = malloc( strlen( statusStr ) + 1 );
1348   if( sigmeta->status ) {
1349     strcpy( sigmeta->status, statusStr );
1350     sigmeta->status[strlen( statusStr )] = '\0';
1351   } else
1352     ; /* nothing to do, is already 0 */
1353
1354   /* Extended information for any number of signatures. */
1355   fpr = gpgme_get_sig_status( ctx, sig_idx, &status, &created );
1356   sigmeta->extended_info = 0;
1357   while( fpr != NULL ) {
1358     struct tm* ctime_val;
1359     const char* sig_status;
1360
1361     void* realloc_return = realloc( sigmeta->extended_info,
1362                                     sizeof( struct SignatureMetaDataExtendedInfo ) * ( sig_idx + 1 ) );
1363     if( realloc_return ) {
1364       sigmeta->extended_info = realloc_return;
1365
1366       /* clear the data area */
1367       memset( &sigmeta->extended_info[sig_idx], 0, sizeof (struct SignatureMetaDataExtendedInfo) );
1368
1369       /* the creation time */
1370       sigmeta->extended_info[sig_idx].creation_time = malloc( sizeof( struct tm ) );
1371       if( sigmeta->extended_info[sig_idx].creation_time ) {
1372         ctime_val = localtime( &created );
1373         memcpy( sigmeta->extended_info[sig_idx].creation_time,
1374                 ctime_val, sizeof( struct tm ) );
1375       }
1376
1377       /* the extended signature verification status */
1378       sumGPGME = gpgme_get_sig_ulong_attr( ctx,
1379                                            sig_idx,
1380                                            GPGME_ATTR_SIG_SUMMARY,
1381                                            0 );
1382       // translate GPGME status flags to common CryptPlug status flags
1383       sumPlug = 0;
1384       if( sumGPGME & GPGME_SIGSUM_VALID       ) sumPlug |= SigStat_VALID      ;
1385       if( sumGPGME & GPGME_SIGSUM_GREEN       ) sumPlug |= SigStat_GREEN      ;
1386       if( sumGPGME & GPGME_SIGSUM_RED         ) sumPlug |= SigStat_RED        ;
1387       if( sumGPGME & GPGME_SIGSUM_KEY_REVOKED ) sumPlug |= SigStat_KEY_REVOKED;
1388       if( sumGPGME & GPGME_SIGSUM_KEY_EXPIRED ) sumPlug |= SigStat_KEY_EXPIRED;
1389       if( sumGPGME & GPGME_SIGSUM_SIG_EXPIRED ) sumPlug |= SigStat_SIG_EXPIRED;
1390       if( sumGPGME & GPGME_SIGSUM_KEY_MISSING ) sumPlug |= SigStat_KEY_MISSING;
1391       if( sumGPGME & GPGME_SIGSUM_CRL_MISSING ) sumPlug |= SigStat_CRL_MISSING;
1392       if( sumGPGME & GPGME_SIGSUM_CRL_TOO_OLD ) sumPlug |= SigStat_CRL_TOO_OLD;
1393       if( sumGPGME & GPGME_SIGSUM_BAD_POLICY  ) sumPlug |= SigStat_BAD_POLICY ;
1394       if( sumGPGME & GPGME_SIGSUM_SYS_ERROR   ) sumPlug |= SigStat_SYS_ERROR  ;
1395       if( !sumPlug )
1396         sumPlug = SigStat_NUMERICAL_CODE | sumGPGME;
1397       sigmeta->extended_info[sig_idx].sigStatusFlags = sumPlug;
1398
1399       sigmeta->extended_info[sig_idx].validity = GPGME_VALIDITY_UNKNOWN;
1400
1401       err = gpgme_get_sig_key (ctx, sig_idx, &key);
1402
1403       if ( err == GPGME_No_Error) {
1404         const char* attr_string;
1405         unsigned long attr_ulong;
1406
1407         /* extract key identidy */
1408         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_KEYID, 0, 0);
1409         if (attr_string != 0)
1410             storeNewCharPtr( &sigmeta->extended_info[sig_idx].keyid, attr_string );
1411
1412         /* extract finger print */
1413         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_FPR, 0, 0);
1414         if (attr_string != 0)
1415             storeNewCharPtr( &sigmeta->extended_info[sig_idx].fingerprint,
1416                             attr_string );
1417
1418         /* algorithms useable with this key */
1419         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_ALGO, 0, 0);
1420         if (attr_string != 0)
1421             storeNewCharPtr( &sigmeta->extended_info[sig_idx].algo,
1422                             attr_string );
1423         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_ALGO, 0, 0);
1424         sigmeta->extended_info[sig_idx].algo_num = attr_ulong;
1425
1426         /* extract key validity */
1427         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_VALIDITY, 0, 0);
1428         sigmeta->extended_info[sig_idx].validity = attr_ulong;
1429
1430         /* extract user id, according to the documentation it's representable
1431         * as a number, but it seems that it also has a string representation
1432         */
1433         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_USERID, 0, 0);
1434         if (attr_string != 0)
1435             storeNewCharPtr( &sigmeta->extended_info[sig_idx].userid,
1436                             attr_string );
1437         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_USERID, 0, 0);
1438         sigmeta->extended_info[sig_idx].userid_num = attr_ulong;
1439
1440         /* extract the length */
1441         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_LEN, 0, 0);
1442         sigmeta->extended_info[sig_idx].keylen = attr_ulong;
1443
1444         /* extract the creation time of the key */
1445         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_CREATED, 0, 0);
1446         sigmeta->extended_info[sig_idx].key_created = attr_ulong;
1447
1448         /* extract the expiration time of the key */
1449         attr_ulong = gpgme_key_get_ulong_attr(key, GPGME_ATTR_EXPIRE, 0, 0);
1450         sigmeta->extended_info[sig_idx].key_expires = attr_ulong;
1451
1452         /* extract user name */
1453         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_NAME, 0, 0);
1454         if (attr_string != 0)
1455             storeNewCharPtr( &sigmeta->extended_info[sig_idx].name,
1456                             attr_string );
1457
1458         /* extract email */
1459         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_EMAIL, 0, 0);
1460         if (attr_string != 0)
1461             storeNewCharPtr( &sigmeta->extended_info[sig_idx].email,
1462                             attr_string );
1463
1464         /* extract the comment */
1465         attr_string = gpgme_key_get_string_attr(key, GPGME_ATTR_COMMENT, 0, 0);
1466         if (attr_string != 0)
1467             storeNewCharPtr( &sigmeta->extended_info[sig_idx].comment,
1468                             attr_string );
1469       }
1470       else
1471         storeNewCharPtr( &sigmeta->extended_info[sig_idx].fingerprint, fpr );
1472
1473       sig_status = sig_status_to_string( status );
1474       storeNewCharPtr( &sigmeta->extended_info[sig_idx].status_text,
1475                        sig_status );
1476
1477     } else
1478       break; /* if allocation fails once, it isn't likely to
1479                 succeed the next time either */
1480
1481     fpr = gpgme_get_sig_status (ctx, ++sig_idx, &status, &created);
1482   }
1483   sigmeta->extended_info_count = sig_idx;
1484   sigmeta->nota_xml = gpgme_get_notation( ctx );
1485   sigmeta->status_code = status;
1486
1487   gpgme_release( ctx );
1488   return ( status == GPGME_SIG_STAT_GOOD );
1489 }
1490
1491 bool storeCertificatesFromMessage(
1492         const char* ciphertext ){ return true; }
1493
1494
1495 /* returns address if address doesn't contain a <xxx> part
1496  * else it returns a new string xxx and frees address
1497  */
1498 static char* parseAddress( char* address )
1499 {
1500   char* result = address;
1501   char* i;
1502   char* j;
1503   if( !result ) return result;
1504   i = index( address, '<' );
1505   if( i ) {
1506     j = index( i+1, '>' );
1507     if( j == NULL ) j = address+strlen(address);
1508     result = malloc( j-i );
1509     strncpy( result, i+1, j-i-1 );
1510     result[j-i-1] = '\0';
1511     free( address );
1512   } else {
1513     i = address;
1514     j = i+strlen(address);
1515   }
1516   {
1517     /* remove surrounding whitespace */
1518     char* k = result+(j-i-1);
1519     char* l = result;
1520     while( isspace( *l ) ) ++l;
1521     while( isspace( *k ) ) --k;
1522     if( l != result || k != result+(j-i-1) ) {
1523       char* result2 = malloc( k-l+2 );
1524       strncpy( result2, l, k-l+1 );
1525       result2[k-l+1] = '\0';
1526       free(result);
1527       result = result2;
1528     }
1529   }
1530   return result;
1531 }
1532
1533 static char* nextAddress( const char** address )
1534 {
1535   const char *start = *address;
1536   char* result = NULL;
1537   int quote = 0;
1538   int comment = 0;
1539   int found = 0;
1540   if( *address == NULL ) return NULL;
1541   while( **address ) {
1542
1543     switch( **address ) {
1544     case '\\': /* escaped character */
1545       ++(*address);
1546       break;
1547     case '"':
1548       if( comment == 0 ) {
1549         if( quote > 0 ) --quote;
1550         else ++quote;
1551       }
1552       break;
1553     case '(': /* comment start */
1554       if( quote == 0 ) ++comment;
1555       break;
1556     case ')': /* comment end */
1557       if( quote == 0 ) --comment;
1558       break;
1559     case '\0':
1560     case '\1': /* delimiter */
1561       if( quote == 0 && comment == 0 ) {
1562         found = 1;
1563       }
1564       break;
1565     }
1566     ++(*address);
1567     if( found ) break;
1568   }
1569   if( found || **address == 0 ) {
1570     size_t len;
1571     len = *address - start;
1572     if( len > 0 ) {
1573       if( **address != 0 ) --len;
1574       result = malloc( len*sizeof(char)+1 );
1575       strncpy( result, start, len );
1576       result[len] = '\0';
1577     }
1578   }
1579   return parseAddress(result);
1580 }
1581
1582 bool encryptMessage( const char*  cleartext,
1583                      const char** ciphertext,
1584                      const size_t* cipherLen,
1585                      const char*  certificate,
1586                      struct StructuringInfo* structuring,
1587                      int* errId,
1588                      char** errTxt )
1589 {
1590   GpgmeCtx ctx;
1591   GpgmeError err;
1592   GpgmeData gCiphertext, gPlaintext;
1593   GpgmeRecipients rset;
1594   char*  rCiph = 0;
1595   bool   bOk   = false;
1596
1597   init_StructuringInfo( structuring );
1598
1599   gpgme_new (&ctx);
1600   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
1601
1602   gpgme_set_armor (ctx, __GPGMEPLUG_ENCRYPTED_CODE_IS_BINARY ? 0 : 1);
1603   /*  gpgme_set_textmode (ctx, 1); */
1604
1605   gpgme_data_new_from_mem (&gPlaintext, cleartext,
1606                             1+strlen( cleartext ), 1 );
1607   err = gpgme_data_new ( &gCiphertext );
1608
1609   gpgme_recipients_new (&rset);
1610
1611   /*
1612   if( GPGMEPLUG_PROTOCOL == GPGME_PROTOCOL_CMS )
1613   {
1614     gpgme_recipients_add_name (rset,
1615       "/CN=test cert 1,OU=Aegypten Project,O=g10 Code GmbH,L=DÃ?sseldorf,C=DE" );
1616
1617     fputs( "\nGPGSMPLUG encryptMessage() using test key of Aegypten Project\n", stderr );
1618   }
1619   else
1620   */
1621   {
1622     const char* p = certificate;
1623     char* tok;
1624     while( (tok = nextAddress( &p ) ) != 0 ) {
1625       gpgme_recipients_add_name (rset, tok );
1626       fprintf( stderr, "\nGPGMEPLUG encryptMessage() using addressee %s\n", tok );
1627       free(tok);
1628     }
1629   }
1630
1631   /* PENDING(g10) Implement this
1632      Possible values: RSA = 1, SHA1 = 2, TripleDES = 3
1633      gpgme_set_encryption_algorithm( ctx, config.encryptionAlgorithm );
1634
1635      -> Your are mixing public key and symmetric algorithms.  The
1636      latter may be configured but the sphix specifications do opnly
1637      allow 3-DES so this is not nothing we need to do.  The proper way
1638      to select the symmetric algorithm is anyway by looking at the
1639      capabilities of the certificate because this is the only way to
1640      know what the recipient can accept. [wk 2002-03-23]
1641
1642      PENDING(g10) Implement this
1643      gpgme_set_encryption_check_certificate_path(
1644      config.checkCertificatePath )
1645
1646      PENDING(g10) Implement this
1647      gpgme_set_encryption_check_certificate_path_to_root(
1648      config.checkEncryptionCertificatePathToRoot )
1649
1650      -> Not checking a certificate up to the ROOT CA is dangerous and
1651      stupid. There is no need for those options.  [wk 2002-03-23] */
1652
1653
1654
1655   err = gpgme_op_encrypt (ctx, rset, gPlaintext, gCiphertext );
1656   if( err ) {
1657     fprintf( stderr, "\ngpgme_op_encrypt() returned this error code:  %i\n\n", err );
1658     if( errId )
1659       *errId = err;
1660     if( errTxt ) {
1661       const char* _errTxt = gpgme_strerror( err );
1662       *errTxt = malloc( strlen( _errTxt ) + 1 );
1663       if( *errTxt )
1664         strcpy(*errTxt, _errTxt );
1665     }
1666   }
1667
1668   gpgme_recipients_release (rset);
1669   gpgme_data_release (gPlaintext);
1670
1671   if( err == GPGME_No_Error ) {
1672     if( __GPGMEPLUG_ENCRYPTED_CODE_IS_BINARY ) {
1673       *ciphertext = gpgme_data_release_and_get_mem( gCiphertext, (size_t*)cipherLen );
1674       bOk = true;
1675     }
1676     else {
1677       rCiph = gpgme_data_release_and_get_mem( gCiphertext, (size_t*)cipherLen );
1678       *ciphertext = malloc( *cipherLen + 1 );
1679       if( *ciphertext ) {
1680         if( *cipherLen ) {
1681           bOk = true;
1682           strncpy((char*)*ciphertext, rCiph, *cipherLen );
1683         }
1684         ((char*)(*ciphertext))[*cipherLen] = 0;
1685       }
1686       free( rCiph );
1687     }
1688   }
1689   else {
1690     gpgme_data_release ( gCiphertext );
1691     *ciphertext = 0;
1692     /* error handling is missing: if only one untrusted key was found
1693       (or none at all), gpg won't sign the message.  (hier fehlt eine
1694       Fehlerbehandlung: fuer einen Recipient nur ein untrusted key
1695       (oder gar keiner) gefunden wurde, verweigert gpg das signieren.)
1696     */
1697   }
1698
1699   gpgme_release (ctx);
1700
1701   fflush( stderr );
1702
1703   if( bOk && structuring ) {
1704     structuring->includeCleartext = GPGMEPLUG_ENC_INCLUDE_CLEARTEXT;
1705     structuring->makeMimeObject   = GPGMEPLUG_ENC_MAKE_MIME_OBJECT;
1706     if( structuring->makeMimeObject ) {
1707       structuring->makeMultiMime  = GPGMEPLUG_ENC_MAKE_MULTI_MIME;
1708       storeNewCharPtr( &structuring->contentTypeMain,
1709                        GPGMEPLUG_ENC_CTYPE_MAIN );
1710       storeNewCharPtr( &structuring->contentDispMain,
1711                        GPGMEPLUG_ENC_CDISP_MAIN );
1712       storeNewCharPtr( &structuring->contentTEncMain,
1713                        GPGMEPLUG_ENC_CTENC_MAIN );
1714       if( structuring->makeMultiMime ) {
1715         storeNewCharPtr( &structuring->contentTypeVersion,
1716                          GPGMEPLUG_ENC_CTYPE_VERSION );
1717         storeNewCharPtr( &structuring->contentDispVersion,
1718                          GPGMEPLUG_ENC_CDISP_VERSION );
1719         storeNewCharPtr( &structuring->contentTEncVersion,
1720                          GPGMEPLUG_ENC_CTENC_VERSION );
1721         storeNewCharPtr( &structuring->bodyTextVersion,
1722                          GPGMEPLUG_ENC_BTEXT_VERSION );
1723         storeNewCharPtr( &structuring->contentTypeCode,
1724                          GPGMEPLUG_ENC_CTYPE_CODE );
1725         storeNewCharPtr( &structuring->contentDispCode,
1726                          GPGMEPLUG_ENC_CDISP_CODE );
1727         storeNewCharPtr( &structuring->contentTEncCode,
1728                          GPGMEPLUG_ENC_CTENC_CODE );
1729       }
1730     } else {
1731       storeNewCharPtr( &structuring->flatTextPrefix,
1732                        GPGMEPLUG_ENC_FLAT_PREFIX );
1733       storeNewCharPtr( &structuring->flatTextSeparator,
1734                        GPGMEPLUG_ENC_FLAT_SEPARATOR );
1735       storeNewCharPtr( &structuring->flatTextPostfix,
1736                        GPGMEPLUG_ENC_FLAT_POSTFIX );
1737     }
1738   }
1739   return bOk;
1740 }
1741
1742
1743 bool encryptAndSignMessage( const char* cleartext,
1744                             const char** ciphertext,
1745                             const char* certificate,
1746                             struct StructuringInfo* structuring )
1747 {
1748   bool bOk;
1749
1750   init_StructuringInfo( structuring );
1751
1752   bOk = false;
1753
1754   /* implementation of this function is still missing */
1755
1756   if( bOk && structuring ) {
1757     structuring->includeCleartext = GPGMEPLUG_ENCSIGN_INCLUDE_CLEARTEXT;
1758     structuring->makeMimeObject   = GPGMEPLUG_ENCSIGN_MAKE_MIME_OBJECT;
1759     if( structuring->makeMimeObject ) {
1760       structuring->makeMultiMime  = GPGMEPLUG_ENCSIGN_MAKE_MULTI_MIME;
1761       storeNewCharPtr( &structuring->contentTypeMain,
1762                        GPGMEPLUG_ENCSIGN_CTYPE_MAIN );
1763       storeNewCharPtr( &structuring->contentDispMain,
1764                        GPGMEPLUG_ENCSIGN_CDISP_MAIN );
1765       storeNewCharPtr( &structuring->contentTEncMain,
1766                        GPGMEPLUG_ENCSIGN_CTENC_MAIN );
1767       if( structuring->makeMultiMime ) {
1768         storeNewCharPtr( &structuring->contentTypeVersion,
1769                          GPGMEPLUG_ENCSIGN_CTYPE_VERSION );
1770         storeNewCharPtr( &structuring->contentDispVersion,
1771                          GPGMEPLUG_ENCSIGN_CDISP_VERSION );
1772         storeNewCharPtr( &structuring->contentTEncVersion,
1773                          GPGMEPLUG_ENCSIGN_CTENC_VERSION );
1774         storeNewCharPtr( &structuring->bodyTextVersion,
1775                          GPGMEPLUG_ENCSIGN_BTEXT_VERSION );
1776         storeNewCharPtr( &structuring->contentTypeCode,
1777                          GPGMEPLUG_ENCSIGN_CTYPE_CODE );
1778         storeNewCharPtr( &structuring->contentDispCode,
1779                          GPGMEPLUG_ENCSIGN_CDISP_CODE );
1780         storeNewCharPtr( &structuring->contentTEncCode,
1781                          GPGMEPLUG_ENCSIGN_CTENC_CODE );
1782       }
1783     } else {
1784       storeNewCharPtr( &structuring->flatTextPrefix,
1785                        GPGMEPLUG_ENCSIGN_FLAT_PREFIX );
1786       storeNewCharPtr( &structuring->flatTextSeparator,
1787                        GPGMEPLUG_ENCSIGN_FLAT_SEPARATOR );
1788       storeNewCharPtr( &structuring->flatTextPostfix,
1789                        GPGMEPLUG_ENCSIGN_FLAT_POSTFIX );
1790     }
1791   }
1792   return bOk;
1793 }
1794
1795
1796 bool decryptMessage( const char* ciphertext,
1797                      bool        cipherIsBinary,
1798                      int         cipherLen,
1799                      const char** cleartext,
1800                      const char* certificate,
1801                      int* errId,
1802                      char** errTxt )
1803 {
1804   GpgmeCtx ctx;
1805   GpgmeError err;
1806   GpgmeData gCiphertext, gPlaintext;
1807   size_t rCLen = 0;
1808   char*  rCiph = 0;
1809   bool bOk = false;
1810
1811   if( !ciphertext )
1812     return false;
1813
1814   err = gpgme_new (&ctx);
1815   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
1816   
1817   gpgme_set_armor (ctx, cipherIsBinary ? 0 : 1);
1818   /*  gpgme_set_textmode (ctx, cipherIsBinary ? 0 : 1); */
1819
1820   /*
1821   gpgme_data_new_from_mem( &gCiphertext, ciphertext,
1822                            1+strlen( ciphertext ), 1 ); */
1823   gpgme_data_new_from_mem( &gCiphertext,
1824                            ciphertext,
1825                            cipherIsBinary
1826                            ? cipherLen
1827                            : strlen( ciphertext ),
1828                            1 );
1829
1830   gpgme_data_new( &gPlaintext );
1831
1832   err = err = gpgme_op_decrypt( ctx, gCiphertext, gPlaintext );
1833   if( err ) {
1834     fprintf( stderr, "\ngpgme_op_decrypt() returned this error code:  %i\n\n", err );
1835     if( errId )
1836       *errId = err;
1837     if( errTxt ) {
1838       const char* _errTxt = gpgme_strerror( err );
1839       *errTxt = malloc( strlen( _errTxt ) + 1 );
1840       if( *errTxt )
1841         strcpy(*errTxt, _errTxt );
1842     }
1843   }
1844   
1845   gpgme_data_release( gCiphertext );
1846
1847   rCiph = gpgme_data_release_and_get_mem( gPlaintext,  &rCLen );
1848
1849   *cleartext = malloc( rCLen + 1 );
1850   if( *cleartext ) {
1851       if( rCLen ) {
1852           bOk = true;
1853           strncpy((char*)*cleartext, rCiph, rCLen );
1854       }
1855       ((char*)(*cleartext))[rCLen] = 0;
1856   }
1857
1858   free( rCiph );
1859   gpgme_release( ctx );
1860   return bOk;
1861 }
1862
1863 bool decryptAndCheckMessage( const char* ciphertext,
1864           const char** cleartext, const char* certificate,
1865           struct SignatureMetaData* sigmeta ){ return true; }
1866
1867
1868 const char* requestCertificateDialog(){ return 0; }
1869
1870 bool requestDecentralCertificate( const char* certparms, 
1871                                   char** generatedKey, int* length )
1872 {
1873     GpgmeError err;
1874     GpgmeCtx ctx;
1875     GpgmeData pub;
1876     int len;
1877
1878     err = gpgme_data_new (&pub);
1879     fprintf( stderr,  "1: gpgme returned %d\n", err );
1880     if( err != GPGME_No_Error )
1881         return false;
1882
1883     err = gpgme_new (&ctx);
1884     fprintf( stderr,  "2: gpgme returned %d\n", err );
1885     if( err != GPGME_No_Error ) {
1886         gpgme_data_release( pub );
1887         return false;
1888     }
1889
1890     gpgme_set_protocol (ctx, GPGME_PROTOCOL_CMS);
1891     /* Don't ASCII-armor, the MUA will use base64 encoding */
1892     /*    gpgme_set_armor (ctx, 1); */
1893     err = gpgme_op_genkey (ctx, certparms, pub, NULL );
1894     fprintf( stderr,  "3: gpgme returned %d\n", err );
1895     if( err != GPGME_No_Error ) {
1896         gpgme_data_release( pub );
1897         gpgme_release( ctx );
1898         return false;
1899     }
1900
1901     gpgme_release (ctx);
1902     *generatedKey = gpgme_data_release_and_get_mem (pub, &len);
1903     *length = len;
1904
1905     /* The buffer generatedKey contains the LEN bytes you want */
1906     // Caller is responsible for freeing
1907     return true;
1908 }
1909
1910 bool requestCentralCertificateAndPSE( const char* name,
1911           const char* email, const char* organization, const char* department,
1912           const char* ca_address ){ return true; }
1913
1914 bool createPSE(){ return true; }
1915
1916 bool registerCertificate( const char* certificate ){ return true; }
1917
1918 bool requestCertificateProlongation( const char* certificate,
1919                                      const char* ca_address ){ return true; }
1920
1921 const char* certificateChain(){ return 0; }
1922
1923 bool deleteCertificate( const char* certificate ){ return true; }
1924
1925 bool archiveCertificate( const char* certificate ){ return true; }
1926
1927
1928 const char* displayCRL(){ return 0; }
1929
1930 void updateCRL(){}
1931
1932 /*
1933  * Copyright (C) 2002 g10 Code GmbH
1934  * 
1935  *     This program is free software; you can redistribute it
1936  *     and/or modify it under the terms of the GNU General Public
1937  *     License as published by the Free Software Foundation; either
1938  *     version 2 of the License, or (at your option) any later
1939  *     version.
1940  * 
1941  *     This program is distributed in the hope that it will be
1942  *     useful, but WITHOUT ANY WARRANTY; without even the implied
1943  *     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
1944  *     PURPOSE.  See the GNU General Public License for more
1945  *     details.
1946  * 
1947  *     You should have received a copy of the GNU General Public
1948  *     License along with this program; if not, write to the Free
1949  *     Software Foundation, Inc., 59 Temple Place - Suite 330,
1950  *     Boston, MA  02111, USA.
1951  */
1952
1953 /* Max number of parts in a DN */
1954 #define MAX_GPGME_IDX 20
1955
1956 /* some macros to replace ctype ones and avoid locale problems */
1957 #define spacep(p)   (*(p) == ' ' || *(p) == '\t')
1958 #define digitp(p)   (*(p) >= '0' && *(p) <= '9')
1959 #define hexdigitp(a) (digitp (a)                     \
1960                       || (*(a) >= 'A' && *(a) <= 'F')  \
1961                       || (*(a) >= 'a' && *(a) <= 'f'))
1962 /* the atoi macros assume that the buffer has only valid digits */
1963 #define atoi_1(p)   (*(p) - '0' )
1964 #define atoi_2(p)   ((atoi_1(p) * 10) + atoi_1((p)+1))
1965 #define atoi_4(p)   ((atoi_2(p) * 100) + atoi_2((p)+2))
1966 #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
1967                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
1968 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
1969
1970 #define safe_malloc( x ) malloc( x )
1971 #define xstrdup( x ) (x)?strdup(x):0
1972
1973 static void 
1974 safe_free( void** x ) 
1975 {
1976   free( *x );
1977   *x = 0;
1978 }
1979 char *
1980 trim_trailing_spaces( char *string )
1981 {
1982     char *p, *mark;
1983
1984     for( mark = NULL, p = string; *p; p++ ) {
1985         if( isspace( *p ) ) {
1986             if( !mark )
1987                 mark = p;
1988         }
1989         else
1990             mark = NULL;
1991     }
1992     if( mark )
1993         *mark = '\0' ;
1994
1995     return string ;
1996 }
1997 /*#define safe_free( x ) free( x )*/
1998
1999 /* Parse a DN and return an array-ized one.  This is not a validating
2000    parser and it does not support any old-stylish syntax; gpgme is
2001    expected to return only rfc2253 compatible strings. */
2002 static const unsigned char *
2003 parse_dn_part (struct DnPair *array, const unsigned char *string)
2004 {
2005   const unsigned char *s, *s1;
2006   size_t n;
2007   unsigned char *p;
2008
2009   /* parse attributeType */
2010   for (s = string+1; *s && *s != '='; s++)
2011     ;
2012   if (!*s)
2013     return NULL; /* error */
2014   n = s - string;
2015   if (!n)
2016     return NULL; /* empty key */
2017   array->key = p = safe_malloc (n+1);
2018   
2019   
2020   memcpy (p, string, n);
2021   p[n] = 0;
2022   trim_trailing_spaces (p);
2023   if ( !strcmp (p, "1.2.840.113549.1.9.1") )
2024     strcpy (p, "EMail");
2025   string = s + 1;
2026
2027   if (*string == '#')
2028     { /* hexstring */
2029       string++;
2030       for (s=string; hexdigitp (s); s++)
2031         s++;
2032       n = s - string;
2033       if (!n || (n & 1))
2034         return NULL; /* empty or odd number of digits */
2035       n /= 2;
2036       array->value = p = safe_malloc (n+1);
2037       
2038       
2039       for (s1=string; n; s1 += 2, n--)
2040         *p++ = xtoi_2 (s1);
2041       *p = 0;
2042    }
2043   else
2044     { /* regular v3 quoted string */
2045       for (n=0, s=string; *s; s++)
2046         {
2047           if (*s == '\\')
2048             { /* pair */
2049               s++;
2050               if (*s == ',' || *s == '=' || *s == '+'
2051                   || *s == '<' || *s == '>' || *s == '#' || *s == ';' 
2052                   || *s == '\\' || *s == '\"' || *s == ' ')
2053                 n++;
2054               else if (hexdigitp (s) && hexdigitp (s+1))
2055                 {
2056                   s++;
2057                   n++;
2058                 }
2059               else
2060                 return NULL; /* invalid escape sequence */
2061             }
2062           else if (*s == '\"')
2063             return NULL; /* invalid encoding */
2064           else if (*s == ',' || *s == '=' || *s == '+'
2065                    || *s == '<' || *s == '>' || *s == '#' || *s == ';' )
2066             break; 
2067           else
2068             n++;
2069         }
2070
2071       array->value = p = safe_malloc (n+1);
2072       
2073       
2074       for (s=string; n; s++, n--)
2075         {
2076           if (*s == '\\')
2077             { 
2078               s++;
2079               if (hexdigitp (s))
2080                 {
2081                   *p++ = xtoi_2 (s);
2082                   s++;
2083                 }
2084               else
2085                 *p++ = *s;
2086             }
2087           else
2088             *p++ = *s;
2089         }
2090       *p = 0;
2091     }
2092   return s;
2093 }
2094
2095
2096 /* Parse a DN and return an array-ized one.  This is not a validating
2097    parser and it does not support any old-stylish syntax; gpgme is
2098    expected to return only rfc2253 compatible strings. */
2099 static struct DnPair *
2100 parse_dn (const unsigned char *string)
2101 {
2102   struct DnPair *array;
2103   size_t arrayidx, arraysize;
2104   int i;
2105
2106   if( !string )
2107     return NULL;
2108
2109   arraysize = 7; /* C,ST,L,O,OU,CN,email */
2110   arrayidx = 0;
2111   array = safe_malloc ((arraysize+1) * sizeof *array);
2112   
2113   
2114   while (*string)
2115     {
2116       while (*string == ' ')
2117         string++;
2118       if (!*string)
2119         break; /* ready */
2120       if (arrayidx >= arraysize)
2121         { /* mutt lacks a real safe_realoc - so we need to copy */
2122           struct DnPair *a2;
2123
2124           arraysize += 5;
2125           a2 = safe_malloc ((arraysize+1) * sizeof *array);
2126           for (i=0; i < arrayidx; i++)
2127             {
2128               a2[i].key = array[i].key;
2129               a2[i].value = array[i].value;
2130             }
2131           safe_free ((void **)&array);
2132           array = a2;
2133         }
2134       array[arrayidx].key = NULL;
2135       array[arrayidx].value = NULL;
2136       string = parse_dn_part (array+arrayidx, string);
2137       arrayidx++;
2138       if (!string)
2139         goto failure;
2140       while (*string == ' ')
2141         string++;
2142       if (*string && *string != ',' && *string != ';' && *string != '+')
2143         goto failure; /* invalid delimiter */
2144       if (*string)
2145         string++;
2146     }
2147   array[arrayidx].key = NULL;
2148   array[arrayidx].value = NULL;
2149   return array;
2150
2151  failure:
2152   for (i=0; i < arrayidx; i++)
2153     {
2154       safe_free ((void**)&array[i].key);
2155       safe_free ((void**)&array[i].value);
2156     }
2157   safe_free ((void**)&array);
2158   return NULL;
2159 }
2160
2161 static int 
2162 add_dn_part( char* result, struct DnPair* dn, const char* part )
2163 {
2164   int any = 0;
2165
2166   if( dn ) {
2167     for(; dn->key; ++dn ) {
2168       if( !strcmp( dn->key, part ) ) {
2169         if( any ) strcat( result, "+" );
2170         /* email hack */
2171         if( !strcmp( part, "1.2.840.113549.1.9.1" ) ) strcat( result, "EMail" );
2172         else strcat( result, part );
2173         strcat( result, "=" );
2174         strcat( result, dn->value );
2175         any = 1;
2176       }
2177     }
2178   }
2179   return any;
2180 }
2181
2182 static char* 
2183 reorder_dn( struct DnPair *dn )
2184 {
2185   // note: The must parts are: CN, L, OU, O, C
2186   const char* stdpart[] = {
2187     "CN", "S", "SN", "GN", "T", "UID",
2188           "MAIL", "EMAIL", "MOBILE", "TEL", "FAX", "STREET",
2189     "L",  "PC", "SP", "ST",
2190     "OU",
2191     "O",
2192     "C",
2193     NULL
2194   };
2195   int any=0, any2=0, len=0, i;
2196   char* result;
2197   if( dn ) {
2198     for( i = 0; dn[i].key; ++i ) {
2199       len += strlen( dn[i].key );
2200       len += strlen( dn[i].value );
2201       len += 4; /* ',' and '=', and possibly "(" and ")" */
2202     }
2203   }
2204   result = (char*)safe_malloc( (len+1)*sizeof(char) );
2205   *result = 0;
2206
2207   /* add standard parts */
2208   for( i = 0; stdpart[i]; ++i ) {
2209     if( any ) {
2210       strcat( result, "," );
2211     }
2212     any = add_dn_part( result, dn, stdpart[i] );
2213   }
2214
2215   /* add remaining parts in no particular order */
2216   if( dn ) {
2217     for(; dn->key; ++dn ) {
2218       for( i = 0; stdpart[i]; ++i ) {
2219         if( !strcmp( dn->key, stdpart[i] ) ) {
2220           break;
2221         }
2222       }
2223       if( !stdpart[i] ) {
2224         if( any ) strcat( result, "," );
2225         if( !any2 ) strcat( result, "(");
2226         any = add_dn_part( result, dn, dn->key );
2227         any2 = 1;
2228       }
2229     }
2230   }
2231   if( any2 ) strcat( result, ")");
2232   return result;
2233 }
2234
2235 struct CertIterator {
2236   GpgmeCtx ctx;  
2237   struct CertificateInfo info;
2238 };
2239
2240 struct CertIterator* 
2241 startListCertificates( const char* pattern, int remote )
2242 {
2243     GpgmeError err;
2244     struct CertIterator* it;
2245     /*fprintf( stderr,  "startListCertificates()" );*/
2246
2247     it = (struct CertIterator*)safe_malloc( sizeof( struct CertIterator ) );
2248
2249     err = gpgme_new (&(it->ctx));
2250     /*fprintf( stderr,  "2: gpgme returned %d\n", err );*/
2251     if( err != GPGME_No_Error ) {
2252       free( it );
2253       return NULL;
2254     }
2255
2256     gpgme_set_protocol (it->ctx, GPGME_PROTOCOL_CMS);
2257     if( remote ) gpgme_set_keylist_mode ( it->ctx, GPGME_KEYLIST_MODE_EXTERN ); 
2258     else gpgme_set_keylist_mode ( it->ctx, GPGME_KEYLIST_MODE_LOCAL );
2259     err =  gpgme_op_keylist_start ( it->ctx, pattern, 0);
2260     if( err != GPGME_No_Error ) {
2261       endListCertificates( it );
2262       return NULL;
2263     }
2264     memset( &(it->info), 0, sizeof( struct CertificateInfo ) );
2265     return it;
2266 }
2267
2268 /* free() each string in a char*[] and the array itself */
2269 static void 
2270 freeStringArray( char** c )
2271 {
2272     char** _c = c;
2273     while( c && *c ) {
2274       /*fprintf( stderr, "freeing \"%s\"\n", *c );*/
2275       safe_free( (void**)&(*c) );
2276       ++c;
2277     }
2278     safe_free( (void**)&_c );
2279 }
2280
2281 /* free all malloc'ed data in a struct CertificateInfo */
2282 static void 
2283 freeInfo( struct CertificateInfo* info )
2284 {
2285   struct DnPair* a = info->dnarray;
2286   assert( info );
2287   if( info->userid ) freeStringArray( info->userid );
2288   if( info->serial ) safe_free( (void**)&(info->serial) );
2289   if( info->fingerprint ) safe_free( (void**)&(info->fingerprint) );
2290   if( info->issuer ) safe_free( (void**)&(info->issuer) );
2291   if( info->chainid ) safe_free( (void**)&(info->chainid) );
2292   if( info->caps ) safe_free( (void**)&(info->caps) );
2293   while( a && a->key && a->value ) {
2294     safe_free ((void**)&(a->key));
2295     safe_free ((void**)&(a->value));
2296     ++a;
2297   }
2298   if( info->dnarray ) safe_free ((void**)&(info->dnarray));
2299   memset( info, 0, sizeof( *info ) );
2300 }
2301
2302 /* Format the fingerprint nicely. The caller should
2303    free the returned value with safe_free() */
2304 static char* make_fingerprint( const char* fpr )
2305 {
2306   int len = strlen(fpr);
2307   int i = 0;
2308   char* result = safe_malloc( (len + len/2 + 1)*sizeof(char) );
2309   if( !result ) return NULL;
2310   for(; *fpr; ++fpr, ++i ) {
2311     if( i%3 == 2) {
2312       result[i] = ':'; ++i;
2313     }
2314     result[i] = *fpr;
2315   }
2316   result[i] = 0;
2317   return result;
2318 }
2319
2320 int 
2321 nextCertificate( struct CertIterator* it, struct CertificateInfo** result )
2322 {
2323   GpgmeError err;
2324   GpgmeKey   key;
2325   int retval = GPGME_No_Error;
2326   assert( it );
2327   err = gpgme_op_keylist_next ( it->ctx, &key);
2328   if( err != GPGME_EOF ) {   
2329     int idx;
2330     const char* s;
2331     unsigned long u;
2332     char* names[MAX_GPGME_IDX+1];
2333     struct DnPair *issuer_dn, *tmp_dn;
2334     retval = err;
2335     memset( names, 0, sizeof( names ) );
2336     freeInfo( &(it->info) );
2337
2338     for( idx = 0; (s = gpgme_key_get_string_attr (key, GPGME_ATTR_USERID, 0, idx)) && idx < MAX_GPGME_IDX; 
2339          ++idx ) {
2340       names[idx] = xstrdup( s );
2341     }
2342     
2343     it->info.userid = safe_malloc( sizeof( char* ) * (idx+1) );
2344     memset( it->info.userid, 0, sizeof( char* ) * (idx+1) );
2345     it->info.dnarray = 0;
2346     for( idx = 0; names[idx] != 0; ++idx ) {
2347       struct DnPair* a = parse_dn( names[idx] ); 
2348       if( idx == 0 ) {
2349         it->info.userid[idx] = reorder_dn( a );
2350         it->info.dnarray = a;
2351         safe_free( (void **)&(names[idx]) );
2352       } else {
2353         it->info.userid[idx] = names[idx];
2354       }
2355     }
2356     it->info.userid[idx] = 0;
2357
2358     s = gpgme_key_get_string_attr (key, GPGME_ATTR_SERIAL, 0, 0); 
2359     it->info.serial = xstrdup(s);
2360
2361     s = gpgme_key_get_string_attr (key, GPGME_ATTR_FPR, 0, 0); 
2362     it->info.fingerprint = make_fingerprint( s );
2363
2364     s = gpgme_key_get_string_attr (key, GPGME_ATTR_ISSUER, 0, 0); 
2365     if( s ) {
2366       issuer_dn = tmp_dn = parse_dn( s );     
2367       /*it->info.issuer = xstrdup(s);*/
2368       it->info.issuer = reorder_dn( issuer_dn );
2369       while( tmp_dn->key ) {
2370         safe_free( (void**)&issuer_dn->key );
2371         safe_free( (void**)&issuer_dn->value );
2372         ++tmp_dn;
2373       }
2374       safe_free( (void**)&issuer_dn );
2375     } else {
2376       it->info.issuer = NULL;
2377     }
2378     s = gpgme_key_get_string_attr (key, GPGME_ATTR_CHAINID, 0, 0); 
2379     it->info.chainid = xstrdup(s);
2380
2381     s = gpgme_key_get_string_attr (key, GPGME_ATTR_KEY_CAPS, 0, 0); 
2382     it->info.caps = xstrdup(s);
2383
2384     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_CREATED, 0, 0); 
2385     it->info.created = u;
2386
2387     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_EXPIRE, 0, 0); 
2388     it->info.expire = u;
2389
2390     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_IS_SECRET, 0, 0); 
2391     it->info.secret = u;
2392
2393     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_UID_INVALID, 0, 0); 
2394     it->info.invalid = u;
2395
2396     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_KEY_EXPIRED, 0, 0); 
2397     it->info.expired = u;
2398
2399     u = gpgme_key_get_ulong_attr (key, GPGME_ATTR_KEY_DISABLED, 0, 0); 
2400     it->info.disabled = u;
2401
2402     gpgme_key_release (key);
2403     /*return &(it->info);*/
2404     *result =  &(it->info);
2405   } else *result = NULL;
2406   return retval;
2407 }
2408
2409 void 
2410 endListCertificates( struct CertIterator* it )
2411 {
2412   /*fprintf( stderr,  "endListCertificates()\n" );*/
2413   assert(it);
2414   freeInfo( &(it->info) );
2415   gpgme_op_keylist_end(it->ctx);
2416   gpgme_release (it->ctx);
2417   free( it );
2418 }
2419
2420 int
2421 importCertificate( const char* fingerprint )
2422 {
2423   GpgmeError err;
2424   GpgmeCtx  ctx;
2425   GpgmeData keydata;
2426   GpgmeRecipients recips;
2427   char* buf;
2428   const char* tmp1;
2429   char* tmp2;
2430
2431   err = gpgme_new( &ctx );
2432   /*fprintf( stderr,  "2: gpgme returned %d\n", err );*/
2433   if( err != GPGME_No_Error ) {
2434     return err;
2435   }
2436   gpgme_set_protocol( ctx, GPGME_PROTOCOL_CMS );
2437   gpgme_set_keylist_mode( ctx, GPGME_KEYLIST_MODE_LOCAL );
2438
2439   err = gpgme_data_new( &keydata );
2440   if( err ) {
2441     fprintf( stderr,  "gpgme_data_new returned %d\n", err );
2442     gpgme_release( ctx );
2443     return err;
2444   }
2445
2446   err = gpgme_recipients_new( &recips );
2447   if( err ) {
2448     fprintf( stderr,  "gpgme_recipients_new returned %d\n", err );
2449     gpgme_data_release( keydata );
2450     gpgme_release( ctx );
2451     return err;
2452   }
2453   
2454   buf = safe_malloc( sizeof(char)*( strlen( fingerprint ) + 1 ) );
2455   if( !buf ) {
2456     gpgme_recipients_release( recips );
2457     gpgme_data_release( keydata );    
2458     gpgme_release( ctx );
2459     return GPGME_Out_Of_Core;
2460   }
2461   tmp1 = fingerprint;
2462   tmp2 = buf;
2463   while( *tmp1 ) {
2464     if( *tmp1 != ':' ) *tmp2++ = *tmp1;
2465     tmp1++;
2466   }
2467   *tmp2 = 0;
2468   fprintf( stderr,  "calling gpgme_recipients_add_name( %s )\n", buf );  
2469   err = gpgme_recipients_add_name( recips, buf ); 
2470   if( err ) {
2471     fprintf( stderr,  "gpgme_recipients_add_name returned %d\n", err );
2472     safe_free( (void**)&buf );
2473     gpgme_recipients_release( recips );
2474     gpgme_data_release( keydata );    
2475     gpgme_release( ctx );
2476     return err;
2477   }
2478
2479   err = gpgme_op_export( ctx, recips, keydata );
2480   if( err ) {
2481     fprintf( stderr,  "gpgme_op_export returned %d\n", err );
2482     safe_free( (void**)&buf );
2483     gpgme_recipients_release( recips );
2484     gpgme_data_release( keydata );    
2485     gpgme_release( ctx );
2486     return err;
2487   }
2488   safe_free( (void**)&buf );
2489
2490   err = gpgme_op_import( ctx, keydata );
2491   if( err ) {    
2492     fprintf( stderr,  "gpgme_op_import returned %d\n", err );
2493     gpgme_recipients_release( recips );
2494     gpgme_data_release( keydata );    
2495     gpgme_release( ctx );
2496     return err;
2497   }
2498
2499   gpgme_recipients_release( recips );
2500   gpgme_data_release( keydata );    
2501   gpgme_release( ctx );
2502   return 0;
2503 }
2504
2505     // // // // // // // // // // // // // // // // // // // // // // // // //
2506    //                                                                      //
2507   //         Continuation of CryptPlug code                               //
2508  //                                                                      //
2509 // // // // // // // // // // // // // // // // // // // // // // // // //
2510
2511
2512 /*
2513   Find all certificate for a given addressee and return them in a
2514   '\1' separated list.
2515   NOTE: The certificate parameter must point to a not-yet allocated
2516         char*.  The function will allocate the memory needed and
2517         return the size in newSize.
2518   If secretOnly is true, only secret keys are returned.
2519 */
2520 bool findCertificates( const char* addressee,
2521                        char** certificates,
2522                        int* newSize,
2523                        bool secretOnly )
2524 {
2525   static int maxCerts = 1024;
2526   // use const char declarations since all of them are needed twice
2527   const char* delimiter = "\1";
2528   const char* openBracket = "    (";
2529   const char* closeBracket = ")";
2530
2531   GpgmeCtx ctx;
2532   GpgmeError err;
2533   GpgmeKey rKey;
2534   const char *s;
2535   const char *s2;
2536   char* dn;
2537   struct DnPair* a;
2538   int nFound = 0;
2539   int iFound = 0;
2540   int siz = 0;
2541   char* DNs[maxCerts];
2542   char* FPRs[maxCerts];
2543   
2544   if( ! certificates ){
2545     fprintf( stderr, "gpgme: findCertificates called with invalid *certificates pointer\n" );
2546     return false;
2547   }
2548
2549   if( ! newSize ){
2550     fprintf( stderr, "gpgme: findCertificates called with invalid newSize pointer\n" );
2551     return false;
2552   }
2553
2554   *certificates = 0;
2555   *newSize = 0;
2556   
2557   // calculate length of buffer needed for certs plus fingerprints
2558   memset( DNs,  0, sizeof( DNs  ) );
2559   memset( FPRs, 0, sizeof( FPRs ) );
2560   gpgme_new (&ctx);
2561   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
2562   err = gpgme_op_keylist_start(ctx, addressee, secretOnly ? 1 : 0);
2563   while( GPGME_No_Error == err ) {
2564     err = gpgme_op_keylist_next(ctx, &rKey);
2565     if( GPGME_No_Error == err ) {
2566       s = gpgme_key_get_string_attr (rKey, GPGME_ATTR_USERID, NULL, 0);
2567       if( s ) {
2568         dn = xstrdup( s );
2569         s2 = gpgme_key_get_string_attr (rKey, GPGME_ATTR_FPR, NULL, 0);
2570         if( s2 ) {
2571           if( nFound )
2572             siz += strlen( delimiter );
2573           a = parse_dn( dn );
2574           free( dn );
2575           dn = reorder_dn( a );
2576           siz += strlen( dn );
2577           siz += strlen( openBracket );
2578           siz += strlen( s2 );
2579           siz += strlen( closeBracket );
2580           DNs[ nFound ] = xstrdup( dn );
2581           FPRs[nFound ] = xstrdup( s2 );
2582           ++nFound;
2583           if( nFound >= maxCerts ) {
2584             fprintf( stderr,
2585                      "gpgme: findCertificates found too many certificates (%d)\n",
2586                      maxCerts );
2587             break;
2588           }
2589         }
2590         free( dn );
2591       }
2592     }
2593   }
2594   gpgme_op_keylist_end( ctx );
2595   gpgme_release (ctx);
2596   
2597   
2598   if( 0 < siz ) {
2599     // add one for trailing ZERO char
2600     ++siz;
2601     *newSize = siz;
2602     // allocate the buffer
2603     *certificates = malloc(   sizeof(char) * siz );
2604     memset( *certificates, 0, sizeof(char) * siz );
2605     // fill the buffer
2606     for( iFound=0; iFound < nFound; ++iFound ) {
2607       if( !iFound )
2608         strcpy(*certificates, DNs[iFound] );
2609       else {
2610         strcat(*certificates, delimiter );
2611         strcat(*certificates, DNs[iFound] );
2612       }
2613       strcat(  *certificates, openBracket );
2614       strcat(  *certificates, FPRs[iFound] );
2615       strcat(  *certificates, closeBracket );
2616       ++iFound;
2617       free( DNs[ iFound ] );
2618       free( FPRs[iFound ] );
2619     }
2620   }
2621     
2622   return ( 0 < nFound );
2623 }