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