certmanager Library API Documentation

cryptplug.cpp

00001 /* -*- Mode: C++ -*-
00002 
00003   this is a C++-ification of:
00004   GPGMEPLUG - an GPGME based cryptography plug-in following
00005               the common CRYPTPLUG specification.
00006 
00007   Copyright (C) 2001 by Klarälvdalens Datakonsult AB
00008   Copyright (C) 2002 g10 Code GmbH
00009   Copyright (C) 2004 Klarälvdalens Datakonsult AB
00010 
00011   GPGMEPLUG is free software; you can redistribute it and/or modify
00012   it under the terms of GNU General Public License as published by
00013   the Free Software Foundation; version 2 of the License.
00014 
00015   GPGMEPLUG is distributed in the hope that it will be useful,
00016   it under the terms of GNU General Public License as published by
00017   the Free Software Foundation; version 2 of the License
00018   but WITHOUT ANY WARRANTY; without even the implied warranty of
00019   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020   GNU General Public License for more details.
00021 
00022   You should have received a copy of the GNU General Public License
00023   along with this program; if not, write to the Free Software
00024   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
00025 */
00026 
00027 #ifdef HAVE_CONFIG_H
00028 #include <config.h>
00029 #endif
00030 
00031 #include "kleo/oidmap.h"
00032 
00033 #include <gpgmepp/context.h>
00034 #include <gpgmepp/data.h>
00035 #include <gpgmepp/importresult.h>
00036 
00054 #include <qstring.h>
00055 
00056 #include <string>
00057 #include <vector>
00058 #include <algorithm>
00059 #include <iostream>
00060 #include <memory>
00061 
00062 #include <stdio.h>
00063 #include <string.h>
00064 #include <strings.h>
00065 #include <assert.h>
00066 #include <errno.h>
00067 #include <time.h>
00068 #include <ctype.h>
00069 #include <locale.h>
00070 
00071 #define __GPGMEPLUG_ERROR_CLEARTEXT_IS_ZERO "Error: Cannot run checkMessageSignature() with cleartext == 0"
00072 
00073 /* Note: The following specification will result in
00074        function encryptAndSignMessage() producing
00075        _empty_ mails.
00076        This must be changed as soon as our plugin
00077        is supporting the encryptAndSignMessage() function. */
00078 #ifndef GPGMEPLUG_ENCSIGN_MAKE_MIME_OBJECT
00079 #define GPGMEPLUG_ENCSIGN_INCLUDE_CLEARTEXT false
00080 #define GPGMEPLUG_ENCSIGN_MAKE_MIME_OBJECT  false
00081 #define GPGMEPLUG_ENCSIGN_MAKE_MULTI_MIME   false
00082 #define GPGMEPLUG_ENCSIGN_CTYPE_MAIN        ""
00083 #define GPGMEPLUG_ENCSIGN_CDISP_MAIN        ""
00084 #define GPGMEPLUG_ENCSIGN_CTENC_MAIN        ""
00085 #define GPGMEPLUG_ENCSIGN_CTYPE_VERSION     ""
00086 #define GPGMEPLUG_ENCSIGN_CDISP_VERSION     ""
00087 #define GPGMEPLUG_ENCSIGN_CTENC_VERSION     ""
00088 #define GPGMEPLUG_ENCSIGN_BTEXT_VERSION     ""
00089 #define GPGMEPLUG_ENCSIGN_CTYPE_CODE        ""
00090 #define GPGMEPLUG_ENCSIGN_CDISP_CODE        ""
00091 #define GPGMEPLUG_ENCSIGN_CTENC_CODE        ""
00092 #define GPGMEPLUG_ENCSIGN_FLAT_PREFIX       ""
00093 #define GPGMEPLUG_ENCSIGN_FLAT_SEPARATOR    ""
00094 #define GPGMEPLUG_ENCSIGN_FLAT_POSTFIX      ""
00095 #endif
00096 
00097 #include "cryptplug.h"
00098 #include <kdebug.h>
00099 
00100 SMIMECryptPlug::SMIMECryptPlug() : CryptPlug() {
00101   GPGMEPLUG_PROTOCOL = GPGME_PROTOCOL_CMS;
00102   mProtocol = GpgME::Context::CMS;
00103 
00104   /* definitions for signing */
00105   // 1. opaque signatures (only used for S/MIME)
00106   GPGMEPLUG_OPA_SIGN_INCLUDE_CLEARTEXT = false;
00107   GPGMEPLUG_OPA_SIGN_MAKE_MIME_OBJECT  = true;
00108   GPGMEPLUG_OPA_SIGN_MAKE_MULTI_MIME   = false;
00109   GPGMEPLUG_OPA_SIGN_CTYPE_MAIN        = "application/pkcs7-mime; smime-type=signed-data; name=\"smime.p7m\"";
00110   GPGMEPLUG_OPA_SIGN_CDISP_MAIN        = "attachment; filename=\"smime.p7m\"";
00111   GPGMEPLUG_OPA_SIGN_CTENC_MAIN        = "base64";
00112   GPGMEPLUG_OPA_SIGN_CTYPE_VERSION     = "";
00113   GPGMEPLUG_OPA_SIGN_CDISP_VERSION     = "";
00114   GPGMEPLUG_OPA_SIGN_CTENC_VERSION     = "";
00115   GPGMEPLUG_OPA_SIGN_BTEXT_VERSION     = "";
00116   GPGMEPLUG_OPA_SIGN_CTYPE_CODE        = "";
00117   GPGMEPLUG_OPA_SIGN_CDISP_CODE        = "";
00118   GPGMEPLUG_OPA_SIGN_CTENC_CODE        = "";
00119   GPGMEPLUG_OPA_SIGN_FLAT_PREFIX       = "";
00120   GPGMEPLUG_OPA_SIGN_FLAT_SEPARATOR    = "";
00121   GPGMEPLUG_OPA_SIGN_FLAT_POSTFIX      = "";
00122   // 2. detached signatures (used for S/MIME and for OpenPGP)
00123   GPGMEPLUG_DET_SIGN_INCLUDE_CLEARTEXT = true;
00124   GPGMEPLUG_DET_SIGN_MAKE_MIME_OBJECT  = true;
00125   GPGMEPLUG_DET_SIGN_MAKE_MULTI_MIME   = true;
00126   GPGMEPLUG_DET_SIGN_CTYPE_MAIN        = "multipart/signed; protocol=\"application/pkcs7-signature\"; micalg=sha1";
00127   GPGMEPLUG_DET_SIGN_CDISP_MAIN        = "";
00128   GPGMEPLUG_DET_SIGN_CTENC_MAIN        = "";
00129   GPGMEPLUG_DET_SIGN_CTYPE_VERSION     = "";
00130   GPGMEPLUG_DET_SIGN_CDISP_VERSION     = "";
00131   GPGMEPLUG_DET_SIGN_CTENC_VERSION     = "";
00132   GPGMEPLUG_DET_SIGN_BTEXT_VERSION     = "";
00133   GPGMEPLUG_DET_SIGN_CTYPE_CODE        = "application/pkcs7-signature; name=\"smime.p7s\"";
00134   GPGMEPLUG_DET_SIGN_CDISP_CODE        = "attachment; filename=\"smime.p7s\"";
00135   GPGMEPLUG_DET_SIGN_CTENC_CODE        = "base64";
00136   GPGMEPLUG_DET_SIGN_FLAT_PREFIX       = "";
00137   GPGMEPLUG_DET_SIGN_FLAT_SEPARATOR    = "";
00138   GPGMEPLUG_DET_SIGN_FLAT_POSTFIX      = "";
00139   // 3. common definitions for opaque and detached signing
00140   __GPGMEPLUG_SIGNATURE_CODE_IS_BINARY = true;
00141 
00142   /* definitions for encoding */
00143   GPGMEPLUG_ENC_INCLUDE_CLEARTEXT  = false;
00144   GPGMEPLUG_ENC_MAKE_MIME_OBJECT   = true;
00145   GPGMEPLUG_ENC_MAKE_MULTI_MIME    = false;
00146   GPGMEPLUG_ENC_CTYPE_MAIN         = "application/pkcs7-mime; smime-type=enveloped-data; name=\"smime.p7m\"";
00147   GPGMEPLUG_ENC_CDISP_MAIN         = "attachment; filename=\"smime.p7m\"";
00148   GPGMEPLUG_ENC_CTENC_MAIN         = "base64";
00149   GPGMEPLUG_ENC_CTYPE_VERSION      = "";
00150   GPGMEPLUG_ENC_CDISP_VERSION      = "";
00151   GPGMEPLUG_ENC_CTENC_VERSION      = "";
00152   GPGMEPLUG_ENC_BTEXT_VERSION      = "";
00153   GPGMEPLUG_ENC_CTYPE_CODE         = "";
00154   GPGMEPLUG_ENC_CDISP_CODE         = "";
00155   GPGMEPLUG_ENC_CTENC_CODE         = "";
00156   GPGMEPLUG_ENC_FLAT_PREFIX        = "";
00157   GPGMEPLUG_ENC_FLAT_SEPARATOR     = "";
00158   GPGMEPLUG_ENC_FLAT_POSTFIX       = "";
00159   __GPGMEPLUG_ENCRYPTED_CODE_IS_BINARY = true;
00160 }
00161 
00162 OpenPGPCryptPlug::OpenPGPCryptPlug() : CryptPlug() {
00163   GPGMEPLUG_PROTOCOL = GPGME_PROTOCOL_OpenPGP;
00164   mProtocol = GpgME::Context::OpenPGP;
00165 
00166   /* definitions for signing */
00167   // 1. opaque signatures (only used for S/MIME)
00168   GPGMEPLUG_OPA_SIGN_INCLUDE_CLEARTEXT = false;
00169   GPGMEPLUG_OPA_SIGN_MAKE_MIME_OBJECT  = false;
00170   GPGMEPLUG_OPA_SIGN_MAKE_MULTI_MIME   = false;
00171   GPGMEPLUG_OPA_SIGN_CTYPE_MAIN        = "";
00172   GPGMEPLUG_OPA_SIGN_CDISP_MAIN        = "";
00173   GPGMEPLUG_OPA_SIGN_CTENC_MAIN        = "";
00174   GPGMEPLUG_OPA_SIGN_CTYPE_VERSION     = "";
00175   GPGMEPLUG_OPA_SIGN_CDISP_VERSION     = "";
00176   GPGMEPLUG_OPA_SIGN_CTENC_VERSION     = "";
00177   GPGMEPLUG_OPA_SIGN_BTEXT_VERSION     = "";
00178   GPGMEPLUG_OPA_SIGN_CTYPE_CODE        = "";
00179   GPGMEPLUG_OPA_SIGN_CDISP_CODE        = "";
00180   GPGMEPLUG_OPA_SIGN_CTENC_CODE        = "";
00181   GPGMEPLUG_OPA_SIGN_FLAT_PREFIX       = "";
00182   GPGMEPLUG_OPA_SIGN_FLAT_SEPARATOR    = "";
00183   GPGMEPLUG_OPA_SIGN_FLAT_POSTFIX      = "";
00184   // 2. detached signatures (used for S/MIME and for OpenPGP)
00185   GPGMEPLUG_DET_SIGN_INCLUDE_CLEARTEXT = true;
00186   GPGMEPLUG_DET_SIGN_MAKE_MIME_OBJECT  = true;
00187   GPGMEPLUG_DET_SIGN_MAKE_MULTI_MIME   = true;
00188   GPGMEPLUG_DET_SIGN_CTYPE_MAIN        = "multipart/signed; protocol=\"application/pgp-signature\"; micalg=pgp-sha1";
00189   GPGMEPLUG_DET_SIGN_CDISP_MAIN        = "";
00190   GPGMEPLUG_DET_SIGN_CTENC_MAIN        = "";
00191   GPGMEPLUG_DET_SIGN_CTYPE_VERSION     = "";
00192   GPGMEPLUG_DET_SIGN_CDISP_VERSION     = "";
00193   GPGMEPLUG_DET_SIGN_CTENC_VERSION     = "";
00194   GPGMEPLUG_DET_SIGN_BTEXT_VERSION     = "";
00195   GPGMEPLUG_DET_SIGN_CTYPE_CODE        = "application/pgp-signature";
00196   GPGMEPLUG_DET_SIGN_CDISP_CODE        = "";
00197   GPGMEPLUG_DET_SIGN_CTENC_CODE        = "";
00198   GPGMEPLUG_DET_SIGN_FLAT_PREFIX       = "";
00199   GPGMEPLUG_DET_SIGN_FLAT_SEPARATOR    = "";
00200   GPGMEPLUG_DET_SIGN_FLAT_POSTFIX      = "";
00201   // 3. common definitions for opaque and detached signing
00202   __GPGMEPLUG_SIGNATURE_CODE_IS_BINARY = false;
00203 
00204   /* definitions for encoding */
00205   GPGMEPLUG_ENC_INCLUDE_CLEARTEXT  = false;
00206   GPGMEPLUG_ENC_MAKE_MIME_OBJECT   = true;
00207   GPGMEPLUG_ENC_MAKE_MULTI_MIME    = true;
00208   GPGMEPLUG_ENC_CTYPE_MAIN         = "multipart/encrypted; protocol=\"application/pgp-encrypted\"";
00209   GPGMEPLUG_ENC_CDISP_MAIN         = "";
00210   GPGMEPLUG_ENC_CTENC_MAIN         = "";
00211   GPGMEPLUG_ENC_CTYPE_VERSION      = "application/pgp-encrypted";
00212   GPGMEPLUG_ENC_CDISP_VERSION      = "attachment";
00213   GPGMEPLUG_ENC_CTENC_VERSION      = "";
00214   GPGMEPLUG_ENC_BTEXT_VERSION      = "Version: 1";
00215   GPGMEPLUG_ENC_CTYPE_CODE         = "application/octet-stream";
00216   GPGMEPLUG_ENC_CDISP_CODE         = "inline; filename=\"msg.asc\"";
00217   GPGMEPLUG_ENC_CTENC_CODE         = "";
00218   GPGMEPLUG_ENC_FLAT_PREFIX        = "";
00219   GPGMEPLUG_ENC_FLAT_SEPARATOR     = "";
00220   GPGMEPLUG_ENC_FLAT_POSTFIX       = "";
00221   __GPGMEPLUG_ENCRYPTED_CODE_IS_BINARY = false;
00222 }
00223 
00224 #define days_from_seconds(x) ((x)/86400)
00225 
00226 /* Max number of parts in a DN */
00227 #define MAX_GPGME_IDX 20
00228 
00229 /* some macros to replace ctype ones and avoid locale problems */
00230 #define spacep(p)   (*(p) == ' ' || *(p) == '\t')
00231 #define digitp(p)   (*(p) >= '0' && *(p) <= '9')
00232 #define hexdigitp(a) (digitp (a)                     \
00233                       || (*(a) >= 'A' && *(a) <= 'F')  \
00234                       || (*(a) >= 'a' && *(a) <= 'f'))
00235 /* the atoi macros assume that the buffer has only valid digits */
00236 #define atoi_1(p)   (*(p) - '0' )
00237 #define atoi_2(p)   ((atoi_1(p) * 10) + atoi_1((p)+1))
00238 #define atoi_4(p)   ((atoi_2(p) * 100) + atoi_2((p)+2))
00239 #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
00240                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
00241 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
00242 
00243 static void *
00244 xmalloc (size_t n)
00245 {
00246   void *p = malloc (n);
00247   if (!p)
00248     {
00249       fputs ("\nfatal: out of core\n", stderr);
00250       exit (4);
00251     }
00252   return p;
00253 }
00254 
00255 /* Please: Don't call an allocation function xfoo when it may return NULL. */
00256 /* Wrong: #define xstrdup( x ) (x)?strdup(x):0 */
00257 /* Right: */
00258 static char *
00259 xstrdup (const char *string)
00260 {
00261   char *p = (char*)xmalloc (strlen (string)+1);
00262   strcpy (p, string);
00263   return p;
00264 }
00265 
00266 
00267 /* Wrapper to cope with a bug in gpgme 0.4.4. */
00268 static void
00269 my_gpgme_key_release (gpgme_key_t key)
00270 {
00271   if (key)
00272     gpgme_key_release (key);
00273 }
00274 
00275 
00276 CryptPlug::CryptPlug() {
00277 }
00278 
00279 CryptPlug::~CryptPlug() {
00280 }
00281 
00282 bool CryptPlug::initialize() {
00283   GpgME::setDefaultLocale( LC_CTYPE, setlocale( LC_CTYPE, 0 ) );
00284   GpgME::setDefaultLocale( LC_MESSAGES, setlocale( LC_MESSAGES, 0 ) );
00285   return (gpgme_engine_check_version (GPGMEPLUG_PROTOCOL) == GPG_ERR_NO_ERROR);
00286 }
00287 
00288 
00289 bool CryptPlug::hasFeature( Feature flag )
00290 {
00291   /* our own plugins are supposed to support everything */
00292   switch ( flag ) {
00293   case Feature_SignMessages:
00294   case Feature_VerifySignatures:
00295   case Feature_EncryptMessages:
00296   case Feature_DecryptMessages:
00297   case Feature_SendCertificates:
00298   case Feature_PinEntrySettings:
00299   case Feature_StoreMessagesWithSigs:
00300   case Feature_EncryptionCRLs:
00301   case Feature_StoreMessagesEncrypted:
00302   case Feature_CheckCertificatePath:
00303     return true;
00304   case Feature_WarnSignCertificateExpiry:
00305   case Feature_WarnSignEmailNotInCertificate:
00306   case Feature_WarnEncryptCertificateExpiry:
00307   case Feature_WarnEncryptEmailNotInCertificate:
00308      return GPGMEPLUG_PROTOCOL == GPGME_PROTOCOL_CMS;
00309   /* undefined or not yet implemented: */
00310   case Feature_CRLDirectoryService:
00311   case Feature_CertificateDirectoryService:
00312   case Feature_undef:
00313   default:
00314     return false;
00315   }
00316 }
00317 
00318 
00319 /* Return the current interface version.  This is a simple way for a
00320    user to check whether all required fucntions are available.  If
00321    MIN_VERSION is not NULL the lowest supported version of the
00322    interface is returned in addition. */
00323 int CryptPlug::interfaceVersion (int *min_version)
00324 {
00325   if (min_version)
00326     *min_version = 0;
00327   return 1;
00328 }
00329 
00330 static
00331 int getAttrExpireFormKey( gpgme_key_t* rKey)
00332 {
00333   int daysLeft = CRYPTPLUG_CERT_DOES_NEVER_EXPIRE;
00334   if ( rKey && *rKey && (*rKey)->subkeys && (*rKey)->subkeys->expires >= 0 ) {
00335     time_t expire_time = (*rKey)->subkeys->expires;
00336     time_t cur_time = time (NULL);
00337     if( cur_time > expire_time ) {
00338       daysLeft = days_from_seconds(cur_time - expire_time);
00339       daysLeft *= -1;
00340     }
00341     else
00342       daysLeft = days_from_seconds(expire_time - cur_time);
00343   }
00344   return daysLeft;
00345 }
00346 
00347 
00348 static
00349 void storeNewCharPtr( char** dest, const char* src )
00350 {
00351   int sLen = strlen( src );
00352   *dest = (char*)xmalloc( sLen + 1 );
00353   strcpy( *dest, src );
00354 }
00355 
00356 
00357 bool CryptPlug::signMessage( const char*  cleartext,
00358                  char** ciphertext,
00359                  const size_t* cipherLen,
00360                  const char*  certificate,
00361                  struct StructuringInfo* structuring,
00362                  int* errId,
00363                  char** errTxt,
00364                  SendCertificates sendCertificates,
00365                  SignatureCompoundMode signatureCompoundMode )
00366 {
00367   bool bIsOpaque;
00368   gpgme_ctx_t ctx;
00369   gpgme_error_t err;
00370   gpgme_key_t rKey;
00371   gpgme_data_t data,  sig;
00372   char* rSig  = 0;
00373   bool  bOk   = false;
00374   int sendCerts = 1;
00375 
00376   init_StructuringInfo( structuring );
00377 
00378   if( !ciphertext )
00379     return false;
00380 
00381   err = gpgme_new (&ctx);
00382   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
00383 
00384   gpgme_set_armor (ctx, __GPGMEPLUG_SIGNATURE_CODE_IS_BINARY ? 0 : 1);
00385   /*  gpgme_set_textmode (ctx, 1); */
00386 
00387   switch ( sendCertificates ) {
00388     case SendCert_undef:
00389       break;
00390     case SendCert_DontSend:
00391       sendCerts = 0;
00392       break;
00393     case SendCert_SendOwn:
00394       sendCerts = 1;
00395       break;
00396     case SendCert_SendChainWithoutRoot:
00397       sendCerts = -2;
00398       break;
00399     case SendCert_SendChainWithRoot:
00400       sendCerts = -1;
00401       break;
00402     default:
00403       sendCerts = 0;
00404       break;
00405   }
00406   gpgme_set_include_certs (ctx, sendCerts);
00407 
00408   /* select the signer's key if provided */
00409   if (certificate != 0) {
00410       err = gpgme_op_keylist_start(ctx, certificate, 0);
00411       while (!err) {
00412           err = gpgme_op_keylist_next(ctx, &rKey);
00413           if (!err) {
00414           if ( rKey && rKey->can_sign ) {
00415                   /* clear existing signers */
00416                   gpgme_signers_clear(ctx);
00417                   /* set the signing key */
00418                   gpgme_signers_add(ctx, rKey);
00419                   /* we only support one signer for now */
00420                   break;
00421               }
00422           }
00423       }
00424       gpgme_op_keylist_end(ctx);
00425   }
00426 
00427   /* PENDING(g10) Implement this
00428 
00429      gpgme_set_signature_algorithm( ctx, config->signatureAlgorithm )
00430      --> This does not make sense.  The algorithm is a property of
00431      the certificate used [wk 2002-03-23] */
00432 
00433   gpgme_data_new_from_mem (&data, cleartext,
00434                             strlen( cleartext ), 1 );
00435   gpgme_data_new ( &sig );
00436 
00437   /* NOTE: Currently we support Opaque signed messages only for S/MIME,
00438      but not for OpenPGP mode! */
00439   if( GPGMEPLUG_PROTOCOL == GPGME_PROTOCOL_CMS )
00440     bIsOpaque = (signatureCompoundMode == SignatureCompoundMode_Opaque);
00441   else
00442     bIsOpaque = false;
00443 
00444   err = gpgme_op_sign ( ctx,
00445                         data,
00446                         sig,
00447                         bIsOpaque
00448                         ? GPGME_SIG_MODE_NORMAL
00449                         : GPGME_SIG_MODE_DETACH );
00450 
00451   if ( !err ) {
00452     if( __GPGMEPLUG_SIGNATURE_CODE_IS_BINARY ) {
00453       *ciphertext = gpgme_data_release_and_get_mem( sig, (size_t*)cipherLen );
00454       bOk = true;
00455     }
00456     else {
00457       rSig = gpgme_data_release_and_get_mem( sig, (size_t*)cipherLen );
00458       *ciphertext = (char*)malloc( *cipherLen + 1 );
00459       if( *ciphertext ) {
00460         if( *cipherLen ) {
00461           bOk = true;
00462           strncpy((char*)*ciphertext, rSig, *cipherLen );
00463         }
00464         (*ciphertext)[*cipherLen] = '\0';
00465       }
00466       free( rSig );
00467     }
00468   }
00469   else {
00470     gpgme_data_release( sig );
00471 /*
00472 *ciphertext = malloc( 70 );
00473 strcpy((char*)*ciphertext, "xyz\nsig-dummy\nzyx" );
00474 (*ciphertext)[17] = '\0';
00475 err = 0;
00476 {
00477 */
00478     *ciphertext = 0;
00479     fprintf( stderr, "\n\n    gpgme_op_sign() returned this error code:  %i\n\n", err );
00480     if( errId )
00481       *errId = err;
00482     if( errTxt ) {
00483       const char* _errTxt = gpgme_strerror( err );
00484       *errTxt = (char*)malloc( strlen( _errTxt ) + 1 );
00485       if( *errTxt )
00486         strcpy(*errTxt, _errTxt );
00487     }
00488 /*
00489 }
00490 */
00491   }
00492   gpgme_data_release( data );
00493   gpgme_release (ctx);
00494 
00495   if( bOk && structuring ) {
00496     if( bIsOpaque ) {
00497       structuring->includeCleartext = GPGMEPLUG_OPA_SIGN_INCLUDE_CLEARTEXT;
00498       structuring->makeMimeObject   = GPGMEPLUG_OPA_SIGN_MAKE_MIME_OBJECT;
00499       if( structuring->makeMimeObject ) {
00500         structuring->makeMultiMime  = GPGMEPLUG_OPA_SIGN_MAKE_MULTI_MIME;
00501         storeNewCharPtr( &structuring->contentTypeMain,
00502                         GPGMEPLUG_OPA_SIGN_CTYPE_MAIN );
00503         storeNewCharPtr( &structuring->contentDispMain,
00504                         GPGMEPLUG_OPA_SIGN_CDISP_MAIN );
00505         storeNewCharPtr( &structuring->contentTEncMain,
00506                         GPGMEPLUG_OPA_SIGN_CTENC_MAIN );
00507         if( structuring->makeMultiMime ) {
00508             storeNewCharPtr( &structuring->contentTypeVersion,
00509                             GPGMEPLUG_OPA_SIGN_CTYPE_VERSION );
00510             storeNewCharPtr( &structuring->contentDispVersion,
00511                             GPGMEPLUG_OPA_SIGN_CDISP_VERSION );
00512             storeNewCharPtr( &structuring->contentTEncVersion,
00513                             GPGMEPLUG_OPA_SIGN_CTENC_VERSION );
00514             storeNewCharPtr( &structuring->bodyTextVersion,
00515                             GPGMEPLUG_OPA_SIGN_BTEXT_VERSION );
00516             storeNewCharPtr( &structuring->contentTypeCode,
00517                             GPGMEPLUG_OPA_SIGN_CTYPE_CODE );
00518             storeNewCharPtr( &structuring->contentDispCode,
00519                             GPGMEPLUG_OPA_SIGN_CDISP_CODE );
00520             storeNewCharPtr( &structuring->contentTEncCode,
00521                             GPGMEPLUG_OPA_SIGN_CTENC_CODE );
00522         }
00523       } else {
00524         storeNewCharPtr( &structuring->flatTextPrefix,
00525                         GPGMEPLUG_OPA_SIGN_FLAT_PREFIX );
00526         storeNewCharPtr( &structuring->flatTextSeparator,
00527                         GPGMEPLUG_OPA_SIGN_FLAT_SEPARATOR );
00528         storeNewCharPtr( &structuring->flatTextPostfix,
00529                         GPGMEPLUG_OPA_SIGN_FLAT_POSTFIX );
00530       }
00531     } else {
00532       structuring->includeCleartext = GPGMEPLUG_DET_SIGN_INCLUDE_CLEARTEXT;
00533       structuring->makeMimeObject   = GPGMEPLUG_DET_SIGN_MAKE_MIME_OBJECT;
00534       if( structuring->makeMimeObject ) {
00535         structuring->makeMultiMime  = GPGMEPLUG_DET_SIGN_MAKE_MULTI_MIME;
00536         storeNewCharPtr( &structuring->contentTypeMain,
00537                         GPGMEPLUG_DET_SIGN_CTYPE_MAIN );
00538         storeNewCharPtr( &structuring->contentDispMain,
00539                         GPGMEPLUG_DET_SIGN_CDISP_MAIN );
00540         storeNewCharPtr( &structuring->contentTEncMain,
00541                         GPGMEPLUG_DET_SIGN_CTENC_MAIN );
00542         if( structuring->makeMultiMime ) {
00543             storeNewCharPtr( &structuring->contentTypeVersion,
00544                             GPGMEPLUG_DET_SIGN_CTYPE_VERSION );
00545             storeNewCharPtr( &structuring->contentDispVersion,
00546                             GPGMEPLUG_DET_SIGN_CDISP_VERSION );
00547             storeNewCharPtr( &structuring->contentTEncVersion,
00548                             GPGMEPLUG_DET_SIGN_CTENC_VERSION );
00549             storeNewCharPtr( &structuring->bodyTextVersion,
00550                             GPGMEPLUG_DET_SIGN_BTEXT_VERSION );
00551             storeNewCharPtr( &structuring->contentTypeCode,
00552                             GPGMEPLUG_DET_SIGN_CTYPE_CODE );
00553             storeNewCharPtr( &structuring->contentDispCode,
00554                             GPGMEPLUG_DET_SIGN_CDISP_CODE );
00555             storeNewCharPtr( &structuring->contentTEncCode,
00556                             GPGMEPLUG_DET_SIGN_CTENC_CODE );
00557         }
00558       } else {
00559         storeNewCharPtr( &structuring->flatTextPrefix,
00560                         GPGMEPLUG_DET_SIGN_FLAT_PREFIX );
00561         storeNewCharPtr( &structuring->flatTextSeparator,
00562                         GPGMEPLUG_DET_SIGN_FLAT_SEPARATOR );
00563         storeNewCharPtr( &structuring->flatTextPostfix,
00564                         GPGMEPLUG_DET_SIGN_FLAT_POSTFIX );
00565       }
00566     }
00567   }
00568   return bOk;
00569 }
00570 
00571 
00572 
00573 bool CryptPlug::storeCertificatesFromMessage( const char* ){ return true; }
00574 
00575 
00576 /* returns address if address doesn't contain a <xxx> part
00577  * else it returns a new string xxx and frees address
00578  */
00579 static char* parseAddress( char* address )
00580 {
00581   char* result = address;
00582   char* i;
00583   char* j;
00584   if( !result ) return result;
00585   i = index( address, '<' );
00586   if( i ) {
00587     j = index( i+1, '>' );
00588     if( j == NULL ) j = address+strlen(address);
00589     result = (char*)xmalloc( j-i );
00590     strncpy( result, i+1, j-i-1 );
00591     result[j-i-1] = '\0';
00592     free( address );
00593   } else {
00594     i = address;
00595     j = i+strlen(address);
00596   }
00597   {
00598     /* remove surrounding whitespace */
00599     char* k = result+(j-i-1);
00600     char* l = result;
00601     while( isspace( *l ) ) ++l;
00602     while( isspace( *k ) ) --k;
00603     if( l != result || k != result+(j-i-1) ) {
00604       char* result2 = (char*)xmalloc( k-l+2 );
00605       strncpy( result2, l, k-l+1 );
00606       result2[k-l+1] = '\0';
00607       free(result);
00608       result = result2;
00609     }
00610   }
00611   return result;
00612 }
00613 
00614 static char* nextAddress( const char** address )
00615 {
00616   const char *start = *address;
00617   char* result = NULL;
00618   int quote = 0;
00619   int comment = 0;
00620   int found = 0;
00621   if( *address == NULL ) return NULL;
00622   while( **address ) {
00623 
00624     switch( **address ) {
00625     case '\\': /* escaped character */
00626       ++(*address);
00627       break;
00628     case '"':
00629       if( comment == 0 ) {
00630         if( quote > 0 ) --quote;
00631         else ++quote;
00632       }
00633       break;
00634     case '(': /* comment start */
00635       if( quote == 0 ) ++comment;
00636       break;
00637     case ')': /* comment end */
00638       if( quote == 0 ) --comment;
00639       break;
00640     case '\0':
00641     case '\1': /* delimiter */
00642       if( quote == 0 && comment == 0 ) {
00643         found = 1;
00644       }
00645       break;
00646     }
00647     ++(*address);
00648     if( found ) break;
00649   }
00650   if( found || **address == 0 ) {
00651     size_t len;
00652     len = *address - start;
00653     if( len > 0 ) {
00654       if( **address != 0 ) --len;
00655       result = (char*)xmalloc( len*sizeof(char)+1 );
00656       strncpy( result, start, len );
00657       result[len] = '\0';
00658     }
00659   }
00660   return parseAddress(result);
00661 }
00662 
00663 bool CryptPlug::encryptMessage( const char*  cleartext,
00664                      const char** ciphertext,
00665                      const size_t* cipherLen,
00666                      const char*  certificate,
00667                      struct StructuringInfo* structuring,
00668                      int* errId,
00669                      char** errTxt )
00670 {
00671   gpgme_ctx_t ctx;
00672   gpgme_error_t err;
00673   gpgme_data_t gCiphertext, gPlaintext;
00674   char*  rCiph = 0;
00675   bool   bOk   = false;
00676 
00677   init_StructuringInfo( structuring );
00678 
00679   gpgme_new (&ctx);
00680   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
00681 
00682   gpgme_set_armor (ctx, __GPGMEPLUG_ENCRYPTED_CODE_IS_BINARY ? 0 : 1);
00683   /*  gpgme_set_textmode (ctx, 1); */
00684 
00685   gpgme_data_new_from_mem (&gPlaintext, cleartext,
00686                             1+strlen( cleartext ), 1 );
00687   err = gpgme_data_new ( &gCiphertext );
00688 
00689 
00690   std::vector<char*> recips;
00691 
00692   {
00693     const char* p = certificate;
00694     char* tok;
00695     while( (tok = nextAddress( &p ) ) != 0 ) {
00696       fprintf( stderr, "\nGPGMEPLUG encryptMessage() using addressee %s\n", tok );
00697       recips.push_back( tok );
00698     }
00699   }
00700 
00701   recips.push_back( 0 );
00702   const char ** patterns = new const char*[ recips.size() ];
00703   const char ** patterns_it = patterns;
00704   std::copy( recips.begin(), recips.end(), patterns_it );
00705   recips.pop_back();
00706 
00707   std::vector<gpgme_key_t> keys;
00708 #if 0 // BROKEN FOR FINGERPRINTS
00709   err = gpgme_op_keylist_ext_start( ctx, patterns, 0, 0 );
00710   while ( !err ) {
00711     gpgme_key_t key = 0;
00712     err = gpgme_op_keylist_next( ctx, &key );
00713     keys.push_back( key );
00714   }
00715   if ( gpg_err_code( err ) == GPG_ERR_EOF )
00716     err = GPG_ERR_NO_ERROR;
00717   gpgme_op_keylist_end( ctx );
00718 #else
00719   for ( const char ** pit = patterns ; *pit && !err ; ++pit ) {
00720     gpgme_key_t key = 0;
00721     err = gpgme_get_key( ctx, *pit, &key, false );
00722     if ( key )
00723       keys.push_back( key );
00724   }
00725 #endif
00726 
00727   keys.push_back( 0 );
00728   gpgme_key_t * rset = new gpgme_key_t[ keys.size() ];
00729   gpgme_key_t * rset_it = rset;
00730   std::copy( keys.begin(), keys.end(), rset_it );
00731   keys.pop_back();
00732 
00733   std::for_each( recips.begin(), recips.end(), &free );
00734   delete[] patterns;
00735 
00736   /* PENDING(g10) Implement this
00737      Possible values: RSA = 1, SHA1 = 2, TripleDES = 3
00738      gpgme_set_encryption_algorithm( ctx, config->encryptionAlgorithm );
00739 
00740      -> Your are mixing public key and symmetric algorithms.  The
00741      latter may be configured but the sphix specifications do opnly
00742      allow 3-DES so this is not nothing we need to do.  The proper way
00743      to select the symmetric algorithm is anyway by looking at the
00744      capabilities of the certificate because this is the only way to
00745      know what the recipient can accept. [wk 2002-03-23]
00746 
00747      PENDING(g10) Implement this
00748      gpgme_set_encryption_check_certificate_path(
00749      config->checkCertificatePath )
00750 
00751      PENDING(g10) Implement this
00752      gpgme_set_encryption_check_certificate_path_to_root(
00753      config->checkEncryptionCertificatePathToRoot )
00754 
00755      -> Not checking a certificate up to the ROOT CA is dangerous and
00756      stupid. There is no need for those options.  [wk 2002-03-23] */
00757 
00758 
00759   if ( !err )
00760     err = gpgme_op_encrypt (ctx, rset, (gpgme_encrypt_flags_t)0, gPlaintext, gCiphertext );
00761   if( err ) {
00762     fprintf( stderr, "\ngpgme_op_encrypt() returned this error code:  %i\n", err );
00763     if( errId )
00764       *errId = err;
00765     if( errTxt ) {
00766       const char* _errTxt = gpgme_strerror( err );
00767       const size_t errTxtLen = strlen( _errTxt ) + 100;  // leave room for reason string
00768       *errTxt = (char*)malloc( errTxtLen + 1 );
00769       if( *errTxt ) {
00770     std::string str = _errTxt;
00771     gpgme_encrypt_result_t opInfo = gpgme_op_encrypt_result( ctx );
00772     if ( opInfo && opInfo->invalid_recipients ) {
00773       str += " - ";
00774       str += gpgme_strerror( opInfo->invalid_recipients->reason );
00775       // PENDING(kdab): there could be more than one!
00776     }
00777     strncmp( *errTxt, str.c_str(), errTxtLen );
00778     (*errTxt)[errTxtLen] = '\0';
00779       }
00780     }
00781   }
00782 
00783   std::for_each( keys.begin(), keys.end(), &my_gpgme_key_release );
00784   delete[] rset;
00785   gpgme_data_release (gPlaintext);
00786 
00787   if( !err ) {
00788     if( __GPGMEPLUG_ENCRYPTED_CODE_IS_BINARY ) {
00789       *ciphertext = gpgme_data_release_and_get_mem( gCiphertext, (size_t*)cipherLen );
00790       bOk = true;
00791     }
00792     else {
00793       rCiph = gpgme_data_release_and_get_mem( gCiphertext, (size_t*)cipherLen );
00794       *ciphertext = (char*)malloc( *cipherLen + 1 );
00795       if( *ciphertext ) {
00796         if( *cipherLen ) {
00797           bOk = true;
00798           strncpy((char*)*ciphertext, rCiph, *cipherLen );
00799         }
00800         ((char*)(*ciphertext))[*cipherLen] = 0;
00801       }
00802       free( rCiph );
00803     }
00804   }
00805   else {
00806     gpgme_data_release ( gCiphertext );
00807     *ciphertext = 0;
00808     /* error handling is missing: if only one untrusted key was found
00809       (or none at all), gpg won't sign the message.  (hier fehlt eine
00810       Fehlerbehandlung: fuer einen Recipient nur ein untrusted key
00811       (oder gar keiner) gefunden wurde, verweigert gpg das signieren.)
00812     */
00813   }
00814 
00815   gpgme_release (ctx);
00816 
00817   fflush( stderr );
00818 
00819   if( bOk && structuring ) {
00820     structuring->includeCleartext = GPGMEPLUG_ENC_INCLUDE_CLEARTEXT;
00821     structuring->makeMimeObject   = GPGMEPLUG_ENC_MAKE_MIME_OBJECT;
00822     if( structuring->makeMimeObject ) {
00823       structuring->makeMultiMime  = GPGMEPLUG_ENC_MAKE_MULTI_MIME;
00824       storeNewCharPtr( &structuring->contentTypeMain,
00825                        GPGMEPLUG_ENC_CTYPE_MAIN );
00826       storeNewCharPtr( &structuring->contentDispMain,
00827                        GPGMEPLUG_ENC_CDISP_MAIN );
00828       storeNewCharPtr( &structuring->contentTEncMain,
00829                        GPGMEPLUG_ENC_CTENC_MAIN );
00830       if( structuring->makeMultiMime ) {
00831         storeNewCharPtr( &structuring->contentTypeVersion,
00832                          GPGMEPLUG_ENC_CTYPE_VERSION );
00833         storeNewCharPtr( &structuring->contentDispVersion,
00834                          GPGMEPLUG_ENC_CDISP_VERSION );
00835         storeNewCharPtr( &structuring->contentTEncVersion,
00836                          GPGMEPLUG_ENC_CTENC_VERSION );
00837         storeNewCharPtr( &structuring->bodyTextVersion,
00838                          GPGMEPLUG_ENC_BTEXT_VERSION );
00839         storeNewCharPtr( &structuring->contentTypeCode,
00840                          GPGMEPLUG_ENC_CTYPE_CODE );
00841         storeNewCharPtr( &structuring->contentDispCode,
00842                          GPGMEPLUG_ENC_CDISP_CODE );
00843         storeNewCharPtr( &structuring->contentTEncCode,
00844                          GPGMEPLUG_ENC_CTENC_CODE );
00845       }
00846     } else {
00847       storeNewCharPtr( &structuring->flatTextPrefix,
00848                        GPGMEPLUG_ENC_FLAT_PREFIX );
00849       storeNewCharPtr( &structuring->flatTextSeparator,
00850                        GPGMEPLUG_ENC_FLAT_SEPARATOR );
00851       storeNewCharPtr( &structuring->flatTextPostfix,
00852                        GPGMEPLUG_ENC_FLAT_POSTFIX );
00853     }
00854   }
00855   return bOk;
00856 }
00857 
00858 
00859 bool CryptPlug::encryptAndSignMessage( const char* /*cleartext*/,
00860                        const char** /*ciphertext*/,
00861                        const char* /*certificate*/,
00862                        struct StructuringInfo* structuring )
00863 {
00864   bool bOk;
00865 
00866   init_StructuringInfo( structuring );
00867 
00868   bOk = false;
00869 
00870   /* implementation of this function is still missing */
00871 
00872   if( bOk && structuring ) {
00873     structuring->includeCleartext = GPGMEPLUG_ENCSIGN_INCLUDE_CLEARTEXT;
00874     structuring->makeMimeObject   = GPGMEPLUG_ENCSIGN_MAKE_MIME_OBJECT;
00875     if( structuring->makeMimeObject ) {
00876       structuring->makeMultiMime  = GPGMEPLUG_ENCSIGN_MAKE_MULTI_MIME;
00877       storeNewCharPtr( &structuring->contentTypeMain,
00878                        GPGMEPLUG_ENCSIGN_CTYPE_MAIN );
00879       storeNewCharPtr( &structuring->contentDispMain,
00880                        GPGMEPLUG_ENCSIGN_CDISP_MAIN );
00881       storeNewCharPtr( &structuring->contentTEncMain,
00882                        GPGMEPLUG_ENCSIGN_CTENC_MAIN );
00883       if( structuring->makeMultiMime ) {
00884         storeNewCharPtr( &structuring->contentTypeVersion,
00885                          GPGMEPLUG_ENCSIGN_CTYPE_VERSION );
00886         storeNewCharPtr( &structuring->contentDispVersion,
00887                          GPGMEPLUG_ENCSIGN_CDISP_VERSION );
00888         storeNewCharPtr( &structuring->contentTEncVersion,
00889                          GPGMEPLUG_ENCSIGN_CTENC_VERSION );
00890         storeNewCharPtr( &structuring->bodyTextVersion,
00891                          GPGMEPLUG_ENCSIGN_BTEXT_VERSION );
00892         storeNewCharPtr( &structuring->contentTypeCode,
00893                          GPGMEPLUG_ENCSIGN_CTYPE_CODE );
00894         storeNewCharPtr( &structuring->contentDispCode,
00895                          GPGMEPLUG_ENCSIGN_CDISP_CODE );
00896         storeNewCharPtr( &structuring->contentTEncCode,
00897                          GPGMEPLUG_ENCSIGN_CTENC_CODE );
00898       }
00899     } else {
00900       storeNewCharPtr( &structuring->flatTextPrefix,
00901                        GPGMEPLUG_ENCSIGN_FLAT_PREFIX );
00902       storeNewCharPtr( &structuring->flatTextSeparator,
00903                        GPGMEPLUG_ENCSIGN_FLAT_SEPARATOR );
00904       storeNewCharPtr( &structuring->flatTextPostfix,
00905                        GPGMEPLUG_ENCSIGN_FLAT_POSTFIX );
00906     }
00907   }
00908   return bOk;
00909 }
00910 
00911 
00912 bool CryptPlug::decryptMessage( const char* ciphertext,
00913                      bool        cipherIsBinary,
00914                      int         cipherLen,
00915                      const char** cleartext,
00916                 const char* /*certificate*/,
00917                      int* errId,
00918                      char** errTxt )
00919 {
00920   gpgme_ctx_t ctx;
00921   gpgme_error_t err;
00922   gpgme_data_t gCiphertext, gPlaintext;
00923   size_t rCLen = 0;
00924   char*  rCiph = 0;
00925   bool bOk = false;
00926 
00927   if( !ciphertext )
00928     return false;
00929 
00930   err = gpgme_new (&ctx);
00931   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
00932 
00933   gpgme_set_armor (ctx, cipherIsBinary ? 0 : 1);
00934   /*  gpgme_set_textmode (ctx, cipherIsBinary ? 0 : 1); */
00935 
00936   /*
00937   gpgme_data_new_from_mem( &gCiphertext, ciphertext,
00938                            1+strlen( ciphertext ), 1 ); */
00939   gpgme_data_new_from_mem( &gCiphertext,
00940                            ciphertext,
00941                            cipherIsBinary
00942                            ? cipherLen
00943                            : strlen( ciphertext ),
00944                            1 );
00945 
00946   gpgme_data_new( &gPlaintext );
00947 
00948   err = gpgme_op_decrypt( ctx, gCiphertext, gPlaintext );
00949   if( err ) {
00950     fprintf( stderr, "\ngpgme_op_decrypt() returned this error code:  %i\n\n", err );
00951     if( errId )
00952       *errId = err;
00953     if( errTxt ) {
00954       const char* _errTxt = gpgme_strerror( err );
00955       *errTxt = (char*)malloc( strlen( _errTxt ) + 1 );
00956       if( *errTxt )
00957         strcpy(*errTxt, _errTxt );
00958     }
00959   }
00960 
00961   gpgme_data_release( gCiphertext );
00962 
00963   rCiph = gpgme_data_release_and_get_mem( gPlaintext,  &rCLen );
00964 
00965   *cleartext = (char*)malloc( rCLen + 1 );
00966   if( *cleartext ) {
00967       if( rCLen ) {
00968           bOk = true;
00969           strncpy((char*)*cleartext, rCiph, rCLen );
00970       }
00971       ((char*)(*cleartext))[rCLen] = 0;
00972   }
00973 
00974   free( rCiph );
00975   gpgme_release( ctx );
00976   return bOk;
00977 }
00978 
00979 
00980 static char *
00981 trim_trailing_spaces( char *string )
00982 {
00983     char *p, *mark;
00984 
00985     for( mark = NULL, p = string; *p; p++ ) {
00986     if( isspace( *p ) ) {
00987         if( !mark )
00988         mark = p;
00989     }
00990     else
00991         mark = NULL;
00992     }
00993     if( mark )
00994     *mark = '\0' ;
00995 
00996     return string ;
00997 }
00998 
00999 /* Parse a DN and return an array-ized one.  This is not a validating
01000    parser and it does not support any old-stylish syntax; gpgme is
01001    expected to return only rfc2253 compatible strings. */
01002 static const unsigned char *
01003 parse_dn_part (CryptPlug::DnPair *array, const unsigned char *string)
01004 {
01005   const unsigned char *s, *s1;
01006   size_t n;
01007   char *p;
01008 
01009   /* parse attributeType */
01010   for (s = string+1; *s && *s != '='; s++)
01011     ;
01012   if (!*s)
01013     return NULL; /* error */
01014   n = s - string;
01015   if (!n)
01016     return NULL; /* empty key */
01017   p = (char*)xmalloc (n+1);
01018 
01019 
01020   memcpy (p, string, n);
01021   p[n] = 0;
01022   trim_trailing_spaces ((char*)p);
01023   // map OIDs to their names:
01024   for ( unsigned int i = 0 ; i < numOidMaps ; ++i )
01025     if ( !strcasecmp ((char*)p, oidmap[i].oid) ) {
01026       free( p );
01027       p = xstrdup (oidmap[i].name);
01028       break;
01029     }
01030   array->key = p;
01031   string = s + 1;
01032 
01033   if (*string == '#')
01034     { /* hexstring */
01035       string++;
01036       for (s=string; hexdigitp (s); s++)
01037         s++;
01038       n = s - string;
01039       if (!n || (n & 1))
01040         return NULL; /* empty or odd number of digits */
01041       n /= 2;
01042       array->value = p = (char*)xmalloc (n+1);
01043 
01044 
01045       for (s1=string; n; s1 += 2, n--)
01046         *p++ = xtoi_2 (s1);
01047       *p = 0;
01048    }
01049   else
01050     { /* regular v3 quoted string */
01051       for (n=0, s=string; *s; s++)
01052         {
01053           if (*s == '\\')
01054             { /* pair */
01055               s++;
01056               if (*s == ',' || *s == '=' || *s == '+'
01057                   || *s == '<' || *s == '>' || *s == '#' || *s == ';'
01058                   || *s == '\\' || *s == '\"' || *s == ' ')
01059                 n++;
01060               else if (hexdigitp (s) && hexdigitp (s+1))
01061                 {
01062                   s++;
01063                   n++;
01064                 }
01065               else
01066                 return NULL; /* invalid escape sequence */
01067             }
01068           else if (*s == '\"')
01069             return NULL; /* invalid encoding */
01070           else if (*s == ',' || *s == '=' || *s == '+'
01071                    || *s == '<' || *s == '>' || *s == '#' || *s == ';' )
01072             break;
01073           else
01074             n++;
01075         }
01076 
01077       array->value = p = (char*)xmalloc (n+1);
01078 
01079 
01080       for (s=string; n; s++, n--)
01081         {
01082           if (*s == '\\')
01083             {
01084               s++;
01085               if (hexdigitp (s))
01086                 {
01087                   *p++ = xtoi_2 (s);
01088                   s++;
01089                 }
01090               else
01091                 *p++ = *s;
01092             }
01093           else
01094             *p++ = *s;
01095         }
01096       *p = 0;
01097     }
01098   return s;
01099 }
01100 
01101 
01102 /* Parse a DN and return an array-ized one.  This is not a validating
01103    parser and it does not support any old-stylish syntax; gpgme is
01104    expected to return only rfc2253 compatible strings. */
01105 static CryptPlug::DnPair *
01106 parse_dn (const unsigned char *string)
01107 {
01108   struct CryptPlug::DnPair *array;
01109   size_t arrayidx, arraysize;
01110 
01111   if( !string )
01112     return NULL;
01113 
01114   arraysize = 7; /* C,ST,L,O,OU,CN,email */
01115   arrayidx = 0;
01116   array = (CryptPlug::DnPair*)xmalloc ((arraysize+1) * sizeof *array);
01117 
01118 
01119   while (*string)
01120     {
01121       while (*string == ' ')
01122         string++;
01123       if (!*string)
01124         break; /* ready */
01125       if (arrayidx >= arraysize)
01126         { /* mutt lacks a real safe_realoc - so we need to copy */
01127           struct CryptPlug::DnPair *a2;
01128 
01129           arraysize += 5;
01130           a2 = (CryptPlug::DnPair*)xmalloc ((arraysize+1) * sizeof *array);
01131           for (unsigned int i=0; i < arrayidx; i++)
01132             {
01133               a2[i].key = array[i].key;
01134               a2[i].value = array[i].value;
01135             }
01136           free (array);
01137           array = a2;
01138         }
01139       array[arrayidx].key = NULL;
01140       array[arrayidx].value = NULL;
01141       string = parse_dn_part (array+arrayidx, string);
01142       arrayidx++;
01143       if (!string)
01144         goto failure;
01145       while (*string == ' ')
01146         string++;
01147       if (*string && *string != ',' && *string != ';' && *string != '+')
01148         goto failure; /* invalid delimiter */
01149       if (*string)
01150         string++;
01151     }
01152   array[arrayidx].key = NULL;
01153   array[arrayidx].value = NULL;
01154   return array;
01155 
01156  failure:
01157   for (unsigned i=0; i < arrayidx; i++)
01158     {
01159       free (array[i].key);
01160       free (array[i].value);
01161     }
01162   free (array);
01163   return NULL;
01164 }
01165 
01166 static void
01167 add_dn_part( QCString& result, struct CryptPlug::DnPair& dnPair )
01168 {
01169   /* email hack */
01170   QCString mappedPart( dnPair.key );
01171   for ( unsigned int i = 0 ; i < numOidMaps ; ++i ){
01172     if( !strcasecmp( dnPair.key, oidmap[i].oid ) ) {
01173       mappedPart = oidmap[i].name;
01174       break;
01175     }
01176   }
01177   result.append( mappedPart );
01178   result.append( "=" );
01179   result.append( dnPair.value );
01180 }
01181 
01182 static int
01183 add_dn_parts( QCString& result, struct CryptPlug::DnPair* dn, const char* part )
01184 {
01185   int any = 0;
01186 
01187   if( dn ) {
01188     for(; dn->key; ++dn ) {
01189       if( !strcmp( dn->key, part ) ) {
01190         if( any )
01191           result.append( "," );
01192         add_dn_part( result, *dn );
01193         any = 1;
01194       }
01195     }
01196   }
01197   return any;
01198 }
01199 
01200 static char*
01201 reorder_dn( struct CryptPlug::DnPair *dn,
01202             char** attrOrder = 0,
01203             const char* unknownAttrsHandling = 0 )
01204 {
01205   struct CryptPlug::DnPair *dnOrg = dn;
01206 
01207   /* note: The must parts are: CN, L, OU, O, C */
01208   const char* defaultpart[] = {
01209     "CN", "S", "SN", "GN", "T", "UID",
01210           "MAIL", "EMAIL", "MOBILE", "TEL", "FAX", "STREET",
01211     "L",  "PC", "SP", "ST",
01212     "OU",
01213     "O",
01214     "C",
01215     NULL
01216   };
01217   const char** stdpart = attrOrder ? ((const char**)attrOrder) : defaultpart;
01218   int any=0, any2=0, found_X_=0, i;
01219   QCString result;
01220   QCString resultUnknowns;
01221 
01222   /* find and save the non-standard parts in their original order */
01223   if( dn ){
01224     for(; dn->key; ++dn ) {
01225       for( i = 0; stdpart[i]; ++i ) {
01226         if( !strcmp( dn->key, stdpart[i] ) ) {
01227           break;
01228         }
01229       }
01230       if( !stdpart[i] ) {
01231         if( any2 )
01232           resultUnknowns.append( "," );
01233         add_dn_part( resultUnknowns, *dn );
01234         any2 = 1;
01235       }
01236     }
01237     dn = dnOrg;
01238   }
01239 
01240   /* prepend the unknown attrs if desired */
01241   if( unknownAttrsHandling &&
01242       !strcmp(unknownAttrsHandling, "PREFIX")
01243       && *resultUnknowns ){
01244     result.append( resultUnknowns );
01245     any = 1;
01246   }else{
01247     any = 0;
01248   }
01249 
01250   /* add standard parts */
01251   for( i = 0; stdpart[i]; ++i ) {
01252     dn = dnOrg;
01253     if( any ) {
01254       result.append( "," );
01255     }
01256     if( any2 &&
01257       !strcmp(stdpart[i], "_X_") &&
01258       unknownAttrsHandling &&
01259       !strcmp(unknownAttrsHandling, "INFIX") ){
01260       if ( !resultUnknowns.isEmpty() ) {
01261         result.append( resultUnknowns );
01262         any = 1;
01263       }
01264       found_X_ = 1;
01265     }else{
01266       any = add_dn_parts( result, dn, stdpart[i] );
01267     }
01268   }
01269 
01270   /* append the unknown attrs if desired */
01271   if( !unknownAttrsHandling ||
01272       !strcmp(unknownAttrsHandling, "POSTFIX") ||
01273       ( !strcmp(unknownAttrsHandling, "INFIX") && !found_X_ ) ){
01274     if( !resultUnknowns.isEmpty() ) {
01275       if( any ){
01276         result.append( "," );
01277       }
01278       result.append( resultUnknowns );
01279     }
01280   }
01281 
01282   char* cResult = (char*)xmalloc( (result.length()+1)*sizeof(char) );
01283   if( result.isEmpty() )
01284     *cResult = 0;
01285   else
01286     strcpy( cResult, result );
01287   return cResult;
01288 }
01289 
01290 struct CryptPlug::CertIterator {
01291   gpgme_ctx_t ctx;
01292   struct CertificateInfo info;
01293 };
01294 
01295 CryptPlug::CertIterator*
01296 CryptPlug::startListCertificates( const char* pattern, int remote )
01297 {
01298     gpgme_error_t err;
01299     struct CertIterator* it;
01300     const char* patterns[] = { pattern, NULL };
01301     fprintf( stderr,  "startListCertificates( \"%s\", %d )\n", pattern, remote );
01302 
01303     it = (CertIterator*)xmalloc( sizeof( struct CertIterator ) );
01304 
01305     err = gpgme_new (&(it->ctx));
01306     /*fprintf( stderr,  "2: gpgme returned %d\n", err );*/
01307     if( err ) {
01308       free( it );
01309       return NULL;
01310     }
01311 
01312     gpgme_set_protocol (it->ctx, GPGME_PROTOCOL_CMS);
01313     if( remote ) gpgme_set_keylist_mode ( it->ctx, GPGME_KEYLIST_MODE_EXTERN );
01314     else gpgme_set_keylist_mode ( it->ctx, GPGME_KEYLIST_MODE_LOCAL );
01315     err =  gpgme_op_keylist_ext_start ( it->ctx, patterns, 0, 0);
01316     memset( &(it->info), 0, sizeof( struct CertificateInfo ) );
01317     if( err ) {
01318       fprintf( stderr,  "gpgme_op_keylist_ext_start returned %d", err );
01319       endListCertificates( it );
01320       return NULL;
01321     }
01322     return it;
01323 }
01324 
01325 /* free() each string in a char*[] and the array itself */
01326 static void
01327 freeStringArray( char** c )
01328 {
01329     char** _c = c;
01330 
01331     while( c && *c ) {
01332       /*fprintf( stderr, "freeing \"%s\"\n", *c );*/
01333       free( *c );
01334       ++c;
01335     }
01336     free( _c );
01337 }
01338 
01339 /* free all malloc'ed data in a struct CertificateInfo */
01340 static void
01341 freeInfo( struct CryptPlug::CertificateInfo* info )
01342 {
01343   struct CryptPlug::DnPair* a = info->dnarray;
01344   assert( info );
01345   freeStringArray( info->userid );
01346   free( info->serial);
01347   free( info->fingerprint );
01348   free( info->issuer_org );
01349   free( info->issuer_reord );
01350   free( info->chainid );
01351   free( info->caps );
01352   while( a && a->key && a->value ) {
01353     free (a->key);
01354     free (a->value);
01355     ++a;
01356   }
01357   free (info->dnarray);
01358   memset( info, 0, sizeof( *info ) );
01359 }
01360 
01361 /* Format the fingerprint nicely. The caller should
01362    free the returned value using free() */
01363 static char* make_fingerprint( const char* fpr )
01364 {
01365   int len = strlen(fpr);
01366   int i = 0;
01367   char* result = (char*)xmalloc( (len + len/2 + 1)*sizeof(char) );
01368 
01369   for(; *fpr; ++fpr, ++i ) {
01370     if( i%3 == 2) {
01371       result[i] = ':'; ++i;
01372     }
01373     result[i] = *fpr;
01374   }
01375   result[i] = 0;
01376   return result;
01377 }
01378 
01379 // from gpgme 0.4.3:
01380 static const char *
01381 capabilities_to_string (gpgme_subkey_t subkey)
01382 {
01383   static const char *const strings[8] =
01384     {
01385       "",
01386       "c",
01387       "s",
01388       "sc",
01389       "e",
01390       "ec",
01391       "es",
01392       "esc"
01393     };
01394   return strings[(!!subkey->can_encrypt << 2)
01395                  | (!!subkey->can_sign << 1)
01396                  | (!!subkey->can_certify)];
01397 }
01398 
01399 int
01400 CryptPlug::nextCertificate( CryptPlug::CertIterator* it,
01401                             CryptPlug::CertificateInfo** result,
01402                             char** attrOrder,
01403                             const char* unknownAttrsHandling )
01404 {
01405   gpgme_error_t err;
01406   gpgme_key_t   key;
01407   int retval = GPG_ERR_NO_ERROR;
01408   assert( it );
01409   fprintf( stderr,  "nextCertificates( %p, %p )\n", it, result );
01410   err = gpgme_op_keylist_next ( it->ctx, &key);
01411   if( !err ) {
01412     int idx;
01413     const char* s = 0;
01414     unsigned long u;
01415     char* names[MAX_GPGME_IDX+1];
01416     struct DnPair *issuer_dn, *tmp_dn;
01417     retval = err;
01418     memset( names, 0, sizeof( names ) );
01419     freeInfo( &(it->info) );
01420 
01421     std::cerr << "nextCertificate..." << std::endl;
01422     if ( key ) {
01423       idx = 0;
01424       for ( gpgme_user_id_t uid = key->uids ; uid && idx < MAX_GPGME_IDX ; uid = uid->next, ++idx )
01425         names[idx] = xstrdup( uid->uid );
01426     }
01427     std::cerr << "DEBUG: " << s << ":" << names[0] << std::endl;
01428     it->info.userid = (char**)xmalloc( sizeof( char* ) * (idx+1) );
01429     memset( it->info.userid, 0, sizeof( char* ) * (idx+1) );
01430     it->info.dnarray = 0;
01431     for( idx = 0; names[idx] != 0; ++idx ) {
01432 
01433       struct DnPair* a = parse_dn( (unsigned char*)names[idx] );
01434       it->info.userid[idx] = reorder_dn( a, attrOrder, unknownAttrsHandling );
01435 
01436       if( idx == 0 ) {
01437         it->info.userid_0_org = names[idx];
01438         it->info.dnarray = a;
01439       }else{
01440         free (names[idx]);
01441         names[idx] = NULL;
01442         while( a && a->key && a->value ) {
01443           free( a->key );
01444           free( a->value );
01445           ++a;
01446         }
01447       }
01448     }
01449     it->info.userid[idx] = 0;
01450 
01451     s = key->issuer_serial;
01452     it->info.serial = s? xstrdup(s) : NULL;
01453 
01454     s = key->subkeys ? key->subkeys->fpr : 0 ;
01455     it->info.fingerprint = make_fingerprint( s );
01456 
01457     s = key->issuer_name;
01458     it->info.issuer_org = s? xstrdup(s): NULL;
01459     if( s ) {
01460       issuer_dn = tmp_dn = parse_dn( (const unsigned char*)s );
01461       /*it->info.issuer = xstrdup(s);*/
01462       it->info.issuer_reord = reorder_dn( issuer_dn, attrOrder, unknownAttrsHandling );
01463       while( tmp_dn && tmp_dn->key ) {
01464         free( tmp_dn->key );
01465         free( tmp_dn->value );
01466         ++tmp_dn;
01467       }
01468       free( issuer_dn );
01469       issuer_dn = tmp_dn = NULL;
01470     } else {
01471       it->info.issuer_reord = NULL;
01472     }
01473     s = key->chain_id;
01474     it->info.chainid = s? xstrdup(s): NULL;
01475 
01476     s = key->subkeys ? capabilities_to_string( key->subkeys ) : 0 ;
01477     it->info.caps = s? xstrdup(s) : NULL;
01478 
01479     u = key->subkeys && key->subkeys->timestamp >= 0 ? key->subkeys->timestamp : 0 ;
01480     it->info.created = u;
01481 
01482     u = key->subkeys && key->subkeys->expires >= 0 ? key->subkeys->expires : 0 ;
01483     it->info.expire = u;
01484 
01485     u = key->secret;
01486     it->info.secret = u;
01487 
01488     u = key->uids ? key->uids->invalid : 0 ;
01489     it->info.invalid = u;
01490 
01491     u = key->subkeys ? key->subkeys->expired : 0 ;
01492     it->info.expired = u;
01493 
01494     u = key->subkeys ? key->subkeys->disabled : 0 ;
01495     it->info.disabled = u;
01496 
01497     my_gpgme_key_release (key);
01498     /*return &(it->info);*/
01499     *result =  &(it->info);
01500   } else {
01501     *result = NULL;
01502   }
01503   return retval;
01504 }
01505 
01506 int
01507 CryptPlug::endListCertificates( CryptPlug::CertIterator* it )
01508 {
01509   fprintf( stderr,  "endListCertificates( %p )\n", it );
01510   assert(it);
01511   gpgme_keylist_result_t result = gpgme_op_keylist_result( it->ctx );
01512   int truncated = result && result->truncated;
01513   freeInfo( &(it->info) );
01514   gpgme_op_keylist_end(it->ctx);
01515   gpgme_release (it->ctx);
01516   free( it );
01517   return truncated;
01518 }
01519 
01520 GpgME::ImportResult CryptPlug::importCertificateFromMem( const char* data, size_t length )
01521 {
01522   using namespace GpgME;
01523 
01524   std::auto_ptr<Context> context( Context::createForProtocol( mProtocol ) );
01525   if ( !context.get() )
01526     return ImportResult();
01527 
01528   Data keydata( data, length, false );
01529   if ( keydata.isNull() )
01530     return ImportResult();
01531 
01532   return context->importKeys( keydata );
01533 }
01534 
01535 
01536 /*  == == == == == == == == == == == == == == == == == == == == == == == == ==
01537    ==                                                                      ==
01538   ==         Continuation of CryptPlug code                               ==
01539  ==                                                                      ==
01540 == == == == == == == == == == == == == == == == == == == == == == == == ==  */
01541 
01542 
01543 /*
01544   Find all certificate for a given addressee and return them in a
01545   '\1' separated list.
01546   NOTE: The certificate parameter must point to a not-yet allocated
01547         char*.  The function will allocate the memory needed and
01548         return the size in newSize.
01549   If secretOnly is true, only secret keys are returned.
01550 */
01551 bool CryptPlug::findCertificates( const char* addressee,
01552                                   char** certificates,
01553                                   int* newSize,
01554                                   bool secretOnly,
01555                                   char** attrOrder,
01556                                   const char* unknownAttrsHandling )
01557 {
01558 #define MAXCERTS 1024
01559   /* use const char declarations since all of them are needed twice */
01560   const char* delimiter = "\1";
01561   const char* openBracket = "    (";
01562   const char* closeBracket = ")";
01563 
01564   gpgme_ctx_t ctx;
01565   gpgme_error_t err;
01566   gpgme_key_t rKey;
01567   const char *s;
01568   const char *s2;
01569   char* dn;
01570   struct DnPair* a;
01571   int nFound = 0;
01572   int iFound = 0;
01573   int siz = 0;
01574   char* DNs[MAXCERTS];
01575   char* FPRs[MAXCERTS];
01576 
01577   if( ! certificates ){
01578     fprintf( stderr, "gpgme: findCertificates called with invalid *certificates pointer\n" );
01579     return false;
01580   }
01581 
01582   if( ! newSize ){
01583     fprintf( stderr, "gpgme: findCertificates called with invalid newSize pointer\n" );
01584     return false;
01585   }
01586 
01587   *certificates = 0;
01588   *newSize = 0;
01589 
01590   /* calculate length of buffer needed for certs plus fingerprints */
01591   gpgme_new (&ctx);
01592   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
01593   err = gpgme_op_keylist_start(ctx, addressee, secretOnly ? 1 : 0);
01594   while( !err ) {
01595     err = gpgme_op_keylist_next(ctx, &rKey);
01596     if( !err ) {
01597       s = rKey && rKey->uids ? rKey->uids->uid : 0 ;
01598       if( s ) {
01599         dn = xstrdup( s );
01600         s2 = rKey && rKey->subkeys ? rKey->subkeys->fpr : 0 ;
01601         if( s2 ) {
01602           if( nFound )
01603             siz += strlen( delimiter );
01604 
01605           //fprintf( stderr, "gpgme: before reordering (%s)\n", dn );
01606 
01607           a = parse_dn( (unsigned char*)dn );
01608           free( dn );
01609           dn = reorder_dn( a, attrOrder, unknownAttrsHandling );
01610 
01611           //fprintf( stderr, "gpgme: after reordering  (%s)\n\n", dn );
01612 
01613           siz += strlen( dn );
01614           siz += strlen( openBracket );
01615           siz += strlen( s2 );
01616           siz += strlen( closeBracket );
01617           DNs[ nFound ] = dn;
01618           dn = NULL; /* prevent it from being free'ed below. */
01619           FPRs[nFound ] = xstrdup( s2 );
01620           ++nFound;
01621           if( nFound >= MAXCERTS ) {
01622             fprintf( stderr,
01623                      "gpgme: findCertificates found too many certificates (%d)\n",
01624                      MAXCERTS );
01625             break;
01626           }
01627         }
01628         free (dn);
01629       }
01630     }
01631   }
01632   gpgme_op_keylist_end( ctx );
01633   gpgme_release (ctx);
01634 
01635 
01636   if( 0 < siz ) {
01637     /* add one for trailing ZERO char */
01638     ++siz;
01639     *newSize = siz;
01640     /* allocate the buffer */
01641     *certificates = (char*)xmalloc( sizeof(char) * siz );
01642     memset( *certificates, 0, sizeof(char) * siz );
01643     /* fill the buffer */
01644     for (iFound=0; iFound < nFound; iFound++) {
01645       if( !iFound )
01646         strcpy(*certificates, DNs[iFound] );
01647       else {
01648         strcat(*certificates, delimiter );
01649         strcat(*certificates, DNs[iFound] );
01650       }
01651       strcat(  *certificates, openBracket );
01652       strcat(  *certificates, FPRs[iFound] );
01653       strcat(  *certificates, closeBracket );
01654       free( DNs[ iFound ] );
01655       free( FPRs[iFound ] );
01656     }
01657   }
01658 
01659   return ( 0 < nFound );
01660 }
01661 
01662 // these are from gpgme-0.4.3:
01663 static gpgme_sig_stat_t
01664 sig_stat_from_status( gpgme_error_t err )
01665 {
01666   switch ( gpg_err_code(err) ) {
01667   case GPG_ERR_NO_ERROR:
01668     return GPGME_SIG_STAT_GOOD;
01669   case GPG_ERR_BAD_SIGNATURE:
01670     return GPGME_SIG_STAT_BAD;
01671   case GPG_ERR_NO_PUBKEY:
01672     return GPGME_SIG_STAT_NOKEY;
01673   case GPG_ERR_NO_DATA:
01674     return GPGME_SIG_STAT_NOSIG;
01675   case GPG_ERR_SIG_EXPIRED:
01676     return GPGME_SIG_STAT_GOOD_EXP;
01677   case GPG_ERR_KEY_EXPIRED:
01678     return GPGME_SIG_STAT_GOOD_EXPKEY;
01679   default:
01680     return GPGME_SIG_STAT_ERROR;
01681   }
01682 }
01683 
01684 
01685 static gpgme_sig_stat_t
01686 intersect_stati( gpgme_signature_t first )
01687 {
01688   if ( !first )
01689     return GPGME_SIG_STAT_NONE;
01690   gpgme_sig_stat_t result = sig_stat_from_status( first->status );
01691   for ( gpgme_signature_t sig = first->next ; sig ; sig = sig->next )
01692     if ( sig_stat_from_status( sig->status ) != result )
01693       return GPGME_SIG_STAT_DIFF;
01694   return result;
01695 }
01696 
01697 static const char*
01698 sig_status_to_string( gpgme_sig_stat_t status )
01699 {
01700   const char *result;
01701 
01702   switch (status) {
01703     case GPGME_SIG_STAT_NONE:
01704       result = "Oops: Signature not verified";
01705       break;
01706     case GPGME_SIG_STAT_NOSIG:
01707       result = "No signature found";
01708       break;
01709     case GPGME_SIG_STAT_GOOD:
01710       result = "Good signature";
01711       break;
01712     case GPGME_SIG_STAT_BAD:
01713       result = "BAD signature";
01714       break;
01715     case GPGME_SIG_STAT_NOKEY:
01716       result = "No public key to verify the signature";
01717       break;
01718     case GPGME_SIG_STAT_ERROR:
01719       result = "Error verifying the signature";
01720       break;
01721     case GPGME_SIG_STAT_DIFF:
01722       result = "Different results for signatures";
01723       break;
01724     default:
01725       result = "Error: Unknown status";
01726       break;
01727   }
01728 
01729   return result;
01730 }
01731 
01732 // WARNING: if you fix a bug here, you have to likely fix it in the
01733 // gpgme 0.3 version below, too!
01734 static
01735 void obtain_signature_information( gpgme_ctx_t ctx,
01736                                    gpgme_sig_stat_t & overallStatus,
01737                                    struct CryptPlug::SignatureMetaData* sigmeta,
01738                                    char** attrOrder,
01739                                    const char* unknownAttrsHandling,
01740                                    bool * signatureFound=0 )
01741 {
01742   gpgme_error_t err;
01743   unsigned long sumGPGME;
01744   SigStatusFlags sumPlug;
01745   struct CryptPlug::DnPair* a;
01746   int sig_idx=0;
01747 
01748   assert( ctx );
01749   assert( sigmeta );
01750 
01751   sigmeta->extended_info = 0;
01752   gpgme_verify_result_t result = gpgme_op_verify_result( ctx );
01753   if ( !result )
01754     return;
01755   for ( gpgme_signature_t signature = result->signatures ; signature ; signature = signature->next, ++sig_idx ) {
01756     void* alloc_return = realloc( sigmeta->extended_info,
01757                                   sizeof( CryptPlug::SignatureMetaDataExtendedInfo )
01758                                   * ( sig_idx + 1 ) );
01759     if ( !alloc_return )
01760       break;
01761     sigmeta->extended_info = (CryptPlug::SignatureMetaDataExtendedInfo*)alloc_return;
01762 
01763     /* shorthand notation :) */
01764     CryptPlug::SignatureMetaDataExtendedInfo & this_info = sigmeta->extended_info[sig_idx];
01765 
01766     /* clear the data area */
01767     memset( &this_info, 0, sizeof (CryptPlug::SignatureMetaDataExtendedInfo) );
01768 
01769     /* the creation time */
01770     if ( signature->timestamp ) {
01771       this_info.creation_time = (tm*)malloc( sizeof( struct tm ) );
01772       if ( this_info.creation_time ) {
01773         struct tm * ctime_val = localtime( (time_t*)&signature->timestamp );
01774         memcpy( this_info.creation_time,
01775                 ctime_val, sizeof( struct tm ) );
01776       }
01777     }
01778 
01779     /* the extended signature verification status */
01780     sumGPGME = signature->summary;
01781     fprintf( stderr, "gpgmeplug checkMessageSignature status flags: %lX\n", sumGPGME );
01782     /* translate GPGME status flags to common CryptPlug status flags */
01783     sumPlug = 0;
01784 #define convert(X) if ( sumGPGME & GPGME_SIGSUM_##X ) sumPlug |= SigStat_##X
01785     convert(VALID);
01786     convert(GREEN);
01787     convert(RED);
01788     convert(KEY_REVOKED);
01789     convert(KEY_EXPIRED);
01790     convert(SIG_EXPIRED);
01791     convert(KEY_MISSING);
01792     convert(CRL_MISSING);
01793     convert(CRL_TOO_OLD);
01794     convert(BAD_POLICY);
01795     convert(SYS_ERROR);
01796 #undef convert
01797     if( sumGPGME && !sumPlug )
01798       sumPlug = SigStat_NUMERICAL_CODE | sumGPGME;
01799     this_info.sigStatusFlags = sumPlug;
01800 
01801     /* extract finger print */
01802     if ( signature->fpr )
01803       storeNewCharPtr( &this_info.fingerprint, signature->fpr );
01804 
01805     /* validity */
01806     this_info.validity = GPGME_VALIDITY_UNKNOWN;
01807 
01808     /* sig key data */
01809     gpgme_key_t key = 0;
01810     // PENDING(marc) if this is deprecated, how shall we get at all
01811     // the infos below?
01812     err = gpgme_get_sig_key (ctx, sig_idx, &key);
01813 
01814     if ( !err && key ) {
01815       const char* attr_string;
01816       unsigned long attr_ulong;
01817 
01818       /* extract key identidy */
01819       attr_string = key->subkeys ? key->subkeys->keyid : 0 ;
01820       if ( attr_string )
01821     storeNewCharPtr( &this_info.keyid, attr_string );
01822 
01823       /* pubkey algorithm */
01824       attr_string = key->subkeys ? gpgme_pubkey_algo_name( key->subkeys->pubkey_algo ) : 0 ;
01825       if (attr_string != 0)
01826     storeNewCharPtr( &this_info.algo, attr_string );
01827       attr_ulong = key->subkeys ? key->subkeys->pubkey_algo : 0 ;
01828       this_info.algo_num = attr_ulong;
01829 
01830       /* extract key validity */
01831       attr_ulong = key->uids ? key->uids->validity : 0 ;
01832       this_info.validity = attr_ulong;
01833 
01834       /* extract user id, according to the documentation it's representable
01835        * as a number, but it seems that it also has a string representation
01836        */
01837       attr_string = key->uids ? key->uids->uid : 0 ;
01838       if (attr_string != 0) {
01839         a = parse_dn( (const unsigned char*)attr_string );
01840         this_info.userid = reorder_dn( a, attrOrder, unknownAttrsHandling );
01841       }
01842 
01843       attr_ulong = 0;
01844       this_info.userid_num = attr_ulong;
01845 
01846       /* extract the length */
01847       this_info.keylen = key->subkeys ? key->subkeys->length : 0 ;
01848 
01849       /* extract the creation time of the key */
01850       attr_ulong = key->subkeys ? key->subkeys->timestamp : 0 ;
01851       this_info.key_created = attr_ulong;
01852 
01853       /* extract the expiration time of the key */
01854       attr_ulong = key->subkeys ? key->subkeys->expires : 0 ;
01855       this_info.key_expires = attr_ulong;
01856 
01857       /* extract user name */
01858       attr_string = key->uids ? key->uids->name : 0 ;
01859       if (attr_string != 0) {
01860         a = parse_dn( (const unsigned char*)attr_string );
01861         this_info.name = reorder_dn( a, attrOrder, unknownAttrsHandling );
01862       }
01863 
01864       /* extract email(s) */
01865       this_info.emailCount = 0;
01866       this_info.emailList = 0;
01867       for ( gpgme_user_id_t uid = key->uids ; uid ; uid = uid->next ) {
01868         attr_string = uid->email;
01869         if ( attr_string && *attr_string) {
01870           fprintf( stderr, "gpgmeplug checkMessageSignature found email: %s\n", attr_string );
01871           if( !this_info.emailCount )
01872             alloc_return = malloc( sizeof( char*) );
01873           else
01874             alloc_return = realloc( this_info.emailList,
01875                   sizeof( char*)
01876                   * (this_info.emailCount + 1) );
01877           if( alloc_return ) {
01878             this_info.emailList = (char**)alloc_return;
01879             storeNewCharPtr( &( this_info.emailList[ this_info.emailCount ] ),
01880                 attr_string );
01881             ++this_info.emailCount;
01882           }
01883         }
01884       }
01885       if( !this_info.emailCount )
01886     fprintf( stderr, "gpgmeplug checkMessageSignature found NO EMAIL\n" );
01887 
01888       /* extract the comment */
01889       attr_string = key->uids ? key->uids->comment : 0 ;
01890       if (attr_string != 0)
01891     storeNewCharPtr( &this_info.comment, attr_string );
01892     }
01893 
01894     gpgme_sig_stat_t status = sig_stat_from_status( signature->status );
01895     const char* sig_status = sig_status_to_string( status );
01896     storeNewCharPtr( &this_info.status_text, sig_status );
01897   }
01898   sigmeta->extended_info_count = sig_idx;
01899   overallStatus = intersect_stati( result->signatures );
01900   sigmeta->status_code = overallStatus;
01901   storeNewCharPtr( &sigmeta->status, sig_status_to_string( overallStatus ) );
01902   if ( signatureFound )
01903     *signatureFound = ( overallStatus != GPGME_SIG_STAT_NONE );
01904 }
01905 
01906 
01907 bool CryptPlug::checkMessageSignature( char** cleartext,
01908                             const char* signaturetext,
01909                             bool signatureIsBinary,
01910                             int signatureLen,
01911                             struct CryptPlug::SignatureMetaData* sigmeta,
01912                             char** attrOrder,
01913                             const char* unknownAttrsHandling )
01914 {
01915   gpgme_ctx_t ctx;
01916   gpgme_sig_stat_t status = GPGME_SIG_STAT_NONE;
01917   gpgme_data_t datapart, sigpart;
01918   char* rClear = 0;
01919   size_t clearLen;
01920   bool isOpaqueSigned;
01921 
01922   if( !cleartext ) {
01923     if( sigmeta )
01924       storeNewCharPtr( &sigmeta->status,
01925                         __GPGMEPLUG_ERROR_CLEARTEXT_IS_ZERO );
01926 
01927     return false;
01928   }
01929 
01930   isOpaqueSigned = !*cleartext;
01931 
01932   gpgme_new( &ctx );
01933   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
01934   gpgme_set_armor (ctx,    signatureIsBinary ? 0 : 1);
01935   /*  gpgme_set_textmode (ctx, signatureIsBinary ? 0 : 1); */
01936 
01937   if( isOpaqueSigned )
01938     gpgme_data_new( &datapart );
01939   else
01940     gpgme_data_new_from_mem( &datapart, *cleartext,
01941                              strlen( *cleartext ), 1 );
01942 
01943   gpgme_data_new_from_mem( &sigpart,
01944                            signaturetext,
01945                            signatureIsBinary
01946                            ? signatureLen
01947                            : strlen( signaturetext ),
01948                            1 );
01949 
01950   if ( isOpaqueSigned )
01951     gpgme_op_verify( ctx, sigpart, 0, datapart );
01952   else
01953     gpgme_op_verify( ctx, sigpart, datapart, 0 );
01954 
01955   if( isOpaqueSigned ) {
01956     rClear = gpgme_data_release_and_get_mem( datapart, &clearLen );
01957     *cleartext = (char*)malloc( clearLen + 1 );
01958     if( *cleartext ) {
01959       if( clearLen )
01960         strncpy(*cleartext, rClear, clearLen );
01961       (*cleartext)[clearLen] = '\0';
01962     }
01963     free( rClear );
01964   }
01965   else
01966     gpgme_data_release( datapart );
01967 
01968   gpgme_data_release( sigpart );
01969 
01970   obtain_signature_information( ctx, status, sigmeta,
01971                                 attrOrder, unknownAttrsHandling );
01972 
01973   gpgme_release( ctx );
01974   return ( status == GPGME_SIG_STAT_GOOD );
01975 }
01976 
01977 
01978 bool CryptPlug::decryptAndCheckMessage( const char*  ciphertext,
01979                                   bool         cipherIsBinary,
01980                                   int          cipherLen,
01981                                   const char** cleartext,
01982                                   const char*  /*certificate*/,
01983                                   bool*        signatureFound,
01984                                   struct CryptPlug::SignatureMetaData* sigmeta,
01985                                   int*   errId,
01986                                   char** errTxt,
01987                                   char** attrOrder,
01988                                   const char* unknownAttrsHandling  )
01989 {
01990   gpgme_ctx_t ctx;
01991   gpgme_error_t err;
01992   gpgme_decrypt_result_t decryptresult;
01993   gpgme_data_t gCiphertext, gPlaintext;
01994   gpgme_sig_stat_t sigstatus = GPGME_SIG_STAT_NONE;
01995   size_t rCLen = 0;
01996   char*  rCiph = 0;
01997   bool bOk = false;
01998   bool bWrongKeyUsage = false;
01999 
02000   if( !ciphertext )
02001     return false;
02002 
02003   err = gpgme_new (&ctx);
02004   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
02005 
02006   gpgme_set_armor (ctx, cipherIsBinary ? 0 : 1);
02007   /*  gpgme_set_textmode (ctx, cipherIsBinary ? 0 : 1); */
02008 
02009   /*
02010   gpgme_data_new_from_mem( &gCiphertext, ciphertext,
02011                            1+strlen( ciphertext ), 1 ); */
02012   gpgme_data_new_from_mem( &gCiphertext,
02013                            ciphertext,
02014                            cipherIsBinary
02015                            ? cipherLen
02016                            : strlen( ciphertext ),
02017                            1 );
02018 
02019   gpgme_data_new( &gPlaintext );
02020 
02021   err = gpgme_op_decrypt_verify( ctx, gCiphertext, gPlaintext );
02022   gpgme_data_release( gCiphertext );
02023   
02024   decryptresult = gpgme_op_decrypt_result( ctx );
02025 #ifdef HAVE_GPGME_WRONG_KEY_USAGE
02026   if( decryptresult->wrong_key_usage )
02027     bWrongKeyUsage = true;
02028 #endif
02029   
02030   if( err ) {
02031     fprintf( stderr, "\ngpgme_op_decrypt_verify() returned this error code:  %i\n\n", err );
02032     if( errId )
02033       *errId = err;
02034     if( errTxt ) {
02035       const char* _errTxt = gpgme_strerror( err );
02036       *errTxt = (char*)malloc( strlen( _errTxt ) + 1 );
02037       if( *errTxt )
02038         strcpy(*errTxt, _errTxt );
02039     }
02040     gpgme_data_release( gPlaintext );
02041     gpgme_release( ctx );
02042     return bOk;
02043   }
02044   
02045   if( bWrongKeyUsage ) {
02046     if( errId )
02047       *errId = CRYPTPLUG_ERR_WRONG_KEY_USAGE; // report the wrong key usage
02048   }  
02049   
02050   rCiph = gpgme_data_release_and_get_mem( gPlaintext,  &rCLen );
02051 
02052   *cleartext = (char*)malloc( rCLen + 1 );
02053   if( *cleartext ) {
02054       if( rCLen ) {
02055           bOk = true;
02056           strncpy((char*)*cleartext, rCiph, rCLen );
02057       }
02058       ((char*)(*cleartext))[rCLen] = 0;
02059   }
02060   free( rCiph );
02061 
02062   obtain_signature_information( ctx, sigstatus, sigmeta,
02063                                 attrOrder, unknownAttrsHandling,
02064                                 signatureFound );
02065 
02066   gpgme_release( ctx );
02067   return bOk;
02068 }
02069 
KDE Logo
This file is part of the documentation for certmanager Library Version 3.3.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Mon Apr 4 04:45:40 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003