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