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 }