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 <klocale.h>
00027
#include <kprocess.h>
00028
#include <kdebug.h>
00029
00030
#include <qtextcodec.h>
00031
00032
#include <string.h>
00033
00034
namespace Kpgp {
00035
00036 BaseG::BaseG()
00037 : Base()
00038 {
00039
00040 runGpg(
"--version", 0 );
00041
int eol = output.find(
'\n' );
00042
if( eol > 0 ) {
00043
int pos = output.findRev(
' ', eol - 1 );
00044
if( pos != -1 ) {
00045 mVersion = output.mid( pos + 1, eol - pos - 1 );
00046 kdDebug(5100) <<
"found GnuPG " << mVersion << endl;
00047 }
00048 }
00049 }
00050
00051
00052 BaseG::~BaseG()
00053 {
00054 }
00055
00056
00057
int
00058 BaseG::encrypt( Block& block,
const KeyIDList& recipients )
00059 {
00060
return encsign( block, recipients, 0 );
00061 }
00062
00063
00064
int
00065 BaseG::clearsign( Block& block,
const char *passphrase )
00066 {
00067
return encsign( block, KeyIDList(), passphrase );
00068 }
00069
00070
00071
int
00072 BaseG::encsign( Block& block,
const KeyIDList& recipients,
00073
const char *passphrase )
00074 {
00075
QCString cmd;
00076
int exitStatus = 0;
00077
00078
if(!recipients.isEmpty() && passphrase != 0)
00079 cmd =
"--batch --armor --sign --encrypt --textmode";
00080
else if(!recipients.isEmpty())
00081 cmd =
"--batch --armor --encrypt --textmode";
00082
else if(passphrase != 0)
00083 cmd =
"--batch --escape-from --clearsign";
00084
else
00085 {
00086 kdDebug(5100) <<
"kpgpbase: Neither recipients nor passphrase specified." << endl;
00087
return OK;
00088 }
00089
00090
if(passphrase != 0)
00091 cmd += addUserId();
00092
00093
if(!recipients.isEmpty())
00094 {
00095 cmd +=
" --set-filename stdin";
00096
00097
QCString pgpUser = Module::getKpgp()->user();
00098
if(Module::getKpgp()->encryptToSelf() && !pgpUser.isEmpty()) {
00099 cmd +=
" -r 0x";
00100 cmd += pgpUser;
00101 }
00102
00103
for( KeyIDList::ConstIterator it = recipients.begin();
00104 it != recipients.end(); ++it ) {
00105 cmd +=
" -r 0x";
00106 cmd += (*it);
00107 }
00108 }
00109
00110 clear();
00111 input = block.text();
00112 exitStatus = runGpg(cmd.data(), passphrase);
00113
if( !output.isEmpty() )
00114 block.setProcessedText( output );
00115 block.setError( error );
00116
00117
if( exitStatus != 0 )
00118 {
00119
00120 errMsg = i18n(
"Unknown error." );
00121 status = ERROR;
00122 }
00123
00124
#if 0
00125
00126
00127
00128
if(!recipients.isEmpty())
00129 {
00130
int index = 0;
00131
bool bad = FALSE;
00132
unsigned int num = 0;
00133
QCString badkeys =
"";
00134
00135
00136
00137
00138
00139
00140
00141
while((index = error.find(
"skipped: ",index)) != -1)
00142 {
00143 bad = TRUE;
00144 index = error.find(
'\'',index);
00145
int index2 = error.find(
'\'',index+1);
00146 badkeys += error.mid(index, index2-index+1) +
", ";
00147 num++;
00148 }
00149
if(bad)
00150 {
00151 badkeys.stripWhiteSpace();
00152
if(num == recipients.count())
00153 errMsg = i18n(
"Could not find public keys matching the userid(s)\n"
00154
"%1;\n"
00155
"the message is not encrypted.")
00156 .arg( badkeys.data() );
00157
else
00158 errMsg = i18n(
"Could not find public keys matching the userid(s)\n"
00159
"%1;\n"
00160
"these persons will not be able to read the message.")
00161 .arg( badkeys.data() );
00162 status |= MISSINGKEY;
00163 status |= ERROR;
00164 }
00165 }
00166
#endif
00167
if( passphrase != 0 )
00168 {
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
if( error.find(
"bad passphrase") != -1 )
00182 {
00183 errMsg = i18n(
"Signing failed because the passphrase is wrong.");
00184 status |= BADPHRASE;
00185 status |= ERR_SIGNING;
00186 status |= ERROR;
00187 }
00188
else if( error.find(
"unusable secret key") != -1 )
00189 {
00190 errMsg = i18n(
"Signing failed because your secret key is unusable.");
00191 status |= ERR_SIGNING;
00192 status |= ERROR;
00193 }
00194
else if( !( status & ERROR ) )
00195 {
00196
00197 status |= SIGNED;
00198 }
00199 }
00200
00201
00202 block.setStatus( status );
00203
return status;
00204 }
00205
00206
00207
int
00208 BaseG::decrypt( Block& block,
const char *passphrase )
00209 {
00210
int index, index2;
00211
int exitStatus = 0;
00212
00213 clear();
00214 input = block.text();
00215 exitStatus = runGpg(
"--batch --decrypt", passphrase);
00216
if( !output.isEmpty() && ( error.find(
"gpg: quoted printable" ) == -1 ) )
00217 block.setProcessedText( output );
00218 block.setError( error );
00219
00220
if(exitStatus == -1) {
00221 errMsg = i18n(
"Error running gpg");
00222 status = RUN_ERR;
00223 block.setStatus( status );
00224
return status;
00225 }
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
if( error.find(
"gpg: encrypted with" ) != -1 )
00248 {
00249
00250 status |= ENCRYPTED;
00251
if( error.find(
"\ngpg: decryption failed" ) != -1 )
00252 {
00253
if( ( index = error.find(
"bad passphrase" ) ) != -1 )
00254 {
00255
if( passphrase != 0 )
00256 {
00257 errMsg = i18n(
"Bad passphrase; could not decrypt." );
00258 kdDebug(5100) <<
"Base: passphrase is bad" << endl;
00259 status |= BADPHRASE;
00260 status |= ERROR;
00261 }
00262
else
00263 {
00264
00265 index2 = error.findRev(
'"', index) - 1;
00266 index = error.findRev(
" \"", index2) + 7;
00267
00268
00269 block.setRequiredUserId( QString::fromUtf8( error.mid( index, index2 - index + 1 ) ) );
00270 kdDebug(5100) <<
"Base: key needed is \"" << block.requiredUserId() <<
"\"!" << endl;
00271 }
00272 }
00273
else if( error.find(
"secret key not available" ) != -1 )
00274 {
00275
00276 status |= NO_SEC_KEY;
00277 status |= ERROR;
00278 errMsg = i18n(
"You do not have the secret key needed to decrypt this message.");
00279 kdDebug(5100) <<
"Base: no secret key for this message" << endl;
00280 }
00281 }
00282
00283
#if 0
00284
00285
00286 index = error.find(
"can only be read by:");
00287
if(index != -1)
00288 {
00289 index = error.find(
'\n',index);
00290
int end = error.find(
"\n\n",index);
00291
00292 mRecipients.clear();
00293
while( (index2 = error.find(
'\n',index+1)) <= end )
00294 {
00295
QCString item = error.mid(index+1,index2-index-1);
00296 item.stripWhiteSpace();
00297 mRecipients.append(item);
00298 index = index2;
00299 }
00300 }
00301
#endif
00302
}
00303
00304
00305
00306
00307
if((index = error.find(
"Signature made")) != -1)
00308 {
00309
00310 status |= SIGNED;
00311
00312
00313 index2 = error.find(
"using", index+15);
00314 block.setSignatureDate( error.mid(index+15, index2-(index+15)-1) );
00315 kdDebug(5100) <<
"Message was signed on '" << block.signatureDate() <<
"'\n";
00316 index2 = error.find(
"key ID ", index2) + 7;
00317 block.setSignatureKeyId( error.mid(index2,8) );
00318 kdDebug(5100) <<
"Message was signed with key '" << block.signatureKeyId() <<
"'\n";
00319
00320 index = error.find(
'\n', index2)+1;
00321
00322
if ((error.find(
"Key matching expected", index) != -1)
00323 || (error.find(
"Can't check signature", index) != -1))
00324 {
00325 status |= UNKNOWN_SIG;
00326 status |= GOODSIG;
00327 block.setSignatureUserId( QString::null );
00328 }
00329
else if( error.find(
"Good signature", index) != -1 )
00330 {
00331 status |= GOODSIG;
00332
00333 index = error.find(
'"',index);
00334 index2 = error.find(
'\n',index+1);
00335 index2 = error.findRev(
'"', index2-1);
00336 block.setSignatureUserId( error.mid( index+1, index2-index-1 ) );
00337 }
00338
else if( error.find(
"BAD signature", index) != -1 )
00339 {
00340
00341 status |= ERROR;
00342
00343 index = error.find(
'"',index);
00344 index2 = error.find(
'\n',index+1);
00345 index2 = error.findRev(
'"', index2-1);
00346 block.setSignatureUserId( error.mid( index+1, index2-index-1 ) );
00347 }
00348
else if( error.find(
"Can't find the right public key", index) != -1 )
00349 {
00350
00351
00352
00353 status |= UNKNOWN_SIG;
00354 status |= GOODSIG;
00355 block.setSignatureUserId( i18n(
"??? (file ~/.gnupg/pubring.gpg not found)") );
00356 }
00357
else
00358 {
00359 status |= ERROR;
00360 block.setSignatureUserId( QString::null );
00361 }
00362 }
00363
00364 block.setStatus( status );
00365
return status;
00366 }
00367
00368
00369 Key*
00370 BaseG::readPublicKey(
const KeyID& keyID,
00371
const bool readTrust ,
00372 Key* key )
00373 {
00374
int exitStatus = 0;
00375
00376 status = 0;
00377
if( readTrust )
00378 exitStatus = runGpg(
"--batch --list-public-keys --with-fingerprint --with-colons --fixed-list-mode 0x" + keyID, 0,
true );
00379
else
00380 exitStatus = runGpg(
"--batch --list-public-keys --with-fingerprint --with-colons --fixed-list-mode --no-expensive-trust-checks 0x" + keyID, 0,
true );
00381
00382
if(exitStatus != 0) {
00383 status = ERROR;
00384
return 0;
00385 }
00386
00387
int offset;
00388
00389
if( !strncmp( output.data(),
"pub:", 4 ) )
00390 offset = 0;
00391
else {
00392 offset = output.find(
"\npub:" );
00393
if( offset == -1 )
00394
return 0;
00395
else
00396 offset++;
00397 }
00398
00399 key = parseKeyData( output, offset, key );
00400
00401
return key;
00402 }
00403
00404
00405 KeyList
00406 BaseG::publicKeys(
const QStringList & patterns )
00407 {
00408
int exitStatus = 0;
00409
00410
00411
00412
QCString cmd =
"--batch --list-public-keys --with-fingerprint --with-colons "
00413
"--fixed-list-mode --no-expensive-trust-checks";
00414
for ( QStringList::ConstIterator it = patterns.begin();
00415 it != patterns.end(); ++it ) {
00416 cmd +=
" ";
00417 cmd += KProcess::quote( *it ).local8Bit();
00418 }
00419 status = 0;
00420 exitStatus = runGpg( cmd, 0,
true );
00421
00422
if(exitStatus != 0) {
00423 status = ERROR;
00424
return KeyList();
00425 }
00426
00427
00428 KeyList publicKeys = parseKeyList(output,
false);
00429
00430
00431 publicKeys.sort();
00432
00433
return publicKeys;
00434 }
00435
00436
00437 KeyList
00438 BaseG::secretKeys(
const QStringList & patterns )
00439 {
00440
int exitStatus = 0;
00441
00442
00443
00444
QCString cmd =
"--batch --list-secret-keys --with-fingerprint --with-colons "
00445
"--fixed-list-mode";
00446
for ( QStringList::ConstIterator it = patterns.begin();
00447 it != patterns.end(); ++it ) {
00448 cmd +=
" ";
00449 cmd += KProcess::quote( *it ).local8Bit();
00450 }
00451 status = 0;
00452 exitStatus = runGpg( cmd, 0,
true );
00453
00454
if(exitStatus != 0) {
00455 status = ERROR;
00456
return KeyList();
00457 }
00458
00459
00460 KeyList secretKeys = parseKeyList(output,
true);
00461
00462
00463 secretKeys.sort();
00464
00465
return secretKeys;
00466 }
00467
00468
00469
int
00470 BaseG::signKey(
const KeyID& keyID,
const char *passphrase)
00471 {
00472
QCString cmd;
00473
int exitStatus = 0;
00474
00475 cmd =
"--batch";
00476 cmd += addUserId();
00477 cmd +=
" --sign-key 0x";
00478 cmd += keyID;
00479
00480 status = 0;
00481 exitStatus = runGpg(cmd.data(), passphrase);
00482
00483
if (exitStatus != 0)
00484 status = ERROR;
00485
00486
return status;
00487 }
00488
00489
00490
QCString
00491 BaseG::getAsciiPublicKey(
const KeyID& keyID)
00492 {
00493
int exitStatus = 0;
00494
00495
if (keyID.isEmpty())
00496
return QCString();
00497
00498 status = 0;
00499 exitStatus = runGpg(
"--batch --armor --export 0x" + keyID, 0,
true);
00500
00501
if(exitStatus != 0) {
00502 status = ERROR;
00503
return QCString();
00504 }
00505
00506
return output;
00507 }
00508
00509
00510 Key*
00511 BaseG::parseKeyData(
const QCString& output,
int& offset, Key* key )
00512
00513
00514
00515
00516
00517
00518
00519 {
00520
int index = offset;
00521
00522
if( ( strncmp( output.data() + offset,
"pub:", 4 ) != 0 )
00523 && ( strncmp( output.data() + offset,
"sec:", 4 ) != 0 ) ) {
00524
return 0;
00525 }
00526
00527
if( key == 0 )
00528 key =
new Key();
00529
else
00530 key->clear();
00531
00532
QCString keyID;
00533
bool firstKey =
true;
00534
00535
while(
true )
00536 {
00537
int eol;
00538
00539
if( ( eol = output.find(
'\n', index ) ) == -1 )
00540
break;
00541
00542
bool bIsPublicKey =
false;
00543
if( ( bIsPublicKey = !strncmp( output.data() + index,
"pub:", 4 ) )
00544 || !strncmp( output.data() + index,
"sec:", 4 ) )
00545 {
00546
00547
00548
00549
if( !firstKey )
00550
break;
00551 firstKey =
false;
00552
00553 key->setSecret( !bIsPublicKey );
00554
00555 Subkey *subkey =
new Subkey(
QCString(), !bIsPublicKey );
00556
00557
int pos = index + 4;
00558
int pos2 = output.find(
':', pos );
00559
for(
int field = 2; field <= 12; field++ )
00560 {
00561
switch( field )
00562 {
00563
case 2:
00564
if( pos2 > pos )
00565 {
00566
switch( output[pos] )
00567 {
00568
case 'o':
00569
break;
00570
case 'i':
00571 subkey->setInvalid(
true );
00572 key->setInvalid(
true );
00573
break;
00574
case 'd':
00575 subkey->setDisabled(
true );
00576 key->setDisabled(
true );
00577
break;
00578
case 'r':
00579 subkey->setRevoked(
true );
00580 key->setRevoked(
true );
00581
break;
00582
case 'e':
00583 subkey->setExpired(
true );
00584 key->setExpired(
true );
00585
break;
00586
case '-':
00587
case 'q':
00588
case 'n':
00589
case 'm':
00590
case 'f':
00591
case 'u':
00592
00593
00594
break;
00595
default:
00596 kdDebug(5100) <<
"Unknown trust value\n";
00597 }
00598 }
00599
break;
00600
case 3:
00601
if( pos2 > pos )
00602 subkey->setKeyLength( output.mid( pos, pos2-pos ).toUInt() );
00603
break;
00604
case 4:
00605
if( pos2 > pos )
00606 subkey->setKeyAlgorithm( output.mid( pos, pos2-pos ).toUInt() );
00607
break;
00608
case 5:
00609 keyID = output.mid( pos, pos2-pos );
00610 subkey->setKeyID( keyID );
00611
break;
00612
case 6:
00613
if( pos2 > pos )
00614 subkey->setCreationDate( output.mid( pos, pos2-pos ).toLong() );
00615
break;
00616
case 7:
00617
if( pos2 > pos )
00618 subkey->setExpirationDate( output.mid( pos, pos2-pos ).toLong() );
00619
else
00620 subkey->setExpirationDate( -1 );
00621
break;
00622
case 8:
00623
case 9:
00624
case 10:
00625
case 11:
00626
break;
00627
case 12:
00628
for(
int i=pos; i<pos2; i++ )
00629
switch( output[i] )
00630 {
00631
case 'e':
00632 subkey->setCanEncrypt(
true );
00633
break;
00634
case 's':
00635 subkey->setCanSign(
true );
00636
break;
00637
case 'c':
00638 subkey->setCanCertify(
true );
00639
break;
00640
case 'E':
00641 key->setCanEncrypt(
true );
00642
break;
00643
case 'S':
00644 key->setCanSign(
true );
00645
break;
00646
case 'C':
00647 key->setCanCertify(
true );
00648
break;
00649
default:
00650 kdDebug(5100) <<
"Unknown key capability\n";
00651 }
00652
break;
00653 }
00654 pos = pos2 + 1;
00655 pos2 = output.find(
':', pos );
00656 }
00657 key->addSubkey( subkey );
00658 }
00659
else if( !strncmp( output.data() + index,
"uid:", 4 ) )
00660 {
00661
00662
00663 UserID *userID =
new UserID(
"" );
00664
00665
int pos = index + 4;
00666
int pos2 = output.find(
':', pos );
00667
for(
int field=2; field <= 10; field++ )
00668 {
00669
switch( field )
00670 {
00671
case 2:
00672
if( pos2 > pos )
00673 {
00674
switch( output[pos] )
00675 {
00676
case 'i':
00677 userID->setInvalid(
true );
00678
break;
00679
case 'r':
00680 userID->setRevoked(
true );
00681
break;
00682
case '-':
00683
case 'q':
00684 userID->setValidity( KPGP_VALIDITY_UNDEFINED );
00685
break;
00686
case 'n':
00687 userID->setValidity( KPGP_VALIDITY_NEVER );
00688
break;
00689
case 'm':
00690 userID->setValidity( KPGP_VALIDITY_MARGINAL );
00691
break;
00692
case 'f':
00693 userID->setValidity( KPGP_VALIDITY_FULL );
00694
break;
00695
case 'u':
00696 userID->setValidity( KPGP_VALIDITY_ULTIMATE );
00697
break;
00698
default:
00699 kdDebug(5100) <<
"Unknown trust value\n";
00700 }
00701 }
00702
break;
00703
case 3:
00704
case 4:
00705
case 5:
00706
case 6:
00707
case 7:
00708
case 8:
00709
case 9:
00710
break;
00711
case 10:
00712
QCString uid = output.mid( pos, pos2-pos );
00713
00714
00715
00716
for (
int idx = 0 ; (idx = uid.find(
"\\x", idx )) >= 0 ; ++idx ) {
00717
char str[2] =
"x";
00718 str[0] = (
char)
QString( uid.mid( idx + 2, 2 ) ).toShort( 0, 16 );
00719 uid.replace( idx, 4, str );
00720 }
00721
QString uidString = QString::fromUtf8( uid.data() );
00722
00723
bool isUtf8 =
true;
00724
for (
unsigned int i = 0; i + 1 < uidString.length(); ++i ) {
00725
if ( uidString[i].unicode() == 0xdbff &&
00726 uidString[i+1].row() == 0xde ) {
00727
00728 isUtf8 =
false;
00729
break;
00730 }
00731 }
00732
if( !isUtf8 ) {
00733
00734
00735 kdDebug(5100) <<
"User Id '" << uid
00736 <<
"' doesn't seem to be utf-8 encoded." << endl;
00737
00738
00739
00740
int nonAsciiCount = 0, asciiCount = 0;
00741
00742
00743
00744
for(
signed char* ch = (
signed char*)uid.data();
00745 *ch && ( *ch !=
'(' ) && ( *ch !=
'<' );
00746 ++ch ) {
00747
if( ( ( *ch >=
'A' ) && ( *ch <=
'Z' ) )
00748 || ( ( *ch >=
'a' ) && ( *ch <=
'z' ) ) )
00749 ++asciiCount;
00750
else if( *ch < 0 )
00751 ++nonAsciiCount;
00752 }
00753 kdDebug(5100) <<
"ascii-nonAscii ratio : " << asciiCount
00754 <<
":" << nonAsciiCount << endl;
00755
if( nonAsciiCount > asciiCount ) {
00756
00757 kdDebug(5100) <<
"Assume koi8-r encoding." << endl;
00758
QTextCodec *codec = QTextCodec::codecForName(
"KOI8-R");
00759 uidString = codec->toUnicode( uid.data() );
00760
00761
00762
00763
00764
00765
00766
00767
if( ( uidString.length() >= 2 )
00768 && ( uidString[0].lower() == uidString[0] )
00769 && ( uidString[1].upper() == uidString[1] ) ) {
00770
00771
00772 kdDebug(5100) <<
"No, it doesn't seem to be koi8-r. "
00773
"Use CP 1251 instead." << endl;
00774
QTextCodec *codec = QTextCodec::codecForName(
"CP1251");
00775 uidString = codec->toUnicode( uid.data() );
00776 }
00777 }
00778
else {
00779
00780 kdDebug(5100) <<
"Assume latin1 encoding." << endl;
00781 uidString = QString::fromLatin1( uid.data() );
00782 }
00783 }
00784 userID->setText( uidString );
00785
break;
00786 }
00787 pos = pos2 + 1;
00788 pos2 = output.find(
':', pos );
00789 }
00790
00791
00792 key->addUserID( userID );
00793 }
00794
else if( !strncmp( output.data() + index,
"fpr:", 4 ) )
00795 {
00796
00797
00798
if (key == 0)
00799
break;
00800
00801
00802
int pos = index + 4;
00803
for(
int i = 0; i < 8; i++ )
00804 pos = output.find(
':', pos ) + 1;
00805
int pos2 = output.find(
':', pos );
00806
00807 key->setFingerprint( keyID, output.mid( pos, pos2-pos ) );
00808 }
00809 index = eol + 1;
00810 }
00811
00812
00813
00814 offset = index;
00815
00816
return key;
00817 }
00818
00819
00820 KeyList
00821 BaseG::parseKeyList(
const QCString& output,
bool secretKeys )
00822 {
00823 KeyList keys;
00824 Key *key = 0;
00825
int offset;
00826
00827
00828
if( !strncmp( output.data(),
"pub:", 4 )
00829 || !strncmp( output.data(),
"sec:", 4 ) )
00830 offset = 0;
00831
else {
00832
if( secretKeys )
00833 offset = output.find(
"\nsec:" );
00834
else
00835 offset = output.find(
"\npub:" );
00836
if( offset == -1 )
00837
return keys;
00838
else
00839 offset++;
00840 }
00841
00842
do {
00843 key = parseKeyData( output, offset );
00844
if( key != 0 )
00845 keys.append( key );
00846 }
00847
while( key != 0 );
00848
00849
00850
00851
return keys;
00852 }
00853
00854
00855 }