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 <tqstring.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( TQCString& result, struct CryptPlug::DnPair& dnPair ) 00574 { 00575 /* email hack */ 00576 TQCString 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( TQCString& 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 TQCString result; 00626 TQCString 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 01053 if( !ciphertext ) 01054 return false; 01055 01056 err = gpgme_new (&ctx); 01057 gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL); 01058 01059 gpgme_set_armor (ctx, cipherIsBinary ? 0 : 1); 01060 /* gpgme_set_textmode (ctx, cipherIsBinary ? 0 : 1); */ 01061 01062 /* 01063 gpgme_data_new_from_mem( &gCiphertext, ciphertext, 01064 1+strlen( ciphertext ), 1 ); */ 01065 gpgme_data_new_from_mem( &gCiphertext, 01066 ciphertext, 01067 cipherIsBinary 01068 ? cipherLen 01069 : strlen( ciphertext ), 01070 1 ); 01071 01072 gpgme_data_new( &gPlaintext ); 01073 01074 err = gpgme_op_decrypt_verify( ctx, gCiphertext, gPlaintext ); 01075 gpgme_data_release( gCiphertext ); 01076 01077 if( err ) { 01078 fprintf( stderr, "\ngpgme_op_decrypt_verify() returned this error code: %i\n\n", err ); 01079 if( errId ) 01080 *errId = err; 01081 if( errTxt ) { 01082 const char* _errTxt = gpgme_strerror( err ); 01083 *errTxt = (char*)malloc( strlen( _errTxt ) + 1 ); 01084 if( *errTxt ) 01085 strcpy(*errTxt, _errTxt ); 01086 } 01087 gpgme_data_release( gPlaintext ); 01088 gpgme_release( ctx ); 01089 return bOk; 01090 } 01091 decryptresult = gpgme_op_decrypt_result( ctx ); 01092 01093 bool bWrongKeyUsage = false; 01094 #ifdef HAVE_GPGME_WRONG_KEY_USAGE 01095 if( decryptresult && decryptresult->wrong_key_usage ) 01096 bWrongKeyUsage = true; 01097 #endif 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