kpgpbase2.cpp
00001 /* 00002 kpgpbase2.cpp 00003 00004 Copyright (C) 2001,2002 the KPGP authors 00005 See file AUTHORS.kpgp for details 00006 00007 This file is part of KPGP, the KDE PGP/GnuPG support library. 00008 00009 KPGP is free software; you can redistribute it and/or modify 00010 it under the terms of the GNU General Public License as published by 00011 the Free Software Foundation; either version 2 of the License, or 00012 (at your option) any later version. 00013 00014 You should have received a copy of the GNU General Public License 00015 along with this program; if not, write to the Free Software Foundation, 00016 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 00017 */ 00018 00019 #ifdef HAVE_CONFIG_H 00020 #include <config.h> 00021 #endif 00022 00023 #include "kpgpbase.h" 00024 #include "kpgp.h" 00025 00026 #include <string.h> /* strncmp */ 00027 #include <assert.h> 00028 00029 #include <tqdatetime.h> 00030 00031 #include <klocale.h> 00032 #include <kprocess.h> 00033 #include <kdebug.h> 00034 00035 #define PGP2 "pgp" 00036 00037 namespace Kpgp { 00038 00039 Base2::Base2() 00040 : Base() 00041 { 00042 } 00043 00044 00045 Base2::~Base2() 00046 { 00047 } 00048 00049 00050 int 00051 Base2::encrypt( Block& block, const KeyIDList& recipients ) 00052 { 00053 return encsign( block, recipients, 0 ); 00054 } 00055 00056 00057 int 00058 Base2::clearsign( Block& block, const char *passphrase ) 00059 { 00060 return encsign( block, KeyIDList(), passphrase ); 00061 } 00062 00063 00064 int 00065 Base2::encsign( Block& block, const KeyIDList& recipients, 00066 const char *passphrase ) 00067 { 00068 TQCString cmd; 00069 int exitStatus = 0; 00070 00071 if(!recipients.isEmpty() && passphrase != 0) 00072 cmd = PGP2 " +batchmode +language=en +verbose=1 -seat"; 00073 else if(!recipients.isEmpty()) 00074 cmd = PGP2 " +batchmode +language=en +verbose=1 -eat"; 00075 else if(passphrase != 0) 00076 cmd = PGP2 " +batchmode +language=en +verbose=1 -sat"; 00077 else 00078 { 00079 kdDebug(5100) << "kpgpbase: Neither recipients nor passphrase specified." << endl; 00080 return OK; 00081 } 00082 00083 if(passphrase != 0) 00084 cmd += addUserId(); 00085 00086 if(!recipients.isEmpty()) { 00087 if(Module::getKpgp()->encryptToSelf()) 00088 { 00089 cmd += " 0x"; 00090 cmd += Module::getKpgp()->user(); 00091 } 00092 00093 for( KeyIDList::ConstIterator it = recipients.begin(); 00094 it != recipients.end(); ++it ) { 00095 cmd += " 0x"; 00096 cmd += (*it); 00097 } 00098 } 00099 cmd += " -f"; 00100 00101 clear(); 00102 input = block.text(); 00103 exitStatus = run(cmd.data(), passphrase); 00104 if( !output.isEmpty() ) 00105 block.setProcessedText( output ); 00106 block.setError( error ); 00107 00108 if(exitStatus != 0) 00109 status = ERROR; 00110 00111 #if 0 00112 // #### FIXME: As we check the keys ourselves the following problems 00113 // shouldn't occur. Therefore I don't handle them for now. 00114 // IK 01/2002 00115 if(!recipients.isEmpty()) 00116 { 00117 int index = 0; 00118 bool bad = FALSE; 00119 unsigned int num = 0; 00120 TQCString badkeys = ""; 00121 if (error.find("Cannot find the public key") != -1) 00122 { 00123 index = 0; 00124 num = 0; 00125 while((index = error.find("Cannot find the public key",index)) 00126 != -1) 00127 { 00128 bad = TRUE; 00129 index = error.find('\'',index); 00130 int index2 = error.find('\'',index+1); 00131 if (num++) 00132 badkeys += ", "; 00133 badkeys += error.mid(index, index2-index+1); 00134 } 00135 if(bad) 00136 { 00137 badkeys.stripWhiteSpace(); 00138 if(num == recipients.count()) 00139 errMsg = i18n("Could not find public keys matching the userid(s)\n" 00140 "%1;\n" 00141 "the message is not encrypted.") 00142 .arg( badkeys.data() ); 00143 else 00144 errMsg = i18n("Could not find public keys matching the userid(s)\n" 00145 "%1;\n" 00146 "these persons will not be able to read the message.") 00147 .arg( badkeys.data() ); 00148 status |= MISSINGKEY; 00149 status |= ERROR; 00150 } 00151 } 00152 if (error.find("skipping userid") != -1) 00153 { 00154 index = 0; 00155 num = 0; 00156 while((index = error.find("skipping userid",index)) 00157 != -1) 00158 { 00159 bad = TRUE; 00160 int index2 = error.find('\n',index+16); 00161 if (num++) 00162 badkeys += ", "; 00163 badkeys += error.mid(index+16, index2-index-16); 00164 index = index2; 00165 } 00166 if(bad) 00167 { 00168 badkeys.stripWhiteSpace(); 00169 if(num == recipients.count()) 00170 errMsg = i18n("Public keys not certified with trusted signature " 00171 "for userid(s)\n" 00172 "%1.\n" 00173 "The message is not encrypted.") 00174 .arg( badkeys.data() ); 00175 else 00176 errMsg = i18n("Public keys not certified with trusted signature " 00177 "for userid(s)\n" 00178 "%1;\n" 00179 "these persons will not be able to read the message.") 00180 .arg( badkeys.data() ); 00181 status |= BADKEYS; 00182 status |= ERROR; 00183 return status; 00184 } 00185 } 00186 } 00187 #endif 00188 if(passphrase != 0) 00189 { 00190 if(error.find("Pass phrase is good") != -1) 00191 { 00192 //kdDebug(5100) << "Base: Good Passphrase!" << endl; 00193 status |= SIGNED; 00194 } 00195 if( error.find("Bad pass phrase") != -1) 00196 { 00197 errMsg = i18n("Bad passphrase; could not sign."); 00198 status |= BADPHRASE; 00199 status |= ERR_SIGNING; 00200 status |= ERROR; 00201 } 00202 } 00203 if (error.find("Signature error") != -1) 00204 { 00205 errMsg = i18n("Signing failed: please check your PGP User Identity, " 00206 "the PGP setup, and the key rings."); 00207 status |= NO_SEC_KEY; 00208 status |= ERR_SIGNING; 00209 status |= ERROR; 00210 } 00211 if (error.find("Encryption error") != -1) 00212 { 00213 errMsg = i18n("Encryption failed: please check your PGP setup " 00214 "and the key rings."); 00215 status |= NO_SEC_KEY; 00216 status |= BADKEYS; 00217 status |= ERROR; 00218 } 00219 00220 //kdDebug(5100) << "status = " << status << endl; 00221 block.setStatus( status ); 00222 return status; 00223 } 00224 00225 00226 int 00227 Base2::decrypt( Block& block, const char *passphrase ) 00228 { 00229 int index, index2; 00230 int exitStatus = 0; 00231 00232 clear(); 00233 input = block.text(); 00234 exitStatus = run(PGP2 " +batchmode +language=en -f", passphrase); 00235 if( !output.isEmpty() ) 00236 block.setProcessedText( output ); 00237 block.setError( error ); 00238 00239 // pgp2.6 has sometimes problems with the ascii armor pgp5.0 produces 00240 // this hack can solve parts of the problem 00241 if(error.find("ASCII armor corrupted.") != -1) 00242 { 00243 kdDebug(5100) << "removing ASCII armor header" << endl; 00244 int index1 = input.find("-----BEGIN PGP SIGNED MESSAGE-----"); 00245 if(index1 != -1) 00246 index1 = input.find("-----BEGIN PGP SIGNATURE-----", index1); 00247 else 00248 index1 = input.find("-----BEGIN PGP MESSAGE-----"); 00249 index1 = input.find('\n', index1); 00250 index2 = input.find("\n\n", index1); 00251 input.remove(index1, index2 - index1); 00252 exitStatus = run(PGP2 " +batchmode +language=en -f", passphrase); 00253 if( !output.isEmpty() ) 00254 block.setProcessedText( output ); 00255 block.setError( error ); 00256 } 00257 00258 if(exitStatus == -1) { 00259 errMsg = i18n("error running PGP"); 00260 status = RUN_ERR; 00261 block.setStatus( status ); 00262 return status; 00263 } 00264 00265 /* Example No.1 (PGP 2.6.3in): 00266 * File is encrypted. Secret key is required to read it. 00267 * Key for user ID: Test Key (only for testing) <testkey@ingo-kloecker.de> 00268 * 1024-bit key, key ID E2D074D3, created 2001/09/09 00269 * 00270 * Error: Bad pass phrase. 00271 * 00272 * This message can only be read by: 00273 * Test key without secret key (for testing only) <nosectestkey@ingo-kloecker.de> 00274 * Test Key (only for testing) <testkey@ingo-kloecker.de> 00275 * 00276 * You do not have the secret key needed to decrypt this file. 00277 */ 00278 /* Example No.2 (PGP 2.6.3in): 00279 * File is encrypted. Secret key is required to read it. 00280 * This message can only be read by: 00281 * Test key without secret key (for testing only) <nosectestkey@ingo-kloecker.de> 00282 * 00283 * You do not have the secret key needed to decrypt this file. 00284 */ 00285 if(error.find("File is encrypted.") != -1) 00286 { 00287 //kdDebug(5100) << "kpgpbase: message is encrypted" << endl; 00288 status |= ENCRYPTED; 00289 if((index = error.find("Key for user ID:")) != -1) 00290 { 00291 // Find out the key for which the phrase is needed 00292 index += 17; 00293 index2 = error.find('\n', index); 00294 block.setRequiredUserId( error.mid(index, index2 - index) ); 00295 //kdDebug(5100) << "Base: key needed is \"" << block.requiredUserId() << "\"!\n"; 00296 00297 if((passphrase != 0) && (error.find("Bad pass phrase") != -1)) 00298 { 00299 errMsg = i18n("Bad passphrase; could not decrypt."); 00300 kdDebug(5100) << "Base: passphrase is bad" << endl; 00301 status |= BADPHRASE; 00302 status |= ERROR; 00303 } 00304 } 00305 else 00306 { 00307 // no secret key fitting this message 00308 status |= NO_SEC_KEY; 00309 status |= ERROR; 00310 errMsg = i18n("You do not have the secret key needed to decrypt this message."); 00311 kdDebug(5100) << "Base: no secret key for this message" << endl; 00312 } 00313 // check for persons 00314 #if 0 00315 // ##### FIXME: This information is anyway currently not used 00316 // I'll change it to always determine the recipients. 00317 index = error.find("can only be read by:"); 00318 if(index != -1) 00319 { 00320 index = error.find('\n',index); 00321 int end = error.find("\n\n",index); 00322 00323 mRecipients.clear(); 00324 while( (index2 = error.find('\n',index+1)) <= end ) 00325 { 00326 TQCString item = error.mid(index+1,index2-index-1); 00327 item.stripWhiteSpace(); 00328 mRecipients.append(item); 00329 index = index2; 00330 } 00331 } 00332 #endif 00333 } 00334 00335 // handle signed message 00336 00337 // Examples (made with PGP 2.6.3in) 00338 /* Example No. 1 (signed with unknown key): 00339 * File has signature. Public key is required to check signature. 00340 * 00341 * Key matching expected Key ID 12345678 not found in file '/home/user/.pgp/pubring.pgp'. 00342 * 00343 * WARNING: Can't find the right public key-- can't check signature integrity. 00344 */ 00345 /* Example No. 2 (bad signature): 00346 * File has signature. Public key is required to check signature. 00347 * .. 00348 * WARNING: Bad signature, doesn't match file contents! 00349 * 00350 * Bad signature from user "Joe User <joe@foo.bar>". 00351 * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678 00352 */ 00353 /* Example No. 3.1 (good signature with untrusted key): 00354 * File has signature. Public key is required to check signature. 00355 * . 00356 * Good signature from user "Joe User <joe@foo.bar>". 00357 * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678 00358 * 00359 * WARNING: Because this public key is not certified with a trusted 00360 * signature, it is not known with high confidence that this public key 00361 * actually belongs to: "Joe User <joe@foo.bar>". 00362 */ 00363 /* Example No. 3.2 (good signature with untrusted key): 00364 * File has signature. Public key is required to check signature. 00365 * . 00366 * Good signature from user "Joe User <joe@foo.bar>". 00367 * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678 00368 * 00369 * WARNING: Because this public key is not certified with enough trusted 00370 * signatures, it is not known with high confidence that this public key 00371 * actually belongs to: "Joe User <joe@foo.bar>". 00372 */ 00373 /* Example No. 4 (good signature with revoked key): 00374 * File has signature. Public key is required to check signature. 00375 * . 00376 * Good signature from user "Joe User <joe@foo.bar>". 00377 * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678 00378 * 00379 * 00380 * Key for user ID: Joe User <joe@foo.bar> 00381 * 1024-bit key, key ID 12345678, created 2001/09/09 00382 * Key has been revoked. 00383 * 00384 * WARNING: This key has been revoked by its owner, 00385 * possibly because the secret key was compromised. 00386 * This could mean that this signature is a forgery. 00387 */ 00388 /* Example No. 5 (good signature with trusted key): 00389 * File has signature. Public key is required to check signature. 00390 * . 00391 * Good signature from user "Joe User <joe@foo.bar>". 00392 * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678 00393 */ 00394 00395 if((index = error.find("File has signature")) != -1) 00396 { 00397 // move index to start of next line 00398 index = error.find('\n', index+18) + 1; 00399 //kdDebug(5100) << "Base: message is signed" << endl; 00400 status |= SIGNED; 00401 // get signature date and signature key ID 00402 if ((index2 = error.find("Signature made", index)) != -1) { 00403 index2 += 15; 00404 int index3 = error.find("using", index2); 00405 block.setSignatureDate( error.mid(index2, index3-index2-1) ); 00406 kdDebug(5100) << "Message was signed on '" << block.signatureDate() << "'\n"; 00407 index3 = error.find("key ID ", index3) + 7; 00408 block.setSignatureKeyId( error.mid(index3,8) ); 00409 kdDebug(5100) << "Message was signed with key '" << block.signatureKeyId() << "'\n"; 00410 } 00411 else { 00412 // if pgp can't find the keyring it unfortunately doesn't print 00413 // the signature date and key ID 00414 block.setSignatureDate( "" ); 00415 block.setSignatureKeyId( "" ); 00416 } 00417 00418 if( ( index2 = error.find("Key matching expected", index) ) != -1) 00419 { 00420 status |= UNKNOWN_SIG; 00421 status |= GOODSIG; 00422 int index3 = error.find("Key ID ", index2) + 7; 00423 block.setSignatureKeyId( error.mid(index3,8) ); 00424 block.setSignatureUserId( TQString() ); 00425 } 00426 else if( (index2 = error.find("Good signature from", index)) != -1 ) 00427 { 00428 status |= GOODSIG; 00429 // get signer 00430 index = error.find('"',index2+19); 00431 index2 = error.find('"', index+1); 00432 block.setSignatureUserId( error.mid(index+1, index2-index-1) ); 00433 } 00434 else if( (index2 = error.find("Bad signature from", index)) != -1 ) 00435 { 00436 status |= ERROR; 00437 // get signer 00438 index = error.find('"',index2+19); 00439 index2 = error.find('"', index+1); 00440 block.setSignatureUserId( error.mid(index+1, index2-index-1) ); 00441 } 00442 else if( error.find("Keyring file", index) != -1 ) 00443 { 00444 // #### fix this hack 00445 status |= UNKNOWN_SIG; 00446 status |= GOODSIG; // this is a hack... 00447 // determine file name of missing keyring file 00448 index = error.find('\'', index) + 1; 00449 index2 = error.find('\'', index); 00450 block.setSignatureUserId( i18n("The keyring file %1 does not exist.\n" 00451 "Please check your PGP setup.").arg(TQString(error.mid(index, index2-index))) ); 00452 } 00453 else 00454 { 00455 status |= ERROR; 00456 block.setSignatureUserId( i18n("Unknown error") ); 00457 } 00458 } 00459 //kdDebug(5100) << "status = " << status << endl; 00460 block.setStatus( status ); 00461 return status; 00462 } 00463 00464 00465 Key* 00466 Base2::readPublicKey( const KeyID& keyID, 00467 const bool readTrust /* = false */, 00468 Key* key /* = 0 */ ) 00469 { 00470 int exitStatus = 0; 00471 00472 status = 0; 00473 exitStatus = run( PGP2 " +batchmode +language=en +verbose=0 -kvc -f 0x" + 00474 keyID, 0, true ); 00475 00476 if(exitStatus != 0) { 00477 status = ERROR; 00478 return 0; 00479 } 00480 00481 key = parsePublicKeyData( output, key ); 00482 00483 if( key == 0 ) 00484 { 00485 return 0; 00486 } 00487 00488 if( readTrust ) 00489 { 00490 exitStatus = run( PGP2 " +batchmode +language=en +verbose=0 -kc -f", 00491 0, true ); 00492 00493 if(exitStatus != 0) { 00494 status = ERROR; 00495 return 0; 00496 } 00497 00498 parseTrustDataForKey( key, error ); 00499 } 00500 00501 return key; 00502 } 00503 00504 00505 KeyList 00506 Base2::publicKeys( const TQStringList & patterns ) 00507 { 00508 return doGetPublicKeys( PGP2 " +batchmode +language=en +verbose=0 -kvc -f", 00509 patterns ); 00510 } 00511 00512 KeyList 00513 Base2::doGetPublicKeys( const TQCString & cmd, const TQStringList & patterns ) 00514 { 00515 int exitStatus = 0; 00516 KeyList publicKeys; 00517 00518 status = 0; 00519 if ( patterns.isEmpty() ) { 00520 exitStatus = run( cmd, 0, true ); 00521 00522 if ( exitStatus != 0 ) { 00523 status = ERROR; 00524 return KeyList(); 00525 } 00526 00527 // now we need to parse the output for public keys 00528 publicKeys = parseKeyList( output, false ); 00529 } 00530 else { 00531 typedef TQMap<TQCString, Key*> KeyMap; 00532 KeyMap map; 00533 00534 for ( TQStringList::ConstIterator it = patterns.begin(); 00535 it != patterns.end(); ++it ) { 00536 exitStatus = run( cmd + " " + KProcess::quote( *it ).local8Bit(), 00537 0, true ); 00538 00539 if ( exitStatus != 0 ) { 00540 status = ERROR; 00541 return KeyList(); 00542 } 00543 00544 // now we need to parse the output for public keys 00545 publicKeys = parseKeyList( output, false ); 00546 00547 // put all new keys into a map, remove duplicates 00548 while ( !publicKeys.isEmpty() ) { 00549 Key * key = publicKeys.take( 0 ); 00550 if ( !map.contains( key->primaryFingerprint() ) ) 00551 map.insert( key->primaryFingerprint(), key ); 00552 else 00553 delete key; 00554 } 00555 } 00556 // build list from the map 00557 for ( KeyMap::ConstIterator it = map.begin(); it != map.end(); ++it ) { 00558 publicKeys.append( it.data() ); 00559 } 00560 } 00561 00562 // sort the list of public keys 00563 publicKeys.sort(); 00564 00565 return publicKeys; 00566 } 00567 00568 KeyList 00569 Base2::secretKeys( const TQStringList & patterns ) 00570 { 00571 return publicKeys( patterns ); 00572 } 00573 00574 00575 int 00576 Base2::signKey(const KeyID& keyID, const char *passphrase) 00577 { 00578 TQCString cmd; 00579 int exitStatus = 0; 00580 00581 cmd = PGP2 " +batchmode +language=en -ks -f "; 00582 cmd += addUserId(); 00583 cmd += " 0x" + keyID; 00584 00585 status = 0; 00586 exitStatus = run(cmd.data(),passphrase); 00587 00588 if (exitStatus != 0) 00589 status = ERROR; 00590 00591 return status; 00592 } 00593 00594 00595 TQCString Base2::getAsciiPublicKey(const KeyID& keyID) 00596 { 00597 int exitStatus = 0; 00598 00599 if (keyID.isEmpty()) 00600 return TQCString(); 00601 00602 status = 0; 00603 exitStatus = run( PGP2 " +batchmode +force +language=en -kxaf 0x" + keyID, 00604 0, true ); 00605 00606 if(exitStatus != 0) { 00607 status = ERROR; 00608 return TQCString(); 00609 } 00610 00611 return output; 00612 } 00613 00614 00615 Key* 00616 Base2::parsePublicKeyData( const TQCString& output, Key* key /* = 0 */ ) 00617 { 00618 Subkey *subkey = 0; 00619 int index; 00620 00621 // search start of key data 00622 if( !strncmp( output.data(), "pub", 3 ) || 00623 !strncmp( output.data(), "sec", 3 ) ) 00624 index = 0; 00625 else 00626 { 00627 /* 00628 if( secretKeys ) 00629 index = output.find( "\nsec" ); 00630 else 00631 */ 00632 index = output.find( "\npub" ); 00633 if( index == -1 ) 00634 return 0; 00635 else 00636 index++; 00637 } 00638 00639 while( true ) 00640 { 00641 int index2; 00642 00643 // search the end of the current line 00644 if( ( index2 = output.find( '\n', index ) ) == -1 ) 00645 break; 00646 00647 if( !strncmp( output.data() + index, "pub", 3 ) || 00648 !strncmp( output.data() + index, "sec", 3 ) ) 00649 { // line contains primary key data 00650 // Example 1 (nothing special): 00651 // pub 1024/E2D074D3 2001/09/09 Test Key <testkey@xyz> 00652 // Example 2 (disabled key): 00653 // pub- 1024/8CCB2C1B 2001/11/04 Disabled Test Key <disabled@xyz> 00654 // Example 3 (expired key): 00655 // pub> 1024/7B94827D 2001/09/09 Expired Test Key <expired@xyz> (EXPIRE:2001-09-10) 00656 // Example 4 (revoked key): 00657 // pub 1024/956721F9 2001/09/09 *** KEY REVOKED *** 00658 00659 int pos, pos2; 00660 00661 if( key == 0 ) 00662 key = new Key(); 00663 else 00664 key->clear(); 00665 /*key->setSecret( secretKeys );*/ 00666 // set default key capabilities 00667 key->setCanEncrypt( true ); 00668 key->setCanSign( true ); 00669 key->setCanCertify( true ); 00670 00671 /*subkey = new Subkey( "", secretKeys );*/ 00672 subkey = new Subkey( "", false ); 00673 key->addSubkey( subkey ); 00674 // set default key capabilities 00675 subkey->setCanEncrypt( true ); 00676 subkey->setCanSign( true ); 00677 subkey->setCanCertify( true ); 00678 // expiration date defaults to never 00679 subkey->setExpirationDate( -1 ); 00680 00681 // Key Flags 00682 switch( output[index+3] ) 00683 { 00684 case ' ': // nothing special 00685 break; 00686 case '-': // disabled key 00687 subkey->setDisabled( true ); 00688 key->setDisabled( true ); 00689 break; 00690 case '>': // expired key 00691 subkey->setExpired( true ); 00692 key->setExpired( true ); 00693 break; 00694 default: 00695 kdDebug(5100) << "Unknown key flag.\n"; 00696 } 00697 00698 // Key Length 00699 pos = index + 4; 00700 while( output[pos] == ' ' ) 00701 pos++; 00702 pos2 = output.find( '/', pos ); 00703 subkey->setKeyLength( output.mid( pos, pos2-pos ).toUInt() ); 00704 00705 // Key ID 00706 pos = pos2 + 1; 00707 pos2 = output.find( ' ', pos ); 00708 subkey->setKeyID( output.mid( pos, pos2-pos ) ); 00709 00710 // Creation Date 00711 pos = pos2 + 1; 00712 while( output[pos] == ' ' ) 00713 pos++; 00714 pos2 = output.find( ' ', pos ); 00715 int year = output.mid( pos, 4 ).toInt(); 00716 int month = output.mid( pos+5, 2 ).toInt(); 00717 int day = output.mid( pos+8, 2 ).toInt(); 00718 TQDateTime dt( TQDate( year, month, day ), TQTime( 00, 00 ) ); 00719 TQDateTime epoch( TQDate( 1970, 01, 01 ), TQTime( 00, 00 ) ); 00720 // The calculated creation date isn't exactly correct because TQDateTime 00721 // doesn't know anything about timezones and always assumes local time 00722 // although epoch is of course UTC. But as PGP 2 anyway doesn't print 00723 // the time this doesn't matter too much. 00724 subkey->setCreationDate( epoch.secsTo( dt ) ); 00725 00726 // User ID 00727 pos = pos2 + 1; 00728 while( output[pos] == ' ' ) 00729 pos++; 00730 TQCString uid = output.mid( pos, index2-pos ); 00731 if( uid != "*** KEY REVOKED ***" ) 00732 key->addUserID( uid ); 00733 else 00734 { 00735 subkey->setRevoked( true ); 00736 key->setRevoked( true ); 00737 } 00738 } 00739 else if( output[index] == ' ' ) 00740 { // line contains additional key data 00741 00742 if( key == 0 ) 00743 break; 00744 assert( subkey != 0 ); 00745 00746 int pos = index + 1; 00747 while( output[pos] == ' ' ) 00748 pos++; 00749 00750 if( !strncmp( output.data() + pos, "Key fingerprint = ", 18 ) ) 00751 { // line contains a fingerprint 00752 // Example: 00753 // Key fingerprint = 47 30 7C 76 05 BF 5E FB 72 41 00 F2 7D 0B D0 49 00754 00755 TQCString fingerprint = output.mid( pos, index2-pos ); 00756 // remove white space from the fingerprint 00757 for ( int idx = 0 ; (idx = fingerprint.find(' ', idx)) >= 0 ; ) 00758 fingerprint.replace( idx, 1, "" ); 00759 00760 subkey->setFingerprint( fingerprint ); 00761 } 00762 else if( !strncmp( output.data() + pos, "Expire: ", 8 ) || 00763 !strncmp( output.data() + pos, "no expire ", 10 ) ) 00764 { // line contains additional key properties 00765 // Examples: 00766 // Expire: 2001/09/10 00767 // no expire ENCRyption only 00768 // no expire SIGNature only 00769 00770 if( output[pos] == 'E' ) 00771 { 00772 // Expiration Date 00773 pos += 8; 00774 int year = output.mid( pos, 4 ).toInt(); 00775 int month = output.mid( pos+5, 2 ).toInt(); 00776 int day = output.mid( pos+8, 2 ).toInt(); 00777 TQDateTime dt( TQDate( year, month, day ), TQTime( 00, 00 ) ); 00778 TQDateTime epoch( TQDate( 1970, 01, 01 ), TQTime( 00, 00 ) ); 00779 // Here the same comments as for the creation date are valid. 00780 subkey->setExpirationDate( epoch.secsTo( dt ) ); 00781 pos += 11; // note that there is always a blank after the expire date 00782 } 00783 else 00784 pos += 10; 00785 00786 // optional key capabilities (sign/encrypt only) 00787 if( pos != index2 ) 00788 { 00789 if( !strncmp( output.data() + pos, "SIGNature only", 14 ) ) 00790 { 00791 subkey->setCanEncrypt( false ); 00792 key->setCanEncrypt( false ); 00793 } 00794 else if( !strncmp( output.data() + pos, "ENCRyption only", 15 ) ) 00795 { 00796 subkey->setCanSign( false ); 00797 key->setCanSign( false ); 00798 subkey->setCanCertify( false ); 00799 key->setCanCertify( false ); 00800 } 00801 } 00802 } 00803 else 00804 { // line contains an additional user id 00805 // Example: 00806 // Test key (2nd user ID) <abc@xyz> 00807 00808 key->addUserID( output.mid( pos, index2-pos ) ); 00809 } 00810 } 00811 index = index2 + 1; 00812 } 00813 00814 //kdDebug(5100) << "finished parsing key data\n"; 00815 00816 return key; 00817 } 00818 00819 00820 void 00821 Base2::parseTrustDataForKey( Key* key, const TQCString& str ) 00822 { 00823 if( ( key == 0 ) || str.isEmpty() ) 00824 return; 00825 00826 TQCString keyID = key->primaryKeyID(); 00827 UserIDList userIDs = key->userIDs(); 00828 00829 // search the trust data belonging to this key 00830 int index = str.find( '\n' ) + 1; 00831 while( ( index > 0 ) && 00832 ( strncmp( str.data() + index+2, keyID.data(), 8 ) != 0 ) ) 00833 index = str.find( '\n', index ) + 1; 00834 00835 if( index == 0 ) 00836 return; 00837 00838 bool ultimateTrust = false; 00839 if( !strncmp( str.data() + index+11, "ultimate", 8 ) ) 00840 ultimateTrust = true; 00841 00842 bool firstLine = true; 00843 00844 while( true ) 00845 { // loop over all trust information about this key 00846 int index2; 00847 00848 // search the end of the current line 00849 if( ( index2 = str.find( '\n', index ) ) == -1 ) 00850 break; 00851 00852 // check if trust info for the next key starts 00853 if( !firstLine && ( str[index+2] != ' ' ) ) 00854 break; 00855 00856 if( str[index+21] != ' ' ) 00857 { // line contains a validity value for a user ID 00858 00859 // determine the validity 00860 Validity validity = KPGP_VALIDITY_UNKNOWN; 00861 if( !strncmp( str.data() + index+21, "complete", 8 ) ) 00862 if( ultimateTrust ) 00863 validity = KPGP_VALIDITY_ULTIMATE; 00864 else 00865 validity = KPGP_VALIDITY_FULL; 00866 else if( !strncmp( str.data() + index+21, "marginal", 8 ) ) 00867 validity = KPGP_VALIDITY_MARGINAL; 00868 else if( !strncmp( str.data() + index+21, "never", 5 ) ) 00869 validity = KPGP_VALIDITY_NEVER; 00870 else if( !strncmp( str.data() + index+21, "undefined", 9 ) ) 00871 validity = KPGP_VALIDITY_UNDEFINED; 00872 00873 // determine the user ID 00874 int pos = index + 31; 00875 if( str[index+2] == ' ' ) 00876 pos++; // additional user IDs start one column later 00877 TQString uid = str.mid( pos, index2-pos ); 00878 00879 // set the validity of the corresponding user ID 00880 for( UserIDListIterator it( userIDs ); it.current(); ++it ) 00881 if( (*it)->text() == uid ) 00882 { 00883 kdDebug(5100)<<"Setting the validity of "<<uid<<" to "<<validity<<endl; 00884 (*it)->setValidity( validity ); 00885 break; 00886 } 00887 } 00888 00889 firstLine = false; 00890 index = index2 + 1; 00891 } 00892 } 00893 00894 00895 KeyList 00896 Base2::parseKeyList( const TQCString& output, bool secretKeys ) 00897 { 00898 kdDebug(5100) << "Kpgp::Base2::parseKeyList()" << endl; 00899 KeyList keys; 00900 Key *key = 0; 00901 Subkey *subkey = 0; 00902 int index; 00903 00904 // search start of key data 00905 if( !strncmp( output.data(), "pub", 3 ) || 00906 !strncmp( output.data(), "sec", 3 ) ) 00907 index = 0; 00908 else 00909 { 00910 if( secretKeys ) 00911 index = output.find( "\nsec" ); 00912 else 00913 index = output.find( "\npub" ); 00914 if( index == -1 ) 00915 return keys; 00916 else 00917 index++; 00918 } 00919 00920 while( true ) 00921 { 00922 int index2; 00923 00924 // search the end of the current line 00925 if( ( index2 = output.find( '\n', index ) ) == -1 ) 00926 break; 00927 00928 if( !strncmp( output.data() + index, "pub", 3 ) || 00929 !strncmp( output.data() + index, "sec", 3 ) ) 00930 { // line contains primary key data 00931 // Example 1: 00932 // pub 1024/E2D074D3 2001/09/09 Test Key <testkey@xyz> 00933 // Example 2 (disabled key): 00934 // pub- 1024/8CCB2C1B 2001/11/04 Disabled Test Key <disabled@xyz> 00935 // Example 3 (expired key): 00936 // pub> 1024/7B94827D 2001/09/09 Expired Test Key <expired@xyz> (EXPIRE:2001-09-10) 00937 // Example 4 (revoked key): 00938 // pub 1024/956721F9 2001/09/09 *** KEY REVOKED *** 00939 00940 int pos, pos2; 00941 00942 if( key != 0 ) // store the previous key in the key list 00943 keys.append( key ); 00944 00945 key = new Key(); 00946 key->setSecret( secretKeys ); 00947 // set default key capabilities 00948 key->setCanEncrypt( true ); 00949 key->setCanSign( true ); 00950 key->setCanCertify( true ); 00951 00952 subkey = new Subkey( "", secretKeys ); 00953 key->addSubkey( subkey ); 00954 // set default key capabilities 00955 subkey->setCanEncrypt( true ); 00956 subkey->setCanSign( true ); 00957 subkey->setCanCertify( true ); 00958 // expiration date defaults to never 00959 subkey->setExpirationDate( -1 ); 00960 00961 // Key Flags 00962 switch( output[index+3] ) 00963 { 00964 case ' ': // nothing special 00965 break; 00966 case '-': // disabled key 00967 subkey->setDisabled( true ); 00968 key->setDisabled( true ); 00969 break; 00970 case '>': // expired key 00971 subkey->setExpired( true ); 00972 key->setExpired( true ); 00973 break; 00974 default: 00975 kdDebug(5100) << "Unknown key flag.\n"; 00976 } 00977 00978 // Key Length 00979 pos = index + 4; 00980 while( output[pos] == ' ' ) 00981 pos++; 00982 pos2 = output.find( '/', pos ); 00983 subkey->setKeyLength( output.mid( pos, pos2-pos ).toUInt() ); 00984 00985 // Key ID 00986 pos = pos2 + 1; 00987 pos2 = output.find( ' ', pos ); 00988 subkey->setKeyID( output.mid( pos, pos2-pos ) ); 00989 00990 // Creation Date 00991 pos = pos2 + 1; 00992 while( output[pos] == ' ' ) 00993 pos++; 00994 pos2 = output.find( ' ', pos ); 00995 int year = output.mid( pos, 4 ).toInt(); 00996 int month = output.mid( pos+5, 2 ).toInt(); 00997 int day = output.mid( pos+8, 2 ).toInt(); 00998 TQDateTime dt( TQDate( year, month, day ), TQTime( 00, 00 ) ); 00999 TQDateTime epoch( TQDate( 1970, 01, 01 ), TQTime( 00, 00 ) ); 01000 // The calculated creation date isn't exactly correct because TQDateTime 01001 // doesn't know anything about timezones and always assumes local time 01002 // although epoch is of course UTC. But as PGP 2 anyway doesn't print 01003 // the time this doesn't matter too much. 01004 subkey->setCreationDate( epoch.secsTo( dt ) ); 01005 01006 // User ID 01007 pos = pos2 + 1; 01008 while( output[pos] == ' ' ) 01009 pos++; 01010 TQCString uid = output.mid( pos, index2-pos ); 01011 if( uid != "*** KEY REVOKED ***" ) 01012 key->addUserID( uid ); 01013 else 01014 { 01015 subkey->setRevoked( true ); 01016 key->setRevoked( true ); 01017 } 01018 } 01019 else if( output[index] == ' ' ) 01020 { // line contains additional key data 01021 01022 if( key == 0 ) 01023 break; 01024 01025 int pos = index + 1; 01026 while( output[pos] == ' ' ) 01027 pos++; 01028 01029 if( !strncmp( output.data() + pos, "Key fingerprint = ", 18 ) ) 01030 { // line contains a fingerprint 01031 // Example: 01032 // Key fingerprint = 47 30 7C 76 05 BF 5E FB 72 41 00 F2 7D 0B D0 49 01033 01034 // int pos2; 01035 // pos2 = pos + 18; 01036 TQCString fingerprint = output.mid( pos, index2-pos ); 01037 // remove white space from the fingerprint 01038 for ( int idx = 0 ; (idx = fingerprint.find(' ', idx)) >= 0 ; ) 01039 fingerprint.replace( idx, 1, "" ); 01040 01041 subkey->setFingerprint( fingerprint ); 01042 } 01043 else if( !strncmp( output.data() + pos, "Expire: ", 8 ) || 01044 !strncmp( output.data() + pos, "no expire ", 10 ) ) 01045 { // line contains additional key properties 01046 // Examples: 01047 // Expire: 2001/09/10 01048 // no expire ENCRyption only 01049 // no expire SIGNature only 01050 01051 if( output[pos] == 'E' ) 01052 { 01053 // Expiration Date 01054 pos += 8; 01055 int year = output.mid( pos, 4 ).toInt(); 01056 int month = output.mid( pos+5, 2 ).toInt(); 01057 int day = output.mid( pos+8, 2 ).toInt(); 01058 TQDateTime dt( TQDate( year, month, day ), TQTime( 00, 00 ) ); 01059 TQDateTime epoch( TQDate( 1970, 01, 01 ), TQTime( 00, 00 ) ); 01060 // Here the same comments as for the creation date are valid. 01061 subkey->setExpirationDate( epoch.secsTo( dt ) ); 01062 pos += 11; // note that there is always a blank after the expire date 01063 } 01064 else 01065 pos += 10; 01066 01067 // optional key capabilities (sign/encrypt only) 01068 if( pos != index2 ) 01069 { 01070 if( !strncmp( output.data() + pos, "SIGNature only", 14 ) ) 01071 { 01072 subkey->setCanEncrypt( false ); 01073 key->setCanEncrypt( false ); 01074 } 01075 else if( !strncmp( output.data() + pos, "ENCRyption only", 15 ) ) 01076 { 01077 subkey->setCanSign( false ); 01078 key->setCanSign( false ); 01079 subkey->setCanCertify( false ); 01080 key->setCanCertify( false ); 01081 } 01082 } 01083 } 01084 else 01085 { // line contains an additional user id 01086 // Example: 01087 // Test key (2nd user ID) <abc@xyz> 01088 01089 key->addUserID( output.mid( pos, index2-pos ) ); 01090 } 01091 } 01092 01093 index = index2 + 1; 01094 } 01095 01096 if (key != 0) // store the last key in the key list 01097 keys.append( key ); 01098 01099 //kdDebug(5100) << "finished parsing keys" << endl; 01100 01101 return keys; 01102 } 01103 01104 01105 } // namespace Kpgp