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