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