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