certmanager/lib

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�vdalens Datakonsult AB
00008   Copyright (C) 2002 g10 Code GmbH
00009   Copyright (C) 2004 Klar�vdalens 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 
00037 #include "ui/passphrasedialog.h" 
00038 #include <klocale.h> 
00039 #include <kstandarddirs.h> 
00040 
00058 #include <qstring.h>
00059 
00060 #include <string>
00061 #include <vector>
00062 #include <algorithm>
00063 #include <iostream>
00064 #include <memory>
00065 
00066 #include <stdio.h>
00067 #include <string.h>
00068 #include <strings.h>
00069 #include <assert.h>
00070 #include <errno.h>
00071 #include <time.h>
00072 #include <ctype.h>
00073 #include <locale.h>
00074 
00075 #define __GPGMEPLUG_ERROR_CLEARTEXT_IS_ZERO "Error: Cannot run checkMessageSignature() with cleartext == 0"
00076 
00077 /* Note: The following specification will result in
00078        function encryptAndSignMessage() producing
00079        _empty_ mails.
00080        This must be changed as soon as our plugin
00081        is supporting the encryptAndSignMessage() function. */
00082 #ifndef GPGMEPLUG_ENCSIGN_MAKE_MIME_OBJECT
00083 #define GPGMEPLUG_ENCSIGN_INCLUDE_CLEARTEXT false
00084 #define GPGMEPLUG_ENCSIGN_MAKE_MIME_OBJECT  false
00085 #define GPGMEPLUG_ENCSIGN_MAKE_MULTI_MIME   false
00086 #define GPGMEPLUG_ENCSIGN_CTYPE_MAIN        ""
00087 #define GPGMEPLUG_ENCSIGN_CDISP_MAIN        ""
00088 #define GPGMEPLUG_ENCSIGN_CTENC_MAIN        ""
00089 #define GPGMEPLUG_ENCSIGN_CTYPE_VERSION     ""
00090 #define GPGMEPLUG_ENCSIGN_CDISP_VERSION     ""
00091 #define GPGMEPLUG_ENCSIGN_CTENC_VERSION     ""
00092 #define GPGMEPLUG_ENCSIGN_BTEXT_VERSION     ""
00093 #define GPGMEPLUG_ENCSIGN_CTYPE_CODE        ""
00094 #define GPGMEPLUG_ENCSIGN_CDISP_CODE        ""
00095 #define GPGMEPLUG_ENCSIGN_CTENC_CODE        ""
00096 #define GPGMEPLUG_ENCSIGN_FLAT_PREFIX       ""
00097 #define GPGMEPLUG_ENCSIGN_FLAT_SEPARATOR    ""
00098 #define GPGMEPLUG_ENCSIGN_FLAT_POSTFIX      ""
00099 #endif
00100 
00101 #include "cryptplug.h"
00102 #include <kdebug.h>
00103 
00104 SMIMECryptPlug::SMIMECryptPlug() : CryptPlug() {
00105   GPGMEPLUG_PROTOCOL = GPGME_PROTOCOL_CMS;
00106   mProtocol = GpgME::Context::CMS;
00107 
00108   /* definitions for signing */
00109   // 1. opaque signatures (only used for S/MIME)
00110   GPGMEPLUG_OPA_SIGN_INCLUDE_CLEARTEXT = false;
00111   GPGMEPLUG_OPA_SIGN_MAKE_MIME_OBJECT  = true;
00112   GPGMEPLUG_OPA_SIGN_MAKE_MULTI_MIME   = false;
00113   GPGMEPLUG_OPA_SIGN_CTYPE_MAIN        = "application/pkcs7-mime; smime-type=signed-data; name=\"smime.p7m\"";
00114   GPGMEPLUG_OPA_SIGN_CDISP_MAIN        = "attachment; filename=\"smime.p7m\"";
00115   GPGMEPLUG_OPA_SIGN_CTENC_MAIN        = "base64";
00116   GPGMEPLUG_OPA_SIGN_CTYPE_VERSION     = "";
00117   GPGMEPLUG_OPA_SIGN_CDISP_VERSION     = "";
00118   GPGMEPLUG_OPA_SIGN_CTENC_VERSION     = "";
00119   GPGMEPLUG_OPA_SIGN_BTEXT_VERSION     = "";
00120   GPGMEPLUG_OPA_SIGN_CTYPE_CODE        = "";
00121   GPGMEPLUG_OPA_SIGN_CDISP_CODE        = "";
00122   GPGMEPLUG_OPA_SIGN_CTENC_CODE        = "";
00123   GPGMEPLUG_OPA_SIGN_FLAT_PREFIX       = "";
00124   GPGMEPLUG_OPA_SIGN_FLAT_SEPARATOR    = "";
00125   GPGMEPLUG_OPA_SIGN_FLAT_POSTFIX      = "";
00126   // 2. detached signatures (used for S/MIME and for OpenPGP)
00127   GPGMEPLUG_DET_SIGN_INCLUDE_CLEARTEXT = true;
00128   GPGMEPLUG_DET_SIGN_MAKE_MIME_OBJECT  = true;
00129   GPGMEPLUG_DET_SIGN_MAKE_MULTI_MIME   = true;
00130   GPGMEPLUG_DET_SIGN_CTYPE_MAIN        = "multipart/signed; protocol=\"application/pkcs7-signature\"; micalg=sha1";
00131   GPGMEPLUG_DET_SIGN_CDISP_MAIN        = "";
00132   GPGMEPLUG_DET_SIGN_CTENC_MAIN        = "";
00133   GPGMEPLUG_DET_SIGN_CTYPE_VERSION     = "";
00134   GPGMEPLUG_DET_SIGN_CDISP_VERSION     = "";
00135   GPGMEPLUG_DET_SIGN_CTENC_VERSION     = "";
00136   GPGMEPLUG_DET_SIGN_BTEXT_VERSION     = "";
00137   GPGMEPLUG_DET_SIGN_CTYPE_CODE        = "application/pkcs7-signature; name=\"smime.p7s\"";
00138   GPGMEPLUG_DET_SIGN_CDISP_CODE        = "attachment; filename=\"smime.p7s\"";
00139   GPGMEPLUG_DET_SIGN_CTENC_CODE        = "base64";
00140   GPGMEPLUG_DET_SIGN_FLAT_PREFIX       = "";
00141   GPGMEPLUG_DET_SIGN_FLAT_SEPARATOR    = "";
00142   GPGMEPLUG_DET_SIGN_FLAT_POSTFIX      = "";
00143   // 3. common definitions for opaque and detached signing
00144   __GPGMEPLUG_SIGNATURE_CODE_IS_BINARY = true;
00145 
00146   /* definitions for encoding */
00147   GPGMEPLUG_ENC_INCLUDE_CLEARTEXT  = false;
00148   GPGMEPLUG_ENC_MAKE_MIME_OBJECT   = true;
00149   GPGMEPLUG_ENC_MAKE_MULTI_MIME    = false;
00150   GPGMEPLUG_ENC_CTYPE_MAIN         = "application/pkcs7-mime; smime-type=enveloped-data; name=\"smime.p7m\"";
00151   GPGMEPLUG_ENC_CDISP_MAIN         = "attachment; filename=\"smime.p7m\"";
00152   GPGMEPLUG_ENC_CTENC_MAIN         = "base64";
00153   GPGMEPLUG_ENC_CTYPE_VERSION      = "";
00154   GPGMEPLUG_ENC_CDISP_VERSION      = "";
00155   GPGMEPLUG_ENC_CTENC_VERSION      = "";
00156   GPGMEPLUG_ENC_BTEXT_VERSION      = "";
00157   GPGMEPLUG_ENC_CTYPE_CODE         = "";
00158   GPGMEPLUG_ENC_CDISP_CODE         = "";
00159   GPGMEPLUG_ENC_CTENC_CODE         = "";
00160   GPGMEPLUG_ENC_FLAT_PREFIX        = "";
00161   GPGMEPLUG_ENC_FLAT_SEPARATOR     = "";
00162   GPGMEPLUG_ENC_FLAT_POSTFIX       = "";
00163   __GPGMEPLUG_ENCRYPTED_CODE_IS_BINARY = true;
00164 }
00165 
00166 OpenPGPCryptPlug::OpenPGPCryptPlug() : CryptPlug() {
00167   GPGMEPLUG_PROTOCOL = GPGME_PROTOCOL_OpenPGP;
00168   mProtocol = GpgME::Context::OpenPGP;
00169 
00170   /* definitions for signing */
00171   // 1. opaque signatures (only used for S/MIME)
00172   GPGMEPLUG_OPA_SIGN_INCLUDE_CLEARTEXT = false;
00173   GPGMEPLUG_OPA_SIGN_MAKE_MIME_OBJECT  = false;
00174   GPGMEPLUG_OPA_SIGN_MAKE_MULTI_MIME   = false;
00175   GPGMEPLUG_OPA_SIGN_CTYPE_MAIN        = "";
00176   GPGMEPLUG_OPA_SIGN_CDISP_MAIN        = "";
00177   GPGMEPLUG_OPA_SIGN_CTENC_MAIN        = "";
00178   GPGMEPLUG_OPA_SIGN_CTYPE_VERSION     = "";
00179   GPGMEPLUG_OPA_SIGN_CDISP_VERSION     = "";
00180   GPGMEPLUG_OPA_SIGN_CTENC_VERSION     = "";
00181   GPGMEPLUG_OPA_SIGN_BTEXT_VERSION     = "";
00182   GPGMEPLUG_OPA_SIGN_CTYPE_CODE        = "";
00183   GPGMEPLUG_OPA_SIGN_CDISP_CODE        = "";
00184   GPGMEPLUG_OPA_SIGN_CTENC_CODE        = "";
00185   GPGMEPLUG_OPA_SIGN_FLAT_PREFIX       = "";
00186   GPGMEPLUG_OPA_SIGN_FLAT_SEPARATOR    = "";
00187   GPGMEPLUG_OPA_SIGN_FLAT_POSTFIX      = "";
00188   // 2. detached signatures (used for S/MIME and for OpenPGP)
00189   GPGMEPLUG_DET_SIGN_INCLUDE_CLEARTEXT = true;
00190   GPGMEPLUG_DET_SIGN_MAKE_MIME_OBJECT  = true;
00191   GPGMEPLUG_DET_SIGN_MAKE_MULTI_MIME   = true;
00192   GPGMEPLUG_DET_SIGN_CTYPE_MAIN        = "multipart/signed; protocol=\"application/pgp-signature\"; micalg=pgp-sha1";
00193   GPGMEPLUG_DET_SIGN_CDISP_MAIN        = "";
00194   GPGMEPLUG_DET_SIGN_CTENC_MAIN        = "";
00195   GPGMEPLUG_DET_SIGN_CTYPE_VERSION     = "";
00196   GPGMEPLUG_DET_SIGN_CDISP_VERSION     = "";
00197   GPGMEPLUG_DET_SIGN_CTENC_VERSION     = "";
00198   GPGMEPLUG_DET_SIGN_BTEXT_VERSION     = "";
00199   GPGMEPLUG_DET_SIGN_CTYPE_CODE        = "application/pgp-signature";
00200   GPGMEPLUG_DET_SIGN_CDISP_CODE        = "";
00201   GPGMEPLUG_DET_SIGN_CTENC_CODE        = "";
00202   GPGMEPLUG_DET_SIGN_FLAT_PREFIX       = "";
00203   GPGMEPLUG_DET_SIGN_FLAT_SEPARATOR    = "";
00204   GPGMEPLUG_DET_SIGN_FLAT_POSTFIX      = "";
00205   // 3. common definitions for opaque and detached signing
00206   __GPGMEPLUG_SIGNATURE_CODE_IS_BINARY = false;
00207 
00208   /* definitions for encoding */
00209   GPGMEPLUG_ENC_INCLUDE_CLEARTEXT  = false;
00210   GPGMEPLUG_ENC_MAKE_MIME_OBJECT   = true;
00211   GPGMEPLUG_ENC_MAKE_MULTI_MIME    = true;
00212   GPGMEPLUG_ENC_CTYPE_MAIN         = "multipart/encrypted; protocol=\"application/pgp-encrypted\"";
00213   GPGMEPLUG_ENC_CDISP_MAIN         = "";
00214   GPGMEPLUG_ENC_CTENC_MAIN         = "";
00215   GPGMEPLUG_ENC_CTYPE_VERSION      = "application/pgp-encrypted";
00216   GPGMEPLUG_ENC_CDISP_VERSION      = "attachment";
00217   GPGMEPLUG_ENC_CTENC_VERSION      = "";
00218   GPGMEPLUG_ENC_BTEXT_VERSION      = "Version: 1";
00219   GPGMEPLUG_ENC_CTYPE_CODE         = "application/octet-stream";
00220   GPGMEPLUG_ENC_CDISP_CODE         = "inline; filename=\"msg.asc\"";
00221   GPGMEPLUG_ENC_CTENC_CODE         = "";
00222   GPGMEPLUG_ENC_FLAT_PREFIX        = "";
00223   GPGMEPLUG_ENC_FLAT_SEPARATOR     = "";
00224   GPGMEPLUG_ENC_FLAT_POSTFIX       = "";
00225   __GPGMEPLUG_ENCRYPTED_CODE_IS_BINARY = false;
00226 }
00227 
00228 #define days_from_seconds(x) ((x)/86400)
00229 
00230 /* Max number of parts in a DN */
00231 #define MAX_GPGME_IDX 20
00232 
00233 /* some macros to replace ctype ones and avoid locale problems */
00234 #define spacep(p)   (*(p) == ' ' || *(p) == '\t')
00235 #define digitp(p)   (*(p) >= '0' && *(p) <= '9')
00236 #define hexdigitp(a) (digitp (a)                     \
00237                       || (*(a) >= 'A' && *(a) <= 'F')  \
00238                       || (*(a) >= 'a' && *(a) <= 'f'))
00239 /* the atoi macros assume that the buffer has only valid digits */
00240 #define atoi_1(p)   (*(p) - '0' )
00241 #define atoi_2(p)   ((atoi_1(p) * 10) + atoi_1((p)+1))
00242 #define atoi_4(p)   ((atoi_2(p) * 100) + atoi_2((p)+2))
00243 #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
00244                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
00245 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
00246 
00247 static void *
00248 xmalloc (size_t n)
00249 {
00250   void *p = malloc (n);
00251   if (!p)
00252     {
00253       fputs ("\nfatal: out of core\n", stderr);
00254       exit (4);
00255     }
00256   return p;
00257 }
00258 
00259 /* Please: Don't call an allocation function xfoo when it may return NULL. */
00260 /* Wrong: #define xstrdup( x ) (x)?strdup(x):0 */
00261 /* Right: */
00262 static char *
00263 xstrdup (const char *string)
00264 {
00265   char *p = (char*)xmalloc (strlen (string)+1);
00266   strcpy (p, string);
00267   return p;
00268 }
00269 
00270 gpgme_error_t passphrase_cb(void *HOOK, const char *UID_HINT, 
00271                             const char *PASSPHRASE_INFO, 
00272                             int PREV_WAS_BAD, int FD) { 
00273   
00274   QString msg = PREV_WAS_BAD ? 
00275                 i18n( "You need a passphrase to unlock the secret key for user:<br/> %1 (retry)" ) : 
00276                 i18n( "You need a passphrase to unlock the secret key for user:<br/> %1" ); 
00277   msg = msg.arg( QString::fromUtf8( UID_HINT ) ) + "<br/><br/>"; 
00278   msg.prepend( "<qt>" ); 
00279   msg += i18n( "This dialog will reappear every time the passphrase is needed. For a more secure solution that also allows caching the passphrase, use gpg-agent." ) + "<br/>"; 
00280   const QString gpgAgent = KStandardDirs::findExe( "gpg-agent" ); 
00281   if ( !gpgAgent.isEmpty() ) { 
00282     msg += i18n( "gpg-agent was found in %1, but does not appear to be running." ) 
00283            .arg( gpgAgent ); 
00284   } else { 
00285     msg += i18n( "gpg-agent is part of gnupg-%1, which you can download from %2" ) 
00286            .arg( "1.9" ) 
00287            .arg( "http://www.gnupg.org/download" );  // add #gnupg2 if you can make this a real link 
00288   } 
00289   msg += "<br/>"; 
00290   msg += i18n( "For information on how to set up gpg-agent, see %1" ) 
00291          .arg( "http://kmail.kde.org/kmail-pgpmime-howto.html" ); 
00292   msg += "<br/><br/>"; 
00293   msg += i18n( "Enter passphrase:" ); 
00294   Kleo::PassphraseDialog dlg( msg, i18n("Passphrase Dialog") ); 
00295   if ( dlg.exec() != QDialog::Accepted ) { 
00296     return GPG_ERR_CANCELED; 
00297   } 
00298  
00299   if (dlg.passphrase()) { 
00300     write(FD, dlg.passphrase(), strlen(dlg.passphrase())); 
00301     write(FD, "\n", 1); 
00302     return GPG_ERR_NO_ERROR; 
00303   } 
00304   else { 
00305     return GPG_ERR_BAD_PASSPHRASE; 
00306   } 
00307 }  
00308 
00309 
00310 CryptPlug::CryptPlug() {
00311 }
00312 
00313 CryptPlug::~CryptPlug() {
00314 }
00315 
00316 bool CryptPlug::initialize() {
00317   GpgME::setDefaultLocale( LC_CTYPE, setlocale( LC_CTYPE, 0 ) );
00318   GpgME::setDefaultLocale( LC_MESSAGES, setlocale( LC_MESSAGES, 0 ) );
00319   return (gpgme_engine_check_version (GPGMEPLUG_PROTOCOL) == GPG_ERR_NO_ERROR);
00320 }
00321 
00322 
00323 bool CryptPlug::hasFeature( Feature flag )
00324 {
00325   /* our own plugins are supposed to support everything */
00326   switch ( flag ) {
00327   case Feature_SignMessages:
00328   case Feature_VerifySignatures:
00329   case Feature_EncryptMessages:
00330   case Feature_DecryptMessages:
00331   case Feature_SendCertificates:
00332   case Feature_PinEntrySettings:
00333   case Feature_StoreMessagesWithSigs:
00334   case Feature_EncryptionCRLs:
00335   case Feature_StoreMessagesEncrypted:
00336   case Feature_CheckCertificatePath:
00337     return true;
00338   case Feature_WarnSignCertificateExpiry:
00339   case Feature_WarnSignEmailNotInCertificate:
00340   case Feature_WarnEncryptCertificateExpiry:
00341   case Feature_WarnEncryptEmailNotInCertificate:
00342      return GPGMEPLUG_PROTOCOL == GPGME_PROTOCOL_CMS;
00343   /* undefined or not yet implemented: */
00344   case Feature_CRLDirectoryService:
00345   case Feature_CertificateDirectoryService:
00346   case Feature_undef:
00347   default:
00348     return false;
00349   }
00350 }
00351 
00352 
00353 static
00354 void storeNewCharPtr( char** dest, const char* src )
00355 {
00356   int sLen = strlen( src );
00357   *dest = (char*)xmalloc( sLen + 1 );
00358   strcpy( *dest, src );
00359 }
00360 
00361 bool CryptPlug::decryptMessage( const char* ciphertext,
00362                      bool        cipherIsBinary,
00363                      int         cipherLen,
00364                      const char** cleartext,
00365                 const char* /*certificate*/,
00366                      int* errId,
00367                      char** errTxt )
00368 {
00369   gpgme_ctx_t ctx;
00370   gpgme_error_t err;
00371   gpgme_data_t gCiphertext, gPlaintext;
00372   size_t rCLen = 0;
00373   char*  rCiph = 0;
00374   bool bOk = false;
00375 
00376   if( !ciphertext )
00377     return false;
00378 
00379   err = gpgme_new (&ctx);
00380   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
00381 
00382   gpgme_set_armor (ctx, cipherIsBinary ? 0 : 1);
00383   /*  gpgme_set_textmode (ctx, cipherIsBinary ? 0 : 1); */
00384 
00385   /*
00386   gpgme_data_new_from_mem( &gCiphertext, ciphertext,
00387                            1+strlen( ciphertext ), 1 ); */
00388   gpgme_data_new_from_mem( &gCiphertext,
00389                            ciphertext,
00390                            cipherIsBinary
00391                            ? cipherLen
00392                            : strlen( ciphertext ),
00393                            1 );
00394 
00395   gpgme_data_new( &gPlaintext );
00396   if (gpgme_get_protocol(ctx) == GPGME_PROTOCOL_OpenPGP) 
00397     gpgme_set_passphrase_cb(ctx, passphrase_cb, NULL); 
00398   else 
00399     gpgme_set_passphrase_cb(ctx, NULL, NULL); 
00400  
00401   err = gpgme_op_decrypt( ctx, gCiphertext, gPlaintext );
00402   if( err ) {
00403     fprintf( stderr, "\ngpgme_op_decrypt() returned this error code:  %i\n\n", err );
00404     if( errId )
00405       *errId = err;
00406     if( errTxt ) {
00407       const char* _errTxt = gpgme_strerror( err );
00408       *errTxt = (char*)malloc( strlen( _errTxt ) + 1 );
00409       if( *errTxt )
00410         strcpy(*errTxt, _errTxt );
00411     }
00412   }
00413 
00414   gpgme_data_release( gCiphertext );
00415 
00416   rCiph = gpgme_data_release_and_get_mem( gPlaintext,  &rCLen );
00417 
00418   *cleartext = (char*)malloc( rCLen + 1 );
00419   if( *cleartext ) {
00420       if( rCLen ) {
00421           bOk = true;
00422           strncpy((char*)*cleartext, rCiph, rCLen );
00423       }
00424       ((char*)(*cleartext))[rCLen] = 0;
00425   }
00426 
00427   free( rCiph );
00428   gpgme_release( ctx );
00429   return bOk;
00430 }
00431 
00432 
00433 static char *
00434 trim_trailing_spaces( char *string )
00435 {
00436     char *p, *mark;
00437 
00438     for( mark = NULL, p = string; *p; p++ ) {
00439     if( isspace( *p ) ) {
00440         if( !mark )
00441         mark = p;
00442     }
00443     else
00444         mark = NULL;
00445     }
00446     if( mark )
00447     *mark = '\0' ;
00448 
00449     return string ;
00450 }
00451 
00452 /* Parse a DN and return an array-ized one.  This is not a validating
00453    parser and it does not support any old-stylish syntax; gpgme is
00454    expected to return only rfc2253 compatible strings. */
00455 static const unsigned char *
00456 parse_dn_part (CryptPlug::DnPair *array, const unsigned char *string)
00457 {
00458   const unsigned char *s, *s1;
00459   size_t n;
00460   char *p;
00461 
00462   /* parse attributeType */
00463   for (s = string+1; *s && *s != '='; s++)
00464     ;
00465   if (!*s)
00466     return NULL; /* error */
00467   n = s - string;
00468   if (!n)
00469     return NULL; /* empty key */
00470   p = (char*)xmalloc (n+1);
00471 
00472 
00473   memcpy (p, string, n);
00474   p[n] = 0;
00475   trim_trailing_spaces ((char*)p);
00476   // map OIDs to their names:
00477   for ( unsigned int i = 0 ; i < numOidMaps ; ++i )
00478     if ( !strcasecmp ((char*)p, oidmap[i].oid) ) {
00479       free( p );
00480       p = xstrdup (oidmap[i].name);
00481       break;
00482     }
00483   array->key = p;
00484   string = s + 1;
00485 
00486   if (*string == '#')
00487     { /* hexstring */
00488       string++;
00489       for (s=string; hexdigitp (s); s++)
00490         s++;
00491       n = s - string;
00492       if (!n || (n & 1))
00493         return NULL; /* empty or odd number of digits */
00494       n /= 2;
00495       array->value = p = (char*)xmalloc (n+1);
00496 
00497 
00498       for (s1=string; n; s1 += 2, n--)
00499         *p++ = xtoi_2 (s1);
00500       *p = 0;
00501    }
00502   else
00503     { /* regular v3 quoted string */
00504       for (n=0, s=string; *s; s++)
00505         {
00506           if (*s == '\\')
00507             { /* pair */
00508               s++;
00509               if (*s == ',' || *s == '=' || *s == '+'
00510                   || *s == '<' || *s == '>' || *s == '#' || *s == ';'
00511                   || *s == '\\' || *s == '\"' || *s == ' ')
00512                 n++;
00513               else if (hexdigitp (s) && hexdigitp (s+1))
00514                 {
00515                   s++;
00516                   n++;
00517                 }
00518               else
00519                 return NULL; /* invalid escape sequence */
00520             }
00521           else if (*s == '\"')
00522             return NULL; /* invalid encoding */
00523           else if (*s == ',' || *s == '=' || *s == '+'
00524                    || *s == '<' || *s == '>' || *s == '#' || *s == ';' )
00525             break;
00526           else
00527             n++;
00528         }
00529 
00530       array->value = p = (char*)xmalloc (n+1);
00531 
00532 
00533       for (s=string; n; s++, n--)
00534         {
00535           if (*s == '\\')
00536             {
00537               s++;
00538               if (hexdigitp (s))
00539                 {
00540                   *p++ = xtoi_2 (s);
00541                   s++;
00542                 }
00543               else
00544                 *p++ = *s;
00545             }
00546           else
00547             *p++ = *s;
00548         }
00549       *p = 0;
00550     }
00551   return s;
00552 }
00553 
00554 
00555 /* Parse a DN and return an array-ized one.  This is not a validating
00556    parser and it does not support any old-stylish syntax; gpgme is
00557    expected to return only rfc2253 compatible strings. */
00558 static CryptPlug::DnPair *
00559 parse_dn (const unsigned char *string)
00560 {
00561   struct CryptPlug::DnPair *array;
00562   size_t arrayidx, arraysize;
00563 
00564   if( !string )
00565     return NULL;
00566 
00567   arraysize = 7; /* C,ST,L,O,OU,CN,email */
00568   arrayidx = 0;
00569   array = (CryptPlug::DnPair*)xmalloc ((arraysize+1) * sizeof *array);
00570 
00571 
00572   while (*string)
00573     {
00574       while (*string == ' ')
00575         string++;
00576       if (!*string)
00577         break; /* ready */
00578       if (arrayidx >= arraysize)
00579         { /* mutt lacks a real safe_realoc - so we need to copy */
00580           struct CryptPlug::DnPair *a2;
00581 
00582           arraysize += 5;
00583           a2 = (CryptPlug::DnPair*)xmalloc ((arraysize+1) * sizeof *array);
00584           for (unsigned int i=0; i < arrayidx; i++)
00585             {
00586               a2[i].key = array[i].key;
00587               a2[i].value = array[i].value;
00588             }
00589           free (array);
00590           array = a2;
00591         }
00592       array[arrayidx].key = NULL;
00593       array[arrayidx].value = NULL;
00594       string = parse_dn_part (array+arrayidx, string);
00595       arrayidx++;
00596       if (!string)
00597         goto failure;
00598       while (*string == ' ')
00599         string++;
00600       if (*string && *string != ',' && *string != ';' && *string != '+')
00601         goto failure; /* invalid delimiter */
00602       if (*string)
00603         string++;
00604     }
00605   array[arrayidx].key = NULL;
00606   array[arrayidx].value = NULL;
00607   return array;
00608 
00609  failure:
00610   for (unsigned i=0; i < arrayidx; i++)
00611     {
00612       free (array[i].key);
00613       free (array[i].value);
00614     }
00615   free (array);
00616   return NULL;
00617 }
00618 
00619 static void
00620 add_dn_part( QCString& result, struct CryptPlug::DnPair& dnPair )
00621 {
00622   /* email hack */
00623   QCString mappedPart( dnPair.key );
00624   for ( unsigned int i = 0 ; i < numOidMaps ; ++i ){
00625     if( !strcasecmp( dnPair.key, oidmap[i].oid ) ) {
00626       mappedPart = oidmap[i].name;
00627       break;
00628     }
00629   }
00630   result.append( mappedPart );
00631   result.append( "=" );
00632   result.append( dnPair.value );
00633 }
00634 
00635 static int
00636 add_dn_parts( QCString& result, struct CryptPlug::DnPair* dn, const char* part )
00637 {
00638   int any = 0;
00639 
00640   if( dn ) {
00641     for(; dn->key; ++dn ) {
00642       if( !strcmp( dn->key, part ) ) {
00643         if( any )
00644           result.append( "," );
00645         add_dn_part( result, *dn );
00646         any = 1;
00647       }
00648     }
00649   }
00650   return any;
00651 }
00652 
00653 static char*
00654 reorder_dn( struct CryptPlug::DnPair *dn,
00655             char** attrOrder = 0,
00656             const char* unknownAttrsHandling = 0 )
00657 {
00658   struct CryptPlug::DnPair *dnOrg = dn;
00659 
00660   /* note: The must parts are: CN, L, OU, O, C */
00661   const char* defaultpart[] = {
00662     "CN", "S", "SN", "GN", "T", "UID",
00663           "MAIL", "EMAIL", "MOBILE", "TEL", "FAX", "STREET",
00664     "L",  "PC", "SP", "ST",
00665     "OU",
00666     "O",
00667     "C",
00668     NULL
00669   };
00670   const char** stdpart = attrOrder ? ((const char**)attrOrder) : defaultpart;
00671   int any=0, any2=0, found_X_=0, i;
00672   QCString result;
00673   QCString resultUnknowns;
00674 
00675   /* find and save the non-standard parts in their original order */
00676   if( dn ){
00677     for(; dn->key; ++dn ) {
00678       for( i = 0; stdpart[i]; ++i ) {
00679         if( !strcmp( dn->key, stdpart[i] ) ) {
00680           break;
00681         }
00682       }
00683       if( !stdpart[i] ) {
00684         if( any2 )
00685           resultUnknowns.append( "," );
00686         add_dn_part( resultUnknowns, *dn );
00687         any2 = 1;
00688       }
00689     }
00690     dn = dnOrg;
00691   }
00692 
00693   /* prepend the unknown attrs if desired */
00694   if( unknownAttrsHandling &&
00695       !strcmp(unknownAttrsHandling, "PREFIX")
00696       && *resultUnknowns ){
00697     result.append( resultUnknowns );
00698     any = 1;
00699   }else{
00700     any = 0;
00701   }
00702 
00703   /* add standard parts */
00704   for( i = 0; stdpart[i]; ++i ) {
00705     dn = dnOrg;
00706     if( any ) {
00707       result.append( "," );
00708     }
00709     if( any2 &&
00710       !strcmp(stdpart[i], "_X_") &&
00711       unknownAttrsHandling &&
00712       !strcmp(unknownAttrsHandling, "INFIX") ){
00713       if ( !resultUnknowns.isEmpty() ) {
00714         result.append( resultUnknowns );
00715         any = 1;
00716       }
00717       found_X_ = 1;
00718     }else{
00719       any = add_dn_parts( result, dn, stdpart[i] );
00720     }
00721   }
00722 
00723   /* append the unknown attrs if desired */
00724   if( !unknownAttrsHandling ||
00725       !strcmp(unknownAttrsHandling, "POSTFIX") ||
00726       ( !strcmp(unknownAttrsHandling, "INFIX") && !found_X_ ) ){
00727     if( !resultUnknowns.isEmpty() ) {
00728       if( any ){
00729         result.append( "," );
00730       }
00731       result.append( resultUnknowns );
00732     }
00733   }
00734 
00735   char* cResult = (char*)xmalloc( (result.length()+1)*sizeof(char) );
00736   if( result.isEmpty() )
00737     *cResult = 0;
00738   else
00739     strcpy( cResult, result );
00740   return cResult;
00741 }
00742 
00743 GpgME::ImportResult CryptPlug::importCertificateFromMem( const char* data, size_t length )
00744 {
00745   using namespace GpgME;
00746 
00747   std::auto_ptr<Context> context( Context::createForProtocol( mProtocol ) );
00748   if ( !context.get() )
00749     return ImportResult();
00750 
00751   Data keydata( data, length, false );
00752   if ( keydata.isNull() )
00753     return ImportResult();
00754 
00755   return context->importKeys( keydata );
00756 }
00757 
00758 
00759 /*  == == == == == == == == == == == == == == == == == == == == == == == == ==
00760    ==                                                                      ==
00761   ==         Continuation of CryptPlug code                               ==
00762  ==                                                                      ==
00763 == == == == == == == == == == == == == == == == == == == == == == == == ==  */
00764 
00765 // these are from gpgme-0.4.3:
00766 static gpgme_sig_stat_t
00767 sig_stat_from_status( gpgme_error_t err )
00768 {
00769   switch ( gpg_err_code(err) ) {
00770   case GPG_ERR_NO_ERROR:
00771     return GPGME_SIG_STAT_GOOD;
00772   case GPG_ERR_BAD_SIGNATURE:
00773     return GPGME_SIG_STAT_BAD;
00774   case GPG_ERR_NO_PUBKEY:
00775     return GPGME_SIG_STAT_NOKEY;
00776   case GPG_ERR_NO_DATA:
00777     return GPGME_SIG_STAT_NOSIG;
00778   case GPG_ERR_SIG_EXPIRED:
00779     return GPGME_SIG_STAT_GOOD_EXP;
00780   case GPG_ERR_KEY_EXPIRED:
00781     return GPGME_SIG_STAT_GOOD_EXPKEY;
00782   default:
00783     return GPGME_SIG_STAT_ERROR;
00784   }
00785 }
00786 
00787 
00788 static gpgme_sig_stat_t
00789 intersect_stati( gpgme_signature_t first )
00790 {
00791   if ( !first )
00792     return GPGME_SIG_STAT_NONE;
00793   gpgme_sig_stat_t result = sig_stat_from_status( first->status );
00794   for ( gpgme_signature_t sig = first->next ; sig ; sig = sig->next )
00795     if ( sig_stat_from_status( sig->status ) != result )
00796       return GPGME_SIG_STAT_DIFF;
00797   return result;
00798 }
00799 
00800 static const char*
00801 sig_status_to_string( gpgme_sig_stat_t status )
00802 {
00803   const char *result;
00804 
00805   switch (status) {
00806     case GPGME_SIG_STAT_NONE:
00807       result = "Oops: Signature not verified";
00808       break;
00809     case GPGME_SIG_STAT_NOSIG:
00810       result = "No signature found";
00811       break;
00812     case GPGME_SIG_STAT_GOOD:
00813       result = "Good signature";
00814       break;
00815     case GPGME_SIG_STAT_BAD:
00816       result = "BAD signature";
00817       break;
00818     case GPGME_SIG_STAT_NOKEY:
00819       result = "No public key to verify the signature";
00820       break;
00821     case GPGME_SIG_STAT_ERROR:
00822       result = "Error verifying the signature";
00823       break;
00824     case GPGME_SIG_STAT_DIFF:
00825       result = "Different results for signatures";
00826       break;
00827     default:
00828       result = "Error: Unknown status";
00829       break;
00830   }
00831 
00832   return result;
00833 }
00834 
00835 // WARNING: if you fix a bug here, you have to likely fix it in the
00836 // gpgme 0.3 version below, too!
00837 static
00838 void obtain_signature_information( gpgme_ctx_t ctx,
00839                                    gpgme_sig_stat_t & overallStatus,
00840                                    struct CryptPlug::SignatureMetaData* sigmeta,
00841                                    char** attrOrder,
00842                                    const char* unknownAttrsHandling,
00843                                    bool * signatureFound=0 )
00844 {
00845   gpgme_error_t err;
00846   unsigned long sumGPGME;
00847   SigStatusFlags sumPlug;
00848   struct CryptPlug::DnPair* a;
00849   int sig_idx=0;
00850 
00851   assert( ctx );
00852   assert( sigmeta );
00853 
00854   sigmeta->extended_info = 0;
00855   gpgme_verify_result_t result = gpgme_op_verify_result( ctx );
00856   if ( !result )
00857     return;
00858   for ( gpgme_signature_t signature = result->signatures ; signature ; signature = signature->next, ++sig_idx ) {
00859     void* alloc_return = realloc( sigmeta->extended_info,
00860                                   sizeof( CryptPlug::SignatureMetaDataExtendedInfo )
00861                                   * ( sig_idx + 1 ) );
00862     if ( !alloc_return )
00863       break;
00864     sigmeta->extended_info = (CryptPlug::SignatureMetaDataExtendedInfo*)alloc_return;
00865 
00866     /* shorthand notation :) */
00867     CryptPlug::SignatureMetaDataExtendedInfo & this_info = sigmeta->extended_info[sig_idx];
00868 
00869     /* clear the data area */
00870     memset( &this_info, 0, sizeof (CryptPlug::SignatureMetaDataExtendedInfo) );
00871 
00872     /* the creation time */
00873     if ( signature->timestamp ) {
00874       this_info.creation_time = (tm*)malloc( sizeof( struct tm ) );
00875       if ( this_info.creation_time ) {
00876         struct tm * ctime_val = localtime( (time_t*)&signature->timestamp );
00877         memcpy( this_info.creation_time,
00878                 ctime_val, sizeof( struct tm ) );
00879       }
00880     }
00881 
00882     /* the extended signature verification status */
00883     sumGPGME = signature->summary;
00884     fprintf( stderr, "gpgmeplug checkMessageSignature status flags: %lX\n", sumGPGME );
00885     /* translate GPGME status flags to common CryptPlug status flags */
00886     sumPlug = 0;
00887 #define convert(X) if ( sumGPGME & GPGME_SIGSUM_##X ) sumPlug |= SigStat_##X
00888     convert(VALID);
00889     convert(GREEN);
00890     convert(RED);
00891     convert(KEY_REVOKED);
00892     convert(KEY_EXPIRED);
00893     convert(SIG_EXPIRED);
00894     convert(KEY_MISSING);
00895     convert(CRL_MISSING);
00896     convert(CRL_TOO_OLD);
00897     convert(BAD_POLICY);
00898     convert(SYS_ERROR);
00899 #undef convert
00900     if( sumGPGME && !sumPlug )
00901       sumPlug = SigStat_NUMERICAL_CODE | sumGPGME;
00902     this_info.sigStatusFlags = sumPlug;
00903 
00904     /* extract finger print */
00905     if ( signature->fpr )
00906       storeNewCharPtr( &this_info.fingerprint, signature->fpr );
00907 
00908     /* validity */
00909     this_info.validity = GPGME_VALIDITY_UNKNOWN;
00910 
00911     /* sig key data */
00912     gpgme_key_t key = 0;
00913     // PENDING(marc) if this is deprecated, how shall we get at all
00914     // the infos below?
00915     err = gpgme_get_sig_key (ctx, sig_idx, &key);
00916 
00917     if ( !err && key ) {
00918       const char* attr_string;
00919       unsigned long attr_ulong;
00920 
00921       /* extract key identidy */
00922       attr_string = key->subkeys ? key->subkeys->keyid : 0 ;
00923       if ( attr_string )
00924     storeNewCharPtr( &this_info.keyid, attr_string );
00925 
00926       /* pubkey algorithm */
00927       attr_string = key->subkeys ? gpgme_pubkey_algo_name( key->subkeys->pubkey_algo ) : 0 ;
00928       if (attr_string != 0)
00929     storeNewCharPtr( &this_info.algo, attr_string );
00930       attr_ulong = key->subkeys ? key->subkeys->pubkey_algo : 0 ;
00931       this_info.algo_num = attr_ulong;
00932 
00933       /* extract key validity */
00934       attr_ulong = key->uids ? key->uids->validity : 0 ;
00935       this_info.validity = attr_ulong;
00936 
00937       /* extract user id, according to the documentation it's representable
00938        * as a number, but it seems that it also has a string representation
00939        */
00940       attr_string = key->uids ? key->uids->uid : 0 ;
00941       if (attr_string != 0) {
00942         a = parse_dn( (const unsigned char*)attr_string );
00943         this_info.userid = reorder_dn( a, attrOrder, unknownAttrsHandling );
00944       }
00945 
00946       attr_ulong = 0;
00947       this_info.userid_num = attr_ulong;
00948 
00949       /* extract the length */
00950       this_info.keylen = key->subkeys ? key->subkeys->length : 0 ;
00951 
00952       /* extract the creation time of the key */
00953       attr_ulong = key->subkeys ? key->subkeys->timestamp : 0 ;
00954       this_info.key_created = attr_ulong;
00955 
00956       /* extract the expiration time of the key */
00957       attr_ulong = key->subkeys ? key->subkeys->expires : 0 ;
00958       this_info.key_expires = attr_ulong;
00959 
00960       /* extract user name */
00961       attr_string = key->uids ? key->uids->name : 0 ;
00962       if (attr_string != 0) {
00963         a = parse_dn( (const unsigned char*)attr_string );
00964         this_info.name = reorder_dn( a, attrOrder, unknownAttrsHandling );
00965       }
00966 
00967       /* extract email(s) */
00968       this_info.emailCount = 0;
00969       this_info.emailList = 0;
00970       for ( gpgme_user_id_t uid = key->uids ; uid ; uid = uid->next ) {
00971         attr_string = uid->email;
00972         if ( attr_string && *attr_string) {
00973           fprintf( stderr, "gpgmeplug checkMessageSignature found email: %s\n", attr_string );
00974           if( !this_info.emailCount )
00975             alloc_return = malloc( sizeof( char*) );
00976           else
00977             alloc_return = realloc( this_info.emailList,
00978                   sizeof( char*)
00979                   * (this_info.emailCount + 1) );
00980           if( alloc_return ) {
00981             this_info.emailList = (char**)alloc_return;
00982             storeNewCharPtr( &( this_info.emailList[ this_info.emailCount ] ),
00983                 attr_string );
00984             ++this_info.emailCount;
00985           }
00986         }
00987       }
00988       if( !this_info.emailCount )
00989     fprintf( stderr, "gpgmeplug checkMessageSignature found NO EMAIL\n" );
00990 
00991       /* extract the comment */
00992       attr_string = key->uids ? key->uids->comment : 0 ;
00993       if (attr_string != 0)
00994     storeNewCharPtr( &this_info.comment, attr_string );
00995     }
00996 
00997     gpgme_sig_stat_t status = sig_stat_from_status( signature->status );
00998     const char* sig_status = sig_status_to_string( status );
00999     storeNewCharPtr( &this_info.status_text, sig_status );
01000   }
01001   sigmeta->extended_info_count = sig_idx;
01002   overallStatus = intersect_stati( result->signatures );
01003   sigmeta->status_code = overallStatus;
01004   storeNewCharPtr( &sigmeta->status, sig_status_to_string( overallStatus ) );
01005   if ( signatureFound )
01006     *signatureFound = ( overallStatus != GPGME_SIG_STAT_NONE );
01007 }
01008 
01009 bool CryptPlug::checkMessageSignature( char** cleartext,
01010                             const char* signaturetext,
01011                             bool signatureIsBinary,
01012                             int signatureLen,
01013                             struct CryptPlug::SignatureMetaData* sigmeta,
01014                             char** attrOrder,
01015                             const char* unknownAttrsHandling )
01016 {
01017   gpgme_ctx_t ctx;
01018   gpgme_sig_stat_t status = GPGME_SIG_STAT_NONE;
01019   gpgme_data_t datapart, sigpart;
01020   char* rClear = 0;
01021   size_t clearLen;
01022   bool isOpaqueSigned;
01023 
01024   if( !cleartext ) {
01025     if( sigmeta )
01026       storeNewCharPtr( &sigmeta->status,
01027                         __GPGMEPLUG_ERROR_CLEARTEXT_IS_ZERO );
01028 
01029     return false;
01030   }
01031 
01032   isOpaqueSigned = !*cleartext;
01033 
01034   gpgme_new( &ctx );
01035   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
01036   gpgme_set_armor (ctx,    signatureIsBinary ? 0 : 1);
01037   /*  gpgme_set_textmode (ctx, signatureIsBinary ? 0 : 1); */
01038 
01039   if( isOpaqueSigned )
01040     gpgme_data_new( &datapart );
01041   else
01042     gpgme_data_new_from_mem( &datapart, *cleartext,
01043                              strlen( *cleartext ), 1 );
01044 
01045   gpgme_data_new_from_mem( &sigpart,
01046                            signaturetext,
01047                            signatureIsBinary
01048                            ? signatureLen
01049                            : strlen( signaturetext ),
01050                            1 );
01051 
01052   if ( isOpaqueSigned )
01053     gpgme_op_verify( ctx, sigpart, 0, datapart );
01054   else
01055     gpgme_op_verify( ctx, sigpart, datapart, 0 );
01056 
01057   if( isOpaqueSigned ) {
01058     rClear = gpgme_data_release_and_get_mem( datapart, &clearLen );
01059     *cleartext = (char*)malloc( clearLen + 1 );
01060     if( *cleartext ) {
01061       if( clearLen )
01062         strncpy(*cleartext, rClear, clearLen );
01063       (*cleartext)[clearLen] = '\0';
01064     }
01065     free( rClear );
01066   }
01067   else
01068     gpgme_data_release( datapart );
01069 
01070   gpgme_data_release( sigpart );
01071 
01072   obtain_signature_information( ctx, status, sigmeta,
01073                                 attrOrder, unknownAttrsHandling );
01074 
01075   gpgme_release( ctx );
01076   return ( status == GPGME_SIG_STAT_GOOD );
01077 }
01078 
01079 bool CryptPlug::decryptAndCheckMessage( const char*  ciphertext,
01080                                   bool         cipherIsBinary,
01081                                   int          cipherLen,
01082                                   const char** cleartext,
01083                                   const char*  /*certificate*/,
01084                                   bool*        signatureFound,
01085                                   struct CryptPlug::SignatureMetaData* sigmeta,
01086                                   int*   errId,
01087                                   char** errTxt,
01088                                   char** attrOrder,
01089                                   const char* unknownAttrsHandling  )
01090 {
01091   gpgme_ctx_t ctx;
01092   gpgme_error_t err;
01093   gpgme_decrypt_result_t decryptresult;
01094   gpgme_data_t gCiphertext, gPlaintext;
01095   gpgme_sig_stat_t sigstatus = GPGME_SIG_STAT_NONE;
01096   size_t rCLen = 0;
01097   char*  rCiph = 0;
01098   bool bOk = false;
01099 
01100   if( !ciphertext )
01101     return false;
01102 
01103   err = gpgme_new (&ctx);
01104   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
01105 
01106   gpgme_set_armor (ctx, cipherIsBinary ? 0 : 1);
01107   /*  gpgme_set_textmode (ctx, cipherIsBinary ? 0 : 1); */
01108 
01109   /*
01110   gpgme_data_new_from_mem( &gCiphertext, ciphertext,
01111                            1+strlen( ciphertext ), 1 ); */
01112   gpgme_data_new_from_mem( &gCiphertext,
01113                            ciphertext,
01114                            cipherIsBinary
01115                            ? cipherLen
01116                            : strlen( ciphertext ),
01117                            1 );
01118 
01119   gpgme_data_new( &gPlaintext );
01120 
01121   if (gpgme_get_protocol(ctx) == GPGME_PROTOCOL_OpenPGP) 
01122     gpgme_set_passphrase_cb(ctx, passphrase_cb, NULL); 
01123   else 
01124     gpgme_set_passphrase_cb(ctx, NULL, NULL); 
01125  
01126 
01127   err = gpgme_op_decrypt_verify( ctx, gCiphertext, gPlaintext );
01128   gpgme_data_release( gCiphertext );
01129 
01130   if( err ) {
01131     fprintf( stderr, "\ngpgme_op_decrypt_verify() returned this error code:  %i\n\n", err );
01132     if( errId )
01133       *errId = err;
01134     if( errTxt ) {
01135       const char* _errTxt = gpgme_strerror( err );
01136       *errTxt = (char*)malloc( strlen( _errTxt ) + 1 );
01137       if( *errTxt )
01138         strcpy(*errTxt, _errTxt );
01139     }
01140     gpgme_data_release( gPlaintext );
01141     gpgme_release( ctx );
01142     return bOk;
01143   }
01144   decryptresult = gpgme_op_decrypt_result( ctx );
01145 
01146   bool bWrongKeyUsage = false;
01147 #ifdef HAVE_GPGME_WRONG_KEY_USAGE
01148   if( decryptresult && decryptresult->wrong_key_usage )
01149     bWrongKeyUsage = true;
01150 #endif
01151 
01152   if( bWrongKeyUsage ) {
01153     if( errId )
01154       *errId = CRYPTPLUG_ERR_WRONG_KEY_USAGE; // report the wrong key usage
01155   }
01156 
01157   rCiph = gpgme_data_release_and_get_mem( gPlaintext,  &rCLen );
01158 
01159   *cleartext = (char*)malloc( rCLen + 1 );
01160   if( *cleartext ) {
01161       if( rCLen ) {
01162           bOk = true;
01163           strncpy((char*)*cleartext, rCiph, rCLen );
01164       }
01165       ((char*)(*cleartext))[rCLen] = 0;
01166   }
01167   free( rCiph );
01168 
01169   obtain_signature_information( ctx, sigstatus, sigmeta,
01170                                 attrOrder, unknownAttrsHandling,
01171                                 signatureFound );
01172 
01173   gpgme_release( ctx );
01174   return bOk;
01175 }
01176 
KDE Home | KDE Accessibility Home | Description of Access Keys