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 }