certmanager/lib Library API Documentation

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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 /* Wrapper to cope with a bug in gpgme 0.4.4. */ 00268 static void 00269 my_gpgme_key_release (gpgme_key_t key) 00270 { 00271 if (key) 00272 gpgme_key_release (key); 00273 } 00274 00275 00276 CryptPlug::CryptPlug() { 00277 } 00278 00279 CryptPlug::~CryptPlug() { 00280 } 00281 00282 bool CryptPlug::initialize() { 00283 GpgME::setDefaultLocale( LC_CTYPE, setlocale( LC_CTYPE, 0 ) ); 00284 GpgME::setDefaultLocale( LC_MESSAGES, setlocale( LC_MESSAGES, 0 ) ); 00285 return (gpgme_engine_check_version (GPGMEPLUG_PROTOCOL) == GPG_ERR_NO_ERROR); 00286 }; 00287 00288 00289 bool CryptPlug::hasFeature( Feature flag ) 00290 { 00291 /* our own plugins are supposed to support everything */ 00292 switch ( flag ) { 00293 case Feature_SignMessages: 00294 case Feature_VerifySignatures: 00295 case Feature_EncryptMessages: 00296 case Feature_DecryptMessages: 00297 case Feature_SendCertificates: 00298 case Feature_PinEntrySettings: 00299 case Feature_StoreMessagesWithSigs: 00300 case Feature_EncryptionCRLs: 00301 case Feature_StoreMessagesEncrypted: 00302 case Feature_CheckCertificatePath: 00303 return true; 00304 case Feature_WarnSignCertificateExpiry: 00305 case Feature_WarnSignEmailNotInCertificate: 00306 case Feature_WarnEncryptCertificateExpiry: 00307 case Feature_WarnEncryptEmailNotInCertificate: 00308 return GPGMEPLUG_PROTOCOL == GPGME_PROTOCOL_CMS; 00309 /* undefined or not yet implemented: */ 00310 case Feature_CRLDirectoryService: 00311 case Feature_CertificateDirectoryService: 00312 case Feature_undef: 00313 default: 00314 return false; 00315 } 00316 } 00317 00318 00319 /* Return the current interface version. This is a simple way for a 00320 user to check whether all required fucntions are available. If 00321 MIN_VERSION is not NULL the lowest supported version of the 00322 interface is returned in addition. */ 00323 int CryptPlug::interfaceVersion (int *min_version) 00324 { 00325 if (min_version) 00326 *min_version = 0; 00327 return 1; 00328 } 00329 00330 static 00331 int getAttrExpireFormKey( gpgme_key_t* rKey) 00332 { 00333 int daysLeft = CRYPTPLUG_CERT_DOES_NEVER_EXPIRE; 00334 if ( rKey && *rKey && (*rKey)->subkeys && (*rKey)->subkeys->expires >= 0 ) { 00335 time_t expire_time = (*rKey)->subkeys->expires; 00336 time_t cur_time = time (NULL); 00337 if( cur_time > expire_time ) { 00338 daysLeft = days_from_seconds(cur_time - expire_time); 00339 daysLeft *= -1; 00340 } 00341 else 00342 daysLeft = days_from_seconds(expire_time - cur_time); 00343 } 00344 return daysLeft; 00345 } 00346 00347 00348 static 00349 void storeNewCharPtr( char** dest, const char* src ) 00350 { 00351 int sLen = strlen( src ); 00352 *dest = (char*)xmalloc( sLen + 1 ); 00353 strcpy( *dest, src ); 00354 } 00355 00356 00357 bool CryptPlug::signMessage( const char* cleartext, 00358 char** ciphertext, 00359 const size_t* cipherLen, 00360 const char* certificate, 00361 struct StructuringInfo* structuring, 00362 int* errId, 00363 char** errTxt, 00364 SendCertificates sendCertificates, 00365 SignatureCompoundMode signatureCompoundMode ) 00366 { 00367 bool bIsOpaque; 00368 gpgme_ctx_t ctx; 00369 gpgme_error_t err; 00370 gpgme_key_t rKey; 00371 gpgme_data_t data, sig; 00372 char* rSig = 0; 00373 bool bOk = false; 00374 int sendCerts = 1; 00375 00376 init_StructuringInfo( structuring ); 00377 00378 if( !ciphertext ) 00379 return false; 00380 00381 err = gpgme_new (&ctx); 00382 gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL); 00383 00384 gpgme_set_armor (ctx, __GPGMEPLUG_SIGNATURE_CODE_IS_BINARY ? 0 : 1); 00385 /* gpgme_set_textmode (ctx, 1); */ 00386 00387 switch ( sendCertificates ) { 00388 case SendCert_undef: 00389 break; 00390 case SendCert_DontSend: 00391 sendCerts = 0; 00392 break; 00393 case SendCert_SendOwn: 00394 sendCerts = 1; 00395 break; 00396 case SendCert_SendChainWithoutRoot: 00397 sendCerts = -2; 00398 break; 00399 case SendCert_SendChainWithRoot: 00400 sendCerts = -1; 00401 break; 00402 default: 00403 sendCerts = 0; 00404 break; 00405 } 00406 gpgme_set_include_certs (ctx, sendCerts); 00407 00408 /* select the signer's key if provided */ 00409 if (certificate != 0) { 00410 err = gpgme_op_keylist_start(ctx, certificate, 0); 00411 while (!err) { 00412 err = gpgme_op_keylist_next(ctx, &rKey); 00413 if (!err) { 00414 if ( rKey && rKey->can_sign ) { 00415 /* clear existing signers */ 00416 gpgme_signers_clear(ctx); 00417 /* set the signing key */ 00418 gpgme_signers_add(ctx, rKey); 00419 /* we only support one signer for now */ 00420 break; 00421 } 00422 } 00423 } 00424 gpgme_op_keylist_end(ctx); 00425 } 00426 00427 /* PENDING(g10) Implement this 00428 00429 gpgme_set_signature_algorithm( ctx, config->signatureAlgorithm ) 00430 --> This does not make sense. The algorithm is a property of 00431 the certificate used [wk 2002-03-23] */ 00432 00433 gpgme_data_new_from_mem (&data, cleartext, 00434 strlen( cleartext ), 1 ); 00435 gpgme_data_new ( &sig ); 00436 00437 /* NOTE: Currently we support Opaque signed messages only for S/MIME, 00438 but not for OpenPGP mode! */ 00439 if( GPGMEPLUG_PROTOCOL == GPGME_PROTOCOL_CMS ) 00440 bIsOpaque = (signatureCompoundMode == SignatureCompoundMode_Opaque); 00441 else 00442 bIsOpaque = false; 00443 00444 err = gpgme_op_sign ( ctx, 00445 data, 00446 sig, 00447 bIsOpaque 00448 ? GPGME_SIG_MODE_NORMAL 00449 : GPGME_SIG_MODE_DETACH ); 00450 00451 if ( !err ) { 00452 if( __GPGMEPLUG_SIGNATURE_CODE_IS_BINARY ) { 00453 *ciphertext = gpgme_data_release_and_get_mem( sig, (size_t*)cipherLen ); 00454 bOk = true; 00455 } 00456 else { 00457 rSig = gpgme_data_release_and_get_mem( sig, (size_t*)cipherLen ); 00458 *ciphertext = (char*)malloc( *cipherLen + 1 ); 00459 if( *ciphertext ) { 00460 if( *cipherLen ) { 00461 bOk = true; 00462 strncpy((char*)*ciphertext, rSig, *cipherLen ); 00463 } 00464 (*ciphertext)[*cipherLen] = '\0'; 00465 } 00466 free( rSig ); 00467 } 00468 } 00469 else { 00470 gpgme_data_release( sig ); 00471 /* 00472 *ciphertext = malloc( 70 ); 00473 strcpy((char*)*ciphertext, "xyz\nsig-dummy\nzyx" ); 00474 (*ciphertext)[17] = '\0'; 00475 err = 0; 00476 { 00477 */ 00478 *ciphertext = 0; 00479 fprintf( stderr, "\n\n gpgme_op_sign() returned this error code: %i\n\n", err ); 00480 if( errId ) 00481 *errId = err; 00482 if( errTxt ) { 00483 const char* _errTxt = gpgme_strerror( err ); 00484 *errTxt = (char*)malloc( strlen( _errTxt ) + 1 ); 00485 if( *errTxt ) 00486 strcpy(*errTxt, _errTxt ); 00487 } 00488 /* 00489 } 00490 */ 00491 } 00492 gpgme_data_release( data ); 00493 gpgme_release (ctx); 00494 00495 if( bOk && structuring ) { 00496 if( bIsOpaque ) { 00497 structuring->includeCleartext = GPGMEPLUG_OPA_SIGN_INCLUDE_CLEARTEXT; 00498 structuring->makeMimeObject = GPGMEPLUG_OPA_SIGN_MAKE_MIME_OBJECT; 00499 if( structuring->makeMimeObject ) { 00500 structuring->makeMultiMime = GPGMEPLUG_OPA_SIGN_MAKE_MULTI_MIME; 00501 storeNewCharPtr( &structuring->contentTypeMain, 00502 GPGMEPLUG_OPA_SIGN_CTYPE_MAIN ); 00503 storeNewCharPtr( &structuring->contentDispMain, 00504 GPGMEPLUG_OPA_SIGN_CDISP_MAIN ); 00505 storeNewCharPtr( &structuring->contentTEncMain, 00506 GPGMEPLUG_OPA_SIGN_CTENC_MAIN ); 00507 if( structuring->makeMultiMime ) { 00508 storeNewCharPtr( &structuring->contentTypeVersion, 00509 GPGMEPLUG_OPA_SIGN_CTYPE_VERSION ); 00510 storeNewCharPtr( &structuring->contentDispVersion, 00511 GPGMEPLUG_OPA_SIGN_CDISP_VERSION ); 00512 storeNewCharPtr( &structuring->contentTEncVersion, 00513 GPGMEPLUG_OPA_SIGN_CTENC_VERSION ); 00514 storeNewCharPtr( &structuring->bodyTextVersion, 00515 GPGMEPLUG_OPA_SIGN_BTEXT_VERSION ); 00516 storeNewCharPtr( &structuring->contentTypeCode, 00517 GPGMEPLUG_OPA_SIGN_CTYPE_CODE ); 00518 storeNewCharPtr( &structuring->contentDispCode, 00519 GPGMEPLUG_OPA_SIGN_CDISP_CODE ); 00520 storeNewCharPtr( &structuring->contentTEncCode, 00521 GPGMEPLUG_OPA_SIGN_CTENC_CODE ); 00522 } 00523 } else { 00524 storeNewCharPtr( &structuring->flatTextPrefix, 00525 GPGMEPLUG_OPA_SIGN_FLAT_PREFIX ); 00526 storeNewCharPtr( &structuring->flatTextSeparator, 00527 GPGMEPLUG_OPA_SIGN_FLAT_SEPARATOR ); 00528 storeNewCharPtr( &structuring->flatTextPostfix, 00529 GPGMEPLUG_OPA_SIGN_FLAT_POSTFIX ); 00530 } 00531 } else { 00532 structuring->includeCleartext = GPGMEPLUG_DET_SIGN_INCLUDE_CLEARTEXT; 00533 structuring->makeMimeObject = GPGMEPLUG_DET_SIGN_MAKE_MIME_OBJECT; 00534 if( structuring->makeMimeObject ) { 00535 structuring->makeMultiMime = GPGMEPLUG_DET_SIGN_MAKE_MULTI_MIME; 00536 storeNewCharPtr( &structuring->contentTypeMain, 00537 GPGMEPLUG_DET_SIGN_CTYPE_MAIN ); 00538 storeNewCharPtr( &structuring->contentDispMain, 00539 GPGMEPLUG_DET_SIGN_CDISP_MAIN ); 00540 storeNewCharPtr( &structuring->contentTEncMain, 00541 GPGMEPLUG_DET_SIGN_CTENC_MAIN ); 00542 if( structuring->makeMultiMime ) { 00543 storeNewCharPtr( &structuring->contentTypeVersion, 00544 GPGMEPLUG_DET_SIGN_CTYPE_VERSION ); 00545 storeNewCharPtr( &structuring->contentDispVersion, 00546 GPGMEPLUG_DET_SIGN_CDISP_VERSION ); 00547 storeNewCharPtr( &structuring->contentTEncVersion, 00548 GPGMEPLUG_DET_SIGN_CTENC_VERSION ); 00549 storeNewCharPtr( &structuring->bodyTextVersion, 00550 GPGMEPLUG_DET_SIGN_BTEXT_VERSION ); 00551 storeNewCharPtr( &structuring->contentTypeCode, 00552 GPGMEPLUG_DET_SIGN_CTYPE_CODE ); 00553 storeNewCharPtr( &structuring->contentDispCode, 00554 GPGMEPLUG_DET_SIGN_CDISP_CODE ); 00555 storeNewCharPtr( &structuring->contentTEncCode, 00556 GPGMEPLUG_DET_SIGN_CTENC_CODE ); 00557 } 00558 } else { 00559 storeNewCharPtr( &structuring->flatTextPrefix, 00560 GPGMEPLUG_DET_SIGN_FLAT_PREFIX ); 00561 storeNewCharPtr( &structuring->flatTextSeparator, 00562 GPGMEPLUG_DET_SIGN_FLAT_SEPARATOR ); 00563 storeNewCharPtr( &structuring->flatTextPostfix, 00564 GPGMEPLUG_DET_SIGN_FLAT_POSTFIX ); 00565 } 00566 } 00567 } 00568 return bOk; 00569 } 00570 00571 00572 00573 bool CryptPlug::storeCertificatesFromMessage( const char* ){ return true; } 00574 00575 00576 /* returns address if address doesn't contain a <xxx> part 00577 * else it returns a new string xxx and frees address 00578 */ 00579 static char* parseAddress( char* address ) 00580 { 00581 char* result = address; 00582 char* i; 00583 char* j; 00584 if( !result ) return result; 00585 i = index( address, '<' ); 00586 if( i ) { 00587 j = index( i+1, '>' ); 00588 if( j == NULL ) j = address+strlen(address); 00589 result = (char*)xmalloc( j-i ); 00590 strncpy( result, i+1, j-i-1 ); 00591 result[j-i-1] = '\0'; 00592 free( address ); 00593 } else { 00594 i = address; 00595 j = i+strlen(address); 00596 } 00597 { 00598 /* remove surrounding whitespace */ 00599 char* k = result+(j-i-1); 00600 char* l = result; 00601 while( isspace( *l ) ) ++l; 00602 while( isspace( *k ) ) --k; 00603 if( l != result || k != result+(j-i-1) ) { 00604 char* result2 = (char*)xmalloc( k-l+2 ); 00605 strncpy( result2, l, k-l+1 ); 00606 result2[k-l+1] = '\0'; 00607 free(result); 00608 result = result2; 00609 } 00610 } 00611 return result; 00612 } 00613 00614 static char* nextAddress( const char** address ) 00615 { 00616 const char *start = *address; 00617 char* result = NULL; 00618 int quote = 0; 00619 int comment = 0; 00620 int found = 0; 00621 if( *address == NULL ) return NULL; 00622 while( **address ) { 00623 00624 switch( **address ) { 00625 case '\\': /* escaped character */ 00626 ++(*address); 00627 break; 00628 case '"': 00629 if( comment == 0 ) { 00630 if( quote > 0 ) --quote; 00631 else ++quote; 00632 } 00633 break; 00634 case '(': /* comment start */ 00635 if( quote == 0 ) ++comment; 00636 break; 00637 case ')': /* comment end */ 00638 if( quote == 0 ) --comment; 00639 break; 00640 case '\0': 00641 case '\1': /* delimiter */ 00642 if( quote == 0 && comment == 0 ) { 00643 found = 1; 00644 } 00645 break; 00646 } 00647 ++(*address); 00648 if( found ) break; 00649 } 00650 if( found || **address == 0 ) { 00651 size_t len; 00652 len = *address - start; 00653 if( len > 0 ) { 00654 if( **address != 0 ) --len; 00655 result = (char*)xmalloc( len*sizeof(char)+1 ); 00656 strncpy( result, start, len ); 00657 result[len] = '\0'; 00658 } 00659 } 00660 return parseAddress(result); 00661 } 00662 00663 bool CryptPlug::encryptMessage( const char* cleartext, 00664 const char** ciphertext, 00665 const size_t* cipherLen, 00666 const char* certificate, 00667 struct StructuringInfo* structuring, 00668 int* errId, 00669 char** errTxt ) 00670 { 00671 gpgme_ctx_t ctx; 00672 gpgme_error_t err; 00673 gpgme_data_t gCiphertext, gPlaintext; 00674 char* rCiph = 0; 00675 bool bOk = false; 00676 00677 init_StructuringInfo( structuring ); 00678 00679 gpgme_new (&ctx); 00680 gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL); 00681 00682 gpgme_set_armor (ctx, __GPGMEPLUG_ENCRYPTED_CODE_IS_BINARY ? 0 : 1); 00683 /* gpgme_set_textmode (ctx, 1); */ 00684 00685 gpgme_data_new_from_mem (&gPlaintext, cleartext, 00686 1+strlen( cleartext ), 1 ); 00687 err = gpgme_data_new ( &gCiphertext ); 00688 00689 00690 std::vector<char*> recips; 00691 00692 { 00693 const char* p = certificate; 00694 char* tok; 00695 while( (tok = nextAddress( &p ) ) != 0 ) { 00696 fprintf( stderr, "\nGPGMEPLUG encryptMessage() using addressee %s\n", tok ); 00697 recips.push_back( tok ); 00698 } 00699 } 00700 00701 recips.push_back( 0 ); 00702 const char ** patterns = new const char*[ recips.size() ]; 00703 const char ** patterns_it = patterns; 00704 std::copy( recips.begin(), recips.end(), patterns_it ); 00705 recips.pop_back(); 00706 00707 std::vector<gpgme_key_t> keys; 00708 #if 0 // BROKEN FOR FINGERPRINTS 00709 err = gpgme_op_keylist_ext_start( ctx, patterns, 0, 0 ); 00710 while ( !err ) { 00711 gpgme_key_t key = 0; 00712 err = gpgme_op_keylist_next( ctx, &key ); 00713 keys.push_back( key ); 00714 } 00715 if ( gpg_err_code( err ) == GPG_ERR_EOF ) 00716 err = GPG_ERR_NO_ERROR; 00717 gpgme_op_keylist_end( ctx ); 00718 #else 00719 for ( const char ** pit = patterns ; *pit && !err ; ++pit ) { 00720 gpgme_key_t key = 0; 00721 err = gpgme_get_key( ctx, *pit, &key, false ); 00722 if ( key ) 00723 keys.push_back( key ); 00724 } 00725 #endif 00726 00727 keys.push_back( 0 ); 00728 gpgme_key_t * rset = new gpgme_key_t[ keys.size() ]; 00729 gpgme_key_t * rset_it = rset; 00730 std::copy( keys.begin(), keys.end(), rset_it ); 00731 keys.pop_back(); 00732 00733 std::for_each( recips.begin(), recips.end(), &free ); 00734 delete[] patterns; 00735 00736 /* PENDING(g10) Implement this 00737 Possible values: RSA = 1, SHA1 = 2, TripleDES = 3 00738 gpgme_set_encryption_algorithm( ctx, config->encryptionAlgorithm ); 00739 00740 -> Your are mixing public key and symmetric algorithms. The 00741 latter may be configured but the sphix specifications do opnly 00742 allow 3-DES so this is not nothing we need to do. The proper way 00743 to select the symmetric algorithm is anyway by looking at the 00744 capabilities of the certificate because this is the only way to 00745 know what the recipient can accept. [wk 2002-03-23] 00746 00747 PENDING(g10) Implement this 00748 gpgme_set_encryption_check_certificate_path( 00749 config->checkCertificatePath ) 00750 00751 PENDING(g10) Implement this 00752 gpgme_set_encryption_check_certificate_path_to_root( 00753 config->checkEncryptionCertificatePathToRoot ) 00754 00755 -> Not checking a certificate up to the ROOT CA is dangerous and 00756 stupid. There is no need for those options. [wk 2002-03-23] */ 00757 00758 00759 if ( !err ) 00760 err = gpgme_op_encrypt (ctx, rset, (gpgme_encrypt_flags_t)0, gPlaintext, gCiphertext ); 00761 if( err ) { 00762 fprintf( stderr, "\ngpgme_op_encrypt() returned this error code: %i\n", err ); 00763 if( errId ) 00764 *errId = err; 00765 if( errTxt ) { 00766 const char* _errTxt = gpgme_strerror( err ); 00767 const size_t errTxtLen = strlen( _errTxt ) + 100; // leave room for reason string 00768 *errTxt = (char*)malloc( errTxtLen + 1 ); 00769 if( *errTxt ) { 00770 std::string str = _errTxt; 00771 gpgme_encrypt_result_t opInfo = gpgme_op_encrypt_result( ctx ); 00772 if ( opInfo && opInfo->invalid_recipients ) { 00773 str += " - "; 00774 str += gpgme_strerror( opInfo->invalid_recipients->reason ); 00775 // PENDING(kdab): there could be more than one! 00776 } 00777 strncmp( *errTxt, str.c_str(), errTxtLen ); 00778 (*errTxt)[errTxtLen] = '\0'; 00779 } 00780 } 00781 } 00782 00783 std::for_each( keys.begin(), keys.end(), &my_gpgme_key_release ); 00784 delete[] rset; 00785 gpgme_data_release (gPlaintext); 00786 00787 if( !err ) { 00788 if( __GPGMEPLUG_ENCRYPTED_CODE_IS_BINARY ) { 00789 *ciphertext = gpgme_data_release_and_get_mem( gCiphertext, (size_t*)cipherLen ); 00790 bOk = true; 00791 } 00792 else { 00793 rCiph = gpgme_data_release_and_get_mem( gCiphertext, (size_t*)cipherLen ); 00794 *ciphertext = (char*)malloc( *cipherLen + 1 ); 00795 if( *ciphertext ) { 00796 if( *cipherLen ) { 00797 bOk = true; 00798 strncpy((char*)*ciphertext, rCiph, *cipherLen ); 00799 } 00800 ((char*)(*ciphertext))[*cipherLen] = 0; 00801 } 00802 free( rCiph ); 00803 } 00804 } 00805 else { 00806 gpgme_data_release ( gCiphertext ); 00807 *ciphertext = 0; 00808 /* error handling is missing: if only one untrusted key was found 00809 (or none at all), gpg won't sign the message. (hier fehlt eine 00810 Fehlerbehandlung: fuer einen Recipient nur ein untrusted key 00811 (oder gar keiner) gefunden wurde, verweigert gpg das signieren.) 00812 */ 00813 } 00814 00815 gpgme_release (ctx); 00816 00817 fflush( stderr ); 00818 00819 if( bOk && structuring ) { 00820 structuring->includeCleartext = GPGMEPLUG_ENC_INCLUDE_CLEARTEXT; 00821 structuring->makeMimeObject = GPGMEPLUG_ENC_MAKE_MIME_OBJECT; 00822 if( structuring->makeMimeObject ) { 00823 structuring->makeMultiMime = GPGMEPLUG_ENC_MAKE_MULTI_MIME; 00824 storeNewCharPtr( &structuring->contentTypeMain, 00825 GPGMEPLUG_ENC_CTYPE_MAIN ); 00826 storeNewCharPtr( &structuring->contentDispMain, 00827 GPGMEPLUG_ENC_CDISP_MAIN ); 00828 storeNewCharPtr( &structuring->contentTEncMain, 00829 GPGMEPLUG_ENC_CTENC_MAIN ); 00830 if( structuring->makeMultiMime ) { 00831 storeNewCharPtr( &structuring->contentTypeVersion, 00832 GPGMEPLUG_ENC_CTYPE_VERSION ); 00833 storeNewCharPtr( &structuring->contentDispVersion, 00834 GPGMEPLUG_ENC_CDISP_VERSION ); 00835 storeNewCharPtr( &structuring->contentTEncVersion, 00836 GPGMEPLUG_ENC_CTENC_VERSION ); 00837 storeNewCharPtr( &structuring->bodyTextVersion, 00838 GPGMEPLUG_ENC_BTEXT_VERSION ); 00839 storeNewCharPtr( &structuring->contentTypeCode, 00840 GPGMEPLUG_ENC_CTYPE_CODE ); 00841 storeNewCharPtr( &structuring->contentDispCode, 00842 GPGMEPLUG_ENC_CDISP_CODE ); 00843 storeNewCharPtr( &structuring->contentTEncCode, 00844 GPGMEPLUG_ENC_CTENC_CODE ); 00845 } 00846 } else { 00847 storeNewCharPtr( &structuring->flatTextPrefix, 00848 GPGMEPLUG_ENC_FLAT_PREFIX ); 00849 storeNewCharPtr( &structuring->flatTextSeparator, 00850 GPGMEPLUG_ENC_FLAT_SEPARATOR ); 00851 storeNewCharPtr( &structuring->flatTextPostfix, 00852 GPGMEPLUG_ENC_FLAT_POSTFIX ); 00853 } 00854 } 00855 return bOk; 00856 } 00857 00858 00859 bool CryptPlug::encryptAndSignMessage( const char* /*cleartext*/, 00860 const char** /*ciphertext*/, 00861 const char* /*certificate*/, 00862 struct StructuringInfo* structuring ) 00863 { 00864 bool bOk; 00865 00866 init_StructuringInfo( structuring ); 00867 00868 bOk = false; 00869 00870 /* implementation of this function is still missing */ 00871 00872 if( bOk && structuring ) { 00873 structuring->includeCleartext = GPGMEPLUG_ENCSIGN_INCLUDE_CLEARTEXT; 00874 structuring->makeMimeObject = GPGMEPLUG_ENCSIGN_MAKE_MIME_OBJECT; 00875 if( structuring->makeMimeObject ) { 00876 structuring->makeMultiMime = GPGMEPLUG_ENCSIGN_MAKE_MULTI_MIME; 00877 storeNewCharPtr( &structuring->contentTypeMain, 00878 GPGMEPLUG_ENCSIGN_CTYPE_MAIN ); 00879 storeNewCharPtr( &structuring->contentDispMain, 00880 GPGMEPLUG_ENCSIGN_CDISP_MAIN ); 00881 storeNewCharPtr( &structuring->contentTEncMain, 00882 GPGMEPLUG_ENCSIGN_CTENC_MAIN ); 00883 if( structuring->makeMultiMime ) { 00884 storeNewCharPtr( &structuring->contentTypeVersion, 00885 GPGMEPLUG_ENCSIGN_CTYPE_VERSION ); 00886 storeNewCharPtr( &structuring->contentDispVersion, 00887 GPGMEPLUG_ENCSIGN_CDISP_VERSION ); 00888 storeNewCharPtr( &structuring->contentTEncVersion, 00889 GPGMEPLUG_ENCSIGN_CTENC_VERSION ); 00890 storeNewCharPtr( &structuring->bodyTextVersion, 00891 GPGMEPLUG_ENCSIGN_BTEXT_VERSION ); 00892 storeNewCharPtr( &structuring->contentTypeCode, 00893 GPGMEPLUG_ENCSIGN_CTYPE_CODE ); 00894 storeNewCharPtr( &structuring->contentDispCode, 00895 GPGMEPLUG_ENCSIGN_CDISP_CODE ); 00896 storeNewCharPtr( &structuring->contentTEncCode, 00897 GPGMEPLUG_ENCSIGN_CTENC_CODE ); 00898 } 00899 } else { 00900 storeNewCharPtr( &structuring->flatTextPrefix, 00901 GPGMEPLUG_ENCSIGN_FLAT_PREFIX ); 00902 storeNewCharPtr( &structuring->flatTextSeparator, 00903 GPGMEPLUG_ENCSIGN_FLAT_SEPARATOR ); 00904 storeNewCharPtr( &structuring->flatTextPostfix, 00905 GPGMEPLUG_ENCSIGN_FLAT_POSTFIX ); 00906 } 00907 } 00908 return bOk; 00909 } 00910 00911 00912 bool CryptPlug::decryptMessage( const char* ciphertext, 00913 bool cipherIsBinary, 00914 int cipherLen, 00915 const char** cleartext, 00916 const char* /*certificate*/, 00917 int* errId, 00918 char** errTxt ) 00919 { 00920 gpgme_ctx_t ctx; 00921 gpgme_error_t err; 00922 gpgme_data_t gCiphertext, gPlaintext; 00923 size_t rCLen = 0; 00924 char* rCiph = 0; 00925 bool bOk = false; 00926 00927 if( !ciphertext ) 00928 return false; 00929 00930 err = gpgme_new (&ctx); 00931 gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL); 00932 00933 gpgme_set_armor (ctx, cipherIsBinary ? 0 : 1); 00934 /* gpgme_set_textmode (ctx, cipherIsBinary ? 0 : 1); */ 00935 00936 /* 00937 gpgme_data_new_from_mem( &gCiphertext, ciphertext, 00938 1+strlen( ciphertext ), 1 ); */ 00939 gpgme_data_new_from_mem( &gCiphertext, 00940 ciphertext, 00941 cipherIsBinary 00942 ? cipherLen 00943 : strlen( ciphertext ), 00944 1 ); 00945 00946 gpgme_data_new( &gPlaintext ); 00947 00948 err = gpgme_op_decrypt( ctx, gCiphertext, gPlaintext ); 00949 if( err ) { 00950 fprintf( stderr, "\ngpgme_op_decrypt() returned this error code: %i\n\n", err ); 00951 if( errId ) 00952 *errId = err; 00953 if( errTxt ) { 00954 const char* _errTxt = gpgme_strerror( err ); 00955 *errTxt = (char*)malloc( strlen( _errTxt ) + 1 ); 00956 if( *errTxt ) 00957 strcpy(*errTxt, _errTxt ); 00958 } 00959 } 00960 00961 gpgme_data_release( gCiphertext ); 00962 00963 rCiph = gpgme_data_release_and_get_mem( gPlaintext, &rCLen ); 00964 00965 *cleartext = (char*)malloc( rCLen + 1 ); 00966 if( *cleartext ) { 00967 if( rCLen ) { 00968 bOk = true; 00969 strncpy((char*)*cleartext, rCiph, rCLen ); 00970 } 00971 ((char*)(*cleartext))[rCLen] = 0; 00972 } 00973 00974 free( rCiph ); 00975 gpgme_release( ctx ); 00976 return bOk; 00977 } 00978 00979 00980 static char * 00981 trim_trailing_spaces( char *string ) 00982 { 00983 char *p, *mark; 00984 00985 for( mark = NULL, p = string; *p; p++ ) { 00986 if( isspace( *p ) ) { 00987 if( !mark ) 00988 mark = p; 00989 } 00990 else 00991 mark = NULL; 00992 } 00993 if( mark ) 00994 *mark = '\0' ; 00995 00996 return string ; 00997 } 00998 00999 /* Parse a DN and return an array-ized one. This is not a validating 01000 parser and it does not support any old-stylish syntax; gpgme is 01001 expected to return only rfc2253 compatible strings. */ 01002 static const unsigned char * 01003 parse_dn_part (CryptPlug::DnPair *array, const unsigned char *string) 01004 { 01005 const unsigned char *s, *s1; 01006 size_t n; 01007 char *p; 01008 01009 /* parse attributeType */ 01010 for (s = string+1; *s && *s != '='; s++) 01011 ; 01012 if (!*s) 01013 return NULL; /* error */ 01014 n = s - string; 01015 if (!n) 01016 return NULL; /* empty key */ 01017 p = (char*)xmalloc (n+1); 01018 01019 01020 memcpy (p, string, n); 01021 p[n] = 0; 01022 trim_trailing_spaces ((char*)p); 01023 // map OIDs to their names: 01024 for ( unsigned int i = 0 ; i < numOidMaps ; ++i ) 01025 if ( !strcasecmp ((char*)p, oidmap[i].oid) ) { 01026 free( p ); 01027 p = xstrdup (oidmap[i].name); 01028 break; 01029 } 01030 array->key = p; 01031 string = s + 1; 01032 01033 if (*string == '#') 01034 { /* hexstring */ 01035 string++; 01036 for (s=string; hexdigitp (s); s++) 01037 s++; 01038 n = s - string; 01039 if (!n || (n & 1)) 01040 return NULL; /* empty or odd number of digits */ 01041 n /= 2; 01042 array->value = p = (char*)xmalloc (n+1); 01043 01044 01045 for (s1=string; n; s1 += 2, n--) 01046 *p++ = xtoi_2 (s1); 01047 *p = 0; 01048 } 01049 else 01050 { /* regular v3 quoted string */ 01051 for (n=0, s=string; *s; s++) 01052 { 01053 if (*s == '\\') 01054 { /* pair */ 01055 s++; 01056 if (*s == ',' || *s == '=' || *s == '+' 01057 || *s == '<' || *s == '>' || *s == '#' || *s == ';' 01058 || *s == '\\' || *s == '\"' || *s == ' ') 01059 n++; 01060 else if (hexdigitp (s) && hexdigitp (s+1)) 01061 { 01062 s++; 01063 n++; 01064 } 01065 else 01066 return NULL; /* invalid escape sequence */ 01067 } 01068 else if (*s == '\"') 01069 return NULL; /* invalid encoding */ 01070 else if (*s == ',' || *s == '=' || *s == '+' 01071 || *s == '<' || *s == '>' || *s == '#' || *s == ';' ) 01072 break; 01073 else 01074 n++; 01075 } 01076 01077 array->value = p = (char*)xmalloc (n+1); 01078 01079 01080 for (s=string; n; s++, n--) 01081 { 01082 if (*s == '\\') 01083 { 01084 s++; 01085 if (hexdigitp (s)) 01086 { 01087 *p++ = xtoi_2 (s); 01088 s++; 01089 } 01090 else 01091 *p++ = *s; 01092 } 01093 else 01094 *p++ = *s; 01095 } 01096 *p = 0; 01097 } 01098 return s; 01099 } 01100 01101 01102 /* Parse a DN and return an array-ized one. This is not a validating 01103 parser and it does not support any old-stylish syntax; gpgme is 01104 expected to return only rfc2253 compatible strings. */ 01105 static CryptPlug::DnPair * 01106 parse_dn (const unsigned char *string) 01107 { 01108 struct CryptPlug::DnPair *array; 01109 size_t arrayidx, arraysize; 01110 01111 if( !string ) 01112 return NULL; 01113 01114 arraysize = 7; /* C,ST,L,O,OU,CN,email */ 01115 arrayidx = 0; 01116 array = (CryptPlug::DnPair*)xmalloc ((arraysize+1) * sizeof *array); 01117 01118 01119 while (*string) 01120 { 01121 while (*string == ' ') 01122 string++; 01123 if (!*string) 01124 break; /* ready */ 01125 if (arrayidx >= arraysize) 01126 { /* mutt lacks a real safe_realoc - so we need to copy */ 01127 struct CryptPlug::DnPair *a2; 01128 01129 arraysize += 5; 01130 a2 = (CryptPlug::DnPair*)xmalloc ((arraysize+1) * sizeof *array); 01131 for (unsigned int i=0; i < arrayidx; i++) 01132 { 01133 a2[i].key = array[i].key; 01134 a2[i].value = array[i].value; 01135 } 01136 free (array); 01137 array = a2; 01138 } 01139 array[arrayidx].key = NULL; 01140 array[arrayidx].value = NULL; 01141 string = parse_dn_part (array+arrayidx, string); 01142 arrayidx++; 01143 if (!string) 01144 goto failure; 01145 while (*string == ' ') 01146 string++; 01147 if (*string && *string != ',' && *string != ';' && *string != '+') 01148 goto failure; /* invalid delimiter */ 01149 if (*string) 01150 string++; 01151 } 01152 array[arrayidx].key = NULL; 01153 array[arrayidx].value = NULL; 01154 return array; 01155 01156 failure: 01157 for (unsigned i=0; i < arrayidx; i++) 01158 { 01159 free (array[i].key); 01160 free (array[i].value); 01161 } 01162 free (array); 01163 return NULL; 01164 } 01165 01166 static void 01167 add_dn_part( QCString& result, struct CryptPlug::DnPair& dnPair ) 01168 { 01169 /* email hack */ 01170 QCString mappedPart( dnPair.key ); 01171 for ( unsigned int i = 0 ; i < numOidMaps ; ++i ){ 01172 if( !strcasecmp( dnPair.key, oidmap[i].oid ) ) { 01173 mappedPart = oidmap[i].name; 01174 break; 01175 } 01176 } 01177 result.append( mappedPart ); 01178 result.append( "=" ); 01179 result.append( dnPair.value ); 01180 } 01181 01182 static int 01183 add_dn_parts( QCString& result, struct CryptPlug::DnPair* dn, const char* part ) 01184 { 01185 int any = 0; 01186 01187 if( dn ) { 01188 for(; dn->key; ++dn ) { 01189 if( !strcmp( dn->key, part ) ) { 01190 if( any ) 01191 result.append( "," ); 01192 add_dn_part( result, *dn ); 01193 any = 1; 01194 } 01195 } 01196 } 01197 return any; 01198 } 01199 01200 static char* 01201 reorder_dn( struct CryptPlug::DnPair *dn, 01202 char** attrOrder = 0, 01203 const char* unknownAttrsHandling = 0 ) 01204 { 01205 struct CryptPlug::DnPair *dnOrg = dn; 01206 01207 /* note: The must parts are: CN, L, OU, O, C */ 01208 const char* defaultpart[] = { 01209 "CN", "S", "SN", "GN", "T", "UID", 01210 "MAIL", "EMAIL", "MOBILE", "TEL", "FAX", "STREET", 01211 "L", "PC", "SP", "ST", 01212 "OU", 01213 "O", 01214 "C", 01215 NULL 01216 }; 01217 const char** stdpart = attrOrder ? ((const char**)attrOrder) : defaultpart; 01218 int any=0, any2=0, found_X_=0, i; 01219 QCString result; 01220 QCString resultUnknowns; 01221 01222 /* find and save the non-standard parts in their original order */ 01223 if( dn ){ 01224 for(; dn->key; ++dn ) { 01225 for( i = 0; stdpart[i]; ++i ) { 01226 if( !strcmp( dn->key, stdpart[i] ) ) { 01227 break; 01228 } 01229 } 01230 if( !stdpart[i] ) { 01231 if( any2 ) 01232 resultUnknowns.append( "," ); 01233 add_dn_part( resultUnknowns, *dn ); 01234 any2 = 1; 01235 } 01236 } 01237 dn = dnOrg; 01238 } 01239 01240 /* prepend the unknown attrs if desired */ 01241 if( unknownAttrsHandling && 01242 !strcmp(unknownAttrsHandling, "PREFIX") 01243 && *resultUnknowns ){ 01244 result.append( resultUnknowns ); 01245 any = 1; 01246 }else{ 01247 any = 0; 01248 } 01249 01250 /* add standard parts */ 01251 for( i = 0; stdpart[i]; ++i ) { 01252 dn = dnOrg; 01253 if( any ) { 01254 result.append( "," ); 01255 } 01256 if( any2 && 01257 !strcmp(stdpart[i], "_X_") && 01258 unknownAttrsHandling && 01259 !strcmp(unknownAttrsHandling, "INFIX") ){ 01260 if ( !resultUnknowns.isEmpty() ) { 01261 result.append( resultUnknowns ); 01262 any = 1; 01263 } 01264 found_X_ = 1; 01265 }else{ 01266 any = add_dn_parts( result, dn, stdpart[i] ); 01267 } 01268 } 01269 01270 /* append the unknown attrs if desired */ 01271 if( !unknownAttrsHandling || 01272 !strcmp(unknownAttrsHandling, "POSTFIX") || 01273 ( !strcmp(unknownAttrsHandling, "INFIX") && !found_X_ ) ){ 01274 if( !resultUnknowns.isEmpty() ) { 01275 if( any ){ 01276 result.append( "," ); 01277 } 01278 result.append( resultUnknowns ); 01279 } 01280 } 01281 01282 char* cResult = (char*)xmalloc( (result.length()+1)*sizeof(char) ); 01283 if( result.isEmpty() ) 01284 *cResult = 0; 01285 else 01286 strcpy( cResult, result ); 01287 return cResult; 01288 } 01289 01290 struct CryptPlug::CertIterator { 01291 gpgme_ctx_t ctx; 01292 struct CertificateInfo info; 01293 }; 01294 01295 CryptPlug::CertIterator* 01296 CryptPlug::startListCertificates( const char* pattern, int remote ) 01297 { 01298 gpgme_error_t err; 01299 struct CertIterator* it; 01300 const char* patterns[] = { pattern, NULL }; 01301 fprintf( stderr, "startListCertificates( \"%s\", %d )\n", pattern, remote ); 01302 01303 it = (CertIterator*)xmalloc( sizeof( struct CertIterator ) ); 01304 01305 err = gpgme_new (&(it->ctx)); 01306 /*fprintf( stderr, "2: gpgme returned %d\n", err );*/ 01307 if( err ) { 01308 free( it ); 01309 return NULL; 01310 } 01311 01312 gpgme_set_protocol (it->ctx, GPGME_PROTOCOL_CMS); 01313 if( remote ) gpgme_set_keylist_mode ( it->ctx, GPGME_KEYLIST_MODE_EXTERN ); 01314 else gpgme_set_keylist_mode ( it->ctx, GPGME_KEYLIST_MODE_LOCAL ); 01315 err = gpgme_op_keylist_ext_start ( it->ctx, patterns, 0, 0); 01316 memset( &(it->info), 0, sizeof( struct CertificateInfo ) ); 01317 if( err ) { 01318 fprintf( stderr, "gpgme_op_keylist_ext_start returned %d", err ); 01319 endListCertificates( it ); 01320 return NULL; 01321 } 01322 return it; 01323 } 01324 01325 /* free() each string in a char*[] and the array itself */ 01326 static void 01327 freeStringArray( char** c ) 01328 { 01329 char** _c = c; 01330 01331 while( c && *c ) { 01332 /*fprintf( stderr, "freeing \"%s\"\n", *c );*/ 01333 free( *c ); 01334 ++c; 01335 } 01336 free( _c ); 01337 } 01338 01339 /* free all malloc'ed data in a struct CertificateInfo */ 01340 static void 01341 freeInfo( struct CryptPlug::CertificateInfo* info ) 01342 { 01343 struct CryptPlug::DnPair* a = info->dnarray; 01344 assert( info ); 01345 freeStringArray( info->userid ); 01346 free( info->serial); 01347 free( info->fingerprint ); 01348 free( info->issuer_org ); 01349 free( info->issuer_reord ); 01350 free( info->chainid ); 01351 free( info->caps ); 01352 while( a && a->key && a->value ) { 01353 free (a->key); 01354 free (a->value); 01355 ++a; 01356 } 01357 free (info->dnarray); 01358 memset( info, 0, sizeof( *info ) ); 01359 } 01360 01361 /* Format the fingerprint nicely. The caller should 01362 free the returned value using free() */ 01363 static char* make_fingerprint( const char* fpr ) 01364 { 01365 int len = strlen(fpr); 01366 int i = 0; 01367 char* result = (char*)xmalloc( (len + len/2 + 1)*sizeof(char) ); 01368 01369 for(; *fpr; ++fpr, ++i ) { 01370 if( i%3 == 2) { 01371 result[i] = ':'; ++i; 01372 } 01373 result[i] = *fpr; 01374 } 01375 result[i] = 0; 01376 return result; 01377 } 01378 01379 // from gpgme 0.4.3: 01380 static const char * 01381 capabilities_to_string (gpgme_subkey_t subkey) 01382 { 01383 static const char *const strings[8] = 01384 { 01385 "", 01386 "c", 01387 "s", 01388 "sc", 01389 "e", 01390 "ec", 01391 "es", 01392 "esc" 01393 }; 01394 return strings[(!!subkey->can_encrypt << 2) 01395 | (!!subkey->can_sign << 1) 01396 | (!!subkey->can_certify)]; 01397 } 01398 01399 int 01400 CryptPlug::nextCertificate( CryptPlug::CertIterator* it, 01401 CryptPlug::CertificateInfo** result, 01402 char** attrOrder, 01403 const char* unknownAttrsHandling ) 01404 { 01405 gpgme_error_t err; 01406 gpgme_key_t key; 01407 int retval = GPG_ERR_NO_ERROR; 01408 assert( it ); 01409 fprintf( stderr, "nextCertificates( %p, %p )\n", it, result ); 01410 err = gpgme_op_keylist_next ( it->ctx, &key); 01411 if( !err ) { 01412 int idx; 01413 const char* s = 0; 01414 unsigned long u; 01415 char* names[MAX_GPGME_IDX+1]; 01416 struct DnPair *issuer_dn, *tmp_dn; 01417 retval = err; 01418 memset( names, 0, sizeof( names ) ); 01419 freeInfo( &(it->info) ); 01420 01421 std::cerr << "nextCertificate..." << std::endl; 01422 if ( key ) { 01423 idx = 0; 01424 for ( gpgme_user_id_t uid = key->uids ; uid && idx < MAX_GPGME_IDX ; uid = uid->next, ++idx ) 01425 names[idx] = xstrdup( uid->uid ); 01426 } 01427 std::cerr << "DEBUG: " << s << ":" << names[0] << std::endl; 01428 it->info.userid = (char**)xmalloc( sizeof( char* ) * (idx+1) ); 01429 memset( it->info.userid, 0, sizeof( char* ) * (idx+1) ); 01430 it->info.dnarray = 0; 01431 for( idx = 0; names[idx] != 0; ++idx ) { 01432 01433 struct DnPair* a = parse_dn( (unsigned char*)names[idx] ); 01434 it->info.userid[idx] = reorder_dn( a, attrOrder, unknownAttrsHandling ); 01435 01436 if( idx == 0 ) { 01437 it->info.userid_0_org = names[idx]; 01438 it->info.dnarray = a; 01439 }else{ 01440 free (names[idx]); 01441 names[idx] = NULL; 01442 while( a && a->key && a->value ) { 01443 free( a->key ); 01444 free( a->value ); 01445 ++a; 01446 } 01447 } 01448 } 01449 it->info.userid[idx] = 0; 01450 01451 s = key->issuer_serial; 01452 it->info.serial = s? xstrdup(s) : NULL; 01453 01454 s = key->subkeys ? key->subkeys->fpr : 0 ; 01455 it->info.fingerprint = make_fingerprint( s ); 01456 01457 s = key->issuer_name; 01458 it->info.issuer_org = s? xstrdup(s): NULL; 01459 if( s ) { 01460 issuer_dn = tmp_dn = parse_dn( (const unsigned char*)s ); 01461 /*it->info.issuer = xstrdup(s);*/ 01462 it->info.issuer_reord = reorder_dn( issuer_dn, attrOrder, unknownAttrsHandling ); 01463 while( tmp_dn && tmp_dn->key ) { 01464 free( tmp_dn->key ); 01465 free( tmp_dn->value ); 01466 ++tmp_dn; 01467 } 01468 free( issuer_dn ); 01469 issuer_dn = tmp_dn = NULL; 01470 } else { 01471 it->info.issuer_reord = NULL; 01472 } 01473 s = key->chain_id; 01474 it->info.chainid = s? xstrdup(s): NULL; 01475 01476 s = key->subkeys ? capabilities_to_string( key->subkeys ) : 0 ; 01477 it->info.caps = s? xstrdup(s) : NULL; 01478 01479 u = key->subkeys && key->subkeys->timestamp >= 0 ? key->subkeys->timestamp : 0 ; 01480 it->info.created = u; 01481 01482 u = key->subkeys && key->subkeys->expires >= 0 ? key->subkeys->expires : 0 ; 01483 it->info.expire = u; 01484 01485 u = key->secret; 01486 it->info.secret = u; 01487 01488 u = key->uids ? key->uids->invalid : 0 ; 01489 it->info.invalid = u; 01490 01491 u = key->subkeys ? key->subkeys->expired : 0 ; 01492 it->info.expired = u; 01493 01494 u = key->subkeys ? key->subkeys->disabled : 0 ; 01495 it->info.disabled = u; 01496 01497 my_gpgme_key_release (key); 01498 /*return &(it->info);*/ 01499 *result = &(it->info); 01500 } else { 01501 *result = NULL; 01502 } 01503 return retval; 01504 } 01505 01506 int 01507 CryptPlug::endListCertificates( CryptPlug::CertIterator* it ) 01508 { 01509 fprintf( stderr, "endListCertificates( %p )\n", it ); 01510 assert(it); 01511 gpgme_keylist_result_t result = gpgme_op_keylist_result( it->ctx ); 01512 int truncated = result && result->truncated; 01513 freeInfo( &(it->info) ); 01514 gpgme_op_keylist_end(it->ctx); 01515 gpgme_release (it->ctx); 01516 free( it ); 01517 return truncated; 01518 } 01519 01520 GpgME::ImportResult CryptPlug::importCertificateFromMem( const char* data, size_t length ) 01521 { 01522 using namespace GpgME; 01523 01524 std::auto_ptr<Context> context( Context::createForProtocol( mProtocol ) ); 01525 if ( !context.get() ) 01526 return ImportResult(); 01527 01528 Data keydata( data, length, false ); 01529 if ( keydata.isNull() ) 01530 return ImportResult(); 01531 01532 return context->importKeys( keydata ); 01533 } 01534 01535 01536 /* == == == == == == == == == == == == == == == == == == == == == == == == == 01537 == == 01538 == Continuation of CryptPlug code == 01539 == == 01540 == == == == == == == == == == == == == == == == == == == == == == == == == */ 01541 01542 01543 /* 01544 Find all certificate for a given addressee and return them in a 01545 '\1' separated list. 01546 NOTE: The certificate parameter must point to a not-yet allocated 01547 char*. The function will allocate the memory needed and 01548 return the size in newSize. 01549 If secretOnly is true, only secret keys are returned. 01550 */ 01551 bool CryptPlug::findCertificates( const char* addressee, 01552 char** certificates, 01553 int* newSize, 01554 bool secretOnly, 01555 char** attrOrder, 01556 const char* unknownAttrsHandling ) 01557 { 01558 #define MAXCERTS 1024 01559 /* use const char declarations since all of them are needed twice */ 01560 const char* delimiter = "\1"; 01561 const char* openBracket = " ("; 01562 const char* closeBracket = ")"; 01563 01564 gpgme_ctx_t ctx; 01565 gpgme_error_t err; 01566 gpgme_key_t rKey; 01567 const char *s; 01568 const char *s2; 01569 char* dn; 01570 struct DnPair* a; 01571 int nFound = 0; 01572 int iFound = 0; 01573 int siz = 0; 01574 char* DNs[MAXCERTS]; 01575 char* FPRs[MAXCERTS]; 01576 01577 if( ! certificates ){ 01578 fprintf( stderr, "gpgme: findCertificates called with invalid *certificates pointer\n" ); 01579 return false; 01580 } 01581 01582 if( ! newSize ){ 01583 fprintf( stderr, "gpgme: findCertificates called with invalid newSize pointer\n" ); 01584 return false; 01585 } 01586 01587 *certificates = 0; 01588 *newSize = 0; 01589 01590 /* calculate length of buffer needed for certs plus fingerprints */ 01591 gpgme_new (&ctx); 01592 gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL); 01593 err = gpgme_op_keylist_start(ctx, addressee, secretOnly ? 1 : 0); 01594 while( !err ) { 01595 err = gpgme_op_keylist_next(ctx, &rKey); 01596 if( !err ) { 01597 s = rKey && rKey->uids ? rKey->uids->uid : 0 ; 01598 if( s ) { 01599 dn = xstrdup( s ); 01600 s2 = rKey && rKey->subkeys ? rKey->subkeys->fpr : 0 ; 01601 if( s2 ) { 01602 if( nFound ) 01603 siz += strlen( delimiter ); 01604 01605 //fprintf( stderr, "gpgme: before reordering (%s)\n", dn ); 01606 01607 a = parse_dn( (unsigned char*)dn ); 01608 free( dn ); 01609 dn = reorder_dn( a, attrOrder, unknownAttrsHandling ); 01610 01611 //fprintf( stderr, "gpgme: after reordering (%s)\n\n", dn ); 01612 01613 siz += strlen( dn ); 01614 siz += strlen( openBracket ); 01615 siz += strlen( s2 ); 01616 siz += strlen( closeBracket ); 01617 DNs[ nFound ] = dn; 01618 dn = NULL; /* prevent it from being free'ed below. */ 01619 FPRs[nFound ] = xstrdup( s2 ); 01620 ++nFound; 01621 if( nFound >= MAXCERTS ) { 01622 fprintf( stderr, 01623 "gpgme: findCertificates found too many certificates (%d)\n", 01624 MAXCERTS ); 01625 break; 01626 } 01627 } 01628 free (dn); 01629 } 01630 } 01631 } 01632 gpgme_op_keylist_end( ctx ); 01633 gpgme_release (ctx); 01634 01635 01636 if( 0 < siz ) { 01637 /* add one for trailing ZERO char */ 01638 ++siz; 01639 *newSize = siz; 01640 /* allocate the buffer */ 01641 *certificates = (char*)xmalloc( sizeof(char) * siz ); 01642 memset( *certificates, 0, sizeof(char) * siz ); 01643 /* fill the buffer */ 01644 for (iFound=0; iFound < nFound; iFound++) { 01645 if( !iFound ) 01646 strcpy(*certificates, DNs[iFound] ); 01647 else { 01648 strcat(*certificates, delimiter ); 01649 strcat(*certificates, DNs[iFound] ); 01650 } 01651 strcat( *certificates, openBracket ); 01652 strcat( *certificates, FPRs[iFound] ); 01653 strcat( *certificates, closeBracket ); 01654 free( DNs[ iFound ] ); 01655 free( FPRs[iFound ] ); 01656 } 01657 } 01658 01659 return ( 0 < nFound ); 01660 } 01661 01662 // these are from gpgme-0.4.3: 01663 static gpgme_sig_stat_t 01664 sig_stat_from_status( gpgme_error_t err ) 01665 { 01666 switch ( gpg_err_code(err) ) { 01667 case GPG_ERR_NO_ERROR: 01668 return GPGME_SIG_STAT_GOOD; 01669 case GPG_ERR_BAD_SIGNATURE: 01670 return GPGME_SIG_STAT_BAD; 01671 case GPG_ERR_NO_PUBKEY: 01672 return GPGME_SIG_STAT_NOKEY; 01673 case GPG_ERR_NO_DATA: 01674 return GPGME_SIG_STAT_NOSIG; 01675 case GPG_ERR_SIG_EXPIRED: 01676 return GPGME_SIG_STAT_GOOD_EXP; 01677 case GPG_ERR_KEY_EXPIRED: 01678 return GPGME_SIG_STAT_GOOD_EXPKEY; 01679 default: 01680 return GPGME_SIG_STAT_ERROR; 01681 } 01682 } 01683 01684 01685 static gpgme_sig_stat_t 01686 intersect_stati( gpgme_signature_t first ) 01687 { 01688 if ( !first ) 01689 return GPGME_SIG_STAT_NONE; 01690 gpgme_sig_stat_t result = sig_stat_from_status( first->status ); 01691 for ( gpgme_signature_t sig = first->next ; sig ; sig = sig->next ) 01692 if ( sig_stat_from_status( sig->status ) != result ) 01693 return GPGME_SIG_STAT_DIFF; 01694 return result; 01695 } 01696 01697 static const char* 01698 sig_status_to_string( gpgme_sig_stat_t status ) 01699 { 01700 const char *result; 01701 01702 switch (status) { 01703 case GPGME_SIG_STAT_NONE: 01704 result = "Oops: Signature not verified"; 01705 break; 01706 case GPGME_SIG_STAT_NOSIG: 01707 result = "No signature found"; 01708 break; 01709 case GPGME_SIG_STAT_GOOD: 01710 result = "Good signature"; 01711 break; 01712 case GPGME_SIG_STAT_BAD: 01713 result = "BAD signature"; 01714 break; 01715 case GPGME_SIG_STAT_NOKEY: 01716 result = "No public key to verify the signature"; 01717 break; 01718 case GPGME_SIG_STAT_ERROR: 01719 result = "Error verifying the signature"; 01720 break; 01721 case GPGME_SIG_STAT_DIFF: 01722 result = "Different results for signatures"; 01723 break; 01724 default: 01725 result = "Error: Unknown status"; 01726 break; 01727 } 01728 01729 return result; 01730 } 01731 01732 // WARNING: if you fix a bug here, you have to likely fix it in the 01733 // gpgme 0.3 version below, too! 01734 static 01735 void obtain_signature_information( gpgme_ctx_t ctx, 01736 gpgme_sig_stat_t & overallStatus, 01737 struct CryptPlug::SignatureMetaData* sigmeta, 01738 char** attrOrder, 01739 const char* unknownAttrsHandling, 01740 bool * signatureFound=0 ) 01741 { 01742 gpgme_error_t err; 01743 unsigned long sumGPGME; 01744 SigStatusFlags sumPlug; 01745 struct CryptPlug::DnPair* a; 01746 int sig_idx=0; 01747 01748 assert( ctx ); 01749 assert( sigmeta ); 01750 01751 sigmeta->extended_info = 0; 01752 gpgme_verify_result_t result = gpgme_op_verify_result( ctx ); 01753 if ( !result ) 01754 return; 01755 for ( gpgme_signature_t signature = result->signatures ; signature ; signature = signature->next, ++sig_idx ) { 01756 void* alloc_return = realloc( sigmeta->extended_info, 01757 sizeof( CryptPlug::SignatureMetaDataExtendedInfo ) 01758 * ( sig_idx + 1 ) ); 01759 if ( !alloc_return ) 01760 break; 01761 sigmeta->extended_info = (CryptPlug::SignatureMetaDataExtendedInfo*)alloc_return; 01762 01763 /* shorthand notation :) */ 01764 CryptPlug::SignatureMetaDataExtendedInfo & this_info = sigmeta->extended_info[sig_idx]; 01765 01766 /* clear the data area */ 01767 memset( &this_info, 0, sizeof (CryptPlug::SignatureMetaDataExtendedInfo) ); 01768 01769 /* the creation time */ 01770 if ( signature->timestamp ) { 01771 this_info.creation_time = (tm*)malloc( sizeof( struct tm ) ); 01772 if ( this_info.creation_time ) { 01773 struct tm * ctime_val = localtime( (time_t*)&signature->timestamp ); 01774 memcpy( this_info.creation_time, 01775 ctime_val, sizeof( struct tm ) ); 01776 } 01777 } 01778 01779 /* the extended signature verification status */ 01780 sumGPGME = signature->summary; 01781 fprintf( stderr, "gpgmeplug checkMessageSignature status flags: %lX\n", sumGPGME ); 01782 /* translate GPGME status flags to common CryptPlug status flags */ 01783 sumPlug = 0; 01784 #define convert(X) if ( sumGPGME & GPGME_SIGSUM_##X ) sumPlug |= SigStat_##X 01785 convert(VALID); 01786 convert(GREEN); 01787 convert(RED); 01788 convert(KEY_REVOKED); 01789 convert(KEY_EXPIRED); 01790 convert(SIG_EXPIRED); 01791 convert(KEY_MISSING); 01792 convert(CRL_MISSING); 01793 convert(CRL_TOO_OLD); 01794 convert(BAD_POLICY); 01795 convert(SYS_ERROR); 01796 #undef convert 01797 if( sumGPGME && !sumPlug ) 01798 sumPlug = SigStat_NUMERICAL_CODE | sumGPGME; 01799 this_info.sigStatusFlags = sumPlug; 01800 01801 /* extract finger print */ 01802 if ( signature->fpr ) 01803 storeNewCharPtr( &this_info.fingerprint, signature->fpr ); 01804 01805 /* validity */ 01806 this_info.validity = GPGME_VALIDITY_UNKNOWN; 01807 01808 /* sig key data */ 01809 gpgme_key_t key = 0; 01810 // PENDING(marc) if this is deprecated, how shall we get at all 01811 // the infos below? 01812 err = gpgme_get_sig_key (ctx, sig_idx, &key); 01813 01814 if ( !err && key ) { 01815 const char* attr_string; 01816 unsigned long attr_ulong; 01817 01818 /* extract key identidy */ 01819 attr_string = key->subkeys ? key->subkeys->keyid : 0 ; 01820 if ( attr_string ) 01821 storeNewCharPtr( &this_info.keyid, attr_string ); 01822 01823 /* pubkey algorithm */ 01824 attr_string = key->subkeys ? gpgme_pubkey_algo_name( key->subkeys->pubkey_algo ) : 0 ; 01825 if (attr_string != 0) 01826 storeNewCharPtr( &this_info.algo, attr_string ); 01827 attr_ulong = key->subkeys ? key->subkeys->pubkey_algo : 0 ; 01828 this_info.algo_num = attr_ulong; 01829 01830 /* extract key validity */ 01831 attr_ulong = key->uids ? key->uids->validity : 0 ; 01832 this_info.validity = attr_ulong; 01833 01834 /* extract user id, according to the documentation it's representable 01835 * as a number, but it seems that it also has a string representation 01836 */ 01837 attr_string = key->uids ? key->uids->uid : 0 ; 01838 if (attr_string != 0) { 01839 a = parse_dn( (const unsigned char*)attr_string ); 01840 this_info.userid = reorder_dn( a, attrOrder, unknownAttrsHandling ); 01841 } 01842 01843 attr_ulong = 0; 01844 this_info.userid_num = attr_ulong; 01845 01846 /* extract the length */ 01847 this_info.keylen = key->subkeys ? key->subkeys->length : 0 ; 01848 01849 /* extract the creation time of the key */ 01850 attr_ulong = key->subkeys ? key->subkeys->timestamp : 0 ; 01851 this_info.key_created = attr_ulong; 01852 01853 /* extract the expiration time of the key */ 01854 attr_ulong = key->subkeys ? key->subkeys->expires : 0 ; 01855 this_info.key_expires = attr_ulong; 01856 01857 /* extract user name */ 01858 attr_string = key->uids ? key->uids->name : 0 ; 01859 if (attr_string != 0) { 01860 a = parse_dn( (const unsigned char*)attr_string ); 01861 this_info.name = reorder_dn( a, attrOrder, unknownAttrsHandling ); 01862 } 01863 01864 /* extract email(s) */ 01865 this_info.emailCount = 0; 01866 this_info.emailList = 0; 01867 for ( gpgme_user_id_t uid = key->uids ; uid ; uid = uid->next ) { 01868 attr_string = uid->email; 01869 if ( attr_string && *attr_string) { 01870 fprintf( stderr, "gpgmeplug checkMessageSignature found email: %s\n", attr_string ); 01871 if( !this_info.emailCount ) 01872 alloc_return = malloc( sizeof( char*) ); 01873 else 01874 alloc_return = realloc( this_info.emailList, 01875 sizeof( char*) 01876 * (this_info.emailCount + 1) ); 01877 if( alloc_return ) { 01878 this_info.emailList = (char**)alloc_return; 01879 storeNewCharPtr( &( this_info.emailList[ this_info.emailCount ] ), 01880 attr_string ); 01881 ++this_info.emailCount; 01882 } 01883 } 01884 } 01885 if( !this_info.emailCount ) 01886 fprintf( stderr, "gpgmeplug checkMessageSignature found NO EMAIL\n" ); 01887 01888 /* extract the comment */ 01889 attr_string = key->uids ? key->uids->comment : 0 ; 01890 if (attr_string != 0) 01891 storeNewCharPtr( &this_info.comment, attr_string ); 01892 } 01893 01894 gpgme_sig_stat_t status = sig_stat_from_status( signature->status ); 01895 const char* sig_status = sig_status_to_string( status ); 01896 storeNewCharPtr( &this_info.status_text, sig_status ); 01897 } 01898 sigmeta->extended_info_count = sig_idx; 01899 overallStatus = intersect_stati( result->signatures ); 01900 sigmeta->status_code = overallStatus; 01901 storeNewCharPtr( &sigmeta->status, sig_status_to_string( overallStatus ) ); 01902 if ( signatureFound ) 01903 *signatureFound = ( overallStatus != GPGME_SIG_STAT_NONE ); 01904 } 01905 01906 01907 bool CryptPlug::checkMessageSignature( char** cleartext, 01908 const char* signaturetext, 01909 bool signatureIsBinary, 01910 int signatureLen, 01911 struct CryptPlug::SignatureMetaData* sigmeta, 01912 char** attrOrder, 01913 const char* unknownAttrsHandling ) 01914 { 01915 gpgme_ctx_t ctx; 01916 gpgme_sig_stat_t status = GPGME_SIG_STAT_NONE; 01917 gpgme_data_t datapart, sigpart; 01918 char* rClear = 0; 01919 size_t clearLen; 01920 bool isOpaqueSigned; 01921 01922 if( !cleartext ) { 01923 if( sigmeta ) 01924 storeNewCharPtr( &sigmeta->status, 01925 __GPGMEPLUG_ERROR_CLEARTEXT_IS_ZERO ); 01926 01927 return false; 01928 } 01929 01930 isOpaqueSigned = !*cleartext; 01931 01932 gpgme_new( &ctx ); 01933 gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL); 01934 gpgme_set_armor (ctx, signatureIsBinary ? 0 : 1); 01935 /* gpgme_set_textmode (ctx, signatureIsBinary ? 0 : 1); */ 01936 01937 if( isOpaqueSigned ) 01938 gpgme_data_new( &datapart ); 01939 else 01940 gpgme_data_new_from_mem( &datapart, *cleartext, 01941 strlen( *cleartext ), 1 ); 01942 01943 gpgme_data_new_from_mem( &sigpart, 01944 signaturetext, 01945 signatureIsBinary 01946 ? signatureLen 01947 : strlen( signaturetext ), 01948 1 ); 01949 01950 if ( isOpaqueSigned ) 01951 gpgme_op_verify( ctx, sigpart, 0, datapart ); 01952 else 01953 gpgme_op_verify( ctx, sigpart, datapart, 0 ); 01954 01955 if( isOpaqueSigned ) { 01956 rClear = gpgme_data_release_and_get_mem( datapart, &clearLen ); 01957 *cleartext = (char*)malloc( clearLen + 1 ); 01958 if( *cleartext ) { 01959 if( clearLen ) 01960 strncpy(*cleartext, rClear, clearLen ); 01961 (*cleartext)[clearLen] = '\0'; 01962 } 01963 free( rClear ); 01964 } 01965 else 01966 gpgme_data_release( datapart ); 01967 01968 gpgme_data_release( sigpart ); 01969 01970 obtain_signature_information( ctx, status, sigmeta, 01971 attrOrder, unknownAttrsHandling ); 01972 01973 gpgme_release( ctx ); 01974 return ( status == GPGME_SIG_STAT_GOOD ); 01975 } 01976 01977 01978 bool CryptPlug::decryptAndCheckMessage( const char* ciphertext, 01979 bool cipherIsBinary, 01980 int cipherLen, 01981 const char** cleartext, 01982 const char* /*certificate*/, 01983 bool* signatureFound, 01984 struct CryptPlug::SignatureMetaData* sigmeta, 01985 int* errId, 01986 char** errTxt, 01987 char** attrOrder, 01988 const char* unknownAttrsHandling ) 01989 { 01990 gpgme_ctx_t ctx; 01991 gpgme_error_t err; 01992 gpgme_data_t gCiphertext, gPlaintext; 01993 gpgme_sig_stat_t sigstatus = GPGME_SIG_STAT_NONE; 01994 size_t rCLen = 0; 01995 char* rCiph = 0; 01996 bool bOk = false; 01997 01998 if( !ciphertext ) 01999 return false; 02000 02001 err = gpgme_new (&ctx); 02002 gpgme_set_protocol (ctx, GPGMEPLUG_PROTOCOL); 02003 02004 gpgme_set_armor (ctx, cipherIsBinary ? 0 : 1); 02005 /* gpgme_set_textmode (ctx, cipherIsBinary ? 0 : 1); */ 02006 02007 /* 02008 gpgme_data_new_from_mem( &gCiphertext, ciphertext, 02009 1+strlen( ciphertext ), 1 ); */ 02010 gpgme_data_new_from_mem( &gCiphertext, 02011 ciphertext, 02012 cipherIsBinary 02013 ? cipherLen 02014 : strlen( ciphertext ), 02015 1 ); 02016 02017 gpgme_data_new( &gPlaintext ); 02018 02019 err = gpgme_op_decrypt_verify( ctx, gCiphertext, gPlaintext ); 02020 gpgme_data_release( gCiphertext ); 02021 if( err ) { 02022 fprintf( stderr, "\ngpgme_op_decrypt_verify() returned this error code: %i\n\n", err ); 02023 if( errId ) 02024 *errId = err; 02025 if( errTxt ) { 02026 const char* _errTxt = gpgme_strerror( err ); 02027 *errTxt = (char*)malloc( strlen( _errTxt ) + 1 ); 02028 if( *errTxt ) 02029 strcpy(*errTxt, _errTxt ); 02030 } 02031 gpgme_data_release( gPlaintext ); 02032 gpgme_release( ctx ); 02033 return bOk; 02034 } 02035 02036 rCiph = gpgme_data_release_and_get_mem( gPlaintext, &rCLen ); 02037 02038 *cleartext = (char*)malloc( rCLen + 1 ); 02039 if( *cleartext ) { 02040 if( rCLen ) { 02041 bOk = true; 02042 strncpy((char*)*cleartext, rCiph, rCLen ); 02043 } 02044 ((char*)(*cleartext))[rCLen] = 0; 02045 } 02046 free( rCiph ); 02047 02048 obtain_signature_information( ctx, sigstatus, sigmeta, 02049 attrOrder, unknownAttrsHandling, 02050 signatureFound ); 02051 02052 gpgme_release( ctx ); 02053 return bOk; 02054 } 02055
KDE Logo
This file is part of the documentation for certmanager/lib Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Oct 21 19:46:26 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003