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