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