00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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>
00027
00028 #include <qregexp.h>
00029 #include <qdatetime.h>
00030
00031 #include <klocale.h>
00032 #include <kprocess.h>
00033 #include <kdebug.h>
00034
00035
00036 namespace Kpgp {
00037
00038 Base5::Base5()
00039 : Base()
00040 {
00041 }
00042
00043
00044 Base5::~Base5()
00045 {
00046 }
00047
00048
00049 int
00050 Base5::encrypt( Block& block, const KeyIDList& recipients )
00051 {
00052 return encsign( block, recipients, 0 );
00053 }
00054
00055
00056 int
00057 Base5::clearsign( Block& block, const char *passphrase )
00058 {
00059 return encsign( block, KeyIDList(), passphrase );
00060 }
00061
00062
00063 int
00064 Base5::encsign( Block& block, const KeyIDList& recipients,
00065 const char *passphrase )
00066 {
00067 QCString cmd;
00068 int exitStatus = 0;
00069 int index;
00070
00071
00072
00073 bool signonly = false;
00074
00075 if(!recipients.isEmpty() && passphrase != 0)
00076 cmd = "pgpe +batchmode -afts ";
00077 else if(!recipients.isEmpty())
00078 cmd = "pgpe +batchmode -aft ";
00079 else if(passphrase != 0)
00080 {
00081 cmd = "pgps +batchmode -abft ";
00082 signonly = true;
00083 }
00084 else
00085 {
00086 errMsg = i18n("Neither recipients nor passphrase specified.");
00087 return OK;
00088 }
00089
00090 if(passphrase != 0)
00091 cmd += addUserId();
00092
00093 if(!recipients.isEmpty())
00094 {
00095 if(Module::getKpgp()->encryptToSelf())
00096 {
00097 cmd += " -r 0x";
00098 cmd += Module::getKpgp()->user();
00099 }
00100
00101 for( KeyIDList::ConstIterator it = recipients.begin();
00102 it != recipients.end(); ++it ) {
00103 cmd += " -r 0x";
00104 cmd += (*it);
00105 }
00106 }
00107
00108 clear();
00109 input = block.text();
00110
00111 if (signonly)
00112 {
00113 input.append("\n");
00114 input.replace(QRegExp("[ \t]+\n"), "\n");
00115 }
00116
00117
00118 exitStatus = run(cmd.data(), passphrase);
00119 block.setError( error );
00120
00121 if(exitStatus != 0)
00122 status = ERROR;
00123
00124
00125 if(error.find("Cannot unlock private key") != -1)
00126 {
00127 errMsg = i18n("The passphrase you entered is invalid.");
00128 status |= ERROR;
00129 status |= BADPHRASE;
00130 }
00131
00132
00133 QCString aStr;
00134 index = -1;
00135 while((index = error.find("WARNING: The above key",index+1)) != -1)
00136 {
00137 int index2 = error.find("But you previously",index);
00138 int index3 = error.find("WARNING: The above key",index+1);
00139 if(index2 == -1 || (index2 > index3 && index3 != -1))
00140 {
00141
00142
00143 index2 = error.find('\n',index);
00144 index3 = error.find('\n',index2+1);
00145 aStr += error.mid(index2+1, index3-index2-1);
00146 aStr += ", ";
00147 }
00148 }
00149 if(!aStr.isEmpty())
00150 {
00151 aStr.truncate(aStr.length()-2);
00152 if(error.find("No valid keys found") != -1)
00153 errMsg = i18n("The key(s) you want to encrypt your message "
00154 "to are not trusted. No encryption done.");
00155 else
00156 errMsg = i18n("The following key(s) are not trusted:\n%1\n"
00157 "Their owner(s) will not be able to decrypt the message.")
00158 .arg(aStr);
00159 status |= ERROR;
00160 status |= BADKEYS;
00161 }
00162
00163 if((index = error.find("No encryption keys found for")) != -1)
00164 {
00165 index = error.find(':',index);
00166 int index2 = error.find('\n',index);
00167
00168 errMsg = i18n("Missing encryption key(s) for:\n%1")
00169 .arg(error.mid(index,index2-index));
00170
00171
00172 status |= ERROR;
00173 status |= MISSINGKEY;
00174 }
00175
00176 if(signonly) {
00177
00178 if (input[0] == '-')
00179 input = "- " + input;
00180 for ( int idx = 0 ; (idx = input.find("\n-", idx)) >= 0 ; idx += 4 )
00181 input.replace(idx, 2, "\n- -");
00182
00183 output = "-----BEGIN PGP SIGNED MESSAGE-----\n\n" + input + "\n" + output;
00184 }
00185
00186 block.setProcessedText( output );
00187 block.setStatus( status );
00188 return status;
00189 }
00190
00191
00192 int
00193 Base5::decrypt( Block& block, const char *passphrase )
00194 {
00195 int exitStatus = 0;
00196
00197 clear();
00198 input = block.text();
00199 exitStatus = run("pgpv -f +batchmode=1", passphrase);
00200 if( !output.isEmpty() )
00201 block.setProcessedText( output );
00202 block.setError( error );
00203
00204 if(exitStatus == -1) {
00205 errMsg = i18n("Error running PGP");
00206 status = RUN_ERR;
00207 block.setStatus( status );
00208 return status;
00209 }
00210
00211
00212 int index;
00213
00214 index = error.find("Cannot decrypt message");
00215 if(index != -1)
00216 {
00217
00218 status |= ENCRYPTED;
00219
00220
00221
00222 if(error.find("Need a pass phrase") != -1)
00223 {
00224 if(passphrase != 0)
00225 {
00226 errMsg = i18n("Bad passphrase; could not decrypt.");
00227 kdDebug(5100) << "Base: passphrase is bad" << endl;
00228 status |= BADPHRASE;
00229 status |= ERROR;
00230 }
00231 }
00232 else
00233 {
00234
00235 status |= NO_SEC_KEY;
00236 status |= ERROR;
00237 errMsg = i18n("You do not have the secret key needed to decrypt this message.");
00238 kdDebug(5100) << "Base: no secret key for this message" << endl;
00239 }
00240
00241 #if 0
00242
00243
00244 index = error.find("can only be decrypted by:");
00245 if(index != -1)
00246 {
00247 index = error.find('\n',index);
00248 int end = error.find("\n\n",index);
00249
00250 mRecipients.clear();
00251 int index2;
00252 while( (index2 = error.find('\n',index+1)) <= end )
00253 {
00254 QCString item = error.mid(index+1,index2-index-1);
00255 item.stripWhiteSpace();
00256 mRecipients.append(item);
00257 index = index2;
00258 }
00259 }
00260 #endif
00261 }
00262 index = error.find("Good signature");
00263 if(index != -1)
00264 {
00265
00266 status |= SIGNED;
00267 status |= GOODSIG;
00268
00269
00270 index = error.find("Key ID ", index) + 7;
00271 block.setSignatureKeyId( error.mid(index, 8) );
00272
00273
00274 index = error.find('"',index) + 1;
00275 int index2 = error.find('"', index);
00276 block.setSignatureUserId( error.mid(index, index2-index) );
00277
00279 block.setSignatureDate( "" );
00280 }
00281 index = error.find("BAD signature");
00282 if(index != -1)
00283 {
00284
00285 status |= SIGNED;
00286 status |= ERROR;
00287
00288
00289 index = error.find("Key ID ", index) + 7;
00290 block.setSignatureKeyId( error.mid(index, 8) );
00291
00292
00293 index = error.find('"',index) + 1;
00294 int index2 = error.find('"', index);
00295 block.setSignatureUserId( error.mid(index, index2-index) );
00296
00298 block.setSignatureDate( "" );
00299 }
00300 index = error.find("Signature by unknown key");
00301 if(index != -1)
00302 {
00303 index = error.find("keyid: 0x",index) + 9;
00304 block.setSignatureKeyId( error.mid(index, 8) );
00305 block.setSignatureUserId( QString::null );
00306
00307 status |= SIGNED;
00308 status |= GOODSIG;
00309
00311 block.setSignatureDate( "" );
00312 }
00313
00314
00315 block.setStatus( status );
00316 return status;
00317 }
00318
00319
00320 Key*
00321 Base5::readPublicKey( const KeyID& keyId, const bool readTrust, Key* key )
00322 {
00323 int exitStatus = 0;
00324
00325 status = 0;
00326 exitStatus = run( "pgpk -ll 0x" + keyId, 0, true );
00327
00328 if(exitStatus != 0) {
00329 status = ERROR;
00330 return 0;
00331 }
00332
00333 key = parseSingleKey( output, key );
00334
00335 if( key == 0 )
00336 {
00337 return 0;
00338 }
00339
00340 if( readTrust )
00341 {
00342 exitStatus = run( "pgpk -c 0x" + keyId, 0, true );
00343
00344 if(exitStatus != 0) {
00345 status = ERROR;
00346 return 0;
00347 }
00348
00349 parseTrustDataForKey( key, output );
00350 }
00351
00352 return key;
00353 }
00354
00355
00356 KeyList
00357 Base5::publicKeys( const QStringList & patterns )
00358 {
00359 int exitStatus = 0;
00360
00361 QCString cmd = "pgpk -ll";
00362 for ( QStringList::ConstIterator it = patterns.begin();
00363 it != patterns.end(); ++it ) {
00364 cmd += " ";
00365 cmd += KProcess::quote( *it ).local8Bit();
00366 }
00367 status = 0;
00368 exitStatus = run( cmd, 0, true );
00369
00370 if(exitStatus != 0) {
00371 status = ERROR;
00372 return KeyList();
00373 }
00374
00375
00376 KeyList keys = parseKeyList( output, false );
00377
00378
00379 keys.sort();
00380
00381 return keys;
00382 }
00383
00384
00385 KeyList
00386 Base5::secretKeys( const QStringList & patterns )
00387 {
00388 int exitStatus = 0;
00389
00390 status = 0;
00391 QCString cmd = "pgpk -ll";
00392 for ( QStringList::ConstIterator it = patterns.begin();
00393 it != patterns.end(); ++it ) {
00394 cmd += " ";
00395 cmd += KProcess::quote( *it ).local8Bit();
00396 }
00397 status = 0;
00398 exitStatus = run( cmd, 0, true );
00399
00400 if(exitStatus != 0) {
00401 status = ERROR;
00402 return KeyList();
00403 }
00404
00405
00406 KeyList keys = parseKeyList( output, true );
00407
00408
00409 keys.sort();
00410
00411 return keys;
00412 }
00413
00414
00415 QCString Base5::getAsciiPublicKey(const KeyID& keyID)
00416 {
00417 int exitStatus = 0;
00418
00419 if (keyID.isEmpty())
00420 return QCString();
00421
00422 status = 0;
00423 exitStatus = run( "pgpk -xa 0x" + keyID, 0, true );
00424
00425 if(exitStatus != 0) {
00426 status = ERROR;
00427 return QCString();
00428 }
00429
00430 return output;
00431 }
00432
00433
00434 int
00435 Base5::signKey(const KeyID& keyID, const char *passphrase)
00436 {
00437 QCString cmd;
00438 int exitStatus = 0;
00439
00440 if(passphrase == 0) return false;
00441
00442 cmd = "pgpk -s -f +batchmode=1 0x";
00443 cmd += keyID;
00444 cmd += addUserId();
00445
00446 status = 0;
00447 exitStatus = run(cmd.data(), passphrase);
00448
00449 if (exitStatus != 0)
00450 status = ERROR;
00451
00452 return status;
00453 }
00454
00455
00456
00457 Key*
00458 Base5::parseKeyData( const QCString& output, int& offset, Key* key )
00459
00460
00461
00462
00463
00464 {
00465 if( ( strncmp( output.data() + offset, "pub", 3 ) != 0 ) &&
00466 ( strncmp( output.data() + offset, "sec", 3 ) != 0 ) )
00467 {
00468 kdDebug(5100) << "Unknown key type or corrupt key data.\n";
00469 return 0;
00470 }
00471
00472 if( key == 0 )
00473 key = new Key();
00474 else
00475 key->clear();
00476
00477 Subkey *subkey = 0;
00478 bool primaryKey = true;
00479
00480 while( true )
00481 {
00482 int eol;
00483
00484
00485 eol = output.find( '\n', offset );
00486 if( ( eol == -1 ) || ( eol == offset ) )
00487 break;
00488
00489
00490
00491 if( !strncmp( output.data() + offset, "pub", 3 ) ||
00492 !strncmp( output.data() + offset, "sec", 3 ) ||
00493 !strncmp( output.data() + offset, "sub", 3 ) )
00494 {
00495
00496 int pos, pos2;
00497
00498 subkey = new Subkey( "", false );
00499 key->addSubkey( subkey );
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510 switch( output[offset+3] )
00511 {
00512 case ' ':
00513 break;
00514 case '@':
00515 subkey->setDisabled( true );
00516 key->setDisabled( true );
00517 break;
00518 default:
00519
00520 ;
00521 }
00522
00523
00524 pos = offset + 4;
00525 while( output[pos] == ' ' )
00526 pos++;
00527 pos2 = output.find( ' ', pos );
00528 subkey->setKeyLength( output.mid( pos, pos2-pos ).toUInt() );
00529
00530
00531
00532 pos = pos2 + 1;
00533 while( output[pos] == ' ' )
00534 pos++;
00535 pos += 2;
00536 pos2 = output.find( ' ', pos );
00537 subkey->setKeyID( output.mid( pos, pos2-pos ) );
00538
00539
00540
00541 pos = pos2 + 1;
00542 while( output[pos] == ' ' )
00543 pos++;
00544 pos2 = output.find( ' ', pos );
00545 int year = output.mid( pos, 4 ).toInt();
00546 int month = output.mid( pos+5, 2 ).toInt();
00547 int day = output.mid( pos+8, 2 ).toInt();
00548 QDateTime dt( QDate( year, month, day ), QTime( 00, 00 ) );
00549 QDateTime epoch( QDate( 1970, 01, 01 ), QTime( 00, 00 ) );
00550
00551
00552
00553
00554 subkey->setCreationDate( epoch.secsTo( dt ) );
00555
00556
00557
00558 if( primaryKey || !key->revoked() )
00559 {
00560 pos = pos2 + 1;
00561 while( output[pos] == ' ' )
00562 pos++;
00563 pos2 = output.find( ' ', pos );
00564 if( output[pos] == '-' )
00565 {
00566 subkey->setExpirationDate( -1 );
00567 }
00568 else if( !strncmp( output.data() + pos, "*REVOKED*", 9 ) )
00569 {
00570 subkey->setRevoked( true );
00571 key->setRevoked( true );
00572 }
00573 else
00574 {
00575 int year = output.mid( pos, 4 ).toInt();
00576 int month = output.mid( pos+5, 2 ).toInt();
00577 int day = output.mid( pos+8, 2 ).toInt();
00578 QDateTime dt( QDate( year, month, day ), QTime( 00, 00 ) );
00579 subkey->setCreationDate( epoch.secsTo( dt ) );
00580
00581 if( QDateTime::currentDateTime() >= dt )
00582 {
00583 subkey->setExpired( true );
00584 key->setExpired( true );
00585 }
00586 }
00587 }
00588 else if( key->revoked() )
00589 subkey->setRevoked( true );
00590
00591
00592 bool sign = false;
00593 bool encr = false;
00594 pos = pos2 + 1;
00595 while( output[pos] == ' ' )
00596 pos++;
00597 pos2 = output.find( ' ', pos );
00598 if( !strncmp( output.data() + pos, "RSA", 3 ) )
00599 {
00600 sign = true;
00601 encr = true;
00602 }
00603 else if( !strncmp( output.data() + pos, "DSS", 3 ) )
00604 sign = true;
00605 else if( !strncmp( output.data() + pos, "Diffie-Hellman", 14 ) )
00606 encr = true;
00607 else
00608 kdDebug(5100)<<"Unknown key algorithm\n";
00609
00610
00611 subkey->setCanEncrypt( encr );
00612 subkey->setCanSign( sign );
00613 subkey->setCanCertify( sign );
00614
00615 if( primaryKey )
00616 {
00617
00618 bool canSign = false;
00619 bool canEncr = false;
00620 pos = pos2 + 1;
00621 while( output[pos] == ' ' )
00622 pos++;
00623 pos2 = eol;
00624 if( !strncmp( output.data() + pos, "Sign & Encrypt", 14 ) )
00625 {
00626 canSign = true;
00627 canEncr = true;
00628 }
00629 else if( !strncmp( output.data() + pos, "Sign only", 9 ) )
00630 canSign = true;
00631 else if( !strncmp( output.data() + pos, "Encrypt only", 12 ) )
00632 canEncr = true;
00633 else
00634 kdDebug(5100)<<"Unknown key capability\n";
00635
00636
00637 if( !key->expired() && !key->revoked() )
00638 {
00639 key->setCanEncrypt( canEncr );
00640 key->setCanSign( canSign );
00641 key->setCanCertify( canSign );
00642 }
00643
00644 primaryKey = false;
00645 }
00646 }
00647 else if( !strncmp( output.data() + offset, "f16", 3 ) ||
00648 !strncmp( output.data() + offset, "f20", 3 ) )
00649 {
00650
00651
00652
00653
00654
00655 int pos = output.find( '=', offset+3 ) + 2;
00656 QCString fingerprint = output.mid( pos, eol-pos );
00657
00658 for ( int idx = 0 ; (idx = fingerprint.find(' ', idx)) >= 0 ; )
00659 fingerprint.replace( idx, 1, "" );
00660 subkey->setFingerprint( fingerprint );
00661
00662 }
00663 else if( !strncmp( output.data() + offset, "uid", 3 ) )
00664 {
00665 int pos = offset+5;
00666 QCString uid = output.mid( pos, eol-pos );
00667 key->addUserID( uid );
00668
00669
00670
00671
00672
00673
00674
00675 }
00676 else if ( !strncmp( output.data() + offset, "sig", 3 ) ||
00677 !strncmp( output.data() + offset, "SIG", 3 ) ||
00678 !strncmp( output.data() + offset, "ret", 3 ) )
00679 {
00680
00681
00682 }
00683
00684 offset = eol + 1;
00685 }
00686
00687 return key;
00688 }
00689
00690
00691 Key*
00692 Base5::parseSingleKey( const QCString& output, Key* key )
00693 {
00694 int offset;
00695
00696
00697 if( !strncmp( output.data(), "Type Bits", 9 ) )
00698 offset = 0;
00699 else
00700 {
00701 offset = output.find( "\nType Bits" ) + 1;
00702 if( offset == 0 )
00703 return 0;
00704 }
00705
00706
00707 offset = output.find( '\n', offset ) + 1;
00708 if( offset == -1 )
00709 return 0;
00710
00711 key = parseKeyData( output, offset, key );
00712
00713
00714
00715 return key;
00716 }
00717
00718
00719 KeyList
00720 Base5::parseKeyList( const QCString& output, bool onlySecretKeys )
00721 {
00722 KeyList keys;
00723 Key *key = 0;
00724 int offset;
00725
00726
00727 if( !strncmp( output.data(), "Type Bits", 9 ) )
00728 offset = 0;
00729 else
00730 {
00731 offset = output.find( "\nType Bits" ) + 1;
00732 if( offset == 0 )
00733 return keys;
00734 }
00735
00736
00737 offset = output.find( '\n', offset ) + 1;
00738 if( offset == -1 )
00739 return keys;
00740
00741 do
00742 {
00743 key = parseKeyData( output, offset );
00744 if( key != 0 )
00745 {
00746
00747 if( !onlySecretKeys || !key->secret() )
00748 keys.append( key );
00749
00750 offset++;
00751 }
00752 }
00753 while( key != 0 );
00754
00755
00756
00757 return keys;
00758 }
00759
00760
00761 void
00762 Base5::parseTrustDataForKey( Key* key, const QCString& str )
00763 {
00764 if( ( key == 0 ) || str.isEmpty() )
00765 return;
00766
00767 QCString keyID = "0x" + key->primaryKeyID();
00768 UserIDList userIDs = key->userIDs();
00769
00770
00771 int offset = str.find( "\n\n KeyID" ) + 9;
00772 if( offset == -1 + 9 )
00773 return;
00774
00775 offset = str.find( '\n', offset ) + 1;
00776 if( offset == -1 + 1 )
00777 return;
00778
00779 bool ultimateTrust = false;
00780 if( !strncmp( str.data() + offset+13, "ultimate", 8 ) )
00781 ultimateTrust = true;
00782
00783 while( true )
00784 {
00785
00786 int eol;
00787
00788
00789 if( ( eol = str.find( '\n', offset ) ) == -1 )
00790 break;
00791
00792 if( str[offset+23] != ' ' )
00793 {
00794
00795
00796 Validity validity = KPGP_VALIDITY_UNKNOWN;
00797 if( !strncmp( str.data() + offset+23, "complete", 8 ) )
00798 if( ultimateTrust )
00799 validity = KPGP_VALIDITY_ULTIMATE;
00800 else
00801 validity = KPGP_VALIDITY_FULL;
00802 else if( !strncmp( str.data() + offset+23, "marginal", 8 ) )
00803 validity = KPGP_VALIDITY_MARGINAL;
00804 else if( !strncmp( str.data() + offset+23, "invalid", 7 ) )
00805 validity = KPGP_VALIDITY_UNDEFINED;
00806
00807
00808 int pos = offset + 33;
00809 QString uid = str.mid( pos, eol-pos );
00810
00811
00812 for( UserIDListIterator it( userIDs ); it.current(); ++it )
00813 if( (*it)->text() == uid )
00814 {
00815 kdDebug(5100)<<"Setting the validity of "<<uid<<" to "<<validity<<endl;
00816 (*it)->setValidity( validity );
00817 break;
00818 }
00819 }
00820
00821 offset = eol + 1;
00822 }
00823 }
00824
00825
00826 }