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ä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., 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 
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 CryptPlug::CryptPlug() {
00268 }
00269 
00270 CryptPlug::~CryptPlug() {
00271 }
00272 
00273 bool CryptPlug::initialize() {
00274   GpgME::setDefaultLocale( LC_CTYPE, setlocale( LC_CTYPE, 0 ) );
00275   GpgME::setDefaultLocale( LC_MESSAGES, setlocale( LC_MESSAGES, 0 ) );
00276   return (gpgme_engine_check_version (GPGMEPLUG_PROTOCOL) == GPG_ERR_NO_ERROR);
00277 }
00278 
00279 
00280 bool CryptPlug::hasFeature( Feature flag )
00281 {
00282   /* our own plugins are supposed to support everything */
00283   switch ( flag ) {
00284   case Feature_SignMessages:
00285   case Feature_VerifySignatures:
00286   case Feature_EncryptMessages:
00287   case Feature_DecryptMessages:
00288   case Feature_SendCertificates:
00289   case Feature_PinEntrySettings:
00290   case Feature_StoreMessagesWithSigs:
00291   case Feature_EncryptionCRLs:
00292   case Feature_StoreMessagesEncrypted:
00293   case Feature_CheckCertificatePath:
00294     return true;
00295   case Feature_WarnSignCertificateExpiry:
00296   case Feature_WarnSignEmailNotInCertificate:
00297   case Feature_WarnEncryptCertificateExpiry:
00298   case Feature_WarnEncryptEmailNotInCertificate:
00299      return GPGMEPLUG_PROTOCOL == GPGME_PROTOCOL_CMS;
00300   /* undefined or not yet implemented: */
00301   case Feature_CRLDirectoryService:
00302   case Feature_CertificateDirectoryService:
00303   case Feature_undef:
00304   default:
00305     return false;
00306   }
00307 }
00308 
00309 
00310 static
00311 void storeNewCharPtr( char** dest, const char* src )
00312 {
00313   int sLen = strlen( src );
00314   *dest = (char*)xmalloc( sLen + 1 );
00315   strcpy( *dest, src );
00316 }
00317 
00318 bool CryptPlug::decryptMessage( const char* ciphertext,
00319                      bool        cipherIsBinary,
00320                      int         cipherLen,
00321                      const char** cleartext,
00322                 const char* /*certificate*/,
00323                      int* errId,
00324                      char** errTxt )
00325 {
00326   gpgme_ctx_t ctx;
00327   gpgme_error_t err;
00328   gpgme_data_t gCiphertext, gPlaintext;
00329   size_t rCLen = 0;
00330   char*  rCiph = 0;
00331   bool bOk = false;
00332 
00333   if( !ciphertext )
00334     return false;
00335 
00336   err = gpgme_new (&ctx);
00337   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
00338 
00339   gpgme_set_armor (ctx, cipherIsBinary ? 0 : 1);
00340   /*  gpgme_set_textmode (ctx, cipherIsBinary ? 0 : 1); */
00341 
00342   /*
00343   gpgme_data_new_from_mem( &gCiphertext, ciphertext,
00344                            1+strlen( ciphertext ), 1 ); */
00345   gpgme_data_new_from_mem( &gCiphertext,
00346                            ciphertext,
00347                            cipherIsBinary
00348                            ? cipherLen
00349                            : strlen( ciphertext ),
00350                            1 );
00351 
00352   gpgme_data_new( &gPlaintext );
00353 
00354   err = gpgme_op_decrypt( ctx, gCiphertext, gPlaintext );
00355   if( err ) {
00356     fprintf( stderr, "\ngpgme_op_decrypt() returned this error code:  %i\n\n", err );
00357     if( errId )
00358       *errId = err;
00359     if( errTxt ) {
00360       const char* _errTxt = gpgme_strerror( err );
00361       *errTxt = (char*)malloc( strlen( _errTxt ) + 1 );
00362       if( *errTxt )
00363         strcpy(*errTxt, _errTxt );
00364     }
00365   }
00366 
00367   gpgme_data_release( gCiphertext );
00368 
00369   rCiph = gpgme_data_release_and_get_mem( gPlaintext,  &rCLen );
00370 
00371   *cleartext = (char*)malloc( rCLen + 1 );
00372   if( *cleartext ) {
00373       if( rCLen ) {
00374           bOk = true;
00375           strncpy((char*)*cleartext, rCiph, rCLen );
00376       }
00377       ((char*)(*cleartext))[rCLen] = 0;
00378   }
00379 
00380   free( rCiph );
00381   gpgme_release( ctx );
00382   return bOk;
00383 }
00384 
00385 
00386 static char *
00387 trim_trailing_spaces( char *string )
00388 {
00389     char *p, *mark;
00390 
00391     for( mark = NULL, p = string; *p; p++ ) {
00392     if( isspace( *p ) ) {
00393         if( !mark )
00394         mark = p;
00395     }
00396     else
00397         mark = NULL;
00398     }
00399     if( mark )
00400     *mark = '\0' ;
00401 
00402     return string ;
00403 }
00404 
00405 /* Parse a DN and return an array-ized one.  This is not a validating
00406    parser and it does not support any old-stylish syntax; gpgme is
00407    expected to return only rfc2253 compatible strings. */
00408 static const unsigned char *
00409 parse_dn_part (CryptPlug::DnPair *array, const unsigned char *string)
00410 {
00411   const unsigned char *s, *s1;
00412   size_t n;
00413   char *p;
00414 
00415   /* parse attributeType */
00416   for (s = string+1; *s && *s != '='; s++)
00417     ;
00418   if (!*s)
00419     return NULL; /* error */
00420   n = s - string;
00421   if (!n)
00422     return NULL; /* empty key */
00423   p = (char*)xmalloc (n+1);
00424 
00425 
00426   memcpy (p, string, n);
00427   p[n] = 0;
00428   trim_trailing_spaces ((char*)p);
00429   // map OIDs to their names:
00430   for ( unsigned int i = 0 ; i < numOidMaps ; ++i )
00431     if ( !strcasecmp ((char*)p, oidmap[i].oid) ) {
00432       free( p );
00433       p = xstrdup (oidmap[i].name);
00434       break;
00435     }
00436   array->key = p;
00437   string = s + 1;
00438 
00439   if (*string == '#')
00440     { /* hexstring */
00441       string++;
00442       for (s=string; hexdigitp (s); s++)
00443         s++;
00444       n = s - string;
00445       if (!n || (n & 1))
00446         return NULL; /* empty or odd number of digits */
00447       n /= 2;
00448       array->value = p = (char*)xmalloc (n+1);
00449 
00450 
00451       for (s1=string; n; s1 += 2, n--)
00452         *p++ = xtoi_2 (s1);
00453       *p = 0;
00454    }
00455   else
00456     { /* regular v3 quoted string */
00457       for (n=0, s=string; *s; s++)
00458         {
00459           if (*s == '\\')
00460             { /* pair */
00461               s++;
00462               if (*s == ',' || *s == '=' || *s == '+'
00463                   || *s == '<' || *s == '>' || *s == '#' || *s == ';'
00464                   || *s == '\\' || *s == '\"' || *s == ' ')
00465                 n++;
00466               else if (hexdigitp (s) && hexdigitp (s+1))
00467                 {
00468                   s++;
00469                   n++;
00470                 }
00471               else
00472                 return NULL; /* invalid escape sequence */
00473             }
00474           else if (*s == '\"')
00475             return NULL; /* invalid encoding */
00476           else if (*s == ',' || *s == '=' || *s == '+'
00477                    || *s == '<' || *s == '>' || *s == '#' || *s == ';' )
00478             break;
00479           else
00480             n++;
00481         }
00482 
00483       array->value = p = (char*)xmalloc (n+1);
00484 
00485 
00486       for (s=string; n; s++, n--)
00487         {
00488           if (*s == '\\')
00489             {
00490               s++;
00491               if (hexdigitp (s))
00492                 {
00493                   *p++ = xtoi_2 (s);
00494                   s++;
00495                 }
00496               else
00497                 *p++ = *s;
00498             }
00499           else
00500             *p++ = *s;
00501         }
00502       *p = 0;
00503     }
00504   return s;
00505 }
00506 
00507 
00508 /* Parse a DN and return an array-ized one.  This is not a validating
00509    parser and it does not support any old-stylish syntax; gpgme is
00510    expected to return only rfc2253 compatible strings. */
00511 static CryptPlug::DnPair *
00512 parse_dn (const unsigned char *string)
00513 {
00514   struct CryptPlug::DnPair *array;
00515   size_t arrayidx, arraysize;
00516 
00517   if( !string )
00518     return NULL;
00519 
00520   arraysize = 7; /* C,ST,L,O,OU,CN,email */
00521   arrayidx = 0;
00522   array = (CryptPlug::DnPair*)xmalloc ((arraysize+1) * sizeof *array);
00523 
00524 
00525   while (*string)
00526     {
00527       while (*string == ' ')
00528         string++;
00529       if (!*string)
00530         break; /* ready */
00531       if (arrayidx >= arraysize)
00532         { /* mutt lacks a real safe_realoc - so we need to copy */
00533           struct CryptPlug::DnPair *a2;
00534 
00535           arraysize += 5;
00536           a2 = (CryptPlug::DnPair*)xmalloc ((arraysize+1) * sizeof *array);
00537           for (unsigned int i=0; i < arrayidx; i++)
00538             {
00539               a2[i].key = array[i].key;
00540               a2[i].value = array[i].value;
00541             }
00542           free (array);
00543           array = a2;
00544         }
00545       array[arrayidx].key = NULL;
00546       array[arrayidx].value = NULL;
00547       string = parse_dn_part (array+arrayidx, string);
00548       arrayidx++;
00549       if (!string)
00550         goto failure;
00551       while (*string == ' ')
00552         string++;
00553       if (*string && *string != ',' && *string != ';' && *string != '+')
00554         goto failure; /* invalid delimiter */
00555       if (*string)
00556         string++;
00557     }
00558   array[arrayidx].key = NULL;
00559   array[arrayidx].value = NULL;
00560   return array;
00561 
00562  failure:
00563   for (unsigned i=0; i < arrayidx; i++)
00564     {
00565       free (array[i].key);
00566       free (array[i].value);
00567     }
00568   free (array);
00569   return NULL;
00570 }
00571 
00572 static void
00573 add_dn_part( QCString& result, struct CryptPlug::DnPair& dnPair )
00574 {
00575   /* email hack */
00576   QCString mappedPart( dnPair.key );
00577   for ( unsigned int i = 0 ; i < numOidMaps ; ++i ){
00578     if( !strcasecmp( dnPair.key, oidmap[i].oid ) ) {
00579       mappedPart = oidmap[i].name;
00580       break;
00581     }
00582   }
00583   result.append( mappedPart );
00584   result.append( "=" );
00585   result.append( dnPair.value );
00586 }
00587 
00588 static int
00589 add_dn_parts( QCString& result, struct CryptPlug::DnPair* dn, const char* part )
00590 {
00591   int any = 0;
00592 
00593   if( dn ) {
00594     for(; dn->key; ++dn ) {
00595       if( !strcmp( dn->key, part ) ) {
00596         if( any )
00597           result.append( "," );
00598         add_dn_part( result, *dn );
00599         any = 1;
00600       }
00601     }
00602   }
00603   return any;
00604 }
00605 
00606 static char*
00607 reorder_dn( struct CryptPlug::DnPair *dn,
00608             char** attrOrder = 0,
00609             const char* unknownAttrsHandling = 0 )
00610 {
00611   struct CryptPlug::DnPair *dnOrg = dn;
00612 
00613   /* note: The must parts are: CN, L, OU, O, C */
00614   const char* defaultpart[] = {
00615     "CN", "S", "SN", "GN", "T", "UID",
00616           "MAIL", "EMAIL", "MOBILE", "TEL", "FAX", "STREET",
00617     "L",  "PC", "SP", "ST",
00618     "OU",
00619     "O",
00620     "C",
00621     NULL
00622   };
00623   const char** stdpart = attrOrder ? ((const char**)attrOrder) : defaultpart;
00624   int any=0, any2=0, found_X_=0, i;
00625   QCString result;
00626   QCString resultUnknowns;
00627 
00628   /* find and save the non-standard parts in their original order */
00629   if( dn ){
00630     for(; dn->key; ++dn ) {
00631       for( i = 0; stdpart[i]; ++i ) {
00632         if( !strcmp( dn->key, stdpart[i] ) ) {
00633           break;
00634         }
00635       }
00636       if( !stdpart[i] ) {
00637         if( any2 )
00638           resultUnknowns.append( "," );
00639         add_dn_part( resultUnknowns, *dn );
00640         any2 = 1;
00641       }
00642     }
00643     dn = dnOrg;
00644   }
00645 
00646   /* prepend the unknown attrs if desired */
00647   if( unknownAttrsHandling &&
00648       !strcmp(unknownAttrsHandling, "PREFIX")
00649       && *resultUnknowns ){
00650     result.append( resultUnknowns );
00651     any = 1;
00652   }else{
00653     any = 0;
00654   }
00655 
00656   /* add standard parts */
00657   for( i = 0; stdpart[i]; ++i ) {
00658     dn = dnOrg;
00659     if( any ) {
00660       result.append( "," );
00661     }
00662     if( any2 &&
00663       !strcmp(stdpart[i], "_X_") &&
00664       unknownAttrsHandling &&
00665       !strcmp(unknownAttrsHandling, "INFIX") ){
00666       if ( !resultUnknowns.isEmpty() ) {
00667         result.append( resultUnknowns );
00668         any = 1;
00669       }
00670       found_X_ = 1;
00671     }else{
00672       any = add_dn_parts( result, dn, stdpart[i] );
00673     }
00674   }
00675 
00676   /* append the unknown attrs if desired */
00677   if( !unknownAttrsHandling ||
00678       !strcmp(unknownAttrsHandling, "POSTFIX") ||
00679       ( !strcmp(unknownAttrsHandling, "INFIX") && !found_X_ ) ){
00680     if( !resultUnknowns.isEmpty() ) {
00681       if( any ){
00682         result.append( "," );
00683       }
00684       result.append( resultUnknowns );
00685     }
00686   }
00687 
00688   char* cResult = (char*)xmalloc( (result.length()+1)*sizeof(char) );
00689   if( result.isEmpty() )
00690     *cResult = 0;
00691   else
00692     strcpy( cResult, result );
00693   return cResult;
00694 }
00695 
00696 GpgME::ImportResult CryptPlug::importCertificateFromMem( const char* data, size_t length )
00697 {
00698   using namespace GpgME;
00699 
00700   std::auto_ptr<Context> context( Context::createForProtocol( mProtocol ) );
00701   if ( !context.get() )
00702     return ImportResult();
00703 
00704   Data keydata( data, length, false );
00705   if ( keydata.isNull() )
00706     return ImportResult();
00707 
00708   return context->importKeys( keydata );
00709 }
00710 
00711 
00712 /*  == == == == == == == == == == == == == == == == == == == == == == == == ==
00713    ==                                                                      ==
00714   ==         Continuation of CryptPlug code                               ==
00715  ==                                                                      ==
00716 == == == == == == == == == == == == == == == == == == == == == == == == ==  */
00717 
00718 // these are from gpgme-0.4.3:
00719 static gpgme_sig_stat_t
00720 sig_stat_from_status( gpgme_error_t err )
00721 {
00722   switch ( gpg_err_code(err) ) {
00723   case GPG_ERR_NO_ERROR:
00724     return GPGME_SIG_STAT_GOOD;
00725   case GPG_ERR_BAD_SIGNATURE:
00726     return GPGME_SIG_STAT_BAD;
00727   case GPG_ERR_NO_PUBKEY:
00728     return GPGME_SIG_STAT_NOKEY;
00729   case GPG_ERR_NO_DATA:
00730     return GPGME_SIG_STAT_NOSIG;
00731   case GPG_ERR_SIG_EXPIRED:
00732     return GPGME_SIG_STAT_GOOD_EXP;
00733   case GPG_ERR_KEY_EXPIRED:
00734     return GPGME_SIG_STAT_GOOD_EXPKEY;
00735   default:
00736     return GPGME_SIG_STAT_ERROR;
00737   }
00738 }
00739 
00740 
00741 static gpgme_sig_stat_t
00742 intersect_stati( gpgme_signature_t first )
00743 {
00744   if ( !first )
00745     return GPGME_SIG_STAT_NONE;
00746   gpgme_sig_stat_t result = sig_stat_from_status( first->status );
00747   for ( gpgme_signature_t sig = first->next ; sig ; sig = sig->next )
00748     if ( sig_stat_from_status( sig->status ) != result )
00749       return GPGME_SIG_STAT_DIFF;
00750   return result;
00751 }
00752 
00753 static const char*
00754 sig_status_to_string( gpgme_sig_stat_t status )
00755 {
00756   const char *result;
00757 
00758   switch (status) {
00759     case GPGME_SIG_STAT_NONE:
00760       result = "Oops: Signature not verified";
00761       break;
00762     case GPGME_SIG_STAT_NOSIG:
00763       result = "No signature found";
00764       break;
00765     case GPGME_SIG_STAT_GOOD:
00766       result = "Good signature";
00767       break;
00768     case GPGME_SIG_STAT_BAD:
00769       result = "BAD signature";
00770       break;
00771     case GPGME_SIG_STAT_NOKEY:
00772       result = "No public key to verify the signature";
00773       break;
00774     case GPGME_SIG_STAT_ERROR:
00775       result = "Error verifying the signature";
00776       break;
00777     case GPGME_SIG_STAT_DIFF:
00778       result = "Different results for signatures";
00779       break;
00780     default:
00781       result = "Error: Unknown status";
00782       break;
00783   }
00784 
00785   return result;
00786 }
00787 
00788 // WARNING: if you fix a bug here, you have to likely fix it in the
00789 // gpgme 0.3 version below, too!
00790 static
00791 void obtain_signature_information( gpgme_ctx_t ctx,
00792                                    gpgme_sig_stat_t & overallStatus,
00793                                    struct CryptPlug::SignatureMetaData* sigmeta,
00794                                    char** attrOrder,
00795                                    const char* unknownAttrsHandling,
00796                                    bool * signatureFound=0 )
00797 {
00798   gpgme_error_t err;
00799   unsigned long sumGPGME;
00800   SigStatusFlags sumPlug;
00801   struct CryptPlug::DnPair* a;
00802   int sig_idx=0;
00803 
00804   assert( ctx );
00805   assert( sigmeta );
00806 
00807   sigmeta->extended_info = 0;
00808   gpgme_verify_result_t result = gpgme_op_verify_result( ctx );
00809   if ( !result )
00810     return;
00811   for ( gpgme_signature_t signature = result->signatures ; signature ; signature = signature->next, ++sig_idx ) {
00812     void* alloc_return = realloc( sigmeta->extended_info,
00813                                   sizeof( CryptPlug::SignatureMetaDataExtendedInfo )
00814                                   * ( sig_idx + 1 ) );
00815     if ( !alloc_return )
00816       break;
00817     sigmeta->extended_info = (CryptPlug::SignatureMetaDataExtendedInfo*)alloc_return;
00818 
00819     /* shorthand notation :) */
00820     CryptPlug::SignatureMetaDataExtendedInfo & this_info = sigmeta->extended_info[sig_idx];
00821 
00822     /* clear the data area */
00823     memset( &this_info, 0, sizeof (CryptPlug::SignatureMetaDataExtendedInfo) );
00824 
00825     /* the creation time */
00826     if ( signature->timestamp ) {
00827       this_info.creation_time = (tm*)malloc( sizeof( struct tm ) );
00828       if ( this_info.creation_time ) {
00829         struct tm * ctime_val = localtime( (time_t*)&signature->timestamp );
00830         memcpy( this_info.creation_time,
00831                 ctime_val, sizeof( struct tm ) );
00832       }
00833     }
00834 
00835     /* the extended signature verification status */
00836     sumGPGME = signature->summary;
00837     fprintf( stderr, "gpgmeplug checkMessageSignature status flags: %lX\n", sumGPGME );
00838     /* translate GPGME status flags to common CryptPlug status flags */
00839     sumPlug = 0;
00840 #define convert(X) if ( sumGPGME & GPGME_SIGSUM_##X ) sumPlug |= SigStat_##X
00841     convert(VALID);
00842     convert(GREEN);
00843     convert(RED);
00844     convert(KEY_REVOKED);
00845     convert(KEY_EXPIRED);
00846     convert(SIG_EXPIRED);
00847     convert(KEY_MISSING);
00848     convert(CRL_MISSING);
00849     convert(CRL_TOO_OLD);
00850     convert(BAD_POLICY);
00851     convert(SYS_ERROR);
00852 #undef convert
00853     if( sumGPGME && !sumPlug )
00854       sumPlug = SigStat_NUMERICAL_CODE | sumGPGME;
00855     this_info.sigStatusFlags = sumPlug;
00856 
00857     /* extract finger print */
00858     if ( signature->fpr )
00859       storeNewCharPtr( &this_info.fingerprint, signature->fpr );
00860 
00861     /* validity */
00862     this_info.validity = GPGME_VALIDITY_UNKNOWN;
00863 
00864     /* sig key data */
00865     gpgme_key_t key = 0;
00866     // PENDING(marc) if this is deprecated, how shall we get at all
00867     // the infos below?
00868     err = gpgme_get_sig_key (ctx, sig_idx, &key);
00869 
00870     if ( !err && key ) {
00871       const char* attr_string;
00872       unsigned long attr_ulong;
00873 
00874       /* extract key identidy */
00875       attr_string = key->subkeys ? key->subkeys->keyid : 0 ;
00876       if ( attr_string )
00877     storeNewCharPtr( &this_info.keyid, attr_string );
00878 
00879       /* pubkey algorithm */
00880       attr_string = key->subkeys ? gpgme_pubkey_algo_name( key->subkeys->pubkey_algo ) : 0 ;
00881       if (attr_string != 0)
00882     storeNewCharPtr( &this_info.algo, attr_string );
00883       attr_ulong = key->subkeys ? key->subkeys->pubkey_algo : 0 ;
00884       this_info.algo_num = attr_ulong;
00885 
00886       /* extract key validity */
00887       attr_ulong = key->uids ? key->uids->validity : 0 ;
00888       this_info.validity = attr_ulong;
00889 
00890       /* extract user id, according to the documentation it's representable
00891        * as a number, but it seems that it also has a string representation
00892        */
00893       attr_string = key->uids ? key->uids->uid : 0 ;
00894       if (attr_string != 0) {
00895         a = parse_dn( (const unsigned char*)attr_string );
00896         this_info.userid = reorder_dn( a, attrOrder, unknownAttrsHandling );
00897       }
00898 
00899       attr_ulong = 0;
00900       this_info.userid_num = attr_ulong;
00901 
00902       /* extract the length */
00903       this_info.keylen = key->subkeys ? key->subkeys->length : 0 ;
00904 
00905       /* extract the creation time of the key */
00906       attr_ulong = key->subkeys ? key->subkeys->timestamp : 0 ;
00907       this_info.key_created = attr_ulong;
00908 
00909       /* extract the expiration time of the key */
00910       attr_ulong = key->subkeys ? key->subkeys->expires : 0 ;
00911       this_info.key_expires = attr_ulong;
00912 
00913       /* extract user name */
00914       attr_string = key->uids ? key->uids->name : 0 ;
00915       if (attr_string != 0) {
00916         a = parse_dn( (const unsigned char*)attr_string );
00917         this_info.name = reorder_dn( a, attrOrder, unknownAttrsHandling );
00918       }
00919 
00920       /* extract email(s) */
00921       this_info.emailCount = 0;
00922       this_info.emailList = 0;
00923       for ( gpgme_user_id_t uid = key->uids ; uid ; uid = uid->next ) {
00924         attr_string = uid->email;
00925         if ( attr_string && *attr_string) {
00926           fprintf( stderr, "gpgmeplug checkMessageSignature found email: %s\n", attr_string );
00927           if( !this_info.emailCount )
00928             alloc_return = malloc( sizeof( char*) );
00929           else
00930             alloc_return = realloc( this_info.emailList,
00931                   sizeof( char*)
00932                   * (this_info.emailCount + 1) );
00933           if( alloc_return ) {
00934             this_info.emailList = (char**)alloc_return;
00935             storeNewCharPtr( &( this_info.emailList[ this_info.emailCount ] ),
00936                 attr_string );
00937             ++this_info.emailCount;
00938           }
00939         }
00940       }
00941       if( !this_info.emailCount )
00942     fprintf( stderr, "gpgmeplug checkMessageSignature found NO EMAIL\n" );
00943 
00944       /* extract the comment */
00945       attr_string = key->uids ? key->uids->comment : 0 ;
00946       if (attr_string != 0)
00947     storeNewCharPtr( &this_info.comment, attr_string );
00948     }
00949 
00950     gpgme_sig_stat_t status = sig_stat_from_status( signature->status );
00951     const char* sig_status = sig_status_to_string( status );
00952     storeNewCharPtr( &this_info.status_text, sig_status );
00953   }
00954   sigmeta->extended_info_count = sig_idx;
00955   overallStatus = intersect_stati( result->signatures );
00956   sigmeta->status_code = overallStatus;
00957   storeNewCharPtr( &sigmeta->status, sig_status_to_string( overallStatus ) );
00958   if ( signatureFound )
00959     *signatureFound = ( overallStatus != GPGME_SIG_STAT_NONE );
00960 }
00961 
00962 bool CryptPlug::checkMessageSignature( char** cleartext,
00963                             const char* signaturetext,
00964                             bool signatureIsBinary,
00965                             int signatureLen,
00966                             struct CryptPlug::SignatureMetaData* sigmeta,
00967                             char** attrOrder,
00968                             const char* unknownAttrsHandling )
00969 {
00970   gpgme_ctx_t ctx;
00971   gpgme_sig_stat_t status = GPGME_SIG_STAT_NONE;
00972   gpgme_data_t datapart, sigpart;
00973   char* rClear = 0;
00974   size_t clearLen;
00975   bool isOpaqueSigned;
00976 
00977   if( !cleartext ) {
00978     if( sigmeta )
00979       storeNewCharPtr( &sigmeta->status,
00980                         __GPGMEPLUG_ERROR_CLEARTEXT_IS_ZERO );
00981 
00982     return false;
00983   }
00984 
00985   isOpaqueSigned = !*cleartext;
00986 
00987   gpgme_new( &ctx );
00988   gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL);
00989   gpgme_set_armor (ctx,    signatureIsBinary ? 0 : 1);
00990   /*  gpgme_set_textmode (ctx, signatureIsBinary ? 0 : 1); */
00991 
00992   if( isOpaqueSigned )
00993     gpgme_data_new( &datapart );
00994   else
00995     gpgme_data_new_from_mem( &datapart, *cleartext,
00996                              strlen( *cleartext ), 1 );
00997 
00998   gpgme_data_new_from_mem( &sigpart,
00999                            signaturetext,
01000                            signatureIsBinary
01001                            ? signatureLen
01002                            : strlen( signaturetext ),
01003                            1 );
01004 
01005   if ( isOpaqueSigned )
01006     gpgme_op_verify( ctx, sigpart, 0, datapart );
01007   else
01008     gpgme_op_verify( ctx, sigpart, datapart, 0 );
01009 
01010   if( isOpaqueSigned ) {
01011     rClear = gpgme_data_release_and_get_mem( datapart, &clearLen );
01012     *cleartext = (char*)malloc( clearLen + 1 );
01013     if( *cleartext ) {
01014       if( clearLen )
01015         strncpy(*cleartext, rClear, clearLen );
01016       (*cleartext)[clearLen] = '\0';
01017     }
01018     free( rClear );
01019   }
01020   else
01021     gpgme_data_release( datapart );
01022 
01023   gpgme_data_release( sigpart );
01024 
01025   obtain_signature_information( ctx, status, sigmeta,
01026                                 attrOrder, unknownAttrsHandling );
01027 
01028   gpgme_release( ctx );
01029   return ( status == GPGME_SIG_STAT_GOOD );
01030 }
01031 
01032 bool CryptPlug::decryptAndCheckMessage( const char*  ciphertext,
01033                                   bool         cipherIsBinary,
01034                                   int          cipherLen,
01035                                   const char** cleartext,
01036                                   const char*  /*certificate*/,
01037                                   bool*        signatureFound,
01038                                   struct CryptPlug::SignatureMetaData* sigmeta,
01039                                   int*   errId,
01040                                   char** errTxt,
01041                                   char** attrOrder,
01042                                   const char* unknownAttrsHandling  )
01043 {
01044   gpgme_ctx_t ctx;
01045   gpgme_error_t err;
01046   gpgme_decrypt_result_t decryptresult;
01047   gpgme_data_t gCiphertext, gPlaintext;
01048   gpgme_sig_stat_t sigstatus = GPGME_SIG_STAT_NONE;
01049   size_t rCLen = 0;
01050   char*  rCiph = 0;
01051   bool bOk = false;
01052   bool bWrongKeyUsage = 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   decryptresult = gpgme_op_decrypt_result( ctx );
01079 #ifdef HAVE_GPGME_WRONG_KEY_USAGE
01080   if( decryptresult->wrong_key_usage )
01081     bWrongKeyUsage = true;
01082 #endif
01083 
01084   if( err ) {
01085     fprintf( stderr, "\ngpgme_op_decrypt_verify() returned this error code:  %i\n\n", err );
01086     if( errId )
01087       *errId = err;
01088     if( errTxt ) {
01089       const char* _errTxt = gpgme_strerror( err );
01090       *errTxt = (char*)malloc( strlen( _errTxt ) + 1 );
01091       if( *errTxt )
01092         strcpy(*errTxt, _errTxt );
01093     }
01094     gpgme_data_release( gPlaintext );
01095     gpgme_release( ctx );
01096     return bOk;
01097   }
01098 
01099   if( bWrongKeyUsage ) {
01100     if( errId )
01101       *errId = CRYPTPLUG_ERR_WRONG_KEY_USAGE; // report the wrong key usage
01102   }
01103 
01104   rCiph = gpgme_data_release_and_get_mem( gPlaintext,  &rCLen );
01105 
01106   *cleartext = (char*)malloc( rCLen + 1 );
01107   if( *cleartext ) {
01108       if( rCLen ) {
01109           bOk = true;
01110           strncpy((char*)*cleartext, rCiph, rCLen );
01111       }
01112       ((char*)(*cleartext))[rCLen] = 0;
01113   }
01114   free( rCiph );
01115 
01116   obtain_signature_information( ctx, sigstatus, sigmeta,
01117                                 attrOrder, unknownAttrsHandling,
01118                                 signatureFound );
01119 
01120   gpgme_release( ctx );
01121   return bOk;
01122 }
01123 
KDE Home | KDE Accessibility Home | Description of Access Keys