00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
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
00078
00079
00080
00081
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
00109
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
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
00144 __GPGMEPLUG_SIGNATURE_CODE_IS_BINARY = true;
00145
00146
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
00171
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
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
00206 __GPGMEPLUG_SIGNATURE_CODE_IS_BINARY = false;
00207
00208
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
00231 #define MAX_GPGME_IDX 20
00232
00233
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
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
00260
00261
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" );
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
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
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* ,
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
00384
00385
00386
00387
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
00453
00454
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
00463 for (s = string+1; *s && *s != '='; s++)
00464 ;
00465 if (!*s)
00466 return NULL;
00467 n = s - string;
00468 if (!n)
00469 return NULL;
00470 p = (char*)xmalloc (n+1);
00471
00472
00473 memcpy (p, string, n);
00474 p[n] = 0;
00475 trim_trailing_spaces ((char*)p);
00476
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 {
00488 string++;
00489 for (s=string; hexdigitp (s); s++)
00490 s++;
00491 n = s - string;
00492 if (!n || (n & 1))
00493 return NULL;
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 {
00504 for (n=0, s=string; *s; s++)
00505 {
00506 if (*s == '\\')
00507 {
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;
00520 }
00521 else if (*s == '\"')
00522 return NULL;
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
00556
00557
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;
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;
00578 if (arrayidx >= arraysize)
00579 {
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;
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
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
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
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
00694 if( unknownAttrsHandling &&
00695 !strcmp(unknownAttrsHandling, "PREFIX")
00696 && *resultUnknowns ){
00697 result.append( resultUnknowns );
00698 any = 1;
00699 }else{
00700 any = 0;
00701 }
00702
00703
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
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
00762
00763
00764
00765
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
00836
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
00867 CryptPlug::SignatureMetaDataExtendedInfo & this_info = sigmeta->extended_info[sig_idx];
00868
00869
00870 memset( &this_info, 0, sizeof (CryptPlug::SignatureMetaDataExtendedInfo) );
00871
00872
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
00883 sumGPGME = signature->summary;
00884 fprintf( stderr, "gpgmeplug checkMessageSignature status flags: %lX\n", sumGPGME );
00885
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
00905 if ( signature->fpr )
00906 storeNewCharPtr( &this_info.fingerprint, signature->fpr );
00907
00908
00909 this_info.validity = GPGME_VALIDITY_UNKNOWN;
00910
00911
00912 gpgme_key_t key = 0;
00913
00914
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
00922 attr_string = key->subkeys ? key->subkeys->keyid : 0 ;
00923 if ( attr_string )
00924 storeNewCharPtr( &this_info.keyid, attr_string );
00925
00926
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
00934 attr_ulong = key->uids ? key->uids->validity : 0 ;
00935 this_info.validity = attr_ulong;
00936
00937
00938
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
00950 this_info.keylen = key->subkeys ? key->subkeys->length : 0 ;
00951
00952
00953 attr_ulong = key->subkeys ? key->subkeys->timestamp : 0 ;
00954 this_info.key_created = attr_ulong;
00955
00956
00957 attr_ulong = key->subkeys ? key->subkeys->expires : 0 ;
00958 this_info.key_expires = attr_ulong;
00959
00960
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
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
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
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* ,
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
01108
01109
01110
01111
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;
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