00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "kpgpbase.h"
00020
00021 #include <string.h>
00022 #include <assert.h>
00023
00024 #include <QDateTime>
00025
00026 #include <QByteArray>
00027
00028 #include <klocale.h>
00029 #include <kdebug.h>
00030
00031 #define PGP6 "pgp"
00032
00033 namespace Kpgp {
00034
00035 Base6::Base6()
00036 : Base2()
00037 {
00038 }
00039
00040
00041 Base6::~Base6()
00042 {
00043 }
00044
00045
00046 int
00047 Base6::decrypt( Block& block, const char *passphrase )
00048 {
00049 int index, index2;
00050 int exitStatus = 0;
00051
00052 clear();
00053 input = block.text();
00054 exitStatus = run( PGP6 " +batchmode +language=C -f", passphrase);
00055 if( !output.isEmpty() )
00056 block.setProcessedText( output );
00057 block.setError( error );
00058
00059 if(exitStatus == -1) {
00060 errMsg = i18n("error running PGP");
00061 status = ERROR;
00062 block.setStatus( status );
00063 return status;
00064 }
00065
00066
00067 if( error.contains("File is encrypted.") )
00068 {
00069
00070 status |= ENCRYPTED;
00071 if((index = error.indexOf("Key for user ID")) != -1 )
00072 {
00073
00074 index = error.indexOf(':', index) + 2;
00075 index2 = error.indexOf('\n', index);
00076 block.setRequiredUserId( error.mid(index, index2 - index) );
00077
00078
00079
00080
00083 if (!passphrase || !output.length())
00084 {
00085 errMsg = i18n("Bad passphrase; could not decrypt.");
00086
00087 status |= BADPHRASE;
00088 status |= ERROR;
00089 }
00090 }
00091 else if( error.contains("You do not have the secret key needed to decrypt this file.") )
00092 {
00093 errMsg = i18n("You do not have the secret key for this message.");
00094
00095 status |= NO_SEC_KEY;
00096 status |= ERROR;
00097 }
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 if(((index = error.indexOf("File is signed.")) != -1 )
00125 || (error.contains("Good signature") ))
00126 {
00127
00128 status |= SIGNED;
00129
00130 if( ( index2 = error.indexOf( "Signature made", index ) ) != -1 )
00131 {
00132 index2 += 15;
00133 int eol = error.indexOf( '\n', index2 );
00134 block.setSignatureDate( error.mid( index2, eol-index2 ) );
00135 kDebug( 5326 ) <<"Message was signed on '" << block.signatureDate() <<"'";
00136 }
00137 else
00138 block.setSignatureDate( QByteArray() );
00139
00140 if( error.contains("signature not checked") )
00141 {
00142 index = error.indexOf("KeyID:",index);
00143 block.setSignatureKeyId( error.mid(index+9,8) );
00144 block.setSignatureUserId( QString() );
00145 status |= UNKNOWN_SIG;
00146 status |= GOODSIG;
00147 }
00148 else if((index = error.indexOf("Good signature")) != -1 )
00149 {
00150 status |= GOODSIG;
00151
00152 index = error.indexOf('"',index)+1;
00153 index2 = error.indexOf('"', index);
00154 block.setSignatureUserId( error.mid(index, index2-index) );
00155
00156
00157 index = error.indexOf("KeyID:",index2);
00158 if (index == -1)
00159 block.setSignatureKeyId( QByteArray() );
00160 else
00161 block.setSignatureKeyId( error.mid(index+9,8) );
00162 }
00163 else if( error.contains("Can't find the right public key") )
00164 {
00165
00166
00167
00168 status |= UNKNOWN_SIG;
00169 status |= GOODSIG;
00170 block.setSignatureUserId( i18n("??? (file ~/.pgp/pubring.pkr not found)") );
00171 block.setSignatureKeyId( "???" );
00172 }
00173 else
00174 {
00175 status |= ERROR;
00176 block.setSignatureUserId( QString() );
00177 block.setSignatureKeyId( QByteArray() );
00178 }
00179 }
00180
00181 block.setStatus( status );
00182 return status;
00183 }
00184
00185
00186 Key*
00187 Base6::readPublicKey( const KeyID& keyID,
00188 const bool readTrust ,
00189 Key* key )
00190 {
00191 int exitStatus = 0;
00192
00193 status = 0;
00194 exitStatus = run( PGP6 " +batchmode -compatible +verbose=0 +language=C -kvvc "
00195 "0x" + keyID, 0, true );
00196
00197 if(exitStatus != 0) {
00198 status = ERROR;
00199 return 0;
00200 }
00201
00202 key = parseSingleKey( output, key );
00203
00204 if( key == 0 )
00205 {
00206 return 0;
00207 }
00208
00209 if( readTrust )
00210 {
00211 exitStatus = run( PGP6 " +batchmode -compatible +verbose=0 +language=C -kc "
00212 "0x" + keyID, 0, true );
00213
00214 if(exitStatus != 0) {
00215 status = ERROR;
00216 return 0;
00217 }
00218
00219 parseTrustDataForKey( key, output );
00220 }
00221
00222 return key;
00223 }
00224
00225
00226 KeyList
00227 Base6::publicKeys( const QStringList & patterns )
00228 {
00229 return doGetPublicKeys( PGP6 " +batchmode -compatible +verbose=0 "
00230 "+language=C -kvvc", patterns );
00231 }
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 KeyList
00344 Base6::secretKeys( const QStringList & patterns )
00345 {
00346 return publicKeys( patterns );
00347 }
00348
00349
00350 int
00351 Base6::isVersion6()
00352 {
00353 int exitStatus = 0;
00354
00355 exitStatus = run( PGP6, 0, true );
00356
00357 if(exitStatus == -1) {
00358 errMsg = i18n("error running PGP");
00359 status = ERROR;
00360 return 0;
00361 }
00362
00363 if( error.contains("Version 6") )
00364 {
00365
00366 return 1;
00367 }
00368
00369
00370 return 0;
00371 }
00372
00373
00374 Key*
00375 Base6::parseKeyData( const QByteArray& output, int& offset, Key* key )
00376
00377
00378
00379
00380
00381 {
00382 if( ( strncmp( output.data() + offset, "DSS", 3 ) != 0 ) &&
00383 ( strncmp( output.data() + offset, "RSA", 3 ) != 0 ) )
00384 {
00385 kDebug( 5326 ) <<"Unknown key type or corrupt key data.";
00386 return 0;
00387 }
00388
00389 Subkey *subkey = 0;
00390 bool firstLine = true;
00391 bool canSign = false;
00392 bool canEncr = false;
00393 bool fpr = false;
00394
00395 while( true )
00396 {
00397 int eol;
00398
00399
00400 if( ( eol = output.indexOf( '\n', offset ) ) == -1 )
00401 break;
00402
00403
00404
00405 if( firstLine && ( !strncmp( output.data() + offset, "DSS", 3 ) ||
00406 !strncmp( output.data() + offset, "RSA", 3 ) ) )
00407 {
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425 bool sign = false;
00426 bool encr = false;
00427
00428
00429 if( !strncmp( output.data() + offset, "DSS", 3 ) )
00430 sign = true;
00431 if( !strncmp( output.data() + offset, "RSA", 3 ) )
00432 {
00433 sign = true;
00434 encr = true;
00435 }
00436
00437 int pos, pos2;
00438
00439 if( key == 0 )
00440 key = new Key();
00441 else
00442 key->clear();
00443
00444 subkey = new Subkey( "", false );
00445 key->addSubkey( subkey );
00446
00447 subkey->setExpirationDate( -1 );
00448
00449
00450 switch( output[offset+3] )
00451 {
00452 case ' ':
00453 break;
00454 case '@':
00455 subkey->setDisabled( true );
00456 key->setDisabled( true );
00457 break;
00458 default:
00459 kDebug( 5326 ) <<"Unknown key flag.";
00460 }
00461
00462
00463 pos = offset + 4;
00464 while( output[pos] == ' ' )
00465 pos++;
00466 pos2 = output.indexOf( ' ', pos );
00467 subkey->setKeyLength( output.mid( pos, pos2-pos ).toUInt() );
00468
00469
00470
00471 pos = pos2 + 1;
00472 while( output[pos] == ' ' )
00473 pos++;
00474 pos += 2;
00475 pos2 = output.indexOf( ' ', pos );
00476 subkey->setKeyID( output.mid( pos, pos2-pos ) );
00477
00478
00479
00480 pos = pos2 + 1;
00481 while( output[pos] == ' ' )
00482 pos++;
00483 pos2 = output.indexOf( ' ', pos );
00484 int year = output.mid( pos, 4 ).toInt();
00485 int month = output.mid( pos+5, 2 ).toInt();
00486 int day = output.mid( pos+8, 2 ).toInt();
00487 QDateTime dt( QDate( year, month, day ), QTime( 00, 00 ) );
00488 QDateTime epoch( QDate( 1970, 01, 01 ), QTime( 00, 00 ) );
00489
00490
00491
00492
00493 subkey->setCreationDate( epoch.secsTo( dt ) );
00494
00495
00496 pos = pos2 + 1;
00497 while( output[pos] == ' ' )
00498 pos++;
00499 while( pos < eol )
00500 {
00501 if( !strncmp( output.data() + pos, "*** KEY REVOKED ***", 19 ) )
00502 {
00503 sign = false;
00504 encr = false;
00505 subkey->setRevoked( true );
00506 key->setRevoked( true );
00507 pos += 19;
00508
00509 }
00510 else if( !strncmp( output.data() + pos, "*** KEY EXPIRED ***", 19 ) )
00511 {
00512 sign = false;
00513 encr = false;
00514 subkey->setExpired( true );
00515 key->setExpired( true );
00516 pos += 19;
00517
00518 }
00519 else if( !strncmp( output.data() + pos, "expires ", 8 ) )
00520 {
00521 pos += 8;
00522 int year = output.mid( pos, 4 ).toInt();
00523 int month = output.mid( pos+5, 2 ).toInt();
00524 int day = output.mid( pos+8, 2 ).toInt();
00525 QDateTime dt( QDate( year, month, day ), QTime( 00, 00 ) );
00526
00527 subkey->setExpirationDate( epoch.secsTo( dt ) );
00528 pos += 10;
00529
00530 }
00531 else if( !strncmp( output.data() + pos, "*** DEFAULT SIGNING KEY ***", 27 ) )
00532 {
00533 pos += 27;
00534
00535 }
00536 else
00537 {
00538 QByteArray uid = output.mid( pos, eol-pos );
00539 key->addUserID( uid );
00540 pos = eol;
00541
00542 }
00543 }
00544
00545 subkey->setCanEncrypt( encr );
00546 subkey->setCanSign( sign );
00547 subkey->setCanCertify( sign );
00548
00549 canSign = sign;
00550 canEncr = encr;
00551 }
00552 else if( !strncmp( output.data() + offset, "DSS", 3 ) ||
00553 !strncmp( output.data() + offset, " DH", 3 ) ||
00554 !strncmp( output.data() + offset, "RSA", 3 ) )
00555 {
00556 if( fpr )
00557 break;
00558
00559
00560 if( key == 0 )
00561 break;
00562
00563 bool sign = false;
00564 bool encr = false;
00565
00566
00567 if( !strncmp( output.data() + offset, "DSS", 3 ) )
00568 sign = true;
00569 if( !strncmp( output.data() + offset, " DH", 3 ) )
00570 encr = true;
00571 if( !strncmp( output.data() + offset, "RSA", 3 ) )
00572 {
00573 sign = true;
00574 encr = true;
00575 }
00576
00577 int pos, pos2;
00578
00579
00580 pos = offset + 4;
00581 while( output[pos] == ' ' )
00582 pos++;
00583 pos2 = output.indexOf( ' ', pos );
00584
00585
00586 pos = pos2 + 1;
00587 while( output[pos] == ' ' )
00588 pos++;
00589 pos2 = output.indexOf( ' ', pos );
00590
00591
00592 pos = pos2 + 1;
00593 while( output[pos] == ' ' )
00594 pos++;
00595 pos2 = output.indexOf( ' ', pos );
00596
00597
00598 pos = pos2 + 1;
00599 while( output[pos] == ' ' )
00600 pos++;
00601 while( pos < eol )
00602 {
00603 if( !strncmp( output.data() + pos, "*** KEY REVOKED ***", 19 ) )
00604 {
00605 sign = false;
00606 encr = false;
00607 pos += 19;
00608
00609 }
00610 else if( !strncmp( output.data() + pos, "*** KEY EXPIRED ***", 19 ) )
00611 {
00612 sign = false;
00613 encr = false;
00614 pos += 19;
00615
00616 }
00617 else if( !strncmp( output.data() + pos, "expires ", 8 ) )
00618 {
00619 pos += 18;
00620
00621 }
00622 else if( !strncmp( output.data() + pos, "*** DEFAULT SIGNING KEY ***", 27 ) )
00623 {
00624 pos += 27;
00625
00626 }
00627 else
00628 {
00629 QByteArray uid = output.mid( pos, eol-pos );
00630 key->addUserID( uid );
00631 pos = eol;
00632
00633 }
00634 }
00635
00636 canSign = canSign || sign;
00637 canEncr = canEncr || encr;
00638 }
00639 else if( !strncmp( output.data() + offset, "Unknown type", 12 ) )
00640 {
00641 kDebug( 5326 )<<"Unknown key type.";
00642 }
00643 else if( output[offset] == ' ' )
00644 {
00645 if( key == 0 )
00646 break;
00647
00648
00649 int pos = offset + 1;
00650 while( output[pos] == ' ' )
00651 pos++;
00652
00653 if( !strncmp( output.data() + pos, "Key fingerprint = ", 18 ) )
00654 {
00655
00656
00657
00658 fpr = true;
00659
00660 pos += 18;
00661 QByteArray fingerprint = output.mid( pos, eol-pos );
00662
00663 for ( int idx = 0 ; (idx = fingerprint.indexOf(' ', idx)) != -1; )
00664 fingerprint.replace( idx, 1, "" );
00665
00666
00667 assert( subkey != 0 );
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 QByteArray& 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.indexOf( "\nType bits" );
00714 if( offset == -1 )
00715 return 0;
00716 else
00717 offset += 10;
00718 }
00719
00720
00721 offset = output.indexOf( '\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 QByteArray& output, bool secretKeys )
00735 {
00736 kDebug( 5326 ) <<"Kpgp::Base6::parseKeyList()";
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.indexOf( "\nType bits" ) + 1;
00747 if( offset == 0 )
00748 return keys;
00749 }
00750
00751
00752 offset = output.indexOf( '\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 QByteArray& str )
00775 {
00776 if( ( key == 0 ) || str.isEmpty() )
00777 return;
00778
00779 QByteArray keyID = "0x" + key->primaryKeyID();
00780 UserIDList userIDs = key->userIDs();
00781
00782
00783 int offset = str.indexOf( "\n\n KeyID" );
00784 if( offset == -1 )
00785 return;
00786
00787 offset = str.indexOf( '\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.indexOf( '\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 kDebug( 5326 )<<"Setting the validity of"<<uid<<" to"<<validity;
00828 (*it)->setValidity( validity );
00829 break;
00830 }
00831 }
00832
00833 offset = eol + 1;
00834 }
00835 }
00836
00837
00838 }