cpp, qt: Include config.h
[gpgme.git] / lang / cpp / src / verificationresult.cpp
1 /*
2   verificationresult.cpp - wraps a gpgme verify result
3   Copyright (C) 2004 Klarälvdalens Datakonsult AB
4
5   This file is part of GPGME++.
6
7   GPGME++ is free software; you can redistribute it and/or
8   modify it under the terms of the GNU Library General Public
9   License as published by the Free Software Foundation; either
10   version 2 of the License, or (at your option) any later version.
11
12   GPGME++ is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU Library General Public License for more details.
16
17   You should have received a copy of the GNU Library General Public License
18   along with GPGME++; see the file COPYING.LIB.  If not, write to the
19   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20   Boston, MA 02110-1301, USA.
21 */
22
23 #ifdef HAVE_CONFIG_H
24  #include "config.h"
25 #endif
26
27 #include <verificationresult.h>
28 #include <notation.h>
29 #include "result_p.h"
30 #include "util.h"
31 #include "key.h"
32
33 #include <gpgme.h>
34
35 #include <istream>
36 #include <algorithm>
37 #include <iterator>
38 #include <string>
39 #include <cstring>
40 #include <cstdlib>
41
42 #include <string.h>
43
44 class GpgME::VerificationResult::Private
45 {
46 public:
47     explicit Private(const gpgme_verify_result_t r)
48     {
49         if (!r) {
50             return;
51         }
52         if (r->file_name) {
53             file_name = r->file_name;
54         }
55         // copy recursively, using compiler-generated copy ctor.
56         // We just need to handle the pointers in the structs:
57         for (gpgme_signature_t is = r->signatures ; is ; is = is->next) {
58             gpgme_signature_t scopy = new _gpgme_signature(*is);
59             if (is->fpr) {
60                 scopy->fpr = strdup(is->fpr);
61             }
62 // PENDING(marc) why does this crash on Windows in strdup()?
63 # ifndef _WIN32
64             if (is->pka_address) {
65                 scopy->pka_address = strdup(is->pka_address);
66             }
67 # else
68             scopy->pka_address = 0;
69 # endif
70             scopy->next = 0;
71             sigs.push_back(scopy);
72             // copy keys
73             if (scopy->key) {
74                 keys.push_back(Key(scopy->key, true));
75             }
76             // copy notations:
77             nota.push_back(std::vector<Nota>());
78             purls.push_back(0);
79             for (gpgme_sig_notation_t in = is->notations ; in ; in = in->next) {
80                 if (!in->name) {
81                     if (in->value) {
82                         purls.back() = strdup(in->value);   // policy url
83                     }
84                     continue;
85                 }
86                 Nota n = { 0, 0, in->flags };
87                 n.name = strdup(in->name);
88                 if (in->value) {
89                     n.value = strdup(in->value);
90                 }
91                 nota.back().push_back(n);
92             }
93         }
94     }
95     ~Private()
96     {
97         for (std::vector<gpgme_signature_t>::iterator it = sigs.begin() ; it != sigs.end() ; ++it) {
98             std::free((*it)->fpr);
99             std::free((*it)->pka_address);
100             delete *it; *it = 0;
101         }
102         for (std::vector< std::vector<Nota> >::iterator it = nota.begin() ; it != nota.end() ; ++it) {
103             for (std::vector<Nota>::iterator jt = it->begin() ; jt != it->end() ; ++jt) {
104                 std::free(jt->name);  jt->name = 0;
105                 std::free(jt->value); jt->value = 0;
106             }
107         }
108         std::for_each(purls.begin(), purls.end(), &std::free);
109     }
110
111     struct Nota {
112         char *name;
113         char *value;
114         gpgme_sig_notation_flags_t flags;
115     };
116
117     std::vector<gpgme_signature_t> sigs;
118     std::vector< std::vector<Nota> > nota;
119     std::vector<GpgME::Key> keys;
120     std::vector<char *> purls;
121     std::string file_name;
122 };
123
124 GpgME::VerificationResult::VerificationResult(gpgme_ctx_t ctx, int error)
125     : GpgME::Result(error), d()
126 {
127     init(ctx);
128 }
129
130 GpgME::VerificationResult::VerificationResult(gpgme_ctx_t ctx, const Error &error)
131     : GpgME::Result(error), d()
132 {
133     init(ctx);
134 }
135
136 void GpgME::VerificationResult::init(gpgme_ctx_t ctx)
137 {
138     if (!ctx) {
139         return;
140     }
141     gpgme_verify_result_t res = gpgme_op_verify_result(ctx);
142     if (!res) {
143         return;
144     }
145     d.reset(new Private(res));
146 }
147
148 make_standard_stuff(VerificationResult)
149
150 const char *GpgME::VerificationResult::fileName() const
151 {
152     return d ? d->file_name.c_str() : 0 ;
153 }
154
155 unsigned int GpgME::VerificationResult::numSignatures() const
156 {
157     return d ? d->sigs.size() : 0 ;
158 }
159
160 GpgME::Signature GpgME::VerificationResult::signature(unsigned int idx) const
161 {
162     return Signature(d, idx);
163 }
164
165 std::vector<GpgME::Signature> GpgME::VerificationResult::signatures() const
166 {
167     if (!d) {
168         return std::vector<Signature>();
169     }
170     std::vector<Signature> result;
171     result.reserve(d->sigs.size());
172     for (unsigned int i = 0 ; i < d->sigs.size() ; ++i) {
173         result.push_back(Signature(d, i));
174     }
175     return result;
176 }
177
178 GpgME::Signature::Signature(const std::shared_ptr<VerificationResult::Private> &parent, unsigned int i)
179     : d(parent), idx(i)
180 {
181 }
182
183 GpgME::Signature::Signature() : d(), idx(0) {}
184
185 bool GpgME::Signature::isNull() const
186 {
187     return !d || idx >= d->sigs.size() ;
188 }
189
190 GpgME::Signature::Summary GpgME::Signature::summary() const
191 {
192     if (isNull()) {
193         return None;
194     }
195     gpgme_sigsum_t sigsum = d->sigs[idx]->summary;
196     unsigned int result = 0;
197     if (sigsum & GPGME_SIGSUM_VALID) {
198         result |= Valid;
199     }
200     if (sigsum & GPGME_SIGSUM_GREEN) {
201         result |= Green;
202     }
203     if (sigsum & GPGME_SIGSUM_RED) {
204         result |= Red;
205     }
206     if (sigsum & GPGME_SIGSUM_KEY_REVOKED) {
207         result |= KeyRevoked;
208     }
209     if (sigsum & GPGME_SIGSUM_KEY_EXPIRED) {
210         result |= KeyExpired;
211     }
212     if (sigsum & GPGME_SIGSUM_SIG_EXPIRED) {
213         result |= SigExpired;
214     }
215     if (sigsum & GPGME_SIGSUM_KEY_MISSING) {
216         result |= KeyMissing;
217     }
218     if (sigsum & GPGME_SIGSUM_CRL_MISSING) {
219         result |= CrlMissing;
220     }
221     if (sigsum & GPGME_SIGSUM_CRL_TOO_OLD) {
222         result |= CrlTooOld;
223     }
224     if (sigsum & GPGME_SIGSUM_BAD_POLICY) {
225         result |= BadPolicy;
226     }
227     if (sigsum & GPGME_SIGSUM_SYS_ERROR) {
228         result |= SysError;
229     }
230     if (sigsum & GPGME_SIGSUM_TOFU_CONFLICT) {
231         result |= TofuConflict;
232     }
233     return static_cast<Summary>(result);
234 }
235
236 const char *GpgME::Signature::fingerprint() const
237 {
238     return isNull() ? 0 : d->sigs[idx]->fpr ;
239 }
240
241 GpgME::Error GpgME::Signature::status() const
242 {
243     return Error(isNull() ? 0 : d->sigs[idx]->status);
244 }
245
246 time_t GpgME::Signature::creationTime() const
247 {
248     return static_cast<time_t>(isNull() ? 0 : d->sigs[idx]->timestamp);
249 }
250
251 time_t GpgME::Signature::expirationTime() const
252 {
253     return static_cast<time_t>(isNull() ? 0 : d->sigs[idx]->exp_timestamp);
254 }
255
256 bool GpgME::Signature::neverExpires() const
257 {
258     return expirationTime() == (time_t)0;
259 }
260
261 bool GpgME::Signature::isWrongKeyUsage() const
262 {
263     return !isNull() && d->sigs[idx]->wrong_key_usage;
264 }
265
266 bool GpgME::Signature::isVerifiedUsingChainModel() const
267 {
268     return !isNull() && d->sigs[idx]->chain_model;
269 }
270
271 GpgME::Signature::PKAStatus GpgME::Signature::pkaStatus() const
272 {
273     if (!isNull()) {
274         return static_cast<PKAStatus>(d->sigs[idx]->pka_trust);
275     }
276     return UnknownPKAStatus;
277 }
278
279 const char *GpgME::Signature::pkaAddress() const
280 {
281     if (!isNull()) {
282         return d->sigs[idx]->pka_address;
283     }
284     return 0;
285 }
286
287 GpgME::Signature::Validity GpgME::Signature::validity() const
288 {
289     if (isNull()) {
290         return Unknown;
291     }
292     switch (d->sigs[idx]->validity) {
293     default:
294     case GPGME_VALIDITY_UNKNOWN:   return Unknown;
295     case GPGME_VALIDITY_UNDEFINED: return Undefined;
296     case GPGME_VALIDITY_NEVER:     return Never;
297     case GPGME_VALIDITY_MARGINAL:  return Marginal;
298     case GPGME_VALIDITY_FULL:      return Full;
299     case GPGME_VALIDITY_ULTIMATE:  return Ultimate;
300     }
301 }
302
303 char GpgME::Signature::validityAsString() const
304 {
305     if (isNull()) {
306         return '?';
307     }
308     switch (d->sigs[idx]->validity) {
309     default:
310     case GPGME_VALIDITY_UNKNOWN:   return '?';
311     case GPGME_VALIDITY_UNDEFINED: return 'q';
312     case GPGME_VALIDITY_NEVER:     return 'n';
313     case GPGME_VALIDITY_MARGINAL:  return 'm';
314     case GPGME_VALIDITY_FULL:      return 'f';
315     case GPGME_VALIDITY_ULTIMATE:  return 'u';
316     }
317 }
318
319 GpgME::Error GpgME::Signature::nonValidityReason() const
320 {
321     return Error(isNull() ? 0 : d->sigs[idx]->validity_reason);
322 }
323
324 unsigned int GpgME::Signature::publicKeyAlgorithm() const
325 {
326     if (!isNull()) {
327         return d->sigs[idx]->pubkey_algo;
328     }
329     return 0;
330 }
331
332 const char *GpgME::Signature::publicKeyAlgorithmAsString() const
333 {
334     if (!isNull()) {
335         return gpgme_pubkey_algo_name(d->sigs[idx]->pubkey_algo);
336     }
337     return 0;
338 }
339
340 unsigned int GpgME::Signature::hashAlgorithm() const
341 {
342     if (!isNull()) {
343         return d->sigs[idx]->hash_algo;
344     }
345     return 0;
346 }
347
348 const char *GpgME::Signature::hashAlgorithmAsString() const
349 {
350     if (!isNull()) {
351         return gpgme_hash_algo_name(d->sigs[idx]->hash_algo);
352     }
353     return 0;
354 }
355
356 const char *GpgME::Signature::policyURL() const
357 {
358     return isNull() ? 0 : d->purls[idx] ;
359 }
360
361 GpgME::Notation GpgME::Signature::notation(unsigned int nidx) const
362 {
363     return GpgME::Notation(d, idx, nidx);
364 }
365
366 std::vector<GpgME::Notation> GpgME::Signature::notations() const
367 {
368     if (isNull()) {
369         return std::vector<GpgME::Notation>();
370     }
371     std::vector<GpgME::Notation> result;
372     result.reserve(d->nota[idx].size());
373     for (unsigned int i = 0 ; i < d->nota[idx].size() ; ++i) {
374         result.push_back(GpgME::Notation(d, idx, i));
375     }
376     return result;
377 }
378
379 GpgME::Key GpgME::Signature::key() const
380 {
381     if (isNull()) {
382         return Key();
383     }
384     return d->keys[idx];
385 }
386
387 class GpgME::Notation::Private
388 {
389 public:
390     Private() : d(), sidx(0), nidx(0), nota(0) {}
391     Private(const std::shared_ptr<VerificationResult::Private> &priv, unsigned int sindex, unsigned int nindex)
392         : d(priv), sidx(sindex), nidx(nindex), nota(0)
393     {
394
395     }
396     Private(gpgme_sig_notation_t n)
397         : d(), sidx(0), nidx(0), nota(n ? new _gpgme_sig_notation(*n) : 0)
398     {
399         if (nota && nota->name) {
400             nota->name = strdup(nota->name);
401         }
402         if (nota && nota->value) {
403             nota->value = strdup(nota->value);
404         }
405     }
406     Private(const Private &other)
407         : d(other.d), sidx(other.sidx), nidx(other.nidx), nota(other.nota)
408     {
409         if (nota) {
410             nota->name = strdup(nota->name);
411             nota->value = strdup(nota->value);
412         }
413     }
414     ~Private()
415     {
416         if (nota) {
417             std::free(nota->name);  nota->name = 0;
418             std::free(nota->value); nota->value = 0;
419             delete nota;
420         }
421     }
422
423     std::shared_ptr<VerificationResult::Private> d;
424     unsigned int sidx, nidx;
425     gpgme_sig_notation_t nota;
426 };
427
428 GpgME::Notation::Notation(const std::shared_ptr<VerificationResult::Private> &parent, unsigned int sindex, unsigned int nindex)
429     : d(new Private(parent, sindex, nindex))
430 {
431
432 }
433
434 GpgME::Notation::Notation(gpgme_sig_notation_t nota)
435     : d(new Private(nota))
436 {
437
438 }
439
440 GpgME::Notation::Notation() : d() {}
441
442 bool GpgME::Notation::isNull() const
443 {
444     if (!d) {
445         return true;
446     }
447     if (d->d) {
448         return d->sidx >= d->d->nota.size() || d->nidx >= d->d->nota[d->sidx].size() ;
449     }
450     return !d->nota;
451 }
452
453 const char *GpgME::Notation::name() const
454 {
455     return
456         isNull() ? 0 :
457         d->d ? d->d->nota[d->sidx][d->nidx].name :
458         d->nota ? d->nota->name : 0 ;
459 }
460
461 const char *GpgME::Notation::value() const
462 {
463     return
464         isNull() ? 0 :
465         d->d ? d->d->nota[d->sidx][d->nidx].value :
466         d->nota ? d->nota->value : 0 ;
467 }
468
469 GpgME::Notation::Flags GpgME::Notation::flags() const
470 {
471     return
472         convert_from_gpgme_sig_notation_flags_t(
473             isNull() ? 0 :
474             d->d ? d->d->nota[d->sidx][d->nidx].flags :
475             d->nota ? d->nota->flags : 0);
476 }
477
478 bool GpgME::Notation::isHumanReadable() const
479 {
480     return flags() & HumanReadable;
481 }
482
483 bool GpgME::Notation::isCritical() const
484 {
485     return flags() & Critical;
486 }
487
488 std::ostream &GpgME::operator<<(std::ostream &os, const VerificationResult &result)
489 {
490     os << "GpgME::VerificationResult(";
491     if (!result.isNull()) {
492         os << "\n error:      " << result.error()
493            << "\n fileName:   " << protect(result.fileName())
494            << "\n signatures:\n";
495         const std::vector<Signature> sigs = result.signatures();
496         std::copy(sigs.begin(), sigs.end(),
497                   std::ostream_iterator<Signature>(os, "\n"));
498     }
499     return os << ')';
500 }
501
502 std::ostream &GpgME::operator<<(std::ostream &os, Signature::PKAStatus pkaStatus)
503 {
504 #define OUTPUT( x ) if ( !(pkaStatus & (GpgME::Signature:: x)) ) {} else do { os << #x " "; } while(0)
505     os << "GpgME::Signature::PKAStatus(";
506     OUTPUT(UnknownPKAStatus);
507     OUTPUT(PKAVerificationFailed);
508     OUTPUT(PKAVerificationSucceeded);
509 #undef OUTPUT
510     return os << ')';
511 }
512
513 std::ostream &GpgME::operator<<(std::ostream &os, Signature::Summary summary)
514 {
515 #define OUTPUT( x ) if ( !(summary & (GpgME::Signature:: x)) ) {} else do { os << #x " "; } while(0)
516     os << "GpgME::Signature::Summary(";
517     OUTPUT(Valid);
518     OUTPUT(Green);
519     OUTPUT(Red);
520     OUTPUT(KeyRevoked);
521     OUTPUT(KeyExpired);
522     OUTPUT(SigExpired);
523     OUTPUT(KeyMissing);
524     OUTPUT(CrlMissing);
525     OUTPUT(CrlTooOld);
526     OUTPUT(BadPolicy);
527     OUTPUT(SysError);
528     OUTPUT(TofuConflict);
529 #undef OUTPUT
530     return os << ')';
531 }
532
533 std::ostream &GpgME::operator<<(std::ostream &os, const Signature &sig)
534 {
535     os << "GpgME::Signature(";
536     if (!sig.isNull()) {
537         os << "\n Summary:                   " << sig.summary()
538            << "\n Fingerprint:               " << protect(sig.fingerprint())
539            << "\n Status:                    " << sig.status()
540            << "\n creationTime:              " << sig.creationTime()
541            << "\n expirationTime:            " << sig.expirationTime()
542            << "\n isWrongKeyUsage:           " << sig.isWrongKeyUsage()
543            << "\n isVerifiedUsingChainModel: " << sig.isVerifiedUsingChainModel()
544            << "\n pkaStatus:                 " << sig.pkaStatus()
545            << "\n pkaAddress:                " << protect(sig.pkaAddress())
546            << "\n validity:                  " << sig.validityAsString()
547            << "\n nonValidityReason:         " << sig.nonValidityReason()
548            << "\n publicKeyAlgorithm:        " << protect(sig.publicKeyAlgorithmAsString())
549            << "\n hashAlgorithm:             " << protect(sig.hashAlgorithmAsString())
550            << "\n policyURL:                 " << protect(sig.policyURL())
551            << "\n notations:\n";
552         const std::vector<Notation> nota = sig.notations();
553         std::copy(nota.begin(), nota.end(),
554                   std::ostream_iterator<Notation>(os, "\n"));
555     }
556     return os << ')';
557 }
558
559 std::ostream &GpgME::operator<<(std::ostream &os, Notation::Flags flags)
560 {
561     os << "GpgME::Notation::Flags(";
562 #define OUTPUT( x ) if ( !(flags & (GpgME::Notation:: x)) ) {} else do { os << #x " "; } while(0)
563     OUTPUT(HumanReadable);
564     OUTPUT(Critical);
565 #undef OUTPUT
566     return os << ')';
567 }
568
569 std::ostream &GpgME::operator<<(std::ostream &os, const Notation &nota)
570 {
571     os << "GpgME::Signature::Notation(";
572     if (!nota.isNull()) {
573         os << "\n name:  " << protect(nota.name())
574            << "\n value: " << protect(nota.value())
575            << "\n flags: " << nota.flags()
576            << '\n';
577     }
578     return os << ")";
579 }