• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdepim
  • Sitemap
  • Contact Us
 

libkleo

cryptplug.cpp

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

libkleo

Skip menu "libkleo"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members