libkdenetwork Library API Documentation

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