libkpgp

kpgpbase2.cpp
1/*
2 kpgpbase2.cpp
3
4 Copyright (C) 2001,2002 the KPGP authors
5 See file AUTHORS.kpgp for details
6
7 This file is part of KPGP, the KDE PGP/GnuPG support library.
8
9 KPGP is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19#ifdef HAVE_CONFIG_H
20#include <config.h>
21#endif
22
23#include "kpgpbase.h"
24#include "kpgp.h"
25
26#include <string.h> /* strncmp */
27#include <assert.h>
28
29#include <tqdatetime.h>
30
31#include <tdelocale.h>
32#include <tdeprocess.h>
33#include <kdebug.h>
34
35#define PGP2 "pgp"
36
37namespace Kpgp {
38
39Base2::Base2()
40 : Base()
41{
42}
43
44
45Base2::~Base2()
46{
47}
48
49
50int
51Base2::encrypt( Block& block, const KeyIDList& recipients )
52{
53 return encsign( block, recipients, 0 );
54}
55
56
57int
58Base2::clearsign( Block& block, const TQString &passphrase )
59{
60 return encsign( block, KeyIDList(), passphrase );
61}
62
63
64int
65Base2::encsign( Block& block, const KeyIDList& recipients,
66 const TQString &passphrase )
67{
68 TQCString cmd;
69 int exitStatus = 0;
70
71 if (!recipients.isEmpty() && !passphrase.isEmpty())
72 cmd = PGP2 " +batchmode +language=en +verbose=1 -seat";
73 else if(!recipients.isEmpty())
74 cmd = PGP2 " +batchmode +language=en +verbose=1 -eat";
75 else if (!passphrase.isEmpty())
76 cmd = PGP2 " +batchmode +language=en +verbose=1 -sat";
77 else
78 {
79 kdDebug(5100) << "kpgpbase: Neither recipients nor passphrase specified." << endl;
80 return OK;
81 }
82
83 if (!passphrase.isEmpty())
84 cmd += addUserId();
85
86 if(!recipients.isEmpty()) {
87 if(Module::getKpgp()->encryptToSelf())
88 {
89 cmd += " 0x";
90 cmd += Module::getKpgp()->user();
91 }
92
93 for( KeyIDList::ConstIterator it = recipients.begin();
94 it != recipients.end(); ++it ) {
95 cmd += " 0x";
96 cmd += (*it);
97 }
98 }
99 cmd += " -f";
100
101 clear();
102 input = block.text();
103 exitStatus = run(cmd.data(), passphrase);
104 if( !output.isEmpty() )
105 block.setProcessedText( output );
106 block.setError( error );
107
108 if(exitStatus != 0)
109 status = ERROR;
110
111#if 0
112 // #### FIXME: As we check the keys ourselves the following problems
113 // shouldn't occur. Therefore I don't handle them for now.
114 // IK 01/2002
115 if(!recipients.isEmpty())
116 {
117 int index = 0;
118 bool bad = FALSE;
119 unsigned int num = 0;
120 TQCString badkeys = "";
121 if (error.find("Cannot find the public key") != -1)
122 {
123 index = 0;
124 num = 0;
125 while((index = error.find("Cannot find the public key",index))
126 != -1)
127 {
128 bad = TRUE;
129 index = error.find('\'',index);
130 int index2 = error.find('\'',index+1);
131 if (num++)
132 badkeys += ", ";
133 badkeys += error.mid(index, index2-index+1);
134 }
135 if(bad)
136 {
137 badkeys.stripWhiteSpace();
138 if(num == recipients.count())
139 errMsg = i18n("Could not find public keys matching the userid(s)\n"
140 "%1;\n"
141 "the message is not encrypted.")
142 .arg( badkeys.data() );
143 else
144 errMsg = i18n("Could not find public keys matching the userid(s)\n"
145 "%1;\n"
146 "these persons will not be able to read the message.")
147 .arg( badkeys.data() );
148 status |= MISSINGKEY;
149 status |= ERROR;
150 }
151 }
152 if (error.find("skipping userid") != -1)
153 {
154 index = 0;
155 num = 0;
156 while((index = error.find("skipping userid",index))
157 != -1)
158 {
159 bad = TRUE;
160 int index2 = error.find('\n',index+16);
161 if (num++)
162 badkeys += ", ";
163 badkeys += error.mid(index+16, index2-index-16);
164 index = index2;
165 }
166 if(bad)
167 {
168 badkeys.stripWhiteSpace();
169 if(num == recipients.count())
170 errMsg = i18n("Public keys not certified with trusted signature "
171 "for userid(s)\n"
172 "%1.\n"
173 "The message is not encrypted.")
174 .arg( badkeys.data() );
175 else
176 errMsg = i18n("Public keys not certified with trusted signature "
177 "for userid(s)\n"
178 "%1;\n"
179 "these persons will not be able to read the message.")
180 .arg( badkeys.data() );
181 status |= BADKEYS;
182 status |= ERROR;
183 return status;
184 }
185 }
186 }
187#endif
188 if (!passphrase.isEmpty())
189 {
190 if(error.find("Pass phrase is good") != -1)
191 {
192 //kdDebug(5100) << "Base: Good Passphrase!" << endl;
193 status |= SIGNED;
194 }
195 if( error.find("Bad pass phrase") != -1)
196 {
197 errMsg = i18n("Bad passphrase; could not sign.");
198 status |= BADPHRASE;
199 status |= ERR_SIGNING;
200 status |= ERROR;
201 }
202 }
203 if (error.find("Signature error") != -1)
204 {
205 errMsg = i18n("Signing failed: please check your PGP User Identity, "
206 "the PGP setup, and the key rings.");
207 status |= NO_SEC_KEY;
208 status |= ERR_SIGNING;
209 status |= ERROR;
210 }
211 if (error.find("Encryption error") != -1)
212 {
213 errMsg = i18n("Encryption failed: please check your PGP setup "
214 "and the key rings.");
215 status |= NO_SEC_KEY;
216 status |= BADKEYS;
217 status |= ERROR;
218 }
219
220 //kdDebug(5100) << "status = " << status << endl;
221 block.setStatus( status );
222 return status;
223}
224
225
226int
227Base2::decrypt( Block& block, const TQString &passphrase )
228{
229 int index, index2;
230 int exitStatus = 0;
231
232 clear();
233 input = block.text();
234 exitStatus = run(PGP2 " +batchmode +language=en -f", passphrase);
235 if( !output.isEmpty() )
236 block.setProcessedText( output );
237 block.setError( error );
238
239 // pgp2.6 has sometimes problems with the ascii armor pgp5.0 produces
240 // this hack can solve parts of the problem
241 if(error.find("ASCII armor corrupted.") != -1)
242 {
243 kdDebug(5100) << "removing ASCII armor header" << endl;
244 int index1 = input.find("-----BEGIN PGP SIGNED MESSAGE-----");
245 if(index1 != -1)
246 index1 = input.find("-----BEGIN PGP SIGNATURE-----", index1);
247 else
248 index1 = input.find("-----BEGIN PGP MESSAGE-----");
249 index1 = input.find('\n', index1);
250 index2 = input.find("\n\n", index1);
251 input.remove(index1, index2 - index1);
252 exitStatus = run(PGP2 " +batchmode +language=en -f", passphrase);
253 if( !output.isEmpty() )
254 block.setProcessedText( output );
255 block.setError( error );
256 }
257
258 if(exitStatus == -1) {
259 errMsg = i18n("error running PGP");
260 status = RUN_ERR;
261 block.setStatus( status );
262 return status;
263 }
264
265 /* Example No.1 (PGP 2.6.3in):
266 * File is encrypted. Secret key is required to read it.
267 * Key for user ID: Test Key (only for testing) <testkey@ingo-kloecker.de>
268 * 1024-bit key, key ID E2D074D3, created 2001/09/09
269 *
270 * Error: Bad pass phrase.
271 *
272 * This message can only be read by:
273 * Test key without secret key (for testing only) <nosectestkey@ingo-kloecker.de>
274 * Test Key (only for testing) <testkey@ingo-kloecker.de>
275 *
276 * You do not have the secret key needed to decrypt this file.
277 */
278 /* Example No.2 (PGP 2.6.3in):
279 * File is encrypted. Secret key is required to read it.
280 * This message can only be read by:
281 * Test key without secret key (for testing only) <nosectestkey@ingo-kloecker.de>
282 *
283 * You do not have the secret key needed to decrypt this file.
284 */
285 if(error.find("File is encrypted.") != -1)
286 {
287 //kdDebug(5100) << "kpgpbase: message is encrypted" << endl;
288 status |= ENCRYPTED;
289 if((index = error.find("Key for user ID:")) != -1)
290 {
291 // Find out the key for which the phrase is needed
292 index += 17;
293 index2 = error.find('\n', index);
294 block.setRequiredUserId( error.mid(index, index2 - index) );
295 //kdDebug(5100) << "Base: key needed is \"" << block.requiredUserId() << "\"!\n";
296
297 if ((!passphrase.isEmpty()) && (error.find("Bad pass phrase") != -1))
298 {
299 errMsg = i18n("Bad passphrase; could not decrypt.");
300 kdDebug(5100) << "Base: passphrase is bad" << endl;
301 status |= BADPHRASE;
302 status |= ERROR;
303 }
304 }
305 else
306 {
307 // no secret key fitting this message
308 status |= NO_SEC_KEY;
309 status |= ERROR;
310 errMsg = i18n("You do not have the secret key needed to decrypt this message.");
311 kdDebug(5100) << "Base: no secret key for this message" << endl;
312 }
313 // check for persons
314#if 0
315 // ##### FIXME: This information is anyway currently not used
316 // I'll change it to always determine the recipients.
317 index = error.find("can only be read by:");
318 if(index != -1)
319 {
320 index = error.find('\n',index);
321 int end = error.find("\n\n",index);
322
323 mRecipients.clear();
324 while( (index2 = error.find('\n',index+1)) <= end )
325 {
326 TQCString item = error.mid(index+1,index2-index-1);
327 item.stripWhiteSpace();
328 mRecipients.append(item);
329 index = index2;
330 }
331 }
332#endif
333 }
334
335 // handle signed message
336
337 // Examples (made with PGP 2.6.3in)
338 /* Example No. 1 (signed with unknown key):
339 * File has signature. Public key is required to check signature.
340 *
341 * Key matching expected Key ID 12345678 not found in file '/home/user/.pgp/pubring.pgp'.
342 *
343 * WARNING: Can't find the right public key-- can't check signature integrity.
344 */
345 /* Example No. 2 (bad signature):
346 * File has signature. Public key is required to check signature.
347 * ..
348 * WARNING: Bad signature, doesn't match file contents!
349 *
350 * Bad signature from user "Joe User <joe@foo.bar>".
351 * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678
352 */
353 /* Example No. 3.1 (good signature with untrusted key):
354 * File has signature. Public key is required to check signature.
355 * .
356 * Good signature from user "Joe User <joe@foo.bar>".
357 * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678
358 *
359 * WARNING: Because this public key is not certified with a trusted
360 * signature, it is not known with high confidence that this public key
361 * actually belongs to: "Joe User <joe@foo.bar>".
362 */
363 /* Example No. 3.2 (good signature with untrusted key):
364 * File has signature. Public key is required to check signature.
365 * .
366 * Good signature from user "Joe User <joe@foo.bar>".
367 * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678
368 *
369 * WARNING: Because this public key is not certified with enough trusted
370 * signatures, it is not known with high confidence that this public key
371 * actually belongs to: "Joe User <joe@foo.bar>".
372 */
373 /* Example No. 4 (good signature with revoked key):
374 * File has signature. Public key is required to check signature.
375 * .
376 * Good signature from user "Joe User <joe@foo.bar>".
377 * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678
378 *
379 *
380 * Key for user ID: Joe User <joe@foo.bar>
381 * 1024-bit key, key ID 12345678, created 2001/09/09
382 * Key has been revoked.
383 *
384 * WARNING: This key has been revoked by its owner,
385 * possibly because the secret key was compromised.
386 * This could mean that this signature is a forgery.
387 */
388 /* Example No. 5 (good signature with trusted key):
389 * File has signature. Public key is required to check signature.
390 * .
391 * Good signature from user "Joe User <joe@foo.bar>".
392 * Signature made 2001/09/09 16:01 GMT using 1024-bit key, key ID 12345678
393 */
394
395 if((index = error.find("File has signature")) != -1)
396 {
397 // move index to start of next line
398 index = error.find('\n', index+18) + 1;
399 //kdDebug(5100) << "Base: message is signed" << endl;
400 status |= SIGNED;
401 // get signature date and signature key ID
402 if ((index2 = error.find("Signature made", index)) != -1) {
403 index2 += 15;
404 int index3 = error.find("using", index2);
405 block.setSignatureDate( error.mid(index2, index3-index2-1) );
406 kdDebug(5100) << "Message was signed on '" << block.signatureDate() << "'\n";
407 index3 = error.find("key ID ", index3) + 7;
408 block.setSignatureKeyId( error.mid(index3,8) );
409 kdDebug(5100) << "Message was signed with key '" << block.signatureKeyId() << "'\n";
410 }
411 else {
412 // if pgp can't find the keyring it unfortunately doesn't print
413 // the signature date and key ID
414 block.setSignatureDate( "" );
415 block.setSignatureKeyId( "" );
416 }
417
418 if( ( index2 = error.find("Key matching expected", index) ) != -1)
419 {
420 status |= UNKNOWN_SIG;
421 status |= GOODSIG;
422 int index3 = error.find("Key ID ", index2) + 7;
423 block.setSignatureKeyId( error.mid(index3,8) );
424 block.setSignatureUserId( TQString() );
425 }
426 else if( (index2 = error.find("Good signature from", index)) != -1 )
427 {
428 status |= GOODSIG;
429 // get signer
430 index = error.find('"',index2+19);
431 index2 = error.find('"', index+1);
432 block.setSignatureUserId( error.mid(index+1, index2-index-1) );
433 }
434 else if( (index2 = error.find("Bad signature from", index)) != -1 )
435 {
436 status |= ERROR;
437 // get signer
438 index = error.find('"',index2+19);
439 index2 = error.find('"', index+1);
440 block.setSignatureUserId( error.mid(index+1, index2-index-1) );
441 }
442 else if( error.find("Keyring file", index) != -1 )
443 {
444 // #### fix this hack
445 status |= UNKNOWN_SIG;
446 status |= GOODSIG; // this is a hack...
447 // determine file name of missing keyring file
448 index = error.find('\'', index) + 1;
449 index2 = error.find('\'', index);
450 block.setSignatureUserId( i18n("The keyring file %1 does not exist.\n"
451 "Please check your PGP setup.").arg(TQString(error.mid(index, index2-index))) );
452 }
453 else
454 {
455 status |= ERROR;
456 block.setSignatureUserId( i18n("Unknown error") );
457 }
458 }
459 //kdDebug(5100) << "status = " << status << endl;
460 block.setStatus( status );
461 return status;
462}
463
464
465Key*
466Base2::readPublicKey( const KeyID& keyID,
467 const bool readTrust /* = false */,
468 Key* key /* = 0 */ )
469{
470 int exitStatus = 0;
471
472 status = 0;
473 exitStatus = run( PGP2 " +batchmode +language=en +verbose=0 -kvc -f 0x" +
474 keyID, 0, true );
475
476 if(exitStatus != 0) {
477 status = ERROR;
478 return 0;
479 }
480
481 key = parsePublicKeyData( output, key );
482
483 if( key == 0 )
484 {
485 return 0;
486 }
487
488 if( readTrust )
489 {
490 exitStatus = run( PGP2 " +batchmode +language=en +verbose=0 -kc -f",
491 0, true );
492
493 if(exitStatus != 0) {
494 status = ERROR;
495 return 0;
496 }
497
498 parseTrustDataForKey( key, error );
499 }
500
501 return key;
502}
503
504
505KeyList
506Base2::publicKeys( const TQStringList & patterns )
507{
508 return doGetPublicKeys( PGP2 " +batchmode +language=en +verbose=0 -kvc -f",
509 patterns );
510}
511
512KeyList
513Base2::doGetPublicKeys( const TQCString & cmd, const TQStringList & patterns )
514{
515 int exitStatus = 0;
516 KeyList publicKeys;
517
518 status = 0;
519 if ( patterns.isEmpty() ) {
520 exitStatus = run( cmd, 0, true );
521
522 if ( exitStatus != 0 ) {
523 status = ERROR;
524 return KeyList();
525 }
526
527 // now we need to parse the output for public keys
528 publicKeys = parseKeyList( output, false );
529 }
530 else {
531 typedef TQMap<TQCString, Key*> KeyMap;
532 KeyMap map;
533
534 for ( TQStringList::ConstIterator it = patterns.begin();
535 it != patterns.end(); ++it ) {
536 exitStatus = run( cmd + " " + TDEProcess::quote( *it ).local8Bit(),
537 0, true );
538
539 if ( exitStatus != 0 ) {
540 status = ERROR;
541 return KeyList();
542 }
543
544 // now we need to parse the output for public keys
545 publicKeys = parseKeyList( output, false );
546
547 // put all new keys into a map, remove duplicates
548 while ( !publicKeys.isEmpty() ) {
549 Key * key = publicKeys.take( 0 );
550 if ( !map.contains( key->primaryFingerprint() ) )
551 map.insert( key->primaryFingerprint(), key );
552 else
553 delete key;
554 }
555 }
556 // build list from the map
557 for ( KeyMap::ConstIterator it = map.begin(); it != map.end(); ++it ) {
558 publicKeys.append( it.data() );
559 }
560 }
561
562 // sort the list of public keys
563 publicKeys.sort();
564
565 return publicKeys;
566}
567
568KeyList
569Base2::secretKeys( const TQStringList & patterns )
570{
571 return publicKeys( patterns );
572}
573
574
575int
576Base2::signKey(const KeyID& keyID, const TQString &passphrase)
577{
578 TQCString cmd;
579 int exitStatus = 0;
580
581 cmd = PGP2 " +batchmode +language=en -ks -f ";
582 cmd += addUserId();
583 cmd += " 0x" + keyID;
584
585 status = 0;
586 exitStatus = run(cmd.data(),passphrase);
587
588 if (exitStatus != 0)
589 status = ERROR;
590
591 return status;
592}
593
594
595TQCString Base2::getAsciiPublicKey(const KeyID& keyID)
596{
597 int exitStatus = 0;
598
599 if (keyID.isEmpty())
600 return TQCString();
601
602 status = 0;
603 exitStatus = run( PGP2 " +batchmode +force +language=en -kxaf 0x" + keyID,
604 0, true );
605
606 if(exitStatus != 0) {
607 status = ERROR;
608 return TQCString();
609 }
610
611 return output;
612}
613
614
615Key*
616Base2::parsePublicKeyData( const TQCString& output, Key* key /* = 0 */ )
617{
618 Subkey *subkey = 0;
619 int index;
620
621 // search start of key data
622 if( !strncmp( output.data(), "pub", 3 ) ||
623 !strncmp( output.data(), "sec", 3 ) )
624 index = 0;
625 else
626 {
627 /*
628 if( secretKeys )
629 index = output.find( "\nsec" );
630 else
631 */
632 index = output.find( "\npub" );
633 if( index == -1 )
634 return 0;
635 else
636 index++;
637 }
638
639 while( true )
640 {
641 int index2;
642
643 // search the end of the current line
644 if( ( index2 = output.find( '\n', index ) ) == -1 )
645 break;
646
647 if( !strncmp( output.data() + index, "pub", 3 ) ||
648 !strncmp( output.data() + index, "sec", 3 ) )
649 { // line contains primary key data
650 // Example 1 (nothing special):
651 // pub 1024/E2D074D3 2001/09/09 Test Key <testkey@xyz>
652 // Example 2 (disabled key):
653 // pub- 1024/8CCB2C1B 2001/11/04 Disabled Test Key <disabled@xyz>
654 // Example 3 (expired key):
655 // pub> 1024/7B94827D 2001/09/09 Expired Test Key <expired@xyz> (EXPIRE:2001-09-10)
656 // Example 4 (revoked key):
657 // pub 1024/956721F9 2001/09/09 *** KEY REVOKED ***
658
659 int pos, pos2;
660
661 if( key == 0 )
662 key = new Key();
663 else
664 key->clear();
665 /*key->setSecret( secretKeys );*/
666 // set default key capabilities
667 key->setCanEncrypt( true );
668 key->setCanSign( true );
669 key->setCanCertify( true );
670
671 /*subkey = new Subkey( "", secretKeys );*/
672 subkey = new Subkey( "", false );
673 key->addSubkey( subkey );
674 // set default key capabilities
675 subkey->setCanEncrypt( true );
676 subkey->setCanSign( true );
677 subkey->setCanCertify( true );
678 // expiration date defaults to never
679 subkey->setExpirationDate( -1 );
680
681 // Key Flags
682 switch( output[index+3] )
683 {
684 case ' ': // nothing special
685 break;
686 case '-': // disabled key
687 subkey->setDisabled( true );
688 key->setDisabled( true );
689 break;
690 case '>': // expired key
691 subkey->setExpired( true );
692 key->setExpired( true );
693 break;
694 default:
695 kdDebug(5100) << "Unknown key flag.\n";
696 }
697
698 // Key Length
699 pos = index + 4;
700 while( output[pos] == ' ' )
701 pos++;
702 pos2 = output.find( '/', pos );
703 subkey->setKeyLength( output.mid( pos, pos2-pos ).toUInt() );
704
705 // Key ID
706 pos = pos2 + 1;
707 pos2 = output.find( ' ', pos );
708 subkey->setKeyID( output.mid( pos, pos2-pos ) );
709
710 // Creation Date
711 pos = pos2 + 1;
712 while( output[pos] == ' ' )
713 pos++;
714 pos2 = output.find( ' ', pos );
715 int year = output.mid( pos, 4 ).toInt();
716 int month = output.mid( pos+5, 2 ).toInt();
717 int day = output.mid( pos+8, 2 ).toInt();
718 TQDateTime dt( TQDate( year, month, day ), TQTime( 00, 00 ) );
719 TQDateTime epoch( TQDate( 1970, 01, 01 ), TQTime( 00, 00 ) );
720 // The calculated creation date isn't exactly correct because TQDateTime
721 // doesn't know anything about timezones and always assumes local time
722 // although epoch is of course UTC. But as PGP 2 anyway doesn't print
723 // the time this doesn't matter too much.
724 subkey->setCreationDate( epoch.secsTo( dt ) );
725
726 // User ID
727 pos = pos2 + 1;
728 while( output[pos] == ' ' )
729 pos++;
730 TQCString uid = output.mid( pos, index2-pos );
731 if( uid != "*** KEY REVOKED ***" )
732 key->addUserID( uid );
733 else
734 {
735 subkey->setRevoked( true );
736 key->setRevoked( true );
737 }
738 }
739 else if( output[index] == ' ' )
740 { // line contains additional key data
741
742 if( key == 0 )
743 break;
744 assert( subkey != 0 );
745
746 int pos = index + 1;
747 while( output[pos] == ' ' )
748 pos++;
749
750 if( !strncmp( output.data() + pos, "Key fingerprint = ", 18 ) )
751 { // line contains a fingerprint
752 // Example:
753 // Key fingerprint = 47 30 7C 76 05 BF 5E FB 72 41 00 F2 7D 0B D0 49
754
755 TQCString fingerprint = output.mid( pos, index2-pos );
756 // remove white space from the fingerprint
757 for ( int idx = 0 ; (idx = fingerprint.find(' ', idx)) >= 0 ; )
758 fingerprint.replace( idx, 1, "" );
759
760 subkey->setFingerprint( fingerprint );
761 }
762 else if( !strncmp( output.data() + pos, "Expire: ", 8 ) ||
763 !strncmp( output.data() + pos, "no expire ", 10 ) )
764 { // line contains additional key properties
765 // Examples:
766 // Expire: 2001/09/10
767 // no expire ENCRyption only
768 // no expire SIGNature only
769
770 if( output[pos] == 'E' )
771 {
772 // Expiration Date
773 pos += 8;
774 int year = output.mid( pos, 4 ).toInt();
775 int month = output.mid( pos+5, 2 ).toInt();
776 int day = output.mid( pos+8, 2 ).toInt();
777 TQDateTime dt( TQDate( year, month, day ), TQTime( 00, 00 ) );
778 TQDateTime epoch( TQDate( 1970, 01, 01 ), TQTime( 00, 00 ) );
779 // Here the same comments as for the creation date are valid.
780 subkey->setExpirationDate( epoch.secsTo( dt ) );
781 pos += 11; // note that there is always a blank after the expire date
782 }
783 else
784 pos += 10;
785
786 // optional key capabilities (sign/encrypt only)
787 if( pos != index2 )
788 {
789 if( !strncmp( output.data() + pos, "SIGNature only", 14 ) )
790 {
791 subkey->setCanEncrypt( false );
792 key->setCanEncrypt( false );
793 }
794 else if( !strncmp( output.data() + pos, "ENCRyption only", 15 ) )
795 {
796 subkey->setCanSign( false );
797 key->setCanSign( false );
798 subkey->setCanCertify( false );
799 key->setCanCertify( false );
800 }
801 }
802 }
803 else
804 { // line contains an additional user id
805 // Example:
806 // Test key (2nd user ID) <abc@xyz>
807
808 key->addUserID( output.mid( pos, index2-pos ) );
809 }
810 }
811 index = index2 + 1;
812 }
813
814 //kdDebug(5100) << "finished parsing key data\n";
815
816 return key;
817}
818
819
820void
821Base2::parseTrustDataForKey( Key* key, const TQCString& str )
822{
823 if( ( key == 0 ) || str.isEmpty() )
824 return;
825
826 TQCString keyID = key->primaryKeyID();
827 UserIDList userIDs = key->userIDs();
828
829 // search the trust data belonging to this key
830 int index = str.find( '\n' ) + 1;
831 while( ( index > 0 ) &&
832 ( strncmp( str.data() + index+2, keyID.data(), 8 ) != 0 ) )
833 index = str.find( '\n', index ) + 1;
834
835 if( index == 0 )
836 return;
837
838 bool ultimateTrust = false;
839 if( !strncmp( str.data() + index+11, "ultimate", 8 ) )
840 ultimateTrust = true;
841
842 bool firstLine = true;
843
844 while( true )
845 { // loop over all trust information about this key
846 int index2;
847
848 // search the end of the current line
849 if( ( index2 = str.find( '\n', index ) ) == -1 )
850 break;
851
852 // check if trust info for the next key starts
853 if( !firstLine && ( str[index+2] != ' ' ) )
854 break;
855
856 if( str[index+21] != ' ' )
857 { // line contains a validity value for a user ID
858
859 // determine the validity
860 Validity validity = KPGP_VALIDITY_UNKNOWN;
861 if( !strncmp( str.data() + index+21, "complete", 8 ) )
862 if( ultimateTrust )
863 validity = KPGP_VALIDITY_ULTIMATE;
864 else
865 validity = KPGP_VALIDITY_FULL;
866 else if( !strncmp( str.data() + index+21, "marginal", 8 ) )
867 validity = KPGP_VALIDITY_MARGINAL;
868 else if( !strncmp( str.data() + index+21, "never", 5 ) )
869 validity = KPGP_VALIDITY_NEVER;
870 else if( !strncmp( str.data() + index+21, "undefined", 9 ) )
871 validity = KPGP_VALIDITY_UNDEFINED;
872
873 // determine the user ID
874 int pos = index + 31;
875 if( str[index+2] == ' ' )
876 pos++; // additional user IDs start one column later
877 TQString uid = str.mid( pos, index2-pos );
878
879 // set the validity of the corresponding user ID
880 for( UserIDListIterator it( userIDs ); it.current(); ++it )
881 if( (*it)->text() == uid )
882 {
883 kdDebug(5100)<<"Setting the validity of "<<uid<<" to "<<validity<<endl;
884 (*it)->setValidity( validity );
885 break;
886 }
887 }
888
889 firstLine = false;
890 index = index2 + 1;
891 }
892}
893
894
895KeyList
896Base2::parseKeyList( const TQCString& output, bool secretKeys )
897{
898 kdDebug(5100) << "Kpgp::Base2::parseKeyList()" << endl;
899 KeyList keys;
900 Key *key = 0;
901 Subkey *subkey = 0;
902 int index;
903
904 // search start of key data
905 if( !strncmp( output.data(), "pub", 3 ) ||
906 !strncmp( output.data(), "sec", 3 ) )
907 index = 0;
908 else
909 {
910 if( secretKeys )
911 index = output.find( "\nsec" );
912 else
913 index = output.find( "\npub" );
914 if( index == -1 )
915 return keys;
916 else
917 index++;
918 }
919
920 while( true )
921 {
922 int index2;
923
924 // search the end of the current line
925 if( ( index2 = output.find( '\n', index ) ) == -1 )
926 break;
927
928 if( !strncmp( output.data() + index, "pub", 3 ) ||
929 !strncmp( output.data() + index, "sec", 3 ) )
930 { // line contains primary key data
931 // Example 1:
932 // pub 1024/E2D074D3 2001/09/09 Test Key <testkey@xyz>
933 // Example 2 (disabled key):
934 // pub- 1024/8CCB2C1B 2001/11/04 Disabled Test Key <disabled@xyz>
935 // Example 3 (expired key):
936 // pub> 1024/7B94827D 2001/09/09 Expired Test Key <expired@xyz> (EXPIRE:2001-09-10)
937 // Example 4 (revoked key):
938 // pub 1024/956721F9 2001/09/09 *** KEY REVOKED ***
939
940 int pos, pos2;
941
942 if( key != 0 ) // store the previous key in the key list
943 keys.append( key );
944
945 key = new Key();
946 key->setSecret( secretKeys );
947 // set default key capabilities
948 key->setCanEncrypt( true );
949 key->setCanSign( true );
950 key->setCanCertify( true );
951
952 subkey = new Subkey( "", secretKeys );
953 key->addSubkey( subkey );
954 // set default key capabilities
955 subkey->setCanEncrypt( true );
956 subkey->setCanSign( true );
957 subkey->setCanCertify( true );
958 // expiration date defaults to never
959 subkey->setExpirationDate( -1 );
960
961 // Key Flags
962 switch( output[index+3] )
963 {
964 case ' ': // nothing special
965 break;
966 case '-': // disabled key
967 subkey->setDisabled( true );
968 key->setDisabled( true );
969 break;
970 case '>': // expired key
971 subkey->setExpired( true );
972 key->setExpired( true );
973 break;
974 default:
975 kdDebug(5100) << "Unknown key flag.\n";
976 }
977
978 // Key Length
979 pos = index + 4;
980 while( output[pos] == ' ' )
981 pos++;
982 pos2 = output.find( '/', pos );
983 subkey->setKeyLength( output.mid( pos, pos2-pos ).toUInt() );
984
985 // Key ID
986 pos = pos2 + 1;
987 pos2 = output.find( ' ', pos );
988 subkey->setKeyID( output.mid( pos, pos2-pos ) );
989
990 // Creation Date
991 pos = pos2 + 1;
992 while( output[pos] == ' ' )
993 pos++;
994 pos2 = output.find( ' ', pos );
995 int year = output.mid( pos, 4 ).toInt();
996 int month = output.mid( pos+5, 2 ).toInt();
997 int day = output.mid( pos+8, 2 ).toInt();
998 TQDateTime dt( TQDate( year, month, day ), TQTime( 00, 00 ) );
999 TQDateTime epoch( TQDate( 1970, 01, 01 ), TQTime( 00, 00 ) );
1000 // The calculated creation date isn't exactly correct because TQDateTime
1001 // doesn't know anything about timezones and always assumes local time
1002 // although epoch is of course UTC. But as PGP 2 anyway doesn't print
1003 // the time this doesn't matter too much.
1004 subkey->setCreationDate( epoch.secsTo( dt ) );
1005
1006 // User ID
1007 pos = pos2 + 1;
1008 while( output[pos] == ' ' )
1009 pos++;
1010 TQCString uid = output.mid( pos, index2-pos );
1011 if( uid != "*** KEY REVOKED ***" )
1012 key->addUserID( uid );
1013 else
1014 {
1015 subkey->setRevoked( true );
1016 key->setRevoked( true );
1017 }
1018 }
1019 else if( output[index] == ' ' )
1020 { // line contains additional key data
1021
1022 if( key == 0 )
1023 break;
1024
1025 int pos = index + 1;
1026 while( output[pos] == ' ' )
1027 pos++;
1028
1029 if( !strncmp( output.data() + pos, "Key fingerprint = ", 18 ) )
1030 { // line contains a fingerprint
1031 // Example:
1032 // Key fingerprint = 47 30 7C 76 05 BF 5E FB 72 41 00 F2 7D 0B D0 49
1033
1034// int pos2;
1035// pos2 = pos + 18;
1036 TQCString fingerprint = output.mid( pos, index2-pos );
1037 // remove white space from the fingerprint
1038 for ( int idx = 0 ; (idx = fingerprint.find(' ', idx)) >= 0 ; )
1039 fingerprint.replace( idx, 1, "" );
1040
1041 subkey->setFingerprint( fingerprint );
1042 }
1043 else if( !strncmp( output.data() + pos, "Expire: ", 8 ) ||
1044 !strncmp( output.data() + pos, "no expire ", 10 ) )
1045 { // line contains additional key properties
1046 // Examples:
1047 // Expire: 2001/09/10
1048 // no expire ENCRyption only
1049 // no expire SIGNature only
1050
1051 if( output[pos] == 'E' )
1052 {
1053 // Expiration Date
1054 pos += 8;
1055 int year = output.mid( pos, 4 ).toInt();
1056 int month = output.mid( pos+5, 2 ).toInt();
1057 int day = output.mid( pos+8, 2 ).toInt();
1058 TQDateTime dt( TQDate( year, month, day ), TQTime( 00, 00 ) );
1059 TQDateTime epoch( TQDate( 1970, 01, 01 ), TQTime( 00, 00 ) );
1060 // Here the same comments as for the creation date are valid.
1061 subkey->setExpirationDate( epoch.secsTo( dt ) );
1062 pos += 11; // note that there is always a blank after the expire date
1063 }
1064 else
1065 pos += 10;
1066
1067 // optional key capabilities (sign/encrypt only)
1068 if( pos != index2 )
1069 {
1070 if( !strncmp( output.data() + pos, "SIGNature only", 14 ) )
1071 {
1072 subkey->setCanEncrypt( false );
1073 key->setCanEncrypt( false );
1074 }
1075 else if( !strncmp( output.data() + pos, "ENCRyption only", 15 ) )
1076 {
1077 subkey->setCanSign( false );
1078 key->setCanSign( false );
1079 subkey->setCanCertify( false );
1080 key->setCanCertify( false );
1081 }
1082 }
1083 }
1084 else
1085 { // line contains an additional user id
1086 // Example:
1087 // Test key (2nd user ID) <abc@xyz>
1088
1089 key->addUserID( output.mid( pos, index2-pos ) );
1090 }
1091 }
1092
1093 index = index2 + 1;
1094 }
1095
1096 if (key != 0) // store the last key in the key list
1097 keys.append( key );
1098
1099 //kdDebug(5100) << "finished parsing keys" << endl;
1100
1101 return keys;
1102}
1103
1104
1105} // namespace Kpgp