libkdenetwork Library API Documentation

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