1 /*
2   key.h - wraps a gpgme key
3   Copyright (C) 2003, 2005 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 // -*- c++ -*-
24 #ifndef __GPGMEPP_KEY_H__
25 #define __GPGMEPP_KEY_H__
26 
27 #include "global.h"
28 #include "notation.h"
29 
30 #include "gpgmefw.h"
31 
32 #include <memory>
33 #include <sys/time.h>
34 
35 #include <vector>
36 #include <algorithm>
37 #include <string>
38 
39 namespace GpgME
40 {
41 
42 class Context;
43 
44 class Subkey;
45 class UserID;
46 class TofuInfo;
47 
48 typedef std::shared_ptr< std::remove_pointer<gpgme_key_t>::type > shared_gpgme_key_t;
49 
50 //
51 // class Key
52 //
53 
54 class GPGMEPP_EXPORT Key
55 {
56     friend class ::GpgME::Context;
57     struct Null {
NullNull58 		Null() {}
59 	};
60 public:
61     Key();
62     /* implicit */ Key(const Null &);
63     Key(const shared_gpgme_key_t &key);
64     Key(gpgme_key_t key, bool acquireRef);
65 
66     static const Null null;
67 
68     const Key &operator=(Key other)
69     {
70         swap(other);
71         return *this;
72     }
73 
74     const Key &mergeWith(const Key &other);
75 
swap(Key & other)76     void swap(Key &other)
77     {
78         using std::swap;
79         swap(this->key, other.key);
80     }
81 
isNull()82     bool isNull() const
83     {
84         return !key;
85     }
86 
87     UserID userID(unsigned int index) const;
88     Subkey subkey(unsigned int index) const;
89 
90     unsigned int numUserIDs() const;
91     unsigned int numSubkeys() const;
92 
93     std::vector<UserID> userIDs() const;
94     std::vector<Subkey> subkeys() const;
95 
96     bool isRevoked() const;
97     bool isExpired() const;
98     bool isDisabled() const;
99     bool isInvalid() const;
100 
101     /*! Shorthand for isNull || isRevoked || isExpired ||
102      *                          isDisabled || isInvalid */
103     bool isBad() const;
104 
105     bool canEncrypt() const;
106     /*!
107       This function contains a workaround for old gpgme's: all secret
108       OpenPGP keys canSign() == true, which canReallySign() doesn't
109       have. I don't have time to find what breaks when I remove this
110       workaround, but since Kleopatra merges secret into public keys,
111       the workaround is not necessary there (and actively harms), I've
112       added a new function instead.
113      */
114     bool canSign() const;
115     bool canReallySign() const;
116     bool canCertify() const;
117     bool canAuthenticate() const;
118     bool isQualified() const;
119     bool isDeVs() const;
120 
121     bool hasSecret() const;
isSecret()122     GPGMEPP_DEPRECATED bool isSecret() const
123     {
124         return hasSecret();
125     }
126 
127     /*!
128       @return true if this is a X.509 root certificate (currently
129       equivalent to something like
130       strcmp( chainID(), subkey(0).fingerprint() ) == 0 )
131     */
132     bool isRoot() const;
133 
134     enum OwnerTrust { Unknown = 0, Undefined = 1, Never = 2,
135                       Marginal = 3, Full = 4, Ultimate = 5
136                     };
137 
138     OwnerTrust ownerTrust() const;
139     char ownerTrustAsString() const;
140 
141     Protocol protocol() const;
142     const char *protocolAsString() const;
143 
144     const char *issuerSerial() const;
145     const char *issuerName() const;
146     const char *chainID() const;
147 
148     const char *keyID() const;
149     const char *shortKeyID() const;
150     const char *primaryFingerprint() const;
151 
152     unsigned int keyListMode() const;
153 
154     /*! Update information about this key.
155      * Starts a keylisting for this key with validity
156      * and tofu information gathering. Blocks for
157      * how long the keylisting takes.*/
158     void update();
159 
160     /**
161      * @brief Add a user id to this key.
162      *
163      * Needs gnupg 2.1.13 and the key needs to be updated
164      * afterwards to see the new uid.
165      *
166      * @param uid should be fully formatted and UTF-8 encoded.
167      *
168      * @returns a possible error.
169      **/
170     Error addUid(const char *uid);
171 
172     /**
173      * @brief try to locate the best pgp key for a given mailbox.
174      *
175      * Boils down to gpg --locate-key <mbox>
176      * This may take some time if remote sources are also
177      * used.
178      *
179      * @param mbox should be a mail address does not need to be normalized.
180      *
181      * @returns The best key for a mailbox or a null key.
182      */
183     static Key locate(const char *mbox);
184 
185     /* @enum Origin
186      * @brief The Origin of the key. */
187     enum Origin : unsigned int {
188         OriginUnknown = 0,
189         OriginKS = 1,
190         OriginDane = 3,
191         OriginWKD = 4,
192         OriginURL = 5,
193         OriginFile = 6,
194         OriginSelf = 7,
195         OriginOther = 31,
196     };
197     /*! Get the origin of the key.
198      *
199      * @returns the Origin. */
200     Origin origin() const;
201 
202     /*! Get the last update time.
203      *
204      * @returns the last update time. */
205     time_t lastUpdate() const;
206 private:
impl()207     gpgme_key_t impl() const
208     {
209         return key.get();
210     }
211     shared_gpgme_key_t key;
212 };
213 
214 //
215 // class Subkey
216 //
217 
218 class GPGMEPP_EXPORT Subkey
219 {
220 public:
221     Subkey();
222     Subkey(const shared_gpgme_key_t &key, gpgme_sub_key_t subkey);
223     Subkey(const shared_gpgme_key_t &key, unsigned int idx);
224 
225     const Subkey &operator=(Subkey other)
226     {
227         swap(other);
228         return *this;
229     }
230 
swap(Subkey & other)231     void swap(Subkey &other)
232     {
233         using std::swap;
234         swap(this->key, other.key);
235         swap(this->subkey, other.subkey);
236     }
237 
isNull()238     bool isNull() const
239     {
240         return !key || !subkey;
241     }
242 
243     Key parent() const;
244 
245     const char *keyID() const;
246     const char *fingerprint() const;
247 
248     time_t creationTime() const;
249     time_t expirationTime() const;
250     bool neverExpires() const;
251 
252     bool isRevoked() const;
253     bool isExpired() const;
254     bool isInvalid() const;
255     bool isDisabled() const;
256 
257     /*! Shorthand for isNull || isRevoked || isExpired ||
258      *                          isDisabled || isInvalid */
259     bool isBad() const;
260 
261     bool canEncrypt() const;
262     bool canSign() const;
263     bool canCertify() const;
264     bool canAuthenticate() const;
265     bool isQualified() const;
266     bool isDeVs() const;
267     bool isCardKey() const;
268 
269     bool isSecret() const;
270 
271     /** Same as gpgme_pubkey_algo_t */
272     enum PubkeyAlgo {
273         AlgoUnknown = 0,
274         AlgoRSA     = 1,
275         AlgoRSA_E   = 2,
276         AlgoRSA_S   = 3,
277         AlgoELG_E   = 16,
278         AlgoDSA     = 17,
279         AlgoECC     = 18,
280         AlgoELG     = 20,
281         AlgoECDSA   = 301,
282         AlgoECDH    = 302,
283         AlgoEDDSA   = 303,
284         AlgoMax     = 1 << 31
285     };
286 
287     PubkeyAlgo publicKeyAlgorithm() const;
288 
289     /**
290       @brief Get the public key algorithm name.
291 
292       This only works for the pre 2.1 algorithms for ECC NULL is returned.
293 
294       @returns a statically allocated string with the name of the public
295                key algorithm, or NULL if that name is not known.
296     */
297     const char *publicKeyAlgorithmAsString() const;
298 
299     /** @brief Same as publicKeyAlgorithmAsString but static. */
300     static const char *publicKeyAlgorithmAsString(PubkeyAlgo algo);
301 
302     /**
303        @brief Get the key algo string like GnuPG 2.1 prints it.
304 
305        This returns combinations of size and algorithm. Like
306        bp512 or rsa2048. Misnamed because publicKeyAlgorithmAsString
307        already used the older pubkey_algo_name.
308        Actually uses gpgme_pubkey_algo_string.
309 
310        @returns the key algorithm as string. Empty string on error.
311     */
312     std::string algoName() const;
313 
314     unsigned int length() const;
315 
316     const char *cardSerialNumber() const;
317 
318     const char *keyGrip() const;
319 
320 private:
321     shared_gpgme_key_t key;
322     gpgme_sub_key_t subkey;
323 };
324 
325 //
326 // class UserID
327 //
328 
329 class GPGMEPP_EXPORT UserID
330 {
331 public:
332     class Signature;
333 
334     UserID();
335     UserID(const shared_gpgme_key_t &key, gpgme_user_id_t uid);
336     UserID(const shared_gpgme_key_t &key, unsigned int idx);
337 
338     const UserID &operator=(UserID other)
339     {
340         swap(other);
341         return *this;
342     }
343 
swap(UserID & other)344     void swap(UserID &other)
345     {
346         using std::swap;
347         swap(this->key, other.key);
348         swap(this->uid, other.uid);
349     }
350 
isNull()351     bool isNull() const
352     {
353         return !key || !uid;
354     }
355 
356     Key parent() const;
357 
358     unsigned int numSignatures() const;
359     Signature signature(unsigned int index) const;
360     std::vector<Signature> signatures() const;
361 
362     const char *id() const;
363     const char *name() const;
364     const char *email() const;
365     const char *comment() const;
366     const char *uidhash() const;
367 
368     enum Validity { Unknown = 0, Undefined = 1, Never = 2,
369                     Marginal = 3, Full = 4, Ultimate = 5
370                   };
371 
372     Validity validity() const;
373     char validityAsString() const;
374 
375     bool isRevoked() const;
376     bool isInvalid() const;
377 
378     /*! Shorthand for isNull || isRevoked || isInvalid */
379     bool isBad() const;
380 
381     /** TOFU info for this userid.
382      * @returns The TOFU stats or a null TofuInfo.
383      */
384     GpgME::TofuInfo tofuInfo() const;
385 
386     /*! Wrapper around gpgme_addrspec_from_uid.
387      *
388      * The input string should match the format of
389      * a user id string.
390      *
391      * @returns a normalized mail address if found
392      * or an empty string. */
393     static std::string addrSpecFromString(const char *uid);
394 
395     /*! Wrapper around gpgme_addrspec_from_uid.
396      *
397      * @returns a normalized mail address for this userid
398      * or an empty string. */
399     std::string addrSpec() const;
400 
401     /*! Revoke the user id.
402      *
403      * Key needs update afterwards.
404      *
405      * @returns an error on error.*/
406     Error revoke();
407 
408     /*! Get the origin of the key.
409      *
410      * @returns the Origin. */
411     Key::Origin origin() const;
412 
413     /*! Get the last update time.
414      *
415      * @returns the last update time. */
416     time_t lastUpdate() const;
417 
418     /*! Get a remark made by the key provided.
419      * A remark is a signature notation on
420      * this user id made by the key with the
421      * name "rem@gnupg.org". Returns an error if the
422      * parent key of this user id was not listed with the
423      * keylist mode flags for signatures and signature notations.
424      *
425      * @param key The key for which comments should be searched.
426      * @param error Set to GPG_ERR_NO_DATA if the keylist did
427      *              not include signature notations.
428      *
429      * @returns The value of the comment or NULL if none exists.
430      **/
431     const char *remark(const Key &key,
432                        Error &error) const;
433 
434     /*! Get multiple remarks made by potentially multiple keys. */
435     std::vector <std::string> remarks(std::vector<GpgME::Key> remarkers,
436                                       Error &error) const;
437 
438 private:
439     shared_gpgme_key_t key;
440     gpgme_user_id_t uid;
441 };
442 
443 //
444 // class UserID::Signature
445 //
446 
447 class GPGMEPP_EXPORT UserID::Signature
448 {
449 public:
450     typedef GPGMEPP_DEPRECATED GpgME::Notation Notation;
451 
452     Signature();
453     Signature(const shared_gpgme_key_t &key, gpgme_user_id_t uid, gpgme_key_sig_t sig);
454     Signature(const shared_gpgme_key_t &key, gpgme_user_id_t uid, unsigned int idx);
455 
456     const Signature &operator=(Signature other)
457     {
458         swap(other);
459         return *this;
460     }
461 
swap(Signature & other)462     void swap(Signature &other)
463     {
464         using std::swap;
465         swap(this->key, other.key);
466         swap(this->uid, other.uid);
467         swap(this->sig, other.sig);
468     }
469 
470     /*! Defines a canonical sort order for signatures of the same user ID. */
471     bool operator<(const Signature &other) const;
472 
473     GPGMEPP_DEPRECATED bool operator<(const Signature &other);
474 
isNull()475     bool isNull() const
476     {
477         return !sig || !uid || !key ;
478     }
479 
480     UserID parent() const;
481 
482     const char *signerKeyID() const;
483 
484     const char *algorithmAsString() const;
485     unsigned int algorithm() const;
486     time_t creationTime() const;
487     time_t expirationTime() const;
488     bool neverExpires() const;
489 
490     bool isRevokation() const;
491     bool isInvalid() const;
492     bool isExpired() const;
493     bool isExportable() const;
494 
495     /*! Shorthand for isNull || isExpired || isInvalid */
496     bool isBad() const;
497 
498     const char *signerUserID() const;
499     const char *signerName() const;
500     const char *signerEmail() const;
501     const char *signerComment() const;
502 
503     unsigned int certClass() const;
504 
505     enum Status { NoError = 0, SigExpired, KeyExpired,
506                   BadSignature, NoPublicKey, GeneralError
507                 };
508     Status status() const;
509     std::string statusAsString() const;
510 
511     const char *policyURL() const;
512 
513     unsigned int numNotations() const;
514     GpgME::Notation notation(unsigned int idx) const;
515     std::vector<GpgME::Notation> notations() const;
516 
517 private:
518     shared_gpgme_key_t key;
519     gpgme_user_id_t uid;
520     gpgme_key_sig_t sig;
521 };
522 
523 GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const UserID &uid);
524 GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const Subkey &subkey);
525 GPGMEPP_EXPORT std::ostream &operator<<(std::ostream &os, const Key &key);
526 
527 } // namespace GpgME
528 
529 GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(Key)
530 GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(Subkey)
531 GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(UserID)
532 GPGMEPP_MAKE_STD_SWAP_SPECIALIZATION(UserID::Signature)
533 
534 GPGMEPP_MAKE_STRCMP(ByFingerprint, .primaryFingerprint());
535 GPGMEPP_MAKE_STRCMP(ByKeyID, .keyID());
536 GPGMEPP_MAKE_STRCMP(ByShortKeyID, .shortKeyID());
537 GPGMEPP_MAKE_STRCMP(ByChainID, .chainID());
538 
539 #endif // __GPGMEPP_KEY_H__
540