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