Cpp: Add TofuInfo to signatures
[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     return static_cast<Summary>(result);
228 }
229
230 const char *GpgME::Signature::fingerprint() const
231 {
232     return isNull() ? 0 : d->sigs[idx]->fpr ;
233 }
234
235 GpgME::Error GpgME::Signature::status() const
236 {
237     return Error(isNull() ? 0 : d->sigs[idx]->status);
238 }
239
240 time_t GpgME::Signature::creationTime() const
241 {
242     return static_cast<time_t>(isNull() ? 0 : d->sigs[idx]->timestamp);
243 }
244
245 time_t GpgME::Signature::expirationTime() const
246 {
247     return static_cast<time_t>(isNull() ? 0 : d->sigs[idx]->exp_timestamp);
248 }
249
250 bool GpgME::Signature::neverExpires() const
251 {
252     return expirationTime() == (time_t)0;
253 }
254
255 bool GpgME::Signature::isWrongKeyUsage() const
256 {
257     return !isNull() && d->sigs[idx]->wrong_key_usage;
258 }
259
260 bool GpgME::Signature::isVerifiedUsingChainModel() const
261 {
262     return !isNull() && d->sigs[idx]->chain_model;
263 }
264
265 GpgME::Signature::PKAStatus GpgME::Signature::pkaStatus() const
266 {
267     if (!isNull()) {
268         return static_cast<PKAStatus>(d->sigs[idx]->pka_trust);
269     }
270     return UnknownPKAStatus;
271 }
272
273 const char *GpgME::Signature::pkaAddress() const
274 {
275     if (!isNull()) {
276         return d->sigs[idx]->pka_address;
277     }
278     return 0;
279 }
280
281 GpgME::Signature::Validity GpgME::Signature::validity() const
282 {
283     if (isNull()) {
284         return Unknown;
285     }
286     switch (d->sigs[idx]->validity) {
287     default:
288     case GPGME_VALIDITY_UNKNOWN:   return Unknown;
289     case GPGME_VALIDITY_UNDEFINED: return Undefined;
290     case GPGME_VALIDITY_NEVER:     return Never;
291     case GPGME_VALIDITY_MARGINAL:  return Marginal;
292     case GPGME_VALIDITY_FULL:      return Full;
293     case GPGME_VALIDITY_ULTIMATE:  return Ultimate;
294     }
295 }
296
297 char GpgME::Signature::validityAsString() const
298 {
299     if (isNull()) {
300         return '?';
301     }
302     switch (d->sigs[idx]->validity) {
303     default:
304     case GPGME_VALIDITY_UNKNOWN:   return '?';
305     case GPGME_VALIDITY_UNDEFINED: return 'q';
306     case GPGME_VALIDITY_NEVER:     return 'n';
307     case GPGME_VALIDITY_MARGINAL:  return 'm';
308     case GPGME_VALIDITY_FULL:      return 'f';
309     case GPGME_VALIDITY_ULTIMATE:  return 'u';
310     }
311 }
312
313 GpgME::Error GpgME::Signature::nonValidityReason() const
314 {
315     return Error(isNull() ? 0 : d->sigs[idx]->validity_reason);
316 }
317
318 unsigned int GpgME::Signature::publicKeyAlgorithm() const
319 {
320     if (!isNull()) {
321         return d->sigs[idx]->pubkey_algo;
322     }
323     return 0;
324 }
325
326 const char *GpgME::Signature::publicKeyAlgorithmAsString() const
327 {
328     if (!isNull()) {
329         return gpgme_pubkey_algo_name(d->sigs[idx]->pubkey_algo);
330     }
331     return 0;
332 }
333
334 unsigned int GpgME::Signature::hashAlgorithm() const
335 {
336     if (!isNull()) {
337         return d->sigs[idx]->hash_algo;
338     }
339     return 0;
340 }
341
342 const char *GpgME::Signature::hashAlgorithmAsString() const
343 {
344     if (!isNull()) {
345         return gpgme_hash_algo_name(d->sigs[idx]->hash_algo);
346     }
347     return 0;
348 }
349
350 const char *GpgME::Signature::policyURL() const
351 {
352     return isNull() ? 0 : d->purls[idx] ;
353 }
354
355 GpgME::Notation GpgME::Signature::notation(unsigned int nidx) const
356 {
357     return GpgME::Notation(d, idx, nidx);
358 }
359
360 std::vector<GpgME::Notation> GpgME::Signature::notations() const
361 {
362     if (isNull()) {
363         return std::vector<GpgME::Notation>();
364     }
365     std::vector<GpgME::Notation> result;
366     result.reserve(d->nota[idx].size());
367     for (unsigned int i = 0 ; i < d->nota[idx].size() ; ++i) {
368         result.push_back(GpgME::Notation(d, idx, i));
369     }
370     return result;
371 }
372
373 std::vector<GpgME::TofuInfo> GpgME::Signature::tofuInfo() const
374 {
375     if (isNull()) {
376         return std::vector<GpgME::TofuInfo>();
377     }
378
379     return d->tinfos[idx];
380 }
381
382 class GpgME::Notation::Private
383 {
384 public:
385     Private() : d(), sidx(0), nidx(0), nota(0) {}
386     Private(const std::shared_ptr<VerificationResult::Private> &priv, unsigned int sindex, unsigned int nindex)
387         : d(priv), sidx(sindex), nidx(nindex), nota(0)
388     {
389
390     }
391     Private(gpgme_sig_notation_t n)
392         : d(), sidx(0), nidx(0), nota(n ? new _gpgme_sig_notation(*n) : 0)
393     {
394         if (nota && nota->name) {
395             nota->name = strdup(nota->name);
396         }
397         if (nota && nota->value) {
398             nota->value = strdup(nota->value);
399         }
400     }
401     Private(const Private &other)
402         : d(other.d), sidx(other.sidx), nidx(other.nidx), nota(other.nota)
403     {
404         if (nota) {
405             nota->name = strdup(nota->name);
406             nota->value = strdup(nota->value);
407         }
408     }
409     ~Private()
410     {
411         if (nota) {
412             std::free(nota->name);  nota->name = 0;
413             std::free(nota->value); nota->value = 0;
414             delete nota;
415         }
416     }
417
418     std::shared_ptr<VerificationResult::Private> d;
419     unsigned int sidx, nidx;
420     gpgme_sig_notation_t nota;
421 };
422
423 GpgME::Notation::Notation(const std::shared_ptr<VerificationResult::Private> &parent, unsigned int sindex, unsigned int nindex)
424     : d(new Private(parent, sindex, nindex))
425 {
426
427 }
428
429 GpgME::Notation::Notation(gpgme_sig_notation_t nota)
430     : d(new Private(nota))
431 {
432
433 }
434
435 GpgME::Notation::Notation() : d() {}
436
437 bool GpgME::Notation::isNull() const
438 {
439     if (!d) {
440         return true;
441     }
442     if (d->d) {
443         return d->sidx >= d->d->nota.size() || d->nidx >= d->d->nota[d->sidx].size() ;
444     }
445     return !d->nota;
446 }
447
448 const char *GpgME::Notation::name() const
449 {
450     return
451         isNull() ? 0 :
452         d->d ? d->d->nota[d->sidx][d->nidx].name :
453         d->nota ? d->nota->name : 0 ;
454 }
455
456 const char *GpgME::Notation::value() const
457 {
458     return
459         isNull() ? 0 :
460         d->d ? d->d->nota[d->sidx][d->nidx].value :
461         d->nota ? d->nota->value : 0 ;
462 }
463
464 GpgME::Notation::Flags GpgME::Notation::flags() const
465 {
466     return
467         convert_from_gpgme_sig_notation_flags_t(
468             isNull() ? 0 :
469             d->d ? d->d->nota[d->sidx][d->nidx].flags :
470             d->nota ? d->nota->flags : 0);
471 }
472
473 bool GpgME::Notation::isHumanReadable() const
474 {
475     return flags() & HumanReadable;
476 }
477
478 bool GpgME::Notation::isCritical() const
479 {
480     return flags() & Critical;
481 }
482
483 std::ostream &GpgME::operator<<(std::ostream &os, const VerificationResult &result)
484 {
485     os << "GpgME::VerificationResult(";
486     if (!result.isNull()) {
487         os << "\n error:      " << result.error()
488            << "\n fileName:   " << protect(result.fileName())
489            << "\n signatures:\n";
490         const std::vector<Signature> sigs = result.signatures();
491         std::copy(sigs.begin(), sigs.end(),
492                   std::ostream_iterator<Signature>(os, "\n"));
493     }
494     return os << ')';
495 }
496
497 std::ostream &GpgME::operator<<(std::ostream &os, Signature::PKAStatus pkaStatus)
498 {
499 #define OUTPUT( x ) if ( !(pkaStatus & (GpgME::Signature:: x)) ) {} else do { os << #x " "; } while(0)
500     os << "GpgME::Signature::PKAStatus(";
501     OUTPUT(UnknownPKAStatus);
502     OUTPUT(PKAVerificationFailed);
503     OUTPUT(PKAVerificationSucceeded);
504 #undef OUTPUT
505     return os << ')';
506 }
507
508 std::ostream &GpgME::operator<<(std::ostream &os, Signature::Summary summary)
509 {
510 #define OUTPUT( x ) if ( !(summary & (GpgME::Signature:: x)) ) {} else do { os << #x " "; } while(0)
511     os << "GpgME::Signature::Summary(";
512     OUTPUT(Valid);
513     OUTPUT(Green);
514     OUTPUT(Red);
515     OUTPUT(KeyRevoked);
516     OUTPUT(KeyExpired);
517     OUTPUT(SigExpired);
518     OUTPUT(KeyMissing);
519     OUTPUT(CrlMissing);
520     OUTPUT(CrlTooOld);
521     OUTPUT(BadPolicy);
522     OUTPUT(SysError);
523 #undef OUTPUT
524     return os << ')';
525 }
526
527 std::ostream &GpgME::operator<<(std::ostream &os, const Signature &sig)
528 {
529     os << "GpgME::Signature(";
530     if (!sig.isNull()) {
531         os << "\n Summary:                   " << sig.summary()
532            << "\n Fingerprint:               " << protect(sig.fingerprint())
533            << "\n Status:                    " << sig.status()
534            << "\n creationTime:              " << sig.creationTime()
535            << "\n expirationTime:            " << sig.expirationTime()
536            << "\n isWrongKeyUsage:           " << sig.isWrongKeyUsage()
537            << "\n isVerifiedUsingChainModel: " << sig.isVerifiedUsingChainModel()
538            << "\n pkaStatus:                 " << sig.pkaStatus()
539            << "\n pkaAddress:                " << protect(sig.pkaAddress())
540            << "\n validity:                  " << sig.validityAsString()
541            << "\n nonValidityReason:         " << sig.nonValidityReason()
542            << "\n publicKeyAlgorithm:        " << protect(sig.publicKeyAlgorithmAsString())
543            << "\n hashAlgorithm:             " << protect(sig.hashAlgorithmAsString())
544            << "\n policyURL:                 " << protect(sig.policyURL())
545            << "\n notations:\n";
546         const std::vector<Notation> nota = sig.notations();
547         std::copy(nota.begin(), nota.end(),
548                   std::ostream_iterator<Notation>(os, "\n"));
549         const std::vector<TofuInfo> tinfos = sig.tofuInfo();
550         std::copy(tinfos.begin(), tinfos.end(),
551                   std::ostream_iterator<TofuInfo>(os, "\n"));
552     }
553     return os << ')';
554 }
555
556 std::ostream &GpgME::operator<<(std::ostream &os, Notation::Flags flags)
557 {
558     os << "GpgME::Notation::Flags(";
559 #define OUTPUT( x ) if ( !(flags & (GpgME::Notation:: x)) ) {} else do { os << #x " "; } while(0)
560     OUTPUT(HumanReadable);
561     OUTPUT(Critical);
562 #undef OUTPUT
563     return os << ')';
564 }
565
566 std::ostream &GpgME::operator<<(std::ostream &os, const Notation &nota)
567 {
568     os << "GpgME::Signature::Notation(";
569     if (!nota.isNull()) {
570         os << "\n name:  " << protect(nota.name())
571            << "\n value: " << protect(nota.value())
572            << "\n flags: " << nota.flags()
573            << '\n';
574     }
575     return os << ")";
576 }