diff --git a/common/status.h b/common/status.h
index 730a75cfc..966489fa3 100644
--- a/common/status.h
+++ b/common/status.h
@@ -1,161 +1,162 @@
/* status.h - Status codes
* Copyright (C) 2007 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of either
*
* - the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at
* your option) any later version.
*
* or
*
* - the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* or both in parallel, as here.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see .
*/
#ifndef GNUPG_COMMON_STATUS_H
#define GNUPG_COMMON_STATUS_H
enum
{
STATUS_ENTER,
STATUS_LEAVE,
STATUS_ABORT,
STATUS_GOODSIG,
STATUS_BADSIG,
STATUS_ERRSIG,
STATUS_BADARMOR,
STATUS_TRUST_UNDEFINED,
STATUS_TRUST_NEVER,
STATUS_TRUST_MARGINAL,
STATUS_TRUST_FULLY,
STATUS_TRUST_ULTIMATE,
STATUS_NEED_PASSPHRASE,
STATUS_VALIDSIG,
STATUS_SIG_ID,
STATUS_ENC_TO,
STATUS_NODATA,
STATUS_BAD_PASSPHRASE,
STATUS_NO_PUBKEY,
STATUS_NO_SECKEY,
STATUS_NEED_PASSPHRASE_SYM,
STATUS_DECRYPTION_INFO,
STATUS_DECRYPTION_FAILED,
STATUS_DECRYPTION_OKAY,
STATUS_MISSING_PASSPHRASE,
STATUS_GOOD_PASSPHRASE,
STATUS_GOODMDC,
STATUS_BADMDC,
STATUS_ERRMDC,
STATUS_IMPORTED,
STATUS_IMPORT_OK,
STATUS_IMPORT_PROBLEM,
STATUS_IMPORT_RES,
STATUS_IMPORT_CHECK,
STATUS_EXPORTED,
STATUS_EXPORT_RES,
STATUS_FILE_START,
STATUS_FILE_DONE,
STATUS_FILE_ERROR,
STATUS_BEGIN_DECRYPTION,
STATUS_END_DECRYPTION,
STATUS_BEGIN_ENCRYPTION,
STATUS_END_ENCRYPTION,
STATUS_BEGIN_SIGNING,
STATUS_DELETE_PROBLEM,
STATUS_GET_BOOL,
STATUS_GET_LINE,
STATUS_GET_HIDDEN,
STATUS_GOT_IT,
STATUS_PROGRESS,
STATUS_SIG_CREATED,
STATUS_SESSION_KEY,
STATUS_NOTATION_NAME,
STATUS_NOTATION_DATA,
STATUS_POLICY_URL,
STATUS_KEY_CREATED,
STATUS_USERID_HINT,
STATUS_UNEXPECTED,
STATUS_INV_RECP,
STATUS_INV_SGNR,
STATUS_NO_RECP,
STATUS_NO_SGNR,
+ STATUS_KEY_CONSIDERED,
STATUS_ALREADY_SIGNED,
STATUS_KEYEXPIRED,
STATUS_KEYREVOKED,
STATUS_EXPSIG,
STATUS_EXPKEYSIG,
STATUS_ATTRIBUTE,
STATUS_REVKEYSIG,
STATUS_NEWSIG,
STATUS_SIG_SUBPACKET,
STATUS_PLAINTEXT,
STATUS_PLAINTEXT_LENGTH,
STATUS_KEY_NOT_CREATED,
STATUS_NEED_PASSPHRASE_PIN,
STATUS_CARDCTRL,
STATUS_SC_OP_FAILURE,
STATUS_SC_OP_SUCCESS,
STATUS_BACKUP_KEY_CREATED,
STATUS_PKA_TRUST_BAD,
STATUS_PKA_TRUST_GOOD,
STATUS_TOFU_USER,
STATUS_TOFU_STATS,
STATUS_TOFU_STATS_SHORT,
STATUS_TOFU_STATS_LONG,
STATUS_TRUNCATED,
STATUS_MOUNTPOINT,
STATUS_PINENTRY_LAUNCHED,
STATUS_PLAINTEXT_FOLLOWS, /* Used by g13-syshelp */
STATUS_ERROR,
STATUS_WARNING,
STATUS_SUCCESS,
STATUS_FAILURE,
STATUS_INQUIRE_MAXLEN
};
const char *get_status_string (int code);
const char *get_inv_recpsgnr_code (gpg_error_t err);
#endif /*GNUPG_COMMON_STATUS_H*/
diff --git a/doc/DETAILS b/doc/DETAILS
index 5ceab68e4..271000749 100644
--- a/doc/DETAILS
+++ b/doc/DETAILS
@@ -1,1284 +1,1295 @@
# doc/DETAILS -*- org -*-
#+TITLE: GnuPG Details
# Globally disable superscripts and subscripts:
#+OPTIONS: ^:{}
#
# Note: This file uses org-mode; it should be easy to read as plain
# text but be aware of some markup peculiarities: Verbatim code is
# enclosed in #+begin-example, #+end-example blocks or marked by a
# colon as the first non-white-space character, words bracketed with
# equal signs indicate a monospace font, and the usual /italics/,
# *bold*, and _underline_ conventions are recognized.
This is the DETAILS file for GnuPG which specifies some internals and
parts of the external API for GPG and GPGSM.
* Format of the colon listings
The format is a based on colon separated record, each recods starts
with a tag string and extends to the end of the line. Here is an
example:
#+begin_example
$ gpg --with-colons --list-keys \
--with-fingerprint --with-fingerprint wk@gnupg.org
pub:f:1024:17:6C7EE1B8621CC013:899817715:1055898235::m:::scESC:
fpr:::::::::ECAF7590EB3443B5C7CF3ACB6C7EE1B8621CC013:
uid:f::::::::Werner Koch :
uid:f::::::::Werner Koch :
sub:f:1536:16:06AD222CADF6A6E1:919537416:1036177416:::::e:
fpr:::::::::CF8BCC4B18DE08FCD8A1615906AD222CADF6A6E1:
sub:r:1536:20:5CE086B5B5A18FF4:899817788:1025961788:::::esc:
fpr:::::::::AB059359A3B81F410FCFF97F5CE086B5B5A18FF4:
#+end_example
The double =--with-fingerprint= prints the fingerprint for the subkeys
too. Old versions of gpg used a slightly different format and required
the use of the option =--fixed-list-mode= to conform to the format
described here.
** Description of the fields
*** Field 1 - Type of record
- pub :: Public key
- crt :: X.509 certificate
- crs :: X.509 certificate and private key available
- sub :: Subkey (secondary key)
- sec :: Secret key
- ssb :: Secret subkey (secondary key)
- uid :: User id (only field 10 is used).
- uat :: User attribute (same as user id except for field 10).
- sig :: Signature
- rev :: Revocation signature
- fpr :: Fingerprint (fingerprint is in field 10)
- pkd :: Public key data [*]
- grp :: Keygrip
- rvk :: Revocation key
- tru :: Trust database information [*]
- spk :: Signature subpacket [*]
- cfg :: Configuration data [*]
Records marked with an asterisk are described at [[*Special%20field%20formats][*Special fields]].
*** Field 2 - Validity
This is a letter describing the computed validity of a key.
Currently this is a single letter, but be prepared that additional
information may follow in some future versions. Note that GnuPG <
2.1 does not set this field for secret key listings.
- o :: Unknown (this key is new to the system)
- i :: The key is invalid (e.g. due to a missing self-signature)
- d :: The key has been disabled
(deprecated - use the 'D' in field 12 instead)
- r :: The key has been revoked
- e :: The key has expired
- - :: Unknown validity (i.e. no value assigned)
- q :: Undefined validity. '-' and 'q' may safely be treated as
the same value for most purposes
- n :: The key is not valid
- m :: The key is marginal valid.
- f :: The key is fully valid
- u :: The key is ultimately valid. This often means that the
secret key is available, but any key may be marked as
ultimately valid.
- w :: The key has a well known private part.
- s :: The key has special validity. This means that it might be
self-signed and expected to be used in the STEED sytem.
If the validity information is given for a UID or UAT record, it
describes the validity calculated based on this user ID. If given
for a key record it describes the validity taken from the best
rated user ID.
For X.509 certificates a 'u' is used for a trusted root
certificate (i.e. for the trust anchor) and an 'f' for all other
valid certificates.
*** Field 3 - Key length
The length of key in bits.
*** Field 4 - Public key algorithm
The values here are those from the OpenPGP specs or if they are
greather than 255 the algorithm ids as used by Libgcrypt.
*** Field 5 - KeyID
This is the 64 bit keyid as specified by OpenPGP and the last 64
bit of the SHA-1 fingerprint of an X.509 certifciate.
*** Field 6 - Creation date
The creation date of the key is given in UTC. For UID and UAT
records, this is used for the self-signature date. Note that the
date is usally printed in seconds since epoch, however, we are
migrating to an ISO 8601 format (e.g. "19660205T091500"). This is
currently only relevant for X.509. A simple way to detect the new
format is to scan for the 'T'. Note that old versions of gpg
without using the =--fixed-list-mode= option used a "yyyy-mm-tt"
format.
*** Field 7 - Expiration date
Key or UID/UAT expiration date or empty if it does not expire.
*** Field 8 - Certificate S/N, UID hash, trust signature info
Used for serial number in crt records. For UID and UAT records,
this is a hash of the user ID contents used to represent that
exact user ID. For trust signatures, this is the trust depth
seperated by the trust value by a space.
*** Field 9 - Ownertrust
This is only used on primary keys. This is a single letter, but
be prepared that additional information may follow in future
versions. For trust signatures with a regular expression, this is
the regular expression value, quoted as in field 10.
*** Field 10 - User-ID
The value is quoted like a C string to avoid control characters
(the colon is quoted =\x3a=). For a "pub" record this field is
not used on --fixed-list-mode. A UAT record puts the attribute
subpacket count here, a space, and then the total attribute
subpacket size. In gpgsm the issuer name comes here. A FPR
record stores the fingerprint here. The fingerprint of a
revocation key is stored here.
*** Field 11 - Signature class
Signature class as per RFC-4880. This is a 2 digit hexnumber
followed by either the letter 'x' for an exportable signature or
the letter 'l' for a local-only signature. The class byte of an
revocation key is also given here, 'x' and 'l' is used the same
way. This field if not used for X.509.
*** Field 12 - Key capabilities
The defined capabilities are:
- e :: Encrypt
- s :: Sign
- c :: Certify
- a :: Authentication
- ? :: Unknown capability
A key may have any combination of them in any order. In addition
to these letters, the primary key has uppercase versions of the
letters to denote the _usable_ capabilities of the entire key, and
a potential letter 'D' to indicate a disabled key.
*** Field 13 - Issuer certificate fingerprint or other info
Used in FPR records for S/MIME keys to store the fingerprint of
the issuer certificate. This is useful to build the certificate
path based on certificates stored in the local key database it is
only filled if the issuer certificate is available. The root has
been reached if this is the same string as the fingerprint. The
advantage of using this value is that it is guaranteed to have
been been build by the same lookup algorithm as gpgsm uses.
For "uid" records this field lists the preferences in the same way
gpg's --edit-key menu does.
For "sig" records, this is the fingerprint of the key that issued
the signature. Note that this is only filled in if the signature
verified correctly. Note also that for various technical reasons,
this fingerprint is only available if --no-sig-cache is used.
*** Field 14 - Flag field
Flag field used in the --edit menu output
*** Field 15 - S/N of a token
Used in sec/ssb to print the serial number of a token (internal
protect mode 1002) or a '#' if that key is a simple stub (internal
protect mode 1001). If the option --with-secret is used and a
secret key is available for the public key, a '+' indicates this.
*** Field 16 - Hash algorithm
For sig records, this is the used hash algorithm. For example:
2 = SHA-1, 8 = SHA-256.
*** Field 17 - Curve name
For pub, sub, sec, and ssb records this field is used for the ECC
curve name.
*** Field 18 - TOFU Policy
This is the TOFU policy. It is either good, bad, unknown, ask or
auto. This is only shows for uid records.
** Special fields
*** PKD - Public key data
If field 1 has the tag "pkd", a listing looks like this:
#+begin_example
pkd:0:1024:B665B1435F4C2 .... FF26ABB:
! ! !-- the value
! !------ for information number of bits in the value
!--------- index (eg. DSA goes from 0 to 3: p,q,g,y)
#+end_example
*** TRU - Trust database information
Example for a "tru" trust base record:
#+begin_example
tru:o:0:1166697654:1:3:1:5
#+end_example
- Field 2 :: Reason for staleness of trust. If this field is
empty, then the trustdb is not stale. This field may
have multiple flags in it:
- o :: Trustdb is old
- t :: Trustdb was built with a different trust model
than the one we are using now.
- Field 3 :: Trust model
- 0 :: Classic trust model, as used in PGP 2.x.
- 1 :: PGP trust model, as used in PGP 6 and later.
This is the same as the classic trust model,
except for the addition of trust signatures.
GnuPG before version 1.4 used the classic trust model
by default. GnuPG 1.4 and later uses the PGP trust
model by default.
- Field 4 :: Date trustdb was created in seconds since Epoch.
- Field 5 :: Date trustdb will expire in seconds since Epoch.
- Field 6 :: Number of marginally trusted users to introduce a new
key signer (gpg's option --marginals-needed).
- Field 7 :: Number of completely trusted users to introduce a new
key signer. (gpg's option --completes-needed)
- Field 8 :: Maximum depth of a certification chain. (gpg's option
--max-cert-depth)
*** SPK - Signature subpacket records
- Field 2 :: Subpacket number as per RFC-4880 and later.
- Field 3 :: Flags in hex. Currently the only two bits assigned
are 1, to indicate that the subpacket came from the
hashed part of the signature, and 2, to indicate the
subpacket was marked critical.
- Field 4 :: Length of the subpacket. Note that this is the
length of the subpacket, and not the length of field
5 below. Due to the need for %-encoding, the length
of field 5 may be up to 3x this value.
- Field 5 :: The subpacket data. Printable ASCII is shown as
ASCII, but other values are rendered as %XX where XX
is the hex value for the byte.
*** CFG - Configuration data
--list-config outputs information about the GnuPG configuration
for the benefit of frontends or other programs that call GnuPG.
There are several list-config items, all colon delimited like the
rest of the --with-colons output. The first field is always "cfg"
to indicate configuration information. The second field is one of
(with examples):
- version :: The third field contains the version of GnuPG.
: cfg:version:1.3.5
- pubkey :: The third field contains the public key algorithms
this version of GnuPG supports, separated by
semicolons. The algorithm numbers are as specified in
RFC-4880. Note that in contrast to the --status-fd
interface these are _not_ the Libgcrypt identifiers.
Using =pubkeyname= prints names instead of numbers.
: cfg:pubkey:1;2;3;16;17
- cipher :: The third field contains the symmetric ciphers this
version of GnuPG supports, separated by semicolons.
The cipher numbers are as specified in RFC-4880.
Using =ciphername= prints names instead of numbers.
: cfg:cipher:2;3;4;7;8;9;10
- digest :: The third field contains the digest (hash) algorithms
this version of GnuPG supports, separated by
semicolons. The digest numbers are as specified in
RFC-4880. Using =digestname= prints names instead of
numbers.
: cfg:digest:1;2;3;8;9;10
- compress :: The third field contains the compression algorithms
this version of GnuPG supports, separated by
semicolons. The algorithm numbers are as specified
in RFC-4880.
: cfg:compress:0;1;2;3
- group :: The third field contains the name of the group, and the
fourth field contains the values that the group expands
to, separated by semicolons.
For example, a group of:
: group mynames = paige 0x12345678 joe patti
would result in:
: cfg:group:mynames:patti;joe;0x12345678;paige
- curve :: The third field contains the curve names this version
of GnuPG supports, separated by semicolons. Using
=curveoid= prints OIDs instead of numbers.
: cfg:curve:ed25519;nistp256;nistp384;nistp521
* Format of the --status-fd output
Every line is prefixed with "[GNUPG:] ", followed by a keyword with
the type of the status line and some arguments depending on the type
(maybe none); an application should always be prepared to see more
arguments in future versions.
** General status codes
*** NEWSIG
Is issued right before a signature verification starts. This is
useful to define a context for parsing ERROR status messages. No
arguments are currently defined.
*** GOODSIG
The signature with the keyid is good. For each signature only one
of the codes GOODSIG, BADSIG, EXPSIG, EXPKEYSIG, REVKEYSIG or
ERRSIG will be emitted. In the past they were used as a marker
for a new signature; new code should use the NEWSIG status
instead. The username is the primary one encoded in UTF-8 and %XX
escaped. The fingerprint may be used instead of the long keyid if
it is available. This is the case with CMS and might eventually
also be available for OpenPGP.
*** EXPSIG
The signature with the keyid is good, but the signature is
expired. The username is the primary one encoded in UTF-8 and %XX
escaped. The fingerprint may be used instead of the long keyid if
it is available. This is the case with CMS and might eventually
also be available for OpenPGP.
*** EXPKEYSIG
The signature with the keyid is good, but the signature was made
by an expired key. The username is the primary one encoded in
UTF-8 and %XX escaped. The fingerprint may be used instead of the
long keyid if it is available. This is the case with CMS and
might eventually also be available for OpenPGP.
*** REVKEYSIG
The signature with the keyid is good, but the signature was made
by a revoked key. The username is the primary one encoded in UTF-8
and %XX escaped. The fingerprint may be used instead of the long
keyid if it is available. This is the case with CMS and might
eventually also beƱ available for OpenPGP.
*** BADSIG
The signature with the keyid has not been verified okay. The
username is the primary one encoded in UTF-8 and %XX escaped. The
fingerprint may be used instead of the long keyid if it is
available. This is the case with CMS and might eventually also be
available for OpenPGP.
*** ERRSIG
It was not possible to check the signature. This may be caused by
a missing public key or an unsupported algorithm. A RC of 4
indicates unknown algorithm, a 9 indicates a missing public
key. The other fields give more information about this signature.
sig_class is a 2 byte hex-value. The fingerprint may be used
instead of the keyid if it is available. This is the case with
gpgsm and might eventually also be available for OpenPGP.
Note, that TIME may either be the number of seconds since Epoch or
an ISO 8601 string. The latter can be detected by the presence of
the letter 'T'.
*** VALIDSIG
The args are:
-
-
-
-
-
-
-
-
-
- [ ]
This status indicates that the signature is cryptographically
valid. This is similar to GOODSIG, EXPSIG, EXPKEYSIG, or REVKEYSIG
(depending on the date and the state of the signature and signing
key) but has the fingerprint as the argument. Multiple status
lines (VALIDSIG and the other appropriate *SIG status) are emitted
for a valid signature. All arguments here are on one long line.
sig-timestamp is the signature creation time in seconds after the
epoch. expire-timestamp is the signature expiration time in
seconds after the epoch (zero means "does not
expire"). sig-version, pubkey-algo, hash-algo, and sig-class (a
2-byte hex value) are all straight from the signature packet.
PRIMARY-KEY-FPR is the fingerprint of the primary key or identical
to the first argument. This is useful to get back to the primary
key without running gpg again for this purpose.
The primary-key-fpr parameter is used for OpenPGP and not
available for CMS signatures. The sig-version as well as the sig
class is not defined for CMS and currently set to 0 and 00.
Note, that *-TIMESTAMP may either be a number of seconds since
Epoch or an ISO 8601 string which can be detected by the presence
of the letter 'T'.
*** SIG_ID
This is emitted only for signatures of class 0 or 1 which have
been verified okay. The string is a signature id and may be used
in applications to detect replay attacks of signed messages. Note
that only DLP algorithms give unique ids - others may yield
duplicated ones when they have been created in the same second.
Note, that SIG-TIMESTAMP may either be a number of seconds since
Epoch or an ISO 8601 string which can be detected by the presence
of the letter 'T'.
*** ENC_TO
The message is encrypted to this LONG_KEYID. KEYTYPE is the
numerical value of the public key algorithm or 0 if it is not
known, KEYLENGTH is the length of the key or 0 if it is not known
(which is currently always the case). Gpg prints this line
always; Gpgsm only if it knows the certificate.
*** BEGIN_DECRYPTION
Mark the start of the actual decryption process. This is also
emitted when in --list-only mode.
*** END_DECRYPTION
Mark the end of the actual decryption process. This are also
emitted when in --list-only mode.
*** DECRYPTION_INFO
Print information about the symmetric encryption algorithm and the
MDC method. This will be emitted even if the decryption fails.
*** DECRYPTION_FAILED
The symmetric decryption failed - one reason could be a wrong
passphrase for a symmetrical encrypted message.
*** DECRYPTION_OKAY
The decryption process succeeded. This means, that either the
correct secret key has been used or the correct passphrase for a
symmetric encrypted message was given. The program itself may
return an errorcode because it may not be possible to verify a
signature for some reasons.
*** SESSION_KEY :
The session key used to decrypt the message. This message will
only be emitted if the option --show-session-key is used. The
format is suitable to be passed as value for the option
--override-session-key. It is not an indication that the
decryption will or has succeeded.
*** BEGIN_ENCRYPTION
Mark the start of the actual encryption process.
*** END_ENCRYPTION
Mark the end of the actual encryption process.
*** FILE_START
Start processing a file . indicates the performed
operation:
- 1 :: verify
- 2 :: encrypt
- 3 :: decrypt
*** FILE_DONE
Marks the end of a file processing which has been started
by FILE_START.
*** BEGIN_SIGNING
Mark the start of the actual signing process. This may be used as
an indication that all requested secret keys are ready for use.
*** ALREADY_SIGNED
Warning: This is experimental and might be removed at any time.
*** SIG_CREATED
A signature has been created using these parameters.
Values for type are:
- D :: detached
- C :: cleartext
- S :: standard
(only the first character should be checked)
are 2 hex digits with the OpenPGP signature class.
Note, that TIMESTAMP may either be a number of seconds since Epoch
or an ISO 8601 string which can be detected by the presence of the
letter 'T'.
*** NOTATION_
There are actually two related status codes to convey notation
data:
- NOTATION_NAME
- NOTATION_DATA
and are %XX escaped; the data may be split among
several NOTATION_DATA lines.
*** POLICY_URL
Note that URL in is %XX escaped.
*** PLAINTEXT
This indicates the format of the plaintext that is about to be
written. The format is a 1 byte hex code that shows the format of
the plaintext: 62 ('b') is binary data, 74 ('t') is text data with
no character set specified, and 75 ('u') is text data encoded in
the UTF-8 character set. The timestamp is in seconds since the
epoch. If a filename is available it gets printed as the third
argument, percent-escaped as usual.
*** PLAINTEXT_LENGTH
This indicates the length of the plaintext that is about to be
written. Note that if the plaintext packet has partial length
encoding it is not possible to know the length ahead of time. In
that case, this status tag does not appear.
*** ATTRIBUTE
- The list or argemnts are:
+ The list or arguments are:
-
-
-
-
-
-
-
-
This is one long line issued for each attribute subpacket when an
attribute packet is seen during key listing. is the
fingerprint of the key. is the length of the attribute
subpacket. is the attribute type (e.g. 1 for an image).
and indicate that this is the N-th indexed
subpacket of count total subpackets in this attribute packet.
and are from the self-signature on the
attribute packet. If the attribute packet does not have a valid
self-signature, then the timestamp is 0. are a bitwise OR
of:
- 0x01 :: this attribute packet is a primary uid
- 0x02 :: this attribute packet is revoked
- 0x04 :: this attribute packet is expired
*** SIG_SUBPACKET
This indicates that a signature subpacket was seen. The format is
the same as the "spk" record above.
** Key related
*** INV_RECP, INV_SGNR
The two similar status codes:
- INV_RECP
- INV_SGNR
are issued for each unusable recipient/sender. The reasons codes
currently in use are:
- 0 :: No specific reason given
- 1 :: Not Found
- 2 :: Ambigious specification
- 3 :: Wrong key usage
- 4 :: Key revoked
- 5 :: Key expired
- 6 :: No CRL known
- 7 :: CRL too old
- 8 :: Policy mismatch
- 9 :: Not a secret key
- 10 :: Key not trusted
- 11 :: Missing certificate
- 12 :: Missing issuer certificate
- 13 :: Key disabled
- 14 :: Syntax error in specification
+ If no specific reason was given a previously emitted status code
+ KEY_CONSIDERED may be used to analyzed the problem.
+
Note that for historical reasons the INV_RECP status is also used
for gpgsm's SIGNER command where it relates to signer's of course.
Newer GnuPG versions are using INV_SGNR; applications should
ignore the INV_RECP during the sender's command processing once
they have seen an INV_SGNR. Different codes are used so that they
can be distinguish while doing an encrypt+sign operation.
+
*** NO_RECP
Issued if no recipients are usable.
*** NO_SGNR
Issued if no senders are usable.
+*** KEY_CONSIDERED
+ Issued to explian the lookup of a key. FPR is the hexified
+ fingerprint of the primary key. The bit values for FLAGS are:
+
+ - 1 :: The key has not been selected.
+ - 2 :: All subkeys of the key are expired or have been revoked.
+
*** KEYEXPIRED
The key has expired. expire-timestamp is the expiration time in
seconds since Epoch. This status line is not very useful because
it will also be emitted for expired subkeys even if this subkey is
not used. To check whether a key used to sign a message has
expired, the EXPKEYSIG status line is to be used.
Note, that the TIMESTAMP may either be a number of seconds since
Epoch or an ISO 8601 string which can be detected by the presence
of the letter 'T'.
*** KEYREVOKED
The used key has been revoked by its owner. No arguments yet.
*** NO_PUBKEY
The public key is not available
*** NO_SECKEY
The secret key is not available
*** KEY_CREATED []
A key has been created. Values for are:
- B :: primary and subkey
- P :: primary
- S :: subkey
The fingerprint is one of the primary key for type B and P and the
one of the subkey for S. Handle is an arbitrary non-whitespace
string used to match key parameters from batch key creation run.
*** KEY_NOT_CREATED []
The key from batch run has not been created due to errors.
*** TRUST_
These are several similar status codes:
- TRUST_UNDEFINED
- TRUST_NEVER
- TRUST_MARGINAL [0 []]
- TRUST_FULLY [0 []]
- TRUST_ULTIMATE [0 []]
For good signatures one of these status lines are emitted to
indicate the validity of the key used to create the signature.
The error token values are currently only emitted by gpgsm.
VALIDATION_MODEL describes the algorithm used to check the
validity of the key. The defaults are the standard Web of Trust
model for gpg and the the standard X.509 model for gpgsm. The
defined values are
- pgp :: The standard PGP WoT.
- shell :: The standard X.509 model.
- chain :: The chain model.
- steed :: The STEED model.
- tofu :: The TOFU model
Note that the term =TRUST_= in the status names is used for
historic reasons; we now speak of validity.
*** TOFU_USER
This status identifies the key and the userid for all following
Tofu information. The fingerprint is the fingerprint of the
primary key and the mbox is in general the mailbox part of the
userid encoded in UTF-8 and percent escaped.
*** TOFU_STATS 0 [ [ ]]
Statistics for the current user id.
Values for VALIDITY are:
- 0 :: conflict
- 1 :: key without history
- 2 :: key with too little history
- 3 :: key with enough history for basic trust
- 4 :: key with a lot of history
Values for POLICY are:
- none :: No Policy set
- auto :: Policy is "auto"
- good :: Policy is "good"
- bad :: Policy is "bad"
- ask :: Policy is "ask"
- unknown :: Policy is not known.
TM1 gives the number of seconds since the the first messages was
verified. TM2 gives the number of seconds since the most recent
message was verified.
*** TOFU_STATS_SHORT
Information about the TOFU binding for the signature.
Example: "15 signatures verified. 10 messages encrypted"
*** TOFU_STATS_LONG
Information about the TOFU binding for the signature in verbose
format. The LONG_STRING is percent escaped.
Example: 'Verified 9 messages signed by "Werner Koch
(dist sig)" in the past 3 minutes, 40 seconds. The most
recent message was verified 4 seconds ago.'
*** PKA_TRUST_
This is is one:
- PKA_TRUST_GOOD
- PKA_TRUST_BAD
Depending on the outcome of the PKA check one of the above status
codes is emitted in addition to a =TRUST_*= status.
** Remote control
*** GET_BOOL, GET_LINE, GET_HIDDEN, GOT_IT
These status line are used with --command-fd for interactive
control of the process.
*** USERID_HINT
Give a hint about the user ID for a certain keyID.
*** NEED_PASSPHRASE
Issued whenever a passphrase is needed. KEYTYPE is the numerical
value of the public key algorithm or 0 if this is not applicable,
KEYLENGTH is the length of the key or 0 if it is not known (this
is currently always the case).
*** NEED_PASSPHRASE_SYM
Issued whenever a passphrase for symmetric encryption is needed.
*** NEED_PASSPHRASE_PIN []
Issued whenever a PIN is requested to unlock a card.
*** MISSING_PASSPHRASE
No passphrase was supplied. An application which encounters this
message may want to stop parsing immediately because the next
message will probably be a BAD_PASSPHRASE. However, if the
application is a wrapper around the key edit menu functionality it
might not make sense to stop parsing but simply ignoring the
following BAD_PASSPHRASE.
*** BAD_PASSPHRASE
The supplied passphrase was wrong or not given. In the latter
case you may have seen a MISSING_PASSPHRASE.
*** GOOD_PASSPHRASE
The supplied passphrase was good and the secret key material
is therefore usable.
** Import/Export
*** IMPORT_CHECK
This status is emitted in interactive mode right before
the "import.okay" prompt.
*** IMPORTED
The keyid and name of the signature just imported
*** IMPORT_OK []
The key with the primary key's FINGERPRINT has been imported.
REASON flags are:
- 0 :: Not actually changed
- 1 :: Entirely new key.
- 2 :: New user IDs
- 4 :: New signatures
- 8 :: New subkeys
- 16 :: Contains private key.
The flags may be ORed.
*** IMPORT_PROBLEM []
Issued for each import failure. Reason codes are:
- 0 :: No specific reason given.
- 1 :: Invalid Certificate.
- 2 :: Issuer Certificate missing.
- 3 :: Certificate Chain too long.
- 4 :: Error storing certificate.
*** IMPORT_RES
Final statistics on import process (this is one long line). The
args are a list of unsigned numbers separated by white space:
-
-
-
- always 0 (formerly used for the number of RSA keys)
-
-
-
-
-
-
-
-
-
-
-
*** EXPORTED
The key with has been exported. The fingerprint is
the fingerprint of the primary key even if the primary key has
been replaced by a stub key during secret key export.
*** EXPORT_RES
Final statistics on export process (this is one long line). The
args are a list of unsigned numbers separated by white space:
-
-
-
** Smartcard related
*** CARDCTRL []
This is used to control smartcard operations. Defined values for
WHAT are:
- 1 :: Request insertion of a card. Serialnumber may be given
to request a specific card. Used by gpg 1.4 w/o
scdaemon
- 2 :: Request removal of a card. Used by gpg 1.4 w/o scdaemon.
- 3 :: Card with serialnumber detected
- 4 :: No card available
- 5 :: No card reader available
- 6 :: No card support available
- 7 :: Card is in termination state
*** SC_OP_FAILURE []
An operation on a smartcard definitely failed. Currently there is
no indication of the actual error code, but application should be
prepared to later accept more arguments. Defined values for
are:
- 0 :: unspecified error (identically to a missing CODE)
- 1 :: canceled
- 2 :: bad PIN
*** SC_OP_SUCCESS
A smart card operaion succeeded. This status is only printed for
certain operation and is mostly useful to check whether a PIN
change really worked.
** Miscellaneous status codes
*** NODATA
No data has been found. Codes for WHAT are:
- 1 :: No armored data.
- 2 :: Expected a packet but did not found one.
- 3 :: Invalid packet found, this may indicate a non OpenPGP
message.
- 4 :: Signature expected but not found
You may see more than one of these status lines.
*** UNEXPECTED
Unexpected data has been encountered. Codes for WHAT are:
- 0 :: Not further specified
- 1 :: Corrupted message structure
*** TRUNCATED
The output was truncated to MAXNO items. This status code is
issued for certain external requests.
*** ERROR []
This is a generic error status message, it might be followed by
error location specific data. and
should not contain spaces. The error code is a either a string
commencing with a letter or such a string prefixed with a
numerical error code and an underscore; e.g.: "151011327_EOF".
*** WARNING []
This is a generic warning status message, it might be followed by
error location specific data. and
should not contain spaces. The error code is a either a string
commencing with a letter or such a string prefixed with a
numerical error code and an underscore; e.g.: "151011327_EOF".
*** SUCCESS []
Postive confirmation that an operation succeeded. It is used
similar to ISO-C's EXIT_SUCCESS. is optional but if
given should not contain spaces. Used only with a few commands.
*** FAILURE
This is the counterpart to SUCCESS and used to indicate a program
failure. It is used similar to ISO-C's EXIT_FAILURE but allows to
convey more information, in particular an gpg-error error code.
That numerical error code may optionally have a suffix made of an
underscore and a string with an error symbol like "151011327_EOF".
A dash may be used instead of .
*** BADARMOR
The ASCII armor is corrupted. No arguments yet.
*** DELETE_PROBLEM
Deleting a key failed. Reason codes are:
- 1 :: No such key
- 2 :: Must delete secret key first
- 3 :: Ambigious specification
- 4 :: Key is stored on a smartcard.
*** PROGRESS
Used by the primegen and Public key functions to indicate
progress. is the character displayed with no --status-fd
enabled, with the linefeed replaced by an 'X'. is the
current amount done and is amount to be done; a of
0 indicates that the total amount is not known. The condition
: TOTAL && CUR == TOTAL
may be used to detect the end of an operation.
Well known values for WHAT are:
- pk_dsa :: DSA key generation
- pk_elg :: Elgamal key generation
- primegen :: Prime generation
- need_entropy :: Waiting for new entropy in the RNG
- tick :: Generic tick without any special meaning - useful
for letting clients know that the server is still
working.
- starting_agent :: A gpg-agent was started because it is not
running as a daemon.
- learncard :: Send by the agent and gpgsm while learing
the data of a smartcard.
- card_busy :: A smartcard is still working
*** BACKUP_KEY_CREATED
A backup of a key identified by has been writte to
the file ; is percent-escaped.
*** MOUNTPOINT
is a percent-plus escaped filename describing the
mountpoint for the current operation (e.g. used by "g13 --mount").
This may either be the specified mountpoint or one randomly
choosen by g13.
*** PINENTRY_LAUNCHED
This status line is emitted by gpg to notify a client that a
Pinentry has been launched. is the PID of the Pinentry. It
may be used to display a hint to the user but can't be used to
synchronize with Pinentry. Note that there is also an Assuan
inquiry line with the same name used internally or, if enabled,
send to the client instead of this status line. Such an inquiry
may be used to sync with Pinentry
** Obsolete status codes
*** SIGEXPIRED
Removed on 2011-02-04. This is deprecated in favor of KEYEXPIRED.
*** RSA_OR_IDEA
Obsolete. This status message used to be emitted for requests to
use the IDEA or RSA algorithms. It has been dropped from GnuPG
2.1 after the respective patents expired.
*** SHM_INFO, SHM_GET, SHM_GET_BOOL, SHM_GET_HIDDEN
These were used for the ancient shared memory based co-processing.
*** BEGIN_STREAM, END_STREAM
Used to issued by the experimental pipemode.
* Format of the --attribute-fd output
When --attribute-fd is set, during key listings (--list-keys,
--list-secret-keys) GnuPG dumps each attribute packet to the file
descriptor specified. --attribute-fd is intended for use with
--status-fd as part of the required information is carried on the
ATTRIBUTE status tag (see above).
The contents of the attribute data is specified by RFC 4880. For
convenience, here is the Photo ID format, as it is currently the
only attribute defined:
- Byte 0-1 :: The length of the image header. Due to a historical
accident (i.e. oops!) back in the NAI PGP days, this
is a little-endian number. Currently 16 (0x10 0x00).
- Byte 2 :: The image header version. Currently 0x01.
- Byte 3 :: Encoding format. 0x01 == JPEG.
- Byte 4-15 :: Reserved, and currently unused.
All other data after this header is raw image (JPEG) data.
* Layout of the TrustDB
The TrustDB is built from fixed length records, where the first byte
describes the record type. All numeric values are stored in network
byte order. The length of each record is 40 bytes. The first
record of the DB is always of type 1 and this is the only record of
this type.
The record types: directory(2), key(3), uid(4), pref(5), sigrec(6),
and shadow directory(8) are not anymore used by version 2 of the
TrustDB.
** Record type 0
Unused record or deleted, can be reused for any purpose. Such
records should in general not exist because deleted records are of
type 254 and kept in a linked list.
** Version info (RECTYPE_VER, 1)
Version information for this TrustDB. This is always the first
record of the DB and the only one of this type.
- 1 u8 :: Record type (value: 1).
- 3 byte :: Magic value ("gpg")
- 1 u8 :: TrustDB version (value: 2).
- 1 u8 :: =marginals=. How many marginal trusted keys are required.
- 1 u8 :: =completes=. How many completely trusted keys are
required.
- 1 u8 :: =max_cert_depth=. How deep is the WoT evaluated. Along
with =marginals= and =completes=, this value is used to
check whether the cached validity value from a [FIXME
dir] record can be used.
- 1 u8 :: =trust_model=
- 1 u8 :: =min_cert_level=
- 2 byte :: Not used
- 1 u32 :: =created=. Timestamp of trustdb creation.
- 1 u32 :: =nextcheck=. Timestamp of last modification which may
affect the validity of keys in the trustdb. This value
is checked against the validity timestamp in the dir
records.
- 1 u32 :: =reserved=. Not used.
- 1 u32 :: =reserved2=. Not used.
- 1 u32 :: =firstfree=. Number of the record with the head record
of the RECTYPE_FREE linked list.
- 1 u32 :: =reserved3=. Not used.
- 1 u32 :: =trusthashtbl=. Record number of the trusthashtable.
** Hash table (RECTYPE_HTBL, 10)
Due to the fact that we use fingerprints to lookup keys, we can
implement quick access by some simple hash methods, and avoid the
overhead of gdbm. A property of fingerprints is that they can be
used directly as hash values. What we use is a dynamic multilevel
architecture, which combines hash tables, record lists, and linked
lists.
This record is a hash table of 256 entries with the property that
all these records are stored consecutively to make one big
table. The hash value is simple the 1st, 2nd, ... byte of the
fingerprint (depending on the indirection level).
- 1 u8 :: Record type (value: 10).
- 1 u8 :: Reserved
- n u32 :: =recnum=. A table with the hash table items fitting into
this record. =n= depends on the record length:
$n=(reclen-2)/4$ which yields 9 for oure current record
length of 40 bytes.
The total number of hash table records to form the table is:
$m=(256+n-1)/n$. This is 29 for our record length of 40.
To look up a key we use the first byte of the fingerprint to get
the recnum from this hash table and then look up the addressed
record:
- If that record is another hash table, we use 2nd byte to index
that hash table and so on;
- if that record is a hash list, we walk all entries until we find
a matching one; or
- if that record is a key record, we compare the fingerprint to
decide whether it is the requested key;
** Hash list (RECTYPE_HLST, 11)
See hash table above on how it is used. It may also be used for
other purposes.
- 1 u8 :: Record type (value: 11).
- 1 u8 :: Reserved.
- 1 u32 :: =next=. Record number of the next hash list record or 0
if none.
- n u32 :: =rnum=. Array with record numbers to values. With
$n=(reclen-5)/5$ and our record length of 40, n is 7.
** Trust record (RECTYPE_TRUST, 12)
- 1 u8 :: Record type (value: 12).
- 1 u8 :: Reserved.
- 20 byte :: =fingerprint=.
- 1 u8 :: =ownertrust=.
- 1 u8 :: =depth=.
- 1 u8 :: =min_ownertrust=.
- 1 byte :: Not used.
- 1 u32 :: =validlist=.
- 10 byte :: Not used.
** Validity record (RECTYPE_VALID, 13)
- 1 u8 :: Record type (value: 13).
- 1 u8 :: Reserved.
- 20 byte :: =namehash=.
- 1 u8 :: =validity=
- 1 u32 :: =next=.
- 1 u8 :: =full_count=.
- 1 u8 :: =marginal_count=.
- 11 byte :: Not used.
** Free record (RECTYPE_FREE, 254)
All these records form a linked list of unused records in the TrustDB.
- 1 u8 :: Record type (value: 254)
- 1 u8 :: Reserved.
- 1 u32 :: =next=. Record number of the next rcord of this type.
The record number to the head of this linked list is
stored in the version info record.
* GNU extensions to the S2K algorithm
1 octet - S2K Usage: either 254 or 255.
1 octet - S2K Cipher Algo: 0
1 octet - S2K Specifier: 101
3 octets - "GNU"
1 octet - GNU S2K Extension Number.
If such a GNU extension is used neither an IV nor any kind of
checksum is used. The defined GNU S2K Extension Numbers are:
- 1 :: Do not store the secret part at all. No specific data
follows.
- 2 :: A stub to access smartcards. This data follows:
- One octet with the length of the following serial number.
- The serial number. Regardless of what the length octet
indicates no more than 16 octets are stored.
Note that gpg stores the GNU S2K Extension Number internally as an
S2K Specifier with an offset of 1000.
* Keyserver helper message format
The keyserver may be contacted by a Unix Domain socket or via TCP.
The format of a request is:
#+begin_example
command-tag
"Content-length:" digits
CRLF
#+end_example
Where command-tag is
#+begin_example
NOOP
GET
PUT
DELETE
#+end_example
The format of a response is:
#+begin_example
"GNUPG/1.0" status-code status-text
"Content-length:" digits
CRLF
#+end_example
followed by bytes of data
Status codes are:
- 1xx :: Informational - Request received, continuing process
- 2xx :: Success - The action was successfully received, understood,
and accepted
- 4xx :: Client Error - The request contains bad syntax or cannot be
fulfilled
- 5xx :: Server Error - The server failed to fulfill an apparently
valid request
* Object identifiers
OIDs below the GnuPG arc:
#+begin_example
1.3.6.1.4.1.11591.2 GnuPG
1.3.6.1.4.1.11591.2.1 notation
1.3.6.1.4.1.11591.2.1.1 pkaAddress
1.3.6.1.4.1.11591.2.2 X.509 extensions
1.3.6.1.4.1.11591.2.2.1 standaloneCertificate
1.3.6.1.4.1.11591.2.2.2 wellKnownPrivateKey
1.3.6.1.4.1.11591.2.12242973 invalid encoded OID
#+end_example
* Miscellaneous notes
** v3 fingerprints
For packet version 3 we calculate the keyids this way:
- RSA :: Low 64 bits of n
- ELGAMAL :: Build a v3 pubkey packet (with CTB 0x99) and
calculate a RMD160 hash value from it. This is used
as the fingerprint and the low 64 bits are the keyid.
** Simplified revocation certificates
Revocation certificates consist only of the signature packet;
"--import" knows how to handle this. The rationale behind it is to
keep them small.
** Documentation on HKP (the http keyserver protocol):
A minimalistic HTTP server on port 11371 recognizes a GET for
/pks/lookup. The standard http URL encoded query parameters are
this (always key=value):
- op=index (like pgp -kv), op=vindex (like pgp -kvv) and op=get (like
pgp -kxa)
- search=. This is a list of words that must occur in the key.
The words are delimited with space, points, @ and so on. The delimiters
are not searched for and the order of the words doesn't matter (but see
next option).
- exact=on. This switch tells the hkp server to only report exact matching
keys back. In this case the order and the "delimiters" are important.
- fingerprint=on. Also reports the fingerprints when used with 'index' or
'vindex'
The keyserver also recognizes http-POSTs to /pks/add. Use this to upload
keys.
A better way to do this would be a request like:
/pks/lookup/?op=
This can be implemented using Hurd's translator mechanism.
However, I think the whole key server stuff has to be re-thought;
I have some ideas and probably create a white paper.
** Algorithm names for the "keygen.algo" prompt
When using a --command-fd controlled key generation or "addkey"
there is way to know the number to enter on the "keygen.algo"
prompt. The displayed numbers are for human reception and may
change with releases. To provide a stable way to enter a desired
algorithm choice the prompt also accepts predefined names for the
algorithms, which will not change.
| Name | No | Description |
|---------+----+---------------------------------|
| rsa+rsa | 1 | RSA and RSA (default) |
| dsa+elg | 2 | DSA and Elgamal |
| dsa | 3 | DSA (sign only) |
| rsa/s | 4 | RSA (sign only) |
| elg | 5 | Elgamal (encrypt only) |
| rsa/e | 6 | RSA (encrypt only) |
| dsa/* | 7 | DSA (set your own capabilities) |
| rsa/* | 8 | RSA (set your own capabilities) |
| ecc+ecc | 9 | ECC and ECC |
| ecc/s | 10 | ECC (sign only) |
| ecc/* | 11 | ECC (set your own capabilities) |
| ecc/e | 12 | ECC (encrypt only) |
| keygrip | 13 | Existing key |
If one of the "foo/*" names are used a "keygen.flags" prompt needs
to be answered as well. Instead of toggling the predefined flags,
it is also possible to set them direct: Use a "=" character
directly followed by a comination of "a" (for authentication), "s"
(for signing), or "c" (for certification).
diff --git a/g10/getkey.c b/g10/getkey.c
index 907007b3e..ad0148e51 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -1,3874 +1,3930 @@
/* getkey.c - Get a key from the database
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
* 2007, 2008, 2010 Free Software Foundation, Inc.
* Copyright (C) 2015 g10 Code GmbH
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see .
*/
#include
#include
#include
#include
#include
#include "gpg.h"
#include "util.h"
#include "packet.h"
#include "iobuf.h"
#include "keydb.h"
#include "options.h"
#include "main.h"
#include "trustdb.h"
#include "i18n.h"
#include "keyserver-internal.h"
#include "call-agent.h"
#include "host2net.h"
#include "mbox-util.h"
+#include "status.h"
#define MAX_PK_CACHE_ENTRIES PK_UID_CACHE_SIZE
#define MAX_UID_CACHE_ENTRIES PK_UID_CACHE_SIZE
#if MAX_PK_CACHE_ENTRIES < 2
#error We need the cache for key creation
#endif
+/* Flags values returned by the lookup code. Note that the values are
+ * directly used by the KEY_CONSIDERED status line. */
+#define LOOKUP_NOT_SELECTED (1<<0)
+#define LOOKUP_ALL_SUBKEYS_EXPIRED (1<<1) /* or revoked */
+
+
+/* A context object used by the lookup functions. */
struct getkey_ctx_s
{
/* Part of the search criteria: whether the search is an exact
search or not. A search that is exact requires that a key or
subkey meet all of the specified criteria. A search that is not
exact allows selecting a different key or subkey from the
keyblock that matched the critera. Further, an exact search
returns the key or subkey that matched whereas a non-exact search
typically returns the primary key. See finish_lookup for
details. */
int exact;
/* Part of the search criteria: Whether the caller only wants keys
with an available secret key. This is used by getkey_next to get
the next result with the same initial criteria. */
int want_secret;
/* Part of the search criteria: The type of the requested key. A
mask of PUBKEY_USAGE_SIG, PUBKEY_USAGE_ENC and PUBKEY_USAGE_CERT.
If non-zero, then for a key to match, it must implement one of
the required uses. */
int req_usage;
/* The database handle. */
KEYDB_HANDLE kr_handle;
/* Whether we should call xfree() on the context when the context is
released using getkey_end()). */
int not_allocated;
/* This variable is used as backing store for strings which have
their address used in ITEMS. */
strlist_t extra_list;
/* Part of the search criteria: The low-level search specification
as passed to keydb_search. */
int nitems;
/* This must be the last element in the structure. When we allocate
the structure, we allocate it so that ITEMS can hold NITEMS. */
KEYDB_SEARCH_DESC items[1];
};
#if 0
static struct
{
int any;
int okay_count;
int nokey_count;
int error_count;
} lkup_stats[21];
#endif
typedef struct keyid_list
{
struct keyid_list *next;
char fpr[MAX_FINGERPRINT_LEN];
u32 keyid[2];
} *keyid_list_t;
#if MAX_PK_CACHE_ENTRIES
typedef struct pk_cache_entry
{
struct pk_cache_entry *next;
u32 keyid[2];
PKT_public_key *pk;
} *pk_cache_entry_t;
static pk_cache_entry_t pk_cache;
static int pk_cache_entries; /* Number of entries in pk cache. */
static int pk_cache_disabled;
#endif
#if MAX_UID_CACHE_ENTRIES < 5
#error we really need the userid cache
#endif
typedef struct user_id_db
{
struct user_id_db *next;
keyid_list_t keyids;
int len;
char name[1];
} *user_id_db_t;
static user_id_db_t user_id_db;
static int uid_cache_entries; /* Number of entries in uid cache. */
static void merge_selfsigs (kbnode_t keyblock);
static int lookup (getkey_ctx_t ctx,
kbnode_t *ret_keyblock, kbnode_t *ret_found_key,
int want_secret);
#if 0
static void
print_stats ()
{
int i;
for (i = 0; i < DIM (lkup_stats); i++)
{
if (lkup_stats[i].any)
es_fprintf (es_stderr,
"lookup stats: mode=%-2d ok=%-6d nokey=%-6d err=%-6d\n",
i,
lkup_stats[i].okay_count,
lkup_stats[i].nokey_count, lkup_stats[i].error_count);
}
}
#endif
/* Cache a copy of a public key in the public key cache. PK is not
* cached if caching is disabled (via getkey_disable_caches), if
* PK->FLAGS.DONT_CACHE is set, we don't know how to derive a key id
* from the public key (e.g., unsupported algorithm), or a key with
* the key id is already in the cache.
*
* The public key packet is copied into the cache using
* copy_public_key. Thus, any secret parts are not copied, for
* instance.
*
* This cache is filled by get_pubkey and is read by get_pubkey and
* get_pubkey_fast. */
void
cache_public_key (PKT_public_key * pk)
{
#if MAX_PK_CACHE_ENTRIES
pk_cache_entry_t ce, ce2;
u32 keyid[2];
if (pk_cache_disabled)
return;
if (pk->flags.dont_cache)
return;
if (is_ELGAMAL (pk->pubkey_algo)
|| pk->pubkey_algo == PUBKEY_ALGO_DSA
|| pk->pubkey_algo == PUBKEY_ALGO_ECDSA
|| pk->pubkey_algo == PUBKEY_ALGO_EDDSA
|| pk->pubkey_algo == PUBKEY_ALGO_ECDH
|| is_RSA (pk->pubkey_algo))
{
keyid_from_pk (pk, keyid);
}
else
return; /* Don't know how to get the keyid. */
for (ce = pk_cache; ce; ce = ce->next)
if (ce->keyid[0] == keyid[0] && ce->keyid[1] == keyid[1])
{
if (DBG_CACHE)
log_debug ("cache_public_key: already in cache\n");
return;
}
if (pk_cache_entries >= MAX_PK_CACHE_ENTRIES)
{
int n;
/* Remove the last 50% of the entries. */
for (ce = pk_cache, n = 0; ce && n < pk_cache_entries/2; n++)
ce = ce->next;
if (ce && ce != pk_cache && ce->next)
{
ce2 = ce->next;
ce->next = NULL;
ce = ce2;
for (; ce; ce = ce2)
{
ce2 = ce->next;
free_public_key (ce->pk);
xfree (ce);
pk_cache_entries--;
}
}
log_assert (pk_cache_entries < MAX_PK_CACHE_ENTRIES);
}
pk_cache_entries++;
ce = xmalloc (sizeof *ce);
ce->next = pk_cache;
pk_cache = ce;
ce->pk = copy_public_key (NULL, pk);
ce->keyid[0] = keyid[0];
ce->keyid[1] = keyid[1];
#endif
}
/* Return a const utf-8 string with the text "[User ID not found]".
This function is required so that we don't need to switch gettext's
encoding temporary. */
static const char *
user_id_not_found_utf8 (void)
{
static char *text;
if (!text)
text = native_to_utf8 (_("[User ID not found]"));
return text;
}
/* Return the user ID from the given keyblock.
* We use the primary uid flag which has been set by the merge_selfsigs
* function. The returned value is only valid as long as the given
* keyblock is not changed. */
static const char *
get_primary_uid (KBNODE keyblock, size_t * uidlen)
{
KBNODE k;
const char *s;
for (k = keyblock; k; k = k->next)
{
if (k->pkt->pkttype == PKT_USER_ID
&& !k->pkt->pkt.user_id->attrib_data
&& k->pkt->pkt.user_id->is_primary)
{
*uidlen = k->pkt->pkt.user_id->len;
return k->pkt->pkt.user_id->name;
}
}
s = user_id_not_found_utf8 ();
*uidlen = strlen (s);
return s;
}
static void
release_keyid_list (keyid_list_t k)
{
while (k)
{
keyid_list_t k2 = k->next;
xfree (k);
k = k2;
}
}
/****************
* Store the association of keyid and userid
* Feed only public keys to this function.
*/
static void
cache_user_id (KBNODE keyblock)
{
user_id_db_t r;
const char *uid;
size_t uidlen;
keyid_list_t keyids = NULL;
KBNODE k;
for (k = keyblock; k; k = k->next)
{
if (k->pkt->pkttype == PKT_PUBLIC_KEY
|| k->pkt->pkttype == PKT_PUBLIC_SUBKEY)
{
keyid_list_t a = xmalloc_clear (sizeof *a);
/* Hmmm: For a long list of keyids it might be an advantage
* to append the keys. */
fingerprint_from_pk (k->pkt->pkt.public_key, a->fpr, NULL);
keyid_from_pk (k->pkt->pkt.public_key, a->keyid);
/* First check for duplicates. */
for (r = user_id_db; r; r = r->next)
{
keyid_list_t b;
for (b = r->keyids; b; b = b->next)
{
if (!memcmp (b->fpr, a->fpr, MAX_FINGERPRINT_LEN))
{
if (DBG_CACHE)
log_debug ("cache_user_id: already in cache\n");
release_keyid_list (keyids);
xfree (a);
return;
}
}
}
/* Now put it into the cache. */
a->next = keyids;
keyids = a;
}
}
if (!keyids)
BUG (); /* No key no fun. */
uid = get_primary_uid (keyblock, &uidlen);
if (uid_cache_entries >= MAX_UID_CACHE_ENTRIES)
{
/* fixme: use another algorithm to free some cache slots */
r = user_id_db;
user_id_db = r->next;
release_keyid_list (r->keyids);
xfree (r);
uid_cache_entries--;
}
r = xmalloc (sizeof *r + uidlen - 1);
r->keyids = keyids;
r->len = uidlen;
memcpy (r->name, uid, r->len);
r->next = user_id_db;
user_id_db = r;
uid_cache_entries++;
}
/* Disable and drop the public key cache (which is filled by
cache_public_key and get_pubkey). Note: there is currently no way
to reenable this cache. */
void
getkey_disable_caches ()
{
#if MAX_PK_CACHE_ENTRIES
{
pk_cache_entry_t ce, ce2;
for (ce = pk_cache; ce; ce = ce2)
{
ce2 = ce->next;
free_public_key (ce->pk);
xfree (ce);
}
pk_cache_disabled = 1;
pk_cache_entries = 0;
pk_cache = NULL;
}
#endif
/* fixme: disable user id cache ? */
}
void
pubkey_free (pubkey_t key)
{
if (key)
{
xfree (key->pk);
release_kbnode (key->keyblock);
xfree (key);
}
}
void
pubkeys_free (pubkey_t keys)
{
while (keys)
{
pubkey_t next = keys->next;
pubkey_free (keys);
keys = next;
}
}
/* Returns all keys that match the search specfication SEARCH_TERMS.
This function also checks for and warns about duplicate entries in
the keydb, which can occur if the user has configured multiple
keyrings or keyboxes or if a keyring or keybox was corrupted.
Note: SEARCH_TERMS will not be expanded (i.e., it may not be a
group).
USE is the operation for which the key is required. It must be
either PUBKEY_USAGE_ENC, PUBKEY_USAGE_SIG, PUBKEY_USAGE_CERT or
PUBKEY_USAGE_AUTH.
XXX: Currently, only PUBKEY_USAGE_ENC and PUBKEY_USAGE_SIG are
implemented.
INCLUDE_UNUSABLE indicates whether disabled keys are allowed.
(Recipients specified with --encrypt-to and --hidden-encrypt-to may
be disabled. It is possible to edit disabled keys.)
SOURCE is the context in which SEARCH_TERMS was specified, e.g.,
"--encrypt-to", etc. If this function is called interactively,
then this should be NULL.
If WARN_POSSIBLY_AMBIGUOUS is set, then emits a warning if the user
does not specify a long key id or a fingerprint.
The results are placed in *KEYS. *KEYS must be NULL! */
gpg_error_t
get_pubkeys (ctrl_t ctrl,
char *search_terms, int use, int include_unusable, char *source,
int warn_possibly_ambiguous,
pubkey_t *r_keys)
{
/* We show a warning when a key appears multiple times in the DB.
This can happen for two reasons:
- The user has configured multiple keyrings or keyboxes.
- The keyring or keybox has been corrupted in some way, e.g., a
bug or a random process changing them.
For each duplicate, we only want to show the key once. Hence,
this list. */
static strlist_t key_dups;
/* USE transformed to a string. */
char *use_str;
gpg_error_t err;
KEYDB_SEARCH_DESC desc;
GETKEY_CTX ctx;
pubkey_t results = NULL;
pubkey_t r;
int count;
char fingerprint[2 * MAX_FINGERPRINT_LEN + 1];
if (DBG_LOOKUP)
{
log_debug ("\n");
log_debug ("%s: Checking %s=%s\n",
__func__, source ? source : "user input", search_terms);
}
if (*r_keys)
log_bug ("%s: KEYS should be NULL!\n", __func__);
switch (use)
{
case PUBKEY_USAGE_ENC: use_str = "encrypt"; break;
case PUBKEY_USAGE_SIG: use_str = "sign"; break;
case PUBKEY_USAGE_CERT: use_str = "cetify"; break;
case PUBKEY_USAGE_AUTH: use_str = "authentication"; break;
default: log_bug ("%s: Bad value for USE (%d)\n", __func__, use);
}
if (use == PUBKEY_USAGE_CERT || use == PUBKEY_USAGE_AUTH)
log_bug ("%s: use=%s is unimplemented.\n", __func__, use_str);
err = classify_user_id (search_terms, &desc, 1);
if (err)
{
log_info (_("key \"%s\" not found: %s\n"),
search_terms, gpg_strerror (err));
if (!opt.quiet && source)
log_info (_("(check argument of option '%s')\n"), source);
goto out;
}
if (warn_possibly_ambiguous
&& ! (desc.mode == KEYDB_SEARCH_MODE_LONG_KID
|| desc.mode == KEYDB_SEARCH_MODE_FPR16
|| desc.mode == KEYDB_SEARCH_MODE_FPR20
|| desc.mode == KEYDB_SEARCH_MODE_FPR))
{
log_info (_("Warning: '%s' should be a long key ID or a fingerprint\n"),
search_terms);
if (!opt.quiet && source)
log_info (_("(check argument of option '%s')\n"), source);
}
/* Gather all of the results. */
ctx = NULL;
count = 0;
do
{
PKT_public_key *pk = xmalloc_clear (sizeof *pk);
KBNODE kb;
pk->req_usage = use;
if (! ctx)
err = get_pubkey_byname (ctrl, &ctx, pk, search_terms, &kb, NULL,
include_unusable, 1);
else
err = getkey_next (ctx, pk, &kb);
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
/* No more results. */
{
xfree (pk);
break;
}
else if (err)
/* An error (other than "not found"). */
{
log_error (_("error looking up: %s\n"),
gpg_strerror (err));
xfree (pk);
break;
}
/* Another result! */
count ++;
r = xmalloc_clear (sizeof (*r));
r->pk = pk;
r->keyblock = kb;
r->next = results;
results = r;
}
while (ctx);
getkey_end (ctx);
if (DBG_LOOKUP)
{
log_debug ("%s resulted in %d matches.\n", search_terms, count);
for (r = results; r; r = r->next)
log_debug (" %s\n",
hexfingerprint (r->keyblock->pkt->pkt.public_key,
fingerprint, sizeof (fingerprint)));
}
if (! results && gpg_err_code (err) == GPG_ERR_NOT_FOUND)
/* No match. */
{
if (DBG_LOOKUP)
log_debug ("%s: '%s' not found.\n", __func__, search_terms);
log_info (_("key \"%s\" not found\n"), search_terms);
if (!opt.quiet && source)
log_info (_("(check argument of option '%s')\n"), source);
goto out;
}
else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
/* No more matches. */
;
else if (err)
/* Some other error. An error message was already printed
out. Free RESULTS and continue. */
goto out;
/* Check for duplicates. */
if (DBG_LOOKUP)
log_debug ("%s: Checking results of %s='%s' for dups\n",
__func__, source ? source : "user input", search_terms);
count = 0;
for (r = results; r; r = r->next)
{
pubkey_t *prevp;
pubkey_t next;
pubkey_t r2;
int dups = 0;
prevp = &r->next;
next = r->next;
while ((r2 = next))
{
if (cmp_public_keys (r->keyblock->pkt->pkt.public_key,
r2->keyblock->pkt->pkt.public_key) != 0)
/* Not a dup. */
{
prevp = &r2->next;
next = r2->next;
continue;
}
dups ++;
count ++;
/* Remove R2 from the list. */
*prevp = r2->next;
release_kbnode (r2->keyblock);
next = r2->next;
xfree (r2);
}
if (dups)
{
hexfingerprint (r->keyblock->pkt->pkt.public_key,
fingerprint, sizeof fingerprint);
if (! strlist_find (key_dups, fingerprint))
{
char fingerprint_formatted[MAX_FORMATTED_FINGERPRINT_LEN + 1];
log_info (_("Warning: %s appears in the keyring %d times\n"),
format_hexfingerprint (fingerprint,
fingerprint_formatted,
sizeof fingerprint_formatted),
1 + dups);
add_to_strlist (&key_dups, fingerprint);
}
}
}
if (DBG_LOOKUP && count)
{
log_debug ("After removing %d dups:\n", count);
for (r = results, count = 0; r; r = r->next)
log_debug (" %d: %s\n",
count,
hexfingerprint (r->keyblock->pkt->pkt.public_key,
fingerprint, sizeof fingerprint));
}
out:
if (err)
pubkeys_free (results);
else
*r_keys = results;
return err;
}
static void
pk_from_block (GETKEY_CTX ctx, PKT_public_key * pk, KBNODE keyblock,
KBNODE found_key)
{
KBNODE a = found_key ? found_key : keyblock;
(void) ctx;
log_assert (a->pkt->pkttype == PKT_PUBLIC_KEY
|| a->pkt->pkttype == PKT_PUBLIC_SUBKEY);
copy_public_key (pk, a->pkt->pkt.public_key);
}
/* Return the public key with the key id KEYID and store it at PK.
* The resources in *PK should be released using
* release_public_key_parts(). This function also stores a copy of
* the public key in the user id cache (see cache_public_key).
*
* If PK is NULL, this function just stores the public key in the
* cache and returns the usual return code.
*
* PK->REQ_USAGE (which is a mask of PUBKEY_USAGE_SIG,
* PUBKEY_USAGE_ENC and PUBKEY_USAGE_CERT) is passed through to the
* lookup function. If this is non-zero, only keys with the specified
* usage will be returned. As such, it is essential that
* PK->REQ_USAGE be correctly initialized!
*
* Returns 0 on success, GPG_ERR_NO_PUBKEY if there is no public key
* with the specified key id, or another error code if an error
* occurs.
*
* If the data was not read from the cache, then the self-signed data
* has definitely been merged into the public key using
* merge_selfsigs. */
int
get_pubkey (PKT_public_key * pk, u32 * keyid)
{
int internal = 0;
int rc = 0;
#if MAX_PK_CACHE_ENTRIES
if (pk)
{
/* Try to get it from the cache. We don't do this when pk is
NULL as it does not guarantee that the user IDs are
cached. */
pk_cache_entry_t ce;
for (ce = pk_cache; ce; ce = ce->next)
{
if (ce->keyid[0] == keyid[0] && ce->keyid[1] == keyid[1])
/* XXX: We don't check PK->REQ_USAGE here, but if we don't
read from the cache, we do check it! */
{
copy_public_key (pk, ce->pk);
return 0;
}
}
}
#endif
/* More init stuff. */
if (!pk)
{
pk = xmalloc_clear (sizeof *pk);
internal++;
}
/* Do a lookup. */
{
struct getkey_ctx_s ctx;
KBNODE kb = NULL;
KBNODE found_key = NULL;
memset (&ctx, 0, sizeof ctx);
ctx.exact = 1; /* Use the key ID exactly as given. */
ctx.not_allocated = 1;
ctx.kr_handle = keydb_new ();
if (!ctx.kr_handle)
{
rc = gpg_error_from_syserror ();
goto leave;
}
ctx.nitems = 1;
ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID;
ctx.items[0].u.kid[0] = keyid[0];
ctx.items[0].u.kid[1] = keyid[1];
ctx.req_usage = pk->req_usage;
rc = lookup (&ctx, &kb, &found_key, 0);
if (!rc)
{
pk_from_block (&ctx, pk, kb, found_key);
}
getkey_end (&ctx);
release_kbnode (kb);
}
if (!rc)
goto leave;
rc = GPG_ERR_NO_PUBKEY;
leave:
if (!rc)
cache_public_key (pk);
if (internal)
free_public_key (pk);
return rc;
}
/* Similar to get_pubkey, but it does not take PK->REQ_USAGE into
* account nor does it merge in the self-signed data. This function
* also only considers primary keys. It is intended to be used as a
* quick check of the key to avoid recursion. It should only be used
* in very certain cases. Like get_pubkey and unlike any of the other
* lookup functions, this function also consults the user id cache
* (see cache_public_key).
*
* Return the public key in *PK. The resources in *PK should be
* released using release_public_key_parts(). */
int
get_pubkey_fast (PKT_public_key * pk, u32 * keyid)
{
int rc = 0;
KEYDB_HANDLE hd;
KBNODE keyblock;
u32 pkid[2];
log_assert (pk);
#if MAX_PK_CACHE_ENTRIES
{
/* Try to get it from the cache */
pk_cache_entry_t ce;
for (ce = pk_cache; ce; ce = ce->next)
{
if (ce->keyid[0] == keyid[0] && ce->keyid[1] == keyid[1]
/* Only consider primary keys. */
&& ce->pk->keyid[0] == ce->pk->main_keyid[0]
&& ce->pk->keyid[1] == ce->pk->main_keyid[1])
{
if (pk)
copy_public_key (pk, ce->pk);
return 0;
}
}
}
#endif
hd = keydb_new ();
if (!hd)
return gpg_error_from_syserror ();
rc = keydb_search_kid (hd, keyid);
if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
{
keydb_release (hd);
return GPG_ERR_NO_PUBKEY;
}
rc = keydb_get_keyblock (hd, &keyblock);
keydb_release (hd);
if (rc)
{
log_error ("keydb_get_keyblock failed: %s\n", gpg_strerror (rc));
return GPG_ERR_NO_PUBKEY;
}
log_assert (keyblock && keyblock->pkt
&& keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
/* We return the primary key. If KEYID matched a subkey, then we
return an error. */
keyid_from_pk (keyblock->pkt->pkt.public_key, pkid);
if (keyid[0] == pkid[0] && keyid[1] == pkid[1])
copy_public_key (pk, keyblock->pkt->pkt.public_key);
else
rc = GPG_ERR_NO_PUBKEY;
release_kbnode (keyblock);
/* Not caching key here since it won't have all of the fields
properly set. */
return rc;
}
/* Return the key block for the key with key id KEYID or NULL, if an
* error occurs. Use release_kbnode() to release the key block.
*
* The self-signed data has already been merged into the public key
* using merge_selfsigs. */
kbnode_t
get_pubkeyblock (u32 * keyid)
{
struct getkey_ctx_s ctx;
int rc = 0;
KBNODE keyblock = NULL;
memset (&ctx, 0, sizeof ctx);
/* No need to set exact here because we want the entire block. */
ctx.not_allocated = 1;
ctx.kr_handle = keydb_new ();
if (!ctx.kr_handle)
return NULL;
ctx.nitems = 1;
ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID;
ctx.items[0].u.kid[0] = keyid[0];
ctx.items[0].u.kid[1] = keyid[1];
rc = lookup (&ctx, &keyblock, NULL, 0);
getkey_end (&ctx);
return rc ? NULL : keyblock;
}
/* Return the public key with the key id KEYID iff the secret key is
* available and store it at PK. The resources should be released
* using release_public_key_parts().
*
* Unlike other lookup functions, PK may not be NULL. PK->REQ_USAGE
* is passed through to the lookup function and is a mask of
* PUBKEY_USAGE_SIG, PUBKEY_USAGE_ENC and PUBKEY_USAGE_CERT. Thus, it
* must be valid! If this is non-zero, only keys with the specified
* usage will be returned.
*
* Returns 0 on success. If a public key with the specified key id is
* not found or a secret key is not available for that public key, an
* error code is returned. Note: this function ignores legacy keys.
* An error code is also return if an error occurs.
*
* The self-signed data has already been merged into the public key
* using merge_selfsigs. */
gpg_error_t
get_seckey (PKT_public_key *pk, u32 *keyid)
{
gpg_error_t err;
struct getkey_ctx_s ctx;
kbnode_t keyblock = NULL;
kbnode_t found_key = NULL;
memset (&ctx, 0, sizeof ctx);
ctx.exact = 1; /* Use the key ID exactly as given. */
ctx.not_allocated = 1;
ctx.kr_handle = keydb_new ();
if (!ctx.kr_handle)
return gpg_error_from_syserror ();
ctx.nitems = 1;
ctx.items[0].mode = KEYDB_SEARCH_MODE_LONG_KID;
ctx.items[0].u.kid[0] = keyid[0];
ctx.items[0].u.kid[1] = keyid[1];
ctx.req_usage = pk->req_usage;
err = lookup (&ctx, &keyblock, &found_key, 1);
if (!err)
{
pk_from_block (&ctx, pk, keyblock, found_key);
}
getkey_end (&ctx);
release_kbnode (keyblock);
if (!err)
{
err = agent_probe_secret_key (/*ctrl*/NULL, pk);
if (err)
release_public_key_parts (pk);
}
return err;
}
/* Skip unusable keys. A key is unusable if it is revoked, expired or
disabled or if the selected user id is revoked or expired. */
static int
skip_unusable (void *dummy, u32 * keyid, int uid_no)
{
int unusable = 0;
KBNODE keyblock;
PKT_public_key *pk;
(void) dummy;
keyblock = get_pubkeyblock (keyid);
if (!keyblock)
{
log_error ("error checking usability status of %s\n", keystr (keyid));
goto leave;
}
pk = keyblock->pkt->pkt.public_key;
/* Is the key revoked or expired? */
if (pk->flags.revoked || pk->has_expired)
unusable = 1;
/* Is the user ID in question revoked or expired? */
if (!unusable && uid_no)
{
KBNODE node;
int uids_seen = 0;
for (node = keyblock; node; node = node->next)
{
if (node->pkt->pkttype == PKT_USER_ID)
{
PKT_user_id *user_id = node->pkt->pkt.user_id;
uids_seen ++;
if (uids_seen != uid_no)
continue;
if (user_id->is_revoked || user_id->is_expired)
unusable = 1;
break;
}
}
/* If UID_NO is non-zero, then the keyblock better have at least
that many UIDs. */
log_assert (uids_seen == uid_no);
}
if (!unusable)
unusable = pk_is_disabled (pk);
leave:
release_kbnode (keyblock);
return unusable;
}
/* Search for keys matching some criteria.
If RETCTX is not NULL, then the constructed context is returned in
*RETCTX so that getpubkey_next can be used to get subsequent
results. In this case, getkey_end() must be used to free the
search context. If RETCTX is not NULL, then RET_KDBHD must be
NULL.
If NAMELIST is not NULL, then a search query is constructed using
classify_user_id on each of the strings in the list. (Recall: the
database does an OR of the terms, not an AND.) If NAMELIST is
NULL, then all results are returned.
If PK is not NULL, the public key of the first result is returned
in *PK. Note: PK->REQ_USAGE must be valid!!! If PK->REQ_USAGE is
set, it is used to filter the search results. See the
documentation for finish_lookup to understand exactly how this is
used. Note: The self-signed data has already been merged into the
public key using merge_selfsigs. Free *PK by calling
release_public_key_parts (or, if PK was allocated using xfree, you
can use free_public_key, which calls release_public_key_parts(PK)
and then xfree(PK)).
If WANT_SECRET is set, then only keys with an available secret key
(either locally or via key registered on a smartcard) are returned.
If INCLUDE_UNUSABLE is set, then unusable keys (see the
documentation for skip_unusable for an exact definition) are
skipped unless they are looked up by key id or by fingerprint.
If RET_KB is not NULL, the keyblock is returned in *RET_KB. This
should be freed using release_kbnode().
If RET_KDBHD is not NULL, then the new database handle used to
conduct the search is returned in *RET_KDBHD. This can be used to
get subsequent results using keydb_search_next. Note: in this
case, no advanced filtering is done for subsequent results (e.g.,
WANT_SECRET and PK->REQ_USAGE are not respected).
This function returns 0 on success. Otherwise, an error code is
returned. In particular, GPG_ERR_NO_PUBKEY or GPG_ERR_NO_SECKEY
(if want_secret is set) is returned if the key is not found. */
static int
key_byname (GETKEY_CTX *retctx, strlist_t namelist,
PKT_public_key *pk,
int want_secret, int include_unusable,
KBNODE * ret_kb, KEYDB_HANDLE * ret_kdbhd)
{
int rc = 0;
int n;
strlist_t r;
GETKEY_CTX ctx;
KBNODE help_kb = NULL;
KBNODE found_key = NULL;
if (retctx)
{
/* Reset the returned context in case of error. */
log_assert (!ret_kdbhd); /* Not allowed because the handle is stored
in the context. */
*retctx = NULL;
}
if (ret_kdbhd)
*ret_kdbhd = NULL;
if (!namelist)
/* No search terms: iterate over the whole DB. */
{
ctx = xmalloc_clear (sizeof *ctx);
ctx->nitems = 1;
ctx->items[0].mode = KEYDB_SEARCH_MODE_FIRST;
if (!include_unusable)
ctx->items[0].skipfnc = skip_unusable;
}
else
{
/* Build the search context. */
for (n = 0, r = namelist; r; r = r->next)
n++;
/* CTX has space for a single search term at the end. Thus, we
need to allocate sizeof *CTX plus (n - 1) sizeof
CTX->ITEMS. */
ctx = xmalloc_clear (sizeof *ctx + (n - 1) * sizeof ctx->items);
ctx->nitems = n;
for (n = 0, r = namelist; r; r = r->next, n++)
{
gpg_error_t err;
err = classify_user_id (r->d, &ctx->items[n], 1);
if (ctx->items[n].exact)
ctx->exact = 1;
if (err)
{
xfree (ctx);
return gpg_err_code (err); /* FIXME: remove gpg_err_code. */
}
if (!include_unusable
&& ctx->items[n].mode != KEYDB_SEARCH_MODE_SHORT_KID
&& ctx->items[n].mode != KEYDB_SEARCH_MODE_LONG_KID
&& ctx->items[n].mode != KEYDB_SEARCH_MODE_FPR16
&& ctx->items[n].mode != KEYDB_SEARCH_MODE_FPR20
&& ctx->items[n].mode != KEYDB_SEARCH_MODE_FPR)
ctx->items[n].skipfnc = skip_unusable;
}
}
ctx->want_secret = want_secret;
ctx->kr_handle = keydb_new ();
if (!ctx->kr_handle)
{
rc = gpg_error_from_syserror ();
getkey_end (ctx);
return rc;
}
if (!ret_kb)
ret_kb = &help_kb;
if (pk)
{
ctx->req_usage = pk->req_usage;
}
rc = lookup (ctx, ret_kb, &found_key, want_secret);
if (!rc && pk)
{
pk_from_block (ctx, pk, *ret_kb, found_key);
}
release_kbnode (help_kb);
if (retctx) /* Caller wants the context. */
*retctx = ctx;
else
{
if (ret_kdbhd)
{
*ret_kdbhd = ctx->kr_handle;
ctx->kr_handle = NULL;
}
getkey_end (ctx);
}
return rc;
}
/* Find a public key identified by NAME.
*
* If name appears to be a valid valid RFC822 mailbox (i.e., email
* address) and auto key lookup is enabled (no_akl == 0), then the
* specified auto key lookup methods (--auto-key-lookup) are used to
* import the key into the local keyring. Otherwise, just the local
* keyring is consulted.
*
* If RETCTX is not NULL, then the constructed context is returned in
* *RETCTX so that getpubkey_next can be used to get subsequent
* results. In this case, getkey_end() must be used to free the
* search context. If RETCTX is not NULL, then RET_KDBHD must be
* NULL.
*
* If PK is not NULL, the public key of the first result is returned
* in *PK. Note: PK->REQ_USAGE must be valid!!! PK->REQ_USAGE is
* passed through to the lookup function and is a mask of
* PUBKEY_USAGE_SIG, PUBKEY_USAGE_ENC and PUBKEY_USAGE_CERT. If this
* is non-zero, only keys with the specified usage will be returned.
* Note: The self-signed data has already been merged into the public
* key using merge_selfsigs. Free *PK by calling
* release_public_key_parts (or, if PK was allocated using xfree, you
* can use free_public_key, which calls release_public_key_parts(PK)
* and then xfree(PK)).
*
* NAME is a string, which is turned into a search query using
* classify_user_id.
*
* If RET_KEYBLOCK is not NULL, the keyblock is returned in
* *RET_KEYBLOCK. This should be freed using release_kbnode().
*
* If RET_KDBHD is not NULL, then the new database handle used to
* conduct the search is returned in *RET_KDBHD. This can be used to
* get subsequent results using keydb_search_next or to modify the
* returned record. Note: in this case, no advanced filtering is done
* for subsequent results (e.g., PK->REQ_USAGE is not respected).
* Unlike RETCTX, this is always returned.
*
* If INCLUDE_UNUSABLE is set, then unusable keys (see the
* documentation for skip_unusable for an exact definition) are
* skipped unless they are looked up by key id or by fingerprint.
*
* If NO_AKL is set, then the auto key locate functionality is
* disabled and only the local key ring is considered. Note: the
* local key ring is consulted even if local is not in the
* --auto-key-locate option list!
*
* This function returns 0 on success. Otherwise, an error code is
* returned. In particular, GPG_ERR_NO_PUBKEY or GPG_ERR_NO_SECKEY
* (if want_secret is set) is returned if the key is not found. */
int
get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
const char *name, KBNODE * ret_keyblock,
KEYDB_HANDLE * ret_kdbhd, int include_unusable, int no_akl)
{
int rc;
strlist_t namelist = NULL;
struct akl *akl;
int is_mbox;
int nodefault = 0;
int anylocalfirst = 0;
if (retctx)
*retctx = NULL;
/* Does NAME appear to be a mailbox (mail address)? */
is_mbox = is_valid_mailbox (name);
/* The auto-key-locate feature works as follows: there are a number
of methods to look up keys. By default, the local keyring is
tried first. Then, each method listed in the --auto-key-locate is
tried in the order it appears.
This can be changed as follows:
- if nodefault appears anywhere in the list of options, then
the local keyring is not tried first, or,
- if local appears anywhere in the list of options, then the
local keyring is not tried first, but in the order in which
it was listed in the --auto-key-locate option.
Note: we only save the search context in RETCTX if the local
method is the first method tried (either explicitly or
implicitly). */
if (!no_akl)
/* auto-key-locate is enabled. */
{
/* nodefault is true if "nodefault" or "local" appear. */
for (akl = opt.auto_key_locate; akl; akl = akl->next)
if (akl->type == AKL_NODEFAULT || akl->type == AKL_LOCAL)
{
nodefault = 1;
break;
}
/* anylocalfirst is true if "local" appears before any other
search methods (except "nodefault"). */
for (akl = opt.auto_key_locate; akl; akl = akl->next)
if (akl->type != AKL_NODEFAULT)
{
if (akl->type == AKL_LOCAL)
anylocalfirst = 1;
break;
}
}
if (!nodefault)
/* "nodefault" didn't occur. Thus, "local" is implicitly the
first method to try. */
anylocalfirst = 1;
if (nodefault && is_mbox)
/* Either "nodefault" or "local" (explicitly) appeared in the auto
key locate list and NAME appears to be an email address. Don't
try the local keyring. */
{
rc = GPG_ERR_NO_PUBKEY;
}
else
/* Either "nodefault" and "local" don't appear in the auto key
locate list (in which case we try the local keyring first) or
NAME does not appear to be an email address (in which case we
only try the local keyring). In this case, lookup NAME in the
local keyring. */
{
add_to_strlist (&namelist, name);
rc = key_byname (retctx, namelist, pk, 0,
include_unusable, ret_keyblock, ret_kdbhd);
}
/* If the requested name resembles a valid mailbox and automatic
retrieval has been enabled, we try to import the key. */
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY && !no_akl && is_mbox)
/* NAME wasn't present in the local keyring (or we didn't try the
local keyring). Since the auto key locate feature is enabled
and NAME appears to be an email address, try the auto locate
feature. */
{
for (akl = opt.auto_key_locate; akl; akl = akl->next)
{
unsigned char *fpr = NULL;
size_t fpr_len;
int did_akl_local = 0;
int no_fingerprint = 0;
const char *mechanism = "?";
switch (akl->type)
{
case AKL_NODEFAULT:
/* This is a dummy mechanism. */
mechanism = "None";
rc = GPG_ERR_NO_PUBKEY;
break;
case AKL_LOCAL:
mechanism = "Local";
did_akl_local = 1;
if (retctx)
{
getkey_end (*retctx);
*retctx = NULL;
}
add_to_strlist (&namelist, name);
rc = key_byname (anylocalfirst ? retctx : NULL,
namelist, pk, 0,
include_unusable, ret_keyblock, ret_kdbhd);
break;
case AKL_CERT:
mechanism = "DNS CERT";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_cert (ctrl, name, 0, &fpr, &fpr_len);
glo_ctrl.in_auto_key_retrieve--;
break;
case AKL_PKA:
mechanism = "PKA";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_pka (ctrl, name, &fpr, &fpr_len);
glo_ctrl.in_auto_key_retrieve--;
break;
case AKL_DANE:
mechanism = "DANE";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_cert (ctrl, name, 1, &fpr, &fpr_len);
glo_ctrl.in_auto_key_retrieve--;
break;
case AKL_WKD:
mechanism = "WKD";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_wkd (ctrl, name, &fpr, &fpr_len);
glo_ctrl.in_auto_key_retrieve--;
break;
case AKL_LDAP:
mechanism = "LDAP";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_ldap (ctrl, name, &fpr, &fpr_len);
glo_ctrl.in_auto_key_retrieve--;
break;
case AKL_KEYSERVER:
/* Strictly speaking, we don't need to only use a valid
mailbox for the getname search, but it helps cut down
on the problem of searching for something like "john"
and getting a whole lot of keys back. */
if (keyserver_any_configured (ctrl))
{
mechanism = "keyserver";
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_name (ctrl, name, &fpr, &fpr_len,
opt.keyserver);
glo_ctrl.in_auto_key_retrieve--;
}
else
{
mechanism = "Unconfigured keyserver";
rc = GPG_ERR_NO_PUBKEY;
}
break;
case AKL_SPEC:
{
struct keyserver_spec *keyserver;
mechanism = akl->spec->uri;
keyserver = keyserver_match (akl->spec);
glo_ctrl.in_auto_key_retrieve++;
rc = keyserver_import_name (ctrl,
name, &fpr, &fpr_len, keyserver);
glo_ctrl.in_auto_key_retrieve--;
}
break;
}
/* Use the fingerprint of the key that we actually fetched.
This helps prevent problems where the key that we fetched
doesn't have the same name that we used to fetch it. In
the case of CERT and PKA, this is an actual security
requirement as the URL might point to a key put in by an
attacker. By forcing the use of the fingerprint, we
won't use the attacker's key here. */
if (!rc && fpr)
{
char fpr_string[MAX_FINGERPRINT_LEN * 2 + 1];
log_assert (fpr_len <= MAX_FINGERPRINT_LEN);
free_strlist (namelist);
namelist = NULL;
bin2hex (fpr, fpr_len, fpr_string);
if (opt.verbose)
log_info ("auto-key-locate found fingerprint %s\n",
fpr_string);
add_to_strlist (&namelist, fpr_string);
}
else if (!rc && !fpr && !did_akl_local)
{ /* The acquisition method said no failure occurred, but
it didn't return a fingerprint. That's a failure. */
no_fingerprint = 1;
rc = GPG_ERR_NO_PUBKEY;
}
xfree (fpr);
fpr = NULL;
if (!rc && !did_akl_local)
{ /* There was no error and we didn't do a local lookup.
This means that we imported a key into the local
keyring. Try to read the imported key from the
keyring. */
if (retctx)
{
getkey_end (*retctx);
*retctx = NULL;
}
rc = key_byname (anylocalfirst ? retctx : NULL,
namelist, pk, 0,
include_unusable, ret_keyblock, ret_kdbhd);
}
if (!rc)
{
/* Key found. */
log_info (_("automatically retrieved '%s' via %s\n"),
name, mechanism);
break;
}
if (gpg_err_code (rc) != GPG_ERR_NO_PUBKEY
|| opt.verbose || no_fingerprint)
log_info (_("error retrieving '%s' via %s: %s\n"),
name, mechanism,
no_fingerprint ? _("No fingerprint") : gpg_strerror (rc));
}
}
if (rc && retctx)
{
getkey_end (*retctx);
*retctx = NULL;
}
if (retctx && *retctx)
{
log_assert (!(*retctx)->extra_list);
(*retctx)->extra_list = namelist;
}
else
free_strlist (namelist);
return rc;
}
/* Lookup a key with the specified fingerprint.
*
* If PK is not NULL, the public key of the first result is returned
* in *PK. Note: this function does an exact search and thus the
* returned public key may be a subkey rather than the primary key.
* Note: The self-signed data has already been merged into the public
* key using merge_selfsigs. Free *PK by calling
* release_public_key_parts (or, if PK was allocated using xfree, you
* can use free_public_key, which calls release_public_key_parts(PK)
* and then xfree(PK)).
*
* If PK->REQ_USAGE is set, it is used to filter the search results.
* (Thus, if PK is not NULL, PK->REQ_USAGE must be valid!!!) See the
* documentation for finish_lookup to understand exactly how this is
* used.
*
* If R_KEYBLOCK is not NULL, then the first result's keyblock is
* returned in *R_KEYBLOCK. This should be freed using
* release_kbnode().
*
* FPRINT is a byte array whose contents is the fingerprint to use as
* the search term. FPRINT_LEN specifies the length of the
* fingerprint (in bytes). Currently, only 16 and 20-byte
* fingerprints are supported.
*
* FIXME: We should replace this with the _byname function. This can
* be done by creating a userID conforming to the unified fingerprint
* style. */
int
get_pubkey_byfprint (PKT_public_key *pk, kbnode_t *r_keyblock,
const byte * fprint, size_t fprint_len)
{
int rc;
if (r_keyblock)
*r_keyblock = NULL;
if (fprint_len == 20 || fprint_len == 16)
{
struct getkey_ctx_s ctx;
KBNODE kb = NULL;
KBNODE found_key = NULL;
memset (&ctx, 0, sizeof ctx);
ctx.exact = 1;
ctx.not_allocated = 1;
ctx.kr_handle = keydb_new ();
if (!ctx.kr_handle)
return gpg_error_from_syserror ();
ctx.nitems = 1;
ctx.items[0].mode = fprint_len == 16 ? KEYDB_SEARCH_MODE_FPR16
: KEYDB_SEARCH_MODE_FPR20;
memcpy (ctx.items[0].u.fpr, fprint, fprint_len);
rc = lookup (&ctx, &kb, &found_key, 0);
if (!rc && pk)
pk_from_block (&ctx, pk, kb, found_key);
if (!rc && r_keyblock)
{
*r_keyblock = kb;
kb = NULL;
}
release_kbnode (kb);
getkey_end (&ctx);
}
else
rc = GPG_ERR_GENERAL; /* Oops */
return rc;
}
/* This function is similar to get_pubkey_byfprint, but it doesn't
* merge the self-signed data into the public key and subkeys or into
* the user ids. It also doesn't add the key to the user id cache.
* Further, this function ignores PK->REQ_USAGE.
*
* This function is intended to avoid recursion and, as such, should
* only be used in very specific situations.
*
* Like get_pubkey_byfprint, PK may be NULL. In that case, this
* function effectively just checks for the existence of the key. */
int
get_pubkey_byfprint_fast (PKT_public_key * pk,
const byte * fprint, size_t fprint_len)
{
int rc = 0;
KEYDB_HANDLE hd;
KBNODE keyblock;
byte fprbuf[MAX_FINGERPRINT_LEN];
int i;
for (i = 0; i < MAX_FINGERPRINT_LEN && i < fprint_len; i++)
fprbuf[i] = fprint[i];
while (i < MAX_FINGERPRINT_LEN)
fprbuf[i++] = 0;
hd = keydb_new ();
if (!hd)
return gpg_error_from_syserror ();
rc = keydb_search_fpr (hd, fprbuf);
if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
{
keydb_release (hd);
return GPG_ERR_NO_PUBKEY;
}
rc = keydb_get_keyblock (hd, &keyblock);
keydb_release (hd);
if (rc)
{
log_error ("keydb_get_keyblock failed: %s\n", gpg_strerror (rc));
return GPG_ERR_NO_PUBKEY;
}
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
|| keyblock->pkt->pkttype == PKT_PUBLIC_SUBKEY);
if (pk)
copy_public_key (pk, keyblock->pkt->pkt.public_key);
release_kbnode (keyblock);
/* Not caching key here since it won't have all of the fields
properly set. */
return 0;
}
const char *
parse_def_secret_key (ctrl_t ctrl)
{
KEYDB_HANDLE hd = NULL;
strlist_t t;
static int warned;
for (t = opt.def_secret_key; t; t = t->next)
{
gpg_error_t err;
KEYDB_SEARCH_DESC desc;
KBNODE kb;
KBNODE node;
err = classify_user_id (t->d, &desc, 1);
if (err)
{
log_error (_("secret key \"%s\" not found: %s\n"),
t->d, gpg_strerror (err));
if (!opt.quiet)
log_info (_("(check argument of option '%s')\n"), "--default-key");
continue;
}
if (! hd)
{
hd = keydb_new ();
if (!hd)
return NULL;
}
else
keydb_search_reset (hd);
err = keydb_search (hd, &desc, 1, NULL);
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
continue;
if (err)
{
log_error (_("key \"%s\" not found: %s\n"), t->d, gpg_strerror (err));
t = NULL;
break;
}
err = keydb_get_keyblock (hd, &kb);
if (err)
{
log_error (_("error reading keyblock: %s\n"),
gpg_strerror (err));
continue;
}
merge_selfsigs (kb);
err = gpg_error (GPG_ERR_NO_SECKEY);
node = kb;
do
{
PKT_public_key *pk = node->pkt->pkt.public_key;
/* Check that the key has the signing capability. */
if (! (pk->pubkey_usage & PUBKEY_USAGE_SIG))
continue;
/* Check if the key is valid. */
if (pk->flags.revoked)
{
if (DBG_LOOKUP)
log_debug ("not using %s as default key, %s",
keystr_from_pk (pk), "revoked");
continue;
}
if (pk->has_expired)
{
if (DBG_LOOKUP)
log_debug ("not using %s as default key, %s",
keystr_from_pk (pk), "expired");
continue;
}
if (pk_is_disabled (pk))
{
if (DBG_LOOKUP)
log_debug ("not using %s as default key, %s",
keystr_from_pk (pk), "disabled");
continue;
}
err = agent_probe_secret_key (ctrl, pk);
if (! err)
/* This is a valid key. */
break;
}
while ((node = find_next_kbnode (node, PKT_PUBLIC_SUBKEY)));
release_kbnode (kb);
if (err)
{
if (! warned && ! opt.quiet)
{
log_info (_("Warning: not using '%s' as default key: %s\n"),
t->d, gpg_strerror (GPG_ERR_NO_SECKEY));
print_reported_error (err, GPG_ERR_NO_SECKEY);
}
}
else
{
if (! warned && ! opt.quiet)
log_info (_("using \"%s\" as default secret key for signing\n"),
t->d);
break;
}
}
if (! warned && opt.def_secret_key && ! t)
log_info (_("all values passed to '%s' ignored\n"),
"--default-key");
warned = 1;
if (hd)
keydb_release (hd);
if (t)
return t->d;
return NULL;
}
/* Look up a secret key.
*
* If PK is not NULL, the public key of the first result is returned
* in *PK. Note: PK->REQ_USAGE must be valid!!! If PK->REQ_USAGE is
* set, it is used to filter the search results. See the
* documentation for finish_lookup to understand exactly how this is
* used. Note: The self-signed data has already been merged into the
* public key using merge_selfsigs. Free *PK by calling
* release_public_key_parts (or, if PK was allocated using xfree, you
* can use free_public_key, which calls release_public_key_parts(PK)
* and then xfree(PK)).
*
* If --default-key was set, then the specified key is looked up. (In
* this case, the default key is returned even if it is considered
* unusable. See the documentation for skip_unusable for exactly what
* this means.)
*
* Otherwise, this initiates a DB scan that returns all keys that are
* usable (see previous paragraph for exactly what usable means) and
* for which a secret key is available.
*
* This function returns the first match. Additional results can be
* returned using getkey_next. */
gpg_error_t
get_seckey_default (ctrl_t ctrl, PKT_public_key *pk)
{
gpg_error_t err;
strlist_t namelist = NULL;
int include_unusable = 1;
const char *def_secret_key = parse_def_secret_key (ctrl);
if (def_secret_key)
add_to_strlist (&namelist, def_secret_key);
else
include_unusable = 0;
err = key_byname (NULL, namelist, pk, 1, include_unusable, NULL, NULL);
free_strlist (namelist);
return err;
}
/* Search for keys matching some criteria.
*
* If RETCTX is not NULL, then the constructed context is returned in
* *RETCTX so that getpubkey_next can be used to get subsequent
* results. In this case, getkey_end() must be used to free the
* search context. If RETCTX is not NULL, then RET_KDBHD must be
* NULL.
*
* If PK is not NULL, the public key of the first result is returned
* in *PK. Note: PK->REQ_USAGE must be valid!!! If PK->REQ_USAGE is
* set, it is used to filter the search results. See the
* documentation for finish_lookup to understand exactly how this is
* used. Note: The self-signed data has already been merged into the
* public key using merge_selfsigs. Free *PK by calling
* release_public_key_parts (or, if PK was allocated using xfree, you
* can use free_public_key, which calls release_public_key_parts(PK)
* and then xfree(PK)).
*
* If NAMES is not NULL, then a search query is constructed using
* classify_user_id on each of the strings in the list. (Recall: the
* database does an OR of the terms, not an AND.) If NAMES is
* NULL, then all results are returned.
*
* If WANT_SECRET is set, then only keys with an available secret key
* (either locally or via key registered on a smartcard) are returned.
*
* This function does not skip unusable keys (see the documentation
* for skip_unusable for an exact definition).
*
* If RET_KEYBLOCK is not NULL, the keyblock is returned in
* *RET_KEYBLOCK. This should be freed using release_kbnode().
*
* This function returns 0 on success. Otherwise, an error code is
* returned. In particular, GPG_ERR_NO_PUBKEY or GPG_ERR_NO_SECKEY
* (if want_secret is set) is returned if the key is not found. */
gpg_error_t
getkey_bynames (getkey_ctx_t *retctx, PKT_public_key *pk,
strlist_t names, int want_secret, kbnode_t *ret_keyblock)
{
return key_byname (retctx, names, pk, want_secret, 1,
ret_keyblock, NULL);
}
/* Search for one key matching some criteria.
*
* If RETCTX is not NULL, then the constructed context is returned in
* *RETCTX so that getpubkey_next can be used to get subsequent
* results. In this case, getkey_end() must be used to free the
* search context. If RETCTX is not NULL, then RET_KDBHD must be
* NULL.
*
* If PK is not NULL, the public key of the first result is returned
* in *PK. Note: PK->REQ_USAGE must be valid!!! If PK->REQ_USAGE is
* set, it is used to filter the search results. See the
* documentation for finish_lookup to understand exactly how this is
* used. Note: The self-signed data has already been merged into the
* public key using merge_selfsigs. Free *PK by calling
* release_public_key_parts (or, if PK was allocated using xfree, you
* can use free_public_key, which calls release_public_key_parts(PK)
* and then xfree(PK)).
*
* If NAME is not NULL, then a search query is constructed using
* classify_user_id on the string. In this case, even unusable keys
* (see the documentation for skip_unusable for an exact definition of
* unusable) are returned. Otherwise, if --default-key was set, then
* that key is returned (even if it is unusable). If neither of these
* conditions holds, then the first usable key is returned.
*
* If WANT_SECRET is set, then only keys with an available secret key
* (either locally or via key registered on a smartcard) are returned.
*
* This function does not skip unusable keys (see the documentation
* for skip_unusable for an exact definition).
*
* If RET_KEYBLOCK is not NULL, the keyblock is returned in
* *RET_KEYBLOCK. This should be freed using release_kbnode().
*
* This function returns 0 on success. Otherwise, an error code is
* returned. In particular, GPG_ERR_NO_PUBKEY or GPG_ERR_NO_SECKEY
* (if want_secret is set) is returned if the key is not found.
*
* FIXME: We also have the get_pubkey_byname function which has a
* different semantic. Should be merged with this one. */
gpg_error_t
getkey_byname (ctrl_t ctrl, getkey_ctx_t *retctx, PKT_public_key *pk,
const char *name, int want_secret, kbnode_t *ret_keyblock)
{
gpg_error_t err;
strlist_t namelist = NULL;
int with_unusable = 1;
const char *def_secret_key = NULL;
if (want_secret && !name)
def_secret_key = parse_def_secret_key (ctrl);
if (want_secret && !name && def_secret_key)
add_to_strlist (&namelist, def_secret_key);
else if (name)
add_to_strlist (&namelist, name);
else
with_unusable = 0;
err = key_byname (retctx, namelist, pk, want_secret, with_unusable,
ret_keyblock, NULL);
/* FIXME: Check that we really return GPG_ERR_NO_SECKEY if
WANT_SECRET has been used. */
free_strlist (namelist);
return err;
}
/* Return the next search result.
*
* If PK is not NULL, the public key of the next result is returned in
* *PK. Note: The self-signed data has already been merged into the
* public key using merge_selfsigs. Free *PK by calling
* release_public_key_parts (or, if PK was allocated using xfree, you
* can use free_public_key, which calls release_public_key_parts(PK)
* and then xfree(PK)).
*
* RET_KEYBLOCK can be given as NULL; if it is not NULL it the entire
* found keyblock wis retruned hich must be released with
* release_kbnode. If the function returns an error NULL is stored at
* RET_KEYBLOCK.
*
* The self-signed data has already been merged into the public key
* using merge_selfsigs. */
gpg_error_t
getkey_next (getkey_ctx_t ctx, PKT_public_key *pk, kbnode_t *ret_keyblock)
{
int rc; /* Fixme: Make sure this is proper gpg_error */
KBNODE found_key = NULL;
/* We need to disable the caching so that for an exact key search we
won't get the result back from the cache and thus end up in an
endless loop. The endless loop can occur, because the cache is
used without respecting the current file pointer! */
keydb_disable_caching (ctx->kr_handle);
rc = lookup (ctx, ret_keyblock, &found_key, ctx->want_secret);
if (!rc && pk && ret_keyblock)
pk_from_block (ctx, pk, *ret_keyblock, found_key);
return rc;
}
/* Release any resources used by a key listing context. This must be
* called on the context returned by, e.g., getkey_byname. */
void
getkey_end (getkey_ctx_t ctx)
{
if (ctx)
{
keydb_release (ctx->kr_handle);
free_strlist (ctx->extra_list);
if (!ctx->not_allocated)
xfree (ctx);
}
}
/************************************************
************* Merging stuff ********************
************************************************/
/* Set the mainkey_id fields for all keys in KEYBLOCK. This is
* usually done by merge_selfsigs but at some places we only need the
* main_kid not a full merge. The function also guarantees that all
* pk->keyids are computed. */
void
setup_main_keyids (kbnode_t keyblock)
{
u32 kid[2], mainkid[2];
kbnode_t kbctx, node;
PKT_public_key *pk;
if (keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
BUG ();
pk = keyblock->pkt->pkt.public_key;
keyid_from_pk (pk, mainkid);
for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); )
{
if (!(node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY))
continue;
pk = node->pkt->pkt.public_key;
keyid_from_pk (pk, kid); /* Make sure pk->keyid is set. */
if (!pk->main_keyid[0] && !pk->main_keyid[1])
{
pk->main_keyid[0] = mainkid[0];
pk->main_keyid[1] = mainkid[1];
}
}
}
/* KEYBLOCK corresponds to a public key block. This function merges
* much of the information from the self-signed data into the public
* key, public subkey and user id data structures. If you use the
* high-level search API (e.g., get_pubkey) for looking up key blocks,
* then you don't need to call this function. This function is
* useful, however, if you change the keyblock, e.g., by adding or
* removing a self-signed data packet. */
void
merge_keys_and_selfsig (KBNODE keyblock)
{
if (!keyblock)
;
else if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY)
merge_selfsigs (keyblock);
else
log_debug ("FIXME: merging secret key blocks is not anymore available\n");
}
static int
parse_key_usage (PKT_signature * sig)
{
int key_usage = 0;
const byte *p;
size_t n;
byte flags;
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_FLAGS, &n);
if (p && n)
{
/* First octet of the keyflags. */
flags = *p;
if (flags & 1)
{
key_usage |= PUBKEY_USAGE_CERT;
flags &= ~1;
}
if (flags & 2)
{
key_usage |= PUBKEY_USAGE_SIG;
flags &= ~2;
}
/* We do not distinguish between encrypting communications and
encrypting storage. */
if (flags & (0x04 | 0x08))
{
key_usage |= PUBKEY_USAGE_ENC;
flags &= ~(0x04 | 0x08);
}
if (flags & 0x20)
{
key_usage |= PUBKEY_USAGE_AUTH;
flags &= ~0x20;
}
if (flags)
key_usage |= PUBKEY_USAGE_UNKNOWN;
if (!key_usage)
key_usage |= PUBKEY_USAGE_NONE;
}
else if (p) /* Key flags of length zero. */
key_usage |= PUBKEY_USAGE_NONE;
/* We set PUBKEY_USAGE_UNKNOWN to indicate that this key has a
capability that we do not handle. This serves to distinguish
between a zero key usage which we handle as the default
capabilities for that algorithm, and a usage that we do not
handle. Likewise we use PUBKEY_USAGE_NONE to indicate that
key_flags have been given but they do not specify any usage. */
return key_usage;
}
/* Apply information from SIGNODE (which is the valid self-signature
* associated with that UID) to the UIDNODE:
* - weather the UID has been revoked
* - assumed creation date of the UID
* - temporary store the keyflags here
* - temporary store the key expiration time here
* - mark whether the primary user ID flag hat been set.
* - store the preferences
*/
static void
fixup_uidnode (KBNODE uidnode, KBNODE signode, u32 keycreated)
{
PKT_user_id *uid = uidnode->pkt->pkt.user_id;
PKT_signature *sig = signode->pkt->pkt.signature;
const byte *p, *sym, *hash, *zip;
size_t n, nsym, nhash, nzip;
sig->flags.chosen_selfsig = 1;/* We chose this one. */
uid->created = 0; /* Not created == invalid. */
if (IS_UID_REV (sig))
{
uid->is_revoked = 1;
return; /* Has been revoked. */
}
else
uid->is_revoked = 0;
uid->expiredate = sig->expiredate;
if (sig->flags.expired)
{
uid->is_expired = 1;
return; /* Has expired. */
}
else
uid->is_expired = 0;
uid->created = sig->timestamp; /* This one is okay. */
uid->selfsigversion = sig->version;
/* If we got this far, it's not expired :) */
uid->is_expired = 0;
/* Store the key flags in the helper variable for later processing. */
uid->help_key_usage = parse_key_usage (sig);
/* Ditto for the key expiration. */
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
if (p && buf32_to_u32 (p))
uid->help_key_expire = keycreated + buf32_to_u32 (p);
else
uid->help_key_expire = 0;
/* Set the primary user ID flag - we will later wipe out some
* of them to only have one in our keyblock. */
uid->is_primary = 0;
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PRIMARY_UID, NULL);
if (p && *p)
uid->is_primary = 2;
/* We could also query this from the unhashed area if it is not in
* the hased area and then later try to decide which is the better
* there should be no security problem with this.
* For now we only look at the hashed one. */
/* Now build the preferences list. These must come from the
hashed section so nobody can modify the ciphers a key is
willing to accept. */
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_SYM, &n);
sym = p;
nsym = p ? n : 0;
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_HASH, &n);
hash = p;
nhash = p ? n : 0;
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_COMPR, &n);
zip = p;
nzip = p ? n : 0;
if (uid->prefs)
xfree (uid->prefs);
n = nsym + nhash + nzip;
if (!n)
uid->prefs = NULL;
else
{
uid->prefs = xmalloc (sizeof (*uid->prefs) * (n + 1));
n = 0;
for (; nsym; nsym--, n++)
{
uid->prefs[n].type = PREFTYPE_SYM;
uid->prefs[n].value = *sym++;
}
for (; nhash; nhash--, n++)
{
uid->prefs[n].type = PREFTYPE_HASH;
uid->prefs[n].value = *hash++;
}
for (; nzip; nzip--, n++)
{
uid->prefs[n].type = PREFTYPE_ZIP;
uid->prefs[n].value = *zip++;
}
uid->prefs[n].type = PREFTYPE_NONE; /* End of list marker */
uid->prefs[n].value = 0;
}
/* See whether we have the MDC feature. */
uid->flags.mdc = 0;
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n);
if (p && n && (p[0] & 0x01))
uid->flags.mdc = 1;
/* And the keyserver modify flag. */
uid->flags.ks_modify = 1;
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KS_FLAGS, &n);
if (p && n && (p[0] & 0x80))
uid->flags.ks_modify = 0;
}
static void
sig_to_revoke_info (PKT_signature * sig, struct revoke_info *rinfo)
{
rinfo->date = sig->timestamp;
rinfo->algo = sig->pubkey_algo;
rinfo->keyid[0] = sig->keyid[0];
rinfo->keyid[1] = sig->keyid[1];
}
/* Given a keyblock, parse the key block and extract various pieces of
information and save them with the primary key packet and the user
id packets. For instance, some information is stored in signature
packets. We find the latest such valid packet (since the user can
change that information) and copy its contents into the
PKT_public_key.
Note that R_REVOKED may be set to 0, 1 or 2.
This function fills in the following fields in the primary key's
keyblock:
main_keyid (computed)
revkey / numrevkeys (derived from self signed key data)
flags.valid (whether we have at least 1 self-sig)
flags.maybe_revoked (whether a designed revoked the key, but
we are missing the key to check the sig)
selfsigversion (highest version of any valid self-sig)
pubkey_usage (derived from most recent self-sig or most
recent user id)
has_expired (various sources)
expiredate (various sources)
See the documentation for fixup_uidnode for how the user id packets
are modified. In addition to that the primary user id's is_primary
field is set to 1 and the other user id's is_primary are set to
0. */
static void
merge_selfsigs_main (KBNODE keyblock, int *r_revoked,
struct revoke_info *rinfo)
{
PKT_public_key *pk = NULL;
KBNODE k;
u32 kid[2];
u32 sigdate, uiddate, uiddate2;
KBNODE signode, uidnode, uidnode2;
u32 curtime = make_timestamp ();
unsigned int key_usage = 0;
u32 keytimestamp = 0;
u32 key_expire = 0;
int key_expire_seen = 0;
byte sigversion = 0;
*r_revoked = 0;
memset (rinfo, 0, sizeof (*rinfo));
/* Section 11.1 of RFC 4880 determines the order of packets within a
message. There are three sections, which must occur in the
following order: the public key, the user ids and user attributes
and the subkeys. Within each section, each primary packet (e.g.,
a user id packet) is followed by one or more signature packets,
which modify that packet. */
/* According to Section 11.1 of RFC 4880, the public key must be the
first packet. */
if (keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
/* parse_keyblock_image ensures that the first packet is the
public key. */
BUG ();
pk = keyblock->pkt->pkt.public_key;
keytimestamp = pk->timestamp;
keyid_from_pk (pk, kid);
pk->main_keyid[0] = kid[0];
pk->main_keyid[1] = kid[1];
if (pk->version < 4)
{
/* Before v4 the key packet itself contains the expiration date
* and there was no way to change it, so we start with the one
* from the key packet. */
key_expire = pk->max_expiredate;
key_expire_seen = 1;
}
/* First pass:
- Find the latest direct key self-signature. We assume that the
newest one overrides all others.
- Determine whether the key has been revoked.
- Gather all revocation keys (unlike other data, we don't just
take them from the latest self-signed packet).
- Determine max (sig[...]->version).
*/
/* Reset this in case this key was already merged. */
xfree (pk->revkey);
pk->revkey = NULL;
pk->numrevkeys = 0;
signode = NULL;
sigdate = 0; /* Helper variable to find the latest signature. */
/* According to Section 11.1 of RFC 4880, the public key comes first
and is immediately followed by any signature packets that modify
it. */
for (k = keyblock;
k && k->pkt->pkttype != PKT_USER_ID
&& k->pkt->pkttype != PKT_ATTRIBUTE
&& k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
k = k->next)
{
if (k->pkt->pkttype == PKT_SIGNATURE)
{
PKT_signature *sig = k->pkt->pkt.signature;
if (sig->keyid[0] == kid[0] && sig->keyid[1] == kid[1])
/* Self sig. */
{
if (check_key_signature (keyblock, k, NULL))
; /* Signature did not verify. */
else if (IS_KEY_REV (sig))
{
/* Key has been revoked - there is no way to
* override such a revocation, so we theoretically
* can stop now. We should not cope with expiration
* times for revocations here because we have to
* assume that an attacker can generate all kinds of
* signatures. However due to the fact that the key
* has been revoked it does not harm either and by
* continuing we gather some more info on that
* key. */
*r_revoked = 1;
sig_to_revoke_info (sig, rinfo);
}
else if (IS_KEY_SIG (sig))
{
/* Add the indicated revocations keys from all
signatures not just the latest. We do this
because you need multiple 1F sigs to properly
handle revocation keys (PGP does it this way, and
a revocation key could be sensitive and hence in
a different signature). */
if (sig->revkey)
{
int i;
pk->revkey =
xrealloc (pk->revkey, sizeof (struct revocation_key) *
(pk->numrevkeys + sig->numrevkeys));
for (i = 0; i < sig->numrevkeys; i++)
memcpy (&pk->revkey[pk->numrevkeys++],
&sig->revkey[i],
sizeof (struct revocation_key));
}
if (sig->timestamp >= sigdate)
/* This is the latest signature so far. */
{
if (sig->flags.expired)
; /* Signature has expired - ignore it. */
else
{
sigdate = sig->timestamp;
signode = k;
if (sig->version > sigversion)
sigversion = sig->version;
}
}
}
}
}
}
/* Remove dupes from the revocation keys. */
if (pk->revkey)
{
int i, j, x, changed = 0;
for (i = 0; i < pk->numrevkeys; i++)
{
for (j = i + 1; j < pk->numrevkeys; j++)
{
if (memcmp (&pk->revkey[i], &pk->revkey[j],
sizeof (struct revocation_key)) == 0)
{
/* remove j */
for (x = j; x < pk->numrevkeys - 1; x++)
pk->revkey[x] = pk->revkey[x + 1];
pk->numrevkeys--;
j--;
changed = 1;
}
}
}
if (changed)
pk->revkey = xrealloc (pk->revkey,
pk->numrevkeys *
sizeof (struct revocation_key));
}
if (signode)
/* SIGNODE is the 1F signature packet with the latest creation
time. Extract some information from it. */
{
/* Some information from a direct key signature take precedence
* over the same information given in UID sigs. */
PKT_signature *sig = signode->pkt->pkt.signature;
const byte *p;
key_usage = parse_key_usage (sig);
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
if (p && buf32_to_u32 (p))
{
key_expire = keytimestamp + buf32_to_u32 (p);
key_expire_seen = 1;
}
/* Mark that key as valid: One direct key signature should
* render a key as valid. */
pk->flags.valid = 1;
}
/* Pass 1.5: Look for key revocation signatures that were not made
by the key (i.e. did a revocation key issue a revocation for
us?). Only bother to do this if there is a revocation key in the
first place and we're not revoked already. */
if (!*r_revoked && pk->revkey)
for (k = keyblock; k && k->pkt->pkttype != PKT_USER_ID; k = k->next)
{
if (k->pkt->pkttype == PKT_SIGNATURE)
{
PKT_signature *sig = k->pkt->pkt.signature;
if (IS_KEY_REV (sig) &&
(sig->keyid[0] != kid[0] || sig->keyid[1] != kid[1]))
{
int rc = check_revocation_keys (pk, sig);
if (rc == 0)
{
*r_revoked = 2;
sig_to_revoke_info (sig, rinfo);
/* Don't continue checking since we can't be any
more revoked than this. */
break;
}
else if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY)
pk->flags.maybe_revoked = 1;
/* A failure here means the sig did not verify, was
not issued by a revocation key, or a revocation
key loop was broken. If a revocation key isn't
findable, however, the key might be revoked and
we don't know it. */
/* TODO: In the future handle subkey and cert
revocations? PGP doesn't, but it's in 2440. */
}
}
}
/* Second pass: Look at the self-signature of all user IDs. */
/* According to RFC 4880 section 11.1, user id and attribute packets
are in the second section, after the public key packet and before
the subkey packets. */
signode = uidnode = NULL;
sigdate = 0; /* Helper variable to find the latest signature in one UID. */
for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next)
{
if (k->pkt->pkttype == PKT_USER_ID || k->pkt->pkttype == PKT_ATTRIBUTE)
/* New user id packet. */
{
if (uidnode && signode)
/* Apply the data from the most recent self-signed packet
to the preceding user id packet. */
{
fixup_uidnode (uidnode, signode, keytimestamp);
pk->flags.valid = 1;
}
/* Clear SIGNODE. The only relevant self-signed data for
UIDNODE follows it. */
if (k->pkt->pkttype == PKT_USER_ID)
uidnode = k;
else
uidnode = NULL;
signode = NULL;
sigdate = 0;
}
else if (k->pkt->pkttype == PKT_SIGNATURE && uidnode)
{
PKT_signature *sig = k->pkt->pkt.signature;
if (sig->keyid[0] == kid[0] && sig->keyid[1] == kid[1])
{
if (check_key_signature (keyblock, k, NULL))
; /* signature did not verify */
else if ((IS_UID_SIG (sig) || IS_UID_REV (sig))
&& sig->timestamp >= sigdate)
{
/* Note: we allow to invalidate cert revocations
* by a newer signature. An attacker can't use this
* because a key should be revoked with a key revocation.
* The reason why we have to allow for that is that at
* one time an email address may become invalid but later
* the same email address may become valid again (hired,
* fired, hired again). */
sigdate = sig->timestamp;
signode = k;
signode->pkt->pkt.signature->flags.chosen_selfsig = 0;
if (sig->version > sigversion)
sigversion = sig->version;
}
}
}
}
if (uidnode && signode)
{
fixup_uidnode (uidnode, signode, keytimestamp);
pk->flags.valid = 1;
}
/* If the key isn't valid yet, and we have
--allow-non-selfsigned-uid set, then force it valid. */
if (!pk->flags.valid && opt.allow_non_selfsigned_uid)
{
if (opt.verbose)
log_info (_("Invalid key %s made valid by"
" --allow-non-selfsigned-uid\n"), keystr_from_pk (pk));
pk->flags.valid = 1;
}
/* The key STILL isn't valid, so try and find an ultimately
trusted signature. */
if (!pk->flags.valid)
{
uidnode = NULL;
for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
k = k->next)
{
if (k->pkt->pkttype == PKT_USER_ID)
uidnode = k;
else if (k->pkt->pkttype == PKT_SIGNATURE && uidnode)
{
PKT_signature *sig = k->pkt->pkt.signature;
if (sig->keyid[0] != kid[0] || sig->keyid[1] != kid[1])
{
PKT_public_key *ultimate_pk;
ultimate_pk = xmalloc_clear (sizeof (*ultimate_pk));
/* We don't want to use the full get_pubkey to
avoid infinite recursion in certain cases.
There is no reason to check that an ultimately
trusted key is still valid - if it has been
revoked the user should also remove the
ultimate trust flag. */
if (get_pubkey_fast (ultimate_pk, sig->keyid) == 0
&& check_key_signature2 (keyblock, k, ultimate_pk,
NULL, NULL, NULL, NULL) == 0
&& get_ownertrust (ultimate_pk) == TRUST_ULTIMATE)
{
free_public_key (ultimate_pk);
pk->flags.valid = 1;
break;
}
free_public_key (ultimate_pk);
}
}
}
}
/* Record the highest selfsig version so we know if this is a v3
key through and through, or a v3 key with a v4 selfsig
somewhere. This is useful in a few places to know if the key
must be treated as PGP2-style or OpenPGP-style. Note that a
selfsig revocation with a higher version number will also raise
this value. This is okay since such a revocation must be
issued by the user (i.e. it cannot be issued by someone else to
modify the key behavior.) */
pk->selfsigversion = sigversion;
/* Now that we had a look at all user IDs we can now get some information
* from those user IDs.
*/
if (!key_usage)
{
/* Find the latest user ID with key flags set. */
uiddate = 0; /* Helper to find the latest user ID. */
for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
k = k->next)
{
if (k->pkt->pkttype == PKT_USER_ID)
{
PKT_user_id *uid = k->pkt->pkt.user_id;
if (uid->help_key_usage && uid->created > uiddate)
{
key_usage = uid->help_key_usage;
uiddate = uid->created;
}
}
}
}
if (!key_usage)
{
/* No key flags at all: get it from the algo. */
key_usage = openpgp_pk_algo_usage (pk->pubkey_algo);
}
else
{
/* Check that the usage matches the usage as given by the algo. */
int x = openpgp_pk_algo_usage (pk->pubkey_algo);
if (x) /* Mask it down to the actual allowed usage. */
key_usage &= x;
}
/* Whatever happens, it's a primary key, so it can certify. */
pk->pubkey_usage = key_usage | PUBKEY_USAGE_CERT;
if (!key_expire_seen)
{
/* Find the latest valid user ID with a key expiration set
* Note, that this may be a different one from the above because
* some user IDs may have no expiration date set. */
uiddate = 0;
for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
k = k->next)
{
if (k->pkt->pkttype == PKT_USER_ID)
{
PKT_user_id *uid = k->pkt->pkt.user_id;
if (uid->help_key_expire && uid->created > uiddate)
{
key_expire = uid->help_key_expire;
uiddate = uid->created;
}
}
}
}
/* Currently only v3 keys have a maximum expiration date, but I'll
bet v5 keys get this feature again. */
if (key_expire == 0
|| (pk->max_expiredate && key_expire > pk->max_expiredate))
key_expire = pk->max_expiredate;
pk->has_expired = key_expire >= curtime ? 0 : key_expire;
pk->expiredate = key_expire;
/* Fixme: we should see how to get rid of the expiretime fields but
* this needs changes at other places too. */
/* And now find the real primary user ID and delete all others. */
uiddate = uiddate2 = 0;
uidnode = uidnode2 = NULL;
for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next)
{
if (k->pkt->pkttype == PKT_USER_ID && !k->pkt->pkt.user_id->attrib_data)
{
PKT_user_id *uid = k->pkt->pkt.user_id;
if (uid->is_primary)
{
if (uid->created > uiddate)
{
uiddate = uid->created;
uidnode = k;
}
else if (uid->created == uiddate && uidnode)
{
/* The dates are equal, so we need to do a
different (and arbitrary) comparison. This
should rarely, if ever, happen. It's good to
try and guarantee that two different GnuPG
users with two different keyrings at least pick
the same primary. */
if (cmp_user_ids (uid, uidnode->pkt->pkt.user_id) > 0)
uidnode = k;
}
}
else
{
if (uid->created > uiddate2)
{
uiddate2 = uid->created;
uidnode2 = k;
}
else if (uid->created == uiddate2 && uidnode2)
{
if (cmp_user_ids (uid, uidnode2->pkt->pkt.user_id) > 0)
uidnode2 = k;
}
}
}
}
if (uidnode)
{
for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
k = k->next)
{
if (k->pkt->pkttype == PKT_USER_ID &&
!k->pkt->pkt.user_id->attrib_data)
{
PKT_user_id *uid = k->pkt->pkt.user_id;
if (k != uidnode)
uid->is_primary = 0;
}
}
}
else if (uidnode2)
{
/* None is flagged primary - use the latest user ID we have,
and disambiguate with the arbitrary packet comparison. */
uidnode2->pkt->pkt.user_id->is_primary = 1;
}
else
{
/* None of our uids were self-signed, so pick the one that
sorts first to be the primary. This is the best we can do
here since there are no self sigs to date the uids. */
uidnode = NULL;
for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
k = k->next)
{
if (k->pkt->pkttype == PKT_USER_ID
&& !k->pkt->pkt.user_id->attrib_data)
{
if (!uidnode)
{
uidnode = k;
uidnode->pkt->pkt.user_id->is_primary = 1;
continue;
}
else
{
if (cmp_user_ids (k->pkt->pkt.user_id,
uidnode->pkt->pkt.user_id) > 0)
{
uidnode->pkt->pkt.user_id->is_primary = 0;
uidnode = k;
uidnode->pkt->pkt.user_id->is_primary = 1;
}
else
k->pkt->pkt.user_id->is_primary = 0; /* just to be
safe */
}
}
}
}
}
/* Convert a buffer to a signature. Useful for 0x19 embedded sigs.
Caller must free the signature when they are done. */
static PKT_signature *
buf_to_sig (const byte * buf, size_t len)
{
PKT_signature *sig = xmalloc_clear (sizeof (PKT_signature));
IOBUF iobuf = iobuf_temp_with_content (buf, len);
int save_mode = set_packet_list_mode (0);
if (parse_signature (iobuf, PKT_SIGNATURE, len, sig) != 0)
{
xfree (sig);
sig = NULL;
}
set_packet_list_mode (save_mode);
iobuf_close (iobuf);
return sig;
}
/* Use the self-signed data to fill in various fields in subkeys.
KEYBLOCK is the whole keyblock. SUBNODE is the subkey to fill in.
Sets the following fields on the subkey:
main_keyid
flags.valid if the subkey has a valid self-sig binding
flags.revoked
flags.backsig
pubkey_usage
has_expired
expired_date
On this subkey's most revent valid self-signed packet, the
following field is set:
flags.chosen_selfsig
*/
static void
merge_selfsigs_subkey (KBNODE keyblock, KBNODE subnode)
{
PKT_public_key *mainpk = NULL, *subpk = NULL;
PKT_signature *sig;
KBNODE k;
u32 mainkid[2];
u32 sigdate = 0;
KBNODE signode;
u32 curtime = make_timestamp ();
unsigned int key_usage = 0;
u32 keytimestamp = 0;
u32 key_expire = 0;
const byte *p;
if (subnode->pkt->pkttype != PKT_PUBLIC_SUBKEY)
BUG ();
mainpk = keyblock->pkt->pkt.public_key;
if (mainpk->version < 4)
return;/* (actually this should never happen) */
keyid_from_pk (mainpk, mainkid);
subpk = subnode->pkt->pkt.public_key;
keytimestamp = subpk->timestamp;
subpk->flags.valid = 0;
subpk->flags.exact = 0;
subpk->main_keyid[0] = mainpk->main_keyid[0];
subpk->main_keyid[1] = mainpk->main_keyid[1];
/* Find the latest key binding self-signature. */
signode = NULL;
sigdate = 0; /* Helper to find the latest signature. */
for (k = subnode->next; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
k = k->next)
{
if (k->pkt->pkttype == PKT_SIGNATURE)
{
sig = k->pkt->pkt.signature;
if (sig->keyid[0] == mainkid[0] && sig->keyid[1] == mainkid[1])
{
if (check_key_signature (keyblock, k, NULL))
; /* Signature did not verify. */
else if (IS_SUBKEY_REV (sig))
{
/* Note that this means that the date on a
revocation sig does not matter - even if the
binding sig is dated after the revocation sig,
the subkey is still marked as revoked. This
seems ok, as it is just as easy to make new
subkeys rather than re-sign old ones as the
problem is in the distribution. Plus, PGP (7)
does this the same way. */
subpk->flags.revoked = 1;
sig_to_revoke_info (sig, &subpk->revoked);
/* Although we could stop now, we continue to
* figure out other information like the old expiration
* time. */
}
else if (IS_SUBKEY_SIG (sig) && sig->timestamp >= sigdate)
{
if (sig->flags.expired)
; /* Signature has expired - ignore it. */
else
{
sigdate = sig->timestamp;
signode = k;
signode->pkt->pkt.signature->flags.chosen_selfsig = 0;
}
}
}
}
}
/* No valid key binding. */
if (!signode)
return;
sig = signode->pkt->pkt.signature;
sig->flags.chosen_selfsig = 1; /* So we know which selfsig we chose later. */
key_usage = parse_key_usage (sig);
if (!key_usage)
{
/* No key flags at all: get it from the algo. */
key_usage = openpgp_pk_algo_usage (subpk->pubkey_algo);
}
else
{
/* Check that the usage matches the usage as given by the algo. */
int x = openpgp_pk_algo_usage (subpk->pubkey_algo);
if (x) /* Mask it down to the actual allowed usage. */
key_usage &= x;
}
subpk->pubkey_usage = key_usage;
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
if (p && buf32_to_u32 (p))
key_expire = keytimestamp + buf32_to_u32 (p);
else
key_expire = 0;
subpk->has_expired = key_expire >= curtime ? 0 : key_expire;
subpk->expiredate = key_expire;
/* Algo doesn't exist. */
if (openpgp_pk_test_algo (subpk->pubkey_algo))
return;
subpk->flags.valid = 1;
/* Find the most recent 0x19 embedded signature on our self-sig. */
if (!subpk->flags.backsig)
{
int seq = 0;
size_t n;
PKT_signature *backsig = NULL;
sigdate = 0;
/* We do this while() since there may be other embedded
signatures in the future. We only want 0x19 here. */
while ((p = enum_sig_subpkt (sig->hashed,
SIGSUBPKT_SIGNATURE, &n, &seq, NULL)))
if (n > 3
&& ((p[0] == 3 && p[2] == 0x19) || (p[0] == 4 && p[1] == 0x19)))
{
PKT_signature *tempsig = buf_to_sig (p, n);
if (tempsig)
{
if (tempsig->timestamp > sigdate)
{
if (backsig)
free_seckey_enc (backsig);
backsig = tempsig;
sigdate = backsig->timestamp;
}
else
free_seckey_enc (tempsig);
}
}
seq = 0;
/* It is safe to have this in the unhashed area since the 0x19
is located on the selfsig for convenience, not security. */
while ((p = enum_sig_subpkt (sig->unhashed, SIGSUBPKT_SIGNATURE,
&n, &seq, NULL)))
if (n > 3
&& ((p[0] == 3 && p[2] == 0x19) || (p[0] == 4 && p[1] == 0x19)))
{
PKT_signature *tempsig = buf_to_sig (p, n);
if (tempsig)
{
if (tempsig->timestamp > sigdate)
{
if (backsig)
free_seckey_enc (backsig);
backsig = tempsig;
sigdate = backsig->timestamp;
}
else
free_seckey_enc (tempsig);
}
}
if (backsig)
{
/* At this point, backsig contains the most recent 0x19 sig.
Let's see if it is good. */
/* 2==valid, 1==invalid, 0==didn't check */
if (check_backsig (mainpk, subpk, backsig) == 0)
subpk->flags.backsig = 2;
else
subpk->flags.backsig = 1;
free_seckey_enc (backsig);
}
}
}
/* Merge information from the self-signatures with the public key,
subkeys and user ids to make using them more easy.
See documentation for merge_selfsigs_main, merge_selfsigs_subkey
and fixup_uidnode for exactly which fields are updated. */
static void
merge_selfsigs (KBNODE keyblock)
{
KBNODE k;
int revoked;
struct revoke_info rinfo;
PKT_public_key *main_pk;
prefitem_t *prefs;
unsigned int mdc_feature;
if (keyblock->pkt->pkttype != PKT_PUBLIC_KEY)
{
if (keyblock->pkt->pkttype == PKT_SECRET_KEY)
{
log_error ("expected public key but found secret key "
"- must stop\n");
/* We better exit here because a public key is expected at
other places too. FIXME: Figure this out earlier and
don't get to here at all */
g10_exit (1);
}
BUG ();
}
merge_selfsigs_main (keyblock, &revoked, &rinfo);
/* Now merge in the data from each of the subkeys. */
for (k = keyblock; k; k = k->next)
{
if (k->pkt->pkttype == PKT_PUBLIC_SUBKEY)
{
merge_selfsigs_subkey (keyblock, k);
}
}
main_pk = keyblock->pkt->pkt.public_key;
if (revoked || main_pk->has_expired || !main_pk->flags.valid)
{
/* If the primary key is revoked, expired, or invalid we
* better set the appropriate flags on that key and all
* subkeys. */
for (k = keyblock; k; k = k->next)
{
if (k->pkt->pkttype == PKT_PUBLIC_KEY
|| k->pkt->pkttype == PKT_PUBLIC_SUBKEY)
{
PKT_public_key *pk = k->pkt->pkt.public_key;
if (!main_pk->flags.valid)
pk->flags.valid = 0;
if (revoked && !pk->flags.revoked)
{
pk->flags.revoked = revoked;
memcpy (&pk->revoked, &rinfo, sizeof (rinfo));
}
if (main_pk->has_expired)
pk->has_expired = main_pk->has_expired;
}
}
return;
}
/* Set the preference list of all keys to those of the primary real
* user ID. Note: we use these preferences when we don't know by
* which user ID the key has been selected.
* fixme: we should keep atoms of commonly used preferences or
* use reference counting to optimize the preference lists storage.
* FIXME: it might be better to use the intersection of
* all preferences.
* Do a similar thing for the MDC feature flag. */
prefs = NULL;
mdc_feature = 0;
for (k = keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next)
{
if (k->pkt->pkttype == PKT_USER_ID
&& !k->pkt->pkt.user_id->attrib_data
&& k->pkt->pkt.user_id->is_primary)
{
prefs = k->pkt->pkt.user_id->prefs;
mdc_feature = k->pkt->pkt.user_id->flags.mdc;
break;
}
}
for (k = keyblock; k; k = k->next)
{
if (k->pkt->pkttype == PKT_PUBLIC_KEY
|| k->pkt->pkttype == PKT_PUBLIC_SUBKEY)
{
PKT_public_key *pk = k->pkt->pkt.public_key;
if (pk->prefs)
xfree (pk->prefs);
pk->prefs = copy_prefs (prefs);
pk->flags.mdc = mdc_feature;
}
}
}
/* See whether the key satisfies any additional requirements specified
- in CTX. If so, return 1 and set CTX->FOUND_KEY to an appropriate
- key or subkey. Otherwise, return 0 if there was no appropriate
- key.
-
- In case the primary key is not required, select a suitable subkey.
- We need the primary key if PUBKEY_USAGE_CERT is set in
- CTX->REQ_USAGE or we are in PGP6 or PGP7 mode and PUBKEY_USAGE_SIG
- is set in CTX->REQ_USAGE.
-
- If any of PUBKEY_USAGE_SIG, PUBKEY_USAGE_ENC and PUBKEY_USAGE_CERT
- are set in CTX->REQ_USAGE, we filter by the key's function.
- Concretely, if PUBKEY_USAGE_SIG and PUBKEY_USAGE_CERT are set, then
- we only return a key if it is (at least) either a signing or a
- certification key.
-
- If CTX->REQ_USAGE is set, then we reject any keys that are not good
- (i.e., valid, not revoked, not expired, etc.). This allows the
- getkey functions to be used for plain key listings.
-
- Sets the matched key's user id field (pk->user_id) to the user id
- that matched the low-level search criteria or NULL.
-
-
- This function needs to handle several different cases:
-
- 1. No requested usage and no primary key requested
- Examples for this case are that we have a keyID to be used
- for decrytion or verification.
- 2. No usage but primary key requested
- This is the case for all functions which work on an
- entire keyblock, e.g. for editing or listing
- 3. Usage and primary key requested
- FXME
- 4. Usage but no primary key requested
- FIXME
-
+ * in CTX. If so, return 1 and set CTX->FOUND_KEY to an appropriate
+ * key or subkey. Otherwise, return 0 if there was no appropriate
+ * key.
+ *
+ * In case the primary key is not required, select a suitable subkey.
+ * We need the primary key if PUBKEY_USAGE_CERT is set in
+ * CTX->REQ_USAGE or we are in PGP6 or PGP7 mode and PUBKEY_USAGE_SIG
+ * is set in CTX->REQ_USAGE.
+ *
+ * If any of PUBKEY_USAGE_SIG, PUBKEY_USAGE_ENC and PUBKEY_USAGE_CERT
+ * are set in CTX->REQ_USAGE, we filter by the key's function.
+ * Concretely, if PUBKEY_USAGE_SIG and PUBKEY_USAGE_CERT are set, then
+ * we only return a key if it is (at least) either a signing or a
+ * certification key.
+ *
+ * If CTX->REQ_USAGE is set, then we reject any keys that are not good
+ * (i.e., valid, not revoked, not expired, etc.). This allows the
+ * getkey functions to be used for plain key listings.
+ *
+ * Sets the matched key's user id field (pk->user_id) to the user id
+ * that matched the low-level search criteria or NULL. If R_FLAGS is
+ * not NULL set certain flags for more detailed error reporting. Used
+ * flags are:
+ * - LOOKUP_ALL_SUBKEYS_EXPIRED :: All Subkeys are expired or have
+ * been revoked.
+ *
+ * This function needs to handle several different cases:
+ *
+ * 1. No requested usage and no primary key requested
+ * Examples for this case are that we have a keyID to be used
+ * for decrytion or verification.
+ * 2. No usage but primary key requested
+ * This is the case for all functions which work on an
+ * entire keyblock, e.g. for editing or listing
+ * 3. Usage and primary key requested
+ * FIXME
+ * 4. Usage but no primary key requested
+ * FIXME
+ *
*/
-static KBNODE
-finish_lookup (GETKEY_CTX ctx, KBNODE keyblock)
+static kbnode_t
+finish_lookup (getkey_ctx_t ctx, kbnode_t keyblock, unsigned int *r_flags)
{
- KBNODE k;
+ kbnode_t k;
/* If CTX->EXACT is set, the key or subkey that actually matched the
low-level search criteria. */
- KBNODE foundk = NULL;
+ kbnode_t foundk = NULL;
/* The user id (if any) that matched the low-level search criteria. */
PKT_user_id *foundu = NULL;
#define USAGE_MASK (PUBKEY_USAGE_SIG|PUBKEY_USAGE_ENC|PUBKEY_USAGE_CERT)
unsigned int req_usage = (ctx->req_usage & USAGE_MASK);
/* Request the primary if we're certifying another key, and also
if signing data while --pgp6 or --pgp7 is on since pgp 6 and 7
do not understand signatures made by a signing subkey. PGP 8
does. */
- int req_prim = (ctx->req_usage & PUBKEY_USAGE_CERT) ||
- ((PGP6 || PGP7) && (ctx->req_usage & PUBKEY_USAGE_SIG));
+ int req_prim = ((ctx->req_usage & PUBKEY_USAGE_CERT)
+ || ((PGP6 || PGP7) && (ctx->req_usage & PUBKEY_USAGE_SIG)));
u32 curtime = make_timestamp ();
u32 latest_date;
- KBNODE latest_key;
+ kbnode_t latest_key;
PKT_public_key *pk;
-
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
+ if (r_flags)
+ *r_flags = 0;
+
+ /* For an exact match mark the primary or subkey that matched the
+ low-level search criteria. */
if (ctx->exact)
- /* Get the key or subkey that matched the low-level search
- criteria. */
{
for (k = keyblock; k; k = k->next)
{
if ((k->flag & 1))
{
log_assert (k->pkt->pkttype == PKT_PUBLIC_KEY
|| k->pkt->pkttype == PKT_PUBLIC_SUBKEY);
foundk = k;
pk = k->pkt->pkt.public_key;
pk->flags.exact = 1;
break;
}
}
}
/* Get the user id that matched that low-level search criteria. */
for (k = keyblock; k; k = k->next)
{
if ((k->flag & 2))
{
log_assert (k->pkt->pkttype == PKT_USER_ID);
foundu = k->pkt->pkt.user_id;
break;
}
}
if (DBG_LOOKUP)
log_debug ("finish_lookup: checking key %08lX (%s)(req_usage=%x)\n",
(ulong) keyid_from_pk (keyblock->pkt->pkt.public_key, NULL),
foundk ? "one" : "all", req_usage);
if (!req_usage)
{
latest_key = foundk ? foundk : keyblock;
goto found;
}
latest_date = 0;
latest_key = NULL;
- /* Set latest_key to the latest (the one with the most recent
- timestamp) good (valid, not revoked, not expired, etc.) subkey.
-
- Don't bother if we are only looking for a primary key or we need
- an exact match and the exact match is not a subkey. */
+ /* Set LATEST_KEY to the latest (the one with the most recent
+ * timestamp) good (valid, not revoked, not expired, etc.) subkey.
+ *
+ * Don't bother if we are only looking for a primary key or we need
+ * an exact match and the exact match is not a subkey. */
if (req_prim || (foundk && foundk->pkt->pkttype != PKT_PUBLIC_SUBKEY))
;
else
{
- KBNODE nextk;
+ kbnode_t nextk;
+ int n_subkeys = 0;
+ int n_revoked_or_expired = 0;
/* Either start a loop or check just this one subkey. */
for (k = foundk ? foundk : keyblock; k; k = nextk)
{
if (foundk)
- /* If FOUNDK is not NULL, then only consider that exact
- key, i.e., don't iterate. */
- nextk = NULL;
+ {
+ /* If FOUNDK is not NULL, then only consider that exact
+ key, i.e., don't iterate. */
+ nextk = NULL;
+ }
else
nextk = k->next;
if (k->pkt->pkttype != PKT_PUBLIC_SUBKEY)
continue;
pk = k->pkt->pkt.public_key;
if (DBG_LOOKUP)
log_debug ("\tchecking subkey %08lX\n",
(ulong) keyid_from_pk (pk, NULL));
+
if (!pk->flags.valid)
{
if (DBG_LOOKUP)
log_debug ("\tsubkey not valid\n");
continue;
}
+ if (!((pk->pubkey_usage & USAGE_MASK) & req_usage))
+ {
+ if (DBG_LOOKUP)
+ log_debug ("\tusage does not match: want=%x have=%x\n",
+ req_usage, pk->pubkey_usage);
+ continue;
+ }
+
+ n_subkeys++;
if (pk->flags.revoked)
{
if (DBG_LOOKUP)
log_debug ("\tsubkey has been revoked\n");
+ n_revoked_or_expired++;
continue;
}
if (pk->has_expired)
{
if (DBG_LOOKUP)
log_debug ("\tsubkey has expired\n");
+ n_revoked_or_expired++;
continue;
-
}
if (pk->timestamp > curtime && !opt.ignore_valid_from)
{
if (DBG_LOOKUP)
log_debug ("\tsubkey not yet valid\n");
continue;
}
- if (!((pk->pubkey_usage & USAGE_MASK) & req_usage))
- {
- if (DBG_LOOKUP)
- log_debug ("\tusage does not match: want=%x have=%x\n",
- req_usage, pk->pubkey_usage);
- continue;
- }
-
if (DBG_LOOKUP)
log_debug ("\tsubkey might be fine\n");
/* In case a key has a timestamp of 0 set, we make sure
that it is used. A better change would be to compare
">=" but that might also change the selected keys and
is as such a more intrusive change. */
if (pk->timestamp > latest_date || (!pk->timestamp && !latest_date))
{
latest_date = pk->timestamp;
latest_key = k;
}
}
+ if (n_subkeys == n_revoked_or_expired && r_flags)
+ *r_flags |= LOOKUP_ALL_SUBKEYS_EXPIRED;
}
/* Check if the primary key is ok (valid, not revoke, not expire,
- matches requested usage) if:
-
- - we didn't find an appropriate subkey and we're not doing an
- exact search,
-
- - we're doing an exact match and the exact match was the
- primary key, or,
-
- - we're just considering the primary key. */
+ * matches requested usage) if:
+ *
+ * - we didn't find an appropriate subkey and we're not doing an
+ * exact search,
+ *
+ * - we're doing an exact match and the exact match was the
+ * primary key, or,
+ *
+ * - we're just considering the primary key. */
if ((!latest_key && !ctx->exact) || foundk == keyblock || req_prim)
{
if (DBG_LOOKUP && !foundk && !req_prim)
log_debug ("\tno suitable subkeys found - trying primary\n");
pk = keyblock->pkt->pkt.public_key;
if (!pk->flags.valid)
{
if (DBG_LOOKUP)
log_debug ("\tprimary key not valid\n");
}
+ else if (!((pk->pubkey_usage & USAGE_MASK) & req_usage))
+ {
+ if (DBG_LOOKUP)
+ log_debug ("\tprimary key usage does not match: "
+ "want=%x have=%x\n", req_usage, pk->pubkey_usage);
+ }
else if (pk->flags.revoked)
{
if (DBG_LOOKUP)
log_debug ("\tprimary key has been revoked\n");
}
else if (pk->has_expired)
{
if (DBG_LOOKUP)
log_debug ("\tprimary key has expired\n");
}
- else if (!((pk->pubkey_usage & USAGE_MASK) & req_usage))
- {
- if (DBG_LOOKUP)
- log_debug ("\tprimary key usage does not match: "
- "want=%x have=%x\n", req_usage, pk->pubkey_usage);
- }
else /* Okay. */
{
if (DBG_LOOKUP)
log_debug ("\tprimary key may be used\n");
latest_key = keyblock;
}
}
if (!latest_key)
{
if (DBG_LOOKUP)
log_debug ("\tno suitable key found - giving up\n");
return NULL; /* Not found. */
}
found:
if (DBG_LOOKUP)
log_debug ("\tusing key %08lX\n",
(ulong) keyid_from_pk (latest_key->pkt->pkt.public_key, NULL));
if (latest_key)
{
pk = latest_key->pkt->pkt.public_key;
if (pk->user_id)
free_user_id (pk->user_id);
pk->user_id = scopy_user_id (foundu);
}
if (latest_key != keyblock && opt.verbose)
{
char *tempkeystr =
xstrdup (keystr_from_pk (latest_key->pkt->pkt.public_key));
log_info (_("using subkey %s instead of primary key %s\n"),
tempkeystr, keystr_from_pk (keyblock->pkt->pkt.public_key));
xfree (tempkeystr);
}
cache_user_id (keyblock);
return latest_key ? latest_key : keyblock; /* Found. */
}
+/* Print a KEY_CONSIDERED status line. */
+static void
+print_status_key_considered (kbnode_t keyblock, unsigned int flags)
+{
+ char hexfpr[2*MAX_FINGERPRINT_LEN + 1];
+ kbnode_t node;
+ char flagbuf[20];
+
+ if (!is_status_enabled ())
+ return;
+
+ for (node=keyblock; node; node = node->next)
+ if (node->pkt->pkttype == PKT_PUBLIC_KEY
+ || node->pkt->pkttype == PKT_SECRET_KEY)
+ break;
+ if (!node)
+ {
+ log_error ("%s: keyblock w/o primary key\n", __func__);
+ return;
+ }
+
+ hexfingerprint (node->pkt->pkt.public_key, hexfpr, sizeof hexfpr);
+ snprintf (flagbuf, sizeof flagbuf, " %u", flags);
+ write_status_strings (STATUS_KEY_CONSIDERED, hexfpr, flagbuf, NULL);
+}
+
+
+
/* A high-level function to lookup keys.
This function builds on top of the low-level keydb API. It first
searches the database using the description stored in CTX->ITEMS,
then it filters the results using CTX and, finally, if WANT_SECRET
is set, it ignores any keys for which no secret key is available.
Unlike the low-level search functions, this function also merges
all of the self-signed data into the keys, subkeys and user id
packets (see the merge_selfsigs for details).
On success the key's keyblock is stored at *RET_KEYBLOCK. */
static int
lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, kbnode_t *ret_found_key,
int want_secret)
{
int rc;
int no_suitable_key = 0;
KBNODE keyblock = NULL;
KBNODE found_key = NULL;
+ unsigned int infoflags;
if (ret_keyblock)
*ret_keyblock = NULL;
for (;;)
{
rc = keydb_search (ctx->kr_handle, ctx->items, ctx->nitems, NULL);
if (rc)
break;
/* If we are iterating over the entire database, then we need to
change from KEYDB_SEARCH_MODE_FIRST, which does an implicit
reset, to KEYDB_SEARCH_MODE_NEXT, which gets the next
record. */
if (ctx->nitems && ctx->items->mode == KEYDB_SEARCH_MODE_FIRST)
ctx->items->mode = KEYDB_SEARCH_MODE_NEXT;
rc = keydb_get_keyblock (ctx->kr_handle, &keyblock);
if (rc)
{
log_error ("keydb_get_keyblock failed: %s\n", gpg_strerror (rc));
goto skip;
}
if (want_secret && agent_probe_any_secret_key (NULL, keyblock))
goto skip; /* No secret key available. */
/* Warning: node flag bits 0 and 1 should be preserved by
* merge_selfsigs. For secret keys, premerge transferred the
* keys to the keyblock. */
merge_selfsigs (keyblock);
- found_key = finish_lookup (ctx, keyblock);
+ found_key = finish_lookup (ctx, keyblock, &infoflags);
+ if (!found_key)
+ infoflags |= LOOKUP_NOT_SELECTED;
+ print_status_key_considered (keyblock, infoflags);
if (found_key)
{
no_suitable_key = 0;
goto found;
}
else
- no_suitable_key = 1;
+ {
+ no_suitable_key = 1;
+ }
skip:
/* Release resources and continue search. */
release_kbnode (keyblock);
keyblock = NULL;
/* The keyblock cache ignores the current "file position".
Thus, if we request the next result and the cache matches
(and it will since it is what we just looked for), we'll get
the same entry back! We can avoid this infinite loop by
disabling the cache. */
keydb_disable_caching (ctx->kr_handle);
}
-found:
+ found:
if (rc && gpg_err_code (rc) != GPG_ERR_NOT_FOUND)
log_error ("keydb_search failed: %s\n", gpg_strerror (rc));
if (!rc)
{
if (ret_keyblock)
*ret_keyblock = keyblock; /* Return the keyblock. */
keyblock = NULL;
}
else if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND && no_suitable_key)
rc = want_secret? GPG_ERR_UNUSABLE_SECKEY : GPG_ERR_UNUSABLE_PUBKEY;
else if (gpg_err_code (rc) == GPG_ERR_NOT_FOUND)
rc = want_secret? GPG_ERR_NO_SECKEY : GPG_ERR_NO_PUBKEY;
release_kbnode (keyblock);
if (ret_found_key)
{
if (! rc)
*ret_found_key = found_key;
else
*ret_found_key = NULL;
}
return rc;
}
/* Enumerate some secret keys (specifically, those specified with
* --default-key and --try-secret-key). Use the following procedure:
*
* 1) Initialize a void pointer to NULL
* 2) Pass a reference to this pointer to this function (content)
* and provide space for the secret key (sk)
* 3) Call this function as long as it does not return an error (or
* until you are done). The error code GPG_ERR_EOF indicates the
* end of the listing.
* 4) Call this function a last time with SK set to NULL,
* so that can free it's context.
*
* In pseudo-code:
*
* void *ctx = NULL;
* PKT_public_key *sk = xmalloc_clear (sizeof (*sk));
*
* while ((err = enum_secret_keys (&ctx, sk)))
* { // Process SK.
* if (done)
* break;
* free_public_key (sk);
* sk = xmalloc_clear (sizeof (*sk));
* }
*
* // Release any resources used by CTX.
* enum_secret_keys (&ctx, NULL);
* free_public_key (sk);
*
* if (gpg_err_code (err) != GPG_ERR_EOF)
* ; // An error occurred.
*/
gpg_error_t
enum_secret_keys (ctrl_t ctrl, void **context, PKT_public_key *sk)
{
gpg_error_t err = 0;
const char *name;
struct
{
int eof;
int state;
strlist_t sl;
kbnode_t keyblock;
kbnode_t node;
} *c = *context;
if (!c)
{
/* Make a new context. */
c = xtrycalloc (1, sizeof *c);
if (!c)
return gpg_error_from_syserror ();
*context = c;
}
if (!sk)
{
/* Free the context. */
release_kbnode (c->keyblock);
xfree (c);
*context = NULL;
return 0;
}
if (c->eof)
return gpg_error (GPG_ERR_EOF);
for (;;)
{
/* Loop until we have a keyblock. */
while (!c->keyblock)
{
/* Loop over the list of secret keys. */
do
{
name = NULL;
switch (c->state)
{
case 0: /* First try to use the --default-key. */
name = parse_def_secret_key (ctrl);
c->state = 1;
break;
case 1: /* Init list of keys to try. */
c->sl = opt.secret_keys_to_try;
c->state++;
break;
case 2: /* Get next item from list. */
if (c->sl)
{
name = c->sl->d;
c->sl = c->sl->next;
}
else
c->state++;
break;
default: /* No more names to check - stop. */
c->eof = 1;
return gpg_error (GPG_ERR_EOF);
}
}
while (!name || !*name);
err = getkey_byname (ctrl, NULL, NULL, name, 1, &c->keyblock);
if (err)
{
/* getkey_byname might return a keyblock even in the
error case - I have not checked. Thus better release
it. */
release_kbnode (c->keyblock);
c->keyblock = NULL;
}
else
c->node = c->keyblock;
}
/* Get the next key from the current keyblock. */
for (; c->node; c->node = c->node->next)
{
if (c->node->pkt->pkttype == PKT_PUBLIC_KEY
|| c->node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
{
copy_public_key (sk, c->node->pkt->pkt.public_key);
c->node = c->node->next;
return 0; /* Found. */
}
}
/* Dispose the keyblock and continue. */
release_kbnode (c->keyblock);
c->keyblock = NULL;
}
}
/*********************************************
*********** User ID printing helpers *******
*********************************************/
/* Return a string with a printable representation of the user_id.
* this string must be freed by xfree. */
static char *
get_user_id_string (u32 * keyid, int mode, size_t *r_len)
{
user_id_db_t r;
keyid_list_t a;
int pass = 0;
char *p;
/* Try it two times; second pass reads from the database. */
do
{
for (r = user_id_db; r; r = r->next)
{
for (a = r->keyids; a; a = a->next)
{
if (a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1])
{
if (mode == 2)
{
/* An empty string as user id is possible. Make
sure that the malloc allocates one byte and
does not bail out. */
p = xmalloc (r->len? r->len : 1);
memcpy (p, r->name, r->len);
if (r_len)
*r_len = r->len;
}
else
{
if (mode)
p = xasprintf ("%08lX%08lX %.*s",
(ulong) keyid[0], (ulong) keyid[1],
r->len, r->name);
else
p = xasprintf ("%s %.*s", keystr (keyid),
r->len, r->name);
if (r_len)
*r_len = strlen (p);
}
return p;
}
}
}
}
while (++pass < 2 && !get_pubkey (NULL, keyid));
if (mode == 2)
p = xstrdup (user_id_not_found_utf8 ());
else if (mode)
p = xasprintf ("%08lX%08lX [?]", (ulong) keyid[0], (ulong) keyid[1]);
else
p = xasprintf ("%s [?]", keystr (keyid));
if (r_len)
*r_len = strlen (p);
return p;
}
char *
get_user_id_string_native (u32 * keyid)
{
char *p = get_user_id_string (keyid, 0, NULL);
char *p2 = utf8_to_native (p, strlen (p), 0);
xfree (p);
return p2;
}
char *
get_long_user_id_string (u32 * keyid)
{
return get_user_id_string (keyid, 1, NULL);
}
/* Please try to use get_user_byfpr instead of this one. */
char *
get_user_id (u32 * keyid, size_t * rn)
{
return get_user_id_string (keyid, 2, rn);
}
/* Please try to use get_user_id_byfpr_native instead of this one. */
char *
get_user_id_native (u32 * keyid)
{
size_t rn;
char *p = get_user_id (keyid, &rn);
char *p2 = utf8_to_native (p, rn, 0);
xfree (p);
return p2;
}
/* Return the user id for a key designated by its fingerprint, FPR,
which must be MAX_FINGERPRINT_LEN bytes in size. Note: the
returned string, which must be freed using xfree, may not be NUL
terminated. To determine the length of the string, you must use
*RN. */
char *
get_user_id_byfpr (const byte *fpr, size_t *rn)
{
user_id_db_t r;
char *p;
int pass = 0;
/* Try it two times; second pass reads from the database. */
do
{
for (r = user_id_db; r; r = r->next)
{
keyid_list_t a;
for (a = r->keyids; a; a = a->next)
{
if (!memcmp (a->fpr, fpr, MAX_FINGERPRINT_LEN))
{
/* An empty string as user id is possible. Make
sure that the malloc allocates one byte and does
not bail out. */
p = xmalloc (r->len? r->len : 1);
memcpy (p, r->name, r->len);
*rn = r->len;
return p;
}
}
}
}
while (++pass < 2
&& !get_pubkey_byfprint (NULL, NULL, fpr, MAX_FINGERPRINT_LEN));
p = xstrdup (user_id_not_found_utf8 ());
*rn = strlen (p);
return p;
}
/* Like get_user_id_byfpr, but convert the string to the native
encoding. The returned string needs to be freed. Unlike
get_user_id_byfpr, the returned string is NUL terminated. */
char *
get_user_id_byfpr_native (const byte *fpr)
{
size_t rn;
char *p = get_user_id_byfpr (fpr, &rn);
char *p2 = utf8_to_native (p, rn, 0);
xfree (p);
return p2;
}
/* Return the database handle used by this context. The context still
owns the handle. */
KEYDB_HANDLE
get_ctx_handle (GETKEY_CTX ctx)
{
return ctx->kr_handle;
}
static void
free_akl (struct akl *akl)
{
if (! akl)
return;
if (akl->spec)
free_keyserver_spec (akl->spec);
xfree (akl);
}
void
release_akl (void)
{
while (opt.auto_key_locate)
{
struct akl *akl2 = opt.auto_key_locate;
opt.auto_key_locate = opt.auto_key_locate->next;
free_akl (akl2);
}
}
/* Returns false on error. */
int
parse_auto_key_locate (char *options)
{
char *tok;
while ((tok = optsep (&options)))
{
struct akl *akl, *check, *last = NULL;
int dupe = 0;
if (tok[0] == '\0')
continue;
akl = xmalloc_clear (sizeof (*akl));
if (ascii_strcasecmp (tok, "clear") == 0)
{
xfree (akl);
free_akl (opt.auto_key_locate);
opt.auto_key_locate = NULL;
continue;
}
else if (ascii_strcasecmp (tok, "nodefault") == 0)
akl->type = AKL_NODEFAULT;
else if (ascii_strcasecmp (tok, "local") == 0)
akl->type = AKL_LOCAL;
else if (ascii_strcasecmp (tok, "ldap") == 0)
akl->type = AKL_LDAP;
else if (ascii_strcasecmp (tok, "keyserver") == 0)
akl->type = AKL_KEYSERVER;
#ifdef USE_DNS_CERT
else if (ascii_strcasecmp (tok, "cert") == 0)
akl->type = AKL_CERT;
#endif
else if (ascii_strcasecmp (tok, "pka") == 0)
akl->type = AKL_PKA;
else if (ascii_strcasecmp (tok, "dane") == 0)
akl->type = AKL_DANE;
else if (ascii_strcasecmp (tok, "wkd") == 0)
akl->type = AKL_WKD;
else if ((akl->spec = parse_keyserver_uri (tok, 1)))
akl->type = AKL_SPEC;
else
{
free_akl (akl);
return 0;
}
/* We must maintain the order the user gave us */
for (check = opt.auto_key_locate; check;
last = check, check = check->next)
{
/* Check for duplicates */
if (check->type == akl->type
&& (akl->type != AKL_SPEC
|| (akl->type == AKL_SPEC
&& strcmp (check->spec->uri, akl->spec->uri) == 0)))
{
dupe = 1;
free_akl (akl);
break;
}
}
if (!dupe)
{
if (last)
last->next = akl;
else
opt.auto_key_locate = akl;
}
}
return 1;
}
/* Returns true if a secret key is available for the public key with
key id KEYID; returns false if not. This function ignores legacy
keys. Note: this is just a fast check and does not tell us whether
the secret key is valid; this check merely indicates whether there
is some secret key with the specified key id. */
int
have_secret_key_with_kid (u32 *keyid)
{
gpg_error_t err;
KEYDB_HANDLE kdbhd;
KEYDB_SEARCH_DESC desc;
kbnode_t keyblock;
kbnode_t node;
int result = 0;
kdbhd = keydb_new ();
if (!kdbhd)
return 0;
memset (&desc, 0, sizeof desc);
desc.mode = KEYDB_SEARCH_MODE_LONG_KID;
desc.u.kid[0] = keyid[0];
desc.u.kid[1] = keyid[1];
while (!result)
{
err = keydb_search (kdbhd, &desc, 1, NULL);
if (err)
break;
err = keydb_get_keyblock (kdbhd, &keyblock);
if (err)
{
log_error (_("error reading keyblock: %s\n"), gpg_strerror (err));
break;
}
for (node = keyblock; node; node = node->next)
{
/* Bit 0 of the flags is set if the search found the key
using that key or subkey. Note: a search will only ever
match a single key or subkey. */
if ((node->flag & 1))
{
log_assert (node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY);
if (!agent_probe_secret_key (NULL, node->pkt->pkt.public_key))
result = 1; /* Secret key available. */
else
result = 0;
break;
}
}
release_kbnode (keyblock);
}
keydb_release (kdbhd);
return result;
}