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