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