libkpgp

kpgpbase2.cpp

00001 /*
00002     kpgpbase2.cpp
00003 
00004     Copyright (C) 2001,2002 the KPGP authors
00005     See file AUTHORS.kpgp for details
00006 
00007     This file is part of KPGP, the KDE PGP/GnuPG support library.
00008 
00009     KPGP is free software; you can redistribute it and/or modify
00010     it under the terms of the GNU General Public License as published by
00011     the Free Software Foundation; either version 2 of the License, or
00012     (at your option) any later version.
00013 
00014     You should have received a copy of the GNU General Public License
00015     along with this program; if not, write to the Free Software Foundation,
00016     Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
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 <string.h> /* strncmp */
00027 #include <assert.h>
00028 
00029 #include <qdatetime.h>
00030 
00031 #include <klocale.h>
00032 #include <kprocess.h>
00033 #include <kdebug.h>
00034 
00035 #define PGP2 "pgp"
00036 
00037 namespace Kpgp {
00038 
00039 Base2::Base2()
00040   : Base()
00041 {
00042 }
00043 
00044 
00045 Base2::~Base2()
00046 {
00047 }
00048 
00049 
00050 int
00051 Base2::encrypt( Block& block, const KeyIDList& recipients )
00052 {
00053   return encsign( block, recipients, 0 );
00054 }
00055 
00056 
00057 int
00058 Base2::clearsign( Block& block, const char *passphrase )
00059 {
00060   return encsign( block, KeyIDList(), passphrase );
00061 }
00062 
00063 
00064 int
00065 Base2::encsign( Block& block, const KeyIDList& recipients,
00066                 const char *passphrase )
00067 {
00068   QCString cmd;
00069   int exitStatus = 0;
00070 
00071   if(!recipients.isEmpty() && passphrase != 0)
00072     cmd = PGP2 " +batchmode +language=en +verbose=1 -seat";
00073   else if(!recipients.isEmpty())
00074     cmd = PGP2 " +batchmode +language=en +verbose=1 -eat";
00075   else if(passphrase != 0)
00076     cmd = PGP2 " +batchmode +language=en +verbose=1 -sat";
00077   else
00078   {
00079     kdDebug(5100) << "kpgpbase: Neither recipients nor passphrase specified." << endl;
00080     return OK;
00081   }
00082 
00083   if(passphrase != 0)
00084     cmd += addUserId();
00085 
00086   if(!recipients.isEmpty()) {
00087     if(Module::getKpgp()->encryptToSelf())
00088     {
00089       cmd += " 0x";
00090       cmd += Module::getKpgp()->user();
00091     }
00092 
00093     for( KeyIDList::ConstIterator it = recipients.begin();
00094          it != recipients.end(); ++it ) {
00095       cmd += " 0x";
00096       cmd += (*it);
00097     }
00098   }
00099   cmd += " -f";
00100 
00101   clear();
00102   input = block.text();
00103   exitStatus = run(cmd.data(), passphrase);
00104   if( !output.isEmpty() )
00105     block.setProcessedText( output );
00106   block.setError( error );
00107 
00108   if(exitStatus != 0)
00109     status = ERROR;
00110 
00111 #if 0
00112   // #### FIXME: As we check the keys ourselves the following problems
00113   //             shouldn't occur. Therefore I don't handle them for now.
00114   //             IK 01/2002
00115   if(!recipients.isEmpty())
00116   {
00117     int index = 0;
00118     bool bad = FALSE;
00119     unsigned int num = 0;
00120     QCString badkeys = "";
00121     if (error.find("Cannot find the public key") != -1)
00122     {
00123       index = 0;
00124       num = 0;
00125       while((index = error.find("Cannot find the public key",index))
00126         != -1)
00127       {
00128         bad = TRUE;
00129         index = error.find('\'',index);
00130         int index2 = error.find('\'',index+1);
00131         if (num++)
00132           badkeys += ", ";
00133         badkeys += error.mid(index, index2-index+1);
00134       }
00135       if(bad)
00136       {
00137         badkeys.stripWhiteSpace();
00138         if(num == recipients.count())
00139       errMsg = i18n("Could not find public keys matching the userid(s)\n"
00140                         "%1;\n"
00141                         "the message is not encrypted.")
00142                        .arg( badkeys.data() );
00143         else
00144           errMsg = i18n("Could not find public keys matching the userid(s)\n"
00145                         "%1;\n"
00146                         "these persons will not be able to read the message.")
00147                        .arg( badkeys.data() );
00148         status |= MISSINGKEY;
00149         status |= ERROR;
00150       }
00151     }
00152     if (error.find("skipping userid") != -1)
00153     {
00154       index = 0;
00155       num = 0;
00156       while((index = error.find("skipping userid",index))
00157         != -1)
00158       {
00159         bad = TRUE;
00160         int index2 = error.find('\n',index+16);
00161         if (num++)
00162           badkeys += ", ";
00163         badkeys += error.mid(index+16, index2-index-16);
00164         index = index2;
00165       }
00166       if(bad)
00167       {
00168         badkeys.stripWhiteSpace();
00169         if(num == recipients.count())
00170       errMsg = i18n("Public keys not certified with trusted signature "
00171                         "for userid(s)\n"
00172                         "%1.\n"
00173                         "The message is not encrypted.")
00174                        .arg( badkeys.data() );
00175         else
00176       errMsg = i18n("Public keys not certified with trusted signature "
00177                         "for userid(s)\n"
00178                         "%1;\n"
00179                         "these persons will not be able to read the message.")
00180                        .arg( badkeys.data() );
00181         status |= BADKEYS;
00182         status |= ERROR;
00183         return status;
00184       }
00185     }
00186   }
00187 #endif
00188   if(passphrase != 0)
00189   {
00190     if(error.find("Pass phrase is good") != -1)
00191     {
00192       //kdDebug(5100) << "Base: Good Passphrase!" << endl;
00193       status |= SIGNED;
00194     }
00195     if( error.find("Bad pass phrase") != -1)
00196     {
00197       errMsg = i18n("Bad passphrase; could not sign.");
00198       status |= BADPHRASE;
00199       status |= ERR_SIGNING;
00200       status |= ERROR;
00201     }
00202   }
00203   if (error.find("Signature error") != -1)
00204   {
00205     errMsg = i18n("Signing failed: please check your PGP User Identity, "
00206                   "the PGP setup, and the key rings.");
00207     status |= NO_SEC_KEY;
00208     status |= ERR_SIGNING;
00209     status |= ERROR;
00210   }
00211   if (error.find("Encryption error") != -1)
00212   {
00213     errMsg = i18n("Encryption failed: please check your PGP setup "
00214                   "and the key rings.");
00215     status |= NO_SEC_KEY;
00216     status |= BADKEYS;
00217     status |= ERROR;
00218   }
00219 
00220   //kdDebug(5100) << "status = " << status << endl;
00221   block.setStatus( status );
00222   return status;
00223 }
00224 
00225 
00226 int
00227 Base2::decrypt( Block& block, const char *passphrase )
00228 {
00229   int index, index2;
00230   int exitStatus = 0;
00231 
00232   clear();
00233   input = block.text();
00234   exitStatus = run(PGP2 " +batchmode +language=en -f", passphrase);
00235   if( !output.isEmpty() )
00236     block.setProcessedText( output );
00237   block.setError( error );
00238 
00239   // pgp2.6 has sometimes problems with the ascii armor pgp5.0 produces
00240   // this hack can solve parts of the problem
00241   if(error.find("ASCII armor corrupted.") != -1)
00242   {
00243     kdDebug(5100) << "removing ASCII armor header" << endl;
00244     int index1 = input.find("-----BEGIN PGP SIGNED MESSAGE-----");
00245     if(index1 != -1)
00246       index1 = input.find("-----BEGIN PGP SIGNATURE-----", index1);
00247     else
00248       index1 = input.find("-----BEGIN PGP MESSAGE-----");
00249     index1 = input.find('\n', index1);
00250     index2 = input.find("\n\n", index1);
00251     input.remove(index1, index2 - index1);
00252     exitStatus = run(PGP2 " +batchmode +language=en -f", passphrase);
00253     if( !output.isEmpty() )
00254       block.setProcessedText( output );
00255     block.setError( error );
00256   }
00257 
00258   if(exitStatus == -1) {
00259     errMsg = i18n("error running PGP");
00260     status = RUN_ERR;
00261     block.setStatus( status );
00262     return status;
00263   }
00264 
00265   /* Example No.1 (PGP 2.6.3in):
00266    * File is encrypted.  Secret key is required to read it.
00267    * Key for user ID: Test Key (only for testing) <testkey@ingo-kloecker.de>
00268    * 1024-bit key, key ID E2D074D3, created 2001/09/09
00269    *
00270    * Error:  Bad pass phrase.
00271    *
00272    * This message can only be read by:
00273    *   Test key without secret key (for testing only) <nosectestkey@ingo-kloecker.de>
00274    *   Test Key (only for testing) <testkey@ingo-kloecker.de>
00275    *
00276    * You do not have the secret key needed to decrypt this file.
00277    */
00278   /* Example No.2 (PGP 2.6.3in):
00279    * File is encrypted.  Secret key is required to read it.
00280    * This message can only be read by:
00281    *   Test key without secret key (for testing only) <nosectestkey@ingo-kloecker.de>
00282    *
00283    * You do not have the secret key needed to decrypt this file.
00284    */
00285   if(error.find("File is encrypted.") != -1)
00286   {
00287     //kdDebug(5100) << "kpgpbase: message is encrypted" << endl;
00288     status |= ENCRYPTED;
00289     if((index = error.find("Key for user ID:")) != -1)
00290     {
00291       // Find out the key for which the phrase is needed
00292       index  += 17;
00293       index2 = error.find('\n', index);
00294       block.setRequiredUserId( error.mid(index, index2 - index) );
00295       //kdDebug(5100) << "Base: key needed is \"" << block.requiredUserId() << "\"!\n";
00296 
00297       if((passphrase != 0) && (error.find("Bad pass phrase") != -1))
00298       {
00299         errMsg = i18n("Bad passphrase; could not decrypt.");
00300         kdDebug(5100) << "Base: passphrase is bad" << endl;
00301         status |= BADPHRASE;
00302         status |= ERROR;
00303       }
00304     }
00305     else
00306     {
00307       // no secret key fitting this message
00308       status |= NO_SEC_KEY;
00309       status |= ERROR;
00310       errMsg = i18n("You do not have the secret key needed to decrypt this message.");
00311       kdDebug(5100) << "Base: no secret key for this message" << endl;
00312     }
00313     // check for persons
00314 #if 0
00315     // ##### FIXME: This information is anyway currently not used
00316     //       I'll change it to always determine the recipients.
00317     index = error.find("can only be read by:");
00318     if(index != -1)
00319     {
00320       index = error.find('\n',index);
00321       int end = error.find("\n\n",index);
00322 
00323       mRecipients.clear();
00324       while( (index2 = error.find('\n',index+1)) <= end )
00325       {
00326     QCString item = error.mid(index+1,index2-index-1);
00327     item.stripWhiteSpace();
00328     mRecipients.append(item);
00329     index = index2;
00330       }
00331     }
00332 #endif
00333   }
00334 
00335   // handle signed message
00336 
00337   // Examples (made with PGP 2.6.3in)
00338   /* Example No. 1 (signed with unknown key):
00339    * File has signature.  Public key is required to check signature.
00340    *
00341    * Key matching expected Key ID 12345678 not found in file '/home/user/.pgp/pubring.pgp'.
00342    *
00343    * WARNING: Can't find the right public key-- can't check signature integrity.
00344    */
00345   /* Example No. 2 (bad signature):
00346    * File has signature.  Public key is required to check signature.
00347    * ..
00348    * WARNING: Bad signature, doesn't match file contents!
00349    *
00350    * Bad signature from user "Joe User <joe@foo.bar>".
00351    * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678
00352    */
00353   /* Example No. 3.1 (good signature with untrusted key):
00354    * File has signature.  Public key is required to check signature.
00355    * .
00356    * Good signature from user "Joe User <joe@foo.bar>".
00357    * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678
00358    *
00359    * WARNING:  Because this public key is not certified with a trusted
00360    * signature, it is not known with high confidence that this public key
00361    * actually belongs to: "Joe User <joe@foo.bar>".
00362    */
00363   /* Example No. 3.2 (good signature with untrusted key):
00364    * File has signature.  Public key is required to check signature.
00365    * .
00366    * Good signature from user "Joe User <joe@foo.bar>".
00367    * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678
00368    *
00369    * WARNING:  Because this public key is not certified with enough trusted
00370    * signatures, it is not known with high confidence that this public key
00371    * actually belongs to: "Joe User <joe@foo.bar>".
00372    */
00373   /* Example No. 4 (good signature with revoked key):
00374    * File has signature.  Public key is required to check signature.
00375    * .
00376    * Good signature from user "Joe User <joe@foo.bar>".
00377    * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678
00378    *
00379    *
00380    * Key for user ID: Joe User <joe@foo.bar>
00381    * 1024-bit key, key ID 12345678, created 2001/09/09
00382    * Key has been revoked.
00383    *
00384    * WARNING:  This key has been revoked by its owner,
00385    * possibly because the secret key was compromised.
00386    * This could mean that this signature is a forgery.
00387    */
00388   /* Example No. 5 (good signature with trusted key):
00389    * File has signature.  Public key is required to check signature.
00390    * .
00391    * Good signature from user "Joe User <joe@foo.bar>".
00392    * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678
00393    */
00394 
00395   if((index = error.find("File has signature")) != -1)
00396   {
00397     // move index to start of next line
00398     index = error.find('\n', index+18) + 1;
00399     //kdDebug(5100) << "Base: message is signed" << endl;
00400     status |= SIGNED;
00401     // get signature date and signature key ID
00402     if ((index2 = error.find("Signature made", index)) != -1) {
00403       index2 += 15;
00404       int index3 = error.find("using", index2);
00405       block.setSignatureDate( error.mid(index2, index3-index2-1) );
00406       kdDebug(5100) << "Message was signed on '" << block.signatureDate() << "'\n";
00407       index3 = error.find("key ID ", index3) + 7;
00408       block.setSignatureKeyId( error.mid(index3,8) );
00409       kdDebug(5100) << "Message was signed with key '" << block.signatureKeyId() << "'\n";
00410     }
00411     else {
00412       // if pgp can't find the keyring it unfortunately doesn't print
00413       // the signature date and key ID
00414       block.setSignatureDate( "" );
00415       block.setSignatureKeyId( "" );
00416     }
00417 
00418     if( ( index2 = error.find("Key matching expected", index) ) != -1)
00419     {
00420       status |= UNKNOWN_SIG;
00421       status |= GOODSIG;
00422       int index3 = error.find("Key ID ", index2) + 7;
00423       block.setSignatureKeyId( error.mid(index3,8) );
00424       block.setSignatureUserId( QString::null );
00425     }
00426     else if( (index2 = error.find("Good signature from", index)) != -1 )
00427     {
00428       status |= GOODSIG;
00429       // get signer
00430       index = error.find('"',index2+19);
00431       index2 = error.find('"', index+1);
00432       block.setSignatureUserId( error.mid(index+1, index2-index-1) );
00433     }
00434     else if( (index2 = error.find("Bad signature from", index)) != -1 )
00435     {
00436       status |= ERROR;
00437       // get signer
00438       index = error.find('"',index2+19);
00439       index2 = error.find('"', index+1);
00440       block.setSignatureUserId( error.mid(index+1, index2-index-1) );
00441     }
00442     else if( error.find("Keyring file", index) != -1 )
00443     {
00444       // #### fix this hack
00445       status |= UNKNOWN_SIG;
00446       status |= GOODSIG; // this is a hack...
00447       // determine file name of missing keyring file
00448       index = error.find('\'', index) + 1;
00449       index2 = error.find('\'', index);
00450       block.setSignatureUserId( i18n("The keyring file %1 does not exist.\n"
00451       "Please check your PGP setup.").arg(error.mid(index, index2-index)) );
00452     }
00453     else
00454     {
00455       status |= ERROR;
00456       block.setSignatureUserId( i18n("Unknown error") );
00457     }
00458   }
00459   //kdDebug(5100) << "status = " << status << endl;
00460   block.setStatus( status );
00461   return status;
00462 }
00463 
00464 
00465 Key*
00466 Base2::readPublicKey( const KeyID& keyID,
00467                       const bool readTrust /* = false */,
00468                       Key* key /* = 0 */ )
00469 {
00470   int exitStatus = 0;
00471 
00472   status = 0;
00473   exitStatus = run( PGP2 " +batchmode +language=en +verbose=0 -kvc -f 0x" +
00474                     keyID, 0, true );
00475 
00476   if(exitStatus != 0) {
00477     status = ERROR;
00478     return 0;
00479   }
00480 
00481   key = parsePublicKeyData( output, key );
00482 
00483   if( key == 0 )
00484   {
00485     return 0;
00486   }
00487 
00488   if( readTrust )
00489   {
00490     exitStatus = run( PGP2 " +batchmode +language=en +verbose=0 -kc -f",
00491                       0, true );
00492 
00493     if(exitStatus != 0) {
00494       status = ERROR;
00495       return 0;
00496     }
00497 
00498     parseTrustDataForKey( key, error );
00499   }
00500 
00501   return key;
00502 }
00503 
00504 
00505 KeyList
00506 Base2::publicKeys( const QStringList & patterns )
00507 {
00508   return doGetPublicKeys( PGP2 " +batchmode +language=en +verbose=0 -kvc -f",
00509                           patterns );
00510 }
00511 
00512 KeyList
00513 Base2::doGetPublicKeys( const QCString & cmd, const QStringList & patterns )
00514 {
00515   int exitStatus = 0;
00516   KeyList publicKeys;
00517 
00518   status = 0;
00519   if ( patterns.isEmpty() ) {
00520     exitStatus = run( cmd, 0, true );
00521 
00522     if ( exitStatus != 0 ) {
00523       status = ERROR;
00524       return KeyList();
00525     }
00526 
00527     // now we need to parse the output for public keys
00528     publicKeys = parseKeyList( output, false );
00529   }
00530   else {
00531     typedef QMap<QCString, Key*> KeyMap;
00532     KeyMap map;
00533 
00534     for ( QStringList::ConstIterator it = patterns.begin();
00535           it != patterns.end(); ++it ) {
00536       exitStatus = run( cmd + " " + KProcess::quote( *it ).local8Bit(),
00537                         0, true );
00538 
00539       if ( exitStatus != 0 ) {
00540         status = ERROR;
00541         return KeyList();
00542       }
00543 
00544       // now we need to parse the output for public keys
00545       publicKeys = parseKeyList( output, false );
00546 
00547       // put all new keys into a map, remove duplicates
00548       while ( !publicKeys.isEmpty() ) {
00549         Key * key = publicKeys.take( 0 );
00550         if ( !map.contains( key->primaryFingerprint() ) )
00551           map.insert( key->primaryFingerprint(), key );
00552         else
00553           delete key;
00554       }
00555     }
00556     // build list from the map
00557     for ( KeyMap::ConstIterator it = map.begin(); it != map.end(); ++it ) {
00558       publicKeys.append( it.data() );
00559     }
00560   }
00561 
00562   // sort the list of public keys
00563   publicKeys.sort();
00564 
00565   return publicKeys;
00566 }
00567 
00568 KeyList
00569 Base2::secretKeys( const QStringList & patterns )
00570 {
00571   return publicKeys( patterns );
00572 }
00573 
00574 
00575 int
00576 Base2::signKey(const KeyID& keyID, const char *passphrase)
00577 {
00578   QCString cmd;
00579   int exitStatus = 0;
00580 
00581   cmd = PGP2 " +batchmode +language=en -ks -f ";
00582   cmd += addUserId();
00583   cmd += " 0x" + keyID;
00584 
00585   status = 0;
00586   exitStatus = run(cmd.data(),passphrase);
00587 
00588   if (exitStatus != 0)
00589     status = ERROR;
00590 
00591   return status;
00592 }
00593 
00594 
00595 QCString Base2::getAsciiPublicKey(const KeyID& keyID)
00596 {
00597   int exitStatus = 0;
00598 
00599   if (keyID.isEmpty())
00600     return QCString();
00601 
00602   status = 0;
00603   exitStatus = run( PGP2 " +batchmode +force +language=en -kxaf 0x" + keyID,
00604                     0, true );
00605 
00606   if(exitStatus != 0) {
00607     status = ERROR;
00608     return QCString();
00609   }
00610 
00611   return output;
00612 }
00613 
00614 
00615 Key*
00616 Base2::parsePublicKeyData( const QCString& output, Key* key /* = 0 */ )
00617 {
00618   Subkey *subkey = 0;
00619   int index;
00620 
00621   // search start of key data
00622   if( !strncmp( output.data(), "pub", 3 ) ||
00623       !strncmp( output.data(), "sec", 3 ) )
00624     index = 0;
00625   else
00626   {
00627     /*
00628     if( secretKeys )
00629       index = output.find( "\nsec" );
00630     else
00631     */
00632       index = output.find( "\npub" );
00633     if( index == -1 )
00634       return 0;
00635     else
00636       index++;
00637   }
00638 
00639   while( true )
00640   {
00641     int index2;
00642 
00643     // search the end of the current line
00644     if( ( index2 = output.find( '\n', index ) ) == -1 )
00645       break;
00646 
00647     if( !strncmp( output.data() + index, "pub", 3 ) ||
00648         !strncmp( output.data() + index, "sec", 3 ) )
00649     { // line contains primary key data
00650       // Example 1 (nothing special):
00651       // pub  1024/E2D074D3 2001/09/09 Test Key <testkey@xyz>
00652       // Example 2 (disabled key):
00653       // pub- 1024/8CCB2C1B 2001/11/04 Disabled Test Key <disabled@xyz>
00654       // Example 3 (expired key):
00655       // pub> 1024/7B94827D 2001/09/09 Expired Test Key <expired@xyz> (EXPIRE:2001-09-10)
00656       // Example 4 (revoked key):
00657       // pub  1024/956721F9 2001/09/09 *** KEY REVOKED ***
00658 
00659       int pos, pos2;
00660 
00661       if( key == 0 )
00662         key = new Key();
00663       else
00664         key->clear();
00665       /*key->setSecret( secretKeys );*/
00666       // set default key capabilities
00667       key->setCanEncrypt( true );
00668       key->setCanSign( true );
00669       key->setCanCertify( true );
00670 
00671       /*subkey = new Subkey( "", secretKeys );*/
00672       subkey = new Subkey( "", false );
00673       key->addSubkey( subkey );
00674       // set default key capabilities
00675       subkey->setCanEncrypt( true );
00676       subkey->setCanSign( true );
00677       subkey->setCanCertify( true );
00678       // expiration date defaults to never
00679       subkey->setExpirationDate( -1 );
00680 
00681       // Key Flags
00682       switch( output[index+3] )
00683       {
00684       case ' ': // nothing special
00685         break;
00686       case '-': // disabled key
00687         subkey->setDisabled( true );
00688         key->setDisabled( true );
00689         break;
00690       case '>': // expired key
00691         subkey->setExpired( true );
00692         key->setExpired( true );
00693         break;
00694       default:
00695         kdDebug(5100) << "Unknown key flag.\n";
00696       }
00697 
00698       // Key Length
00699       pos = index + 4;
00700       while( output[pos] == ' ' )
00701         pos++;
00702       pos2 = output.find( '/', pos );
00703       subkey->setKeyLength( output.mid( pos, pos2-pos ).toUInt() );
00704 
00705       // Key ID
00706       pos = pos2 + 1;
00707       pos2 = output.find( ' ', pos );
00708       subkey->setKeyID( output.mid( pos, pos2-pos ) );
00709 
00710       // Creation Date
00711       pos = pos2 + 1;
00712       while( output[pos] == ' ' )
00713         pos++;
00714       pos2 = output.find( ' ', pos );
00715       int year = output.mid( pos, 4 ).toInt();
00716       int month = output.mid( pos+5, 2 ).toInt();
00717       int day = output.mid( pos+8, 2 ).toInt();
00718       QDateTime dt( QDate( year, month, day ), QTime( 00, 00 ) );
00719       QDateTime epoch( QDate( 1970, 01, 01 ), QTime( 00, 00 ) );
00720       // The calculated creation date isn't exactly correct because QDateTime
00721       // doesn't know anything about timezones and always assumes local time
00722       // although epoch is of course UTC. But as PGP 2 anyway doesn't print
00723       // the time this doesn't matter too much.
00724       subkey->setCreationDate( epoch.secsTo( dt ) );
00725 
00726       // User ID
00727       pos = pos2 + 1;
00728       while( output[pos] == ' ' )
00729         pos++;
00730       QCString uid = output.mid( pos, index2-pos );
00731       if( uid != "*** KEY REVOKED ***" )
00732         key->addUserID( uid );
00733       else
00734       {
00735         subkey->setRevoked( true );
00736         key->setRevoked( true );
00737       }
00738     }
00739     else if( output[index] == ' ' )
00740     { // line contains additional key data
00741 
00742       if( key == 0 )
00743         break;
00744       assert( subkey != 0 );
00745 
00746       int pos = index + 1;
00747       while( output[pos] == ' ' )
00748         pos++;
00749 
00750       if( !strncmp( output.data() + pos, "Key fingerprint = ", 18 ) )
00751       { // line contains a fingerprint
00752         // Example:
00753         //             Key fingerprint = 47 30 7C 76 05 BF 5E FB  72 41 00 F2 7D 0B D0 49
00754 
00755         QCString fingerprint = output.mid( pos, index2-pos );
00756         // remove white space from the fingerprint
00757     for ( int idx = 0 ; (idx = fingerprint.find(' ', idx)) >= 0 ; )
00758       fingerprint.replace( idx, 1, "" );
00759 
00760         subkey->setFingerprint( fingerprint );
00761       }
00762       else if( !strncmp( output.data() + pos, "Expire: ", 8 ) ||
00763                !strncmp( output.data() + pos, "no expire ", 10 ) )
00764       { // line contains additional key properties
00765         // Examples:
00766         //            Expire: 2001/09/10
00767         //                     no expire ENCRyption only
00768         //                     no expire SIGNature only
00769 
00770         if( output[pos] == 'E' )
00771         {
00772           // Expiration Date
00773           pos += 8;
00774           int year = output.mid( pos, 4 ).toInt();
00775           int month = output.mid( pos+5, 2 ).toInt();
00776           int day = output.mid( pos+8, 2 ).toInt();
00777           QDateTime dt( QDate( year, month, day ), QTime( 00, 00 ) );
00778           QDateTime epoch( QDate( 1970, 01, 01 ), QTime( 00, 00 ) );
00779           // Here the same comments as for the creation date are valid.
00780           subkey->setExpirationDate( epoch.secsTo( dt ) );
00781           pos += 11; // note that there is always a blank after the expire date
00782         }
00783         else
00784           pos += 10;
00785 
00786         // optional key capabilities (sign/encrypt only)
00787         if( pos != index2 )
00788         {
00789           if( !strncmp( output.data() + pos, "SIGNature only", 14 ) )
00790           {
00791             subkey->setCanEncrypt( false );
00792             key->setCanEncrypt( false );
00793           }
00794           else if( !strncmp( output.data() + pos, "ENCRyption only", 15 ) )
00795           {
00796             subkey->setCanSign( false );
00797             key->setCanSign( false );
00798             subkey->setCanCertify( false );
00799             key->setCanCertify( false );
00800           }
00801         }
00802       }
00803       else
00804       { // line contains an additional user id
00805         // Example:
00806         //                               Test key (2nd user ID) <abc@xyz>
00807 
00808         key->addUserID( output.mid( pos, index2-pos ) );
00809       }
00810     }
00811     index = index2 + 1;
00812   }
00813 
00814   //kdDebug(5100) << "finished parsing key data\n";
00815 
00816   return key;
00817 }
00818 
00819 
00820 void
00821 Base2::parseTrustDataForKey( Key* key, const QCString& str )
00822 {
00823   if( ( key == 0 ) || str.isEmpty() )
00824     return;
00825 
00826   QCString keyID = key->primaryKeyID();
00827   UserIDList userIDs = key->userIDs();
00828 
00829   // search the trust data belonging to this key
00830   int index = str.find( '\n' ) + 1;
00831   while( ( index > 0 ) &&
00832          ( strncmp( str.data() + index+2, keyID.data(), 8 ) != 0 ) )
00833     index = str.find( '\n', index ) + 1;
00834 
00835   if( index == 0 )
00836     return;
00837 
00838   bool ultimateTrust = false;
00839   if( !strncmp( str.data() + index+11, "ultimate", 8 ) )
00840     ultimateTrust = true;
00841 
00842   bool firstLine = true;
00843 
00844   while( true )
00845   { // loop over all trust information about this key
00846     int index2;
00847 
00848     // search the end of the current line
00849     if( ( index2 = str.find( '\n', index ) ) == -1 )
00850       break;
00851 
00852     // check if trust info for the next key starts
00853     if( !firstLine && ( str[index+2] != ' ' ) )
00854       break;
00855 
00856     if( str[index+21] != ' ' )
00857     { // line contains a validity value for a user ID
00858 
00859       // determine the validity
00860       Validity validity = KPGP_VALIDITY_UNKNOWN;
00861       if( !strncmp( str.data() + index+21, "complete", 8 ) )
00862         if( ultimateTrust )
00863           validity = KPGP_VALIDITY_ULTIMATE;
00864         else
00865           validity = KPGP_VALIDITY_FULL;
00866       else if( !strncmp( str.data() + index+21, "marginal", 8 ) )
00867         validity = KPGP_VALIDITY_MARGINAL;
00868       else if( !strncmp( str.data() + index+21, "never", 5 ) )
00869         validity = KPGP_VALIDITY_NEVER;
00870       else if( !strncmp( str.data() + index+21, "undefined", 9 ) )
00871         validity = KPGP_VALIDITY_UNDEFINED;
00872 
00873       // determine the user ID
00874       int pos = index + 31;
00875       if( str[index+2] == ' ' )
00876         pos++; // additional user IDs start one column later
00877       QString uid = str.mid( pos, index2-pos );
00878 
00879       // set the validity of the corresponding user ID
00880       for( UserIDListIterator it( userIDs ); it.current(); ++it )
00881         if( (*it)->text() == uid )
00882         {
00883           kdDebug(5100)<<"Setting the validity of "<<uid<<" to "<<validity<<endl;
00884           (*it)->setValidity( validity );
00885           break;
00886         }
00887     }
00888 
00889     firstLine = false;
00890     index = index2 + 1;
00891   }
00892 }
00893 
00894 
00895 KeyList
00896 Base2::parseKeyList( const QCString& output, bool secretKeys )
00897 {
00898   kdDebug(5100) << "Kpgp::Base2::parseKeyList()" << endl;
00899   KeyList keys;
00900   Key *key = 0;
00901   Subkey *subkey = 0;
00902   int index;
00903 
00904   // search start of key data
00905   if( !strncmp( output.data(), "pub", 3 ) ||
00906       !strncmp( output.data(), "sec", 3 ) )
00907     index = 0;
00908   else
00909   {
00910     if( secretKeys )
00911       index = output.find( "\nsec" );
00912     else
00913       index = output.find( "\npub" );
00914     if( index == -1 )
00915       return keys;
00916     else
00917       index++;
00918   }
00919 
00920   while( true )
00921   {
00922     int index2;
00923 
00924     // search the end of the current line
00925     if( ( index2 = output.find( '\n', index ) ) == -1 )
00926       break;
00927 
00928     if( !strncmp( output.data() + index, "pub", 3 ) ||
00929         !strncmp( output.data() + index, "sec", 3 ) )
00930     { // line contains primary key data
00931       // Example 1:
00932       // pub  1024/E2D074D3 2001/09/09 Test Key <testkey@xyz>
00933       // Example 2 (disabled key):
00934       // pub- 1024/8CCB2C1B 2001/11/04 Disabled Test Key <disabled@xyz>
00935       // Example 3 (expired key):
00936       // pub> 1024/7B94827D 2001/09/09 Expired Test Key <expired@xyz> (EXPIRE:2001-09-10)
00937       // Example 4 (revoked key):
00938       // pub  1024/956721F9 2001/09/09 *** KEY REVOKED ***
00939 
00940       int pos, pos2;
00941 
00942       if( key != 0 ) // store the previous key in the key list
00943     keys.append( key );
00944 
00945       key = new Key();
00946       key->setSecret( secretKeys );
00947       // set default key capabilities
00948       key->setCanEncrypt( true );
00949       key->setCanSign( true );
00950       key->setCanCertify( true );
00951 
00952       subkey = new Subkey( "", secretKeys );
00953       key->addSubkey( subkey );
00954       // set default key capabilities
00955       subkey->setCanEncrypt( true );
00956       subkey->setCanSign( true );
00957       subkey->setCanCertify( true );
00958       // expiration date defaults to never
00959       subkey->setExpirationDate( -1 );
00960 
00961       // Key Flags
00962       switch( output[index+3] )
00963       {
00964       case ' ': // nothing special
00965         break;
00966       case '-': // disabled key
00967         subkey->setDisabled( true );
00968         key->setDisabled( true );
00969         break;
00970       case '>': // expired key
00971         subkey->setExpired( true );
00972         key->setExpired( true );
00973         break;
00974       default:
00975         kdDebug(5100) << "Unknown key flag.\n";
00976       }
00977 
00978       // Key Length
00979       pos = index + 4;
00980       while( output[pos] == ' ' )
00981         pos++;
00982       pos2 = output.find( '/', pos );
00983       subkey->setKeyLength( output.mid( pos, pos2-pos ).toUInt() );
00984 
00985       // Key ID
00986       pos = pos2 + 1;
00987       pos2 = output.find( ' ', pos );
00988       subkey->setKeyID( output.mid( pos, pos2-pos ) );
00989 
00990       // Creation Date
00991       pos = pos2 + 1;
00992       while( output[pos] == ' ' )
00993         pos++;
00994       pos2 = output.find( ' ', pos );
00995       int year = output.mid( pos, 4 ).toInt();
00996       int month = output.mid( pos+5, 2 ).toInt();
00997       int day = output.mid( pos+8, 2 ).toInt();
00998       QDateTime dt( QDate( year, month, day ), QTime( 00, 00 ) );
00999       QDateTime epoch( QDate( 1970, 01, 01 ), QTime( 00, 00 ) );
01000       // The calculated creation date isn't exactly correct because QDateTime
01001       // doesn't know anything about timezones and always assumes local time
01002       // although epoch is of course UTC. But as PGP 2 anyway doesn't print
01003       // the time this doesn't matter too much.
01004       subkey->setCreationDate( epoch.secsTo( dt ) );
01005 
01006       // User ID
01007       pos = pos2 + 1;
01008       while( output[pos] == ' ' )
01009         pos++;
01010       QCString uid = output.mid( pos, index2-pos );
01011       if( uid != "*** KEY REVOKED ***" )
01012         key->addUserID( uid );
01013       else
01014       {
01015         subkey->setRevoked( true );
01016         key->setRevoked( true );
01017       }
01018     }
01019     else if( output[index] == ' ' )
01020     { // line contains additional key data
01021 
01022       if( key == 0 )
01023         break;
01024 
01025       int pos = index + 1;
01026       while( output[pos] == ' ' )
01027         pos++;
01028 
01029       if( !strncmp( output.data() + pos, "Key fingerprint = ", 18 ) )
01030       { // line contains a fingerprint
01031         // Example:
01032         //             Key fingerprint = 47 30 7C 76 05 BF 5E FB  72 41 00 F2 7D 0B D0 49
01033 
01034         int pos2;
01035         pos2 = pos + 18;
01036         QCString fingerprint = output.mid( pos, index2-pos );
01037         // remove white space from the fingerprint
01038     for ( int idx = 0 ; (idx = fingerprint.find(' ', idx)) >= 0 ; )
01039       fingerprint.replace( idx, 1, "" );
01040 
01041         subkey->setFingerprint( fingerprint );
01042       }
01043       else if( !strncmp( output.data() + pos, "Expire: ", 8 ) ||
01044                !strncmp( output.data() + pos, "no expire ", 10 ) )
01045       { // line contains additional key properties
01046         // Examples:
01047         //            Expire: 2001/09/10
01048         //                     no expire ENCRyption only
01049         //                     no expire SIGNature only
01050 
01051         if( output[pos] == 'E' )
01052         {
01053           // Expiration Date
01054           pos += 8;
01055           int year = output.mid( pos, 4 ).toInt();
01056           int month = output.mid( pos+5, 2 ).toInt();
01057           int day = output.mid( pos+8, 2 ).toInt();
01058           QDateTime dt( QDate( year, month, day ), QTime( 00, 00 ) );
01059           QDateTime epoch( QDate( 1970, 01, 01 ), QTime( 00, 00 ) );
01060           // Here the same comments as for the creation date are valid.
01061           subkey->setExpirationDate( epoch.secsTo( dt ) );
01062           pos += 11; // note that there is always a blank after the expire date
01063         }
01064         else
01065           pos += 10;
01066 
01067         // optional key capabilities (sign/encrypt only)
01068         if( pos != index2 )
01069         {
01070           if( !strncmp( output.data() + pos, "SIGNature only", 14 ) )
01071           {
01072             subkey->setCanEncrypt( false );
01073             key->setCanEncrypt( false );
01074           }
01075           else if( !strncmp( output.data() + pos, "ENCRyption only", 15 ) )
01076           {
01077             subkey->setCanSign( false );
01078             key->setCanSign( false );
01079             subkey->setCanCertify( false );
01080             key->setCanCertify( false );
01081           }
01082         }
01083       }
01084       else
01085       { // line contains an additional user id
01086         // Example:
01087         //                               Test key (2nd user ID) <abc@xyz>
01088 
01089         key->addUserID( output.mid( pos, index2-pos ) );
01090       }
01091     }
01092 
01093     index = index2 + 1;
01094   }
01095 
01096   if (key != 0) // store the last key in the key list
01097     keys.append( key );
01098 
01099   //kdDebug(5100) << "finished parsing keys" << endl;
01100 
01101   return keys;
01102 }
01103 
01104 
01105 } // namespace Kpgp
KDE Home | KDE Accessibility Home | Description of Access Keys