diff --git a/doc/gpg.texi b/doc/gpg.texi index 2e7230982..887a62458 100644 --- a/doc/gpg.texi +++ b/doc/gpg.texi @@ -1,3583 +1,3593 @@ @c Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, @c 2008, 2009, 2010 Free Software Foundation, Inc. @c This is part of the GnuPG manual. @c For copying conditions, see the file gnupg.texi. @c Note that we use this texinfo file for all GnuPG-2 branches. @c The macro "gpgtwoone" controls parts which are only @c valid for GnuPG 2.1 and later. @node Invoking GPG @chapter Invoking GPG @cindex GPG command options @cindex command options @cindex options, GPG command @c Begin algorithm defaults @ifclear gpgtwoone @set DEFSYMENCALGO CAST5 @end ifclear @ifset gpgtwoone @set DEFSYMENCALGO AES128 @end ifset @c End algorithm defaults @macro gpgname gpg2 @end macro @manpage gpg2.1 @ifset manverb .B gpg2 \- OpenPGP encryption and signing tool @end ifset @mansect synopsis @ifset manverb .B gpg2 .RB [ \-\-homedir .IR dir ] .RB [ \-\-options .IR file ] .RI [ options ] .I command .RI [ args ] @end ifset @mansect description @command{@gpgname} is the OpenPGP part of the GNU Privacy Guard (GnuPG). It is a tool to provide digital encryption and signing services using the OpenPGP standard. @command{@gpgname} features complete key management and all bells and whistles you can expect from a decent OpenPGP implementation. In contrast to the standalone command gpg from GnuPG 1.x, which is might be better suited for server and embedded platforms, the 2.x version is commonly installed under the name @command{gpg2} and targeted to the desktop as it requires several other modules to be installed. @manpause The old 1.x version will be kept maintained and it is possible to install both versions on the same system. Documentation for the old GnuPG 1.x command is available as a man page and at @inforef{Top,GnuPG 1,gpg}. @xref{Option Index}, for an index to @command{@gpgname}'s commands and options. @mancont @menu * GPG Commands:: List of all commands. * GPG Options:: List of all options. * GPG Configuration:: Configuration files. * GPG Examples:: Some usage examples. Developer information: * Unattended Usage of GPG:: Using @command{gpg} from other programs. @end menu @c * GPG Protocol:: The protocol the server mode uses. @c ******************************************* @c *************** **************** @c *************** COMMANDS **************** @c *************** **************** @c ******************************************* @mansect commands @node GPG Commands @section Commands Commands are not distinguished from options except for the fact that only one command is allowed. @command{@gpgname} may be run with no commands, in which case it will perform a reasonable action depending on the type of file it is given as input (an encrypted message is decrypted, a signature is verified, a file containing keys is listed). Please remember that option as well as command parsing stops as soon as a non-option is encountered, you can explicitly stop parsing by using the special option @option{--}. @menu * General GPG Commands:: Commands not specific to the functionality. * Operational GPG Commands:: Commands to select the type of operation. * OpenPGP Key Management:: How to manage your keys. @end menu @c ******************************************* @c ********** GENERAL COMMANDS ************* @c ******************************************* @node General GPG Commands @subsection Commands not specific to the function @table @gnupgtabopt @item --version @opindex version Print the program version and licensing information. Note that you cannot abbreviate this command. @item --help @itemx -h @opindex help Print a usage message summarizing the most useful command line options. Note that you cannot abbreviate this command. @item --warranty @opindex warranty Print warranty information. @item --dump-options @opindex dump-options Print a list of all available options and commands. Note that you cannot abbreviate this command. @end table @c ******************************************* @c ******** OPERATIONAL COMMANDS *********** @c ******************************************* @node Operational GPG Commands @subsection Commands to select the type of operation @table @gnupgtabopt @item --sign @itemx -s @opindex sign Make a signature. This command may be combined with @option{--encrypt} (for a signed and encrypted message), @option{--symmetric} (for a signed and symmetrically encrypted message), or @option{--encrypt} and @option{--symmetric} together (for a signed message that may be decrypted via a secret key or a passphrase). The key to be used for signing is chosen by default or can be set with the @option{--local-user} and @option{--default-key} options. @item --clearsign @opindex clearsign Make a clear text signature. The content in a clear text signature is readable without any special software. OpenPGP software is only needed to verify the signature. Clear text signatures may modify end-of-line whitespace for platform independence and are not intended to be reversible. The key to be used for signing is chosen by default or can be set with the @option{--local-user} and @option{--default-key} options. @item --detach-sign @itemx -b @opindex detach-sign Make a detached signature. @item --encrypt @itemx -e @opindex encrypt Encrypt data. This option may be combined with @option{--sign} (for a signed and encrypted message), @option{--symmetric} (for a message that may be decrypted via a secret key or a passphrase), or @option{--sign} and @option{--symmetric} together (for a signed message that may be decrypted via a secret key or a passphrase). @item --symmetric @itemx -c @opindex symmetric Encrypt with a symmetric cipher using a passphrase. The default symmetric cipher used is @value{DEFSYMENCALGO}, but may be chosen with the @option{--cipher-algo} option. This option may be combined with @option{--sign} (for a signed and symmetrically encrypted message), @option{--encrypt} (for a message that may be decrypted via a secret key or a passphrase), or @option{--sign} and @option{--encrypt} together (for a signed message that may be decrypted via a secret key or a passphrase). @item --store @opindex store Store only (make a simple RFC1991 literal data packet). @item --decrypt @itemx -d @opindex decrypt Decrypt the file given on the command line (or STDIN if no file is specified) and write it to STDOUT (or the file specified with @option{--output}). If the decrypted file is signed, the signature is also verified. This command differs from the default operation, as it never writes to the filename which is included in the file and it rejects files which don't begin with an encrypted message. @item --verify @opindex verify Assume that the first argument is a signed file and verify it without generating any output. With no arguments, the signature packet is read from STDIN. If only a one argument is given, it is expected to be a complete signature. With more than 1 argument, the first should be a detached signature and the remaining files ake up the the signed data. To read the signed data from STDIN, use @samp{-} as the second filename. For security reasons a detached signature cannot read the signed material from STDIN without denoting it in the above way. Note: If the option @option{--batch} is not used, @command{@gpgname} may assume that a single argument is a file with a detached signature and it will try to find a matching data file by stripping certain suffixes. Using this historical feature to verify a detached signature is strongly discouraged; always specify the data file too. Note: When verifying a cleartext signature, @command{gpg} verifies only what makes up the cleartext signed data and not any extra data outside of the cleartext signature or header lines following directly the dash marker line. The option @code{--output} may be used to write out the actual signed data; but there are other pitfalls with this format as well. It is suggested to avoid cleartext signatures in favor of detached signatures. @item --multifile @opindex multifile This modifies certain other commands to accept multiple files for processing on the command line or read from STDIN with each filename on a separate line. This allows for many files to be processed at once. @option{--multifile} may currently be used along with @option{--verify}, @option{--encrypt}, and @option{--decrypt}. Note that @option{--multifile --verify} may not be used with detached signatures. @item --verify-files @opindex verify-files Identical to @option{--multifile --verify}. @item --encrypt-files @opindex encrypt-files Identical to @option{--multifile --encrypt}. @item --decrypt-files @opindex decrypt-files Identical to @option{--multifile --decrypt}. @item --list-keys @itemx -k @itemx --list-public-keys @opindex list-keys List all keys from the public keyrings, or just the keys given on the command line. Avoid using the output of this command in scripts or other programs as it is likely to change as GnuPG changes. See @option{--with-colons} for a machine-parseable key listing command that is appropriate for use in scripts and other programs. @item --list-secret-keys @itemx -K @opindex list-secret-keys List all keys from the secret keyrings, or just the ones given on the command line. A @code{#} after the letters @code{sec} means that the secret key is not usable (for example, if it was created via @option{--export-secret-subkeys}). @item --list-sigs @opindex list-sigs Same as @option{--list-keys}, but the signatures are listed too. This command has the same effect as using @option{--list-keys} with @option{--with-sig-list}. For each signature listed, there are several flags in between the "sig" tag and keyid. These flags give additional information about each signature. From left to right, they are the numbers 1-3 for certificate check level (see @option{--ask-cert-level}), "L" for a local or non-exportable signature (see @option{--lsign-key}), "R" for a nonRevocable signature (see the @option{--edit-key} command "nrsign"), "P" for a signature that contains a policy URL (see @option{--cert-policy-url}), "N" for a signature that contains a notation (see @option{--cert-notation}), "X" for an eXpired signature (see @option{--ask-cert-expire}), and the numbers 1-9 or "T" for 10 and above to indicate trust signature levels (see the @option{--edit-key} command "tsign"). @item --check-sigs @opindex check-sigs Same as @option{--list-sigs}, but the signatures are verified. Note that for performance reasons the revocation status of a signing key is not shown. This command has the same effect as using @option{--list-keys} with @option{--with-sig-check}. The status of the verification is indicated by a flag directly following the "sig" tag (and thus before the flags described above for @option{--list-sigs}). A "!" indicates that the signature has been successfully verified, a "-" denotes a bad signature and a "%" is used if an error occurred while checking the signature (e.g. a non supported algorithm). @item --locate-keys @opindex locate-keys Locate the keys given as arguments. This command basically uses the same algorithm as used when locating keys for encryption or signing and may thus be used to see what keys @command{@gpgname} might use. In particular external methods as defined by @option{--auto-key-locate} may be used to locate a key. Only public keys are listed. @item --fingerprint @opindex fingerprint List all keys (or the specified ones) along with their fingerprints. This is the same output as @option{--list-keys} but with the additional output of a line with the fingerprint. May also be combined with @option{--list-sigs} or @option{--check-sigs}. If this command is given twice, the fingerprints of all secondary keys are listed too. @item --list-packets @opindex list-packets List only the sequence of packets. This is mainly useful for debugging. When used with option @option{--verbose} the actual MPI values are dumped and not only their lengths. @item --card-edit @opindex card-edit Present a menu to work with a smartcard. The subcommand "help" provides an overview on available commands. For a detailed description, please see the Card HOWTO at https://gnupg.org/documentation/howtos.html#GnuPG-cardHOWTO . @item --card-status @opindex card-status Show the content of the smart card. @item --change-pin @opindex change-pin Present a menu to allow changing the PIN of a smartcard. This functionality is also available as the subcommand "passwd" with the @option{--card-edit} command. @item --delete-keys @code{name} @itemx --delete-keys @code{name} Remove key from the public keyring. In batch mode either @option{--yes} is required or the key must be specified by fingerprint. This is a safeguard against accidental deletion of multiple keys. @item --delete-secret-keys @code{name} @opindex delete-secret-keys Remove key from the secret keyring. In batch mode the key must be specified by fingerprint. @item --delete-secret-and-public-key @code{name} @opindex delete-secret-and-public-key Same as @option{--delete-key}, but if a secret key exists, it will be removed first. In batch mode the key must be specified by fingerprint. @item --export @opindex export Either export all keys from all keyrings (default keyrings and those registered via option @option{--keyring}), or if at least one name is given, those of the given name. The exported keys are written to STDOUT or to the file given with option @option{--output}. Use together with @option{--armor} to mail those keys. @item --send-keys @code{key IDs} @opindex send-keys Similar to @option{--export} but sends the keys to a keyserver. Fingerprints may be used instead of key IDs. Option @option{--keyserver} must be used to give the name of this keyserver. Don't send your complete keyring to a keyserver --- select only those keys which are new or changed by you. If no key IDs are given, @command{gpg} does nothing. @item --export-secret-keys @itemx --export-secret-subkeys @opindex export-secret-keys @opindex export-secret-subkeys Same as @option{--export}, but exports the secret keys instead. The exported keys are written to STDOUT or to the file given with option @option{--output}. This command is often used along with the option @option{--armor} to allow easy printing of the key for paper backup; however the external tool @command{paperkey} does a better job for creating backups on paper. Note that exporting a secret key can be a security risk if the exported keys are send over an insecure channel. The second form of the command has the special property to render the secret part of the primary key useless; this is a GNU extension to OpenPGP and other implementations can not be expected to successfully import such a key. Its intended use is to generated a full key with an additional signing subkey on a dedicated machine and then using this command to export the key without the primary key to the main machine. @ifset gpgtwoone GnuPG may ask you to enter the passphrase for the key. This is required because the internal protection method of the secret key is different from the one specified by the OpenPGP protocol. @end ifset @ifclear gpgtwoone See the option @option{--simple-sk-checksum} if you want to import an exported secret key into ancient OpenPGP implementations. @end ifclear @item --import @itemx --fast-import @opindex import Import/merge keys. This adds the given keys to the keyring. The fast version is currently just a synonym. There are a few other options which control how this command works. Most notable here is the @option{--import-options merge-only} option which does not insert new keys but does only the merging of new signatures, user-IDs and subkeys. @item --recv-keys @code{key IDs} @opindex recv-keys Import the keys with the given key IDs from a keyserver. Option @option{--keyserver} must be used to give the name of this keyserver. @item --refresh-keys @opindex refresh-keys Request updates from a keyserver for keys that already exist on the local keyring. This is useful for updating a key with the latest signatures, user IDs, etc. Calling this with no arguments will refresh the entire keyring. Option @option{--keyserver} must be used to give the name of the keyserver for all keys that do not have preferred keyservers set (see @option{--keyserver-options honor-keyserver-url}). @item --search-keys @code{names} @opindex search-keys Search the keyserver for the given names. Multiple names given here will be joined together to create the search string for the keyserver. Option @option{--keyserver} must be used to give the name of this keyserver. Keyservers that support different search methods allow using the syntax specified in "How to specify a user ID" below. Note that different keyserver types support different search methods. Currently only LDAP supports them all. @item --fetch-keys @code{URIs} @opindex fetch-keys Retrieve keys located at the specified URIs. Note that different installations of GnuPG may support different protocols (HTTP, FTP, LDAP, etc.) @item --update-trustdb @opindex update-trustdb Do trust database maintenance. This command iterates over all keys and builds the Web of Trust. This is an interactive command because it may have to ask for the "ownertrust" values for keys. The user has to give an estimation of how far she trusts the owner of the displayed key to correctly certify (sign) other keys. GnuPG only asks for the ownertrust value if it has not yet been assigned to a key. Using the @option{--edit-key} menu, the assigned value can be changed at any time. @item --check-trustdb @opindex check-trustdb Do trust database maintenance without user interaction. From time to time the trust database must be updated so that expired keys or signatures and the resulting changes in the Web of Trust can be tracked. Normally, GnuPG will calculate when this is required and do it automatically unless @option{--no-auto-check-trustdb} is set. This command can be used to force a trust database check at any time. The processing is identical to that of @option{--update-trustdb} but it skips keys with a not yet defined "ownertrust". For use with cron jobs, this command can be used together with @option{--batch} in which case the trust database check is done only if a check is needed. To force a run even in batch mode add the option @option{--yes}. @anchor{option --export-ownertrust} @item --export-ownertrust @opindex export-ownertrust Send the ownertrust values to STDOUT. This is useful for backup purposes as these values are the only ones which can't be re-created from a corrupted trustdb. Example: @c man:.RS @example @gpgname{} --export-ownertrust > otrust.txt @end example @c man:.RE @item --import-ownertrust @opindex import-ownertrust Update the trustdb with the ownertrust values stored in @code{files} (or STDIN if not given); existing values will be overwritten. In case of a severely damaged trustdb and if you have a recent backup of the ownertrust values (e.g. in the file @file{otrust.txt}, you may re-create the trustdb using these commands: @c man:.RS @example cd ~/.gnupg rm trustdb.gpg @gpgname{} --import-ownertrust < otrust.txt @end example @c man:.RE @item --rebuild-keydb-caches @opindex rebuild-keydb-caches When updating from version 1.0.6 to 1.0.7 this command should be used to create signature caches in the keyring. It might be handy in other situations too. @item --print-md @code{algo} @itemx --print-mds @opindex print-md Print message digest of algorithm ALGO for all given files or STDIN. With the second form (or a deprecated "*" as algo) digests for all available algorithms are printed. @item --gen-random @code{0|1|2} @code{count} @opindex gen-random Emit @var{count} random bytes of the given quality level 0, 1 or 2. If @var{count} is not given or zero, an endless sequence of random bytes will be emitted. If used with @option{--armor} the output will be base64 encoded. PLEASE, don't use this command unless you know what you are doing; it may remove precious entropy from the system! @item --gen-prime @code{mode} @code{bits} @opindex gen-prime Use the source, Luke :-). The output format is still subject to change. @item --enarmor @item --dearmor @opindex enarmor @opindex dearmor Pack or unpack an arbitrary input into/from an OpenPGP ASCII armor. This is a GnuPG extension to OpenPGP and in general not very useful. @c @item --server @c @opindex server @c Run gpg in server mode. This feature is not yet ready for use and @c thus not documented. @end table @c ******************************************* @c ******* KEY MANGEMENT COMMANDS ********** @c ******************************************* @node OpenPGP Key Management @subsection How to manage your keys This section explains the main commands for key management @table @gnupgtabopt @ifset gpgtwoone @item --quick-gen-key @code{user-id} @opindex quick-gen-key -This is simple command to generate a standard key with one user id. +This is a simple command to generate a standard key with one user id. In contrast to @option{--gen-key} the key is generated directly without the need to answer a bunch of prompts. Unless the option @option{--yes} is given, the key creation will be canceled if the given user id already exists in the key ring. If invoked directly on the console without any special options an answer to a ``Continue?'' style confirmation prompt is required. In case the user id already exists in the key ring a second prompt to force the creation of the key will show up. If this command is used with @option{--batch}, @option{--pinentry-mode} has been set to @code{loopback}, and one of the passphrase options (@option{--passphrase}, @option{--passphrase-fd}, or @option{passphrase-file}) is used, the supplied passphrase is used for the new key and the agent does not ask for it. To create a key without any protection @code{--passphrase ''} may be used. @end ifset @item --gen-key @opindex gen-key Generate a new key pair using teh current default parameters. This is the standard command to create a new key. @ifset gpgtwoone @item --full-gen-key @opindex gen-key Generate a new key pair with dialogs for all options. This is an extended version of @option{--gen-key}. @end ifset There is also a feature which allows you to create keys in batch mode. See the the manual section ``Unattended key generation'' on how to use this. @item --gen-revoke @code{name} @opindex gen-revoke Generate a revocation certificate for the complete key. To revoke a subkey or a signature, use the @option{--edit} command. @item --desig-revoke @code{name} @opindex desig-revoke Generate a designated revocation certificate for a key. This allows a user (with the permission of the keyholder) to revoke someone else's key. @item --edit-key @opindex edit-key Present a menu which enables you to do most of the key management related tasks. It expects the specification of a key on the command line. @c ******** Begin Edit-key Options ********** @table @asis @item uid @code{n} @opindex keyedit:uid Toggle selection of user ID or photographic user ID with index @code{n}. Use @code{*} to select all and @code{0} to deselect all. @item key @code{n} @opindex keyedit:key Toggle selection of subkey with index @code{n}. Use @code{*} to select all and @code{0} to deselect all. @item sign @opindex keyedit:sign Make a signature on key of user @code{name} If the key is not yet signed by the default user (or the users given with -u), the program displays the information of the key again, together with its fingerprint and asks whether it should be signed. This question is repeated for all users specified with -u. @item lsign @opindex keyedit:lsign Same as "sign" but the signature is marked as non-exportable and will therefore never be used by others. This may be used to make keys valid only in the local environment. @item nrsign @opindex keyedit:nrsign Same as "sign" but the signature is marked as non-revocable and can therefore never be revoked. @item tsign @opindex keyedit:tsign Make a trust signature. This is a signature that combines the notions of certification (like a regular signature), and trust (like the "trust" command). It is generally only useful in distinct communities or groups. @end table @c man:.RS Note that "l" (for local / non-exportable), "nr" (for non-revocable, and "t" (for trust) may be freely mixed and prefixed to "sign" to create a signature of any type desired. @c man:.RE @table @asis @item delsig @opindex keyedit:delsig Delete a signature. Note that it is not possible to retract a signature, once it has been send to the public (i.e. to a keyserver). In that case you better use @code{revsig}. @item revsig @opindex keyedit:revsig Revoke a signature. For every signature which has been generated by one of the secret keys, GnuPG asks whether a revocation certificate should be generated. @item check @opindex keyedit:check Check the signatures on all selected user IDs. @item adduid @opindex keyedit:adduid Create an additional user ID. @item addphoto @opindex keyedit:addphoto Create a photographic user ID. This will prompt for a JPEG file that will be embedded into the user ID. Note that a very large JPEG will make for a very large key. Also note that some programs will display your JPEG unchanged (GnuPG), and some programs will scale it to fit in a dialog box (PGP). @item showphoto @opindex keyedit:showphoto Display the selected photographic user ID. @item deluid @opindex keyedit:deluid Delete a user ID or photographic user ID. Note that it is not possible to retract a user id, once it has been send to the public (i.e. to a keyserver). In that case you better use @code{revuid}. @item revuid @opindex keyedit:revuid Revoke a user ID or photographic user ID. @item primary @opindex keyedit:primary Flag the current user id as the primary one, removes the primary user id flag from all other user ids and sets the timestamp of all affected self-signatures one second ahead. Note that setting a photo user ID as primary makes it primary over other photo user IDs, and setting a regular user ID as primary makes it primary over other regular user IDs. @item keyserver @opindex keyedit:keyserver Set a preferred keyserver for the specified user ID(s). This allows other users to know where you prefer they get your key from. See @option{--keyserver-options honor-keyserver-url} for more on how this works. Setting a value of "none" removes an existing preferred keyserver. @item notation @opindex keyedit:notation Set a name=value notation for the specified user ID(s). See @option{--cert-notation} for more on how this works. Setting a value of "none" removes all notations, setting a notation prefixed with a minus sign (-) removes that notation, and setting a notation name (without the =value) prefixed with a minus sign removes all notations with that name. @item pref @opindex keyedit:pref List preferences from the selected user ID. This shows the actual preferences, without including any implied preferences. @item showpref @opindex keyedit:showpref More verbose preferences listing for the selected user ID. This shows the preferences in effect by including the implied preferences of 3DES (cipher), SHA-1 (digest), and Uncompressed (compression) if they are not already included in the preference list. In addition, the preferred keyserver and signature notations (if any) are shown. @item setpref @code{string} @opindex keyedit:setpref Set the list of user ID preferences to @code{string} for all (or just the selected) user IDs. Calling setpref with no arguments sets the preference list to the default (either built-in or set via @option{--default-preference-list}), and calling setpref with "none" as the argument sets an empty preference list. Use @command{@gpgname --version} to get a list of available algorithms. Note that while you can change the preferences on an attribute user ID (aka "photo ID"), GnuPG does not select keys via attribute user IDs so these preferences will not be used by GnuPG. When setting preferences, you should list the algorithms in the order which you'd like to see them used by someone else when encrypting a message to your key. If you don't include 3DES, it will be automatically added at the end. Note that there are many factors that go into choosing an algorithm (for example, your key may not be the only recipient), and so the remote OpenPGP application being used to send to you may or may not follow your exact chosen order for a given message. It will, however, only choose an algorithm that is present on the preference list of every recipient key. See also the INTEROPERABILITY WITH OTHER OPENPGP PROGRAMS section below. @item addkey @opindex keyedit:addkey Add a subkey to this key. @item addcardkey @opindex keyedit:addcardkey Generate a subkey on a card and add it to this key. @item keytocard @opindex keyedit:keytocard Transfer the selected secret subkey (or the primary key if no subkey has been selected) to a smartcard. The secret key in the keyring will be replaced by a stub if the key could be stored successfully on the card and you use the save command later. Only certain key types may be transferred to the card. A sub menu allows you to select on what card to store the key. Note that it is not possible to get that key back from the card - if the card gets broken your secret key will be lost unless you have a backup somewhere. @item bkuptocard @code{file} @opindex keyedit:bkuptocard Restore the given file to a card. This command may be used to restore a backup key (as generated during card initialization) to a new card. In almost all cases this will be the encryption key. You should use this command only with the corresponding public key and make sure that the file given as argument is indeed the backup to restore. You should then select 2 to restore as encryption key. You will first be asked to enter the passphrase of the backup key and then for the Admin PIN of the card. @item delkey @opindex keyedit:delkey Remove a subkey (secondary key). Note that it is not possible to retract a subkey, once it has been send to the public (i.e. to a keyserver). In that case you better use @code{revkey}. @item revkey @opindex keyedit:revkey Revoke a subkey. @item expire @opindex keyedit:expire Change the key or subkey expiration time. If a subkey is selected, the expiration time of this subkey will be changed. With no selection, the key expiration of the primary key is changed. @item trust @opindex keyedit:trust Change the owner trust value for the key. This updates the trust-db immediately and no save is required. @item disable @itemx enable @opindex keyedit:disable @opindex keyedit:enable Disable or enable an entire key. A disabled key can not normally be used for encryption. @item addrevoker @opindex keyedit:addrevoker Add a designated revoker to the key. This takes one optional argument: "sensitive". If a designated revoker is marked as sensitive, it will not be exported by default (see export-options). @item passwd @opindex keyedit:passwd Change the passphrase of the secret key. @item toggle @opindex keyedit:toggle Toggle between public and secret key listing. @item clean @opindex keyedit:clean Compact (by removing all signatures except the selfsig) any user ID that is no longer usable (e.g. revoked, or expired). Then, remove any signatures that are not usable by the trust calculations. Specifically, this removes any signature that does not validate, any signature that is superseded by a later signature, revoked signatures, and signatures issued by keys that are not present on the keyring. @item minimize @opindex keyedit:minimize Make the key as small as possible. This removes all signatures from each user ID except for the most recent self-signature. @item cross-certify @opindex keyedit:cross-certify Add cross-certification signatures to signing subkeys that may not currently have them. Cross-certification signatures protect against a subtle attack against signing subkeys. See @option{--require-cross-certification}. All new keys generated have this signature by default, so this option is only useful to bring older keys up to date. @item save @opindex keyedit:save Save all changes to the key rings and quit. @item quit @opindex keyedit:quit Quit the program without updating the key rings. @end table @c man:.RS The listing shows you the key with its secondary keys and all user ids. The primary user id is indicated by a dot, and selected keys or user ids are indicated by an asterisk. The trust value is displayed with the primary key: the first is the assigned owner trust and the second is the calculated trust value. Letters are used for the values: @c man:.RE @table @asis @item - No ownertrust assigned / not yet calculated. @item e Trust calculation has failed; probably due to an expired key. @item q Not enough information for calculation. @item n Never trust this key. @item m Marginally trusted. @item f Fully trusted. @item u Ultimately trusted. @end table @c ******** End Edit-key Options ********** @item --sign-key @code{name} @opindex sign-key Signs a public key with your secret key. This is a shortcut version of the subcommand "sign" from @option{--edit}. @item --lsign-key @code{name} @opindex lsign-key Signs a public key with your secret key but marks it as non-exportable. This is a shortcut version of the subcommand "lsign" from @option{--edit-key}. @ifset gpgtwoone @item --quick-sign-key @code{fpr} [@code{names}] @itemx --quick-lsign-key @code{fpr} [@code{names}] @opindex quick-sign-key @opindex quick-lsign-key Directly sign a key from the passphrase without any further user interaction. The @code{fpr} must be the verified primary fingerprint of a key in the local keyring. If no @code{names} are given, all useful user ids are signed; with given [@code{names}] only useful user ids matching one of theses names are signed. The command @option{--quick-lsign-key} marks the signatures as non-exportable. If such a non-exportable signature already exists the @option{--quick-sign-key} turns it into a exportable signature. This command uses reasonable defaults and thus does not provide the full flexibility of the "sign" subcommand from @option{--edit-key}. Its intended use is to help unattended key signing by utilizing a list of verified fingerprints. @end ifset +@ifset gpgtwoone +@item --quick-adduid @var{user-id} @var{new-user-id} +@opindex quick-adduid +This command adds a new user id to an existing key. In contrast to +the interactive sub-command @code{adduid} of @option{--edit-key} the +@var{new-user-id} is added verbatim with only leading and trailing +white space removed, it is expected to be UTF-8 encoded, and no checks +on its form are applied. +@end ifset + @item --passwd @var{user_id} @opindex passwd Change the passphrase of the secret key belonging to the certificate specified as @var{user_id}. This is a shortcut for the sub-command @code{passwd} of the edit key menu. @end table @c ******************************************* @c *************** **************** @c *************** OPTIONS **************** @c *************** **************** @c ******************************************* @mansect options @node GPG Options @section Option Summary @command{@gpgname} features a bunch of options to control the exact behaviour and to change the default configuration. @menu * GPG Configuration Options:: How to change the configuration. * GPG Key related Options:: Key related options. * GPG Input and Output:: Input and Output. * OpenPGP Options:: OpenPGP protocol specific options. * Compliance Options:: Compliance options. * GPG Esoteric Options:: Doing things one usually don't want to do. * Deprecated Options:: Deprecated options. @end menu Long options can be put in an options file (default "~/.gnupg/gpg.conf"). Short option names will not work - for example, "armor" is a valid option for the options file, while "a" is not. Do not write the 2 dashes, but simply the name of the option and any required arguments. Lines with a hash ('#') as the first non-white-space character are ignored. Commands may be put in this file too, but that is not generally useful as the command will execute automatically with every execution of gpg. Please remember that option parsing stops as soon as a non-option is encountered, you can explicitly stop parsing by using the special option @option{--}. @c ******************************************* @c ******** CONFIGURATION OPTIONS ********** @c ******************************************* @node GPG Configuration Options @subsection How to change the configuration These options are used to change the configuration and are usually found in the option file. @table @gnupgtabopt @item --default-key @var{name} @opindex default-key Use @var{name} as the default key to sign with. If this option is not used, the default key is the first key found in the secret keyring. Note that @option{-u} or @option{--local-user} overrides this option. @item --default-recipient @var{name} @opindex default-recipient Use @var{name} as default recipient if option @option{--recipient} is not used and don't ask if this is a valid one. @var{name} must be non-empty. @item --default-recipient-self @opindex default-recipient-self Use the default key as default recipient if option @option{--recipient} is not used and don't ask if this is a valid one. The default key is the first one from the secret keyring or the one set with @option{--default-key}. @item --no-default-recipient @opindex no-default-recipient Reset @option{--default-recipient} and @option{--default-recipient-self}. @item -v, --verbose @opindex verbose Give more information during processing. If used twice, the input data is listed in detail. @item --no-verbose @opindex no-verbose Reset verbose level to 0. @item -q, --quiet @opindex quiet Try to be as quiet as possible. @item --batch @itemx --no-batch @opindex batch @opindex no-batch Use batch mode. Never ask, do not allow interactive commands. @option{--no-batch} disables this option. Note that even with a filename given on the command line, gpg might still need to read from STDIN (in particular if gpg figures that the input is a detached signature and no data file has been specified). Thus if you do not want to feed data via STDIN, you should connect STDIN to @file{/dev/null}. @item --no-tty @opindex no-tty Make sure that the TTY (terminal) is never used for any output. This option is needed in some cases because GnuPG sometimes prints warnings to the TTY even if @option{--batch} is used. @item --yes @opindex yes Assume "yes" on most questions. @item --no @opindex no Assume "no" on most questions. @item --list-options @code{parameters} @opindex list-options This is a space or comma delimited string that gives options used when listing keys and signatures (that is, @option{--list-keys}, @option{--list-sigs}, @option{--list-public-keys}, @option{--list-secret-keys}, and the @option{--edit-key} functions). Options can be prepended with a @option{no-} (after the two dashes) to give the opposite meaning. The options are: @table @asis @item show-photos @opindex list-options:show-photos Causes @option{--list-keys}, @option{--list-sigs}, @option{--list-public-keys}, and @option{--list-secret-keys} to display any photo IDs attached to the key. Defaults to no. See also @option{--photo-viewer}. Does not work with @option{--with-colons}: see @option{--attribute-fd} for the appropriate way to get photo data for scripts and other frontends. @item show-usage @opindex list-options:show-usage Show usage information for keys and subkeys in the standard key listing. This is a list of letters indicating the allowed usage for a key (@code{E}=encryption, @code{S}=signing, @code{C}=certification, @code{A}=authentication). Defaults to no. @item show-policy-urls @opindex list-options:show-policy-urls Show policy URLs in the @option{--list-sigs} or @option{--check-sigs} listings. Defaults to no. @item show-notations @itemx show-std-notations @itemx show-user-notations @opindex list-options:show-notations @opindex list-options:show-std-notations @opindex list-options:show-user-notations Show all, IETF standard, or user-defined signature notations in the @option{--list-sigs} or @option{--check-sigs} listings. Defaults to no. @item show-keyserver-urls @opindex list-options:show-keyserver-urls Show any preferred keyserver URL in the @option{--list-sigs} or @option{--check-sigs} listings. Defaults to no. @item show-uid-validity @opindex list-options:show-uid-validity Display the calculated validity of user IDs during key listings. Defaults to no. @item show-unusable-uids @opindex list-options:show-unusable-uids Show revoked and expired user IDs in key listings. Defaults to no. @item show-unusable-subkeys @opindex list-options:show-unusable-subkeys Show revoked and expired subkeys in key listings. Defaults to no. @item show-keyring @opindex list-options:show-keyring Display the keyring name at the head of key listings to show which keyring a given key resides on. Defaults to no. @item show-sig-expire @opindex list-options:show-sig-expire Show signature expiration dates (if any) during @option{--list-sigs} or @option{--check-sigs} listings. Defaults to no. @item show-sig-subpackets @opindex list-options:show-sig-subpackets Include signature subpackets in the key listing. This option can take an optional argument list of the subpackets to list. If no argument is passed, list all subpackets. Defaults to no. This option is only meaningful when using @option{--with-colons} along with @option{--list-sigs} or @option{--check-sigs}. @end table @item --verify-options @code{parameters} @opindex verify-options This is a space or comma delimited string that gives options used when verifying signatures. Options can be prepended with a `no-' to give the opposite meaning. The options are: @table @asis @item show-photos @opindex verify-options:show-photos Display any photo IDs present on the key that issued the signature. Defaults to no. See also @option{--photo-viewer}. @item show-policy-urls @opindex verify-options:show-policy-urls Show policy URLs in the signature being verified. Defaults to no. @item show-notations @itemx show-std-notations @itemx show-user-notations @opindex verify-options:show-notations @opindex verify-options:show-std-notations @opindex verify-options:show-user-notations Show all, IETF standard, or user-defined signature notations in the signature being verified. Defaults to IETF standard. @item show-keyserver-urls @opindex verify-options:show-keyserver-urls Show any preferred keyserver URL in the signature being verified. Defaults to no. @item show-uid-validity @opindex verify-options:show-uid-validity Display the calculated validity of the user IDs on the key that issued the signature. Defaults to no. @item show-unusable-uids @opindex verify-options:show-unusable-uids Show revoked and expired user IDs during signature verification. Defaults to no. @item show-primary-uid-only @opindex verify-options:show-primary-uid-only Show only the primary user ID during signature verification. That is all the AKA lines as well as photo Ids are not shown with the signature verification status. @item pka-lookups @opindex verify-options:pka-lookups Enable PKA lookups to verify sender addresses. Note that PKA is based on DNS, and so enabling this option may disclose information on when and what signatures are verified or to whom data is encrypted. This is similar to the "web bug" described for the auto-key-retrieve feature. @item pka-trust-increase @opindex verify-options:pka-trust-increase Raise the trust in a signature to full if the signature passes PKA validation. This option is only meaningful if pka-lookups is set. @end table @item --enable-large-rsa @itemx --disable-large-rsa @opindex enable-large-rsa @opindex disable-large-rsa With --gen-key and --batch, enable the creation of larger RSA secret keys than is generally recommended (up to 8192 bits). These large keys are more expensive to use, and their signatures and certifications are also larger. @item --enable-dsa2 @itemx --disable-dsa2 @opindex enable-dsa2 @opindex disable-dsa2 Enable hash truncation for all DSA keys even for old DSA Keys up to 1024 bit. This is also the default with @option{--openpgp}. Note that older versions of GnuPG also required this flag to allow the generation of DSA larger than 1024 bit. @item --photo-viewer @code{string} @opindex photo-viewer This is the command line that should be run to view a photo ID. "%i" will be expanded to a filename containing the photo. "%I" does the same, except the file will not be deleted once the viewer exits. Other flags are "%k" for the key ID, "%K" for the long key ID, "%f" for the key fingerprint, "%t" for the extension of the image type (e.g. "jpg"), "%T" for the MIME type of the image (e.g. "image/jpeg"), "%v" for the single-character calculated validity of the image being viewed (e.g. "f"), "%V" for the calculated validity as a string (e.g. "full"), "%U" for a base32 encoded hash of the user ID, and "%%" for an actual percent sign. If neither %i or %I are present, then the photo will be supplied to the viewer on standard input. The default viewer is "xloadimage -fork -quiet -title 'KeyID 0x%k' STDIN". Note that if your image viewer program is not secure, then executing it from GnuPG does not make it secure. @item --exec-path @code{string} @opindex exec-path Sets a list of directories to search for photo viewers and keyserver helpers. If not provided, keyserver helpers use the compiled-in default directory, and photo viewers use the $PATH environment variable. Note, that on W32 system this value is ignored when searching for keyserver helpers. @item --keyring @code{file} @opindex keyring Add @code{file} to the current list of keyrings. If @code{file} begins with a tilde and a slash, these are replaced by the $HOME directory. If the filename does not contain a slash, it is assumed to be in the GnuPG home directory ("~/.gnupg" if @option{--homedir} or $GNUPGHOME is not used). Note that this adds a keyring to the current list. If the intent is to use the specified keyring alone, use @option{--keyring} along with @option{--no-default-keyring}. @item --secret-keyring @code{file} @opindex secret-keyring @ifset gpgtwoone This is an obsolete option and ignored. All secret keys are stored in the @file{private-keys-v1.d} directory below the GnuPG home directory. @end ifset @ifclear gpgtwoone Same as @option{--keyring} but for the secret keyrings. @end ifclear @item --primary-keyring @code{file} @opindex primary-keyring Designate @code{file} as the primary public keyring. This means that newly imported keys (via @option{--import} or keyserver @option{--recv-from}) will go to this keyring. @item --trustdb-name @code{file} @opindex trustdb-name Use @code{file} instead of the default trustdb. If @code{file} begins with a tilde and a slash, these are replaced by the $HOME directory. If the filename does not contain a slash, it is assumed to be in the GnuPG home directory (@file{~/.gnupg} if @option{--homedir} or $GNUPGHOME is not used). @include opt-homedir.texi @item --display-charset @code{name} @opindex display-charset Set the name of the native character set. This is used to convert some informational strings like user IDs to the proper UTF-8 encoding. Note that this has nothing to do with the character set of data to be encrypted or signed; GnuPG does not recode user-supplied data. If this option is not used, the default character set is determined from the current locale. A verbosity level of 3 shows the chosen set. Valid values for @code{name} are: @table @asis @item iso-8859-1 @opindex display-charset:iso-8859-1 This is the Latin 1 set. @item iso-8859-2 @opindex display-charset:iso-8859-2 The Latin 2 set. @item iso-8859-15 @opindex display-charset:iso-8859-15 This is currently an alias for the Latin 1 set. @item koi8-r @opindex display-charset:koi8-r The usual Russian set (rfc1489). @item utf-8 @opindex display-charset:utf-8 Bypass all translations and assume that the OS uses native UTF-8 encoding. @end table @item --utf8-strings @itemx --no-utf8-strings @opindex utf8-strings Assume that command line arguments are given as UTF8 strings. The default (@option{--no-utf8-strings}) is to assume that arguments are encoded in the character set as specified by @option{--display-charset}. These options affect all following arguments. Both options may be used multiple times. @anchor{gpg-option --options} @item --options @code{file} @opindex options Read options from @code{file} and do not try to read them from the default options file in the homedir (see @option{--homedir}). This option is ignored if used in an options file. @item --no-options @opindex no-options Shortcut for @option{--options /dev/null}. This option is detected before an attempt to open an option file. Using this option will also prevent the creation of a @file{~/.gnupg} homedir. @item -z @code{n} @itemx --compress-level @code{n} @itemx --bzip2-compress-level @code{n} @opindex compress-level @opindex bzip2-compress-level Set compression level to @code{n} for the ZIP and ZLIB compression algorithms. The default is to use the default compression level of zlib (normally 6). @option{--bzip2-compress-level} sets the compression level for the BZIP2 compression algorithm (defaulting to 6 as well). This is a different option from @option{--compress-level} since BZIP2 uses a significant amount of memory for each additional compression level. @option{-z} sets both. A value of 0 for @code{n} disables compression. @item --bzip2-decompress-lowmem @opindex bzip2-decompress-lowmem Use a different decompression method for BZIP2 compressed files. This alternate method uses a bit more than half the memory, but also runs at half the speed. This is useful under extreme low memory circumstances when the file was originally compressed at a high @option{--bzip2-compress-level}. @item --mangle-dos-filenames @itemx --no-mangle-dos-filenames @opindex mangle-dos-filenames @opindex no-mangle-dos-filenames Older version of Windows cannot handle filenames with more than one dot. @option{--mangle-dos-filenames} causes GnuPG to replace (rather than add to) the extension of an output filename to avoid this problem. This option is off by default and has no effect on non-Windows platforms. @item --ask-cert-level @itemx --no-ask-cert-level @opindex ask-cert-level When making a key signature, prompt for a certification level. If this option is not specified, the certification level used is set via @option{--default-cert-level}. See @option{--default-cert-level} for information on the specific levels and how they are used. @option{--no-ask-cert-level} disables this option. This option defaults to no. @item --default-cert-level @code{n} @opindex default-cert-level The default to use for the check level when signing a key. 0 means you make no particular claim as to how carefully you verified the key. 1 means you believe the key is owned by the person who claims to own it but you could not, or did not verify the key at all. This is useful for a "persona" verification, where you sign the key of a pseudonymous user. 2 means you did casual verification of the key. For example, this could mean that you verified the key fingerprint and checked the user ID on the key against a photo ID. 3 means you did extensive verification of the key. For example, this could mean that you verified the key fingerprint with the owner of the key in person, and that you checked, by means of a hard to forge document with a photo ID (such as a passport) that the name of the key owner matches the name in the user ID on the key, and finally that you verified (by exchange of email) that the email address on the key belongs to the key owner. Note that the examples given above for levels 2 and 3 are just that: examples. In the end, it is up to you to decide just what "casual" and "extensive" mean to you. This option defaults to 0 (no particular claim). @item --min-cert-level @opindex min-cert-level When building the trust database, treat any signatures with a certification level below this as invalid. Defaults to 2, which disregards level 1 signatures. Note that level 0 "no particular claim" signatures are always accepted. @item --trusted-key @code{long key ID} @opindex trusted-key Assume that the specified key (which must be given as a full 8 byte key ID) is as trustworthy as one of your own secret keys. This option is useful if you don't want to keep your secret keys (or one of them) online but still want to be able to check the validity of a given recipient's or signator's key. @item --trust-model @code{pgp|classic|direct|always|auto} @opindex trust-model Set what trust model GnuPG should follow. The models are: @table @asis @item pgp @opindex trust-mode:pgp This is the Web of Trust combined with trust signatures as used in PGP 5.x and later. This is the default trust model when creating a new trust database. @item classic @opindex trust-mode:classic This is the standard Web of Trust as introduced by PGP 2. @item direct @opindex trust-mode:direct Key validity is set directly by the user and not calculated via the Web of Trust. @item always @opindex trust-mode:always Skip key validation and assume that used keys are always fully valid. You generally won't use this unless you are using some external validation scheme. This option also suppresses the "[uncertain]" tag printed with signature checks when there is no evidence that the user ID is bound to the key. Note that this trust model still does not allow the use of expired, revoked, or disabled keys. @item auto @opindex trust-mode:auto Select the trust model depending on whatever the internal trust database says. This is the default model if such a database already exists. @end table @item --auto-key-locate @code{parameters} @itemx --no-auto-key-locate @opindex auto-key-locate GnuPG can automatically locate and retrieve keys as needed using this option. This happens when encrypting to an email address (in the "user@@example.com" form), and there are no user@@example.com keys on the local keyring. This option takes any number of the following mechanisms, in the order they are to be tried: @table @asis @item cert Locate a key using DNS CERT, as specified in rfc4398. @item pka Locate a key using DNS PKA. @item ldap Using DNS Service Discovery, check the domain in question for any LDAP keyservers to use. If this fails, attempt to locate the key using the PGP Universal method of checking @samp{ldap://keys.(thedomain)}. @item keyserver Locate a key using whatever keyserver is defined using the @option{--keyserver} option. @item keyserver-URL In addition, a keyserver URL as used in the @option{--keyserver} option may be used here to query that particular keyserver. @item local Locate the key using the local keyrings. This mechanism allows to select the order a local key lookup is done. Thus using @samp{--auto-key-locate local} is identical to @option{--no-auto-key-locate}. @item nodefault This flag disables the standard local key lookup, done before any of the mechanisms defined by the @option{--auto-key-locate} are tried. The position of this mechanism in the list does not matter. It is not required if @code{local} is also used. @item clear Clear all defined mechanisms. This is useful to override mechanisms given in a config file. @end table @item --keyid-format @code{short|0xshort|long|0xlong} @opindex keyid-format Select how to display key IDs. "short" is the traditional 8-character key ID. "long" is the more accurate (but less convenient) 16-character key ID. Add an "0x" to either to include an "0x" at the beginning of the key ID, as in 0x99242560. Note that this option is ignored if the option --with-colons is used. @item --keyserver @code{name} @opindex keyserver Use @code{name} as your keyserver. This is the server that @option{--recv-keys}, @option{--send-keys}, and @option{--search-keys} will communicate with to receive keys from, send keys to, and search for keys on. The format of the @code{name} is a URI: `scheme:[//]keyservername[:port]' The scheme is the type of keyserver: "hkp" for the HTTP (or compatible) keyservers, "ldap" for the LDAP keyservers, or "mailto" for the Graff email keyserver. Note that your particular installation of GnuPG may have other keyserver types available as well. Keyserver schemes are case-insensitive. After the keyserver name, optional keyserver configuration options may be provided. These are the same as the global @option{--keyserver-options} from below, but apply only to this particular keyserver. Most keyservers synchronize with each other, so there is generally no need to send keys to more than one server. The keyserver @code{hkp://keys.gnupg.net} uses round robin DNS to give a different keyserver each time you use it. @item --keyserver-options @code{name=value} @opindex keyserver-options This is a space or comma delimited string that gives options for the keyserver. Options can be prefixed with a `no-' to give the opposite meaning. Valid import-options or export-options may be used here as well to apply to importing (@option{--recv-key}) or exporting (@option{--send-key}) a key from a keyserver. While not all options are available for all keyserver types, some common options are: @table @asis @item include-revoked When searching for a key with @option{--search-keys}, include keys that are marked on the keyserver as revoked. Note that not all keyservers differentiate between revoked and unrevoked keys, and for such keyservers this option is meaningless. Note also that most keyservers do not have cryptographic verification of key revocations, and so turning this option off may result in skipping keys that are incorrectly marked as revoked. @item include-disabled When searching for a key with @option{--search-keys}, include keys that are marked on the keyserver as disabled. Note that this option is not used with HKP keyservers. @item auto-key-retrieve This option enables the automatic retrieving of keys from a keyserver when verifying signatures made by keys that are not on the local keyring. Note that this option makes a "web bug" like behavior possible. Keyserver operators can see which keys you request, so by sending you a message signed by a brand new key (which you naturally will not have on your local keyring), the operator can tell both your IP address and the time when you verified the signature. @item honor-keyserver-url When using @option{--refresh-keys}, if the key in question has a preferred keyserver URL, then use that preferred keyserver to refresh the key from. In addition, if auto-key-retrieve is set, and the signature being verified has a preferred keyserver URL, then use that preferred keyserver to fetch the key from. Note that this option introduces a "web bug": The creator of the key can see when the keys is refreshed. Thus this option is not enabled by default. @item honor-pka-record If auto-key-retrieve is set, and the signature being verified has a PKA record, then use the PKA information to fetch the key. Defaults to "yes". @item include-subkeys When receiving a key, include subkeys as potential targets. Note that this option is not used with HKP keyservers, as they do not support retrieving keys by subkey id. @ifclear gpgtwoone @item use-temp-files On most Unix-like platforms, GnuPG communicates with the keyserver helper program via pipes, which is the most efficient method. This option forces GnuPG to use temporary files to communicate. On some platforms (such as Win32 and RISC OS), this option is always enabled. @end ifclear @ifclear gpgtwoone @item keep-temp-files If using `use-temp-files', do not delete the temp files after using them. This option is useful to learn the keyserver communication protocol by reading the temporary files. @end ifclear @item timeout Tell the keyserver helper program how long (in seconds) to try and perform a keyserver action before giving up. Note that performing multiple actions at the same time uses this timeout value per action. For example, when retrieving multiple keys via @option{--recv-keys}, the timeout applies separately to each key retrieval, and not to the @option{--recv-keys} command as a whole. Defaults to 30 seconds. @item http-proxy=@code{value} Set the proxy to use for HTTP and HKP keyservers. @ifset gpgtwoone This overrides any proxy defined in @file{dirmngr.conf}. @end ifset @ifclear gpgtwoone This overrides the "http_proxy" environment variable, if any. @end ifclear @ifclear gpgtwoone @item max-cert-size When retrieving a key via DNS CERT, only accept keys up to this size. Defaults to 16384 bytes. @end ifclear @item verbose @ifset gpgtwoone This option has no more function since GnuPG 2.1. Use the @code{dirmngr} configuration options instead. @end ifset @ifclear gpgtwoone Tell the keyserver helper program to be more verbose. This option can be repeated multiple times to increase the verbosity level. @end ifclear @item debug @ifset gpgtwoone This option has no more function since GnuPG 2.1. Use the @code{dirmngr} configuration options instead. @end ifset @ifclear gpgtwoone Turn on debug output in the keyserver helper program. Note that the details of debug output depends on which keyserver helper program is being used, and in turn, on any libraries that the keyserver helper program uses internally (libcurl, openldap, etc). @end ifclear @item check-cert @ifset gpgtwoone This option has no more function since GnuPG 2.1. Use the @code{dirmngr} configuration options instead. @end ifset @ifclear gpgtwoone Enable certificate checking if the keyserver presents one (for hkps or ldaps). Defaults to on. @end ifclear @item ca-cert-file @ifset gpgtwoone This option has no more function since GnuPG 2.1. Use the @code{dirmngr} configuration options instead. @end ifset @ifclear gpgtwoone Provide a certificate store to override the system default. Only necessary if check-cert is enabled, and the keyserver is using a certificate that is not present in a system default certificate list. Note that depending on the SSL library that the keyserver helper is built with, this may actually be a directory or a file. @end ifclear @end table @item --completes-needed @code{n} @opindex compliant-needed Number of completely trusted users to introduce a new key signer (defaults to 1). @item --marginals-needed @code{n} @opindex marginals-needed Number of marginally trusted users to introduce a new key signer (defaults to 3) @item --max-cert-depth @code{n} @opindex max-cert-depth Maximum depth of a certification chain (default is 5). @ifclear gpgtwoone @item --simple-sk-checksum @opindex simple-sk-checksum Secret keys are integrity protected by using a SHA-1 checksum. This method is part of the upcoming enhanced OpenPGP specification but GnuPG already uses it as a countermeasure against certain attacks. Old applications don't understand this new format, so this option may be used to switch back to the old behaviour. Using this option bears a security risk. Note that using this option only takes effect when the secret key is encrypted - the simplest way to make this happen is to change the passphrase on the key (even changing it to the same value is acceptable). @end ifclear @item --no-sig-cache @opindex no-sig-cache Do not cache the verification status of key signatures. Caching gives a much better performance in key listings. However, if you suspect that your public keyring is not save against write modifications, you can use this option to disable the caching. It probably does not make sense to disable it because all kind of damage can be done if someone else has write access to your public keyring. @item --no-sig-create-check @opindex no-sig-create-check GnuPG normally verifies each signature right after creation to protect against bugs and hardware malfunctions which could leak out bits from the secret key. This extra verification needs some time (about 115% for DSA keys), and so this option can be used to disable it. However, due to the fact that the signature creation needs manual interaction, this performance penalty does not matter in most settings. @item --auto-check-trustdb @itemx --no-auto-check-trustdb @opindex auto-check-trustdb If GnuPG feels that its information about the Web of Trust has to be updated, it automatically runs the @option{--check-trustdb} command internally. This may be a time consuming process. @option{--no-auto-check-trustdb} disables this option. @item --use-agent @itemx --no-use-agent @opindex use-agent This is dummy option. @command{@gpgname} always requires the agent. @item --gpg-agent-info @opindex gpg-agent-info This is dummy option. It has no effect when used with @command{gpg2}. @item --agent-program @var{file} @opindex agent-program Specify an agent program to be used for secret key operations. The default value is determined by running @command{gpgconf} with the option @option{--list-dirs}. Note that the pipe symbol (@code{|}) is used for a regression test suite hack and may thus not be used in the file name. @ifclear gpgtwoone This is only used as a fallback when the environment variable @code{GPG_AGENT_INFO} is not set or a running agent cannot be connected. @end ifclear @ifset gpgtwoone @item --dirmngr-program @var{file} @opindex dirmngr-program Specify a dirmngr program to be used for keyserver access. The default value is @file{/usr/sbin/dirmngr}. This is only used as a fallback when the environment variable @code{DIRMNGR_INFO} is not set or a running dirmngr cannot be connected. @end ifset @item --no-autostart @opindex no-autostart Do not start the gpg-agent or the dirmngr if it has not yet been started and its service is required. This option is mostly useful on machines where the connection to gpg-agent has been redirected to another machines. If dirmngr is required on the remote machine, it may be started manually using @command{gpgconf --launch dirmngr}. @item --lock-once @opindex lock-once Lock the databases the first time a lock is requested and do not release the lock until the process terminates. @item --lock-multiple @opindex lock-multiple Release the locks every time a lock is no longer needed. Use this to override a previous @option{--lock-once} from a config file. @item --lock-never @opindex lock-never Disable locking entirely. This option should be used only in very special environments, where it can be assured that only one process is accessing those files. A bootable floppy with a stand-alone encryption system will probably use this. Improper usage of this option may lead to data and key corruption. @item --exit-on-status-write-error @opindex exit-on-status-write-error This option will cause write errors on the status FD to immediately terminate the process. That should in fact be the default but it never worked this way and thus we need an option to enable this, so that the change won't break applications which close their end of a status fd connected pipe too early. Using this option along with @option{--enable-progress-filter} may be used to cleanly cancel long running gpg operations. @item --limit-card-insert-tries @code{n} @opindex limit-card-insert-tries With @code{n} greater than 0 the number of prompts asking to insert a smartcard gets limited to N-1. Thus with a value of 1 gpg won't at all ask to insert a card if none has been inserted at startup. This option is useful in the configuration file in case an application does not know about the smartcard support and waits ad infinitum for an inserted card. @item --no-random-seed-file @opindex no-random-seed-file GnuPG uses a file to store its internal random pool over invocations. This makes random generation faster; however sometimes write operations are not desired. This option can be used to achieve that with the cost of slower random generation. @item --no-greeting @opindex no-greeting Suppress the initial copyright message. @item --no-secmem-warning @opindex no-secmem-warning Suppress the warning about "using insecure memory". @item --no-permission-warning @opindex permission-warning Suppress the warning about unsafe file and home directory (@option{--homedir}) permissions. Note that the permission checks that GnuPG performs are not intended to be authoritative, but rather they simply warn about certain common permission problems. Do not assume that the lack of a warning means that your system is secure. Note that the warning for unsafe @option{--homedir} permissions cannot be suppressed in the gpg.conf file, as this would allow an attacker to place an unsafe gpg.conf file in place, and use this file to suppress warnings about itself. The @option{--homedir} permissions warning may only be suppressed on the command line. @item --no-mdc-warning @opindex no-mdc-warning Suppress the warning about missing MDC integrity protection. @item --require-secmem @itemx --no-require-secmem @opindex require-secmem Refuse to run if GnuPG cannot get secure memory. Defaults to no (i.e. run, but give a warning). @item --require-cross-certification @itemx --no-require-cross-certification @opindex require-cross-certification When verifying a signature made from a subkey, ensure that the cross certification "back signature" on the subkey is present and valid. This protects against a subtle attack against subkeys that can sign. Defaults to @option{--require-cross-certification} for @command{@gpgname}. @item --expert @itemx --no-expert @opindex expert Allow the user to do certain nonsensical or "silly" things like signing an expired or revoked key, or certain potentially incompatible things like generating unusual key types. This also disables certain warning messages about potentially incompatible actions. As the name implies, this option is for experts only. If you don't fully understand the implications of what it allows you to do, leave this off. @option{--no-expert} disables this option. @end table @c ******************************************* @c ******** KEY RELATED OPTIONS ************ @c ******************************************* @node GPG Key related Options @subsection Key related options @table @gnupgtabopt @item --recipient @var{name} @itemx -r @opindex recipient Encrypt for user id @var{name}. If this option or @option{--hidden-recipient} is not specified, GnuPG asks for the user-id unless @option{--default-recipient} is given. @item --hidden-recipient @var{name} @itemx -R @opindex hidden-recipient Encrypt for user ID @var{name}, but hide the key ID of this user's key. This option helps to hide the receiver of the message and is a limited countermeasure against traffic analysis. If this option or @option{--recipient} is not specified, GnuPG asks for the user ID unless @option{--default-recipient} is given. @item --encrypt-to @code{name} @opindex encrypt-to Same as @option{--recipient} but this one is intended for use in the options file and may be used with your own user-id as an "encrypt-to-self". These keys are only used when there are other recipients given either by use of @option{--recipient} or by the asked user id. No trust checking is performed for these user ids and even disabled keys can be used. @item --hidden-encrypt-to @code{name} @opindex hidden-encrypt-to Same as @option{--hidden-recipient} but this one is intended for use in the options file and may be used with your own user-id as a hidden "encrypt-to-self". These keys are only used when there are other recipients given either by use of @option{--recipient} or by the asked user id. No trust checking is performed for these user ids and even disabled keys can be used. @item --no-encrypt-to @opindex no-encrypt-to Disable the use of all @option{--encrypt-to} and @option{--hidden-encrypt-to} keys. @item --group @code{name=value1 } @opindex group Sets up a named group, which is similar to aliases in email programs. Any time the group name is a recipient (@option{-r} or @option{--recipient}), it will be expanded to the values specified. Multiple groups with the same name are automatically merged into a single group. The values are @code{key IDs} or fingerprints, but any key description is accepted. Note that a value with spaces in it will be treated as two different values. Note also there is only one level of expansion --- you cannot make an group that points to another group. When used from the command line, it may be necessary to quote the argument to this option to prevent the shell from treating it as multiple arguments. @item --ungroup @code{name} @opindex ungroup Remove a given entry from the @option{--group} list. @item --no-groups @opindex no-groups Remove all entries from the @option{--group} list. @item --local-user @var{name} @itemx -u @opindex local-user Use @var{name} as the key to sign with. Note that this option overrides @option{--default-key}. @ifset gpgtwoone @item --try-secret-key @var{name} @opindex try-secret-key For hidden recipients GPG needs to know the keys to use for trial decryption. The key set with @option{--default-key} is always tried first, but this is often not sufficient. This option allows to set more keys to be used for trial decryption. Although any valid user-id specification may be used for @var{name} it makes sense to use at least the long keyid to avoid ambiguities. Note that gpg-agent might pop up a pinentry for a lot keys to do the trial decryption. If you want to stop all further trial decryption you may use close-window button instead of the cancel button. @end ifset @item --try-all-secrets @opindex try-all-secrets Don't look at the key ID as stored in the message but try all secret keys in turn to find the right decryption key. This option forces the behaviour as used by anonymous recipients (created by using @option{--throw-keyids} or @option{--hidden-recipient}) and might come handy in case where an encrypted message contains a bogus key ID. @item --skip-hidden-recipients @itemx --no-skip-hidden-recipients @opindex skip-hidden-recipients @opindex no-skip-hidden-recipients During decryption skip all anonymous recipients. This option helps in the case that people use the hidden recipients feature to hide there own encrypt-to key from others. If oneself has many secret keys this may lead to a major annoyance because all keys are tried in turn to decrypt something which was not really intended for it. The drawback of this option is that it is currently not possible to decrypt a message which includes real anonymous recipients. @end table @c ******************************************* @c ******** INPUT AND OUTPUT *************** @c ******************************************* @node GPG Input and Output @subsection Input and Output @table @gnupgtabopt @item --armor @itemx -a @opindex armor Create ASCII armored output. The default is to create the binary OpenPGP format. @item --no-armor @opindex no-armor Assume the input data is not in ASCII armored format. @item --output @var{file} @itemx -o @var{file} @opindex output Write output to @var{file}. @item --max-output @code{n} @opindex max-output This option sets a limit on the number of bytes that will be generated when processing a file. Since OpenPGP supports various levels of compression, it is possible that the plaintext of a given message may be significantly larger than the original OpenPGP message. While GnuPG works properly with such messages, there is often a desire to set a maximum file size that will be generated before processing is forced to stop by the OS limits. Defaults to 0, which means "no limit". @item --import-options @code{parameters} @opindex import-options This is a space or comma delimited string that gives options for importing keys. Options can be prepended with a `no-' to give the opposite meaning. The options are: @table @asis @item import-local-sigs Allow importing key signatures marked as "local". This is not generally useful unless a shared keyring scheme is being used. Defaults to no. @item keep-ownertrust Normally possible still existing ownertrust values of a key are cleared if a key is imported. This is in general desirable so that a formerly deleted key does not automatically gain an ownertrust values merely due to import. On the other hand it is sometimes necessary to re-import a trusted set of keys again but keeping already assigned ownertrust values. This can be achived by using this option. @item repair-pks-subkey-bug During import, attempt to repair the damage caused by the PKS keyserver bug (pre version 0.9.6) that mangles keys with multiple subkeys. Note that this cannot completely repair the damaged key as some crucial data is removed by the keyserver, but it does at least give you back one subkey. Defaults to no for regular @option{--import} and to yes for keyserver @option{--recv-keys}. @item merge-only During import, allow key updates to existing keys, but do not allow any new keys to be imported. Defaults to no. @item import-clean After import, compact (remove all signatures except the self-signature) any user IDs from the new key that are not usable. Then, remove any signatures from the new key that are not usable. This includes signatures that were issued by keys that are not present on the keyring. This option is the same as running the @option{--edit-key} command "clean" after import. Defaults to no. @item import-minimal Import the smallest key possible. This removes all signatures except the most recent self-signature on each user ID. This option is the same as running the @option{--edit-key} command "minimize" after import. Defaults to no. @end table @item --export-options @code{parameters} @opindex export-options This is a space or comma delimited string that gives options for exporting keys. Options can be prepended with a `no-' to give the opposite meaning. The options are: @table @asis @item export-local-sigs Allow exporting key signatures marked as "local". This is not generally useful unless a shared keyring scheme is being used. Defaults to no. @item export-attributes Include attribute user IDs (photo IDs) while exporting. This is useful to export keys if they are going to be used by an OpenPGP program that does not accept attribute user IDs. Defaults to yes. @item export-sensitive-revkeys Include designated revoker information that was marked as "sensitive". Defaults to no. @c Since GnuPG 2.1 gpg-agent manages the secret key and thus the @c export-reset-subkey-passwd hack is not anymore justified. Such use @c cases need to be implemented using a specialized secret key export @c tool. @ifclear gpgtwoone @item export-reset-subkey-passwd When using the @option{--export-secret-subkeys} command, this option resets the passphrases for all exported subkeys to empty. This is useful when the exported subkey is to be used on an unattended machine where a passphrase doesn't necessarily make sense. Defaults to no. @end ifclear @item export-clean Compact (remove all signatures from) user IDs on the key being exported if the user IDs are not usable. Also, do not export any signatures that are not usable. This includes signatures that were issued by keys that are not present on the keyring. This option is the same as running the @option{--edit-key} command "clean" before export except that the local copy of the key is not modified. Defaults to no. @item export-minimal Export the smallest key possible. This removes all signatures except the most recent self-signature on each user ID. This option is the same as running the @option{--edit-key} command "minimize" before export except that the local copy of the key is not modified. Defaults to no. @end table @item --with-colons @opindex with-colons Print key listings delimited by colons. Note that the output will be encoded in UTF-8 regardless of any @option{--display-charset} setting. This format is useful when GnuPG is called from scripts and other programs as it is easily machine parsed. The details of this format are documented in the file @file{doc/DETAILS}, which is included in the GnuPG source distribution. @item --print-pka-records @opindex print-pka-records Modify the output of the list commands to print PKA records suitable to put into DNS zone files. An ORIGIN line is printed before each record to allow diverting the records to the corresponding zone file. @item --fixed-list-mode @opindex fixed-list-mode Do not merge primary user ID and primary key in @option{--with-colon} listing mode and print all timestamps as seconds since 1970-01-01. Since GnuPG 2.0.10, this mode is always used and thus this option is obsolete; it does not harm to use it though. @ifset gpgtwoone @item --legacy-list-mode @opindex legacy-list-mode Revert to the pre-2.1 public key list mode. This only affects the human readable output and not the machine interface (i.e. @code{--with-colons}). Note that the legacy format does not allow to convey suitable information for elliptic curves. @end ifset @item --with-fingerprint @opindex with-fingerprint Same as the command @option{--fingerprint} but changes only the format of the output and may be used together with another command. @ifset gpgtwoone @item --with-icao-spelling @opindex with-icao-spelling Print the ICAO spelling of the fingerprint in addition to the hex digits. @item --with-keygrip @opindex with-keygrip Include the keygrip in the key listings. @item --with-secret @opindex with-secret Include info about the presence of a secret key in public key listings done with @code{--with-colons}. @end ifset @end table @c ******************************************* @c ******** OPENPGP OPTIONS **************** @c ******************************************* @node OpenPGP Options @subsection OpenPGP protocol specific options. @table @gnupgtabopt @item -t, --textmode @itemx --no-textmode @opindex textmode Treat input files as text and store them in the OpenPGP canonical text form with standard "CRLF" line endings. This also sets the necessary flags to inform the recipient that the encrypted or signed data is text and may need its line endings converted back to whatever the local system uses. This option is useful when communicating between two platforms that have different line ending conventions (UNIX-like to Mac, Mac to Windows, etc). @option{--no-textmode} disables this option, and is the default. @ifclear gpgtwoone @item --force-v3-sigs @itemx --no-force-v3-sigs @opindex force-v3-sigs OpenPGP states that an implementation should generate v4 signatures but PGP versions 5 through 7 only recognize v4 signatures on key material. This option forces v3 signatures for signatures on data. Note that this option implies @option{--no-ask-sig-expire}, and unsets @option{--sig-policy-url}, @option{--sig-notation}, and @option{--sig-keyserver-url}, as these features cannot be used with v3 signatures. @option{--no-force-v3-sigs} disables this option. Defaults to no. @item --force-v4-certs @itemx --no-force-v4-certs @opindex force-v4-certs Always use v4 key signatures even on v3 keys. This option also changes the default hash algorithm for v3 RSA keys from MD5 to SHA-1. @option{--no-force-v4-certs} disables this option. @end ifclear @ifset gpgtwoone @item --force-v3-sigs @itemx --no-force-v3-sigs @item --force-v4-certs @itemx --no-force-v4-certs These options are obsolete and have no effect since GnuPG 2.1. @end ifset @item --force-mdc @opindex force-mdc Force the use of encryption with a modification detection code. This is always used with the newer ciphers (those with a blocksize greater than 64 bits), or if all of the recipient keys indicate MDC support in their feature flags. @item --disable-mdc @opindex disable-mdc Disable the use of the modification detection code. Note that by using this option, the encrypted message becomes vulnerable to a message modification attack. @item --personal-cipher-preferences @code{string} @opindex personal-cipher-preferences Set the list of personal cipher preferences to @code{string}. Use @command{@gpgname --version} to get a list of available algorithms, and use @code{none} to set no preference at all. This allows the user to safely override the algorithm chosen by the recipient key preferences, as GPG will only select an algorithm that is usable by all recipients. The most highly ranked cipher in this list is also used for the @option{--symmetric} encryption command. @item --personal-digest-preferences @code{string} @opindex personal-digest-preferences Set the list of personal digest preferences to @code{string}. Use @command{@gpgname --version} to get a list of available algorithms, and use @code{none} to set no preference at all. This allows the user to safely override the algorithm chosen by the recipient key preferences, as GPG will only select an algorithm that is usable by all recipients. The most highly ranked digest algorithm in this list is also used when signing without encryption (e.g. @option{--clearsign} or @option{--sign}). @item --personal-compress-preferences @code{string} @opindex personal-compress-preferences Set the list of personal compression preferences to @code{string}. Use @command{@gpgname --version} to get a list of available algorithms, and use @code{none} to set no preference at all. This allows the user to safely override the algorithm chosen by the recipient key preferences, as GPG will only select an algorithm that is usable by all recipients. The most highly ranked compression algorithm in this list is also used when there are no recipient keys to consider (e.g. @option{--symmetric}). @item --s2k-cipher-algo @code{name} @opindex s2k-cipher-algo Use @code{name} as the cipher algorithm used to protect secret keys. The default cipher is @value{DEFSYMENCALGO}. This cipher is also used for conventional encryption if @option{--personal-cipher-preferences} and @option{--cipher-algo} is not given. @item --s2k-digest-algo @code{name} @opindex s2k-digest-algo Use @code{name} as the digest algorithm used to mangle the passphrases. The default algorithm is SHA-1. @item --s2k-mode @code{n} @opindex s2k-mode Selects how passphrases are mangled. If @code{n} is 0 a plain passphrase (which is not recommended) will be used, a 1 adds a salt to the passphrase and a 3 (the default) iterates the whole process a number of times (see --s2k-count). Unless @option{--rfc1991} is used, this mode is also used for conventional encryption. @item --s2k-count @code{n} @opindex s2k-count Specify how many times the passphrase mangling is repeated. This value may range between 1024 and 65011712 inclusive. The default is inquired from gpg-agent. Note that not all values in the 1024-65011712 range are legal and if an illegal value is selected, GnuPG will round up to the nearest legal value. This option is only meaningful if @option{--s2k-mode} is 3. @end table @c *************************** @c ******* Compliance ******** @c *************************** @node Compliance Options @subsection Compliance options These options control what GnuPG is compliant to. Only one of these options may be active at a time. Note that the default setting of this is nearly always the correct one. See the INTEROPERABILITY WITH OTHER OPENPGP PROGRAMS section below before using one of these options. @table @gnupgtabopt @item --gnupg @opindex gnupg Use standard GnuPG behavior. This is essentially OpenPGP behavior (see @option{--openpgp}), but with some additional workarounds for common compatibility problems in different versions of PGP. This is the default option, so it is not generally needed, but it may be useful to override a different compliance option in the gpg.conf file. @item --openpgp @opindex openpgp Reset all packet, cipher and digest options to strict OpenPGP behavior. Use this option to reset all previous options like @option{--s2k-*}, @option{--cipher-algo}, @option{--digest-algo} and @option{--compress-algo} to OpenPGP compliant values. All PGP workarounds are disabled. @item --rfc4880 @opindex rfc4880 Reset all packet, cipher and digest options to strict RFC-4880 behavior. Note that this is currently the same thing as @option{--openpgp}. @item --rfc2440 @opindex rfc2440 Reset all packet, cipher and digest options to strict RFC-2440 behavior. @ifclear gpgtowone @item --rfc1991 @opindex rfc1991 Try to be more RFC-1991 (PGP 2.x) compliant. This option is deprecated will be removed in GnuPG 2.1. @item --pgp2 @opindex pgp2 Set up all options to be as PGP 2.x compliant as possible, and warn if an action is taken (e.g. encrypting to a non-RSA key) that will create a message that PGP 2.x will not be able to handle. Note that `PGP 2.x' here means `MIT PGP 2.6.2'. There are other versions of PGP 2.x available, but the MIT release is a good common baseline. This option implies @option{--rfc1991 --disable-mdc --no-force-v4-certs --escape-from-lines --force-v3-sigs --allow-weak-digest-algos --cipher-algo IDEA --digest-algo MD5 --compress-algo ZIP}. It also disables @option{--textmode} when encrypting. This option is deprecated will be removed in GnuPG 2.1. The reason for dropping PGP-2 support is that the PGP 2 format is not anymore considered safe (for example due to the use of the broken MD5 algorithm). Note that the decryption of PGP-2 created messages will continue to work. @end ifclear @item --pgp6 @opindex pgp6 Set up all options to be as PGP 6 compliant as possible. This restricts you to the ciphers IDEA (if the IDEA plugin is installed), 3DES, and CAST5, the hashes MD5, SHA1 and RIPEMD160, and the compression algorithms none and ZIP. This also disables --throw-keyids, and making signatures with signing subkeys as PGP 6 does not understand signatures made by signing subkeys. @ifclear gpgtwoone This option implies @option{--disable-mdc --escape-from-lines --force-v3-sigs}. @end ifclear @ifset gpgtwoone This option implies @option{--disable-mdc --escape-from-lines}. @end ifset @item --pgp7 @opindex pgp7 Set up all options to be as PGP 7 compliant as possible. This is identical to @option{--pgp6} except that MDCs are not disabled, and the list of allowable ciphers is expanded to add AES128, AES192, AES256, and TWOFISH. @item --pgp8 @opindex pgp8 Set up all options to be as PGP 8 compliant as possible. PGP 8 is a lot closer to the OpenPGP standard than previous versions of PGP, so all this does is disable @option{--throw-keyids} and set @option{--escape-from-lines}. All algorithms are allowed except for the SHA224, SHA384, and SHA512 digests. @end table @c ******************************************* @c ******** ESOTERIC OPTIONS *************** @c ******************************************* @node GPG Esoteric Options @subsection Doing things one usually doesn't want to do. @table @gnupgtabopt @item -n @itemx --dry-run @opindex dry-run Don't make any changes (this is not completely implemented). @item --list-only @opindex list-only Changes the behaviour of some commands. This is like @option{--dry-run} but different in some cases. The semantic of this command may be extended in the future. Currently it only skips the actual decryption pass and therefore enables a fast listing of the encryption keys. @item -i @itemx --interactive @opindex interactive Prompt before overwriting any files. @item --debug-level @var{level} @opindex debug-level Select the debug level for investigating problems. @var{level} may be a numeric value or by a keyword: @table @code @item none No debugging at all. A value of less than 1 may be used instead of the keyword. @item basic Some basic debug messages. A value between 1 and 2 may be used instead of the keyword. @item advanced More verbose debug messages. A value between 3 and 5 may be used instead of the keyword. @item expert Even more detailed messages. A value between 6 and 8 may be used instead of the keyword. @item guru All of the debug messages you can get. A value greater than 8 may be used instead of the keyword. The creation of hash tracing files is only enabled if the keyword is used. @end table How these messages are mapped to the actual debugging flags is not specified and may change with newer releases of this program. They are however carefully selected to best aid in debugging. @item --debug @var{flags} @opindex debug Set debugging flags. All flags are or-ed and @var{flags} may be given in C syntax (e.g. 0x0042). @item --debug-all @opindex debug-all Set all useful debugging flags. @item --debug-iolbf @opindex debug-iolbf Set stdout into line buffered mode. This option is only honored when given on the command line. @item --faked-system-time @var{epoch} @opindex faked-system-time This option is only useful for testing; it sets the system time back or forth to @var{epoch} which is the number of seconds elapsed since the year 1970. Alternatively @var{epoch} may be given as a full ISO time string (e.g. "20070924T154812"). @item --enable-progress-filter @opindex enable-progress-filter Enable certain PROGRESS status outputs. This option allows frontends to display a progress indicator while gpg is processing larger files. There is a slight performance overhead using it. @item --status-fd @code{n} @opindex status-fd Write special status strings to the file descriptor @code{n}. See the file DETAILS in the documentation for a listing of them. @item --status-file @code{file} @opindex status-file Same as @option{--status-fd}, except the status data is written to file @code{file}. @item --logger-fd @code{n} @opindex logger-fd Write log output to file descriptor @code{n} and not to STDERR. @item --log-file @code{file} @itemx --logger-file @code{file} @opindex log-file Same as @option{--logger-fd}, except the logger data is written to file @code{file}. Note that @option{--log-file} is only implemented for GnuPG-2. @item --attribute-fd @code{n} @opindex attribute-fd Write attribute subpackets to the file descriptor @code{n}. This is most useful for use with @option{--status-fd}, since the status messages are needed to separate out the various subpackets from the stream delivered to the file descriptor. @item --attribute-file @code{file} @opindex attribute-file Same as @option{--attribute-fd}, except the attribute data is written to file @code{file}. @item --comment @code{string} @itemx --no-comments @opindex comment Use @code{string} as a comment string in clear text signatures and ASCII armored messages or keys (see @option{--armor}). The default behavior is not to use a comment string. @option{--comment} may be repeated multiple times to get multiple comment strings. @option{--no-comments} removes all comments. It is a good idea to keep the length of a single comment below 60 characters to avoid problems with mail programs wrapping such lines. Note that comment lines, like all other header lines, are not protected by the signature. @item --emit-version @itemx --no-emit-version @opindex emit-version Force inclusion of the version string in ASCII armored output. If given once only the name of the program and the major number is emitted (default), given twice the minor is also emitted, given triple the micro is added, and given quad an operating system identification is also emitted. @option{--no-emit-version} disables the version line. @item --sig-notation @code{name=value} @itemx --cert-notation @code{name=value} @itemx -N, --set-notation @code{name=value} @opindex sig-notation @opindex cert-notation @opindex set-notation Put the name value pair into the signature as notation data. @code{name} must consist only of printable characters or spaces, and must contain a '@@' character in the form keyname@@domain.example.com (substituting the appropriate keyname and domain name, of course). This is to help prevent pollution of the IETF reserved notation namespace. The @option{--expert} flag overrides the '@@' check. @code{value} may be any printable string; it will be encoded in UTF8, so you should check that your @option{--display-charset} is set correctly. If you prefix @code{name} with an exclamation mark (!), the notation data will be flagged as critical (rfc4880:5.2.3.16). @option{--sig-notation} sets a notation for data signatures. @option{--cert-notation} sets a notation for key signatures (certifications). @option{--set-notation} sets both. There are special codes that may be used in notation names. "%k" will be expanded into the key ID of the key being signed, "%K" into the long key ID of the key being signed, "%f" into the fingerprint of the key being signed, "%s" into the key ID of the key making the signature, "%S" into the long key ID of the key making the signature, "%g" into the fingerprint of the key making the signature (which might be a subkey), "%p" into the fingerprint of the primary key of the key making the signature, "%c" into the signature count from the OpenPGP smartcard, and "%%" results in a single "%". %k, %K, and %f are only meaningful when making a key signature (certification), and %c is only meaningful when using the OpenPGP smartcard. @item --sig-policy-url @code{string} @itemx --cert-policy-url @code{string} @itemx --set-policy-url @code{string} @opindex sig-policy-url @opindex cert-policy-url @opindex set-policy-url Use @code{string} as a Policy URL for signatures (rfc4880:5.2.3.20). If you prefix it with an exclamation mark (!), the policy URL packet will be flagged as critical. @option{--sig-policy-url} sets a policy url for data signatures. @option{--cert-policy-url} sets a policy url for key signatures (certifications). @option{--set-policy-url} sets both. The same %-expandos used for notation data are available here as well. @item --sig-keyserver-url @code{string} @opindex sig-keyserver-url Use @code{string} as a preferred keyserver URL for data signatures. If you prefix it with an exclamation mark (!), the keyserver URL packet will be flagged as critical. The same %-expandos used for notation data are available here as well. @item --set-filename @code{string} @opindex set-filename Use @code{string} as the filename which is stored inside messages. This overrides the default, which is to use the actual filename of the file being encrypted. @item --for-your-eyes-only @itemx --no-for-your-eyes-only @opindex for-your-eyes-only Set the `for your eyes only' flag in the message. This causes GnuPG to refuse to save the file unless the @option{--output} option is given, and PGP to use a "secure viewer" with a claimed Tempest-resistant font to display the message. This option overrides @option{--set-filename}. @option{--no-for-your-eyes-only} disables this option. @item --use-embedded-filename @itemx --no-use-embedded-filename @opindex use-embedded-filename Try to create a file with a name as embedded in the data. This can be a dangerous option as it allows to overwrite files. Defaults to no. @item --cipher-algo @code{name} @opindex cipher-algo Use @code{name} as cipher algorithm. Running the program with the command @option{--version} yields a list of supported algorithms. If this is not used the cipher algorithm is selected from the preferences stored with the key. In general, you do not want to use this option as it allows you to violate the OpenPGP standard. @option{--personal-cipher-preferences} is the safe way to accomplish the same thing. @item --digest-algo @code{name} @opindex digest-algo Use @code{name} as the message digest algorithm. Running the program with the command @option{--version} yields a list of supported algorithms. In general, you do not want to use this option as it allows you to violate the OpenPGP standard. @option{--personal-digest-preferences} is the safe way to accomplish the same thing. @item --compress-algo @code{name} @opindex compress-algo Use compression algorithm @code{name}. "zlib" is RFC-1950 ZLIB compression. "zip" is RFC-1951 ZIP compression which is used by PGP. "bzip2" is a more modern compression scheme that can compress some things better than zip or zlib, but at the cost of more memory used during compression and decompression. "uncompressed" or "none" disables compression. If this option is not used, the default behavior is to examine the recipient key preferences to see which algorithms the recipient supports. If all else fails, ZIP is used for maximum compatibility. ZLIB may give better compression results than ZIP, as the compression window size is not limited to 8k. BZIP2 may give even better compression results than that, but will use a significantly larger amount of memory while compressing and decompressing. This may be significant in low memory situations. Note, however, that PGP (all versions) only supports ZIP compression. Using any algorithm other than ZIP or "none" will make the message unreadable with PGP. In general, you do not want to use this option as it allows you to violate the OpenPGP standard. @option{--personal-compress-preferences} is the safe way to accomplish the same thing. @item --cert-digest-algo @code{name} @opindex cert-digest-algo Use @code{name} as the message digest algorithm used when signing a key. Running the program with the command @option{--version} yields a list of supported algorithms. Be aware that if you choose an algorithm that GnuPG supports but other OpenPGP implementations do not, then some users will not be able to use the key signatures you make, or quite possibly your entire key. @item --disable-cipher-algo @code{name} @opindex disable-cipher-algo Never allow the use of @code{name} as cipher algorithm. The given name will not be checked so that a later loaded algorithm will still get disabled. @item --disable-pubkey-algo @code{name} @opindex disable-pubkey-algo Never allow the use of @code{name} as public key algorithm. The given name will not be checked so that a later loaded algorithm will still get disabled. @item --throw-keyids @itemx --no-throw-keyids @opindex throw-keyids Do not put the recipient key IDs into encrypted messages. This helps to hide the receivers of the message and is a limited countermeasure against traffic analysis.@footnote{Using a little social engineering anyone who is able to decrypt the message can check whether one of the other recipients is the one he suspects.} On the receiving side, it may slow down the decryption process because all available secret keys must be tried. @option{--no-throw-keyids} disables this option. This option is essentially the same as using @option{--hidden-recipient} for all recipients. @item --not-dash-escaped @opindex not-dash-escaped This option changes the behavior of cleartext signatures so that they can be used for patch files. You should not send such an armored file via email because all spaces and line endings are hashed too. You can not use this option for data which has 5 dashes at the beginning of a line, patch files don't have this. A special armor header line tells GnuPG about this cleartext signature option. @item --escape-from-lines @itemx --no-escape-from-lines @opindex escape-from-lines Because some mailers change lines starting with "From " to ">From " it is good to handle such lines in a special way when creating cleartext signatures to prevent the mail system from breaking the signature. Note that all other PGP versions do it this way too. Enabled by default. @option{--no-escape-from-lines} disables this option. @item --passphrase-repeat @code{n} @opindex passphrase-repeat Specify how many times @command{@gpgname} will request a new passphrase be repeated. This is useful for helping memorize a passphrase. Defaults to 1 repetition. @item --passphrase-fd @code{n} @opindex passphrase-fd Read the passphrase from file descriptor @code{n}. Only the first line will be read from file descriptor @code{n}. If you use 0 for @code{n}, the passphrase will be read from STDIN. This can only be used if only one passphrase is supplied. Note that this passphrase is only used if the option @option{--batch} has also been given. This is different from GnuPG version 1.x. @item --passphrase-file @code{file} @opindex passphrase-file Read the passphrase from file @code{file}. Only the first line will be read from file @code{file}. This can only be used if only one passphrase is supplied. Obviously, a passphrase stored in a file is of questionable security if other users can read this file. Don't use this option if you can avoid it. Note that this passphrase is only used if the option @option{--batch} has also been given. This is different from GnuPG version 1.x. @item --passphrase @code{string} @opindex passphrase Use @code{string} as the passphrase. This can only be used if only one passphrase is supplied. Obviously, this is of very questionable security on a multi-user system. Don't use this option if you can avoid it. Note that this passphrase is only used if the option @option{--batch} has also been given. This is different from GnuPG version 1.x. @ifset gpgtwoone @item --pinentry-mode @code{mode} @opindex pinentry-mode Set the pinentry mode to @code{mode}. Allowed values for @code{mode} are: @table @asis @item default Use the default of the agent, which is @code{ask}. @item ask Force the use of the Pinentry. @item cancel Emulate use of Pinentry's cancel button. @item error Return a Pinentry error (``No Pinentry''). @item loopback Redirect Pinentry queries to the caller. Note that in contrast to Pinentry the user is not prompted again if he enters a bad password. @end table @end ifset @item --command-fd @code{n} @opindex command-fd This is a replacement for the deprecated shared-memory IPC mode. If this option is enabled, user input on questions is not expected from the TTY but from the given file descriptor. It should be used together with @option{--status-fd}. See the file doc/DETAILS in the source distribution for details on how to use it. @item --command-file @code{file} @opindex command-file Same as @option{--command-fd}, except the commands are read out of file @code{file} @item --allow-non-selfsigned-uid @itemx --no-allow-non-selfsigned-uid @opindex allow-non-selfsigned-uid Allow the import and use of keys with user IDs which are not self-signed. This is not recommended, as a non self-signed user ID is trivial to forge. @option{--no-allow-non-selfsigned-uid} disables. @item --allow-freeform-uid @opindex allow-freeform-uid Disable all checks on the form of the user ID while generating a new one. This option should only be used in very special environments as it does not ensure the de-facto standard format of user IDs. @item --ignore-time-conflict @opindex ignore-time-conflict GnuPG normally checks that the timestamps associated with keys and signatures have plausible values. However, sometimes a signature seems to be older than the key due to clock problems. This option makes these checks just a warning. See also @option{--ignore-valid-from} for timestamp issues on subkeys. @item --ignore-valid-from @opindex ignore-valid-from GnuPG normally does not select and use subkeys created in the future. This option allows the use of such keys and thus exhibits the pre-1.0.7 behaviour. You should not use this option unless there is some clock problem. See also @option{--ignore-time-conflict} for timestamp issues with signatures. @item --ignore-crc-error @opindex ignore-crc-error The ASCII armor used by OpenPGP is protected by a CRC checksum against transmission errors. Occasionally the CRC gets mangled somewhere on the transmission channel but the actual content (which is protected by the OpenPGP protocol anyway) is still okay. This option allows GnuPG to ignore CRC errors. @item --ignore-mdc-error @opindex ignore-mdc-error This option changes a MDC integrity protection failure into a warning. This can be useful if a message is partially corrupt, but it is necessary to get as much data as possible out of the corrupt message. However, be aware that a MDC protection failure may also mean that the message was tampered with intentionally by an attacker. @item --allow-weak-digest-algos @opindex allow-weak-digest-algos Signatures made with the broken MD5 algorithm are normally rejected with an ``invalid digest algorithm'' message. This option allows the verification of signatures made with such weak algorithms. @item --no-default-keyring @opindex no-default-keyring Do not add the default keyrings to the list of keyrings. Note that GnuPG will not operate without any keyrings, so if you use this option and do not provide alternate keyrings via @option{--keyring} or @option{--secret-keyring}, then GnuPG will still use the default public or secret keyrings. @item --skip-verify @opindex skip-verify Skip the signature verification step. This may be used to make the decryption faster if the signature verification is not needed. @item --with-key-data @opindex with-key-data Print key listings delimited by colons (like @option{--with-colons}) and print the public key data. @item --fast-list-mode @opindex fast-list-mode Changes the output of the list commands to work faster; this is achieved by leaving some parts empty. Some applications don't need the user ID and the trust information given in the listings. By using this options they can get a faster listing. The exact behaviour of this option may change in future versions. If you are missing some information, don't use this option. @item --no-literal @opindex no-literal This is not for normal use. Use the source to see for what it might be useful. @item --set-filesize @opindex set-filesize This is not for normal use. Use the source to see for what it might be useful. @item --show-session-key @opindex show-session-key Display the session key used for one message. See @option{--override-session-key} for the counterpart of this option. We think that Key Escrow is a Bad Thing; however the user should have the freedom to decide whether to go to prison or to reveal the content of one specific message without compromising all messages ever encrypted for one secret key. You can also use this option if you receive an encrypted message which is abusive or offensive, to prove to the administrators of the messaging system that the ciphertext transmitted corresponds to an inappropriate plaintext so they can take action against the offending user. @item --override-session-key @code{string} @opindex override-session-key Don't use the public key but the session key @code{string}. The format of this string is the same as the one printed by @option{--show-session-key}. This option is normally not used but comes handy in case someone forces you to reveal the content of an encrypted message; using this option you can do this without handing out the secret key. @item --ask-sig-expire @itemx --no-ask-sig-expire @opindex ask-sig-expire When making a data signature, prompt for an expiration time. If this option is not specified, the expiration time set via @option{--default-sig-expire} is used. @option{--no-ask-sig-expire} disables this option. @item --default-sig-expire @opindex default-sig-expire The default expiration time to use for signature expiration. Valid values are "0" for no expiration, a number followed by the letter d (for days), w (for weeks), m (for months), or y (for years) (for example "2m" for two months, or "5y" for five years), or an absolute date in the form YYYY-MM-DD. Defaults to "0". @item --ask-cert-expire @itemx --no-ask-cert-expire @opindex ask-cert-expire When making a key signature, prompt for an expiration time. If this option is not specified, the expiration time set via @option{--default-cert-expire} is used. @option{--no-ask-cert-expire} disables this option. @item --default-cert-expire @opindex default-cert-expire The default expiration time to use for key signature expiration. Valid values are "0" for no expiration, a number followed by the letter d (for days), w (for weeks), m (for months), or y (for years) (for example "2m" for two months, or "5y" for five years), or an absolute date in the form YYYY-MM-DD. Defaults to "0". @item --allow-secret-key-import @opindex allow-secret-key-import This is an obsolete option and is not used anywhere. @item --allow-multiple-messages @item --no-allow-multiple-messages @opindex allow-multiple-messages Allow processing of multiple OpenPGP messages contained in a single file or stream. Some programs that call GPG are not prepared to deal with multiple messages being processed together, so this option defaults to no. Note that versions of GPG prior to 1.4.7 always allowed multiple messages. Warning: Do not use this option unless you need it as a temporary workaround! @item --enable-special-filenames @opindex enable-special-filenames This options enables a mode in which filenames of the form @file{-&n}, where n is a non-negative decimal number, refer to the file descriptor n and not to a file with that name. @item --no-expensive-trust-checks @opindex no-expensive-trust-checks Experimental use only. @item --preserve-permissions @opindex preserve-permissions Don't change the permissions of a secret keyring back to user read/write only. Use this option only if you really know what you are doing. @item --default-preference-list @code{string} @opindex default-preference-list Set the list of default preferences to @code{string}. This preference list is used for new keys and becomes the default for "setpref" in the edit menu. @item --default-keyserver-url @code{name} @opindex default-keyserver-url Set the default keyserver URL to @code{name}. This keyserver will be used as the keyserver URL when writing a new self-signature on a key, which includes key generation and changing preferences. @item --list-config @opindex list-config Display various internal configuration parameters of GnuPG. This option is intended for external programs that call GnuPG to perform tasks, and is thus not generally useful. See the file @file{doc/DETAILS} in the source distribution for the details of which configuration items may be listed. @option{--list-config} is only usable with @option{--with-colons} set. @item --list-gcrypt-config @opindex list-gcrypt-config Display various internal configuration parameters of Libgcrypt. @item --gpgconf-list @opindex gpgconf-list This command is similar to @option{--list-config} but in general only internally used by the @command{gpgconf} tool. @item --gpgconf-test @opindex gpgconf-test This is more or less dummy action. However it parses the configuration file and returns with failure if the configuration file would prevent @command{gpg} from startup. Thus it may be used to run a syntax check on the configuration file. @end table @c ******************************* @c ******* Deprecated ************ @c ******************************* @node Deprecated Options @subsection Deprecated options @table @gnupgtabopt @item --show-photos @itemx --no-show-photos @opindex show-photos Causes @option{--list-keys}, @option{--list-sigs}, @option{--list-public-keys}, @option{--list-secret-keys}, and verifying a signature to also display the photo ID attached to the key, if any. See also @option{--photo-viewer}. These options are deprecated. Use @option{--list-options [no-]show-photos} and/or @option{--verify-options [no-]show-photos} instead. @item --show-keyring @opindex show-keyring Display the keyring name at the head of key listings to show which keyring a given key resides on. This option is deprecated: use @option{--list-options [no-]show-keyring} instead. @item --always-trust @opindex always-trust Identical to @option{--trust-model always}. This option is deprecated. @item --show-notation @itemx --no-show-notation @opindex show-notation Show signature notations in the @option{--list-sigs} or @option{--check-sigs} listings as well as when verifying a signature with a notation in it. These options are deprecated. Use @option{--list-options [no-]show-notation} and/or @option{--verify-options [no-]show-notation} instead. @item --show-policy-url @itemx --no-show-policy-url @opindex show-policy-url Show policy URLs in the @option{--list-sigs} or @option{--check-sigs} listings as well as when verifying a signature with a policy URL in it. These options are deprecated. Use @option{--list-options [no-]show-policy-url} and/or @option{--verify-options [no-]show-policy-url} instead. @end table @c ******************************************* @c *************** **************** @c *************** FILES **************** @c *************** **************** @c ******************************************* @mansect files @node GPG Configuration @section Configuration files There are a few configuration files to control certain aspects of @command{@gpgname}'s operation. Unless noted, they are expected in the current home directory (@pxref{option --homedir}). @table @file @item gpg.conf @cindex gpg.conf This is the standard configuration file read by @command{@gpgname} on startup. It may contain any valid long option; the leading two dashes may not be entered and the option may not be abbreviated. This default name may be changed on the command line (@pxref{gpg-option --options}). You should backup this file. @end table @c man:.RE Note that on larger installations, it is useful to put predefined files into the directory @file{/etc/skel/.gnupg/} so that newly created users start up with a working configuration. For existing users a small helper script is provided to create these files (@pxref{addgnupghome}). For internal purposes @command{@gpgname} creates and maintains a few other files; They all live in in the current home directory (@pxref{option --homedir}). Only the @command{@gpgname} may modify these files. @table @file @item ~/.gnupg/pubring.gpg The public keyring. You should backup this file. @item ~/.gnupg/pubring.gpg.lock The lock file for the public keyring. @ifset gpgtwoone @item ~/.gnupg/pubring.kbx The public keyring using a different format. This file is sharred with @command{gpgsm}. You should backup this file. @item ~/.gnupg/pubring.kbx.lock The lock file for @file{pubring.kbx}. @end ifset @item ~/.gnupg/secring.gpg @ifclear gpgtwoone The secret keyring. You should backup this file. @end ifclear @ifset gpgtwoone A secret keyring as used by GnuPG versions before 2.1. It is not used by GnuPG 2.1 and later. @item ~/.gnupg/.gpg-v21-migrated File indicating that a migration to GnuPG 2.1 has taken place. @end ifset @item ~/.gnupg/trustdb.gpg The trust database. There is no need to backup this file; it is better to backup the ownertrust values (@pxref{option --export-ownertrust}). @item ~/.gnupg/trustdb.gpg.lock The lock file for the trust database. @item ~/.gnupg/random_seed A file used to preserve the state of the internal random pool. @item ~/.gnupg/secring.gpg.lock The lock file for the secret keyring. @item ~/.gnupg/openpgp-revocs.d/ This is the directory where gpg stores pre-generated revocation certificates. The file name corresponds to the OpenPGP fingerprint of the respective key. It is suggested to backup those certificates and if the primary private key is not stored on the disk to move them to an external storage device. Anyone who can access theses files is able to revoke the corresponding key. You may want to print them out. You should backup all files in this directory and take care to keep this backup closed away. @item /usr[/local]/share/gnupg/options.skel The skeleton options file. @item /usr[/local]/lib/gnupg/ Default location for extensions. @end table @c man:.RE Operation is further controlled by a few environment variables: @table @asis @item HOME Used to locate the default home directory. @item GNUPGHOME If set directory used instead of "~/.gnupg". @item GPG_AGENT_INFO @ifset gpgtwoone This variable was used by GnuPG versions before 2.1 @end ifset @ifclear gpgtwoone Used to locate the gpg-agent. The value consists of 3 colon delimited fields: The first is the path to the Unix Domain Socket, the second the PID of the gpg-agent and the protocol version which should be set to 1. When starting the gpg-agent as described in its documentation, this variable is set to the correct value. The option @option{--gpg-agent-info} can be used to override it. @end ifclear @item PINENTRY_USER_DATA This value is passed via gpg-agent to pinentry. It is useful to convey extra information to a custom pinentry. @item COLUMNS @itemx LINES Used to size some displays to the full size of the screen. @item LANGUAGE Apart from its use by GNU, it is used in the W32 version to override the language selection done through the Registry. If used and set to a valid and available language name (@var{langid}), the file with the translation is loaded from @code{@var{gpgdir}/gnupg.nls/@var{langid}.mo}. Here @var{gpgdir} is the directory out of which the gpg binary has been loaded. If it can't be loaded the Registry is tried and as last resort the native Windows locale system is used. @end table @c ******************************************* @c *************** **************** @c *************** EXAMPLES **************** @c *************** **************** @c ******************************************* @mansect examples @node GPG Examples @section Examples @table @asis @item gpg -se -r @code{Bob} @code{file} sign and encrypt for user Bob @item gpg --clearsign @code{file} make a clear text signature @item gpg -sb @code{file} make a detached signature @item gpg -u 0x12345678 -sb @code{file} make a detached signature with the key 0x12345678 @item gpg --list-keys @code{user_ID} show keys @item gpg --fingerprint @code{user_ID} show fingerprint @item gpg --verify @code{pgpfile} @itemx gpg --verify @code{sigfile} Verify the signature of the file but do not output the data. The second form is used for detached signatures, where @code{sigfile} is the detached signature (either ASCII armored or binary) and are the signed data; if this is not given, the name of the file holding the signed data is constructed by cutting off the extension (".asc" or ".sig") of @code{sigfile} or by asking the user for the filename. @end table @c ******************************************* @c *************** **************** @c *************** USER ID **************** @c *************** **************** @c ******************************************* @mansect how to specify a user id @ifset isman @include specify-user-id.texi @end ifset @mansect return value @chapheading RETURN VALUE The program returns 0 if everything was fine, 1 if at least a signature was bad, and other error codes for fatal errors. @mansect warnings @chapheading WARNINGS Use a *good* password for your user account and a *good* passphrase to protect your secret key. This passphrase is the weakest part of the whole system. Programs to do dictionary attacks on your secret keyring are very easy to write and so you should protect your "~/.gnupg/" directory very well. Keep in mind that, if this program is used over a network (telnet), it is *very* easy to spy out your passphrase! If you are going to verify detached signatures, make sure that the program knows about it; either give both filenames on the command line or use @samp{-} to specify STDIN. @mansect interoperability @chapheading INTEROPERABILITY WITH OTHER OPENPGP PROGRAMS GnuPG tries to be a very flexible implementation of the OpenPGP standard. In particular, GnuPG implements many of the optional parts of the standard, such as the SHA-512 hash, and the ZLIB and BZIP2 compression algorithms. It is important to be aware that not all OpenPGP programs implement these optional algorithms and that by forcing their use via the @option{--cipher-algo}, @option{--digest-algo}, @option{--cert-digest-algo}, or @option{--compress-algo} options in GnuPG, it is possible to create a perfectly valid OpenPGP message, but one that cannot be read by the intended recipient. There are dozens of variations of OpenPGP programs available, and each supports a slightly different subset of these optional algorithms. For example, until recently, no (unhacked) version of PGP supported the BLOWFISH cipher algorithm. A message using BLOWFISH simply could not be read by a PGP user. By default, GnuPG uses the standard OpenPGP preferences system that will always do the right thing and create messages that are usable by all recipients, regardless of which OpenPGP program they use. Only override this safe default if you really know what you are doing. If you absolutely must override the safe default, or if the preferences on a given key are invalid for some reason, you are far better off using the @option{--pgp6}, @option{--pgp7}, or @option{--pgp8} options. These options are safe as they do not force any particular algorithms in violation of OpenPGP, but rather reduce the available algorithms to a "PGP-safe" list. @mansect bugs @chapheading BUGS On older systems this program should be installed as setuid(root). This is necessary to lock memory pages. Locking memory pages prevents the operating system from writing memory pages (which may contain passphrases or other sensitive material) to disk. If you get no warning message about insecure memory your operating system supports locking without being root. The program drops root privileges as soon as locked memory is allocated. Note also that some systems (especially laptops) have the ability to ``suspend to disk'' (also known as ``safe sleep'' or ``hibernate''). This writes all memory to disk before going into a low power or even powered off mode. Unless measures are taken in the operating system to protect the saved memory, passphrases or other sensitive material may be recoverable from it later. Before you report a bug you should first search the mailing list archives for similar problems and second check whether such a bug has already been reported to our bug tracker at http://bugs.gnupg.org . @c ******************************************* @c *************** ************** @c *************** UNATTENDED ************** @c *************** ************** @c ******************************************* @manpause @node Unattended Usage of GPG @section Unattended Usage @command{gpg} is often used as a backend engine by other software. To help with this a machine interface has been defined to have an unambiguous way to do this. The options @option{--status-fd} and @option{--batch} are almost always required for this. @menu * Unattended GPG key generation:: Unattended key generation @end menu @node Unattended GPG key generation @subsection Unattended key generation The command @option{--gen-key} may be used along with the option @option{--batch} for unattended key generation. The parameters are either read from stdin or given as a file on the command line. The format of the parameter file is as follows: @itemize @bullet @item Text only, line length is limited to about 1000 characters. @item UTF-8 encoding must be used to specify non-ASCII characters. @item Empty lines are ignored. @item Leading and trailing while space is ignored. @item A hash sign as the first non white space character indicates a comment line. @item Control statements are indicated by a leading percent sign, the arguments are separated by white space from the keyword. @item Parameters are specified by a keyword, followed by a colon. Arguments are separated by white space. @item The first parameter must be @samp{Key-Type}; control statements may be placed anywhere. @item The order of the parameters does not matter except for @samp{Key-Type} which must be the first parameter. The parameters are only used for the generated keyblock (primary and subkeys); parameters from previous sets are not used. Some syntactically checks may be performed. @item Key generation takes place when either the end of the parameter file is reached, the next @samp{Key-Type} parameter is encountered or at the control statement @samp{%commit} is encountered. @end itemize @noindent Control statements: @table @asis @item %echo @var{text} Print @var{text} as diagnostic. @item %dry-run Suppress actual key generation (useful for syntax checking). @item %commit Perform the key generation. Note that an implicit commit is done at the next @asis{Key-Type} parameter. @item %pubring @var{filename} @itemx %secring @var{filename} Do not write the key to the default or commandline given keyring but to @var{filename}. This must be given before the first commit to take place, duplicate specification of the same filename is ignored, the last filename before a commit is used. The filename is used until a new filename is used (at commit points) and all keys are written to that file. If a new filename is given, this file is created (and overwrites an existing one). For GnuPG versions prior to 2.1, both control statements must be given. For GnuPG 2.1 and later @samp{%secring} is a no-op. @item %ask-passphrase @itemx %no-ask-passphrase @ifclear gpgtwoone Enable (or disable) a mode where the command @option{passphrase} is ignored and instead the usual passphrase dialog is used. This does not make sense for batch key generation; however the unattended key generation feature is also used by GUIs and this feature relinquishes the GUI from implementing its own passphrase entry code. These are global control statements and affect all future key generations. @end ifclear @ifset gpgtwoone This option is a no-op for GnuPG 2.1 and later. @end ifset @item %no-protection Using this option allows the creation of keys without any passphrase protection. This option is mainly intended for regression tests. @item %transient-key If given the keys are created using a faster and a somewhat less secure random number generator. This option may be used for keys which are only used for a short time and do not require full cryptographic strength. It takes only effect if used together with the control statement @samp{%no-protection}. @end table @noindent General Parameters: @table @asis @item Key-Type: @var{algo} Starts a new parameter block by giving the type of the primary key. The algorithm must be capable of signing. This is a required parameter. @var{algo} may either be an OpenPGP algorithm number or a string with the algorithm name. The special value @samp{default} may be used for @var{algo} to create the default key type; in this case a @samp{Key-Usage} shall not be given and @samp{default} also be used for @samp{Subkey-Type}. @item Key-Length: @var{nbits} The requested length of the generated key in bits. The default is returned by running the command @samp{gpg2 --gpgconf-list}. @item Key-Grip: @var{hexstring} This is optional and used to generate a CSR or certificate for an already existing key. Key-Length will be ignored when given. @item Key-Usage: @var{usage-list} Space or comma delimited list of key usages. Allowed values are @samp{encrypt}, @samp{sign}, and @samp{auth}. This is used to generate the key flags. Please make sure that the algorithm is capable of this usage. Note that OpenPGP requires that all primary keys are capable of certification, so no matter what usage is given here, the @samp{cert} flag will be on. If no @samp{Key-Usage} is specified and the @samp{Key-Type} is not @samp{default}, all allowed usages for that particular algorithm are used; if it is not given but @samp{default} is used the usage will be @samp{sign}. @item Subkey-Type: @var{algo} This generates a secondary key (subkey). Currently only one subkey can be handled. See also @samp{Key-Type} above. @item Subkey-Length: @var{nbits} Length of the secondary key (subkey) in bits. The default is returned by running the command @samp{gpg2 --gpgconf-list}". @item Subkey-Usage: @var{usage-list} Key usage lists for a subkey; similar to @samp{Key-Usage}. @item Passphrase: @var{string} If you want to specify a passphrase for the secret key, enter it here. Default is to use the Pinentry dialog to ask for a passphrase. @item Name-Real: @var{name} @itemx Name-Comment: @var{comment} @itemx Name-Email: @var{email} The three parts of a user name. Remember to use UTF-8 encoding here. If you don't give any of them, no user ID is created. @item Expire-Date: @var{iso-date}|(@var{number}[d|w|m|y]) Set the expiration date for the key (and the subkey). It may either be entered in ISO date format (e.g. "20000815T145012") or as number of days, weeks, month or years after the creation date. The special notation "seconds=N" is also allowed to specify a number of seconds since creation. Without a letter days are assumed. Note that there is no check done on the overflow of the type used by OpenPGP for timestamps. Thus you better make sure that the given value make sense. Although OpenPGP works with time intervals, GnuPG uses an absolute value internally and thus the last year we can represent is 2105. @item Creation-Date: @var{iso-date} Set the creation date of the key as stored in the key information and which is also part of the fingerprint calculation. Either a date like "1986-04-26" or a full timestamp like "19860426T042640" may be used. The time is considered to be UTC. The special notation "seconds=N" may be used to directly specify a the number of seconds since Epoch (Unix time). If it is not given the current time is used. @item Preferences: @var{string} Set the cipher, hash, and compression preference values for this key. This expects the same type of string as the sub-command @samp{setpref} in the @option{--edit-key} menu. @item Revoker: @var{algo}:@var{fpr} [sensitive] Add a designated revoker to the generated key. Algo is the public key algorithm of the designated revoker (i.e. RSA=1, DSA=17, etc.) @var{fpr} is the fingerprint of the designated revoker. The optional @samp{sensitive} flag marks the designated revoker as sensitive information. Only v4 keys may be designated revokers. @item Keyserver: @var{string} This is an optional parameter that specifies the preferred keyserver URL for the key. @item Handle: @var{string} This is an optional parameter only used with the status lines KEY_CREATED and KEY_NOT_CREATED. @var{string} may be up to 100 characters and should not contain spaces. It is useful for batch key generation to associate a key parameter block with a status line. @end table @noindent Here is an example on how to create a key: @smallexample $ cat >foo < ssb 1024g/8F70E2C0 2000-03-09 @end smallexample @noindent If you want to create a key with the default algorithms you would use these parameters: @smallexample %echo Generating a default key Key-Type: default Subkey-Type: default Name-Real: Joe Tester Name-Comment: with stupid passphrase Name-Email: joe@@foo.bar Expire-Date: 0 Passphrase: abc %pubring foo.pub %secring foo.sec # Do a commit here, so that we can later print "done" :-) %commit %echo done @end smallexample @mansect see also @ifset isman @command{gpgv}(1), @command{gpgsm}(1), @command{gpg-agent}(1) @end ifset @include see-also-note.texi diff --git a/g10/gpg.c b/g10/gpg.c index 13d688483..5a8a6621f 100644 --- a/g10/gpg.c +++ b/g10/gpg.c @@ -1,4635 +1,4652 @@ /* gpg.c - The GnuPG utility (main for gpg) * Copyright (C) 1998-2011 Free Software Foundation, Inc. * Copyright (C) 1997-2014 Werner Koch * 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 #include #include #ifdef HAVE_STAT #include /* for stat() */ #endif #include #ifdef HAVE_W32_SYSTEM # ifdef HAVE_WINSOCK2_H # include # endif # include #endif #define INCLUDED_BY_MAIN_MODULE 1 #include "gpg.h" #include #include "../common/iobuf.h" #include "util.h" #include "packet.h" #include "membuf.h" #include "main.h" #include "options.h" #include "keydb.h" #include "trustdb.h" #include "filter.h" #include "ttyio.h" #include "i18n.h" #include "sysutils.h" #include "status.h" #include "keyserver-internal.h" #include "exec.h" #include "gc-opt-flags.h" #include "asshelp.h" #include "call-dirmngr.h" #include "../common/init.h" #include "../common/shareddefs.h" #if defined(HAVE_DOSISH_SYSTEM) || defined(__CYGWIN__) #define MY_O_BINARY O_BINARY #ifndef S_IRGRP # define S_IRGRP 0 # define S_IWGRP 0 #endif #else #define MY_O_BINARY 0 #endif enum cmd_and_opt_values { aNull = 0, oArmor = 'a', aDetachedSign = 'b', aSym = 'c', aDecrypt = 'd', aEncr = 'e', oInteractive = 'i', aListKeys = 'k', oDryRun = 'n', oOutput = 'o', oQuiet = 'q', oRecipient = 'r', oHiddenRecipient = 'R', aSign = 's', oTextmodeShort= 't', oLocalUser = 'u', oVerbose = 'v', oCompress = 'z', oSetNotation = 'N', aListSecretKeys = 'K', oBatch = 500, oMaxOutput, oSigNotation, oCertNotation, oShowNotation, oNoShowNotation, aEncrFiles, aEncrSym, aDecryptFiles, aClearsign, aStore, aQuickKeygen, aFullKeygen, aKeygen, aSignEncr, aSignEncrSym, aSignSym, aSignKey, aLSignKey, aQuickSignKey, aQuickLSignKey, + aQuickAddUid, aListConfig, aListGcryptConfig, aGPGConfList, aGPGConfTest, aListPackets, aEditKey, aDeleteKeys, aDeleteSecretKeys, aDeleteSecretAndPublicKeys, aImport, aFastImport, aVerify, aVerifyFiles, aListSigs, aSendKeys, aRecvKeys, aLocateKeys, aSearchKeys, aRefreshKeys, aFetchKeys, aExport, aExportSecret, aExportSecretSub, aCheckKeys, aGenRevoke, aDesigRevoke, aPrimegen, aPrintMD, aPrintMDs, aCheckTrustDB, aUpdateTrustDB, aFixTrustDB, aListTrustDB, aListTrustPath, aExportOwnerTrust, aImportOwnerTrust, aDeArmor, aEnArmor, aGenRandom, aRebuildKeydbCaches, aCardStatus, aCardEdit, aChangePIN, aPasswd, aServer, oTextmode, oNoTextmode, oExpert, oNoExpert, oDefSigExpire, oAskSigExpire, oNoAskSigExpire, oDefCertExpire, oAskCertExpire, oNoAskCertExpire, oDefCertLevel, oMinCertLevel, oAskCertLevel, oNoAskCertLevel, oFingerprint, oWithFingerprint, oWithICAOSpelling, oWithKeygrip, oWithSecret, oAnswerYes, oAnswerNo, oKeyring, oPrimaryKeyring, oSecretKeyring, oShowKeyring, oDefaultKey, oDefRecipient, oDefRecipientSelf, oNoDefRecipient, oTrySecretKey, oOptions, oDebug, oDebugLevel, oDebugAll, oDebugIOLBF, oStatusFD, oStatusFile, oAttributeFD, oAttributeFile, oEmitVersion, oNoEmitVersion, oCompletesNeeded, oMarginalsNeeded, oMaxCertDepth, oLoadExtension, oGnuPG, oRFC2440, oRFC4880, oOpenPGP, oPGP6, oPGP7, oPGP8, oRFC2440Text, oNoRFC2440Text, oCipherAlgo, oDigestAlgo, oCertDigestAlgo, oCompressAlgo, oCompressLevel, oBZ2CompressLevel, oBZ2DecompressLowmem, oPassphrase, oPassphraseFD, oPassphraseFile, oPassphraseRepeat, oPinentryMode, oCommandFD, oCommandFile, oQuickRandom, oNoVerbose, oTrustDBName, oNoSecmemWarn, oRequireSecmem, oNoRequireSecmem, oNoPermissionWarn, oNoMDCWarn, oNoArmor, oNoDefKeyring, oNoGreeting, oNoTTY, oNoOptions, oNoBatch, oHomedir, oWithColons, oWithKeyData, oWithSigList, oWithSigCheck, oSkipVerify, oSkipHiddenRecipients, oNoSkipHiddenRecipients, oAlwaysTrust, oTrustModel, oForceOwnertrust, oSetFilename, oForYourEyesOnly, oNoForYourEyesOnly, oSetPolicyURL, oSigPolicyURL, oCertPolicyURL, oShowPolicyURL, oNoShowPolicyURL, oSigKeyserverURL, oUseEmbeddedFilename, oNoUseEmbeddedFilename, oComment, oDefaultComment, oNoComments, oThrowKeyids, oNoThrowKeyids, oShowPhotos, oNoShowPhotos, oPhotoViewer, oForceMDC, oNoForceMDC, oDisableMDC, oNoDisableMDC, oS2KMode, oS2KDigest, oS2KCipher, oS2KCount, oDisplayCharset, oNotDashEscaped, oEscapeFrom, oNoEscapeFrom, oLockOnce, oLockMultiple, oLockNever, oKeyServer, oKeyServerOptions, oImportOptions, oExportOptions, oListOptions, oVerifyOptions, oTempDir, oExecPath, oEncryptTo, oHiddenEncryptTo, oNoEncryptTo, oLoggerFD, oLoggerFile, oUtf8Strings, oNoUtf8Strings, oDisableCipherAlgo, oDisablePubkeyAlgo, oAllowNonSelfsignedUID, oNoAllowNonSelfsignedUID, oAllowFreeformUID, oNoAllowFreeformUID, oAllowSecretKeyImport, oEnableSpecialFilenames, oNoLiteral, oSetFilesize, oHonorHttpProxy, oFastListMode, oListOnly, oIgnoreTimeConflict, oIgnoreValidFrom, oIgnoreCrcError, oIgnoreMDCError, oShowSessionKey, oOverrideSessionKey, oNoRandomSeedFile, oAutoKeyRetrieve, oNoAutoKeyRetrieve, oUseAgent, oNoUseAgent, oGpgAgentInfo, oMergeOnly, oTryAllSecrets, oTrustedKey, oNoExpensiveTrustChecks, oFixedListMode, oLegacyListMode, oNoSigCache, oNoSigCreateCheck, oAutoCheckTrustDB, oNoAutoCheckTrustDB, oPreservePermissions, oDefaultPreferenceList, oDefaultKeyserverURL, oPersonalCipherPreferences, oPersonalDigestPreferences, oPersonalCompressPreferences, oAgentProgram, oDirmngrProgram, oDisplay, oTTYname, oTTYtype, oLCctype, oLCmessages, oXauthority, oGroup, oUnGroup, oNoGroups, oStrict, oNoStrict, oMangleDosFilenames, oNoMangleDosFilenames, oEnableProgressFilter, oMultifile, oKeyidFormat, oExitOnStatusWriteError, oLimitCardInsertTries, oReaderPort, octapiDriver, opcscDriver, oDisableCCID, oRequireCrossCert, oNoRequireCrossCert, oAutoKeyLocate, oNoAutoKeyLocate, oAllowMultisigVerification, oEnableLargeRSA, oDisableLargeRSA, oEnableDSA2, oDisableDSA2, oAllowMultipleMessages, oNoAllowMultipleMessages, oAllowWeakDigestAlgos, oFakedSystemTime, oNoAutostart, oPrintPKARecords, oNoop }; static ARGPARSE_OPTS opts[] = { ARGPARSE_group (300, N_("@Commands:\n ")), ARGPARSE_c (aSign, "sign", N_("make a signature")), ARGPARSE_c (aClearsign, "clearsign", N_("make a clear text signature")), ARGPARSE_c (aDetachedSign, "detach-sign", N_("make a detached signature")), ARGPARSE_c (aEncr, "encrypt", N_("encrypt data")), ARGPARSE_c (aEncrFiles, "encrypt-files", "@"), ARGPARSE_c (aSym, "symmetric", N_("encryption only with symmetric cipher")), ARGPARSE_c (aStore, "store", "@"), ARGPARSE_c (aDecrypt, "decrypt", N_("decrypt data (default)")), ARGPARSE_c (aDecryptFiles, "decrypt-files", "@"), ARGPARSE_c (aVerify, "verify" , N_("verify a signature")), ARGPARSE_c (aVerifyFiles, "verify-files" , "@" ), ARGPARSE_c (aListKeys, "list-keys", N_("list keys")), ARGPARSE_c (aListKeys, "list-public-keys", "@" ), ARGPARSE_c (aListSigs, "list-sigs", N_("list keys and signatures")), ARGPARSE_c (aCheckKeys, "check-sigs",N_("list and check key signatures")), ARGPARSE_c (oFingerprint, "fingerprint", N_("list keys and fingerprints")), ARGPARSE_c (aListSecretKeys, "list-secret-keys", N_("list secret keys")), ARGPARSE_c (aKeygen, "gen-key", N_("generate a new key pair")), ARGPARSE_c (aQuickKeygen, "quick-gen-key" , N_("quickly generate a new key pair")), + ARGPARSE_c (aQuickAddUid, "quick-adduid", + N_("quickly add a new user-id")), ARGPARSE_c (aFullKeygen, "full-gen-key" , N_("full featured key pair generation")), ARGPARSE_c (aGenRevoke, "gen-revoke",N_("generate a revocation certificate")), ARGPARSE_c (aDeleteKeys,"delete-keys", N_("remove keys from the public keyring")), ARGPARSE_c (aDeleteSecretKeys, "delete-secret-keys", N_("remove keys from the secret keyring")), ARGPARSE_c (aQuickSignKey, "quick-sign-key" , N_("quickly sign a key")), ARGPARSE_c (aQuickLSignKey, "quick-lsign-key", N_("quickly sign a key locally")), ARGPARSE_c (aSignKey, "sign-key" ,N_("sign a key")), ARGPARSE_c (aLSignKey, "lsign-key" ,N_("sign a key locally")), ARGPARSE_c (aEditKey, "edit-key" ,N_("sign or edit a key")), ARGPARSE_c (aEditKey, "key-edit" ,"@"), ARGPARSE_c (aPasswd, "passwd", N_("change a passphrase")), ARGPARSE_c (aDesigRevoke, "desig-revoke","@" ), ARGPARSE_c (aExport, "export" , N_("export keys") ), ARGPARSE_c (aSendKeys, "send-keys" , N_("export keys to a key server") ), ARGPARSE_c (aRecvKeys, "recv-keys" , N_("import keys from a key server") ), ARGPARSE_c (aSearchKeys, "search-keys" , N_("search for keys on a key server") ), ARGPARSE_c (aRefreshKeys, "refresh-keys", N_("update all keys from a keyserver")), ARGPARSE_c (aLocateKeys, "locate-keys", "@"), ARGPARSE_c (aFetchKeys, "fetch-keys" , "@" ), ARGPARSE_c (aExportSecret, "export-secret-keys" , "@" ), ARGPARSE_c (aExportSecretSub, "export-secret-subkeys" , "@" ), ARGPARSE_c (aImport, "import", N_("import/merge keys")), ARGPARSE_c (aFastImport, "fast-import", "@"), #ifdef ENABLE_CARD_SUPPORT ARGPARSE_c (aCardStatus, "card-status", N_("print the card status")), ARGPARSE_c (aCardEdit, "card-edit", N_("change data on a card")), ARGPARSE_c (aChangePIN, "change-pin", N_("change a card's PIN")), #endif ARGPARSE_c (aListConfig, "list-config", "@"), ARGPARSE_c (aListGcryptConfig, "list-gcrypt-config", "@"), ARGPARSE_c (aGPGConfList, "gpgconf-list", "@" ), ARGPARSE_c (aGPGConfTest, "gpgconf-test", "@" ), ARGPARSE_c (aListPackets, "list-packets","@"), #ifndef NO_TRUST_MODELS ARGPARSE_c (aExportOwnerTrust, "export-ownertrust", "@"), ARGPARSE_c (aImportOwnerTrust, "import-ownertrust", "@"), ARGPARSE_c (aUpdateTrustDB,"update-trustdb", N_("update the trust database")), ARGPARSE_c (aCheckTrustDB, "check-trustdb", "@"), ARGPARSE_c (aFixTrustDB, "fix-trustdb", "@"), #endif ARGPARSE_c (aDeArmor, "dearmor", "@"), ARGPARSE_c (aDeArmor, "dearmour", "@"), ARGPARSE_c (aEnArmor, "enarmor", "@"), ARGPARSE_c (aEnArmor, "enarmour", "@"), ARGPARSE_c (aPrintMD, "print-md", N_("print message digests")), ARGPARSE_c (aPrimegen, "gen-prime", "@" ), ARGPARSE_c (aGenRandom,"gen-random", "@" ), ARGPARSE_c (aServer, "server", N_("run in server mode")), ARGPARSE_group (301, N_("@\nOptions:\n ")), ARGPARSE_s_n (oArmor, "armor", N_("create ascii armored output")), ARGPARSE_s_n (oArmor, "armour", "@"), ARGPARSE_s_s (oRecipient, "recipient", N_("|USER-ID|encrypt for USER-ID")), ARGPARSE_s_s (oHiddenRecipient, "hidden-recipient", "@"), ARGPARSE_s_s (oRecipient, "remote-user", "@"), /* (old option name) */ ARGPARSE_s_s (oDefRecipient, "default-recipient", "@"), ARGPARSE_s_n (oDefRecipientSelf, "default-recipient-self", "@"), ARGPARSE_s_n (oNoDefRecipient, "no-default-recipient", "@"), ARGPARSE_s_s (oTempDir, "temp-directory", "@"), ARGPARSE_s_s (oExecPath, "exec-path", "@"), ARGPARSE_s_s (oEncryptTo, "encrypt-to", "@"), ARGPARSE_s_n (oNoEncryptTo, "no-encrypt-to", "@"), ARGPARSE_s_s (oHiddenEncryptTo, "hidden-encrypt-to", "@"), ARGPARSE_s_s (oLocalUser, "local-user", N_("|USER-ID|use USER-ID to sign or decrypt")), ARGPARSE_s_s (oTrySecretKey, "try-secret-key", "@"), ARGPARSE_s_i (oCompress, NULL, N_("|N|set compress level to N (0 disables)")), ARGPARSE_s_i (oCompressLevel, "compress-level", "@"), ARGPARSE_s_i (oBZ2CompressLevel, "bzip2-compress-level", "@"), ARGPARSE_s_n (oBZ2DecompressLowmem, "bzip2-decompress-lowmem", "@"), ARGPARSE_s_n (oTextmodeShort, NULL, "@"), ARGPARSE_s_n (oTextmode, "textmode", N_("use canonical text mode")), ARGPARSE_s_n (oNoTextmode, "no-textmode", "@"), ARGPARSE_s_n (oExpert, "expert", "@"), ARGPARSE_s_n (oNoExpert, "no-expert", "@"), ARGPARSE_s_s (oDefSigExpire, "default-sig-expire", "@"), ARGPARSE_s_n (oAskSigExpire, "ask-sig-expire", "@"), ARGPARSE_s_n (oNoAskSigExpire, "no-ask-sig-expire", "@"), ARGPARSE_s_s (oDefCertExpire, "default-cert-expire", "@"), ARGPARSE_s_n (oAskCertExpire, "ask-cert-expire", "@"), ARGPARSE_s_n (oNoAskCertExpire, "no-ask-cert-expire", "@"), ARGPARSE_s_i (oDefCertLevel, "default-cert-level", "@"), ARGPARSE_s_i (oMinCertLevel, "min-cert-level", "@"), ARGPARSE_s_n (oAskCertLevel, "ask-cert-level", "@"), ARGPARSE_s_n (oNoAskCertLevel, "no-ask-cert-level", "@"), ARGPARSE_s_s (oOutput, "output", N_("|FILE|write output to FILE")), ARGPARSE_p_u (oMaxOutput, "max-output", "@"), ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")), ARGPARSE_s_n (oQuiet, "quiet", "@"), ARGPARSE_s_n (oNoTTY, "no-tty", "@"), ARGPARSE_s_n (oForceMDC, "force-mdc", "@"), ARGPARSE_s_n (oNoForceMDC, "no-force-mdc", "@"), ARGPARSE_s_n (oDisableMDC, "disable-mdc", "@"), ARGPARSE_s_n (oNoDisableMDC, "no-disable-mdc", "@"), ARGPARSE_s_n (oDryRun, "dry-run", N_("do not make any changes")), ARGPARSE_s_n (oInteractive, "interactive", N_("prompt before overwriting")), ARGPARSE_s_n (oBatch, "batch", "@"), ARGPARSE_s_n (oAnswerYes, "yes", "@"), ARGPARSE_s_n (oAnswerNo, "no", "@"), ARGPARSE_s_s (oKeyring, "keyring", "@"), ARGPARSE_s_s (oPrimaryKeyring, "primary-keyring", "@"), ARGPARSE_s_s (oSecretKeyring, "secret-keyring", "@"), ARGPARSE_s_n (oShowKeyring, "show-keyring", "@"), ARGPARSE_s_s (oDefaultKey, "default-key", "@"), ARGPARSE_s_s (oKeyServer, "keyserver", "@"), ARGPARSE_s_s (oKeyServerOptions, "keyserver-options", "@"), ARGPARSE_s_s (oImportOptions, "import-options", "@"), ARGPARSE_s_s (oExportOptions, "export-options", "@"), ARGPARSE_s_s (oListOptions, "list-options", "@"), ARGPARSE_s_s (oVerifyOptions, "verify-options", "@"), ARGPARSE_s_s (oDisplayCharset, "display-charset", "@"), ARGPARSE_s_s (oDisplayCharset, "charset", "@"), ARGPARSE_s_s (oOptions, "options", "@"), ARGPARSE_p_u (oDebug, "debug", "@"), ARGPARSE_s_s (oDebugLevel, "debug-level", "@"), ARGPARSE_s_n (oDebugAll, "debug-all", "@"), ARGPARSE_s_n (oDebugIOLBF, "debug-iolbf", "@"), ARGPARSE_s_i (oStatusFD, "status-fd", "@"), ARGPARSE_s_s (oStatusFile, "status-file", "@"), ARGPARSE_s_i (oAttributeFD, "attribute-fd", "@"), ARGPARSE_s_s (oAttributeFile, "attribute-file", "@"), ARGPARSE_s_i (oCompletesNeeded, "completes-needed", "@"), ARGPARSE_s_i (oMarginalsNeeded, "marginals-needed", "@"), ARGPARSE_s_i (oMaxCertDepth, "max-cert-depth", "@" ), ARGPARSE_s_s (oTrustedKey, "trusted-key", "@"), ARGPARSE_s_s (oLoadExtension, "load-extension", "@"), /* Dummy. */ ARGPARSE_s_n (oGnuPG, "gnupg", "@"), ARGPARSE_s_n (oGnuPG, "no-pgp2", "@"), ARGPARSE_s_n (oGnuPG, "no-pgp6", "@"), ARGPARSE_s_n (oGnuPG, "no-pgp7", "@"), ARGPARSE_s_n (oGnuPG, "no-pgp8", "@"), ARGPARSE_s_n (oRFC2440, "rfc2440", "@"), ARGPARSE_s_n (oRFC4880, "rfc4880", "@"), ARGPARSE_s_n (oOpenPGP, "openpgp", N_("use strict OpenPGP behavior")), ARGPARSE_s_n (oPGP6, "pgp6", "@"), ARGPARSE_s_n (oPGP7, "pgp7", "@"), ARGPARSE_s_n (oPGP8, "pgp8", "@"), ARGPARSE_s_n (oRFC2440Text, "rfc2440-text", "@"), ARGPARSE_s_n (oNoRFC2440Text, "no-rfc2440-text", "@"), ARGPARSE_s_i (oS2KMode, "s2k-mode", "@"), ARGPARSE_s_s (oS2KDigest, "s2k-digest-algo", "@"), ARGPARSE_s_s (oS2KCipher, "s2k-cipher-algo", "@"), ARGPARSE_s_i (oS2KCount, "s2k-count", "@"), ARGPARSE_s_s (oCipherAlgo, "cipher-algo", "@"), ARGPARSE_s_s (oDigestAlgo, "digest-algo", "@"), ARGPARSE_s_s (oCertDigestAlgo, "cert-digest-algo", "@"), ARGPARSE_s_s (oCompressAlgo,"compress-algo", "@"), ARGPARSE_s_s (oCompressAlgo, "compression-algo", "@"), /* Alias */ ARGPARSE_s_n (oThrowKeyids, "throw-keyids", "@"), ARGPARSE_s_n (oNoThrowKeyids, "no-throw-keyids", "@"), ARGPARSE_s_n (oShowPhotos, "show-photos", "@"), ARGPARSE_s_n (oNoShowPhotos, "no-show-photos", "@"), ARGPARSE_s_s (oPhotoViewer, "photo-viewer", "@"), ARGPARSE_s_s (oSetNotation, "set-notation", "@"), ARGPARSE_s_s (oSigNotation, "sig-notation", "@"), ARGPARSE_s_s (oCertNotation, "cert-notation", "@"), ARGPARSE_group (302, N_( "@\n(See the man page for a complete listing of all commands and options)\n" )), ARGPARSE_group (303, N_("@\nExamples:\n\n" " -se -r Bob [file] sign and encrypt for user Bob\n" " --clearsign [file] make a clear text signature\n" " --detach-sign [file] make a detached signature\n" " --list-keys [names] show keys\n" " --fingerprint [names] show fingerprints\n")), /* More hidden commands and options. */ ARGPARSE_c (aPrintMDs, "print-mds", "@"), /* old */ #ifndef NO_TRUST_MODELS ARGPARSE_c (aListTrustDB, "list-trustdb", "@"), #endif /* Not yet used: ARGPARSE_c (aListTrustPath, "list-trust-path", "@"), */ ARGPARSE_c (aDeleteSecretAndPublicKeys, "delete-secret-and-public-keys", "@"), ARGPARSE_c (aRebuildKeydbCaches, "rebuild-keydb-caches", "@"), ARGPARSE_s_s (oPassphrase, "passphrase", "@"), ARGPARSE_s_i (oPassphraseFD, "passphrase-fd", "@"), ARGPARSE_s_s (oPassphraseFile, "passphrase-file", "@"), ARGPARSE_s_i (oPassphraseRepeat,"passphrase-repeat", "@"), ARGPARSE_s_s (oPinentryMode, "pinentry-mode", "@"), ARGPARSE_s_i (oCommandFD, "command-fd", "@"), ARGPARSE_s_s (oCommandFile, "command-file", "@"), ARGPARSE_s_n (oQuickRandom, "debug-quick-random", "@"), ARGPARSE_s_n (oNoVerbose, "no-verbose", "@"), #ifndef NO_TRUST_MODELS ARGPARSE_s_s (oTrustDBName, "trustdb-name", "@"), ARGPARSE_s_n (oAutoCheckTrustDB, "auto-check-trustdb", "@"), ARGPARSE_s_n (oNoAutoCheckTrustDB, "no-auto-check-trustdb", "@"), ARGPARSE_s_s (oForceOwnertrust, "force-ownertrust", "@"), #endif ARGPARSE_s_n (oNoSecmemWarn, "no-secmem-warning", "@"), ARGPARSE_s_n (oRequireSecmem, "require-secmem", "@"), ARGPARSE_s_n (oNoRequireSecmem, "no-require-secmem", "@"), ARGPARSE_s_n (oNoPermissionWarn, "no-permission-warning", "@"), ARGPARSE_s_n (oNoMDCWarn, "no-mdc-warning", "@"), ARGPARSE_s_n (oNoArmor, "no-armor", "@"), ARGPARSE_s_n (oNoArmor, "no-armour", "@"), ARGPARSE_s_n (oNoDefKeyring, "no-default-keyring", "@"), ARGPARSE_s_n (oNoGreeting, "no-greeting", "@"), ARGPARSE_s_n (oNoOptions, "no-options", "@"), ARGPARSE_s_s (oHomedir, "homedir", "@"), ARGPARSE_s_n (oNoBatch, "no-batch", "@"), ARGPARSE_s_n (oWithColons, "with-colons", "@"), ARGPARSE_s_n (oWithKeyData,"with-key-data", "@"), ARGPARSE_s_n (oWithSigList,"with-sig-list", "@"), ARGPARSE_s_n (oWithSigCheck,"with-sig-check", "@"), ARGPARSE_s_n (aListKeys, "list-key", "@"), /* alias */ ARGPARSE_s_n (aListSigs, "list-sig", "@"), /* alias */ ARGPARSE_s_n (aCheckKeys, "check-sig", "@"), /* alias */ ARGPARSE_s_n (oSkipVerify, "skip-verify", "@"), ARGPARSE_s_n (oSkipHiddenRecipients, "skip-hidden-recipients", "@"), ARGPARSE_s_n (oNoSkipHiddenRecipients, "no-skip-hidden-recipients", "@"), ARGPARSE_s_i (oDefCertLevel, "default-cert-check-level", "@"), /* old */ ARGPARSE_s_n (oAlwaysTrust, "always-trust", "@"), ARGPARSE_s_s (oTrustModel, "trust-model", "@"), ARGPARSE_s_s (oSetFilename, "set-filename", "@"), ARGPARSE_s_n (oForYourEyesOnly, "for-your-eyes-only", "@"), ARGPARSE_s_n (oNoForYourEyesOnly, "no-for-your-eyes-only", "@"), ARGPARSE_s_s (oSetPolicyURL, "set-policy-url", "@"), ARGPARSE_s_s (oSigPolicyURL, "sig-policy-url", "@"), ARGPARSE_s_s (oCertPolicyURL, "cert-policy-url", "@"), ARGPARSE_s_n (oShowPolicyURL, "show-policy-url", "@"), ARGPARSE_s_n (oNoShowPolicyURL, "no-show-policy-url", "@"), ARGPARSE_s_s (oSigKeyserverURL, "sig-keyserver-url", "@"), ARGPARSE_s_n (oShowNotation, "show-notation", "@"), ARGPARSE_s_n (oNoShowNotation, "no-show-notation", "@"), ARGPARSE_s_s (oComment, "comment", "@"), ARGPARSE_s_n (oDefaultComment, "default-comment", "@"), ARGPARSE_s_n (oNoComments, "no-comments", "@"), ARGPARSE_s_n (oEmitVersion, "emit-version", "@"), ARGPARSE_s_n (oNoEmitVersion, "no-emit-version", "@"), ARGPARSE_s_n (oNoEmitVersion, "no-version", "@"), /* alias */ ARGPARSE_s_n (oNotDashEscaped, "not-dash-escaped", "@"), ARGPARSE_s_n (oEscapeFrom, "escape-from-lines", "@"), ARGPARSE_s_n (oNoEscapeFrom, "no-escape-from-lines", "@"), ARGPARSE_s_n (oLockOnce, "lock-once", "@"), ARGPARSE_s_n (oLockMultiple, "lock-multiple", "@"), ARGPARSE_s_n (oLockNever, "lock-never", "@"), ARGPARSE_s_i (oLoggerFD, "logger-fd", "@"), ARGPARSE_s_s (oLoggerFile, "log-file", "@"), ARGPARSE_s_s (oLoggerFile, "logger-file", "@"), /* 1.4 compatibility. */ ARGPARSE_s_n (oUseEmbeddedFilename, "use-embedded-filename", "@"), ARGPARSE_s_n (oNoUseEmbeddedFilename, "no-use-embedded-filename", "@"), ARGPARSE_s_n (oUtf8Strings, "utf8-strings", "@"), ARGPARSE_s_n (oNoUtf8Strings, "no-utf8-strings", "@"), ARGPARSE_s_n (oWithFingerprint, "with-fingerprint", "@"), ARGPARSE_s_n (oWithICAOSpelling, "with-icao-spelling", "@"), ARGPARSE_s_n (oWithKeygrip, "with-keygrip", "@"), ARGPARSE_s_n (oWithSecret, "with-secret", "@"), ARGPARSE_s_s (oDisableCipherAlgo, "disable-cipher-algo", "@"), ARGPARSE_s_s (oDisablePubkeyAlgo, "disable-pubkey-algo", "@"), ARGPARSE_s_n (oAllowNonSelfsignedUID, "allow-non-selfsigned-uid", "@"), ARGPARSE_s_n (oNoAllowNonSelfsignedUID, "no-allow-non-selfsigned-uid", "@"), ARGPARSE_s_n (oAllowFreeformUID, "allow-freeform-uid", "@"), ARGPARSE_s_n (oNoAllowFreeformUID, "no-allow-freeform-uid", "@"), ARGPARSE_s_n (oNoLiteral, "no-literal", "@"), ARGPARSE_p_u (oSetFilesize, "set-filesize", "@"), ARGPARSE_s_n (oFastListMode, "fast-list-mode", "@"), ARGPARSE_s_n (oFixedListMode, "fixed-list-mode", "@"), ARGPARSE_s_n (oLegacyListMode, "legacy-list-mode", "@"), ARGPARSE_s_n (oListOnly, "list-only", "@"), ARGPARSE_s_n (oPrintPKARecords, "print-pka-records", "@"), ARGPARSE_s_n (oIgnoreTimeConflict, "ignore-time-conflict", "@"), ARGPARSE_s_n (oIgnoreValidFrom, "ignore-valid-from", "@"), ARGPARSE_s_n (oIgnoreCrcError, "ignore-crc-error", "@"), ARGPARSE_s_n (oIgnoreMDCError, "ignore-mdc-error", "@"), ARGPARSE_s_n (oShowSessionKey, "show-session-key", "@"), ARGPARSE_s_s (oOverrideSessionKey, "override-session-key", "@"), ARGPARSE_s_n (oNoRandomSeedFile, "no-random-seed-file", "@"), ARGPARSE_s_n (oAutoKeyRetrieve, "auto-key-retrieve", "@"), ARGPARSE_s_n (oNoAutoKeyRetrieve, "no-auto-key-retrieve", "@"), ARGPARSE_s_n (oNoSigCache, "no-sig-cache", "@"), ARGPARSE_s_n (oNoSigCreateCheck, "no-sig-create-check", "@"), ARGPARSE_s_n (oMergeOnly, "merge-only", "@" ), ARGPARSE_s_n (oAllowSecretKeyImport, "allow-secret-key-import", "@"), ARGPARSE_s_n (oTryAllSecrets, "try-all-secrets", "@"), ARGPARSE_s_n (oEnableSpecialFilenames, "enable-special-filenames", "@"), ARGPARSE_s_n (oNoExpensiveTrustChecks, "no-expensive-trust-checks", "@"), ARGPARSE_s_n (oPreservePermissions, "preserve-permissions", "@"), ARGPARSE_s_s (oDefaultPreferenceList, "default-preference-list", "@"), ARGPARSE_s_s (oDefaultKeyserverURL, "default-keyserver-url", "@"), ARGPARSE_s_s (oPersonalCipherPreferences, "personal-cipher-preferences","@"), ARGPARSE_s_s (oPersonalDigestPreferences, "personal-digest-preferences","@"), ARGPARSE_s_s (oPersonalCompressPreferences, "personal-compress-preferences", "@"), ARGPARSE_s_s (oFakedSystemTime, "faked-system-time", "@"), /* Aliases. I constantly mistype these, and assume other people do as well. */ ARGPARSE_s_s (oPersonalCipherPreferences, "personal-cipher-prefs", "@"), ARGPARSE_s_s (oPersonalDigestPreferences, "personal-digest-prefs", "@"), ARGPARSE_s_s (oPersonalCompressPreferences, "personal-compress-prefs", "@"), ARGPARSE_s_s (oAgentProgram, "agent-program", "@"), ARGPARSE_s_s (oDirmngrProgram, "dirmngr-program", "@"), ARGPARSE_s_s (oDisplay, "display", "@"), ARGPARSE_s_s (oTTYname, "ttyname", "@"), ARGPARSE_s_s (oTTYtype, "ttytype", "@"), ARGPARSE_s_s (oLCctype, "lc-ctype", "@"), ARGPARSE_s_s (oLCmessages, "lc-messages","@"), ARGPARSE_s_s (oXauthority, "xauthority", "@"), ARGPARSE_s_s (oGroup, "group", "@"), ARGPARSE_s_s (oUnGroup, "ungroup", "@"), ARGPARSE_s_n (oNoGroups, "no-groups", "@"), ARGPARSE_s_n (oStrict, "strict", "@"), ARGPARSE_s_n (oNoStrict, "no-strict", "@"), ARGPARSE_s_n (oMangleDosFilenames, "mangle-dos-filenames", "@"), ARGPARSE_s_n (oNoMangleDosFilenames, "no-mangle-dos-filenames", "@"), ARGPARSE_s_n (oEnableProgressFilter, "enable-progress-filter", "@"), ARGPARSE_s_n (oMultifile, "multifile", "@"), ARGPARSE_s_s (oKeyidFormat, "keyid-format", "@"), ARGPARSE_s_n (oExitOnStatusWriteError, "exit-on-status-write-error", "@"), ARGPARSE_s_i (oLimitCardInsertTries, "limit-card-insert-tries", "@"), ARGPARSE_s_n (oAllowMultisigVerification, "allow-multisig-verification", "@"), ARGPARSE_s_n (oEnableLargeRSA, "enable-large-rsa", "@"), ARGPARSE_s_n (oDisableLargeRSA, "disable-large-rsa", "@"), ARGPARSE_s_n (oEnableDSA2, "enable-dsa2", "@"), ARGPARSE_s_n (oDisableDSA2, "disable-dsa2", "@"), ARGPARSE_s_n (oAllowMultipleMessages, "allow-multiple-messages", "@"), ARGPARSE_s_n (oNoAllowMultipleMessages, "no-allow-multiple-messages", "@"), ARGPARSE_s_n (oAllowWeakDigestAlgos, "allow-weak-digest-algos", "@"), /* These two are aliases to help users of the PGP command line product use gpg with minimal pain. Many commands are common already as they seem to have borrowed commands from us. Now I'm returning the favor. */ ARGPARSE_s_s (oLocalUser, "sign-with", "@"), ARGPARSE_s_s (oRecipient, "user", "@"), ARGPARSE_s_n (oRequireCrossCert, "require-backsigs", "@"), ARGPARSE_s_n (oRequireCrossCert, "require-cross-certification", "@"), ARGPARSE_s_n (oNoRequireCrossCert, "no-require-backsigs", "@"), ARGPARSE_s_n (oNoRequireCrossCert, "no-require-cross-certification", "@"), /* New options. Fixme: Should go more to the top. */ ARGPARSE_s_s (oAutoKeyLocate, "auto-key-locate", "@"), ARGPARSE_s_n (oNoAutoKeyLocate, "no-auto-key-locate", "@"), ARGPARSE_s_n (oNoAutostart, "no-autostart", "@"), /* Dummy options with warnings. */ ARGPARSE_s_n (oUseAgent, "use-agent", "@"), ARGPARSE_s_n (oNoUseAgent, "no-use-agent", "@"), ARGPARSE_s_s (oGpgAgentInfo, "gpg-agent-info", "@"), ARGPARSE_s_s (oReaderPort, "reader-port", "@"), ARGPARSE_s_s (octapiDriver, "ctapi-driver", "@"), ARGPARSE_s_s (opcscDriver, "pcsc-driver", "@"), ARGPARSE_s_n (oDisableCCID, "disable-ccid", "@"), ARGPARSE_s_n (oHonorHttpProxy, "honor-http-proxy", "@"), /* Dummy options. */ ARGPARSE_s_n (oNoop, "sk-comments", "@"), ARGPARSE_s_n (oNoop, "no-sk-comments", "@"), ARGPARSE_s_n (oNoop, "compress-keys", "@"), ARGPARSE_s_n (oNoop, "compress-sigs", "@"), ARGPARSE_s_n (oNoop, "force-v3-sigs", "@"), ARGPARSE_s_n (oNoop, "no-force-v3-sigs", "@"), ARGPARSE_s_n (oNoop, "force-v4-certs", "@"), ARGPARSE_s_n (oNoop, "no-force-v4-certs", "@"), ARGPARSE_end () }; #ifdef ENABLE_SELINUX_HACKS #define ALWAYS_ADD_KEYRINGS 1 #else #define ALWAYS_ADD_KEYRINGS 0 #endif int g10_errors_seen = 0; static int utf8_strings = 0; static int maybe_setuid = 1; static char *build_list( const char *text, char letter, const char *(*mapf)(int), int (*chkf)(int) ); static void set_cmd( enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd ); static void print_mds( const char *fname, int algo ); static void add_notation_data( const char *string, int which ); static void add_policy_url( const char *string, int which ); static void add_keyserver_url( const char *string, int which ); static void emergency_cleanup (void); static char * make_libversion (const char *libname, const char *(*getfnc)(const char*)) { const char *s; char *result; if (maybe_setuid) { gcry_control (GCRYCTL_INIT_SECMEM, 0, 0); /* Drop setuid. */ maybe_setuid = 0; } s = getfnc (NULL); result = xmalloc (strlen (libname) + 1 + strlen (s) + 1); strcpy (stpcpy (stpcpy (result, libname), " "), s); return result; } static int build_list_pk_test_algo (int algo) { /* Show only one "RSA" string. If RSA_E or RSA_S is available RSA is also available. */ if (algo == PUBKEY_ALGO_RSA_E || algo == PUBKEY_ALGO_RSA_S) return GPG_ERR_DIGEST_ALGO; return openpgp_pk_test_algo (algo); } static const char * build_list_pk_algo_name (int algo) { return openpgp_pk_algo_name (algo); } static int build_list_cipher_test_algo (int algo) { return openpgp_cipher_test_algo (algo); } static const char * build_list_cipher_algo_name (int algo) { return openpgp_cipher_algo_name (algo); } static int build_list_md_test_algo (int algo) { /* By default we do not accept MD5 based signatures. To avoid confusion we do not announce support for it either. */ if (algo == DIGEST_ALGO_MD5) return GPG_ERR_DIGEST_ALGO; return openpgp_md_test_algo (algo); } static const char * build_list_md_algo_name (int algo) { return openpgp_md_algo_name (algo); } static const char * my_strusage( int level ) { static char *digests, *pubkeys, *ciphers, *zips, *ver_gcry; const char *p; switch( level ) { case 11: p = "@GPG@ (@GNUPG@)"; break; case 13: p = VERSION; break; case 17: p = PRINTABLE_OS_NAME; break; case 19: p = _("Please report bugs to <@EMAIL@>.\n"); break; case 20: if (!ver_gcry) ver_gcry = make_libversion ("libgcrypt", gcry_check_version); p = ver_gcry; break; #ifdef IS_DEVELOPMENT_VERSION case 25: p="NOTE: THIS IS A DEVELOPMENT VERSION!"; break; case 26: p="It is only intended for test purposes and should NOT be"; break; case 27: p="used in a production environment or with production keys!"; break; #endif case 1: case 40: p = _("Usage: @GPG@ [options] [files] (-h for help)"); break; case 41: p = _("Syntax: @GPG@ [options] [files]\n" "Sign, check, encrypt or decrypt\n" "Default operation depends on the input data\n"); break; case 31: p = "\nHome: "; break; #ifndef __riscos__ case 32: p = opt.homedir; break; #else /* __riscos__ */ case 32: p = make_filename(opt.homedir, NULL); break; #endif /* __riscos__ */ case 33: p = _("\nSupported algorithms:\n"); break; case 34: if (!pubkeys) pubkeys = build_list (_("Pubkey: "), 1, build_list_pk_algo_name, build_list_pk_test_algo ); p = pubkeys; break; case 35: if( !ciphers ) ciphers = build_list(_("Cipher: "), 'S', build_list_cipher_algo_name, build_list_cipher_test_algo ); p = ciphers; break; case 36: if( !digests ) digests = build_list(_("Hash: "), 'H', build_list_md_algo_name, build_list_md_test_algo ); p = digests; break; case 37: if( !zips ) zips = build_list(_("Compression: "),'Z', compress_algo_to_string, check_compress_algo); p = zips; break; default: p = NULL; } return p; } static char * build_list (const char *text, char letter, const char * (*mapf)(int), int (*chkf)(int)) { membuf_t mb; int indent; int i, j, len; const char *s; char *string; if (maybe_setuid) gcry_control (GCRYCTL_INIT_SECMEM, 0, 0); /* Drop setuid. */ indent = utf8_charcount (text); len = 0; init_membuf (&mb, 512); for (i=0; i <= 110; i++ ) { if (!chkf (i) && (s = mapf (i))) { if (mb.len - len > 60) { put_membuf_str (&mb, ",\n"); len = mb.len; for (j=0; j < indent; j++) put_membuf_str (&mb, " "); } else if (mb.len) put_membuf_str (&mb, ", "); else put_membuf_str (&mb, text); put_membuf_str (&mb, s); if (opt.verbose && letter) { char num[20]; if (letter == 1) snprintf (num, sizeof num, " (%d)", i); else snprintf (num, sizeof num, " (%c%d)", letter, i); put_membuf_str (&mb, num); } } } if (mb.len) put_membuf_str (&mb, "\n"); put_membuf (&mb, "", 1); string = get_membuf (&mb, NULL); return xrealloc (string, strlen (string)+1); } static void wrong_args( const char *text) { es_fprintf (es_stderr, _("usage: %s [options] %s\n"), GPG_NAME, text); g10_exit(2); } static char * make_username( const char *string ) { char *p; if( utf8_strings ) p = xstrdup(string); else p = native_to_utf8( string ); return p; } static void set_opt_session_env (const char *name, const char *value) { gpg_error_t err; err = session_env_setenv (opt.session_env, name, value); if (err) log_fatal ("error setting session environment: %s\n", gpg_strerror (err)); } /* Setup the debugging. With a LEVEL of NULL only the active debug flags are propagated to the subsystems. With LEVEL set, a specific set of debug flags is set; thus overriding all flags already set. */ static void set_debug (const char *level) { int numok = (level && digitp (level)); int numlvl = numok? atoi (level) : 0; if (!level) ; else if (!strcmp (level, "none") || (numok && numlvl < 1)) opt.debug = 0; else if (!strcmp (level, "basic") || (numok && numlvl <= 2)) opt.debug = DBG_MEMSTAT_VALUE; else if (!strcmp (level, "advanced") || (numok && numlvl <= 5)) opt.debug = DBG_MEMSTAT_VALUE|DBG_TRUST_VALUE|DBG_EXTPROG_VALUE; else if (!strcmp (level, "expert") || (numok && numlvl <= 8)) opt.debug = (DBG_MEMSTAT_VALUE|DBG_TRUST_VALUE|DBG_EXTPROG_VALUE |DBG_CACHE_VALUE|DBG_LOOKUP|DBG_FILTER_VALUE|DBG_PACKET_VALUE); else if (!strcmp (level, "guru") || numok) { opt.debug = ~0; /* Unless the "guru" string has been used we don't want to allow hashing debugging. The rationale is that people tend to select the highest debug value and would then clutter their disk with debug files which may reveal confidential data. */ if (numok) opt.debug &= ~(DBG_HASHING_VALUE); } else { log_error (_("invalid debug-level '%s' given\n"), level); g10_exit (2); } if (opt.debug & DBG_MEMORY_VALUE ) memory_debug_mode = 1; if (opt.debug & DBG_MEMSTAT_VALUE ) memory_stat_debug_mode = 1; if (opt.debug & DBG_MPI_VALUE) gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 2); if (opt.debug & DBG_CRYPTO_VALUE ) gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1); if (opt.debug & DBG_IOBUF_VALUE ) iobuf_debug_mode = 1; gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose); if (opt.debug) log_info ("enabled debug flags:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", (opt.debug & DBG_PACKET_VALUE )? " packet":"", (opt.debug & DBG_MPI_VALUE )? " mpi":"", (opt.debug & DBG_CRYPTO_VALUE )? " crypto":"", (opt.debug & DBG_FILTER_VALUE )? " filter":"", (opt.debug & DBG_IOBUF_VALUE )? " iobuf":"", (opt.debug & DBG_MEMORY_VALUE )? " memory":"", (opt.debug & DBG_CACHE_VALUE )? " cache":"", (opt.debug & DBG_MEMSTAT_VALUE)? " memstat":"", (opt.debug & DBG_TRUST_VALUE )? " trust":"", (opt.debug & DBG_HASHING_VALUE)? " hashing":"", (opt.debug & DBG_EXTPROG_VALUE)? " extprog":"", (opt.debug & DBG_CARD_IO_VALUE)? " cardio":"", (opt.debug & DBG_IPC_VALUE )? " ipc":"", (opt.debug & DBG_CLOCK_VALUE )? " clock":"", (opt.debug & DBG_LOOKUP_VALUE )? " lookup":""); } /* We need the home directory also in some other directories, so make sure that both variables are always in sync. */ static void set_homedir (const char *dir) { if (!dir) dir = ""; opt.homedir = dir; } /* We set the screen dimensions for UI purposes. Do not allow screens smaller than 80x24 for the sake of simplicity. */ static void set_screen_dimensions(void) { #ifndef HAVE_W32_SYSTEM char *str; str=getenv("COLUMNS"); if(str) opt.screen_columns=atoi(str); str=getenv("LINES"); if(str) opt.screen_lines=atoi(str); #endif if(opt.screen_columns<80 || opt.screen_columns>255) opt.screen_columns=80; if(opt.screen_lines<24 || opt.screen_lines>255) opt.screen_lines=24; } /* Helper to open a file FNAME either for reading or writing to be used with --status-file etc functions. Not generally useful but it avoids the riscos specific functions and well some Windows people might like it too. Prints an error message and returns -1 on error. On success the file descriptor is returned. */ static int open_info_file (const char *fname, int for_write, int binary) { #ifdef __riscos__ return riscos_fdopenfile (fname, for_write); #elif defined (ENABLE_SELINUX_HACKS) /* We can't allow these even when testing for a secured filename because files to be secured might not yet been secured. This is similar to the option file but in that case it is unlikely that sensitive information may be retrieved by means of error messages. */ (void)fname; (void)for_write; (void)binary; return -1; #else int fd; if (binary) binary = MY_O_BINARY; /* if (is_secured_filename (fname)) */ /* { */ /* fd = -1; */ /* gpg_err_set_errno (EPERM); */ /* } */ /* else */ /* { */ do { if (for_write) fd = open (fname, O_CREAT | O_TRUNC | O_WRONLY | binary, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP); else fd = open (fname, O_RDONLY | binary); } while (fd == -1 && errno == EINTR); /* } */ if ( fd == -1) log_error ( for_write? _("can't create '%s': %s\n") : _("can't open '%s': %s\n"), fname, strerror(errno)); return fd; #endif } static void set_cmd( enum cmd_and_opt_values *ret_cmd, enum cmd_and_opt_values new_cmd ) { enum cmd_and_opt_values cmd = *ret_cmd; if( !cmd || cmd == new_cmd ) cmd = new_cmd; else if( cmd == aSign && new_cmd == aEncr ) cmd = aSignEncr; else if( cmd == aEncr && new_cmd == aSign ) cmd = aSignEncr; else if( cmd == aSign && new_cmd == aSym ) cmd = aSignSym; else if( cmd == aSym && new_cmd == aSign ) cmd = aSignSym; else if( cmd == aSym && new_cmd == aEncr ) cmd = aEncrSym; else if( cmd == aEncr && new_cmd == aSym ) cmd = aEncrSym; else if (cmd == aSignEncr && new_cmd == aSym) cmd = aSignEncrSym; else if (cmd == aSignSym && new_cmd == aEncr) cmd = aSignEncrSym; else if (cmd == aEncrSym && new_cmd == aSign) cmd = aSignEncrSym; else if( ( cmd == aSign && new_cmd == aClearsign ) || ( cmd == aClearsign && new_cmd == aSign ) ) cmd = aClearsign; else { log_error(_("conflicting commands\n")); g10_exit(2); } *ret_cmd = cmd; } static void add_group(char *string) { char *name,*value; struct groupitem *item; /* Break off the group name */ name=strsep(&string,"="); if(string==NULL) { log_error(_("no = sign found in group definition '%s'\n"),name); return; } trim_trailing_ws(name,strlen(name)); /* Does this group already exist? */ for(item=opt.grouplist;item;item=item->next) if(strcasecmp(item->name,name)==0) break; if(!item) { item=xmalloc(sizeof(struct groupitem)); item->name=name; item->next=opt.grouplist; item->values=NULL; opt.grouplist=item; } /* Break apart the values */ while ((value= strsep(&string," \t"))) { if (*value) add_to_strlist2(&item->values,value,utf8_strings); } } static void rm_group(char *name) { struct groupitem *item,*last=NULL; trim_trailing_ws(name,strlen(name)); for(item=opt.grouplist;item;last=item,item=item->next) { if(strcasecmp(item->name,name)==0) { if(last) last->next=item->next; else opt.grouplist=item->next; free_strlist(item->values); xfree(item); break; } } } /* We need to check three things. 0) The homedir. It must be x00, a directory, and owned by the user. 1) The options/gpg.conf file. Okay unless it or its containing directory is group or other writable or not owned by us. Disable exec in this case. 2) Extensions. Same as #1. Returns true if the item is unsafe. */ static int check_permissions (const char *path, int item) { #if defined(HAVE_STAT) && !defined(HAVE_DOSISH_SYSTEM) static int homedir_cache=-1; char *tmppath,*dir; struct stat statbuf,dirbuf; int homedir=0,ret=0,checkonly=0; int perm=0,own=0,enc_dir_perm=0,enc_dir_own=0; if(opt.no_perm_warn) return 0; assert(item==0 || item==1 || item==2); /* extensions may attach a path */ if(item==2 && path[0]!=DIRSEP_C) { if(strchr(path,DIRSEP_C)) tmppath=make_filename(path,NULL); else tmppath=make_filename(gnupg_libdir (),path,NULL); } else tmppath=xstrdup(path); /* If the item is located in the homedir, but isn't the homedir, don't continue if we already checked the homedir itself. This is to avoid user confusion with an extra options file warning which could be rectified if the homedir itself had proper permissions. */ if(item!=0 && homedir_cache>-1 && ascii_strncasecmp(opt.homedir,tmppath,strlen(opt.homedir))==0) { ret=homedir_cache; goto end; } /* It's okay if the file or directory doesn't exist */ if(stat(tmppath,&statbuf)!=0) { ret=0; goto end; } /* Now check the enclosing directory. Theoretically, we could walk this test up to the root directory /, but for the sake of sanity, I'm stopping at one level down. */ dir=make_dirname(tmppath); if(stat(dir,&dirbuf)!=0 || !S_ISDIR(dirbuf.st_mode)) { /* Weird error */ ret=1; goto end; } xfree(dir); /* Assume failure */ ret=1; if(item==0) { /* The homedir must be x00, a directory, and owned by the user. */ if(S_ISDIR(statbuf.st_mode)) { if(statbuf.st_uid==getuid()) { if((statbuf.st_mode & (S_IRWXG|S_IRWXO))==0) ret=0; else perm=1; } else own=1; homedir_cache=ret; } } else if(item==1 || item==2) { /* The options or extension file. Okay unless it or its containing directory is group or other writable or not owned by us or root. */ if(S_ISREG(statbuf.st_mode)) { if(statbuf.st_uid==getuid() || statbuf.st_uid==0) { if((statbuf.st_mode & (S_IWGRP|S_IWOTH))==0) { /* it's not writable, so make sure the enclosing directory is also not writable */ if(dirbuf.st_uid==getuid() || dirbuf.st_uid==0) { if((dirbuf.st_mode & (S_IWGRP|S_IWOTH))==0) ret=0; else enc_dir_perm=1; } else enc_dir_own=1; } else { /* it's writable, so the enclosing directory had better not let people get to it. */ if(dirbuf.st_uid==getuid() || dirbuf.st_uid==0) { if((dirbuf.st_mode & (S_IRWXG|S_IRWXO))==0) ret=0; else perm=enc_dir_perm=1; /* unclear which one to fix! */ } else enc_dir_own=1; } } else own=1; } } else BUG(); if(!checkonly) { if(own) { if(item==0) log_info(_("WARNING: unsafe ownership on" " homedir '%s'\n"),tmppath); else if(item==1) log_info(_("WARNING: unsafe ownership on" " configuration file '%s'\n"),tmppath); else log_info(_("WARNING: unsafe ownership on" " extension '%s'\n"),tmppath); } if(perm) { if(item==0) log_info(_("WARNING: unsafe permissions on" " homedir '%s'\n"),tmppath); else if(item==1) log_info(_("WARNING: unsafe permissions on" " configuration file '%s'\n"),tmppath); else log_info(_("WARNING: unsafe permissions on" " extension '%s'\n"),tmppath); } if(enc_dir_own) { if(item==0) log_info(_("WARNING: unsafe enclosing directory ownership on" " homedir '%s'\n"),tmppath); else if(item==1) log_info(_("WARNING: unsafe enclosing directory ownership on" " configuration file '%s'\n"),tmppath); else log_info(_("WARNING: unsafe enclosing directory ownership on" " extension '%s'\n"),tmppath); } if(enc_dir_perm) { if(item==0) log_info(_("WARNING: unsafe enclosing directory permissions on" " homedir '%s'\n"),tmppath); else if(item==1) log_info(_("WARNING: unsafe enclosing directory permissions on" " configuration file '%s'\n"),tmppath); else log_info(_("WARNING: unsafe enclosing directory permissions on" " extension '%s'\n"),tmppath); } } end: xfree(tmppath); if(homedir) homedir_cache=ret; return ret; #else /*!(HAVE_STAT && !HAVE_DOSISH_SYSTEM)*/ (void)path; (void)item; return 0; #endif /*!(HAVE_STAT && !HAVE_DOSISH_SYSTEM)*/ } /* Print the OpenPGP defined algo numbers. */ static void print_algo_numbers(int (*checker)(int)) { int i,first=1; for(i=0;i<=110;i++) { if(!checker(i)) { if(first) first=0; else es_printf (";"); es_printf ("%d",i); } } } static void print_algo_names(int (*checker)(int),const char *(*mapper)(int)) { int i,first=1; for(i=0;i<=110;i++) { if(!checker(i)) { if(first) first=0; else es_printf (";"); es_printf ("%s",mapper(i)); } } } /* In the future, we can do all sorts of interesting configuration output here. For now, just give "group" as the Enigmail folks need it, and pubkey, cipher, hash, and compress as they may be useful for frontends. */ static void list_config(char *items) { int show_all = !items; char *name = NULL; const char *s; struct groupitem *giter; int first, iter; if(!opt.with_colons) return; while(show_all || (name=strsep(&items," "))) { int any=0; if(show_all || ascii_strcasecmp(name,"group")==0) { for (giter = opt.grouplist; giter; giter = giter->next) { strlist_t sl; es_fprintf (es_stdout, "cfg:group:"); es_write_sanitized (es_stdout, giter->name, strlen(giter->name), ":", NULL); es_putc (':', es_stdout); for(sl=giter->values; sl; sl=sl->next) { es_write_sanitized (es_stdout, sl->d, strlen (sl->d), ":;", NULL); if(sl->next) es_printf(";"); } es_printf("\n"); } any=1; } if(show_all || ascii_strcasecmp(name,"version")==0) { es_printf("cfg:version:"); es_write_sanitized (es_stdout, VERSION, strlen(VERSION), ":", NULL); es_printf ("\n"); any=1; } if(show_all || ascii_strcasecmp(name,"pubkey")==0) { es_printf ("cfg:pubkey:"); print_algo_numbers (build_list_pk_test_algo); es_printf ("\n"); any=1; } if(show_all || ascii_strcasecmp(name,"pubkeyname")==0) { es_printf ("cfg:pubkeyname:"); print_algo_names (build_list_pk_test_algo, build_list_pk_algo_name); es_printf ("\n"); any=1; } if(show_all || ascii_strcasecmp(name,"cipher")==0) { es_printf ("cfg:cipher:"); print_algo_numbers (build_list_cipher_test_algo); es_printf ("\n"); any=1; } if (show_all || !ascii_strcasecmp (name,"ciphername")) { es_printf ("cfg:ciphername:"); print_algo_names (build_list_cipher_test_algo, build_list_cipher_algo_name); es_printf ("\n"); any = 1; } if(show_all || ascii_strcasecmp(name,"digest")==0 || ascii_strcasecmp(name,"hash")==0) { es_printf ("cfg:digest:"); print_algo_numbers (build_list_md_test_algo); es_printf ("\n"); any=1; } if (show_all || !ascii_strcasecmp(name,"digestname") || !ascii_strcasecmp(name,"hashname")) { es_printf ("cfg:digestname:"); print_algo_names (build_list_md_test_algo, build_list_md_algo_name); es_printf ("\n"); any=1; } if(show_all || ascii_strcasecmp(name,"compress")==0) { es_printf ("cfg:compress:"); print_algo_numbers(check_compress_algo); es_printf ("\n"); any=1; } if (show_all || !ascii_strcasecmp(name,"ccid-reader-id")) { /* We ignore this for GnuPG 1.4 backward compatibility. */ any=1; } if (show_all || !ascii_strcasecmp (name,"curve")) { es_printf ("cfg:curve:"); for (iter=0, first=1; (s = openpgp_enum_curves (&iter)); first=0) es_printf ("%s%s", first?"":";", s); es_printf ("\n"); any=1; } /* Curve OIDs are rarely useful and thus only printed if requested. */ if (name && !ascii_strcasecmp (name,"curveoid")) { es_printf ("cfg:curveoid:"); for (iter=0, first=1; (s = openpgp_enum_curves (&iter)); first = 0) { s = openpgp_curve_to_oid (s, NULL); es_printf ("%s%s", first?"":";", s? s:"[?]"); } es_printf ("\n"); any=1; } if(show_all) break; if(!any) log_error(_("unknown configuration item '%s'\n"),name); } } /* List options and default values in the GPG Conf format. This is a new tool distributed with gnupg 1.9.x but we also want some limited support in older gpg versions. The output is the name of the configuration file and a list of options available for editing by gpgconf. */ static void gpgconf_list (const char *configfile) { char *configfile_esc = percent_escape (configfile, NULL); es_printf ("%s-%s.conf:%lu:\"%s\n", GPGCONF_NAME, GPG_NAME, GC_OPT_FLAG_DEFAULT, configfile_esc ? configfile_esc : "/dev/null"); es_printf ("verbose:%lu:\n", GC_OPT_FLAG_NONE); es_printf ("quiet:%lu:\n", GC_OPT_FLAG_NONE); es_printf ("keyserver:%lu:\n", GC_OPT_FLAG_NONE); es_printf ("reader-port:%lu:\n", GC_OPT_FLAG_NONE); es_printf ("default-key:%lu:\n", GC_OPT_FLAG_NONE); es_printf ("encrypt-to:%lu:\n", GC_OPT_FLAG_NONE); es_printf ("try-secret-key:%lu:\n", GC_OPT_FLAG_NONE); es_printf ("auto-key-locate:%lu:\n", GC_OPT_FLAG_NONE); es_printf ("log-file:%lu:\n", GC_OPT_FLAG_NONE); es_printf ("debug-level:%lu:\"none:\n", GC_OPT_FLAG_DEFAULT); es_printf ("group:%lu:\n", GC_OPT_FLAG_NONE); /* The next one is an info only item and should match the macros at the top of keygen.c */ es_printf ("default_pubkey_algo:%lu:\"%s:\n", GC_OPT_FLAG_DEFAULT, "RSA-2048"); xfree (configfile_esc); } static int parse_subpacket_list(char *list) { char *tok; byte subpackets[128],i; int count=0; if(!list) { /* No arguments means all subpackets */ memset(subpackets+1,1,sizeof(subpackets)-1); count=127; } else { memset(subpackets,0,sizeof(subpackets)); /* Merge with earlier copy */ if(opt.show_subpackets) { byte *in; for(in=opt.show_subpackets;*in;in++) { if(*in>127 || *in<1) BUG(); if(!subpackets[*in]) count++; subpackets[*in]=1; } } while((tok=strsep(&list," ,"))) { if(!*tok) continue; i=atoi(tok); if(i>127 || i<1) return 0; if(!subpackets[i]) count++; subpackets[i]=1; } } xfree(opt.show_subpackets); opt.show_subpackets=xmalloc(count+1); opt.show_subpackets[count--]=0; for(i=1;i<128 && count>=0;i++) if(subpackets[i]) opt.show_subpackets[count--]=i; return 1; } static int parse_list_options(char *str) { char *subpackets=""; /* something that isn't NULL */ struct parse_options lopts[]= { {"show-photos",LIST_SHOW_PHOTOS,NULL, N_("display photo IDs during key listings")}, {"show-usage",LIST_SHOW_USAGE,NULL, N_("show key usage information during key listings")}, {"show-policy-urls",LIST_SHOW_POLICY_URLS,NULL, N_("show policy URLs during signature listings")}, {"show-notations",LIST_SHOW_NOTATIONS,NULL, N_("show all notations during signature listings")}, {"show-std-notations",LIST_SHOW_STD_NOTATIONS,NULL, N_("show IETF standard notations during signature listings")}, {"show-standard-notations",LIST_SHOW_STD_NOTATIONS,NULL, NULL}, {"show-user-notations",LIST_SHOW_USER_NOTATIONS,NULL, N_("show user-supplied notations during signature listings")}, {"show-keyserver-urls",LIST_SHOW_KEYSERVER_URLS,NULL, N_("show preferred keyserver URLs during signature listings")}, {"show-uid-validity",LIST_SHOW_UID_VALIDITY,NULL, N_("show user ID validity during key listings")}, {"show-unusable-uids",LIST_SHOW_UNUSABLE_UIDS,NULL, N_("show revoked and expired user IDs in key listings")}, {"show-unusable-subkeys",LIST_SHOW_UNUSABLE_SUBKEYS,NULL, N_("show revoked and expired subkeys in key listings")}, {"show-keyring",LIST_SHOW_KEYRING,NULL, N_("show the keyring name in key listings")}, {"show-sig-expire",LIST_SHOW_SIG_EXPIRE,NULL, N_("show expiration dates during signature listings")}, {"show-sig-subpackets",LIST_SHOW_SIG_SUBPACKETS,NULL, NULL}, {NULL,0,NULL,NULL} }; /* C99 allows for non-constant initializers, but we'd like to compile everywhere, so fill in the show-sig-subpackets argument here. Note that if the parse_options array changes, we'll have to change the subscript here. */ lopts[12].value=&subpackets; if(parse_options(str,&opt.list_options,lopts,1)) { if(opt.list_options&LIST_SHOW_SIG_SUBPACKETS) { /* Unset so users can pass multiple lists in. */ opt.list_options&=~LIST_SHOW_SIG_SUBPACKETS; if(!parse_subpacket_list(subpackets)) return 0; } else if(subpackets==NULL && opt.show_subpackets) { /* User did 'no-show-subpackets' */ xfree(opt.show_subpackets); opt.show_subpackets=NULL; } return 1; } else return 0; } /* Collapses argc/argv into a single string that must be freed */ static char * collapse_args(int argc,char *argv[]) { char *str=NULL; int i,first=1,len=0; for(i=0;iflags = KEYDB_RESOURCE_FLAG_PRIMARY; break; case oShowKeyring: deprecated_warning(configname,configlineno,"--show-keyring", "--list-options ","show-keyring"); opt.list_options|=LIST_SHOW_KEYRING; break; case oDebug: opt.debug |= pargs.r.ret_ulong; break; case oDebugAll: opt.debug = ~0; break; case oDebugLevel: debug_level = pargs.r.ret_str; break; case oDebugIOLBF: break; /* Already set in pre-parse step. */ case oStatusFD: set_status_fd ( translate_sys2libc_fd_int (pargs.r.ret_int, 1) ); break; case oStatusFile: set_status_fd ( open_info_file (pargs.r.ret_str, 1, 0) ); break; case oAttributeFD: set_attrib_fd ( translate_sys2libc_fd_int (pargs.r.ret_int, 1) ); break; case oAttributeFile: set_attrib_fd ( open_info_file (pargs.r.ret_str, 1, 1) ); break; case oLoggerFD: log_set_fd (translate_sys2libc_fd_int (pargs.r.ret_int, 1)); break; case oLoggerFile: logfile = pargs.r.ret_str; break; case oWithFingerprint: opt.with_fingerprint = 1; opt.fingerprint++; break; case oWithICAOSpelling: opt.with_icao_spelling = 1; break; case oFingerprint: opt.fingerprint++; fpr_maybe_cmd = 1; break; case oWithKeygrip: opt.with_keygrip = 1; break; case oWithSecret: opt.with_secret = 1; break; case oSecretKeyring: /* Ignore this old option. */ break; case oOptions: /* config files may not be nested (silently ignore them) */ if( !configfp ) { xfree(configname); configname = xstrdup(pargs.r.ret_str); goto next_pass; } break; case oNoArmor: opt.no_armor=1; opt.armor=0; break; case oNoDefKeyring: default_keyring = 0; break; case oNoGreeting: nogreeting = 1; break; case oNoVerbose: opt.verbose = 0; gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose); opt.list_sigs=0; break; case oQuickRandom: gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0); break; case oEmitVersion: opt.emit_version++; break; case oNoEmitVersion: opt.emit_version=0; break; case oCompletesNeeded: opt.completes_needed = pargs.r.ret_int; break; case oMarginalsNeeded: opt.marginals_needed = pargs.r.ret_int; break; case oMaxCertDepth: opt.max_cert_depth = pargs.r.ret_int; break; #ifndef NO_TRUST_MODELS case oTrustDBName: trustdb_name = pargs.r.ret_str; break; #endif /*!NO_TRUST_MODELS*/ case oDefaultKey: opt.def_secret_key = pargs.r.ret_str; break; case oDefRecipient: if( *pargs.r.ret_str ) opt.def_recipient = make_username(pargs.r.ret_str); break; case oDefRecipientSelf: xfree(opt.def_recipient); opt.def_recipient = NULL; opt.def_recipient_self = 1; break; case oNoDefRecipient: xfree(opt.def_recipient); opt.def_recipient = NULL; opt.def_recipient_self = 0; break; case oNoOptions: opt.no_homedir_creation = 1; break; /* no-options */ case oHomedir: break; case oNoBatch: opt.batch = 0; break; case oWithKeyData: opt.with_key_data=1; /*FALLTHRU*/ case oWithColons: opt.with_colons=':'; break; case oWithSigCheck: opt.check_sigs = 1; /*FALLTHRU*/ case oWithSigList: opt.list_sigs = 1; break; case oSkipVerify: opt.skip_verify=1; break; case oSkipHiddenRecipients: opt.skip_hidden_recipients = 1; break; case oNoSkipHiddenRecipients: opt.skip_hidden_recipients = 0; break; case aListSecretKeys: set_cmd( &cmd, aListSecretKeys); break; #ifndef NO_TRUST_MODELS /* There are many programs (like mutt) that call gpg with --always-trust so keep this option around for a long time. */ case oAlwaysTrust: opt.trust_model=TM_ALWAYS; break; case oTrustModel: parse_trust_model(pargs.r.ret_str); break; #endif /*!NO_TRUST_MODELS*/ case oForceOwnertrust: log_info(_("Note: %s is not for normal use!\n"), "--force-ownertrust"); opt.force_ownertrust=string_to_trust_value(pargs.r.ret_str); if(opt.force_ownertrust==-1) { log_error("invalid ownertrust '%s'\n",pargs.r.ret_str); opt.force_ownertrust=0; } break; case oLoadExtension: /* Dummy so that gpg 1.4 conf files can work. Should eventually be removed. */ break; case oOpenPGP: case oRFC4880: /* This is effectively the same as RFC2440, but with "--enable-dsa2 --no-rfc2440-text --escape-from-lines --require-cross-certification". */ opt.compliance = CO_RFC4880; opt.flags.dsa2 = 1; opt.flags.require_cross_cert = 1; opt.rfc2440_text = 0; opt.allow_non_selfsigned_uid = 1; opt.allow_freeform_uid = 1; opt.escape_from = 1; opt.not_dash_escaped = 0; opt.def_cipher_algo = 0; opt.def_digest_algo = 0; opt.cert_digest_algo = 0; opt.compress_algo = -1; opt.s2k_mode = 3; /* iterated+salted */ opt.s2k_digest_algo = DIGEST_ALGO_SHA1; opt.s2k_cipher_algo = CIPHER_ALGO_3DES; break; case oRFC2440: opt.compliance = CO_RFC2440; opt.flags.dsa2 = 0; opt.rfc2440_text = 1; opt.allow_non_selfsigned_uid = 1; opt.allow_freeform_uid = 1; opt.escape_from = 0; opt.not_dash_escaped = 0; opt.def_cipher_algo = 0; opt.def_digest_algo = 0; opt.cert_digest_algo = 0; opt.compress_algo = -1; opt.s2k_mode = 3; /* iterated+salted */ opt.s2k_digest_algo = DIGEST_ALGO_SHA1; opt.s2k_cipher_algo = CIPHER_ALGO_3DES; break; case oPGP6: opt.compliance = CO_PGP6; break; case oPGP7: opt.compliance = CO_PGP7; break; case oPGP8: opt.compliance = CO_PGP8; break; case oGnuPG: opt.compliance = CO_GNUPG; break; case oRFC2440Text: opt.rfc2440_text=1; break; case oNoRFC2440Text: opt.rfc2440_text=0; break; case oSetFilename: if(utf8_strings) opt.set_filename = pargs.r.ret_str; else opt.set_filename = native_to_utf8(pargs.r.ret_str); break; case oForYourEyesOnly: eyes_only = 1; break; case oNoForYourEyesOnly: eyes_only = 0; break; case oSetPolicyURL: add_policy_url(pargs.r.ret_str,0); add_policy_url(pargs.r.ret_str,1); break; case oSigPolicyURL: add_policy_url(pargs.r.ret_str,0); break; case oCertPolicyURL: add_policy_url(pargs.r.ret_str,1); break; case oShowPolicyURL: deprecated_warning(configname,configlineno,"--show-policy-url", "--list-options ","show-policy-urls"); deprecated_warning(configname,configlineno,"--show-policy-url", "--verify-options ","show-policy-urls"); opt.list_options|=LIST_SHOW_POLICY_URLS; opt.verify_options|=VERIFY_SHOW_POLICY_URLS; break; case oNoShowPolicyURL: deprecated_warning(configname,configlineno,"--no-show-policy-url", "--list-options ","no-show-policy-urls"); deprecated_warning(configname,configlineno,"--no-show-policy-url", "--verify-options ","no-show-policy-urls"); opt.list_options&=~LIST_SHOW_POLICY_URLS; opt.verify_options&=~VERIFY_SHOW_POLICY_URLS; break; case oSigKeyserverURL: add_keyserver_url(pargs.r.ret_str,0); break; case oUseEmbeddedFilename: opt.flags.use_embedded_filename=1; break; case oNoUseEmbeddedFilename: opt.flags.use_embedded_filename=0; break; case oComment: if(pargs.r.ret_str[0]) append_to_strlist(&opt.comments,pargs.r.ret_str); break; case oDefaultComment: deprecated_warning(configname,configlineno, "--default-comment","--no-comments",""); /* fall through */ case oNoComments: free_strlist(opt.comments); opt.comments=NULL; break; case oThrowKeyids: opt.throw_keyids = 1; break; case oNoThrowKeyids: opt.throw_keyids = 0; break; case oShowPhotos: deprecated_warning(configname,configlineno,"--show-photos", "--list-options ","show-photos"); deprecated_warning(configname,configlineno,"--show-photos", "--verify-options ","show-photos"); opt.list_options|=LIST_SHOW_PHOTOS; opt.verify_options|=VERIFY_SHOW_PHOTOS; break; case oNoShowPhotos: deprecated_warning(configname,configlineno,"--no-show-photos", "--list-options ","no-show-photos"); deprecated_warning(configname,configlineno,"--no-show-photos", "--verify-options ","no-show-photos"); opt.list_options&=~LIST_SHOW_PHOTOS; opt.verify_options&=~VERIFY_SHOW_PHOTOS; break; case oPhotoViewer: opt.photo_viewer = pargs.r.ret_str; break; case oForceMDC: opt.force_mdc = 1; break; case oNoForceMDC: opt.force_mdc = 0; break; case oDisableMDC: opt.disable_mdc = 1; break; case oNoDisableMDC: opt.disable_mdc = 0; break; case oS2KMode: opt.s2k_mode = pargs.r.ret_int; break; case oS2KDigest: s2k_digest_string = xstrdup(pargs.r.ret_str); break; case oS2KCipher: s2k_cipher_string = xstrdup(pargs.r.ret_str); break; case oS2KCount: if (pargs.r.ret_int) opt.s2k_count = encode_s2k_iterations (pargs.r.ret_int); else opt.s2k_count = 0; /* Auto-calibrate when needed. */ break; case oNoEncryptTo: opt.no_encrypt_to = 1; break; case oEncryptTo: /* store the recipient in the second list */ sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings ); sl->flags = 1; break; case oHiddenEncryptTo: /* store the recipient in the second list */ sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings ); sl->flags = 1|2; break; case oRecipient: /* store the recipient */ add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings ); any_explicit_recipient = 1; break; case oHiddenRecipient: /* store the recipient with a flag */ sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings ); sl->flags = 2; any_explicit_recipient = 1; break; case oTrySecretKey: add_to_strlist2 (&opt.secret_keys_to_try, pargs.r.ret_str, utf8_strings); break; case oTextmodeShort: opt.textmode = 2; break; case oTextmode: opt.textmode=1; break; case oNoTextmode: opt.textmode=0; break; case oExpert: opt.expert = 1; break; case oNoExpert: opt.expert = 0; break; case oDefSigExpire: if(*pargs.r.ret_str!='\0') { if(parse_expire_string(pargs.r.ret_str)==(u32)-1) log_error(_("'%s' is not a valid signature expiration\n"), pargs.r.ret_str); else opt.def_sig_expire=pargs.r.ret_str; } break; case oAskSigExpire: opt.ask_sig_expire = 1; break; case oNoAskSigExpire: opt.ask_sig_expire = 0; break; case oDefCertExpire: if(*pargs.r.ret_str!='\0') { if(parse_expire_string(pargs.r.ret_str)==(u32)-1) log_error(_("'%s' is not a valid signature expiration\n"), pargs.r.ret_str); else opt.def_cert_expire=pargs.r.ret_str; } break; case oAskCertExpire: opt.ask_cert_expire = 1; break; case oNoAskCertExpire: opt.ask_cert_expire = 0; break; case oDefCertLevel: opt.def_cert_level=pargs.r.ret_int; break; case oMinCertLevel: opt.min_cert_level=pargs.r.ret_int; break; case oAskCertLevel: opt.ask_cert_level = 1; break; case oNoAskCertLevel: opt.ask_cert_level = 0; break; case oLocalUser: /* store the local users */ add_to_strlist2( &locusr, pargs.r.ret_str, utf8_strings ); break; case oCompress: /* this is the -z command line option */ opt.compress_level = opt.bz2_compress_level = pargs.r.ret_int; break; case oCompressLevel: opt.compress_level = pargs.r.ret_int; break; case oBZ2CompressLevel: opt.bz2_compress_level = pargs.r.ret_int; break; case oBZ2DecompressLowmem: opt.bz2_decompress_lowmem=1; break; case oPassphrase: set_passphrase_from_string(pargs.r.ret_str); break; case oPassphraseFD: pwfd = translate_sys2libc_fd_int (pargs.r.ret_int, 0); break; case oPassphraseFile: pwfd = open_info_file (pargs.r.ret_str, 0, 1); break; case oPassphraseRepeat: opt.passphrase_repeat = pargs.r.ret_int; break; case oPinentryMode: opt.pinentry_mode = parse_pinentry_mode (pargs.r.ret_str); if (opt.pinentry_mode == -1) log_error (_("invalid pinentry mode '%s'\n"), pargs.r.ret_str); break; case oCommandFD: opt.command_fd = translate_sys2libc_fd_int (pargs.r.ret_int, 0); break; case oCommandFile: opt.command_fd = open_info_file (pargs.r.ret_str, 0, 1); break; case oCipherAlgo: def_cipher_string = xstrdup(pargs.r.ret_str); break; case oDigestAlgo: def_digest_string = xstrdup(pargs.r.ret_str); break; case oCompressAlgo: /* If it is all digits, stick a Z in front of it for later. This is for backwards compatibility with versions that took the compress algorithm number. */ { char *pt=pargs.r.ret_str; while(*pt) { if (!isascii (*pt) || !isdigit (*pt)) break; pt++; } if(*pt=='\0') { compress_algo_string=xmalloc(strlen(pargs.r.ret_str)+2); strcpy(compress_algo_string,"Z"); strcat(compress_algo_string,pargs.r.ret_str); } else compress_algo_string = xstrdup(pargs.r.ret_str); } break; case oCertDigestAlgo: cert_digest_string = xstrdup(pargs.r.ret_str); break; case oNoSecmemWarn: gcry_control (GCRYCTL_DISABLE_SECMEM_WARN); break; case oRequireSecmem: require_secmem=1; break; case oNoRequireSecmem: require_secmem=0; break; case oNoPermissionWarn: opt.no_perm_warn=1; break; case oNoMDCWarn: opt.no_mdc_warn=1; break; case oDisplayCharset: if( set_native_charset( pargs.r.ret_str ) ) log_error(_("'%s' is not a valid character set\n"), pargs.r.ret_str); break; case oNotDashEscaped: opt.not_dash_escaped = 1; break; case oEscapeFrom: opt.escape_from = 1; break; case oNoEscapeFrom: opt.escape_from = 0; break; case oLockOnce: opt.lock_once = 1; break; case oLockNever: dotlock_disable (); break; case oLockMultiple: #ifndef __riscos__ opt.lock_once = 0; #else /* __riscos__ */ riscos_not_implemented("lock-multiple"); #endif /* __riscos__ */ break; case oKeyServer: { keyserver_spec_t keyserver; keyserver = parse_keyserver_uri (pargs.r.ret_str, 0); if (!keyserver) log_error (_("could not parse keyserver URL\n")); else { /* We only support a single keyserver. Later ones override earlier ones. (Since we parse the config file first and then the command line arguments, the command line takes precedence.) */ if (opt.keyserver) free_keyserver_spec (opt.keyserver); opt.keyserver = keyserver; } } break; case oKeyServerOptions: if(!parse_keyserver_options(pargs.r.ret_str)) { if(configname) log_error(_("%s:%d: invalid keyserver options\n"), configname,configlineno); else log_error(_("invalid keyserver options\n")); } break; case oImportOptions: if(!parse_import_options(pargs.r.ret_str,&opt.import_options,1)) { if(configname) log_error(_("%s:%d: invalid import options\n"), configname,configlineno); else log_error(_("invalid import options\n")); } break; case oExportOptions: if(!parse_export_options(pargs.r.ret_str,&opt.export_options,1)) { if(configname) log_error(_("%s:%d: invalid export options\n"), configname,configlineno); else log_error(_("invalid export options\n")); } break; case oListOptions: if(!parse_list_options(pargs.r.ret_str)) { if(configname) log_error(_("%s:%d: invalid list options\n"), configname,configlineno); else log_error(_("invalid list options\n")); } break; case oVerifyOptions: { struct parse_options vopts[]= { {"show-photos",VERIFY_SHOW_PHOTOS,NULL, N_("display photo IDs during signature verification")}, {"show-policy-urls",VERIFY_SHOW_POLICY_URLS,NULL, N_("show policy URLs during signature verification")}, {"show-notations",VERIFY_SHOW_NOTATIONS,NULL, N_("show all notations during signature verification")}, {"show-std-notations",VERIFY_SHOW_STD_NOTATIONS,NULL, N_("show IETF standard notations during signature verification")}, {"show-standard-notations",VERIFY_SHOW_STD_NOTATIONS,NULL, NULL}, {"show-user-notations",VERIFY_SHOW_USER_NOTATIONS,NULL, N_("show user-supplied notations during signature verification")}, {"show-keyserver-urls",VERIFY_SHOW_KEYSERVER_URLS,NULL, N_("show preferred keyserver URLs during signature verification")}, {"show-uid-validity",VERIFY_SHOW_UID_VALIDITY,NULL, N_("show user ID validity during signature verification")}, {"show-unusable-uids",VERIFY_SHOW_UNUSABLE_UIDS,NULL, N_("show revoked and expired user IDs in signature verification")}, {"show-primary-uid-only",VERIFY_SHOW_PRIMARY_UID_ONLY,NULL, N_("show only the primary user ID in signature verification")}, {"pka-lookups",VERIFY_PKA_LOOKUPS,NULL, N_("validate signatures with PKA data")}, {"pka-trust-increase",VERIFY_PKA_TRUST_INCREASE,NULL, N_("elevate the trust of signatures with valid PKA data")}, {NULL,0,NULL,NULL} }; if(!parse_options(pargs.r.ret_str,&opt.verify_options,vopts,1)) { if(configname) log_error(_("%s:%d: invalid verify options\n"), configname,configlineno); else log_error(_("invalid verify options\n")); } } break; case oTempDir: opt.temp_dir=pargs.r.ret_str; break; case oExecPath: if(set_exec_path(pargs.r.ret_str)) log_error(_("unable to set exec-path to %s\n"),pargs.r.ret_str); else opt.exec_path_set=1; break; case oSetNotation: add_notation_data( pargs.r.ret_str, 0 ); add_notation_data( pargs.r.ret_str, 1 ); break; case oSigNotation: add_notation_data( pargs.r.ret_str, 0 ); break; case oCertNotation: add_notation_data( pargs.r.ret_str, 1 ); break; case oShowNotation: deprecated_warning(configname,configlineno,"--show-notation", "--list-options ","show-notations"); deprecated_warning(configname,configlineno,"--show-notation", "--verify-options ","show-notations"); opt.list_options|=LIST_SHOW_NOTATIONS; opt.verify_options|=VERIFY_SHOW_NOTATIONS; break; case oNoShowNotation: deprecated_warning(configname,configlineno,"--no-show-notation", "--list-options ","no-show-notations"); deprecated_warning(configname,configlineno,"--no-show-notation", "--verify-options ","no-show-notations"); opt.list_options&=~LIST_SHOW_NOTATIONS; opt.verify_options&=~VERIFY_SHOW_NOTATIONS; break; case oUtf8Strings: utf8_strings = 1; break; case oNoUtf8Strings: utf8_strings = 0; break; case oDisableCipherAlgo: { int algo = string_to_cipher_algo (pargs.r.ret_str); gcry_cipher_ctl (NULL, GCRYCTL_DISABLE_ALGO, &algo, sizeof algo); } break; case oDisablePubkeyAlgo: { int algo = gcry_pk_map_name (pargs.r.ret_str); gcry_pk_ctl (GCRYCTL_DISABLE_ALGO, &algo, sizeof algo); } break; case oNoSigCache: opt.no_sig_cache = 1; break; case oNoSigCreateCheck: opt.no_sig_create_check = 1; break; case oAllowNonSelfsignedUID: opt.allow_non_selfsigned_uid = 1; break; case oNoAllowNonSelfsignedUID: opt.allow_non_selfsigned_uid=0; break; case oAllowFreeformUID: opt.allow_freeform_uid = 1; break; case oNoAllowFreeformUID: opt.allow_freeform_uid = 0; break; case oNoLiteral: opt.no_literal = 1; break; case oSetFilesize: opt.set_filesize = pargs.r.ret_ulong; break; case oFastListMode: opt.fast_list_mode = 1; break; case oFixedListMode: /* Dummy */ break; case oLegacyListMode: opt.legacy_list_mode = 1; break; case oPrintPKARecords: opt.print_pka_records = 1; break; case oListOnly: opt.list_only=1; break; case oIgnoreTimeConflict: opt.ignore_time_conflict = 1; break; case oIgnoreValidFrom: opt.ignore_valid_from = 1; break; case oIgnoreCrcError: opt.ignore_crc_error = 1; break; case oIgnoreMDCError: opt.ignore_mdc_error = 1; break; case oNoRandomSeedFile: use_random_seed = 0; break; case oAutoKeyRetrieve: case oNoAutoKeyRetrieve: if(pargs.r_opt==oAutoKeyRetrieve) opt.keyserver_options.options|=KEYSERVER_AUTO_KEY_RETRIEVE; else opt.keyserver_options.options&=~KEYSERVER_AUTO_KEY_RETRIEVE; deprecated_warning(configname,configlineno, pargs.r_opt==oAutoKeyRetrieve?"--auto-key-retrieve": "--no-auto-key-retrieve","--keyserver-options ", pargs.r_opt==oAutoKeyRetrieve?"auto-key-retrieve": "no-auto-key-retrieve"); break; case oShowSessionKey: opt.show_session_key = 1; break; case oOverrideSessionKey: opt.override_session_key = pargs.r.ret_str; break; case oMergeOnly: deprecated_warning(configname,configlineno,"--merge-only", "--import-options ","merge-only"); opt.import_options|=IMPORT_MERGE_ONLY; break; case oAllowSecretKeyImport: /* obsolete */ break; case oTryAllSecrets: opt.try_all_secrets = 1; break; case oTrustedKey: register_trusted_key( pargs.r.ret_str ); break; case oEnableSpecialFilenames: iobuf_enable_special_filenames (1); break; case oNoExpensiveTrustChecks: opt.no_expensive_trust_checks=1; break; case oAutoCheckTrustDB: opt.no_auto_check_trustdb=0; break; case oNoAutoCheckTrustDB: opt.no_auto_check_trustdb=1; break; case oPreservePermissions: opt.preserve_permissions=1; break; case oDefaultPreferenceList: opt.def_preference_list = pargs.r.ret_str; break; case oDefaultKeyserverURL: { keyserver_spec_t keyserver; keyserver = parse_keyserver_uri (pargs.r.ret_str,1 ); if (!keyserver) log_error (_("could not parse keyserver URL\n")); else free_keyserver_spec (keyserver); opt.def_keyserver_url = pargs.r.ret_str; } break; case oPersonalCipherPreferences: pers_cipher_list=pargs.r.ret_str; break; case oPersonalDigestPreferences: pers_digest_list=pargs.r.ret_str; break; case oPersonalCompressPreferences: pers_compress_list=pargs.r.ret_str; break; case oAgentProgram: opt.agent_program = pargs.r.ret_str; break; case oDirmngrProgram: opt.dirmngr_program = pargs.r.ret_str; break; case oDisplay: set_opt_session_env ("DISPLAY", pargs.r.ret_str); break; case oTTYname: set_opt_session_env ("GPG_TTY", pargs.r.ret_str); break; case oTTYtype: set_opt_session_env ("TERM", pargs.r.ret_str); break; case oXauthority: set_opt_session_env ("XAUTHORITY", pargs.r.ret_str); break; case oLCctype: opt.lc_ctype = pargs.r.ret_str; break; case oLCmessages: opt.lc_messages = pargs.r.ret_str; break; case oGroup: add_group(pargs.r.ret_str); break; case oUnGroup: rm_group(pargs.r.ret_str); break; case oNoGroups: while(opt.grouplist) { struct groupitem *iter=opt.grouplist; free_strlist(iter->values); opt.grouplist=opt.grouplist->next; xfree(iter); } break; case oStrict: case oNoStrict: /* Not used */ break; case oMangleDosFilenames: opt.mangle_dos_filenames = 1; break; case oNoMangleDosFilenames: opt.mangle_dos_filenames = 0; break; case oEnableProgressFilter: opt.enable_progress_filter = 1; break; case oMultifile: multifile=1; break; case oKeyidFormat: if(ascii_strcasecmp(pargs.r.ret_str,"short")==0) opt.keyid_format=KF_SHORT; else if(ascii_strcasecmp(pargs.r.ret_str,"long")==0) opt.keyid_format=KF_LONG; else if(ascii_strcasecmp(pargs.r.ret_str,"0xshort")==0) opt.keyid_format=KF_0xSHORT; else if(ascii_strcasecmp(pargs.r.ret_str,"0xlong")==0) opt.keyid_format=KF_0xLONG; else log_error("unknown keyid-format '%s'\n",pargs.r.ret_str); break; case oExitOnStatusWriteError: opt.exit_on_status_write_error = 1; break; case oLimitCardInsertTries: opt.limit_card_insert_tries = pargs.r.ret_int; break; case oRequireCrossCert: opt.flags.require_cross_cert=1; break; case oNoRequireCrossCert: opt.flags.require_cross_cert=0; break; case oAutoKeyLocate: if(!parse_auto_key_locate(pargs.r.ret_str)) { if(configname) log_error(_("%s:%d: invalid auto-key-locate list\n"), configname,configlineno); else log_error(_("invalid auto-key-locate list\n")); } break; case oNoAutoKeyLocate: release_akl(); break; case oEnableLargeRSA: #if SECMEM_BUFFER_SIZE >= 65536 opt.flags.large_rsa=1; #else if (configname) log_info("%s:%d: WARNING: gpg not built with large secure " "memory buffer. Ignoring enable-large-rsa\n", configname,configlineno); else log_info("WARNING: gpg not built with large secure " "memory buffer. Ignoring --enable-large-rsa\n"); #endif /* SECMEM_BUFFER_SIZE >= 65536 */ break; case oDisableLargeRSA: opt.flags.large_rsa=0; break; case oEnableDSA2: opt.flags.dsa2=1; break; case oDisableDSA2: opt.flags.dsa2=0; break; case oAllowMultisigVerification: case oAllowMultipleMessages: opt.flags.allow_multiple_messages=1; break; case oNoAllowMultipleMessages: opt.flags.allow_multiple_messages=0; break; case oAllowWeakDigestAlgos: opt.flags.allow_weak_digest_algos = 1; break; case oFakedSystemTime: { time_t faked_time = isotime2epoch (pargs.r.ret_str); if (faked_time == (time_t)(-1)) faked_time = (time_t)strtoul (pargs.r.ret_str, NULL, 10); gnupg_set_time (faked_time, 0); } break; case oNoAutostart: opt.autostart = 0; break; case oNoop: break; default: pargs.err = configfp? ARGPARSE_PRINT_WARNING:ARGPARSE_PRINT_ERROR; break; } } if (configfp) { fclose( configfp ); configfp = NULL; /* Remember the first config file name. */ if (!save_configname) save_configname = configname; else xfree(configname); configname = NULL; goto next_pass; } xfree(configname); configname = NULL; if (log_get_errorcount (0)) g10_exit(2); /* The command --gpgconf-list is pretty simple and may be called directly after the option parsing. */ if (cmd == aGPGConfList) { gpgconf_list (save_configname ? save_configname : default_configname); g10_exit (0); } xfree (save_configname); xfree (default_configname); if( nogreeting ) greeting = 0; if( greeting ) { es_fprintf (es_stderr, "%s %s; %s\n", strusage(11), strusage(13), strusage(14) ); es_fprintf (es_stderr, "%s\n", strusage(15) ); } #ifdef IS_DEVELOPMENT_VERSION if (!opt.batch) { const char *s; if((s=strusage(25))) log_info("%s\n",s); if((s=strusage(26))) log_info("%s\n",s); if((s=strusage(27))) log_info("%s\n",s); } #endif /* FIXME: We should use logging to a file only in server mode; however we have not yet implemetyed that. Thus we try to get away with --batch as indication for logging to file required. */ if (logfile && opt.batch) { log_set_file (logfile); log_set_prefix (NULL, 1|2|4); } if (opt.verbose > 2) log_info ("using character set '%s'\n", get_native_charset ()); if( may_coredump && !opt.quiet ) log_info(_("WARNING: program may create a core file!\n")); if (eyes_only) { if (opt.set_filename) log_info(_("WARNING: %s overrides %s\n"), "--for-your-eyes-only","--set-filename"); opt.set_filename="_CONSOLE"; } if (opt.no_literal) { log_info(_("Note: %s is not for normal use!\n"), "--no-literal"); if (opt.textmode) log_error(_("%s not allowed with %s!\n"), "--textmode", "--no-literal" ); if (opt.set_filename) log_error(_("%s makes no sense with %s!\n"), eyes_only?"--for-your-eyes-only":"--set-filename", "--no-literal" ); } if (opt.set_filesize) log_info(_("Note: %s is not for normal use!\n"), "--set-filesize"); if( opt.batch ) tty_batchmode( 1 ); if (gnupg_faked_time_p ()) { gnupg_isotime_t tbuf; log_info (_("WARNING: running with faked system time: ")); gnupg_get_isotime (tbuf); dump_isotime (tbuf); log_printf ("\n"); } /* Print a warning if an argument looks like an option. */ if (!opt.quiet && !(pargs.flags & ARGPARSE_FLAG_STOP_SEEN)) { int i; for (i=0; i < argc; i++) if (argv[i][0] == '-' && argv[i][1] == '-') log_info (_("Note: '%s' is not considered an option\n"), argv[i]); } gcry_control (GCRYCTL_RESUME_SECMEM_WARN); if(require_secmem && !got_secmem) { log_info(_("will not run with insecure memory due to %s\n"), "--require-secmem"); g10_exit(2); } set_debug (debug_level); if (DBG_CLOCK) log_clock ("start"); /* Do these after the switch(), so they can override settings. */ if(PGP6) { /* That does not anymore work becuase we have no more support for v3 signatures. */ opt.disable_mdc=1; opt.escape_from=1; opt.ask_sig_expire=0; } else if(PGP7) { /* That does not anymore work because we have no more support for v3 signatures. */ opt.escape_from=1; opt.ask_sig_expire=0; } else if(PGP8) { opt.escape_from=1; } if( def_cipher_string ) { opt.def_cipher_algo = string_to_cipher_algo (def_cipher_string); xfree(def_cipher_string); def_cipher_string = NULL; if ( openpgp_cipher_test_algo (opt.def_cipher_algo) ) log_error(_("selected cipher algorithm is invalid\n")); } if( def_digest_string ) { opt.def_digest_algo = string_to_digest_algo (def_digest_string); xfree(def_digest_string); def_digest_string = NULL; if ( openpgp_md_test_algo (opt.def_digest_algo) ) log_error(_("selected digest algorithm is invalid\n")); } if( compress_algo_string ) { opt.compress_algo = string_to_compress_algo(compress_algo_string); xfree(compress_algo_string); compress_algo_string = NULL; if( check_compress_algo(opt.compress_algo) ) log_error(_("selected compression algorithm is invalid\n")); } if( cert_digest_string ) { opt.cert_digest_algo = string_to_digest_algo (cert_digest_string); xfree(cert_digest_string); cert_digest_string = NULL; if (openpgp_md_test_algo(opt.cert_digest_algo)) log_error(_("selected certification digest algorithm is invalid\n")); } if( s2k_cipher_string ) { opt.s2k_cipher_algo = string_to_cipher_algo (s2k_cipher_string); xfree(s2k_cipher_string); s2k_cipher_string = NULL; if (openpgp_cipher_test_algo (opt.s2k_cipher_algo)) log_error(_("selected cipher algorithm is invalid\n")); } if( s2k_digest_string ) { opt.s2k_digest_algo = string_to_digest_algo (s2k_digest_string); xfree(s2k_digest_string); s2k_digest_string = NULL; if (openpgp_md_test_algo(opt.s2k_digest_algo)) log_error(_("selected digest algorithm is invalid\n")); } if( opt.completes_needed < 1 ) log_error(_("completes-needed must be greater than 0\n")); if( opt.marginals_needed < 2 ) log_error(_("marginals-needed must be greater than 1\n")); if( opt.max_cert_depth < 1 || opt.max_cert_depth > 255 ) log_error(_("max-cert-depth must be in the range from 1 to 255\n")); if(opt.def_cert_level<0 || opt.def_cert_level>3) log_error(_("invalid default-cert-level; must be 0, 1, 2, or 3\n")); if( opt.min_cert_level < 1 || opt.min_cert_level > 3 ) log_error(_("invalid min-cert-level; must be 1, 2, or 3\n")); switch( opt.s2k_mode ) { case 0: log_info(_("Note: simple S2K mode (0) is strongly discouraged\n")); break; case 1: case 3: break; default: log_error(_("invalid S2K mode; must be 0, 1 or 3\n")); } /* This isn't actually needed, but does serve to error out if the string is invalid. */ if(opt.def_preference_list && keygen_set_std_prefs(opt.def_preference_list,0)) log_error(_("invalid default preferences\n")); if(pers_cipher_list && keygen_set_std_prefs(pers_cipher_list,PREFTYPE_SYM)) log_error(_("invalid personal cipher preferences\n")); if(pers_digest_list && keygen_set_std_prefs(pers_digest_list,PREFTYPE_HASH)) log_error(_("invalid personal digest preferences\n")); if(pers_compress_list && keygen_set_std_prefs(pers_compress_list,PREFTYPE_ZIP)) log_error(_("invalid personal compress preferences\n")); /* We don't support all possible commands with multifile yet */ if(multifile) { char *cmdname; switch(cmd) { case aSign: cmdname="--sign"; break; case aClearsign: cmdname="--clearsign"; break; case aDetachedSign: cmdname="--detach-sign"; break; case aSym: cmdname="--symmetric"; break; case aEncrSym: cmdname="--symmetric --encrypt"; break; case aStore: cmdname="--store"; break; default: cmdname=NULL; break; } if(cmdname) log_error(_("%s does not yet work with %s\n"),cmdname,"--multifile"); } if( log_get_errorcount(0) ) g10_exit(2); if(opt.compress_level==0) opt.compress_algo=COMPRESS_ALGO_NONE; /* Check our chosen algorithms against the list of legal algorithms. */ if(!GNUPG) { const char *badalg=NULL; preftype_t badtype=PREFTYPE_NONE; if(opt.def_cipher_algo && !algo_available(PREFTYPE_SYM,opt.def_cipher_algo,NULL)) { badalg = openpgp_cipher_algo_name (opt.def_cipher_algo); badtype = PREFTYPE_SYM; } else if(opt.def_digest_algo && !algo_available(PREFTYPE_HASH,opt.def_digest_algo,NULL)) { badalg = gcry_md_algo_name (opt.def_digest_algo); badtype = PREFTYPE_HASH; } else if(opt.cert_digest_algo && !algo_available(PREFTYPE_HASH,opt.cert_digest_algo,NULL)) { badalg = gcry_md_algo_name (opt.cert_digest_algo); badtype = PREFTYPE_HASH; } else if(opt.compress_algo!=-1 && !algo_available(PREFTYPE_ZIP,opt.compress_algo,NULL)) { badalg = compress_algo_to_string(opt.compress_algo); badtype = PREFTYPE_ZIP; } if(badalg) { switch(badtype) { case PREFTYPE_SYM: log_info(_("you may not use cipher algorithm '%s'" " while in %s mode\n"), badalg,compliance_option_string()); break; case PREFTYPE_HASH: log_info(_("you may not use digest algorithm '%s'" " while in %s mode\n"), badalg,compliance_option_string()); break; case PREFTYPE_ZIP: log_info(_("you may not use compression algorithm '%s'" " while in %s mode\n"), badalg,compliance_option_string()); break; default: BUG(); } compliance_failure(); } } /* Set the random seed file. */ if( use_random_seed ) { char *p = make_filename(opt.homedir, "random_seed", NULL ); gcry_control (GCRYCTL_SET_RANDOM_SEED_FILE, p); if (!access (p, F_OK)) register_secured_file (p); xfree(p); } /* If there is no command but the --fingerprint is given, default to the --list-keys command. */ if (!cmd && fpr_maybe_cmd) { set_cmd (&cmd, aListKeys); } if( opt.verbose > 1 ) set_packet_list_mode(1); /* Add the keyrings, but not for some special commands. We always need to add the keyrings if we are running under SELinux, this is so that the rings are added to the list of secured files. */ if( ALWAYS_ADD_KEYRINGS || (cmd != aDeArmor && cmd != aEnArmor && cmd != aGPGConfTest) ) { if (!nrings || default_keyring) /* Add default ring. */ keydb_add_resource ("pubring" EXTSEP_S GPGEXT_GPG, KEYDB_RESOURCE_FLAG_DEFAULT); for (sl = nrings; sl; sl = sl->next ) keydb_add_resource (sl->d, sl->flags); } FREE_STRLIST(nrings); if (cmd == aGPGConfTest) g10_exit(0); if( pwfd != -1 ) /* Read the passphrase now. */ read_passphrase_from_fd( pwfd ); fname = argc? *argv : NULL; if(fname && utf8_strings) opt.flags.utf8_filename=1; ctrl = xcalloc (1, sizeof *ctrl); gpg_init_default_ctrl (ctrl); #ifndef NO_TRUST_MODELS switch (cmd) { case aPrimegen: case aPrintMD: case aPrintMDs: case aGenRandom: case aDeArmor: case aEnArmor: break; case aFixTrustDB: case aExportOwnerTrust: rc = setup_trustdb (0, trustdb_name); break; case aListTrustDB: rc = setup_trustdb (argc? 1:0, trustdb_name); break; default: /* If we are using TM_ALWAYS, we do not need to create the trustdb. */ rc = setup_trustdb (opt.trust_model != TM_ALWAYS, trustdb_name); break; } if (rc) log_error (_("failed to initialize the TrustDB: %s\n"), gpg_strerror (rc)); #endif /*!NO_TRUST_MODELS*/ switch (cmd) { case aStore: case aSym: case aSign: case aSignSym: case aClearsign: if (!opt.quiet && any_explicit_recipient) log_info (_("WARNING: recipients (-r) given " "without using public key encryption\n")); break; default: break; } /* Check for certain command whether we need to migrate a secring.gpg to the gpg-agent. */ switch (cmd) { case aListSecretKeys: case aSign: case aSignEncr: case aSignEncrSym: case aSignSym: case aClearsign: case aDecrypt: case aSignKey: case aLSignKey: case aEditKey: case aPasswd: case aDeleteSecretKeys: case aDeleteSecretAndPublicKeys: case aQuickKeygen: + case aQuickAddUid: case aFullKeygen: case aKeygen: case aImport: case aExportSecret: case aExportSecretSub: case aGenRevoke: case aDesigRevoke: case aCardEdit: case aChangePIN: migrate_secring (ctrl); break; case aListKeys: if (opt.with_secret) migrate_secring (ctrl); break; default: break; } /* The command dispatcher. */ switch( cmd ) { case aServer: gpg_server (ctrl); break; case aStore: /* only store the file */ if( argc > 1 ) wrong_args(_("--store [filename]")); if( (rc = encrypt_store(fname)) ) log_error ("storing '%s' failed: %s\n", print_fname_stdin(fname),gpg_strerror (rc) ); break; case aSym: /* encrypt the given file only with the symmetric cipher */ if( argc > 1 ) wrong_args(_("--symmetric [filename]")); if( (rc = encrypt_symmetric(fname)) ) log_error (_("symmetric encryption of '%s' failed: %s\n"), print_fname_stdin(fname),gpg_strerror (rc) ); break; case aEncr: /* encrypt the given file */ if(multifile) encrypt_crypt_files (ctrl, argc, argv, remusr); else { if( argc > 1 ) wrong_args(_("--encrypt [filename]")); if( (rc = encrypt_crypt (ctrl, -1, fname, remusr, 0, NULL, -1)) ) log_error("%s: encryption failed: %s\n", print_fname_stdin(fname), gpg_strerror (rc) ); } break; case aEncrSym: /* This works with PGP 8 in the sense that it acts just like a symmetric message. It doesn't work at all with 2 or 6. It might work with 7, but alas, I don't have a copy to test with right now. */ if( argc > 1 ) wrong_args(_("--symmetric --encrypt [filename]")); else if(opt.s2k_mode==0) log_error(_("you cannot use --symmetric --encrypt" " with --s2k-mode 0\n")); else if(PGP6 || PGP7) log_error(_("you cannot use --symmetric --encrypt" " while in %s mode\n"),compliance_option_string()); else { if( (rc = encrypt_crypt (ctrl, -1, fname, remusr, 1, NULL, -1)) ) log_error("%s: encryption failed: %s\n", print_fname_stdin(fname), gpg_strerror (rc) ); } break; case aSign: /* sign the given file */ sl = NULL; if( detached_sig ) { /* sign all files */ for( ; argc; argc--, argv++ ) add_to_strlist( &sl, *argv ); } else { if( argc > 1 ) wrong_args(_("--sign [filename]")); if( argc ) { sl = xmalloc_clear( sizeof *sl + strlen(fname)); strcpy(sl->d, fname); } } if( (rc = sign_file (ctrl, sl, detached_sig, locusr, 0, NULL, NULL)) ) log_error("signing failed: %s\n", gpg_strerror (rc) ); free_strlist(sl); break; case aSignEncr: /* sign and encrypt the given file */ if( argc > 1 ) wrong_args(_("--sign --encrypt [filename]")); if( argc ) { sl = xmalloc_clear( sizeof *sl + strlen(fname)); strcpy(sl->d, fname); } else sl = NULL; if ((rc = sign_file (ctrl, sl, detached_sig, locusr, 1, remusr, NULL))) log_error("%s: sign+encrypt failed: %s\n", print_fname_stdin(fname), gpg_strerror (rc) ); free_strlist(sl); break; case aSignEncrSym: /* sign and encrypt the given file */ if( argc > 1 ) wrong_args(_("--symmetric --sign --encrypt [filename]")); else if(opt.s2k_mode==0) log_error(_("you cannot use --symmetric --sign --encrypt" " with --s2k-mode 0\n")); else if(PGP6 || PGP7) log_error(_("you cannot use --symmetric --sign --encrypt" " while in %s mode\n"),compliance_option_string()); else { if( argc ) { sl = xmalloc_clear( sizeof *sl + strlen(fname)); strcpy(sl->d, fname); } else sl = NULL; if ((rc = sign_file (ctrl, sl, detached_sig, locusr, 2, remusr, NULL))) log_error("%s: symmetric+sign+encrypt failed: %s\n", print_fname_stdin(fname), gpg_strerror (rc) ); free_strlist(sl); } break; case aSignSym: /* sign and conventionally encrypt the given file */ if (argc > 1) wrong_args(_("--sign --symmetric [filename]")); rc = sign_symencrypt_file (fname, locusr); if (rc) log_error("%s: sign+symmetric failed: %s\n", print_fname_stdin(fname), gpg_strerror (rc) ); break; case aClearsign: /* make a clearsig */ if( argc > 1 ) wrong_args(_("--clearsign [filename]")); if( (rc = clearsign_file(fname, locusr, NULL)) ) log_error("%s: clearsign failed: %s\n", print_fname_stdin(fname), gpg_strerror (rc) ); break; case aVerify: if (multifile) { if ((rc = verify_files (ctrl, argc, argv))) log_error("verify files failed: %s\n", gpg_strerror (rc) ); } else { if ((rc = verify_signatures (ctrl, argc, argv))) log_error("verify signatures failed: %s\n", gpg_strerror (rc) ); } break; case aDecrypt: if (multifile) decrypt_messages (ctrl, argc, argv); else { if( argc > 1 ) wrong_args(_("--decrypt [filename]")); if( (rc = decrypt_message (ctrl, fname) )) log_error("decrypt_message failed: %s\n", gpg_strerror (rc) ); } break; case aQuickSignKey: case aQuickLSignKey: { const char *fpr; if (argc < 1) wrong_args ("--quick-[l]sign-key fingerprint [userids]"); fpr = *argv++; argc--; sl = NULL; for( ; argc; argc--, argv++) append_to_strlist2 (&sl, *argv, utf8_strings); keyedit_quick_sign (ctrl, fpr, sl, locusr, (cmd == aQuickLSignKey)); free_strlist (sl); } break; case aSignKey: if( argc != 1 ) wrong_args(_("--sign-key user-id")); /* fall through */ case aLSignKey: if( argc != 1 ) wrong_args(_("--lsign-key user-id")); /* fall through */ sl=NULL; if(cmd==aSignKey) append_to_strlist(&sl,"sign"); else if(cmd==aLSignKey) append_to_strlist(&sl,"lsign"); else BUG(); append_to_strlist( &sl, "save" ); username = make_username( fname ); keyedit_menu (ctrl, username, locusr, sl, 0, 0 ); xfree(username); free_strlist(sl); break; case aEditKey: /* Edit a key signature */ if( !argc ) wrong_args(_("--edit-key user-id [commands]")); username = make_username( fname ); if( argc > 1 ) { sl = NULL; for( argc--, argv++ ; argc; argc--, argv++ ) append_to_strlist( &sl, *argv ); keyedit_menu (ctrl, username, locusr, sl, 0, 1 ); free_strlist(sl); } else keyedit_menu (ctrl, username, locusr, NULL, 0, 1 ); xfree(username); break; case aPasswd: if (argc != 1) wrong_args (_("--passwd ")); else { username = make_username (fname); keyedit_passwd (ctrl, username); xfree (username); } break; case aDeleteKeys: case aDeleteSecretKeys: case aDeleteSecretAndPublicKeys: sl = NULL; /* I'm adding these in reverse order as add_to_strlist2 reverses them again, and it's easier to understand in the proper order :) */ for( ; argc; argc-- ) add_to_strlist2( &sl, argv[argc-1], utf8_strings ); delete_keys(sl,cmd==aDeleteSecretKeys,cmd==aDeleteSecretAndPublicKeys); free_strlist(sl); break; case aCheckKeys: opt.check_sigs = 1; case aListSigs: opt.list_sigs = 1; case aListKeys: sl = NULL; for( ; argc; argc--, argv++ ) add_to_strlist2( &sl, *argv, utf8_strings ); public_key_list (ctrl, sl, 0); free_strlist(sl); break; case aListSecretKeys: sl = NULL; for( ; argc; argc--, argv++ ) add_to_strlist2( &sl, *argv, utf8_strings ); secret_key_list (ctrl, sl); free_strlist(sl); break; case aLocateKeys: sl = NULL; for (; argc; argc--, argv++) add_to_strlist2( &sl, *argv, utf8_strings ); public_key_list (ctrl, sl, 1); free_strlist (sl); break; case aQuickKeygen: if (argc != 1 ) wrong_args("--gen-key user-id"); username = make_username (fname); quick_generate_keypair (username); xfree (username); break; case aKeygen: /* generate a key */ if( opt.batch ) { if( argc > 1 ) wrong_args("--gen-key [parameterfile]"); generate_keypair (ctrl, 0, argc? *argv : NULL, NULL, 0); } else { if( argc ) wrong_args("--gen-key"); generate_keypair (ctrl, 0, NULL, NULL, 0); } break; case aFullKeygen: /* Generate a key with all options. */ if (opt.batch) { if (argc > 1) wrong_args ("--full-gen-key [parameterfile]"); generate_keypair (ctrl, 1, argc? *argv : NULL, NULL, 0); } else { if (argc) wrong_args("--full-gen-key"); generate_keypair (ctrl, 1, NULL, NULL, 0); } break; + case aQuickAddUid: + { + const char *uid, *newuid; + + if (argc != 2) + wrong_args ("--quick-adduid USER-ID NEW-USER-ID"); + uid = *argv++; argc--; + newuid = *argv++; argc--; + keyedit_quick_adduid (ctrl, uid, newuid); + } + break; + case aFastImport: opt.import_options |= IMPORT_FAST; case aImport: import_keys (ctrl, argc? argv:NULL, argc, NULL, opt.import_options); break; /* TODO: There are a number of command that use this same "make strlist, call function, report error, free strlist" pattern. Join them together here and avoid all that duplicated code. */ case aExport: case aSendKeys: case aRecvKeys: sl = NULL; for( ; argc; argc--, argv++ ) append_to_strlist2( &sl, *argv, utf8_strings ); if( cmd == aSendKeys ) rc = keyserver_export (ctrl, sl ); else if( cmd == aRecvKeys ) rc = keyserver_import (ctrl, sl ); else rc = export_pubkeys (ctrl, sl, opt.export_options); if(rc) { if(cmd==aSendKeys) log_error(_("keyserver send failed: %s\n"),gpg_strerror (rc)); else if(cmd==aRecvKeys) log_error(_("keyserver receive failed: %s\n"),gpg_strerror (rc)); else log_error(_("key export failed: %s\n"),gpg_strerror (rc)); } free_strlist(sl); break; case aSearchKeys: sl = NULL; for (; argc; argc--, argv++) append_to_strlist2 (&sl, *argv, utf8_strings); rc = keyserver_search (ctrl, sl); if (rc) log_error (_("keyserver search failed: %s\n"), gpg_strerror (rc)); free_strlist (sl); break; case aRefreshKeys: sl = NULL; for( ; argc; argc--, argv++ ) append_to_strlist2( &sl, *argv, utf8_strings ); rc = keyserver_refresh (ctrl, sl); if(rc) log_error(_("keyserver refresh failed: %s\n"),gpg_strerror (rc)); free_strlist(sl); break; case aFetchKeys: sl = NULL; for( ; argc; argc--, argv++ ) append_to_strlist2( &sl, *argv, utf8_strings ); rc = keyserver_fetch (ctrl, sl); if(rc) log_error("key fetch failed: %s\n",gpg_strerror (rc)); free_strlist(sl); break; case aExportSecret: sl = NULL; for( ; argc; argc--, argv++ ) add_to_strlist2( &sl, *argv, utf8_strings ); export_seckeys (ctrl, sl); free_strlist(sl); break; case aExportSecretSub: sl = NULL; for( ; argc; argc--, argv++ ) add_to_strlist2( &sl, *argv, utf8_strings ); export_secsubkeys (ctrl, sl); free_strlist(sl); break; case aGenRevoke: if( argc != 1 ) wrong_args("--gen-revoke user-id"); username = make_username(*argv); gen_revoke( username ); xfree( username ); break; case aDesigRevoke: if( argc != 1 ) wrong_args("--desig-revoke user-id"); username = make_username(*argv); gen_desig_revoke( username, locusr ); xfree( username ); break; case aDeArmor: if( argc > 1 ) wrong_args("--dearmor [file]"); rc = dearmor_file( argc? *argv: NULL ); if( rc ) log_error(_("dearmoring failed: %s\n"), gpg_strerror (rc)); break; case aEnArmor: if( argc > 1 ) wrong_args("--enarmor [file]"); rc = enarmor_file( argc? *argv: NULL ); if( rc ) log_error(_("enarmoring failed: %s\n"), gpg_strerror (rc)); break; case aPrimegen: #if 0 /*FIXME*/ { int mode = argc < 2 ? 0 : atoi(*argv); if( mode == 1 && argc == 2 ) { mpi_print (es_stdout, generate_public_prime( atoi(argv[1]) ), 1); } else if( mode == 2 && argc == 3 ) { mpi_print (es_stdout, generate_elg_prime( 0, atoi(argv[1]), atoi(argv[2]), NULL,NULL ), 1); } else if( mode == 3 && argc == 3 ) { MPI *factors; mpi_print (es_stdout, generate_elg_prime( 1, atoi(argv[1]), atoi(argv[2]), NULL,&factors ), 1); es_putc ('\n', es_stdout); mpi_print (es_stdout, factors[0], 1 ); /* print q */ } else if( mode == 4 && argc == 3 ) { MPI g = mpi_alloc(1); mpi_print (es_stdout, generate_elg_prime( 0, atoi(argv[1]), atoi(argv[2]), g, NULL ), 1); es_putc ('\n', es_stdout); mpi_print (es_stdout, g, 1 ); mpi_free (g); } else wrong_args("--gen-prime mode bits [qbits] "); es_putc ('\n', es_stdout); } #endif wrong_args("--gen-prime not yet supported "); break; case aGenRandom: { int level = argc ? atoi(*argv):0; int count = argc > 1 ? atoi(argv[1]): 0; int endless = !count; if( argc < 1 || argc > 2 || level < 0 || level > 2 || count < 0 ) wrong_args("--gen-random 0|1|2 [count]"); while( endless || count ) { byte *p; /* Wee need a multiple of 3, so that in case of armored output we get a correct string. No linefolding is done, as it is best to levae this to other tools */ size_t n = !endless && count < 99? count : 99; p = gcry_random_bytes (n, level); #ifdef HAVE_DOSISH_SYSTEM setmode ( fileno(stdout), O_BINARY ); #endif if (opt.armor) { char *tmp = make_radix64_string (p, n); es_fputs (tmp, es_stdout); xfree (tmp); if (n%3 == 1) es_putc ('=', es_stdout); if (n%3) es_putc ('=', es_stdout); } else { es_fwrite( p, n, 1, es_stdout ); } xfree(p); if( !endless ) count -= n; } if (opt.armor) es_putc ('\n', es_stdout); } break; case aPrintMD: if( argc < 1) wrong_args("--print-md algo [files]"); { int all_algos = (**argv=='*' && !(*argv)[1]); int algo = all_algos? 0 : gcry_md_map_name (*argv); if( !algo && !all_algos ) log_error(_("invalid hash algorithm '%s'\n"), *argv ); else { argc--; argv++; if( !argc ) print_mds(NULL, algo); else { for(; argc; argc--, argv++ ) print_mds(*argv, algo); } } } break; case aPrintMDs: /* old option */ if( !argc ) print_mds(NULL,0); else { for(; argc; argc--, argv++ ) print_mds(*argv,0); } break; #ifndef NO_TRUST_MODELS case aListTrustDB: if( !argc ) list_trustdb(NULL); else { for( ; argc; argc--, argv++ ) list_trustdb( *argv ); } break; case aUpdateTrustDB: if( argc ) wrong_args("--update-trustdb"); update_trustdb(); break; case aCheckTrustDB: /* Old versions allowed for arguments - ignore them */ check_trustdb(); break; case aFixTrustDB: how_to_fix_the_trustdb (); break; case aListTrustPath: if( !argc ) wrong_args("--list-trust-path "); for( ; argc; argc--, argv++ ) { username = make_username( *argv ); list_trust_path( username ); xfree(username); } break; case aExportOwnerTrust: if( argc ) wrong_args("--export-ownertrust"); export_ownertrust(); break; case aImportOwnerTrust: if( argc > 1 ) wrong_args("--import-ownertrust [file]"); import_ownertrust( argc? *argv:NULL ); break; #endif /*!NO_TRUST_MODELS*/ case aRebuildKeydbCaches: if (argc) wrong_args ("--rebuild-keydb-caches"); keydb_rebuild_caches (1); break; #ifdef ENABLE_CARD_SUPPORT case aCardStatus: if (argc) wrong_args ("--card-status"); card_status (es_stdout, NULL, 0); break; case aCardEdit: if (argc) { sl = NULL; for (argc--, argv++ ; argc; argc--, argv++) append_to_strlist (&sl, *argv); card_edit (ctrl, sl); free_strlist (sl); } else card_edit (ctrl, NULL); break; case aChangePIN: if (!argc) change_pin (0,1); else if (argc == 1) change_pin (atoi (*argv),1); else wrong_args ("--change-pin [no]"); break; #endif /* ENABLE_CARD_SUPPORT*/ case aListConfig: { char *str=collapse_args(argc,argv); list_config(str); xfree(str); } break; case aListGcryptConfig: /* Fixme: It would be nice to integrate that with --list-config but unfortunately there is no way yet to have libgcrypt print it to an estream for further parsing. */ gcry_control (GCRYCTL_PRINT_CONFIG, stdout); break; case aListPackets: opt.list_packets=2; default: if( argc > 1 ) wrong_args(_("[filename]")); /* Issue some output for the unix newbie */ if (!fname && !opt.outfile && gnupg_isatty (fileno (stdin)) && gnupg_isatty (fileno (stdout)) && gnupg_isatty (fileno (stderr))) log_info(_("Go ahead and type your message ...\n")); a = iobuf_open(fname); if (a && is_secured_file (iobuf_get_fd (a))) { iobuf_close (a); a = NULL; gpg_err_set_errno (EPERM); } if( !a ) log_error(_("can't open '%s'\n"), print_fname_stdin(fname)); else { if( !opt.no_armor ) { if( use_armor_filter( a ) ) { afx = new_armor_context (); push_armor_filter (afx, a); } } if( cmd == aListPackets ) { set_packet_list_mode(1); opt.list_packets=1; } rc = proc_packets (ctrl, NULL, a ); if( rc ) log_error("processing message failed: %s\n", gpg_strerror (rc)); iobuf_close(a); } break; } /* cleanup */ gpg_deinit_default_ctrl (ctrl); xfree (ctrl); release_armor_context (afx); FREE_STRLIST(remusr); FREE_STRLIST(locusr); g10_exit(0); return 8; /*NEVER REACHED*/ } /* Note: This function is used by signal handlers!. */ static void emergency_cleanup (void) { gcry_control (GCRYCTL_TERM_SECMEM ); } void g10_exit( int rc ) { gcry_control (GCRYCTL_UPDATE_RANDOM_SEED_FILE); if (DBG_CLOCK) log_clock ("stop"); if ( (opt.debug & DBG_MEMSTAT_VALUE) ) { gcry_control (GCRYCTL_DUMP_MEMORY_STATS); gcry_control (GCRYCTL_DUMP_RANDOM_STATS); } if (opt.debug) gcry_control (GCRYCTL_DUMP_SECMEM_STATS ); emergency_cleanup (); rc = rc? rc : log_get_errorcount(0)? 2 : g10_errors_seen? 1 : 0; exit (rc); } /* Pretty-print hex hashes. This assumes at least an 80-character display, but there are a few other similar assumptions in the display code. */ static void print_hex (gcry_md_hd_t md, int algo, const char *fname) { int i,n,count,indent=0; const byte *p; if (fname) indent = es_printf("%s: ",fname); if (indent>40) { es_printf ("\n"); indent=0; } if (algo==DIGEST_ALGO_RMD160) indent += es_printf("RMD160 = "); else if (algo>0) indent += es_printf("%6s = ", gcry_md_algo_name (algo)); else algo = abs(algo); count = indent; p = gcry_md_read (md, algo); n = gcry_md_get_algo_dlen (algo); count += es_printf ("%02X",*p++); for(i=1;i79) { es_printf ("\n%*s",indent," "); count = indent; } else count += es_printf(" "); if (!(i%8)) count += es_printf(" "); } else if (n==20) { if(!(i%2)) { if(count+4>79) { es_printf ("\n%*s",indent," "); count=indent; } else count += es_printf(" "); } if (!(i%10)) count += es_printf(" "); } else { if(!(i%4)) { if (count+8>79) { es_printf ("\n%*s",indent," "); count=indent; } else count += es_printf(" "); } } count += es_printf("%02X",*p); } es_printf ("\n"); } static void print_hashline( gcry_md_hd_t md, int algo, const char *fname ) { int i, n; const byte *p; if ( fname ) { for (p = fname; *p; p++ ) { if ( *p <= 32 || *p > 127 || *p == ':' || *p == '%' ) es_printf ("%%%02X", *p ); else es_putc (*p, es_stdout); } } es_putc (':', es_stdout); es_printf ("%d:", algo); p = gcry_md_read (md, algo); n = gcry_md_get_algo_dlen (algo); for(i=0; i < n ; i++, p++ ) es_printf ("%02X", *p); es_fputs (":\n", es_stdout); } static void print_mds( const char *fname, int algo ) { estream_t fp; char buf[1024]; size_t n; gcry_md_hd_t md; if (!fname) { fp = es_stdin; es_set_binary (fp); } else { fp = es_fopen (fname, "rb" ); if (fp && is_secured_file (es_fileno (fp))) { es_fclose (fp); fp = NULL; gpg_err_set_errno (EPERM); } } if (!fp) { log_error("%s: %s\n", fname?fname:"[stdin]", strerror(errno) ); return; } gcry_md_open (&md, 0, 0); if (algo) gcry_md_enable (md, algo); else { if (!gcry_md_test_algo (GCRY_MD_MD5)) gcry_md_enable (md, GCRY_MD_MD5); gcry_md_enable (md, GCRY_MD_SHA1); if (!gcry_md_test_algo (GCRY_MD_RMD160)) gcry_md_enable (md, GCRY_MD_RMD160); if (!gcry_md_test_algo (GCRY_MD_SHA224)) gcry_md_enable (md, GCRY_MD_SHA224); if (!gcry_md_test_algo (GCRY_MD_SHA256)) gcry_md_enable (md, GCRY_MD_SHA256); if (!gcry_md_test_algo (GCRY_MD_SHA384)) gcry_md_enable (md, GCRY_MD_SHA384); if (!gcry_md_test_algo (GCRY_MD_SHA512)) gcry_md_enable (md, GCRY_MD_SHA512); } while ((n=es_fread (buf, 1, DIM(buf), fp))) gcry_md_write (md, buf, n); if (es_ferror(fp)) log_error ("%s: %s\n", fname?fname:"[stdin]", strerror(errno)); else { gcry_md_final (md); if (opt.with_colons) { if ( algo ) print_hashline (md, algo, fname); else { if (!gcry_md_test_algo (GCRY_MD_MD5)) print_hashline( md, GCRY_MD_MD5, fname ); print_hashline( md, GCRY_MD_SHA1, fname ); if (!gcry_md_test_algo (GCRY_MD_RMD160)) print_hashline( md, GCRY_MD_RMD160, fname ); if (!gcry_md_test_algo (GCRY_MD_SHA224)) print_hashline (md, GCRY_MD_SHA224, fname); if (!gcry_md_test_algo (GCRY_MD_SHA256)) print_hashline( md, GCRY_MD_SHA256, fname ); if (!gcry_md_test_algo (GCRY_MD_SHA384)) print_hashline ( md, GCRY_MD_SHA384, fname ); if (!gcry_md_test_algo (GCRY_MD_SHA512)) print_hashline ( md, GCRY_MD_SHA512, fname ); } } else { if (algo) print_hex (md, -algo, fname); else { if (!gcry_md_test_algo (GCRY_MD_MD5)) print_hex (md, GCRY_MD_MD5, fname); print_hex (md, GCRY_MD_SHA1, fname ); if (!gcry_md_test_algo (GCRY_MD_RMD160)) print_hex (md, GCRY_MD_RMD160, fname ); if (!gcry_md_test_algo (GCRY_MD_SHA224)) print_hex (md, GCRY_MD_SHA224, fname); if (!gcry_md_test_algo (GCRY_MD_SHA256)) print_hex (md, GCRY_MD_SHA256, fname ); if (!gcry_md_test_algo (GCRY_MD_SHA384)) print_hex (md, GCRY_MD_SHA384, fname ); if (!gcry_md_test_algo (GCRY_MD_SHA512)) print_hex (md, GCRY_MD_SHA512, fname ); } } } gcry_md_close (md); if (fp != es_stdin) es_fclose (fp); } /**************** * Check the supplied name,value string and add it to the notation * data to be used for signatures. which==0 for sig notations, and 1 * for cert notations. */ static void add_notation_data( const char *string, int which ) { struct notation *notation; notation=string_to_notation(string,utf8_strings); if(notation) { if(which) { notation->next=opt.cert_notations; opt.cert_notations=notation; } else { notation->next=opt.sig_notations; opt.sig_notations=notation; } } } static void add_policy_url( const char *string, int which ) { unsigned int i,critical=0; strlist_t sl; if(*string=='!') { string++; critical=1; } for(i=0;iflags |= 1; } static void add_keyserver_url( const char *string, int which ) { unsigned int i,critical=0; strlist_t sl; if(*string=='!') { string++; critical=1; } for(i=0;iflags |= 1; } diff --git a/g10/keyedit.c b/g10/keyedit.c index 804eff19f..be15b095c 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -1,5285 +1,5383 @@ -/* keyedit.c - keyedit stuff - * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, - * 2008, 2009, 2010 Free Software Foundation, Inc. - * Copyright (C) 2013, 2014 Werner Koch +/* keyedit.c - Edit properties of a key + * Copyright (C) 1998-2010 Free Software Foundation, Inc. + * Copyright (C) 1998-2015 Werner Koch * * 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 #include #ifdef HAVE_LIBREADLINE # define GNUPG_LIBREADLINE_H_INCLUDED # include #endif #include "gpg.h" #include "options.h" #include "packet.h" #include "status.h" #include "iobuf.h" #include "keydb.h" #include "photoid.h" #include "util.h" #include "main.h" #include "trustdb.h" #include "filter.h" #include "ttyio.h" #include "status.h" #include "i18n.h" #include "keyserver-internal.h" #include "call-agent.h" static void show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose); static void show_names (estream_t fp, KBNODE keyblock, PKT_public_key * pk, unsigned int flag, int with_prefs); static void show_key_with_all_names (estream_t fp, KBNODE keyblock, int only_marked, int with_revoker, int with_fpr, int with_subkeys, int with_prefs, int nowarn); static void show_key_and_fingerprint (KBNODE keyblock); static void subkey_expire_warning (kbnode_t keyblock); -static int menu_adduid (KBNODE keyblock, int photo, const char *photo_name); +static int menu_adduid (KBNODE keyblock, int photo, const char *photo_name, + const char *uidstr); static void menu_deluid (KBNODE pub_keyblock); static int menu_delsig (KBNODE pub_keyblock); static int menu_clean (KBNODE keyblock, int self_only); static void menu_delkey (KBNODE pub_keyblock); static int menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive); static int menu_expire (KBNODE pub_keyblock); static int menu_backsign (KBNODE pub_keyblock); static int menu_set_primary_uid (KBNODE pub_keyblock); static int menu_set_preferences (KBNODE pub_keyblock); static int menu_set_keyserver_url (const char *url, KBNODE pub_keyblock); static int menu_set_notation (const char *string, KBNODE pub_keyblock); static int menu_select_uid (KBNODE keyblock, int idx); static int menu_select_uid_namehash (KBNODE keyblock, const char *namehash); static int menu_select_key (KBNODE keyblock, int idx); static int count_uids (KBNODE keyblock); static int count_uids_with_flag (KBNODE keyblock, unsigned flag); static int count_keys_with_flag (KBNODE keyblock, unsigned flag); static int count_selected_uids (KBNODE keyblock); static int real_uids_left (KBNODE keyblock); static int count_selected_keys (KBNODE keyblock); static int menu_revsig (KBNODE keyblock); static int menu_revuid (KBNODE keyblock); static int menu_revkey (KBNODE pub_keyblock); static int menu_revsubkey (KBNODE pub_keyblock); #ifndef NO_TRUST_MODELS static int enable_disable_key (KBNODE keyblock, int disable); #endif /*!NO_TRUST_MODELS*/ static void menu_showphoto (KBNODE keyblock); static int update_trust = 0; #define CONTROL_D ('D' - 'A' + 1) #define NODFLG_BADSIG (1<<0) /* Bad signature. */ #define NODFLG_NOKEY (1<<1) /* No public key. */ #define NODFLG_SIGERR (1<<2) /* Other sig error. */ #define NODFLG_MARK_A (1<<4) /* Temporary mark. */ #define NODFLG_DELSIG (1<<5) /* To be deleted. */ #define NODFLG_SELUID (1<<8) /* Indicate the selected userid. */ #define NODFLG_SELKEY (1<<9) /* Indicate the selected key. */ #define NODFLG_SELSIG (1<<10) /* Indicate a selected signature. */ struct sign_attrib { int non_exportable, non_revocable; struct revocation_reason_info *reason; byte trust_depth, trust_value; char *trust_regexp; }; /* TODO: Fix duplicated code between here and the check-sigs/list-sigs code in keylist.c. */ static int print_and_check_one_sig_colon (KBNODE keyblock, KBNODE node, int *inv_sigs, int *no_key, int *oth_err, int *is_selfsig, int print_without_key) { PKT_signature *sig = node->pkt->pkt.signature; int rc, sigrc; /* TODO: Make sure a cached sig record here still has the pk that issued it. See also keylist.c:list_keyblock_print */ rc = check_key_signature (keyblock, node, is_selfsig); switch (gpg_err_code (rc)) { case 0: node->flag &= ~(NODFLG_BADSIG | NODFLG_NOKEY | NODFLG_SIGERR); sigrc = '!'; break; case GPG_ERR_BAD_SIGNATURE: node->flag = NODFLG_BADSIG; sigrc = '-'; if (inv_sigs) ++ * inv_sigs; break; case GPG_ERR_NO_PUBKEY: case GPG_ERR_UNUSABLE_PUBKEY: node->flag = NODFLG_NOKEY; sigrc = '?'; if (no_key) ++ * no_key; break; default: node->flag = NODFLG_SIGERR; sigrc = '%'; if (oth_err) ++ * oth_err; break; } if (sigrc != '?' || print_without_key) { es_printf ("sig:%c::%d:%08lX%08lX:%lu:%lu:", sigrc, sig->pubkey_algo, (ulong) sig->keyid[0], (ulong) sig->keyid[1], (ulong) sig->timestamp, (ulong) sig->expiredate); if (sig->trust_depth || sig->trust_value) es_printf ("%d %d", sig->trust_depth, sig->trust_value); es_printf (":"); if (sig->trust_regexp) es_write_sanitized (es_stdout, sig->trust_regexp, strlen (sig->trust_regexp), ":", NULL); es_printf ("::%02x%c\n", sig->sig_class, sig->flags.exportable ? 'x' : 'l'); if (opt.show_subpackets) print_subpackets_colon (sig); } return (sigrc == '!'); } /* * Print information about a signature, check it and return true * if the signature is okay. NODE must be a signature packet. */ static int print_and_check_one_sig (KBNODE keyblock, KBNODE node, int *inv_sigs, int *no_key, int *oth_err, int *is_selfsig, int print_without_key) { PKT_signature *sig = node->pkt->pkt.signature; int rc, sigrc; int is_rev = sig->sig_class == 0x30; /* TODO: Make sure a cached sig record here still has the pk that issued it. See also keylist.c:list_keyblock_print */ rc = check_key_signature (keyblock, node, is_selfsig); switch (gpg_err_code (rc)) { case 0: node->flag &= ~(NODFLG_BADSIG | NODFLG_NOKEY | NODFLG_SIGERR); sigrc = '!'; break; case GPG_ERR_BAD_SIGNATURE: node->flag = NODFLG_BADSIG; sigrc = '-'; if (inv_sigs) ++ * inv_sigs; break; case GPG_ERR_NO_PUBKEY: case GPG_ERR_UNUSABLE_PUBKEY: node->flag = NODFLG_NOKEY; sigrc = '?'; if (no_key) ++ * no_key; break; default: node->flag = NODFLG_SIGERR; sigrc = '%'; if (oth_err) ++ * oth_err; break; } if (sigrc != '?' || print_without_key) { tty_printf ("%s%c%c %c%c%c%c%c%c %s %s", is_rev ? "rev" : "sig", sigrc, (sig->sig_class - 0x10 > 0 && sig->sig_class - 0x10 < 4) ? '0' + sig->sig_class - 0x10 : ' ', sig->flags.exportable ? ' ' : 'L', sig->flags.revocable ? ' ' : 'R', sig->flags.policy_url ? 'P' : ' ', sig->flags.notation ? 'N' : ' ', sig->flags.expired ? 'X' : ' ', (sig->trust_depth > 9) ? 'T' : (sig->trust_depth > 0) ? '0' + sig->trust_depth : ' ', keystr (sig->keyid), datestr_from_sig (sig)); if (opt.list_options & LIST_SHOW_SIG_EXPIRE) tty_printf (" %s", expirestr_from_sig (sig)); tty_printf (" "); if (sigrc == '%') tty_printf ("[%s] ", gpg_strerror (rc)); else if (sigrc == '?') ; else if (*is_selfsig) { tty_printf (is_rev ? _("[revocation]") : _("[self-signature]")); } else { size_t n; char *p = get_user_id (sig->keyid, &n); tty_print_utf8_string2 (NULL, p, n, opt.screen_columns - keystrlen () - 26 - ((opt. list_options & LIST_SHOW_SIG_EXPIRE) ? 11 : 0)); xfree (p); } tty_printf ("\n"); if (sig->flags.policy_url && (opt.list_options & LIST_SHOW_POLICY_URLS)) show_policy_url (sig, 3, 0); if (sig->flags.notation && (opt.list_options & LIST_SHOW_NOTATIONS)) show_notation (sig, 3, 0, ((opt. list_options & LIST_SHOW_STD_NOTATIONS) ? 1 : 0) + ((opt. list_options & LIST_SHOW_USER_NOTATIONS) ? 2 : 0)); if (sig->flags.pref_ks && (opt.list_options & LIST_SHOW_KEYSERVER_URLS)) show_keyserver_url (sig, 3, 0); } return (sigrc == '!'); } /* * Check the keysigs and set the flags to indicate errors. * Returns true if error found. */ static int check_all_keysigs (KBNODE keyblock, int only_selected) { KBNODE kbctx; KBNODE node; int inv_sigs = 0; int no_key = 0; int oth_err = 0; int has_selfsig = 0; int mis_selfsig = 0; int selected = !only_selected; int anyuid = 0; for (kbctx = NULL; (node = walk_kbnode (keyblock, &kbctx, 0));) { if (node->pkt->pkttype == PKT_USER_ID) { PKT_user_id *uid = node->pkt->pkt.user_id; if (only_selected) selected = (node->flag & NODFLG_SELUID); if (selected) { tty_printf ("uid "); tty_print_utf8_string (uid->name, uid->len); tty_printf ("\n"); if (anyuid && !has_selfsig) mis_selfsig++; has_selfsig = 0; anyuid = 1; } } else if (selected && node->pkt->pkttype == PKT_SIGNATURE && ((node->pkt->pkt.signature->sig_class & ~3) == 0x10 || node->pkt->pkt.signature->sig_class == 0x30)) { int selfsig; if (print_and_check_one_sig (keyblock, node, &inv_sigs, &no_key, &oth_err, &selfsig, 0)) { if (selfsig) has_selfsig = 1; } /* Hmmm: should we update the trustdb here? */ } } if (!has_selfsig) mis_selfsig++; if (inv_sigs == 1) tty_printf (_("1 bad signature\n")); else if (inv_sigs) tty_printf (_("%d bad signatures\n"), inv_sigs); if (no_key == 1) tty_printf (_("1 signature not checked due to a missing key\n")); else if (no_key) tty_printf (_("%d signatures not checked due to missing keys\n"), no_key); if (oth_err == 1) tty_printf (_("1 signature not checked due to an error\n")); else if (oth_err) tty_printf (_("%d signatures not checked due to errors\n"), oth_err); if (mis_selfsig == 1) tty_printf (_("1 user ID without valid self-signature detected\n")); else if (mis_selfsig) tty_printf (_("%d user IDs without valid self-signatures detected\n"), mis_selfsig); return inv_sigs || no_key || oth_err || mis_selfsig; } static int sign_mk_attrib (PKT_signature * sig, void *opaque) { struct sign_attrib *attrib = opaque; byte buf[8]; if (attrib->non_exportable) { buf[0] = 0; /* not exportable */ build_sig_subpkt (sig, SIGSUBPKT_EXPORTABLE, buf, 1); } if (attrib->non_revocable) { buf[0] = 0; /* not revocable */ build_sig_subpkt (sig, SIGSUBPKT_REVOCABLE, buf, 1); } if (attrib->reason) revocation_reason_build_cb (sig, attrib->reason); if (attrib->trust_depth) { /* Not critical. If someone doesn't understand trust sigs, this can still be a valid regular signature. */ buf[0] = attrib->trust_depth; buf[1] = attrib->trust_value; build_sig_subpkt (sig, SIGSUBPKT_TRUST, buf, 2); /* Critical. If someone doesn't understands regexps, this whole sig should be invalid. Note the +1 for the length - regexps are null terminated. */ if (attrib->trust_regexp) build_sig_subpkt (sig, SIGSUBPKT_FLAG_CRITICAL | SIGSUBPKT_REGEXP, attrib->trust_regexp, strlen (attrib->trust_regexp) + 1); } return 0; } static void trustsig_prompt (byte * trust_value, byte * trust_depth, char **regexp) { char *p; *trust_value = 0; *trust_depth = 0; *regexp = NULL; /* Same string as pkclist.c:do_edit_ownertrust */ tty_printf (_ ("Please decide how far you trust this user to correctly verify" " other users' keys\n(by looking at passports, checking" " fingerprints from different sources, etc.)\n")); tty_printf ("\n"); tty_printf (_(" %d = I trust marginally\n"), 1); tty_printf (_(" %d = I trust fully\n"), 2); tty_printf ("\n"); while (*trust_value == 0) { p = cpr_get ("trustsig_prompt.trust_value", _("Your selection? ")); trim_spaces (p); cpr_kill_prompt (); /* 60 and 120 are as per RFC2440 */ if (p[0] == '1' && !p[1]) *trust_value = 60; else if (p[0] == '2' && !p[1]) *trust_value = 120; xfree (p); } tty_printf ("\n"); tty_printf (_("Please enter the depth of this trust signature.\n" "A depth greater than 1 allows the key you are signing to make\n" "trust signatures on your behalf.\n")); tty_printf ("\n"); while (*trust_depth == 0) { p = cpr_get ("trustsig_prompt.trust_depth", _("Your selection? ")); trim_spaces (p); cpr_kill_prompt (); *trust_depth = atoi (p); xfree (p); } tty_printf ("\n"); tty_printf (_("Please enter a domain to restrict this signature, " "or enter for none.\n")); tty_printf ("\n"); p = cpr_get ("trustsig_prompt.trust_regexp", _("Your selection? ")); trim_spaces (p); cpr_kill_prompt (); if (strlen (p) > 0) { char *q = p; int regexplen = 100, ind; *regexp = xmalloc (regexplen); /* Now mangle the domain the user entered into a regexp. To do this, \-escape everything that isn't alphanumeric, and attach "<[^>]+[@.]" to the front, and ">$" to the end. */ strcpy (*regexp, "<[^>]+[@.]"); ind = strlen (*regexp); while (*q) { if (!((*q >= 'A' && *q <= 'Z') || (*q >= 'a' && *q <= 'z') || (*q >= '0' && *q <= '9'))) (*regexp)[ind++] = '\\'; (*regexp)[ind++] = *q; if ((regexplen - ind) < 3) { regexplen += 100; *regexp = xrealloc (*regexp, regexplen); } q++; } (*regexp)[ind] = '\0'; strcat (*regexp, ">$"); } xfree (p); tty_printf ("\n"); } /* * Loop over all LOCUSR and and sign the uids after asking. If no * user id is marked, all user ids will be signed; if some user_ids * are marked only those will be signed. If QUICK is true the * function won't ask the user and use sensible defaults. */ static int sign_uids (estream_t fp, kbnode_t keyblock, strlist_t locusr, int *ret_modified, int local, int nonrevocable, int trust, int interactive, int quick) { int rc = 0; SK_LIST sk_list = NULL; SK_LIST sk_rover = NULL; PKT_public_key *pk = NULL; KBNODE node, uidnode; PKT_public_key *primary_pk = NULL; int select_all = !count_selected_uids (keyblock) || interactive; /* Build a list of all signators. * * We use the CERT flag to request the primary which must always * be one which is capable of signing keys. I can't see a reason * why to sign keys using a subkey. Implementation of USAGE_CERT * is just a hack in getkey.c and does not mean that a subkey * marked as certification capable will be used. */ rc = build_sk_list (locusr, &sk_list, PUBKEY_USAGE_CERT); if (rc) goto leave; /* Loop over all signators. */ for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next) { u32 sk_keyid[2], pk_keyid[2]; char *p, *trust_regexp = NULL; int class = 0, selfsig = 0; u32 duration = 0, timestamp = 0; byte trust_depth = 0, trust_value = 0; pk = sk_rover->pk; keyid_from_pk (pk, sk_keyid); /* Set mark A for all selected user ids. */ for (node = keyblock; node; node = node->next) { if (select_all || (node->flag & NODFLG_SELUID)) node->flag |= NODFLG_MARK_A; else node->flag &= ~NODFLG_MARK_A; } /* Reset mark for uids which are already signed. */ uidnode = NULL; for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_KEY) { primary_pk = node->pkt->pkt.public_key; keyid_from_pk (primary_pk, pk_keyid); /* Is this a self-sig? */ if (pk_keyid[0] == sk_keyid[0] && pk_keyid[1] == sk_keyid[1]) selfsig = 1; } else if (node->pkt->pkttype == PKT_USER_ID) { uidnode = (node->flag & NODFLG_MARK_A) ? node : NULL; if (uidnode) { int yesreally = 0; char *user; user = utf8_to_native (uidnode->pkt->pkt.user_id->name, uidnode->pkt->pkt.user_id->len, 0); if (uidnode->pkt->pkt.user_id->is_revoked) { tty_fprintf (fp, _("User ID \"%s\" is revoked."), user); if (selfsig) tty_fprintf (fp, "\n"); else if (opt.expert && !quick) { tty_fprintf (fp, "\n"); /* No, so remove the mark and continue */ if (!cpr_get_answer_is_yes ("sign_uid.revoke_okay", _("Are you sure you " "still want to sign " "it? (y/N) "))) { uidnode->flag &= ~NODFLG_MARK_A; uidnode = NULL; } else if (interactive) yesreally = 1; } else { uidnode->flag &= ~NODFLG_MARK_A; uidnode = NULL; tty_fprintf (fp, _(" Unable to sign.\n")); } } else if (uidnode->pkt->pkt.user_id->is_expired) { tty_fprintf (fp, _("User ID \"%s\" is expired."), user); if (selfsig) tty_fprintf (fp, "\n"); else if (opt.expert && !quick) { tty_fprintf (fp, "\n"); /* No, so remove the mark and continue */ if (!cpr_get_answer_is_yes ("sign_uid.expire_okay", _("Are you sure you " "still want to sign " "it? (y/N) "))) { uidnode->flag &= ~NODFLG_MARK_A; uidnode = NULL; } else if (interactive) yesreally = 1; } else { uidnode->flag &= ~NODFLG_MARK_A; uidnode = NULL; tty_fprintf (fp, _(" Unable to sign.\n")); } } else if (!uidnode->pkt->pkt.user_id->created && !selfsig) { tty_fprintf (fp, _("User ID \"%s\" is not self-signed."), user); if (opt.expert && !quick) { tty_fprintf (fp, "\n"); /* No, so remove the mark and continue */ if (!cpr_get_answer_is_yes ("sign_uid.nosig_okay", _("Are you sure you " "still want to sign " "it? (y/N) "))) { uidnode->flag &= ~NODFLG_MARK_A; uidnode = NULL; } else if (interactive) yesreally = 1; } else { uidnode->flag &= ~NODFLG_MARK_A; uidnode = NULL; tty_fprintf (fp, _(" Unable to sign.\n")); } } if (uidnode && interactive && !yesreally && !quick) { tty_fprintf (fp, _("User ID \"%s\" is signable. "), user); if (!cpr_get_answer_is_yes ("sign_uid.sign_okay", _("Sign it? (y/N) "))) { uidnode->flag &= ~NODFLG_MARK_A; uidnode = NULL; } } xfree (user); } } else if (uidnode && node->pkt->pkttype == PKT_SIGNATURE && (node->pkt->pkt.signature->sig_class & ~3) == 0x10) { if (sk_keyid[0] == node->pkt->pkt.signature->keyid[0] && sk_keyid[1] == node->pkt->pkt.signature->keyid[1]) { char buf[50]; char *user; user = utf8_to_native (uidnode->pkt->pkt.user_id->name, uidnode->pkt->pkt.user_id->len, 0); /* It's a v3 self-sig. Make it into a v4 self-sig? */ if (node->pkt->pkt.signature->version < 4 && selfsig && !quick) { tty_fprintf (fp, _("The self-signature on \"%s\"\n" "is a PGP 2.x-style signature.\n"), user); /* Note that the regular PGP2 warning below still applies if there are no v4 sigs on this key at all. */ if (opt.expert) if (cpr_get_answer_is_yes ("sign_uid.v4_promote_okay", _("Do you want to promote " "it to an OpenPGP self-" "signature? (y/N) "))) { node->flag |= NODFLG_DELSIG; xfree (user); continue; } } /* Is the current signature expired? */ if (node->pkt->pkt.signature->flags.expired) { tty_fprintf (fp, _("Your current signature on \"%s\"\n" "has expired.\n"), user); if (quick || cpr_get_answer_is_yes ("sign_uid.replace_expired_okay", _("Do you want to issue a " "new signature to replace " "the expired one? (y/N) "))) { /* Mark these for later deletion. We don't want to delete them here, just in case the replacement signature doesn't happen for some reason. We only delete these after the replacement is already in place. */ node->flag |= NODFLG_DELSIG; xfree (user); continue; } } if (!node->pkt->pkt.signature->flags.exportable && !local) { /* It's a local sig, and we want to make a exportable sig. */ tty_fprintf (fp, _("Your current signature on \"%s\"\n" "is a local signature.\n"), user); if (quick || cpr_get_answer_is_yes ("sign_uid.local_promote_okay", _("Do you want to promote " "it to a full exportable " "signature? (y/N) "))) { /* Mark these for later deletion. We don't want to delete them here, just in case the replacement signature doesn't happen for some reason. We only delete these after the replacement is already in place. */ node->flag |= NODFLG_DELSIG; xfree (user); continue; } } /* Fixme: see whether there is a revocation in which * case we should allow to sign it again. */ if (!node->pkt->pkt.signature->flags.exportable && local) tty_fprintf ( fp, _("\"%s\" was already locally signed by key %s\n"), user, keystr_from_pk (pk)); else tty_fprintf (fp, _("\"%s\" was already signed by key %s\n"), user, keystr_from_pk (pk)); if (opt.expert && !quick && cpr_get_answer_is_yes ("sign_uid.dupe_okay", _("Do you want to sign it " "again anyway? (y/N) "))) { /* Don't delete the old sig here since this is an --expert thing. */ xfree (user); continue; } snprintf (buf, sizeof buf, "%08lX%08lX", (ulong) pk->keyid[0], (ulong) pk->keyid[1]); write_status_text (STATUS_ALREADY_SIGNED, buf); uidnode->flag &= ~NODFLG_MARK_A; /* remove mark */ xfree (user); } } } /* Check whether any uids are left for signing. */ if (!count_uids_with_flag (keyblock, NODFLG_MARK_A)) { tty_fprintf (fp, _("Nothing to sign with key %s\n"), keystr_from_pk (pk)); continue; } /* Ask whether we really should sign these user id(s). */ tty_fprintf (fp, "\n"); show_key_with_all_names (fp, keyblock, 1, 0, 1, 0, 0, 0); tty_fprintf (fp, "\n"); if (primary_pk->expiredate && !selfsig) { u32 now = make_timestamp (); if (primary_pk->expiredate <= now) { tty_fprintf (fp, _("This key has expired!")); if (opt.expert && !quick) { tty_fprintf (fp, " "); if (!cpr_get_answer_is_yes ("sign_uid.expired_okay", _("Are you sure you still " "want to sign it? (y/N) "))) continue; } else { tty_fprintf (fp, _(" Unable to sign.\n")); continue; } } else { tty_fprintf (fp, _("This key is due to expire on %s.\n"), expirestr_from_pk (primary_pk)); if (opt.ask_cert_expire && !quick) { char *answer = cpr_get ("sign_uid.expire", _("Do you want your signature to " "expire at the same time? (Y/n) ")); if (answer_is_yes_no_default (answer, 1)) { /* This fixes the signature timestamp we're going to make as now. This is so the expiration date is exactly correct, and not a few seconds off (due to the time it takes to answer the questions, enter the passphrase, etc). */ timestamp = now; duration = primary_pk->expiredate - now; } cpr_kill_prompt (); xfree (answer); } } } /* Only ask for duration if we haven't already set it to match the expiration of the pk */ if (!duration && !selfsig) { if (opt.ask_cert_expire && !quick) duration = ask_expire_interval (1, opt.def_cert_expire); else duration = parse_expire_string (opt.def_cert_expire); } if (selfsig) ; else { if (opt.batch || !opt.ask_cert_level || quick) class = 0x10 + opt.def_cert_level; else { char *answer; tty_fprintf (fp, _("How carefully have you verified the key you are " "about to sign actually belongs\nto the person " "named above? If you don't know what to " "answer, enter \"0\".\n")); tty_fprintf (fp, "\n"); tty_fprintf (fp, _(" (0) I will not answer.%s\n"), opt.def_cert_level == 0 ? " (default)" : ""); tty_fprintf (fp, _(" (1) I have not checked at all.%s\n"), opt.def_cert_level == 1 ? " (default)" : ""); tty_fprintf (fp, _(" (2) I have done casual checking.%s\n"), opt.def_cert_level == 2 ? " (default)" : ""); tty_fprintf (fp, _(" (3) I have done very careful checking.%s\n"), opt.def_cert_level == 3 ? " (default)" : ""); tty_fprintf (fp, "\n"); while (class == 0) { answer = cpr_get ("sign_uid.class", _("Your selection? " "(enter '?' for more information): ")); if (answer[0] == '\0') class = 0x10 + opt.def_cert_level; /* Default */ else if (ascii_strcasecmp (answer, "0") == 0) class = 0x10; /* Generic */ else if (ascii_strcasecmp (answer, "1") == 0) class = 0x11; /* Persona */ else if (ascii_strcasecmp (answer, "2") == 0) class = 0x12; /* Casual */ else if (ascii_strcasecmp (answer, "3") == 0) class = 0x13; /* Positive */ else tty_fprintf (fp, _("Invalid selection.\n")); xfree (answer); } } if (trust && !quick) trustsig_prompt (&trust_value, &trust_depth, &trust_regexp); } if (!quick) { p = get_user_id_native (sk_keyid); tty_fprintf (fp, _("Are you sure that you want to sign this key with your\n" "key \"%s\" (%s)\n"), p, keystr_from_pk (pk)); xfree (p); } if (selfsig) { tty_fprintf (fp, "\n"); tty_fprintf (fp, _("This will be a self-signature.\n")); if (local) { tty_fprintf (fp, "\n"); tty_fprintf (fp, _("WARNING: the signature will not be marked " "as non-exportable.\n")); } if (nonrevocable) { tty_fprintf (fp, "\n"); tty_fprintf (fp, _("WARNING: the signature will not be marked " "as non-revocable.\n")); } } else { if (local) { tty_fprintf (fp, "\n"); tty_fprintf (fp, _("The signature will be marked as non-exportable.\n")); } if (nonrevocable) { tty_fprintf (fp, "\n"); tty_fprintf (fp, _("The signature will be marked as non-revocable.\n")); } switch (class) { case 0x11: tty_fprintf (fp, "\n"); tty_fprintf (fp, _("I have not checked this key at all.\n")); break; case 0x12: tty_fprintf (fp, "\n"); tty_fprintf (fp, _("I have checked this key casually.\n")); break; case 0x13: tty_fprintf (fp, "\n"); tty_fprintf (fp, _("I have checked this key very carefully.\n")); break; } } tty_fprintf (fp, "\n"); if (opt.batch && opt.answer_yes) ; else if (quick) ; else if (!cpr_get_answer_is_yes ("sign_uid.okay", _("Really sign? (y/N) "))) continue; /* Now we can sign the user ids. */ reloop: /* (Must use this, because we are modifing the list.) */ primary_pk = NULL; for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_KEY) primary_pk = node->pkt->pkt.public_key; else if (node->pkt->pkttype == PKT_USER_ID && (node->flag & NODFLG_MARK_A)) { PACKET *pkt; PKT_signature *sig; struct sign_attrib attrib; assert (primary_pk); memset (&attrib, 0, sizeof attrib); attrib.non_exportable = local; attrib.non_revocable = nonrevocable; attrib.trust_depth = trust_depth; attrib.trust_value = trust_value; attrib.trust_regexp = trust_regexp; node->flag &= ~NODFLG_MARK_A; /* We force creation of a v4 signature for local * signatures, otherwise we would not generate the * subpacket with v3 keys and the signature becomes * exportable. */ if (selfsig) rc = make_keysig_packet (&sig, primary_pk, node->pkt->pkt.user_id, NULL, pk, 0x13, 0, 0, 0, keygen_add_std_prefs, primary_pk, NULL); else rc = make_keysig_packet (&sig, primary_pk, node->pkt->pkt.user_id, NULL, pk, class, 0, timestamp, duration, sign_mk_attrib, &attrib, NULL); if (rc) { log_error (_("signing failed: %s\n"), gpg_strerror (rc)); goto leave; } *ret_modified = 1; /* We changed the keyblock. */ update_trust = 1; pkt = xmalloc_clear (sizeof *pkt); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; insert_kbnode (node, new_kbnode (pkt), PKT_SIGNATURE); goto reloop; } } /* Delete any sigs that got promoted */ for (node = keyblock; node; node = node->next) if (node->flag & NODFLG_DELSIG) delete_kbnode (node); } /* End loop over signators. */ leave: release_sk_list (sk_list); return rc; } /* * Change the passphrase of the primary and all secondary keys. Note * that it is common to use only one passphrase for the primary and * all subkeys. However, this is now (since GnuPG 2.1) all up to the * gpg-agent. Returns 0 on success or an error code. */ static gpg_error_t change_passphrase (ctrl_t ctrl, kbnode_t keyblock) { gpg_error_t err; kbnode_t node; PKT_public_key *pk; int any; u32 keyid[2], subid[2]; char *hexgrip = NULL; char *cache_nonce = NULL; char *passwd_nonce = NULL; node = find_kbnode (keyblock, PKT_PUBLIC_KEY); if (!node) { log_error ("Oops; public key missing!\n"); err = gpg_error (GPG_ERR_INTERNAL); goto leave; } pk = node->pkt->pkt.public_key; keyid_from_pk (pk, keyid); /* Check whether it is likely that we will be able to change the passphrase for any subkey. */ for (any = 0, node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_PUBLIC_SUBKEY) { char *serialno; pk = node->pkt->pkt.public_key; keyid_from_pk (pk, subid); xfree (hexgrip); err = hexkeygrip_from_pk (pk, &hexgrip); if (err) goto leave; err = agent_get_keyinfo (ctrl, hexgrip, &serialno); if (!err && serialno) ; /* Key on card. */ else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) ; /* Maybe stub key. */ else if (!err) any = 1; /* Key is known. */ else log_error ("key %s: error getting keyinfo from agent: %s\n", keystr_with_sub (keyid, subid), gpg_strerror (err)); xfree (serialno); } } err = 0; if (!any) { tty_printf (_("Key has only stub or on-card key items - " "no passphrase to change.\n")); goto leave; } /* Change the passphrase for all keys. */ for (any = 0, node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_PUBLIC_SUBKEY) { char *desc; pk = node->pkt->pkt.public_key; keyid_from_pk (pk, subid); xfree (hexgrip); err = hexkeygrip_from_pk (pk, &hexgrip); if (err) goto leave; desc = gpg_format_keydesc (pk, FORMAT_KEYDESC_NORMAL, 1); err = agent_passwd (ctrl, hexgrip, desc, &cache_nonce, &passwd_nonce); xfree (desc); if (err) log_log ((gpg_err_code (err) == GPG_ERR_CANCELED || gpg_err_code (err) == GPG_ERR_FULLY_CANCELED) ? GPGRT_LOG_INFO : GPGRT_LOG_ERROR, _("key %s: error changing passphrase: %s\n"), keystr_with_sub (keyid, subid), gpg_strerror (err)); if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED) break; } } leave: xfree (hexgrip); xfree (cache_nonce); xfree (passwd_nonce); return err; } /* * There are some keys out (due to a bug in gnupg), where the sequence * of the packets is wrong. This function fixes that. * Returns: true if the keyblock has been fixed. * * Note: This function does not work if there is more than one user ID. */ static int fix_key_signature_order (KBNODE keyblock) { KBNODE node, last, subkey; int fixed = 0; /* Locate key signatures of class 0x10..0x13 behind sub key packets. */ for (subkey = last = NULL, node = keyblock; node; last = node, node = node->next) { switch (node->pkt->pkttype) { case PKT_PUBLIC_SUBKEY: case PKT_SECRET_SUBKEY: if (!subkey) subkey = last; /* Actually it is the one before the subkey. */ break; case PKT_SIGNATURE: if (subkey) { PKT_signature *sig = node->pkt->pkt.signature; if (sig->sig_class >= 0x10 && sig->sig_class <= 0x13) { log_info (_("moving a key signature to the correct place\n")); last->next = node->next; node->next = subkey->next; subkey->next = node; node = last; fixed = 1; } } break; default: break; } } return fixed; } /* Fix various problems in the keyblock. Returns true if the keyblock was changed. Note that a pointer to the keyblock must be given and the function may change it (i.e. replacing the first node). */ static int fix_keyblock (kbnode_t *keyblockp) { int changed = 0; if (fix_key_signature_order (*keyblockp)) changed++; if (collapse_uids (keyblockp)) changed++; reorder_keyblock (*keyblockp); /* If we modified the keyblock, make sure the flags are right. */ if (changed) merge_keys_and_selfsig (*keyblockp); return changed; } static int parse_sign_type (const char *str, int *localsig, int *nonrevokesig, int *trustsig) { const char *p = str; while (*p) { if (ascii_strncasecmp (p, "l", 1) == 0) { *localsig = 1; p++; } else if (ascii_strncasecmp (p, "nr", 2) == 0) { *nonrevokesig = 1; p += 2; } else if (ascii_strncasecmp (p, "t", 1) == 0) { *trustsig = 1; p++; } else return 0; } return 1; } /* * Menu driven key editor. If seckey_check is true, then a secret key * that matches username will be looked for. If it is false, not all * commands will be available. * * Note: to keep track of certain selections we use node->mark MARKBIT_xxxx. */ /* Need an SK for this command */ #define KEYEDIT_NEED_SK 1 /* Cannot be viewing the SK for this command */ #define KEYEDIT_NOT_SK 2 /* Must be viewing the SK for this command */ #define KEYEDIT_ONLY_SK 4 /* Match the tail of the string */ #define KEYEDIT_TAIL_MATCH 8 enum cmdids { cmdNONE = 0, cmdQUIT, cmdHELP, cmdFPR, cmdLIST, cmdSELUID, cmdCHECK, cmdSIGN, cmdREVSIG, cmdREVKEY, cmdREVUID, cmdDELSIG, cmdPRIMARY, cmdDEBUG, cmdSAVE, cmdADDUID, cmdADDPHOTO, cmdDELUID, cmdADDKEY, cmdDELKEY, cmdADDREVOKER, cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF, cmdEXPIRE, cmdBACKSIGN, #ifndef NO_TRUST_MODELS cmdENABLEKEY, cmdDISABLEKEY, #endif /*!NO_TRUST_MODELS*/ cmdSHOWPREF, cmdSETPREF, cmdPREFKS, cmdNOTATION, cmdINVCMD, cmdSHOWPHOTO, cmdUPDTRUST, cmdCHKTRUST, cmdADDCARDKEY, cmdKEYTOCARD, cmdBKUPTOCARD, cmdCHECKBKUPKEY, cmdCLEAN, cmdMINIMIZE, cmdNOP }; static struct { const char *name; enum cmdids id; int flags; const char *desc; } cmds[] = { { "quit", cmdQUIT, 0, N_("quit this menu")}, { "q", cmdQUIT, 0, NULL}, { "save", cmdSAVE, 0, N_("save and quit")}, { "help", cmdHELP, 0, N_("show this help")}, { "?", cmdHELP, 0, NULL}, { "fpr", cmdFPR, 0, N_("show key fingerprint")}, { "list", cmdLIST, 0, N_("list key and user IDs")}, { "l", cmdLIST, 0, NULL}, { "uid", cmdSELUID, 0, N_("select user ID N")}, { "key", cmdSELKEY, 0, N_("select subkey N")}, { "check", cmdCHECK, 0, N_("check signatures")}, { "c", cmdCHECK, 0, NULL}, { "cross-certify", cmdBACKSIGN, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, NULL}, { "backsign", cmdBACKSIGN, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, NULL}, { "sign", cmdSIGN, KEYEDIT_NOT_SK | KEYEDIT_TAIL_MATCH, N_("sign selected user IDs [* see below for related commands]")}, { "s", cmdSIGN, KEYEDIT_NOT_SK, NULL}, /* "lsign" and friends will never match since "sign" comes first and it is a tail match. They are just here so they show up in the help menu. */ { "lsign", cmdNOP, 0, N_("sign selected user IDs locally")}, { "tsign", cmdNOP, 0, N_("sign selected user IDs with a trust signature")}, { "nrsign", cmdNOP, 0, N_("sign selected user IDs with a non-revocable signature")}, { "debug", cmdDEBUG, 0, NULL}, { "adduid", cmdADDUID, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, N_("add a user ID")}, { "addphoto", cmdADDPHOTO, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, N_("add a photo ID")}, { "deluid", cmdDELUID, KEYEDIT_NOT_SK, N_("delete selected user IDs")}, /* delphoto is really deluid in disguise */ { "delphoto", cmdDELUID, KEYEDIT_NOT_SK, NULL}, { "addkey", cmdADDKEY, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, N_("add a subkey")}, #ifdef ENABLE_CARD_SUPPORT { "addcardkey", cmdADDCARDKEY, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, N_("add a key to a smartcard")}, { "keytocard", cmdKEYTOCARD, KEYEDIT_NEED_SK | KEYEDIT_ONLY_SK, N_("move a key to a smartcard")}, { "bkuptocard", cmdBKUPTOCARD, KEYEDIT_NEED_SK | KEYEDIT_ONLY_SK, N_("move a backup key to a smartcard")}, { "checkbkupkey", cmdCHECKBKUPKEY, KEYEDIT_NEED_SK | KEYEDIT_ONLY_SK, NULL}, #endif /*ENABLE_CARD_SUPPORT */ { "delkey", cmdDELKEY, KEYEDIT_NOT_SK, N_("delete selected subkeys")}, { "addrevoker", cmdADDREVOKER, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, N_("add a revocation key")}, { "delsig", cmdDELSIG, KEYEDIT_NOT_SK, N_("delete signatures from the selected user IDs")}, { "expire", cmdEXPIRE, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, N_("change the expiration date for the key or selected subkeys")}, { "primary", cmdPRIMARY, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, N_("flag the selected user ID as primary")}, { "toggle", cmdTOGGLE, KEYEDIT_NEED_SK, N_("toggle between the secret and public key listings")}, { "t", cmdTOGGLE, KEYEDIT_NEED_SK, NULL}, { "pref", cmdPREF, KEYEDIT_NOT_SK, N_("list preferences (expert)")}, { "showpref", cmdSHOWPREF, KEYEDIT_NOT_SK, N_("list preferences (verbose)")}, { "setpref", cmdSETPREF, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, N_("set preference list for the selected user IDs")}, { "updpref", cmdSETPREF, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, NULL}, { "keyserver", cmdPREFKS, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, N_("set the preferred keyserver URL for the selected user IDs")}, { "notation", cmdNOTATION, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, N_("set a notation for the selected user IDs")}, { "passwd", cmdPASSWD, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, N_("change the passphrase")}, { "password", cmdPASSWD, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, NULL}, #ifndef NO_TRUST_MODELS { "trust", cmdTRUST, KEYEDIT_NOT_SK, N_("change the ownertrust")}, #endif /*!NO_TRUST_MODELS*/ { "revsig", cmdREVSIG, KEYEDIT_NOT_SK, N_("revoke signatures on the selected user IDs")}, { "revuid", cmdREVUID, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, N_("revoke selected user IDs")}, { "revphoto", cmdREVUID, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, NULL}, { "revkey", cmdREVKEY, KEYEDIT_NOT_SK | KEYEDIT_NEED_SK, N_("revoke key or selected subkeys")}, #ifndef NO_TRUST_MODELS { "enable", cmdENABLEKEY, KEYEDIT_NOT_SK, N_("enable key")}, { "disable", cmdDISABLEKEY, KEYEDIT_NOT_SK, N_("disable key")}, #endif /*!NO_TRUST_MODELS*/ { "showphoto", cmdSHOWPHOTO, 0, N_("show selected photo IDs")}, { "clean", cmdCLEAN, KEYEDIT_NOT_SK, N_("compact unusable user IDs and remove unusable signatures from key")}, { "minimize", cmdMINIMIZE, KEYEDIT_NOT_SK, N_("compact unusable user IDs and remove all signatures from key")}, { NULL, cmdNONE, 0, NULL} }; #ifdef HAVE_LIBREADLINE /* These two functions are used by readline for command completion. */ static char * command_generator (const char *text, int state) { static int list_index, len; const char *name; /* If this is a new word to complete, initialize now. This includes saving the length of TEXT for efficiency, and initializing the index variable to 0. */ if (!state) { list_index = 0; len = strlen (text); } /* Return the next partial match */ while ((name = cmds[list_index].name)) { /* Only complete commands that have help text */ if (cmds[list_index++].desc && strncmp (name, text, len) == 0) return strdup (name); } return NULL; } static char ** keyedit_completion (const char *text, int start, int end) { /* If we are at the start of a line, we try and command-complete. If not, just do nothing for now. */ (void) end; if (start == 0) return rl_completion_matches (text, command_generator); rl_attempted_completion_over = 1; return NULL; } #endif /* HAVE_LIBREADLINE */ /* Main function of the menu driven key editor. */ void keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr, strlist_t commands, int quiet, int seckey_check) { enum cmdids cmd = 0; gpg_error_t err = 0; KBNODE keyblock = NULL; KEYDB_HANDLE kdbhd = NULL; int have_seckey = 0; char *answer = NULL; int redisplay = 1; int modified = 0; int sec_shadowing = 0; int run_subkey_warnings = 0; int toggle; int have_commands = !!commands; if (opt.command_fd != -1) ; else if (opt.batch && !have_commands) { log_error (_("can't do this in batch mode\n")); goto leave; } #ifdef HAVE_W32_SYSTEM /* Due to Windows peculiarities we need to make sure that the trustdb stale check is done before we open another file (i.e. by searching for a key). In theory we could make sure that the files are closed after use but the open/close caches inhibits that and flushing the cache right before the stale check is not easy to implement. Thus we take the easy way out and run the stale check as early as possible. Note, that for non- W32 platforms it is run indirectly trough a call to get_validity (). */ check_trustdb_stale (); #endif /* Get the public key */ err = get_pubkey_byname (ctrl, NULL, NULL, username, &keyblock, &kdbhd, 1, 1); if (err) { log_error (_("key \"%s\" not found: %s\n"), username, gpg_strerror (err)); goto leave; } if (fix_keyblock (&keyblock)) modified++; /* See whether we have a matching secret key. */ if (seckey_check) { have_seckey = !agent_probe_any_secret_key (ctrl, keyblock); if (have_seckey && !quiet) tty_printf (_("Secret key is available.\n")); } toggle = 0; /* Main command loop. */ for (;;) { int i, arg_number, photo; const char *arg_string = ""; char *p; PKT_public_key *pk = keyblock->pkt->pkt.public_key; tty_printf ("\n"); if (redisplay && !quiet) { show_key_with_all_names (NULL, keyblock, 0, 1, 0, 1, 0, 0); tty_printf ("\n"); redisplay = 0; } if (run_subkey_warnings) { run_subkey_warnings = 0; if (!count_selected_keys (keyblock)) subkey_expire_warning (keyblock); } do { xfree (answer); if (have_commands) { if (commands) { answer = xstrdup (commands->d); commands = commands->next; } else if (opt.batch) { answer = xstrdup ("quit"); } else have_commands = 0; } if (!have_commands) { #ifdef HAVE_LIBREADLINE tty_enable_completion (keyedit_completion); #endif answer = cpr_get_no_help ("keyedit.prompt", GPG_NAME "> "); cpr_kill_prompt (); tty_disable_completion (); } trim_spaces (answer); } while (*answer == '#'); arg_number = 0; /* Here is the init which egcc complains about. */ photo = 0; /* Same here. */ if (!*answer) cmd = cmdLIST; else if (*answer == CONTROL_D) cmd = cmdQUIT; else if (digitp (answer)) { cmd = cmdSELUID; arg_number = atoi (answer); } else { if ((p = strchr (answer, ' '))) { *p++ = 0; trim_spaces (answer); trim_spaces (p); arg_number = atoi (p); arg_string = p; } for (i = 0; cmds[i].name; i++) { if (cmds[i].flags & KEYEDIT_TAIL_MATCH) { size_t l = strlen (cmds[i].name); size_t a = strlen (answer); if (a >= l) { if (!ascii_strcasecmp (&answer[a - l], cmds[i].name)) { answer[a - l] = '\0'; break; } } } else if (!ascii_strcasecmp (answer, cmds[i].name)) break; } if ((cmds[i].flags & KEYEDIT_NEED_SK) && !have_seckey) { tty_printf (_("Need the secret key to do this.\n")); cmd = cmdNOP; } else if (((cmds[i].flags & KEYEDIT_NOT_SK) && have_seckey && toggle) || ((cmds[i].flags & KEYEDIT_ONLY_SK) && have_seckey && !toggle)) { tty_printf (_("Please use the command \"toggle\" first.\n")); cmd = cmdNOP; } else cmd = cmds[i].id; } /* Dispatch the command. */ switch (cmd) { case cmdHELP: for (i = 0; cmds[i].name; i++) { if ((cmds[i].flags & KEYEDIT_NEED_SK) && !have_seckey) ; /* Skip those item if we do not have the secret key. */ else if (cmds[i].desc) tty_printf ("%-11s %s\n", cmds[i].name, _(cmds[i].desc)); } tty_printf ("\n"); tty_printf (_("* The 'sign' command may be prefixed with an 'l' for local " "signatures (lsign),\n" " a 't' for trust signatures (tsign), an 'nr' for " "non-revocable signatures\n" " (nrsign), or any combination thereof (ltsign, " "tnrsign, etc.).\n")); break; case cmdLIST: redisplay = 1; break; case cmdFPR: show_key_and_fingerprint (keyblock); break; case cmdSELUID: if (strlen (arg_string) == NAMEHASH_LEN * 2) redisplay = menu_select_uid_namehash (keyblock, arg_string); else { if (*arg_string == '*' && (!arg_string[1] || spacep (arg_string + 1))) arg_number = -1; /* Select all. */ redisplay = menu_select_uid (keyblock, arg_number); } break; case cmdSELKEY: { if (*arg_string == '*' && (!arg_string[1] || spacep (arg_string + 1))) arg_number = -1; /* Select all. */ if (menu_select_key (keyblock, arg_number)) redisplay = 1; } break; case cmdCHECK: check_all_keysigs (keyblock, count_selected_uids (keyblock)); break; case cmdSIGN: { int localsig = 0, nonrevokesig = 0, trustsig = 0, interactive = 0; if (pk->flags.revoked) { tty_printf (_("Key is revoked.")); if (opt.expert) { tty_printf (" "); if (!cpr_get_answer_is_yes ("keyedit.sign_revoked.okay", _("Are you sure you still want to sign it? (y/N) "))) break; } else { tty_printf (_(" Unable to sign.\n")); break; } } if (count_uids (keyblock) > 1 && !count_selected_uids (keyblock) && !cpr_get_answer_is_yes ("keyedit.sign_all.okay", _("Really sign all user IDs?" " (y/N) "))) { if (opt.interactive) interactive = 1; else { tty_printf (_("Hint: Select the user IDs to sign\n")); have_commands = 0; break; } } /* What sort of signing are we doing? */ if (!parse_sign_type (answer, &localsig, &nonrevokesig, &trustsig)) { tty_printf (_("Unknown signature type '%s'\n"), answer); break; } sign_uids (NULL, keyblock, locusr, &modified, localsig, nonrevokesig, trustsig, interactive, 0); } break; case cmdDEBUG: dump_kbnode (keyblock); break; case cmdTOGGLE: /* The toggle command is a leftover from old gpg versions where we worked with a secret and a public keyring. It is not necessary anymore but we keep this command for the sake of scripts using it. */ toggle = !toggle; redisplay = 1; break; case cmdADDPHOTO: if (RFC2440) { tty_printf (_("This command is not allowed while in %s mode.\n"), compliance_option_string ()); break; } photo = 1; /* fall through */ case cmdADDUID: - if (menu_adduid (keyblock, photo, arg_string)) + if (menu_adduid (keyblock, photo, arg_string, NULL)) { update_trust = 1; redisplay = 1; modified = 1; merge_keys_and_selfsig (keyblock); } break; case cmdDELUID: { int n1; if (!(n1 = count_selected_uids (keyblock))) tty_printf (_("You must select at least one user ID.\n")); else if (real_uids_left (keyblock) < 1) tty_printf (_("You can't delete the last user ID!\n")); else if (cpr_get_answer_is_yes ("keyedit.remove.uid.okay", n1 > 1 ? _("Really remove all selected user IDs? (y/N) ") : _("Really remove this user ID? (y/N) "))) { menu_deluid (keyblock); redisplay = 1; modified = 1; } } break; case cmdDELSIG: { int n1; if (!(n1 = count_selected_uids (keyblock))) tty_printf (_("You must select at least one user ID.\n")); else if (menu_delsig (keyblock)) { /* No redisplay here, because it may scroll away some * of the status output of this command. */ modified = 1; } } break; case cmdADDKEY: if (!generate_subkeypair (ctrl, keyblock)) { redisplay = 1; modified = 1; merge_keys_and_selfsig (keyblock); } break; #ifdef ENABLE_CARD_SUPPORT case cmdADDCARDKEY: if (!card_generate_subkey (keyblock)) { redisplay = 1; modified = 1; merge_keys_and_selfsig (keyblock); } break; case cmdKEYTOCARD: { KBNODE node = NULL; switch (count_selected_keys (keyblock)) { case 0: if (cpr_get_answer_is_yes ("keyedit.keytocard.use_primary", /* TRANSLATORS: Please take care: This is about moving the key and not about removing it. */ _("Really move the primary key? (y/N) "))) node = keyblock; break; case 1: for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY && node->flag & NODFLG_SELKEY) break; } break; default: tty_printf (_("You must select exactly one key.\n")); break; } if (node) { PKT_public_key *xxpk = node->pkt->pkt.public_key; if (card_store_subkey (node, xxpk ? xxpk->pubkey_usage : 0)) { redisplay = 1; sec_shadowing = 1; } } } break; case cmdBKUPTOCARD: case cmdCHECKBKUPKEY: log_debug ("FIXME: This needs to be changed\n"); { /* Ask for a filename, check whether this is really a backup key as generated by the card generation, parse that key and store it on card. */ KBNODE node; const char *fname; PACKET *pkt; IOBUF a; fname = arg_string; if (!*fname) { tty_printf (_("Command expects a filename argument\n")); break; } /* Open that file. */ a = iobuf_open (fname); if (a && is_secured_file (iobuf_get_fd (a))) { iobuf_close (a); a = NULL; gpg_err_set_errno (EPERM); } if (!a) { tty_printf (_("Can't open '%s': %s\n"), fname, strerror (errno)); break; } /* Parse and check that file. */ pkt = xmalloc (sizeof *pkt); init_packet (pkt); err = parse_packet (a, pkt); iobuf_close (a); iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char *) fname); if (!err && pkt->pkttype != PKT_SECRET_KEY && pkt->pkttype != PKT_SECRET_SUBKEY) err = GPG_ERR_NO_SECKEY; if (err) { tty_printf (_("Error reading backup key from '%s': %s\n"), fname, gpg_strerror (err)); free_packet (pkt); xfree (pkt); break; } node = new_kbnode (pkt); if (cmd == cmdCHECKBKUPKEY) { /* PKT_public_key *sk = node->pkt->pkt.secret_key; */ /* switch (is_secret_key_protected (sk)) */ /* { */ /* case 0: /\* Not protected. *\/ */ /* tty_printf (_("This key is not protected.\n")); */ /* break; */ /* case -1: */ /* log_error (_("unknown key protection algorithm\n")); */ /* break; */ /* default: */ /* if (sk->protect.s2k.mode == 1001) */ /* tty_printf (_("Secret parts of key" */ /* " are not available.\n")); */ /* if (sk->protect.s2k.mode == 1002) */ /* tty_printf (_("Secret parts of key" */ /* " are stored on-card.\n")); */ /* else */ /* check_secret_key (sk, 0); */ /* } */ } else /* Store it. */ { if (card_store_subkey (node, 0)) { redisplay = 1; sec_shadowing = 1; } } release_kbnode (node); } break; #endif /* ENABLE_CARD_SUPPORT */ case cmdDELKEY: { int n1; if (!(n1 = count_selected_keys (keyblock))) tty_printf (_("You must select at least one key.\n")); else if (!cpr_get_answer_is_yes ("keyedit.remove.subkey.okay", n1 > 1 ? _("Do you really want to delete the " "selected keys? (y/N) ") : _("Do you really want to delete this key? (y/N) "))) ; else { menu_delkey (keyblock); redisplay = 1; modified = 1; } } break; case cmdADDREVOKER: { int sensitive = 0; if (ascii_strcasecmp (arg_string, "sensitive") == 0) sensitive = 1; if (menu_addrevoker (ctrl, keyblock, sensitive)) { redisplay = 1; modified = 1; merge_keys_and_selfsig (keyblock); } } break; case cmdREVUID: { int n1; if (!(n1 = count_selected_uids (keyblock))) tty_printf (_("You must select at least one user ID.\n")); else if (cpr_get_answer_is_yes ("keyedit.revoke.uid.okay", n1 > 1 ? _("Really revoke all selected user IDs? (y/N) ") : _("Really revoke this user ID? (y/N) "))) { if (menu_revuid (keyblock)) { modified = 1; redisplay = 1; } } } break; case cmdREVKEY: { int n1; if (!(n1 = count_selected_keys (keyblock))) { if (cpr_get_answer_is_yes ("keyedit.revoke.subkey.okay", _("Do you really want to revoke" " the entire key? (y/N) "))) { if (menu_revkey (keyblock)) modified = 1; redisplay = 1; } } else if (cpr_get_answer_is_yes ("keyedit.revoke.subkey.okay", n1 > 1 ? _("Do you really want to revoke" " the selected subkeys? (y/N) ") : _("Do you really want to revoke" " this subkey? (y/N) "))) { if (menu_revsubkey (keyblock)) modified = 1; redisplay = 1; } if (modified) merge_keys_and_selfsig (keyblock); } break; case cmdEXPIRE: if (menu_expire (keyblock)) { merge_keys_and_selfsig (keyblock); run_subkey_warnings = 1; modified = 1; redisplay = 1; } break; case cmdBACKSIGN: if (menu_backsign (keyblock)) { modified = 1; redisplay = 1; } break; case cmdPRIMARY: if (menu_set_primary_uid (keyblock)) { merge_keys_and_selfsig (keyblock); modified = 1; redisplay = 1; } break; case cmdPASSWD: change_passphrase (ctrl, keyblock); break; #ifndef NO_TRUST_MODELS case cmdTRUST: if (opt.trust_model == TM_EXTERNAL) { tty_printf (_("Owner trust may not be set while " "using a user provided trust database\n")); break; } show_key_with_all_names (NULL, keyblock, 0, 0, 0, 1, 0, 0); tty_printf ("\n"); if (edit_ownertrust (find_kbnode (keyblock, PKT_PUBLIC_KEY)->pkt->pkt. public_key, 1)) { redisplay = 1; /* No real need to set update_trust here as edit_ownertrust() calls revalidation_mark() anyway. */ update_trust = 1; } break; #endif /*!NO_TRUST_MODELS*/ case cmdPREF: { int count = count_selected_uids (keyblock); assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY); show_names (NULL, keyblock, keyblock->pkt->pkt.public_key, count ? NODFLG_SELUID : 0, 1); } break; case cmdSHOWPREF: { int count = count_selected_uids (keyblock); assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY); show_names (NULL, keyblock, keyblock->pkt->pkt.public_key, count ? NODFLG_SELUID : 0, 2); } break; case cmdSETPREF: { PKT_user_id *tempuid; keygen_set_std_prefs (!*arg_string ? "default" : arg_string, 0); tempuid = keygen_get_std_prefs (); tty_printf (_("Set preference list to:\n")); show_prefs (tempuid, NULL, 1); free_user_id (tempuid); if (cpr_get_answer_is_yes ("keyedit.setpref.okay", count_selected_uids (keyblock) ? _("Really update the preferences" " for the selected user IDs? (y/N) ") : _("Really update the preferences? (y/N) "))) { if (menu_set_preferences (keyblock)) { merge_keys_and_selfsig (keyblock); modified = 1; redisplay = 1; } } } break; case cmdPREFKS: if (menu_set_keyserver_url (*arg_string ? arg_string : NULL, keyblock)) { merge_keys_and_selfsig (keyblock); modified = 1; redisplay = 1; } break; case cmdNOTATION: if (menu_set_notation (*arg_string ? arg_string : NULL, keyblock)) { merge_keys_and_selfsig (keyblock); modified = 1; redisplay = 1; } break; case cmdNOP: break; case cmdREVSIG: if (menu_revsig (keyblock)) { redisplay = 1; modified = 1; } break; #ifndef NO_TRUST_MODELS case cmdENABLEKEY: case cmdDISABLEKEY: if (enable_disable_key (keyblock, cmd == cmdDISABLEKEY)) { redisplay = 1; modified = 1; } break; #endif /*!NO_TRUST_MODELS*/ case cmdSHOWPHOTO: menu_showphoto (keyblock); break; case cmdCLEAN: if (menu_clean (keyblock, 0)) redisplay = modified = 1; break; case cmdMINIMIZE: if (menu_clean (keyblock, 1)) redisplay = modified = 1; break; case cmdQUIT: if (have_commands) goto leave; if (!modified && !sec_shadowing) goto leave; if (!cpr_get_answer_is_yes ("keyedit.save.okay", _("Save changes? (y/N) "))) { if (cpr_enabled () || cpr_get_answer_is_yes ("keyedit.cancel.okay", _("Quit without saving? (y/N) "))) goto leave; break; } /* fall thru */ case cmdSAVE: if (modified) { err = keydb_update_keyblock (kdbhd, keyblock); if (err) { log_error (_("update failed: %s\n"), gpg_strerror (err)); break; } } if (sec_shadowing) { err = agent_scd_learn (NULL, 1); if (err) { log_error (_("update failed: %s\n"), gpg_strerror (err)); break; } } if (!modified && !sec_shadowing) tty_printf (_("Key not changed so no update needed.\n")); if (update_trust) { revalidation_mark (); update_trust = 0; } goto leave; case cmdINVCMD: default: tty_printf ("\n"); tty_printf (_("Invalid command (try \"help\")\n")); break; } } /* End of the main command loop. */ leave: release_kbnode (keyblock); keydb_release (kdbhd); xfree (answer); } /* Change the passphrase of the secret key identified by USERNAME. */ void keyedit_passwd (ctrl_t ctrl, const char *username) { gpg_error_t err; PKT_public_key *pk; kbnode_t keyblock = NULL; pk = xtrycalloc (1, sizeof *pk); if (!pk) { err = gpg_error_from_syserror (); goto leave; } err = getkey_byname (NULL, pk, username, 1, &keyblock); if (err) goto leave; err = change_passphrase (ctrl, keyblock); leave: release_kbnode (keyblock); free_public_key (pk); if (err) { log_info ("error changing the passphrase for '%s': %s\n", username, gpg_strerror (err)); write_status_error ("keyedit.passwd", err); } else write_status_text (STATUS_SUCCESS, "keyedit.passwd"); } +/* Unattended adding of a new keyid. USERNAME specifies the + key. NEWUID is the new user id to add to the key. */ +void +keyedit_quick_adduid (ctrl_t ctrl, const char *username, const char *newuid) +{ + gpg_error_t err; + KEYDB_HANDLE kdbhd = NULL; + KEYDB_SEARCH_DESC desc; + kbnode_t keyblock = NULL; + kbnode_t node; + char *uidstring = NULL; + + uidstring = xstrdup (newuid); + trim_spaces (uidstring); + if (!*uidstring) + { + log_error ("%s\n", gpg_strerror (GPG_ERR_INV_USER_ID)); + goto leave; + } + +#ifdef HAVE_W32_SYSTEM + /* See keyedit_menu for why we need this. */ + check_trustdb_stale (); +#endif + + /* Search the key; we don't want the whole getkey stuff here. */ + kdbhd = keydb_new (); + err = classify_user_id (username, &desc, 1); + if (!err) + err = keydb_search (kdbhd, &desc, 1, NULL); + if (!err) + { + err = keydb_get_keyblock (kdbhd, &keyblock); + if (err) + { + log_error (_("error reading keyblock: %s\n"), gpg_strerror (err)); + goto leave; + } + /* Now with the keyblock retrieved, search again to detect an + ambiguous specification. We need to save the found state so + that we can do an update later. */ + keydb_push_found_state (kdbhd); + err = keydb_search (kdbhd, &desc, 1, NULL); + if (!err) + err = gpg_error (GPG_ERR_AMBIGUOUS_NAME); + else if (gpg_err_code (err) == GPG_ERR_NOT_FOUND) + err = 0; + keydb_pop_found_state (kdbhd); + + if (!err) + { + /* We require the secret primary key to add a UID. */ + node = find_kbnode (keyblock, PKT_PUBLIC_KEY); + if (!node) + BUG (); + err = agent_probe_secret_key (ctrl, node->pkt->pkt.public_key); + } + } + if (err) + { + log_error (_("secret key \"%s\" not found: %s\n"), + username, gpg_strerror (err)); + goto leave; + } + + fix_keyblock (&keyblock); + + if (menu_adduid (keyblock, 0, NULL, uidstring)) + { + err = keydb_update_keyblock (kdbhd, keyblock); + if (err) + { + log_error (_("update failed: %s\n"), gpg_strerror (err)); + goto leave; + } + + if (update_trust) + revalidation_mark (); + } + + leave: + xfree (uidstring); + release_kbnode (keyblock); + keydb_release (kdbhd); +} + + /* Unattended key signing function. If the key specifified by FPR is availabale and FPR is the primary fingerprint all user ids of the user ids of the key are signed using the default signing key. If UIDS is an empty list all usable UIDs are signed, if it is not empty, only those user ids matching one of the entries of the loist are signed. With LOCAL being true kthe signatures are marked as non-exportable. */ void keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids, strlist_t locusr, int local) { gpg_error_t err; kbnode_t keyblock = NULL; KEYDB_HANDLE kdbhd = NULL; int modified = 0; KEYDB_SEARCH_DESC desc; PKT_public_key *pk; kbnode_t node; strlist_t sl; int any; #ifdef HAVE_W32_SYSTEM /* See keyedit_menu for why we need this. */ check_trustdb_stale (); #endif /* We require a fingerprint because only this uniquely identifies a key and may thus be used to select a key for unattended key signing. */ if (classify_user_id (fpr, &desc, 1) || !(desc.mode == KEYDB_SEARCH_MODE_FPR || desc.mode == KEYDB_SEARCH_MODE_FPR16 || desc.mode == KEYDB_SEARCH_MODE_FPR20)) { log_error (_("\"%s\" is not a fingerprint\n"), fpr); goto leave; } err = get_pubkey_byname (ctrl, NULL, NULL, fpr, &keyblock, &kdbhd, 1, 1); if (err) { log_error (_("key \"%s\" not found: %s\n"), fpr, gpg_strerror (err)); goto leave; } /* Check that the primary fingerprint has been given. */ { byte fprbin[MAX_FINGERPRINT_LEN]; size_t fprlen; fingerprint_from_pk (keyblock->pkt->pkt.public_key, fprbin, &fprlen); if (fprlen == 16 && desc.mode == KEYDB_SEARCH_MODE_FPR16 && !memcmp (fprbin, desc.u.fpr, 16)) ; else if (fprlen == 16 && desc.mode == KEYDB_SEARCH_MODE_FPR && !memcmp (fprbin, desc.u.fpr, 16) && !desc.u.fpr[16] && !desc.u.fpr[17] && !desc.u.fpr[18] && !desc.u.fpr[19]) ; else if (fprlen == 20 && (desc.mode == KEYDB_SEARCH_MODE_FPR20 || desc.mode == KEYDB_SEARCH_MODE_FPR) && !memcmp (fprbin, desc.u.fpr, 20)) ; else { log_error (_("\"%s\" is not the primary fingerprint\n"), fpr); goto leave; } } if (fix_keyblock (&keyblock)) modified++; /* Give some info in verbose. */ if (opt.verbose) { show_key_with_all_names (es_stdout, keyblock, 0, 1/*with_revoker*/, 1/*with_fingerprint*/, 0, 0, 1); es_fflush (es_stdout); } pk = keyblock->pkt->pkt.public_key; if (pk->flags.revoked) { if (!opt.verbose) show_key_with_all_names (es_stdout, keyblock, 0, 0, 0, 0, 0, 1); log_error ("%s%s", _("Key is revoked."), _(" Unable to sign.\n")); goto leave; } /* Set the flags according to the UIDS list. Fixme: We may want to use classify_user_id along with dedicated compare functions so that we match the same way as in the key lookup. */ any = 0; menu_select_uid (keyblock, 0); /* Better clear the flags first. */ for (sl=uids; sl; sl = sl->next) { for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID) { PKT_user_id *uid = node->pkt->pkt.user_id; if (!uid->attrib_data && ascii_memistr (uid->name, uid->len, sl->d)) { node->flag |= NODFLG_SELUID; any = 1; } } } } if (uids && !any) { if (!opt.verbose) show_key_with_all_names (es_stdout, keyblock, 0, 0, 0, 0, 0, 1); es_fflush (es_stdout); log_error ("%s %s", _("No matching user IDs."), _("Nothing to sign.\n")); goto leave; } /* Sign. */ sign_uids (es_stdout, keyblock, locusr, &modified, local, 0, 0, 0, 1); es_fflush (es_stdout); if (modified) { err = keydb_update_keyblock (kdbhd, keyblock); if (err) { log_error (_("update failed: %s\n"), gpg_strerror (err)); goto leave; } } else log_info (_("Key not changed so no update needed.\n")); if (update_trust) revalidation_mark (); leave: release_kbnode (keyblock); keydb_release (kdbhd); } static void tty_print_notations (int indent, PKT_signature * sig) { int first = 1; struct notation *notation, *nd; if (indent < 0) { first = 0; indent = -indent; } notation = sig_to_notation (sig); for (nd = notation; nd; nd = nd->next) { if (!first) tty_printf ("%*s", indent, ""); else first = 0; tty_print_utf8_string (nd->name, strlen (nd->name)); tty_printf ("="); tty_print_utf8_string (nd->value, strlen (nd->value)); tty_printf ("\n"); } free_notation (notation); } /* * Show preferences of a public keyblock. */ static void show_prefs (PKT_user_id * uid, PKT_signature * selfsig, int verbose) { const prefitem_t fake = { 0, 0 }; const prefitem_t *prefs; int i; if (!uid) return; if (uid->prefs) prefs = uid->prefs; else if (verbose) prefs = &fake; else return; if (verbose) { int any, des_seen = 0, sha1_seen = 0, uncomp_seen = 0; tty_printf (" "); tty_printf (_("Cipher: ")); for (i = any = 0; prefs[i].type; i++) { if (prefs[i].type == PREFTYPE_SYM) { if (any) tty_printf (", "); any = 1; /* We don't want to display strings for experimental algos */ if (!openpgp_cipher_test_algo (prefs[i].value) && prefs[i].value < 100) tty_printf ("%s", openpgp_cipher_algo_name (prefs[i].value)); else tty_printf ("[%d]", prefs[i].value); if (prefs[i].value == CIPHER_ALGO_3DES) des_seen = 1; } } if (!des_seen) { if (any) tty_printf (", "); tty_printf ("%s", openpgp_cipher_algo_name (CIPHER_ALGO_3DES)); } tty_printf ("\n "); tty_printf (_("Digest: ")); for (i = any = 0; prefs[i].type; i++) { if (prefs[i].type == PREFTYPE_HASH) { if (any) tty_printf (", "); any = 1; /* We don't want to display strings for experimental algos */ if (!gcry_md_test_algo (prefs[i].value) && prefs[i].value < 100) tty_printf ("%s", gcry_md_algo_name (prefs[i].value)); else tty_printf ("[%d]", prefs[i].value); if (prefs[i].value == DIGEST_ALGO_SHA1) sha1_seen = 1; } } if (!sha1_seen) { if (any) tty_printf (", "); tty_printf ("%s", gcry_md_algo_name (DIGEST_ALGO_SHA1)); } tty_printf ("\n "); tty_printf (_("Compression: ")); for (i = any = 0; prefs[i].type; i++) { if (prefs[i].type == PREFTYPE_ZIP) { const char *s = compress_algo_to_string (prefs[i].value); if (any) tty_printf (", "); any = 1; /* We don't want to display strings for experimental algos */ if (s && prefs[i].value < 100) tty_printf ("%s", s); else tty_printf ("[%d]", prefs[i].value); if (prefs[i].value == COMPRESS_ALGO_NONE) uncomp_seen = 1; } } if (!uncomp_seen) { if (any) tty_printf (", "); else { tty_printf ("%s", compress_algo_to_string (COMPRESS_ALGO_ZIP)); tty_printf (", "); } tty_printf ("%s", compress_algo_to_string (COMPRESS_ALGO_NONE)); } if (uid->flags.mdc || !uid->flags.ks_modify) { tty_printf ("\n "); tty_printf (_("Features: ")); any = 0; if (uid->flags.mdc) { tty_printf ("MDC"); any = 1; } if (!uid->flags.ks_modify) { if (any) tty_printf (", "); tty_printf (_("Keyserver no-modify")); } } tty_printf ("\n"); if (selfsig) { const byte *pref_ks; size_t pref_ks_len; pref_ks = parse_sig_subpkt (selfsig->hashed, SIGSUBPKT_PREF_KS, &pref_ks_len); if (pref_ks && pref_ks_len) { tty_printf (" "); tty_printf (_("Preferred keyserver: ")); tty_print_utf8_string (pref_ks, pref_ks_len); tty_printf ("\n"); } if (selfsig->flags.notation) { tty_printf (" "); tty_printf (_("Notations: ")); tty_print_notations (5 + strlen (_("Notations: ")), selfsig); } } } else { tty_printf (" "); for (i = 0; prefs[i].type; i++) { tty_printf (" %c%d", prefs[i].type == PREFTYPE_SYM ? 'S' : prefs[i].type == PREFTYPE_HASH ? 'H' : prefs[i].type == PREFTYPE_ZIP ? 'Z' : '?', prefs[i].value); } if (uid->flags.mdc) tty_printf (" [mdc]"); if (!uid->flags.ks_modify) tty_printf (" [no-ks-modify]"); tty_printf ("\n"); } } /* This is the version of show_key_with_all_names used when opt.with_colons is used. It prints all available data in a easy to parse format and does not translate utf8 */ static void show_key_with_all_names_colon (estream_t fp, kbnode_t keyblock) { KBNODE node; int i, j, ulti_hack = 0; byte pk_version = 0; PKT_public_key *primary = NULL; if (!fp) fp = es_stdout; /* the keys */ for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_KEY || (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)) { PKT_public_key *pk = node->pkt->pkt.public_key; u32 keyid[2]; if (node->pkt->pkttype == PKT_PUBLIC_KEY) { pk_version = pk->version; primary = pk; } keyid_from_pk (pk, keyid); es_fputs (node->pkt->pkttype == PKT_PUBLIC_KEY ? "pub:" : "sub:", fp); if (!pk->flags.valid) es_putc ('i', fp); else if (pk->flags.revoked) es_putc ('r', fp); else if (pk->has_expired) es_putc ('e', fp); else if (!(opt.fast_list_mode || opt.no_expensive_trust_checks)) { int trust = get_validity_info (pk, NULL); if (trust == 'u') ulti_hack = 1; es_putc (trust, fp); } es_fprintf (fp, ":%u:%d:%08lX%08lX:%lu:%lu::", nbits_from_pk (pk), pk->pubkey_algo, (ulong) keyid[0], (ulong) keyid[1], (ulong) pk->timestamp, (ulong) pk->expiredate); if (node->pkt->pkttype == PKT_PUBLIC_KEY && !(opt.fast_list_mode || opt.no_expensive_trust_checks)) es_putc (get_ownertrust_info (pk), fp); es_putc (':', fp); es_putc (':', fp); es_putc (':', fp); /* Print capabilities. */ if ((pk->pubkey_usage & PUBKEY_USAGE_ENC)) es_putc ('e', fp); if ((pk->pubkey_usage & PUBKEY_USAGE_SIG)) es_putc ('s', fp); if ((pk->pubkey_usage & PUBKEY_USAGE_CERT)) es_putc ('c', fp); if ((pk->pubkey_usage & PUBKEY_USAGE_AUTH)) es_putc ('a', fp); es_putc ('\n', fp); print_fingerprint (fp, pk, 0); print_revokers (fp, pk); } } /* the user ids */ i = 0; for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID) { PKT_user_id *uid = node->pkt->pkt.user_id; ++i; if (uid->attrib_data) es_fputs ("uat:", fp); else es_fputs ("uid:", fp); if (uid->is_revoked) es_fputs ("r::::::::", fp); else if (uid->is_expired) es_fputs ("e::::::::", fp); else if (opt.fast_list_mode || opt.no_expensive_trust_checks) es_fputs ("::::::::", fp); else { int uid_validity; if (primary && !ulti_hack) uid_validity = get_validity_info (primary, uid); else uid_validity = 'u'; es_fprintf (fp, "%c::::::::", uid_validity); } if (uid->attrib_data) es_fprintf (fp, "%u %lu", uid->numattribs, uid->attrib_len); else es_write_sanitized (fp, uid->name, uid->len, ":", NULL); es_putc (':', fp); /* signature class */ es_putc (':', fp); /* capabilities */ es_putc (':', fp); /* preferences */ if (pk_version > 3 || uid->selfsigversion > 3) { const prefitem_t *prefs = uid->prefs; for (j = 0; prefs && prefs[j].type; j++) { if (j) es_putc (' ', fp); es_fprintf (fp, "%c%d", prefs[j].type == PREFTYPE_SYM ? 'S' : prefs[j].type == PREFTYPE_HASH ? 'H' : prefs[j].type == PREFTYPE_ZIP ? 'Z' : '?', prefs[j].value); } if (uid->flags.mdc) es_fputs (",mdc", fp); if (!uid->flags.ks_modify) es_fputs (",no-ks-modify", fp); } es_putc (':', fp); /* flags */ es_fprintf (fp, "%d,", i); if (uid->is_primary) es_putc ('p', fp); if (uid->is_revoked) es_putc ('r', fp); if (uid->is_expired) es_putc ('e', fp); if ((node->flag & NODFLG_SELUID)) es_putc ('s', fp); if ((node->flag & NODFLG_MARK_A)) es_putc ('m', fp); es_putc (':', fp); es_putc ('\n', fp); } } } static void show_names (estream_t fp, KBNODE keyblock, PKT_public_key * pk, unsigned int flag, int with_prefs) { KBNODE node; int i = 0; for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID && !is_deleted_kbnode (node)) { PKT_user_id *uid = node->pkt->pkt.user_id; ++i; if (!flag || (flag && (node->flag & flag))) { if (!(flag & NODFLG_MARK_A) && pk) tty_fprintf (fp, "%s ", uid_trust_string_fixed (pk, uid)); if (flag & NODFLG_MARK_A) tty_fprintf (fp, " "); else if (node->flag & NODFLG_SELUID) tty_fprintf (fp, "(%d)* ", i); else if (uid->is_primary) tty_fprintf (fp, "(%d). ", i); else tty_fprintf (fp, "(%d) ", i); tty_print_utf8_string2 (fp, uid->name, uid->len, 0); tty_fprintf (fp, "\n"); if (with_prefs && pk) { if (pk->version > 3 || uid->selfsigversion > 3) { PKT_signature *selfsig = NULL; KBNODE signode; for (signode = node->next; signode && signode->pkt->pkttype == PKT_SIGNATURE; signode = signode->next) { if (signode->pkt->pkt.signature-> flags.chosen_selfsig) { selfsig = signode->pkt->pkt.signature; break; } } show_prefs (uid, selfsig, with_prefs == 2); } else tty_fprintf (fp, _("There are no preferences on a" " PGP 2.x-style user ID.\n")); } } } } } /* * Display the key a the user ids, if only_marked is true, do only so * for user ids with mark A flag set and do not display the index * number. If FP is not NULL print to the given stream and not to the * tty (ignored in with-colons mode). */ static void show_key_with_all_names (estream_t fp, KBNODE keyblock, int only_marked, int with_revoker, int with_fpr, int with_subkeys, int with_prefs, int nowarn) { KBNODE node; int i; int do_warn = 0; PKT_public_key *primary = NULL; char pkstrbuf[PUBKEY_STRING_SIZE]; if (opt.with_colons) { show_key_with_all_names_colon (fp, keyblock); return; } /* the keys */ for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_KEY || (with_subkeys && node->pkt->pkttype == PKT_PUBLIC_SUBKEY && !is_deleted_kbnode (node))) { PKT_public_key *pk = node->pkt->pkt.public_key; const char *otrust = "err"; const char *trust = "err"; if (node->pkt->pkttype == PKT_PUBLIC_KEY) { /* do it here, so that debug messages don't clutter the * output */ static int did_warn = 0; trust = get_validity_string (pk, NULL); otrust = get_ownertrust_string (pk); /* Show a warning once */ if (!did_warn && (get_validity (pk, NULL) & TRUST_FLAG_PENDING_CHECK)) { did_warn = 1; do_warn = 1; } primary = pk; } if (pk->flags.revoked) { char *user = get_user_id_string_native (pk->revoked.keyid); tty_fprintf (fp, _("The following key was revoked on" " %s by %s key %s\n"), revokestr_from_pk (pk), gcry_pk_algo_name (pk->revoked.algo), user); xfree (user); } if (with_revoker) { if (!pk->revkey && pk->numrevkeys) BUG (); else for (i = 0; i < pk->numrevkeys; i++) { u32 r_keyid[2]; char *user; const char *algo; algo = gcry_pk_algo_name (pk->revkey[i].algid); keyid_from_fingerprint (pk->revkey[i].fpr, MAX_FINGERPRINT_LEN, r_keyid); user = get_user_id_string_native (r_keyid); tty_fprintf (fp, _("This key may be revoked by %s key %s"), algo ? algo : "?", user); if (pk->revkey[i].class & 0x40) { tty_fprintf (fp, " "); tty_fprintf (fp, _("(sensitive)")); } tty_fprintf (fp, "\n"); xfree (user); } } keyid_from_pk (pk, NULL); tty_fprintf (fp, "%s%c %s/%s", node->pkt->pkttype == PKT_PUBLIC_KEY ? "pub" : node->pkt->pkttype == PKT_PUBLIC_SUBKEY ? "sub" : node->pkt->pkttype == PKT_SECRET_KEY ? "sec" : "ssb", (node->flag & NODFLG_SELKEY) ? '*' : ' ', pubkey_string (pk, pkstrbuf, sizeof pkstrbuf), keystr (pk->keyid)); if (opt.legacy_list_mode) tty_fprintf (fp, " "); else tty_fprintf (fp, "\n "); tty_fprintf (fp, _("created: %s"), datestr_from_pk (pk)); tty_fprintf (fp, " "); if (pk->flags.revoked) tty_fprintf (fp, _("revoked: %s"), revokestr_from_pk (pk)); else if (pk->has_expired) tty_fprintf (fp, _("expired: %s"), expirestr_from_pk (pk)); else tty_fprintf (fp, _("expires: %s"), expirestr_from_pk (pk)); tty_fprintf (fp, " "); tty_fprintf (fp, _("usage: %s"), usagestr_from_pk (pk, 1)); tty_fprintf (fp, "\n"); if (pk->seckey_info && pk->seckey_info->is_protected && pk->seckey_info->s2k.mode == 1002) { tty_fprintf (fp, "%*s%s", opt.legacy_list_mode? 21:5, "", _("card-no: ")); if (pk->seckey_info->ivlen == 16 && !memcmp (pk->seckey_info->iv, "\xD2\x76\x00\x01\x24\x01", 6)) { /* This is an OpenPGP card. */ for (i = 8; i < 14; i++) { if (i == 10) tty_fprintf (fp, " "); tty_fprintf (fp, "%02X", pk->seckey_info->iv[i]); } } else { /* Unknown card: Print all. */ for (i = 0; i < pk->seckey_info->ivlen; i++) tty_fprintf (fp, "%02X", pk->seckey_info->iv[i]); } tty_fprintf (fp, "\n"); } if (node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_SECRET_KEY) { if (opt.trust_model != TM_ALWAYS) { tty_fprintf (fp, "%*s", opt.legacy_list_mode? ((int) keystrlen () + 13):5, ""); /* Ownertrust is only meaningful for the PGP or classic trust models */ if (opt.trust_model == TM_PGP || opt.trust_model == TM_CLASSIC) { int width = 14 - strlen (otrust); if (width <= 0) width = 1; tty_fprintf (fp, _("trust: %s"), otrust); tty_fprintf (fp, "%*s", width, ""); } tty_fprintf (fp, _("validity: %s"), trust); tty_fprintf (fp, "\n"); } if (node->pkt->pkttype == PKT_PUBLIC_KEY && (get_ownertrust (pk) & TRUST_FLAG_DISABLED)) { tty_fprintf (fp, "*** "); tty_fprintf (fp, _("This key has been disabled")); tty_fprintf (fp, "\n"); } } if ((node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_SECRET_KEY) && with_fpr) { print_fingerprint (fp, pk, 2); tty_fprintf (fp, "\n"); } } } show_names (fp, keyblock, primary, only_marked ? NODFLG_MARK_A : 0, with_prefs); if (do_warn && !nowarn) tty_fprintf (fp, _("Please note that the shown key validity" " is not necessarily correct\n" "unless you restart the program.\n")); } /* Display basic key information. This function is suitable to show information on the key without any dependencies on the trustdb or any other internal GnuPG stuff. KEYBLOCK may either be a public or a secret key.*/ void show_basic_key_info (KBNODE keyblock) { KBNODE node; int i; char pkstrbuf[PUBKEY_STRING_SIZE]; /* The primary key */ for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_KEY || node->pkt->pkttype == PKT_SECRET_KEY) { PKT_public_key *pk = node->pkt->pkt.public_key; /* Note, we use the same format string as in other show functions to make the translation job easier. */ tty_printf ("%s %s/%s ", node->pkt->pkttype == PKT_PUBLIC_KEY ? "pub" : node->pkt->pkttype == PKT_PUBLIC_SUBKEY ? "sub" : node->pkt->pkttype == PKT_SECRET_KEY ? "sec" :"ssb", pubkey_string (pk, pkstrbuf, sizeof pkstrbuf), keystr_from_pk (pk)); tty_printf (_("created: %s"), datestr_from_pk (pk)); tty_printf (" "); tty_printf (_("expires: %s"), expirestr_from_pk (pk)); tty_printf ("\n"); print_fingerprint (NULL, pk, 3); tty_printf ("\n"); } } /* The user IDs. */ for (i = 0, node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID) { PKT_user_id *uid = node->pkt->pkt.user_id; ++i; tty_printf (" "); if (uid->is_revoked) tty_printf ("[%s] ", _("revoked")); else if (uid->is_expired) tty_printf ("[%s] ", _("expired")); tty_print_utf8_string (uid->name, uid->len); tty_printf ("\n"); } } } static void show_key_and_fingerprint (KBNODE keyblock) { KBNODE node; PKT_public_key *pk = NULL; char pkstrbuf[PUBKEY_STRING_SIZE]; for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_KEY) { pk = node->pkt->pkt.public_key; tty_printf ("pub %s/%s %s ", pubkey_string (pk, pkstrbuf, sizeof pkstrbuf), keystr_from_pk(pk), datestr_from_pk (pk)); } else if (node->pkt->pkttype == PKT_USER_ID) { PKT_user_id *uid = node->pkt->pkt.user_id; tty_print_utf8_string (uid->name, uid->len); break; } } tty_printf ("\n"); if (pk) print_fingerprint (NULL, pk, 2); } /* Show a warning if no uids on the key have the primary uid flag set. */ static void no_primary_warning (KBNODE keyblock) { KBNODE node; int have_primary = 0, uid_count = 0; /* TODO: if we ever start behaving differently with a primary or non-primary attribute ID, we will need to check for attributes here as well. */ for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID && node->pkt->pkt.user_id->attrib_data == NULL) { uid_count++; if (node->pkt->pkt.user_id->is_primary == 2) { have_primary = 1; break; } } } if (uid_count > 1 && !have_primary) log_info (_ ("WARNING: no user ID has been marked as primary. This command" " may\n cause a different user ID to become" " the assumed primary.\n")); } /* Print a warning if the latest encryption subkey expires soon. This function is called after the expire data of the primary key has been changed. */ static void subkey_expire_warning (kbnode_t keyblock) { u32 curtime = make_timestamp (); kbnode_t node; PKT_public_key *pk; /* u32 mainexpire = 0; */ u32 subexpire = 0; u32 latest_date = 0; for (node = keyblock; node; node = node->next) { /* if (node->pkt->pkttype == PKT_PUBLIC_KEY) */ /* { */ /* pk = node->pkt->pkt.public_key; */ /* mainexpire = pk->expiredate; */ /* } */ if (node->pkt->pkttype != PKT_PUBLIC_SUBKEY) continue; pk = node->pkt->pkt.public_key; if (!pk->flags.valid) continue; if (pk->flags.revoked) continue; if (pk->timestamp > curtime) continue; /* Ignore future keys. */ if (!(pk->pubkey_usage & PUBKEY_USAGE_ENC)) continue; /* Not an encryption key. */ if (pk->timestamp > latest_date || (!pk->timestamp && !latest_date)) { latest_date = pk->timestamp; subexpire = pk->expiredate; } } if (!subexpire) return; /* No valid subkey with an expiration time. */ if (curtime + (10*86400) > subexpire) { log_info (_("WARNING: Your encryption subkey expires soon.\n")); log_info (_("You may want to change its expiration date too.\n")); } } /* - * Ask for a new user id, add the self-signature and update the keyblock. - * Return true if there is a new user id + * Ask for a new user id, add the self-signature, and update the + * keyblock. If UIDSTRING is not NULL the user ID is generated + * unattended using that string. UIDSTRING is expected to be utf-8 + * encoded and white space trimmed. Returns true if there is a new + * user id. */ static int -menu_adduid (KBNODE pub_keyblock, int photo, const char *photo_name) +menu_adduid (kbnode_t pub_keyblock, int photo, const char *photo_name, + const char *uidstring) { PKT_user_id *uid; PKT_public_key *pk = NULL; PKT_signature *sig = NULL; PACKET *pkt; KBNODE node; KBNODE pub_where = NULL; gpg_error_t err; + if (photo && uidstring) + return 0; /* Not allowed. */ + for (node = pub_keyblock; node; pub_where = node, node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_KEY) pk = node->pkt->pkt.public_key; else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) break; } if (!node) /* No subkey. */ pub_where = NULL; assert (pk); if (photo) { int hasattrib = 0; for (node = pub_keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_USER_ID && node->pkt->pkt.user_id->attrib_data != NULL) { hasattrib = 1; break; } /* It is legal but bad for compatibility to add a photo ID to a v3 key as it means that PGP2 will not be able to use that key anymore. Also, PGP may not expect a photo on a v3 key. Don't bother to ask this if the key already has a photo - any damage has already been done at that point. -dms */ if (pk->version == 3 && !hasattrib) { if (opt.expert) { tty_printf (_("WARNING: This is a PGP2-style key. " "Adding a photo ID may cause some versions\n" " of PGP to reject this key.\n")); if (!cpr_get_answer_is_yes ("keyedit.v3_photo.okay", _("Are you sure you still want " "to add it? (y/N) "))) return 0; } else { tty_printf (_("You may not add a photo ID to " "a PGP2-style key.\n")); return 0; } } uid = generate_photo_id (pk, photo_name); } else - uid = generate_user_id (pub_keyblock); + uid = generate_user_id (pub_keyblock, uidstring); if (!uid) - return 0; + { + if (uidstring) + log_error ("%s", _("Such a user ID already exists on this key!\n")); + return 0; + } err = make_keysig_packet (&sig, pk, uid, NULL, pk, 0x13, 0, 0, 0, keygen_add_std_prefs, pk, NULL); if (err) { log_error ("signing failed: %s\n", gpg_strerror (err)); free_user_id (uid); return 0; } /* Insert/append to public keyblock */ pkt = xmalloc_clear (sizeof *pkt); pkt->pkttype = PKT_USER_ID; pkt->pkt.user_id = uid; node = new_kbnode (pkt); if (pub_where) insert_kbnode (pub_where, node, 0); else add_kbnode (pub_keyblock, node); pkt = xmalloc_clear (sizeof *pkt); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = copy_signature (NULL, sig); if (pub_where) insert_kbnode (node, new_kbnode (pkt), 0); else add_kbnode (pub_keyblock, new_kbnode (pkt)); return 1; } /* * Remove all selected userids from the keyring */ static void menu_deluid (KBNODE pub_keyblock) { KBNODE node; int selected = 0; for (node = pub_keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID) { selected = node->flag & NODFLG_SELUID; if (selected) { /* Only cause a trust update if we delete a non-revoked user id */ if (!node->pkt->pkt.user_id->is_revoked) update_trust = 1; delete_kbnode (node); } } else if (selected && node->pkt->pkttype == PKT_SIGNATURE) delete_kbnode (node); else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) selected = 0; } commit_kbnode (&pub_keyblock); } static int menu_delsig (KBNODE pub_keyblock) { KBNODE node; PKT_user_id *uid = NULL; int changed = 0; for (node = pub_keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID) { uid = (node->flag & NODFLG_SELUID) ? node->pkt->pkt.user_id : NULL; } else if (uid && node->pkt->pkttype == PKT_SIGNATURE) { int okay, valid, selfsig, inv_sig, no_key, other_err; tty_printf ("uid "); tty_print_utf8_string (uid->name, uid->len); tty_printf ("\n"); okay = inv_sig = no_key = other_err = 0; if (opt.with_colons) valid = print_and_check_one_sig_colon (pub_keyblock, node, &inv_sig, &no_key, &other_err, &selfsig, 1); else valid = print_and_check_one_sig (pub_keyblock, node, &inv_sig, &no_key, &other_err, &selfsig, 1); if (valid) { okay = cpr_get_answer_yes_no_quit ("keyedit.delsig.valid", _("Delete this good signature? (y/N/q)")); /* Only update trust if we delete a good signature. The other two cases do not affect trust. */ if (okay) update_trust = 1; } else if (inv_sig || other_err) okay = cpr_get_answer_yes_no_quit ("keyedit.delsig.invalid", _("Delete this invalid signature? (y/N/q)")); else if (no_key) okay = cpr_get_answer_yes_no_quit ("keyedit.delsig.unknown", _("Delete this unknown signature? (y/N/q)")); if (okay == -1) break; if (okay && selfsig && !cpr_get_answer_is_yes ("keyedit.delsig.selfsig", _("Really delete this self-signature? (y/N)"))) okay = 0; if (okay) { delete_kbnode (node); changed++; } } else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) uid = NULL; } if (changed) { commit_kbnode (&pub_keyblock); tty_printf (changed == 1 ? _("Deleted %d signature.\n") : _("Deleted %d signatures.\n"), changed); } else tty_printf (_("Nothing deleted.\n")); return changed; } static int menu_clean (KBNODE keyblock, int self_only) { KBNODE uidnode; int modified = 0, select_all = !count_selected_uids (keyblock); for (uidnode = keyblock->next; uidnode && uidnode->pkt->pkttype != PKT_PUBLIC_SUBKEY; uidnode = uidnode->next) { if (uidnode->pkt->pkttype == PKT_USER_ID && (uidnode->flag & NODFLG_SELUID || select_all)) { int uids = 0, sigs = 0; char *user = utf8_to_native (uidnode->pkt->pkt.user_id->name, uidnode->pkt->pkt.user_id->len, 0); clean_one_uid (keyblock, uidnode, opt.verbose, self_only, &uids, &sigs); if (uids) { const char *reason; if (uidnode->pkt->pkt.user_id->is_revoked) reason = _("revoked"); else if (uidnode->pkt->pkt.user_id->is_expired) reason = _("expired"); else reason = _("invalid"); tty_printf (_("User ID \"%s\" compacted: %s\n"), user, reason); modified = 1; } else if (sigs) { tty_printf (sigs == 1 ? _("User ID \"%s\": %d signature removed\n") : _("User ID \"%s\": %d signatures removed\n"), user, sigs); modified = 1; } else { tty_printf (self_only == 1 ? _("User ID \"%s\": already minimized\n") : _("User ID \"%s\": already clean\n"), user); } xfree (user); } } return modified; } /* * Remove some of the secondary keys */ static void menu_delkey (KBNODE pub_keyblock) { KBNODE node; int selected = 0; for (node = pub_keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) { selected = node->flag & NODFLG_SELKEY; if (selected) delete_kbnode (node); } else if (selected && node->pkt->pkttype == PKT_SIGNATURE) delete_kbnode (node); else selected = 0; } commit_kbnode (&pub_keyblock); /* No need to set update_trust here since signing keys are no longer used to certify other keys, so there is no change in trust when revoking/removing them. */ } /* * Ask for a new revoker, create the self-signature and put it into * the keyblock. Returns true if there is a new revoker. */ static int menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive) { PKT_public_key *pk = NULL; PKT_public_key *revoker_pk = NULL; PKT_signature *sig = NULL; PACKET *pkt; struct revocation_key revkey; size_t fprlen; int rc; assert (pub_keyblock->pkt->pkttype == PKT_PUBLIC_KEY); pk = pub_keyblock->pkt->pkt.public_key; if (pk->numrevkeys == 0 && pk->version == 3) { /* It is legal but bad for compatibility to add a revoker to a v3 key as it means that PGP2 will not be able to use that key anymore. Also, PGP may not expect a revoker on a v3 key. Don't bother to ask this if the key already has a revoker - any damage has already been done at that point. -dms */ if (opt.expert) { tty_printf (_("WARNING: This is a PGP 2.x-style key. " "Adding a designated revoker may cause\n" " some versions of PGP to reject this key.\n")); if (!cpr_get_answer_is_yes ("keyedit.v3_revoker.okay", _("Are you sure you still want " "to add it? (y/N) "))) return 0; } else { tty_printf (_("You may not add a designated revoker to " "a PGP 2.x-style key.\n")); return 0; } } for (;;) { char *answer; free_public_key (revoker_pk); revoker_pk = xmalloc_clear (sizeof (*revoker_pk)); tty_printf ("\n"); answer = cpr_get_utf8 ("keyedit.add_revoker", _("Enter the user ID of the designated revoker: ")); if (answer[0] == '\0' || answer[0] == CONTROL_D) { xfree (answer); goto fail; } /* Note that I'm requesting CERT here, which usually implies primary keys only, but some casual testing shows that PGP and GnuPG both can handle a designated revocation from a subkey. */ revoker_pk->req_usage = PUBKEY_USAGE_CERT; rc = get_pubkey_byname (ctrl, NULL, revoker_pk, answer, NULL, NULL, 1, 1); if (rc) { log_error (_("key \"%s\" not found: %s\n"), answer, gpg_strerror (rc)); xfree (answer); continue; } xfree (answer); fingerprint_from_pk (revoker_pk, revkey.fpr, &fprlen); if (fprlen != 20) { log_error (_("cannot appoint a PGP 2.x style key as a " "designated revoker\n")); continue; } revkey.class = 0x80; if (sensitive) revkey.class |= 0x40; revkey.algid = revoker_pk->pubkey_algo; if (cmp_public_keys (revoker_pk, pk) == 0) { /* This actually causes no harm (after all, a key that designates itself as a revoker is the same as a regular key), but it's easy enough to check. */ log_error (_("you cannot appoint a key as its own " "designated revoker\n")); continue; } keyid_from_pk (pk, NULL); /* Does this revkey already exist? */ if (!pk->revkey && pk->numrevkeys) BUG (); else { int i; for (i = 0; i < pk->numrevkeys; i++) { if (memcmp (&pk->revkey[i], &revkey, sizeof (struct revocation_key)) == 0) { char buf[50]; log_error (_("this key has already been designated " "as a revoker\n")); sprintf (buf, "%08lX%08lX", (ulong) pk->keyid[0], (ulong) pk->keyid[1]); write_status_text (STATUS_ALREADY_SIGNED, buf); break; } } if (i < pk->numrevkeys) continue; } print_pubkey_info (NULL, revoker_pk); print_fingerprint (NULL, revoker_pk, 2); tty_printf ("\n"); tty_printf (_("WARNING: appointing a key as a designated revoker " "cannot be undone!\n")); tty_printf ("\n"); if (!cpr_get_answer_is_yes ("keyedit.add_revoker.okay", _("Are you sure you want to appoint this " "key as a designated revoker? (y/N) "))) continue; free_public_key (revoker_pk); revoker_pk = NULL; break; } rc = make_keysig_packet (&sig, pk, NULL, NULL, pk, 0x1F, 0, 0, 0, keygen_add_revkey, &revkey, NULL); if (rc) { log_error ("signing failed: %s\n", gpg_strerror (rc)); goto fail; } /* Insert into public keyblock. */ pkt = xmalloc_clear (sizeof *pkt); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; insert_kbnode (pub_keyblock, new_kbnode (pkt), PKT_SIGNATURE); return 1; fail: if (sig) free_seckey_enc (sig); free_public_key (revoker_pk); return 0; } static int menu_expire (KBNODE pub_keyblock) { int n1, signumber, rc; u32 expiredate; int mainkey = 0; PKT_public_key *main_pk, *sub_pk; PKT_user_id *uid; KBNODE node; u32 keyid[2]; n1 = count_selected_keys (pub_keyblock); if (n1 > 1) { tty_printf (_("Please select at most one subkey.\n")); return 0; } else if (n1) tty_printf (_("Changing expiration time for a subkey.\n")); else { tty_printf (_("Changing expiration time for the primary key.\n")); mainkey = 1; no_primary_warning (pub_keyblock); } expiredate = ask_expiredate (); /* Now we can actually change the self-signature(s) */ main_pk = sub_pk = NULL; uid = NULL; signumber = 0; for (node = pub_keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_KEY) { main_pk = node->pkt->pkt.public_key; keyid_from_pk (main_pk, keyid); main_pk->expiredate = expiredate; } else if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY && (node->flag & NODFLG_SELKEY)) { sub_pk = node->pkt->pkt.public_key; sub_pk->expiredate = expiredate; } else if (node->pkt->pkttype == PKT_USER_ID) uid = node->pkt->pkt.user_id; else if (main_pk && node->pkt->pkttype == PKT_SIGNATURE && (mainkey || sub_pk)) { PKT_signature *sig = node->pkt->pkt.signature; if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] && ((mainkey && uid && uid->created && (sig->sig_class & ~3) == 0x10) || (!mainkey && sig->sig_class == 0x18)) && sig->flags.chosen_selfsig) { /* This is a self-signature which is to be replaced. */ PKT_signature *newsig; PACKET *newpkt; signumber++; if ((mainkey && main_pk->version < 4) || (!mainkey && sub_pk->version < 4)) { log_info (_("You can't change the expiration date of a v3 key\n")); return 0; } if (mainkey) rc = update_keysig_packet (&newsig, sig, main_pk, uid, NULL, main_pk, keygen_add_key_expire, main_pk); else rc = update_keysig_packet (&newsig, sig, main_pk, NULL, sub_pk, main_pk, keygen_add_key_expire, sub_pk); if (rc) { log_error ("make_keysig_packet failed: %s\n", gpg_strerror (rc)); return 0; } /* Replace the packet. */ newpkt = xmalloc_clear (sizeof *newpkt); newpkt->pkttype = PKT_SIGNATURE; newpkt->pkt.signature = newsig; free_packet (node->pkt); xfree (node->pkt); node->pkt = newpkt; sub_pk = NULL; } } } update_trust = 1; return 1; } static int menu_backsign (KBNODE pub_keyblock) { int rc, modified = 0; PKT_public_key *main_pk; KBNODE node; u32 timestamp; assert (pub_keyblock->pkt->pkttype == PKT_PUBLIC_KEY); merge_keys_and_selfsig (pub_keyblock); main_pk = pub_keyblock->pkt->pkt.public_key; keyid_from_pk (main_pk, NULL); /* We use the same timestamp for all backsigs so that we don't reveal information about the used machine. */ timestamp = make_timestamp (); for (node = pub_keyblock; node; node = node->next) { PKT_public_key *sub_pk = NULL; KBNODE node2, sig_pk = NULL /*,sig_sk = NULL*/; /* char *passphrase; */ /* Find a signing subkey with no backsig */ if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) { if (node->pkt->pkt.public_key->pubkey_usage & PUBKEY_USAGE_SIG) { if (node->pkt->pkt.public_key->flags.backsig) tty_printf (_ ("signing subkey %s is already cross-certified\n"), keystr_from_pk (node->pkt->pkt.public_key)); else sub_pk = node->pkt->pkt.public_key; } else tty_printf (_("subkey %s does not sign and so does" " not need to be cross-certified\n"), keystr_from_pk (node->pkt->pkt.public_key)); } if (!sub_pk) continue; /* Find the selected selfsig on this subkey */ for (node2 = node->next; node2 && node2->pkt->pkttype == PKT_SIGNATURE; node2 = node2->next) if (node2->pkt->pkt.signature->version >= 4 && node2->pkt->pkt.signature->flags.chosen_selfsig) { sig_pk = node2; break; } if (!sig_pk) continue; /* Find the secret subkey that matches the public subkey */ log_debug ("FIXME: Check whether a secret subkey is available.\n"); /* if (!sub_sk) */ /* { */ /* tty_printf (_("no secret subkey for public subkey %s - ignoring\n"), */ /* keystr_from_pk (sub_pk)); */ /* continue; */ /* } */ /* Now we can get to work. */ rc = make_backsig (sig_pk->pkt->pkt.signature, main_pk, sub_pk, sub_pk, timestamp, NULL); if (!rc) { PKT_signature *newsig; PACKET *newpkt; rc = update_keysig_packet (&newsig, sig_pk->pkt->pkt.signature, main_pk, NULL, sub_pk, main_pk, NULL, NULL); if (!rc) { /* Put the new sig into place on the pubkey */ newpkt = xmalloc_clear (sizeof (*newpkt)); newpkt->pkttype = PKT_SIGNATURE; newpkt->pkt.signature = newsig; free_packet (sig_pk->pkt); xfree (sig_pk->pkt); sig_pk->pkt = newpkt; modified = 1; } else { log_error ("update_keysig_packet failed: %s\n", gpg_strerror (rc)); break; } } else { log_error ("make_backsig failed: %s\n", gpg_strerror (rc)); break; } } return modified; } static int change_primary_uid_cb (PKT_signature * sig, void *opaque) { byte buf[1]; /* first clear all primary uid flags so that we are sure none are * lingering around */ delete_sig_subpkt (sig->hashed, SIGSUBPKT_PRIMARY_UID); delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PRIMARY_UID); /* if opaque is set,we want to set the primary id */ if (opaque) { buf[0] = 1; build_sig_subpkt (sig, SIGSUBPKT_PRIMARY_UID, buf, 1); } return 0; } /* * Set the primary uid flag for the selected UID. We will also reset * all other primary uid flags. For this to work with have to update * all the signature timestamps. If we would do this with the current * time, we lose quite a lot of information, so we use a a kludge to * do this: Just increment the timestamp by one second which is * sufficient to updated a signature during import. */ static int menu_set_primary_uid (KBNODE pub_keyblock) { PKT_public_key *main_pk; PKT_user_id *uid; KBNODE node; u32 keyid[2]; int selected; int attribute = 0; int modified = 0; if (count_selected_uids (pub_keyblock) != 1) { tty_printf (_("Please select exactly one user ID.\n")); return 0; } main_pk = NULL; uid = NULL; selected = 0; /* Is our selected uid an attribute packet? */ for (node = pub_keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_USER_ID && node->flag & NODFLG_SELUID) attribute = (node->pkt->pkt.user_id->attrib_data != NULL); for (node = pub_keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) break; /* No more user ids expected - ready. */ if (node->pkt->pkttype == PKT_PUBLIC_KEY) { main_pk = node->pkt->pkt.public_key; keyid_from_pk (main_pk, keyid); } else if (node->pkt->pkttype == PKT_USER_ID) { uid = node->pkt->pkt.user_id; selected = node->flag & NODFLG_SELUID; } else if (main_pk && uid && node->pkt->pkttype == PKT_SIGNATURE) { PKT_signature *sig = node->pkt->pkt.signature; if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] && (uid && (sig->sig_class & ~3) == 0x10) && attribute == (uid->attrib_data != NULL) && sig->flags.chosen_selfsig) { if (sig->version < 4) { char *user = utf8_to_native (uid->name, strlen (uid->name), 0); log_info (_("skipping v3 self-signature on user ID \"%s\"\n"), user); xfree (user); } else { /* This is a selfsignature which is to be replaced. We can just ignore v3 signatures because they are not able to carry the primary ID flag. We also ignore self-sigs on user IDs that are not of the same type that we are making primary. That is, if we are making a user ID primary, we alter user IDs. If we are making an attribute packet primary, we alter attribute packets. */ /* FIXME: We must make sure that we only have one self-signature per user ID here (not counting revocations) */ PKT_signature *newsig; PACKET *newpkt; const byte *p; int action; /* See whether this signature has the primary UID flag. */ p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PRIMARY_UID, NULL); if (!p) p = parse_sig_subpkt (sig->unhashed, SIGSUBPKT_PRIMARY_UID, NULL); if (p && *p) /* yes */ action = selected ? 0 : -1; else /* no */ action = selected ? 1 : 0; if (action) { int rc = update_keysig_packet (&newsig, sig, main_pk, uid, NULL, main_pk, change_primary_uid_cb, action > 0 ? "x" : NULL); if (rc) { log_error ("update_keysig_packet failed: %s\n", gpg_strerror (rc)); return 0; } /* replace the packet */ newpkt = xmalloc_clear (sizeof *newpkt); newpkt->pkttype = PKT_SIGNATURE; newpkt->pkt.signature = newsig; free_packet (node->pkt); xfree (node->pkt); node->pkt = newpkt; modified = 1; } } } } } return modified; } /* * Set preferences to new values for the selected user IDs */ static int menu_set_preferences (KBNODE pub_keyblock) { PKT_public_key *main_pk; PKT_user_id *uid; KBNODE node; u32 keyid[2]; int selected, select_all; int modified = 0; no_primary_warning (pub_keyblock); select_all = !count_selected_uids (pub_keyblock); /* Now we can actually change the self signature(s) */ main_pk = NULL; uid = NULL; selected = 0; for (node = pub_keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) break; /* No more user-ids expected - ready. */ if (node->pkt->pkttype == PKT_PUBLIC_KEY) { main_pk = node->pkt->pkt.public_key; keyid_from_pk (main_pk, keyid); } else if (node->pkt->pkttype == PKT_USER_ID) { uid = node->pkt->pkt.user_id; selected = select_all || (node->flag & NODFLG_SELUID); } else if (main_pk && uid && selected && node->pkt->pkttype == PKT_SIGNATURE) { PKT_signature *sig = node->pkt->pkt.signature; if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] && (uid && (sig->sig_class & ~3) == 0x10) && sig->flags.chosen_selfsig) { if (sig->version < 4) { char *user = utf8_to_native (uid->name, strlen (uid->name), 0); log_info (_("skipping v3 self-signature on user ID \"%s\"\n"), user); xfree (user); } else { /* This is a selfsignature which is to be replaced * We have to ignore v3 signatures because they are * not able to carry the preferences. */ PKT_signature *newsig; PACKET *newpkt; int rc; rc = update_keysig_packet (&newsig, sig, main_pk, uid, NULL, main_pk, keygen_upd_std_prefs, NULL); if (rc) { log_error ("update_keysig_packet failed: %s\n", gpg_strerror (rc)); return 0; } /* replace the packet */ newpkt = xmalloc_clear (sizeof *newpkt); newpkt->pkttype = PKT_SIGNATURE; newpkt->pkt.signature = newsig; free_packet (node->pkt); xfree (node->pkt); node->pkt = newpkt; modified = 1; } } } } return modified; } static int menu_set_keyserver_url (const char *url, KBNODE pub_keyblock) { PKT_public_key *main_pk; PKT_user_id *uid; KBNODE node; u32 keyid[2]; int selected, select_all; int modified = 0; char *answer, *uri; no_primary_warning (pub_keyblock); if (url) answer = xstrdup (url); else { answer = cpr_get_utf8 ("keyedit.add_keyserver", _("Enter your preferred keyserver URL: ")); if (answer[0] == '\0' || answer[0] == CONTROL_D) { xfree (answer); return 0; } } if (ascii_strcasecmp (answer, "none") == 0) uri = NULL; else { struct keyserver_spec *keyserver = NULL; /* Sanity check the format */ keyserver = parse_keyserver_uri (answer, 1); xfree (answer); if (!keyserver) { log_info (_("could not parse keyserver URL\n")); return 0; } uri = xstrdup (keyserver->uri); free_keyserver_spec (keyserver); } select_all = !count_selected_uids (pub_keyblock); /* Now we can actually change the self signature(s) */ main_pk = NULL; uid = NULL; selected = 0; for (node = pub_keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) break; /* ready */ if (node->pkt->pkttype == PKT_PUBLIC_KEY) { main_pk = node->pkt->pkt.public_key; keyid_from_pk (main_pk, keyid); } else if (node->pkt->pkttype == PKT_USER_ID) { uid = node->pkt->pkt.user_id; selected = select_all || (node->flag & NODFLG_SELUID); } else if (main_pk && uid && selected && node->pkt->pkttype == PKT_SIGNATURE) { PKT_signature *sig = node->pkt->pkt.signature; if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] && (uid && (sig->sig_class & ~3) == 0x10) && sig->flags.chosen_selfsig) { char *user = utf8_to_native (uid->name, strlen (uid->name), 0); if (sig->version < 4) log_info (_("skipping v3 self-signature on user ID \"%s\"\n"), user); else { /* This is a selfsignature which is to be replaced * We have to ignore v3 signatures because they are * not able to carry the subpacket. */ PKT_signature *newsig; PACKET *newpkt; int rc; const byte *p; size_t plen; p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_KS, &plen); if (p && plen) { tty_printf ("Current preferred keyserver for user" " ID \"%s\": ", user); tty_print_utf8_string (p, plen); tty_printf ("\n"); if (!cpr_get_answer_is_yes ("keyedit.confirm_keyserver", uri ? _("Are you sure you want to replace it? (y/N) ") : _("Are you sure you want to delete it? (y/N) "))) continue; } else if (uri == NULL) { /* There is no current keyserver URL, so there is no point in trying to un-set it. */ continue; } rc = update_keysig_packet (&newsig, sig, main_pk, uid, NULL, main_pk, keygen_add_keyserver_url, uri); if (rc) { log_error ("update_keysig_packet failed: %s\n", gpg_strerror (rc)); xfree (uri); return 0; } /* replace the packet */ newpkt = xmalloc_clear (sizeof *newpkt); newpkt->pkttype = PKT_SIGNATURE; newpkt->pkt.signature = newsig; free_packet (node->pkt); xfree (node->pkt); node->pkt = newpkt; modified = 1; } xfree (user); } } } xfree (uri); return modified; } static int menu_set_notation (const char *string, KBNODE pub_keyblock) { PKT_public_key *main_pk; PKT_user_id *uid; KBNODE node; u32 keyid[2]; int selected, select_all; int modified = 0; char *answer; struct notation *notation; no_primary_warning (pub_keyblock); if (string) answer = xstrdup (string); else { answer = cpr_get_utf8 ("keyedit.add_notation", _("Enter the notation: ")); if (answer[0] == '\0' || answer[0] == CONTROL_D) { xfree (answer); return 0; } } if (!ascii_strcasecmp (answer, "none") || !ascii_strcasecmp (answer, "-")) notation = NULL; /* Delete them all. */ else { notation = string_to_notation (answer, 0); if (!notation) { xfree (answer); return 0; } } xfree (answer); select_all = !count_selected_uids (pub_keyblock); /* Now we can actually change the self signature(s) */ main_pk = NULL; uid = NULL; selected = 0; for (node = pub_keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) break; /* ready */ if (node->pkt->pkttype == PKT_PUBLIC_KEY) { main_pk = node->pkt->pkt.public_key; keyid_from_pk (main_pk, keyid); } else if (node->pkt->pkttype == PKT_USER_ID) { uid = node->pkt->pkt.user_id; selected = select_all || (node->flag & NODFLG_SELUID); } else if (main_pk && uid && selected && node->pkt->pkttype == PKT_SIGNATURE) { PKT_signature *sig = node->pkt->pkt.signature; if (keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] && (uid && (sig->sig_class & ~3) == 0x10) && sig->flags.chosen_selfsig) { char *user = utf8_to_native (uid->name, strlen (uid->name), 0); if (sig->version < 4) log_info (_("skipping v3 self-signature on user ID \"%s\"\n"), user); else { PKT_signature *newsig; PACKET *newpkt; int rc, skip = 0, addonly = 1; if (sig->flags.notation) { tty_printf ("Current notations for user ID \"%s\":\n", user); tty_print_notations (-9, sig); } else { tty_printf ("No notations on user ID \"%s\"\n", user); if (notation == NULL) { /* There are no current notations, so there is no point in trying to un-set them. */ continue; } } if (notation) { struct notation *n; int deleting = 0; notation->next = sig_to_notation (sig); for (n = notation->next; n; n = n->next) if (strcmp (n->name, notation->name) == 0) { if (notation->value) { if (strcmp (n->value, notation->value) == 0) { if (notation->flags.ignore) { /* Value match with a delete flag. */ n->flags.ignore = 1; deleting = 1; } else { /* Adding the same notation twice, so don't add it at all. */ skip = 1; tty_printf ("Skipping notation:" " %s=%s\n", notation->name, notation->value); break; } } } else { /* No value, so it means delete. */ n->flags.ignore = 1; deleting = 1; } if (n->flags.ignore) { tty_printf ("Removing notation: %s=%s\n", n->name, n->value); addonly = 0; } } if (!notation->flags.ignore && !skip) tty_printf ("Adding notation: %s=%s\n", notation->name, notation->value); /* We tried to delete, but had no matches. */ if (notation->flags.ignore && !deleting) continue; } else { tty_printf ("Removing all notations\n"); addonly = 0; } if (skip || (!addonly && !cpr_get_answer_is_yes ("keyedit.confirm_notation", _("Proceed? (y/N) ")))) continue; rc = update_keysig_packet (&newsig, sig, main_pk, uid, NULL, main_pk, keygen_add_notations, notation); if (rc) { log_error ("update_keysig_packet failed: %s\n", gpg_strerror (rc)); free_notation (notation); xfree (user); return 0; } /* replace the packet */ newpkt = xmalloc_clear (sizeof *newpkt); newpkt->pkttype = PKT_SIGNATURE; newpkt->pkt.signature = newsig; free_packet (node->pkt); xfree (node->pkt); node->pkt = newpkt; modified = 1; if (notation) { /* Snip off the notation list from the sig */ free_notation (notation->next); notation->next = NULL; } xfree (user); } } } } free_notation (notation); return modified; } /* * Select one user id or remove all selection if IDX is 0 or select * all if IDX is -1. Returns: True if the selection changed. */ static int menu_select_uid (KBNODE keyblock, int idx) { KBNODE node; int i; if (idx == -1) /* Select all. */ { for (node = keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_USER_ID) node->flag |= NODFLG_SELUID; return 1; } else if (idx) /* Toggle. */ { for (i = 0, node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID) if (++i == idx) break; } if (!node) { tty_printf (_("No user ID with index %d\n"), idx); return 0; } for (i = 0, node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID) { if (++i == idx) { if ((node->flag & NODFLG_SELUID)) node->flag &= ~NODFLG_SELUID; else node->flag |= NODFLG_SELUID; } } } } else /* Unselect all */ { for (node = keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_USER_ID) node->flag &= ~NODFLG_SELUID; } return 1; } /* Search in the keyblock for a uid that matches namehash */ static int menu_select_uid_namehash (KBNODE keyblock, const char *namehash) { byte hash[NAMEHASH_LEN]; KBNODE node; int i; assert (strlen (namehash) == NAMEHASH_LEN * 2); for (i = 0; i < NAMEHASH_LEN; i++) hash[i] = hextobyte (&namehash[i * 2]); for (node = keyblock->next; node; node = node->next) { if (node->pkt->pkttype == PKT_USER_ID) { namehash_from_uid (node->pkt->pkt.user_id); if (memcmp (node->pkt->pkt.user_id->namehash, hash, NAMEHASH_LEN) == 0) { if (node->flag & NODFLG_SELUID) node->flag &= ~NODFLG_SELUID; else node->flag |= NODFLG_SELUID; break; } } } if (!node) { tty_printf (_("No user ID with hash %s\n"), namehash); return 0; } return 1; } /* * Select secondary keys * Returns: True if the selection changed. */ static int menu_select_key (KBNODE keyblock, int idx) { KBNODE node; int i; if (idx == -1) /* Select all. */ { for (node = keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY) node->flag |= NODFLG_SELKEY; } else if (idx) /* Toggle selection. */ { for (i = 0, node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY) if (++i == idx) break; } if (!node) { tty_printf (_("No subkey with index %d\n"), idx); return 0; } for (i = 0, node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY) if (++i == idx) { if ((node->flag & NODFLG_SELKEY)) node->flag &= ~NODFLG_SELKEY; else node->flag |= NODFLG_SELKEY; } } } else /* Unselect all. */ { for (node = keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY) node->flag &= ~NODFLG_SELKEY; } return 1; } static int count_uids_with_flag (KBNODE keyblock, unsigned flag) { KBNODE node; int i = 0; for (node = keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_USER_ID && (node->flag & flag)) i++; return i; } static int count_keys_with_flag (KBNODE keyblock, unsigned flag) { KBNODE node; int i = 0; for (node = keyblock; node; node = node->next) if ((node->pkt->pkttype == PKT_PUBLIC_SUBKEY || node->pkt->pkttype == PKT_SECRET_SUBKEY) && (node->flag & flag)) i++; return i; } static int count_uids (KBNODE keyblock) { KBNODE node; int i = 0; for (node = keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_USER_ID) i++; return i; } /* * Returns true if there is at least one selected user id */ static int count_selected_uids (KBNODE keyblock) { return count_uids_with_flag (keyblock, NODFLG_SELUID); } static int count_selected_keys (KBNODE keyblock) { return count_keys_with_flag (keyblock, NODFLG_SELKEY); } /* Returns how many real (i.e. not attribute) uids are unmarked. */ static int real_uids_left (KBNODE keyblock) { KBNODE node; int real = 0; for (node = keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_USER_ID && !(node->flag & NODFLG_SELUID) && !node->pkt->pkt.user_id->attrib_data) real++; return real; } /* * Ask whether the signature should be revoked. If the user commits this, * flag bit MARK_A is set on the signature and the user ID. */ static void ask_revoke_sig (KBNODE keyblock, KBNODE node) { int doit = 0; PKT_user_id *uid; PKT_signature *sig = node->pkt->pkt.signature; KBNODE unode = find_prev_kbnode (keyblock, node, PKT_USER_ID); if (!unode) { log_error ("Oops: no user ID for signature\n"); return; } uid = unode->pkt->pkt.user_id; if (opt.with_colons) { if (uid->attrib_data) printf ("uat:::::::::%u %lu", uid->numattribs, uid->attrib_len); else { es_printf ("uid:::::::::"); es_write_sanitized (es_stdout, uid->name, uid->len, ":", NULL); } es_printf ("\n"); print_and_check_one_sig_colon (keyblock, node, NULL, NULL, NULL, NULL, 1); } else { char *p = utf8_to_native (unode->pkt->pkt.user_id->name, unode->pkt->pkt.user_id->len, 0); tty_printf (_("user ID: \"%s\"\n"), p); xfree (p); tty_printf (_("signed by your key %s on %s%s%s\n"), keystr (sig->keyid), datestr_from_sig (sig), sig->flags.exportable ? "" : _(" (non-exportable)"), ""); } if (sig->flags.expired) { tty_printf (_("This signature expired on %s.\n"), expirestr_from_sig (sig)); /* Use a different question so we can have different help text */ doit = cpr_get_answer_is_yes ("ask_revoke_sig.expired", _("Are you sure you still want to revoke it? (y/N) ")); } else doit = cpr_get_answer_is_yes ("ask_revoke_sig.one", _("Create a revocation certificate for this signature? (y/N) ")); if (doit) { node->flag |= NODFLG_MARK_A; unode->flag |= NODFLG_MARK_A; } } /* * Display all user ids of the current public key together with signatures * done by one of our keys. Then walk over all this sigs and ask the user * whether he wants to revoke this signature. * Return: True when the keyblock has changed. */ static int menu_revsig (KBNODE keyblock) { PKT_signature *sig; PKT_public_key *primary_pk; KBNODE node; int changed = 0; int rc, any, skip = 1, all = !count_selected_uids (keyblock); struct revocation_reason_info *reason = NULL; assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY); /* First check whether we have any signatures at all. */ any = 0; for (node = keyblock; node; node = node->next) { node->flag &= ~(NODFLG_SELSIG | NODFLG_MARK_A); if (node->pkt->pkttype == PKT_USER_ID) { if (node->flag & NODFLG_SELUID || all) skip = 0; else skip = 1; } else if (!skip && node->pkt->pkttype == PKT_SIGNATURE && ((sig = node->pkt->pkt.signature), have_secret_key_with_kid (sig->keyid))) { if ((sig->sig_class & ~3) == 0x10) { any = 1; break; } } } if (!any) { tty_printf (_("Not signed by you.\n")); return 0; } /* FIXME: detect duplicates here */ tty_printf (_("You have signed these user IDs on key %s:\n"), keystr_from_pk (keyblock->pkt->pkt.public_key)); for (node = keyblock; node; node = node->next) { node->flag &= ~(NODFLG_SELSIG | NODFLG_MARK_A); if (node->pkt->pkttype == PKT_USER_ID) { if (node->flag & NODFLG_SELUID || all) { PKT_user_id *uid = node->pkt->pkt.user_id; /* Hmmm: Should we show only UIDs with a signature? */ tty_printf (" "); tty_print_utf8_string (uid->name, uid->len); tty_printf ("\n"); skip = 0; } else skip = 1; } else if (!skip && node->pkt->pkttype == PKT_SIGNATURE && ((sig = node->pkt->pkt.signature), have_secret_key_with_kid (sig->keyid))) { if ((sig->sig_class & ~3) == 0x10) { tty_printf (" "); tty_printf (_("signed by your key %s on %s%s%s\n"), keystr (sig->keyid), datestr_from_sig (sig), sig->flags.exportable ? "" : _(" (non-exportable)"), sig->flags.revocable ? "" : _(" (non-revocable)")); if (sig->flags.revocable) node->flag |= NODFLG_SELSIG; } else if (sig->sig_class == 0x30) { tty_printf (" "); tty_printf (_("revoked by your key %s on %s\n"), keystr (sig->keyid), datestr_from_sig (sig)); } } } tty_printf ("\n"); /* ask */ for (node = keyblock; node; node = node->next) { if (!(node->flag & NODFLG_SELSIG)) continue; ask_revoke_sig (keyblock, node); } /* present selected */ any = 0; for (node = keyblock; node; node = node->next) { if (!(node->flag & NODFLG_MARK_A)) continue; if (!any) { any = 1; tty_printf (_("You are about to revoke these signatures:\n")); } if (node->pkt->pkttype == PKT_USER_ID) { PKT_user_id *uid = node->pkt->pkt.user_id; tty_printf (" "); tty_print_utf8_string (uid->name, uid->len); tty_printf ("\n"); } else if (node->pkt->pkttype == PKT_SIGNATURE) { sig = node->pkt->pkt.signature; tty_printf (" "); tty_printf (_("signed by your key %s on %s%s%s\n"), keystr (sig->keyid), datestr_from_sig (sig), "", sig->flags.exportable ? "" : _(" (non-exportable)")); } } if (!any) return 0; /* none selected */ if (!cpr_get_answer_is_yes ("ask_revoke_sig.okay", _("Really create the revocation certificates? (y/N) "))) return 0; /* forget it */ reason = ask_revocation_reason (0, 1, 0); if (!reason) { /* user decided to cancel */ return 0; } /* now we can sign the user ids */ reloop: /* (must use this, because we are modifing the list) */ primary_pk = keyblock->pkt->pkt.public_key; for (node = keyblock; node; node = node->next) { KBNODE unode; PACKET *pkt; struct sign_attrib attrib; PKT_public_key *signerkey; if (!(node->flag & NODFLG_MARK_A) || node->pkt->pkttype != PKT_SIGNATURE) continue; unode = find_prev_kbnode (keyblock, node, PKT_USER_ID); assert (unode); /* we already checked this */ memset (&attrib, 0, sizeof attrib); attrib.reason = reason; attrib.non_exportable = !node->pkt->pkt.signature->flags.exportable; node->flag &= ~NODFLG_MARK_A; signerkey = xmalloc_secure_clear (sizeof *signerkey); if (get_seckey (signerkey, node->pkt->pkt.signature->keyid)) { log_info (_("no secret key\n")); free_public_key (signerkey); continue; } rc = make_keysig_packet (&sig, primary_pk, unode->pkt->pkt.user_id, NULL, signerkey, 0x30, 0, 0, 0, sign_mk_attrib, &attrib, NULL); free_public_key (signerkey); if (rc) { log_error (_("signing failed: %s\n"), gpg_strerror (rc)); release_revocation_reason_info (reason); return changed; } changed = 1; /* we changed the keyblock */ update_trust = 1; /* Are we revoking our own uid? */ if (primary_pk->keyid[0] == sig->keyid[0] && primary_pk->keyid[1] == sig->keyid[1]) unode->pkt->pkt.user_id->is_revoked = 1; pkt = xmalloc_clear (sizeof *pkt); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; insert_kbnode (unode, new_kbnode (pkt), 0); goto reloop; } release_revocation_reason_info (reason); return changed; } /* Revoke a user ID (i.e. revoke a user ID selfsig). Return true if keyblock changed. */ static int menu_revuid (KBNODE pub_keyblock) { PKT_public_key *pk = pub_keyblock->pkt->pkt.public_key; KBNODE node; int changed = 0; int rc; struct revocation_reason_info *reason = NULL; /* Note that this is correct as per the RFCs, but nevertheless somewhat meaningless in the real world. 1991 did define the 0x30 sig class, but PGP 2.x did not actually implement it, so it would probably be safe to use v4 revocations everywhere. -ds */ for (node = pub_keyblock; node; node = node->next) if (pk->version > 3 || (node->pkt->pkttype == PKT_USER_ID && node->pkt->pkt.user_id->selfsigversion > 3)) { if ((reason = ask_revocation_reason (0, 1, 4))) break; else goto leave; } reloop: /* (better this way because we are modifing the keyring) */ for (node = pub_keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_USER_ID && (node->flag & NODFLG_SELUID)) { PKT_user_id *uid = node->pkt->pkt.user_id; if (uid->is_revoked) { char *user = utf8_to_native (uid->name, uid->len, 0); log_info (_("user ID \"%s\" is already revoked\n"), user); xfree (user); } else { PACKET *pkt; PKT_signature *sig; struct sign_attrib attrib; u32 timestamp = make_timestamp (); if (uid->created >= timestamp) { /* Okay, this is a problem. The user ID selfsig was created in the future, so we need to warn the user and set our revocation timestamp one second after that so everything comes out clean. */ log_info (_("WARNING: a user ID signature is dated %d" " seconds in the future\n"), uid->created - timestamp); timestamp = uid->created + 1; } memset (&attrib, 0, sizeof attrib); attrib.reason = reason; node->flag &= ~NODFLG_SELUID; rc = make_keysig_packet (&sig, pk, uid, NULL, pk, 0x30, 0, timestamp, 0, sign_mk_attrib, &attrib, NULL); if (rc) { log_error (_("signing failed: %s\n"), gpg_strerror (rc)); goto leave; } else { pkt = xmalloc_clear (sizeof *pkt); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; insert_kbnode (node, new_kbnode (pkt), 0); #ifndef NO_TRUST_MODELS /* If the trustdb has an entry for this key+uid then the trustdb needs an update. */ if (!update_trust && (get_validity (pk, uid) & TRUST_MASK) >= TRUST_UNDEFINED) update_trust = 1; #endif /*!NO_TRUST_MODELS*/ changed = 1; node->pkt->pkt.user_id->is_revoked = 1; goto reloop; } } } if (changed) commit_kbnode (&pub_keyblock); leave: release_revocation_reason_info (reason); return changed; } /* * Revoke the whole key. */ static int menu_revkey (KBNODE pub_keyblock) { PKT_public_key *pk = pub_keyblock->pkt->pkt.public_key; int rc, changed = 0; struct revocation_reason_info *reason; PACKET *pkt; PKT_signature *sig; if (pk->flags.revoked) { tty_printf (_("Key %s is already revoked.\n"), keystr_from_pk (pk)); return 0; } reason = ask_revocation_reason (1, 0, 0); /* user decided to cancel */ if (!reason) return 0; rc = make_keysig_packet (&sig, pk, NULL, NULL, pk, 0x20, 0, 0, 0, revocation_reason_build_cb, reason, NULL); if (rc) { log_error (_("signing failed: %s\n"), gpg_strerror (rc)); goto scram; } changed = 1; /* we changed the keyblock */ pkt = xmalloc_clear (sizeof *pkt); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; insert_kbnode (pub_keyblock, new_kbnode (pkt), 0); commit_kbnode (&pub_keyblock); update_trust = 1; scram: release_revocation_reason_info (reason); return changed; } static int menu_revsubkey (KBNODE pub_keyblock) { PKT_public_key *mainpk; KBNODE node; int changed = 0; int rc; struct revocation_reason_info *reason = NULL; reason = ask_revocation_reason (1, 0, 0); if (!reason) return 0; /* User decided to cancel. */ reloop: /* (better this way because we are modifing the keyring) */ mainpk = pub_keyblock->pkt->pkt.public_key; for (node = pub_keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY && (node->flag & NODFLG_SELKEY)) { PACKET *pkt; PKT_signature *sig; PKT_public_key *subpk = node->pkt->pkt.public_key; struct sign_attrib attrib; if (subpk->flags.revoked) { tty_printf (_("Subkey %s is already revoked.\n"), keystr_from_pk (subpk)); continue; } memset (&attrib, 0, sizeof attrib); attrib.reason = reason; node->flag &= ~NODFLG_SELKEY; rc = make_keysig_packet (&sig, mainpk, NULL, subpk, mainpk, 0x28, 0, 0, 0, sign_mk_attrib, &attrib, NULL); if (rc) { log_error (_("signing failed: %s\n"), gpg_strerror (rc)); release_revocation_reason_info (reason); return changed; } changed = 1; /* we changed the keyblock */ pkt = xmalloc_clear (sizeof *pkt); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; insert_kbnode (node, new_kbnode (pkt), 0); goto reloop; } } commit_kbnode (&pub_keyblock); /* No need to set update_trust here since signing keys no longer are used to certify other keys, so there is no change in trust when revoking/removing them */ release_revocation_reason_info (reason); return changed; } /* Note that update_ownertrust is going to mark the trustdb dirty when enabling or disabling a key. This is arguably sub-optimal as disabled keys are still counted in the web of trust, but perhaps not worth adding extra complexity to change. -ds */ #ifndef NO_TRUST_MODELS static int enable_disable_key (KBNODE keyblock, int disable) { PKT_public_key *pk = find_kbnode (keyblock, PKT_PUBLIC_KEY)->pkt->pkt.public_key; unsigned int trust, newtrust; trust = newtrust = get_ownertrust (pk); newtrust &= ~TRUST_FLAG_DISABLED; if (disable) newtrust |= TRUST_FLAG_DISABLED; if (trust == newtrust) return 0; /* already in that state */ update_ownertrust (pk, newtrust); return 0; } #endif /*!NO_TRUST_MODELS*/ static void menu_showphoto (KBNODE keyblock) { KBNODE node; int select_all = !count_selected_uids (keyblock); int count = 0; PKT_public_key *pk = NULL; /* Look for the public key first. We have to be really, really, explicit as to which photo this is, and what key it is a UID on since people may want to sign it. */ for (node = keyblock; node; node = node->next) { if (node->pkt->pkttype == PKT_PUBLIC_KEY) pk = node->pkt->pkt.public_key; else if (node->pkt->pkttype == PKT_USER_ID) { PKT_user_id *uid = node->pkt->pkt.user_id; count++; if ((select_all || (node->flag & NODFLG_SELUID)) && uid->attribs != NULL) { int i; for (i = 0; i < uid->numattribs; i++) { byte type; u32 size; if (uid->attribs[i].type == ATTRIB_IMAGE && parse_image_header (&uid->attribs[i], &type, &size)) { tty_printf (_("Displaying %s photo ID of size %ld for " "key %s (uid %d)\n"), image_type_to_string (type, 1), (ulong) size, keystr_from_pk (pk), count); show_photos (&uid->attribs[i], 1, pk, uid); } } } } } } diff --git a/g10/keygen.c b/g10/keygen.c index ccd01f927..fa5907d6a 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -1,4782 +1,4810 @@ /* keygen.c - generate a key pair * Copyright (C) 1998-2007, 2009-2011 Free Software Foundation, Inc. * Copyright (C) 2014, 2015 Werner Koch * * 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 #include #include #include #include #include "gpg.h" #include "util.h" #include "main.h" #include "packet.h" #include "ttyio.h" #include "options.h" #include "keydb.h" #include "trustdb.h" #include "status.h" #include "i18n.h" #include "keyserver-internal.h" #include "call-agent.h" #include "pkglue.h" #include "../common/shareddefs.h" #include "host2net.h" #include "mbox-util.h" /* The default algorithms. If you change them remember to change them also in gpg.c:gpgconf_list. You should also check that the value is inside the bounds enforced by ask_keysize and gen_xxx. */ #define DEFAULT_STD_ALGO PUBKEY_ALGO_RSA #define DEFAULT_STD_KEYSIZE 2048 #define DEFAULT_STD_CURVE NULL #define DEFAULT_STD_SUBALGO PUBKEY_ALGO_RSA #define DEFAULT_STD_SUBKEYSIZE 2048 #define DEFAULT_STD_SUBCURVE NULL /* Flag bits used during key generation. */ #define KEYGEN_FLAG_NO_PROTECTION 1 #define KEYGEN_FLAG_TRANSIENT_KEY 2 /* Maximum number of supported algorithm preferences. */ #define MAX_PREFS 30 enum para_name { pKEYTYPE, pKEYLENGTH, pKEYCURVE, pKEYUSAGE, pSUBKEYTYPE, pSUBKEYLENGTH, pSUBKEYCURVE, pSUBKEYUSAGE, pAUTHKEYTYPE, pNAMEREAL, pNAMEEMAIL, pNAMECOMMENT, pPREFERENCES, pREVOKER, pUSERID, pCREATIONDATE, pKEYCREATIONDATE, /* Same in seconds since epoch. */ pEXPIREDATE, pKEYEXPIRE, /* in n seconds */ pSUBKEYEXPIRE, /* in n seconds */ pPASSPHRASE, pSERIALNO, pCARDBACKUPKEY, pHANDLE, pKEYSERVER }; struct para_data_s { struct para_data_s *next; int lnr; enum para_name key; union { u32 expire; u32 creation; unsigned int usage; struct revocation_key revkey; char value[1]; } u; }; struct output_control_s { int lnr; int dryrun; unsigned int keygen_flags; int use_files; struct { char *fname; char *newfname; IOBUF stream; armor_filter_context_t *afx; } pub; }; struct opaque_data_usage_and_pk { unsigned int usage; PKT_public_key *pk; }; static int prefs_initialized = 0; static byte sym_prefs[MAX_PREFS]; static int nsym_prefs; static byte hash_prefs[MAX_PREFS]; static int nhash_prefs; static byte zip_prefs[MAX_PREFS]; static int nzip_prefs; static int mdc_available,ks_modify; static void do_generate_keypair( struct para_data_s *para, struct output_control_s *outctrl, int card ); static int write_keyblock (iobuf_t out, kbnode_t node); static gpg_error_t gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root, u32 *timestamp, u32 expireval); static int gen_card_key_with_backup (int algo, int keyno, int is_primary, kbnode_t pub_root, u32 timestamp, u32 expireval, struct para_data_s *para); static void print_status_key_created (int letter, PKT_public_key *pk, const char *handle) { byte array[MAX_FINGERPRINT_LEN], *s; char *buf, *p; size_t i, n; if (!handle) handle = ""; buf = xmalloc (MAX_FINGERPRINT_LEN*2+31 + strlen (handle) + 1); p = buf; if (letter || pk) { *p++ = letter; *p++ = ' '; fingerprint_from_pk (pk, array, &n); s = array; for (i=0; i < n ; i++, s++, p += 2) sprintf (p, "%02X", *s); } if (*handle) { *p++ = ' '; for (i=0; handle[i] && i < 100; i++) *p++ = isspace ((unsigned int)handle[i])? '_':handle[i]; } *p = 0; write_status_text ((letter || pk)?STATUS_KEY_CREATED:STATUS_KEY_NOT_CREATED, buf); xfree (buf); } static void print_status_key_not_created (const char *handle) { print_status_key_created (0, NULL, handle); } static void write_uid( KBNODE root, const char *s ) { PACKET *pkt = xmalloc_clear(sizeof *pkt ); size_t n = strlen(s); pkt->pkttype = PKT_USER_ID; pkt->pkt.user_id = xmalloc_clear( sizeof *pkt->pkt.user_id + n - 1 ); pkt->pkt.user_id->len = n; pkt->pkt.user_id->ref = 1; strcpy(pkt->pkt.user_id->name, s); add_kbnode( root, new_kbnode( pkt ) ); } static void do_add_key_flags (PKT_signature *sig, unsigned int use) { byte buf[1]; buf[0] = 0; /* The spec says that all primary keys MUST be able to certify. */ if(sig->sig_class!=0x18) buf[0] |= 0x01; if (use & PUBKEY_USAGE_SIG) buf[0] |= 0x02; if (use & PUBKEY_USAGE_ENC) buf[0] |= 0x04 | 0x08; if (use & PUBKEY_USAGE_AUTH) buf[0] |= 0x20; build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, buf, 1); } int keygen_add_key_expire (PKT_signature *sig, void *opaque) { PKT_public_key *pk = opaque; byte buf[8]; u32 u; if (pk->expiredate) { if (pk->expiredate > pk->timestamp) u = pk->expiredate - pk->timestamp; else u = 1; buf[0] = (u >> 24) & 0xff; buf[1] = (u >> 16) & 0xff; buf[2] = (u >> 8) & 0xff; buf[3] = u & 0xff; build_sig_subpkt (sig, SIGSUBPKT_KEY_EXPIRE, buf, 4); } else { /* Make sure we don't leave a key expiration subpacket lying around */ delete_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE); } return 0; } static int keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque) { struct opaque_data_usage_and_pk *oduap = opaque; do_add_key_flags (sig, oduap->usage); return keygen_add_key_expire (sig, oduap->pk); } static int set_one_pref (int val, int type, const char *item, byte *buf, int *nbuf) { int i; for (i=0; i < *nbuf; i++ ) if (buf[i] == val) { log_info (_("preference '%s' duplicated\n"), item); return -1; } if (*nbuf >= MAX_PREFS) { if(type==1) log_info(_("too many cipher preferences\n")); else if(type==2) log_info(_("too many digest preferences\n")); else if(type==3) log_info(_("too many compression preferences\n")); else BUG(); return -1; } buf[(*nbuf)++] = val; return 0; } /* * Parse the supplied string and use it to set the standard * preferences. The string may be in a form like the one printed by * "pref" (something like: "S10 S3 H3 H2 Z2 Z1") or the actual * cipher/hash/compress names. Use NULL to set the default * preferences. Returns: 0 = okay */ int keygen_set_std_prefs (const char *string,int personal) { byte sym[MAX_PREFS], hash[MAX_PREFS], zip[MAX_PREFS]; int nsym=0, nhash=0, nzip=0, val, rc=0; int mdc=1, modify=0; /* mdc defaults on, modify defaults off. */ char dummy_string[20*4+1]; /* Enough for 20 items. */ if (!string || !ascii_strcasecmp (string, "default")) { if (opt.def_preference_list) string=opt.def_preference_list; else { int any_compress = 0; dummy_string[0]='\0'; /* The rationale why we use the order AES256,192,128 is for compatibility reasons with PGP. If gpg would define AES128 first, we would get the somewhat confusing situation: gpg -r pgpkey -r gpgkey ---gives--> AES256 gpg -r gpgkey -r pgpkey ---gives--> AES Note that by using --personal-cipher-preferences it is possible to prefer AES128. */ /* Make sure we do not add more than 15 items here, as we could overflow the size of dummy_string. We currently have at most 12. */ if ( !openpgp_cipher_test_algo (CIPHER_ALGO_AES256) ) strcat(dummy_string,"S9 "); if ( !openpgp_cipher_test_algo (CIPHER_ALGO_AES192) ) strcat(dummy_string,"S8 "); if ( !openpgp_cipher_test_algo (CIPHER_ALGO_AES) ) strcat(dummy_string,"S7 "); strcat(dummy_string,"S2 "); /* 3DES */ /* The default hash algo order is: SHA-256, SHA-384, SHA-512, SHA-224, SHA-1. */ if (!openpgp_md_test_algo (DIGEST_ALGO_SHA256)) strcat (dummy_string, "H8 "); if (!openpgp_md_test_algo (DIGEST_ALGO_SHA384)) strcat (dummy_string, "H9 "); if (!openpgp_md_test_algo (DIGEST_ALGO_SHA512)) strcat (dummy_string, "H10 "); if (!openpgp_md_test_algo (DIGEST_ALGO_SHA224)) strcat (dummy_string, "H11 "); strcat (dummy_string, "H2 "); /* SHA-1 */ if(!check_compress_algo(COMPRESS_ALGO_ZLIB)) { strcat(dummy_string,"Z2 "); any_compress = 1; } if(!check_compress_algo(COMPRESS_ALGO_BZIP2)) { strcat(dummy_string,"Z3 "); any_compress = 1; } if(!check_compress_algo(COMPRESS_ALGO_ZIP)) { strcat(dummy_string,"Z1 "); any_compress = 1; } /* In case we have no compress algo at all, declare that we prefer no compresssion. */ if (!any_compress) strcat(dummy_string,"Z0 "); /* Remove the trailing space. */ if (*dummy_string && dummy_string[strlen (dummy_string)-1] == ' ') dummy_string[strlen (dummy_string)-1] = 0; string=dummy_string; } } else if (!ascii_strcasecmp (string, "none")) string = ""; if(strlen(string)) { char *tok,*prefstring; prefstring=xstrdup(string); /* need a writable string! */ while((tok=strsep(&prefstring," ,"))) { if((val=string_to_cipher_algo (tok))) { if(set_one_pref(val,1,tok,sym,&nsym)) rc=-1; } else if((val=string_to_digest_algo (tok))) { if(set_one_pref(val,2,tok,hash,&nhash)) rc=-1; } else if((val=string_to_compress_algo(tok))>-1) { if(set_one_pref(val,3,tok,zip,&nzip)) rc=-1; } else if (ascii_strcasecmp(tok,"mdc")==0) mdc=1; else if (ascii_strcasecmp(tok,"no-mdc")==0) mdc=0; else if (ascii_strcasecmp(tok,"ks-modify")==0) modify=1; else if (ascii_strcasecmp(tok,"no-ks-modify")==0) modify=0; else { log_info (_("invalid item '%s' in preference string\n"),tok); rc=-1; } } xfree(prefstring); } if(!rc) { if(personal) { if(personal==PREFTYPE_SYM) { xfree(opt.personal_cipher_prefs); if(nsym==0) opt.personal_cipher_prefs=NULL; else { int i; opt.personal_cipher_prefs= xmalloc(sizeof(prefitem_t *)*(nsym+1)); for (i=0; iref=1; uid->prefs=xmalloc((sizeof(prefitem_t *)* (nsym_prefs+nhash_prefs+nzip_prefs+1))); for(i=0;iprefs[j].type=PREFTYPE_SYM; uid->prefs[j].value=sym_prefs[i]; } for(i=0;iprefs[j].type=PREFTYPE_HASH; uid->prefs[j].value=hash_prefs[i]; } for(i=0;iprefs[j].type=PREFTYPE_ZIP; uid->prefs[j].value=zip_prefs[i]; } uid->prefs[j].type=PREFTYPE_NONE; uid->prefs[j].value=0; uid->flags.mdc=mdc_available; uid->flags.ks_modify=ks_modify; return uid; } static void add_feature_mdc (PKT_signature *sig,int enabled) { const byte *s; size_t n; int i; char *buf; s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n ); /* Already set or cleared */ if (s && n && ((enabled && (s[0] & 0x01)) || (!enabled && !(s[0] & 0x01)))) return; if (!s || !n) { /* create a new one */ n = 1; buf = xmalloc_clear (n); } else { buf = xmalloc (n); memcpy (buf, s, n); } if(enabled) buf[0] |= 0x01; /* MDC feature */ else buf[0] &= ~0x01; /* Are there any bits set? */ for(i=0;ihashed, SIGSUBPKT_FEATURES); else build_sig_subpkt (sig, SIGSUBPKT_FEATURES, buf, n); xfree (buf); } static void add_keyserver_modify (PKT_signature *sig,int enabled) { const byte *s; size_t n; int i; char *buf; /* The keyserver modify flag is a negative flag (i.e. no-modify) */ enabled=!enabled; s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KS_FLAGS, &n ); /* Already set or cleared */ if (s && n && ((enabled && (s[0] & 0x80)) || (!enabled && !(s[0] & 0x80)))) return; if (!s || !n) { /* create a new one */ n = 1; buf = xmalloc_clear (n); } else { buf = xmalloc (n); memcpy (buf, s, n); } if(enabled) buf[0] |= 0x80; /* no-modify flag */ else buf[0] &= ~0x80; /* Are there any bits set? */ for(i=0;ihashed, SIGSUBPKT_KS_FLAGS); else build_sig_subpkt (sig, SIGSUBPKT_KS_FLAGS, buf, n); xfree (buf); } int keygen_upd_std_prefs (PKT_signature *sig, void *opaque) { (void)opaque; if (!prefs_initialized) keygen_set_std_prefs (NULL, 0); if (nsym_prefs) build_sig_subpkt (sig, SIGSUBPKT_PREF_SYM, sym_prefs, nsym_prefs); else { delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_SYM); delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_SYM); } if (nhash_prefs) build_sig_subpkt (sig, SIGSUBPKT_PREF_HASH, hash_prefs, nhash_prefs); else { delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_HASH); delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_HASH); } if (nzip_prefs) build_sig_subpkt (sig, SIGSUBPKT_PREF_COMPR, zip_prefs, nzip_prefs); else { delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_COMPR); delete_sig_subpkt (sig->unhashed, SIGSUBPKT_PREF_COMPR); } /* Make sure that the MDC feature flag is set if needed. */ add_feature_mdc (sig,mdc_available); add_keyserver_modify (sig,ks_modify); keygen_add_keyserver_url(sig,NULL); return 0; } /**************** * Add preference to the self signature packet. * This is only called for packets with version > 3. */ int keygen_add_std_prefs (PKT_signature *sig, void *opaque) { PKT_public_key *pk = opaque; do_add_key_flags (sig, pk->pubkey_usage); keygen_add_key_expire (sig, opaque ); keygen_upd_std_prefs (sig, opaque); keygen_add_keyserver_url (sig,NULL); return 0; } int keygen_add_keyserver_url(PKT_signature *sig, void *opaque) { const char *url=opaque; if(!url) url=opt.def_keyserver_url; if(url) build_sig_subpkt(sig,SIGSUBPKT_PREF_KS,url,strlen(url)); else delete_sig_subpkt (sig->hashed,SIGSUBPKT_PREF_KS); return 0; } int keygen_add_notations(PKT_signature *sig,void *opaque) { struct notation *notation; /* We always start clean */ delete_sig_subpkt(sig->hashed,SIGSUBPKT_NOTATION); delete_sig_subpkt(sig->unhashed,SIGSUBPKT_NOTATION); sig->flags.notation=0; for(notation=opaque;notation;notation=notation->next) if(!notation->flags.ignore) { unsigned char *buf; unsigned int n1,n2; n1=strlen(notation->name); if(notation->altvalue) n2=strlen(notation->altvalue); else if(notation->bdat) n2=notation->blen; else n2=strlen(notation->value); buf = xmalloc( 8 + n1 + n2 ); /* human readable or not */ buf[0] = notation->bdat?0:0x80; buf[1] = buf[2] = buf[3] = 0; buf[4] = n1 >> 8; buf[5] = n1; buf[6] = n2 >> 8; buf[7] = n2; memcpy(buf+8, notation->name, n1 ); if(notation->altvalue) memcpy(buf+8+n1, notation->altvalue, n2 ); else if(notation->bdat) memcpy(buf+8+n1, notation->bdat, n2 ); else memcpy(buf+8+n1, notation->value, n2 ); build_sig_subpkt( sig, SIGSUBPKT_NOTATION | (notation->flags.critical?SIGSUBPKT_FLAG_CRITICAL:0), buf, 8+n1+n2 ); xfree(buf); } return 0; } int keygen_add_revkey (PKT_signature *sig, void *opaque) { struct revocation_key *revkey = opaque; byte buf[2+MAX_FINGERPRINT_LEN]; buf[0] = revkey->class; buf[1] = revkey->algid; memcpy (&buf[2], revkey->fpr, MAX_FINGERPRINT_LEN); build_sig_subpkt (sig, SIGSUBPKT_REV_KEY, buf, 2+MAX_FINGERPRINT_LEN); /* All sigs with revocation keys set are nonrevocable. */ sig->flags.revocable = 0; buf[0] = 0; build_sig_subpkt (sig, SIGSUBPKT_REVOCABLE, buf, 1); parse_revkeys (sig); return 0; } /* Create a back-signature. If TIMESTAMP is not NULL, use it for the signature creation time. */ gpg_error_t make_backsig (PKT_signature *sig, PKT_public_key *pk, PKT_public_key *sub_pk, PKT_public_key *sub_psk, u32 timestamp, const char *cache_nonce) { gpg_error_t err; PKT_signature *backsig; cache_public_key (sub_pk); err = make_keysig_packet (&backsig, pk, NULL, sub_pk, sub_psk, 0x19, 0, timestamp, 0, NULL, NULL, cache_nonce); if (err) log_error ("make_keysig_packet failed for backsig: %s\n", gpg_strerror (err)); else { /* Get it into a binary packed form. */ IOBUF backsig_out = iobuf_temp(); PACKET backsig_pkt; init_packet (&backsig_pkt); backsig_pkt.pkttype = PKT_SIGNATURE; backsig_pkt.pkt.signature = backsig; err = build_packet (backsig_out, &backsig_pkt); free_packet (&backsig_pkt); if (err) log_error ("build_packet failed for backsig: %s\n", gpg_strerror (err)); else { size_t pktlen = 0; byte *buf = iobuf_get_temp_buffer (backsig_out); /* Remove the packet header. */ if(buf[0]&0x40) { if (buf[1] < 192) { pktlen = buf[1]; buf += 2; } else if(buf[1] < 224) { pktlen = (buf[1]-192)*256; pktlen += buf[2]+192; buf += 3; } else if (buf[1] == 255) { pktlen = buf32_to_size_t (buf+2); buf += 6; } else BUG (); } else { int mark = 1; switch (buf[0]&3) { case 3: BUG (); break; case 2: pktlen = (size_t)buf[mark++] << 24; pktlen |= buf[mark++] << 16; case 1: pktlen |= buf[mark++] << 8; case 0: pktlen |= buf[mark++]; } buf += mark; } /* Now make the binary blob into a subpacket. */ build_sig_subpkt (sig, SIGSUBPKT_SIGNATURE, buf, pktlen); iobuf_close (backsig_out); } } return err; } /* Write a direct key signature to the first key in ROOT using the key PSK. REVKEY is describes the direct key signature and TIMESTAMP is the timestamp to set on the signature. */ static gpg_error_t write_direct_sig (KBNODE root, PKT_public_key *psk, struct revocation_key *revkey, u32 timestamp, const char *cache_nonce) { gpg_error_t err; PACKET *pkt; PKT_signature *sig; KBNODE node; PKT_public_key *pk; if (opt.verbose) log_info (_("writing direct signature\n")); /* Get the pk packet from the pub_tree. */ node = find_kbnode (root, PKT_PUBLIC_KEY); if (!node) BUG (); pk = node->pkt->pkt.public_key; /* We have to cache the key, so that the verification of the signature creation is able to retrieve the public key. */ cache_public_key (pk); /* Make the signature. */ err = make_keysig_packet (&sig, pk, NULL,NULL, psk, 0x1F, 0, timestamp, 0, keygen_add_revkey, revkey, cache_nonce); if (err) { log_error ("make_keysig_packet failed: %s\n", gpg_strerror (err) ); return err; } pkt = xmalloc_clear (sizeof *pkt); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; add_kbnode (root, new_kbnode (pkt)); return err; } /* Write a self-signature to the first user id in ROOT using the key PSK. USE and TIMESTAMP give the extra data we need for the signature. */ static gpg_error_t write_selfsigs (KBNODE root, PKT_public_key *psk, unsigned int use, u32 timestamp, const char *cache_nonce) { gpg_error_t err; PACKET *pkt; PKT_signature *sig; PKT_user_id *uid; KBNODE node; PKT_public_key *pk; if (opt.verbose) log_info (_("writing self signature\n")); /* Get the uid packet from the list. */ node = find_kbnode (root, PKT_USER_ID); if (!node) BUG(); /* No user id packet in tree. */ uid = node->pkt->pkt.user_id; /* Get the pk packet from the pub_tree. */ node = find_kbnode (root, PKT_PUBLIC_KEY); if (!node) BUG(); pk = node->pkt->pkt.public_key; /* The usage has not yet been set - do it now. */ pk->pubkey_usage = use; /* We have to cache the key, so that the verification of the signature creation is able to retrieve the public key. */ cache_public_key (pk); /* Make the signature. */ err = make_keysig_packet (&sig, pk, uid, NULL, psk, 0x13, 0, timestamp, 0, keygen_add_std_prefs, pk, cache_nonce); if (err) { log_error ("make_keysig_packet failed: %s\n", gpg_strerror (err)); return err; } pkt = xmalloc_clear (sizeof *pkt); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; add_kbnode (root, new_kbnode (pkt)); return err; } /* Write the key binding signature. If TIMESTAMP is not NULL use the signature creation time. PRI_PSK is the key use for signing. SUB_PSK is a key used to create a back-signature; that one is only used if USE has the PUBKEY_USAGE_SIG capability. */ static int write_keybinding (KBNODE root, PKT_public_key *pri_psk, PKT_public_key *sub_psk, unsigned int use, u32 timestamp, const char *cache_nonce) { gpg_error_t err; PACKET *pkt; PKT_signature *sig; KBNODE node; PKT_public_key *pri_pk, *sub_pk; struct opaque_data_usage_and_pk oduap; if (opt.verbose) log_info(_("writing key binding signature\n")); /* Get the primary pk packet from the tree. */ node = find_kbnode (root, PKT_PUBLIC_KEY); if (!node) BUG(); pri_pk = node->pkt->pkt.public_key; /* We have to cache the key, so that the verification of the * signature creation is able to retrieve the public key. */ cache_public_key (pri_pk); /* Find the last subkey. */ sub_pk = NULL; for (node = root; node; node = node->next ) { if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) sub_pk = node->pkt->pkt.public_key; } if (!sub_pk) BUG(); /* Make the signature. */ oduap.usage = use; oduap.pk = sub_pk; err = make_keysig_packet (&sig, pri_pk, NULL, sub_pk, pri_psk, 0x18, 0, timestamp, 0, keygen_add_key_flags_and_expire, &oduap, cache_nonce); if (err) { log_error ("make_keysig_packeto failed: %s\n", gpg_strerror (err)); return err; } /* Make a backsig. */ if (use & PUBKEY_USAGE_SIG) { err = make_backsig (sig, pri_pk, sub_pk, sub_psk, timestamp, cache_nonce); if (err) return err; } pkt = xmalloc_clear ( sizeof *pkt ); pkt->pkttype = PKT_SIGNATURE; pkt->pkt.signature = sig; add_kbnode (root, new_kbnode (pkt) ); return err; } static gpg_error_t ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo) { gpg_error_t err; gcry_sexp_t list, l2; char *curve; int i; const char *oidstr; unsigned int nbits; array[0] = NULL; array[1] = NULL; array[2] = NULL; list = gcry_sexp_find_token (sexp, "public-key", 0); if (!list) return gpg_error (GPG_ERR_INV_OBJ); l2 = gcry_sexp_cadr (list); gcry_sexp_release (list); list = l2; if (!list) return gpg_error (GPG_ERR_NO_OBJ); l2 = gcry_sexp_find_token (list, "curve", 0); if (!l2) { err = gpg_error (GPG_ERR_NO_OBJ); goto leave; } curve = gcry_sexp_nth_string (l2, 1); if (!curve) { err = gpg_error (GPG_ERR_NO_OBJ); goto leave; } gcry_sexp_release (l2); oidstr = openpgp_curve_to_oid (curve, &nbits); if (!oidstr) { /* That can't happen because we used one of the curves gpg_curve_to_oid knows about. */ err = gpg_error (GPG_ERR_INV_OBJ); goto leave; } err = openpgp_oid_from_str (oidstr, &array[0]); if (err) goto leave; l2 = gcry_sexp_find_token (list, "q", 0); if (!l2) { err = gpg_error (GPG_ERR_NO_OBJ); goto leave; } array[1] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); gcry_sexp_release (l2); if (!array[1]) { err = gpg_error (GPG_ERR_INV_OBJ); goto leave; } gcry_sexp_release (list); if (algo == PUBKEY_ALGO_ECDH) { array[2] = pk_ecdh_default_params (nbits); if (!array[2]) { err = gpg_error_from_syserror (); goto leave; } } leave: if (err) { for (i=0; i < 3; i++) { gcry_mpi_release (array[i]); array[i] = NULL; } } return err; } /* Extract key parameters from SEXP and store them in ARRAY. ELEMS is a string where each character denotes a parameter name. TOPNAME is the name of the top element above the elements. */ static int key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, const char *topname, const char *elems) { gcry_sexp_t list, l2; const char *s; int i, idx; int rc = 0; list = gcry_sexp_find_token (sexp, topname, 0); if (!list) return gpg_error (GPG_ERR_INV_OBJ); l2 = gcry_sexp_cadr (list); gcry_sexp_release (list); list = l2; if (!list) return gpg_error (GPG_ERR_NO_OBJ); for (idx=0,s=elems; *s; s++, idx++) { l2 = gcry_sexp_find_token (list, s, 1); if (!l2) { rc = gpg_error (GPG_ERR_NO_OBJ); /* required parameter not found */ goto leave; } array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG); gcry_sexp_release (l2); if (!array[idx]) { rc = gpg_error (GPG_ERR_INV_OBJ); /* required parameter invalid */ goto leave; } } gcry_sexp_release (list); leave: if (rc) { for (i=0; itimestamp = timestamp; pk->version = 4; if (expireval) pk->expiredate = pk->timestamp + expireval; pk->pubkey_algo = algo; if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH ) err = ecckey_from_sexp (pk->pkey, s_key, algo); else err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem); if (err) { log_error ("key_from_sexp failed: %s\n", gpg_strerror (err) ); gcry_sexp_release (s_key); free_public_key (pk); return err; } gcry_sexp_release (s_key); pkt = xtrycalloc (1, sizeof *pkt); if (!pkt) { err = gpg_error_from_syserror (); free_public_key (pk); return err; } pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY; pkt->pkt.public_key = pk; add_kbnode (pub_root, new_kbnode (pkt)); return 0; } /* Common code for the key generation fucntion gen_xxx. */ static int common_gen (const char *keyparms, int algo, const char *algoelem, kbnode_t pub_root, u32 timestamp, u32 expireval, int is_subkey, int keygen_flags, const char *passphrase, char **cache_nonce_addr) { int err; PACKET *pkt; PKT_public_key *pk; gcry_sexp_t s_key; err = agent_genkey (NULL, cache_nonce_addr, keyparms, !!(keygen_flags & KEYGEN_FLAG_NO_PROTECTION), passphrase, &s_key); if (err) { log_error ("agent_genkey failed: %s\n", gpg_strerror (err) ); return err; } pk = xtrycalloc (1, sizeof *pk); if (!pk) { err = gpg_error_from_syserror (); gcry_sexp_release (s_key); return err; } pk->timestamp = timestamp; pk->version = 4; if (expireval) pk->expiredate = pk->timestamp + expireval; pk->pubkey_algo = algo; if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH ) err = ecckey_from_sexp (pk->pkey, s_key, algo); else err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem); if (err) { log_error ("key_from_sexp failed: %s\n", gpg_strerror (err) ); gcry_sexp_release (s_key); free_public_key (pk); return err; } gcry_sexp_release (s_key); pkt = xtrycalloc (1, sizeof *pkt); if (!pkt) { err = gpg_error_from_syserror (); free_public_key (pk); return err; } pkt->pkttype = is_subkey ? PKT_PUBLIC_SUBKEY : PKT_PUBLIC_KEY; pkt->pkt.public_key = pk; add_kbnode (pub_root, new_kbnode (pkt)); return 0; } /* * Generate an Elgamal key. */ static int gen_elg (int algo, unsigned int nbits, KBNODE pub_root, u32 timestamp, u32 expireval, int is_subkey, int keygen_flags, const char *passphrase, char **cache_nonce_addr) { int err; char *keyparms; char nbitsstr[35]; assert (is_ELGAMAL (algo)); if (nbits < 1024) { nbits = 2048; log_info (_("keysize invalid; using %u bits\n"), nbits ); } else if (nbits > 4096) { nbits = 4096; log_info (_("keysize invalid; using %u bits\n"), nbits ); } if ((nbits % 32)) { nbits = ((nbits + 31) / 32) * 32; log_info (_("keysize rounded up to %u bits\n"), nbits ); } /* Note that we use transient-key only if no-protection has also been enabled. */ snprintf (nbitsstr, sizeof nbitsstr, "%u", nbits); keyparms = xtryasprintf ("(genkey(%s(nbits %zu:%s)%s))", algo == GCRY_PK_ELG_E ? "openpgp-elg" : algo == GCRY_PK_ELG ? "elg" : "x-oops" , strlen (nbitsstr), nbitsstr, ((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? "(transient-key)" : "" ); if (!keyparms) err = gpg_error_from_syserror (); else { err = common_gen (keyparms, algo, "pgy", pub_root, timestamp, expireval, is_subkey, keygen_flags, passphrase, cache_nonce_addr); xfree (keyparms); } return err; } /* * Generate an DSA key */ static gpg_error_t gen_dsa (unsigned int nbits, KBNODE pub_root, u32 timestamp, u32 expireval, int is_subkey, int keygen_flags, const char *passphrase, char **cache_nonce_addr) { int err; unsigned int qbits; char *keyparms; char nbitsstr[35]; char qbitsstr[35]; if (nbits < 768) { nbits = 2048; log_info(_("keysize invalid; using %u bits\n"), nbits ); } else if ( nbits > 3072 ) { nbits = 3072; log_info(_("keysize invalid; using %u bits\n"), nbits ); } if( (nbits % 64) ) { nbits = ((nbits + 63) / 64) * 64; log_info(_("keysize rounded up to %u bits\n"), nbits ); } /* To comply with FIPS rules we round up to the next value unless in expert mode. */ if (!opt.expert && nbits > 1024 && (nbits % 1024)) { nbits = ((nbits + 1023) / 1024) * 1024; log_info(_("keysize rounded up to %u bits\n"), nbits ); } /* Figure out a q size based on the key size. FIPS 180-3 says: L = 1024, N = 160 L = 2048, N = 224 L = 2048, N = 256 L = 3072, N = 256 2048/256 is an odd pair since there is also a 2048/224 and 3072/256. Matching sizes is not a very exact science. We'll do 256 qbits for nbits over 2047, 224 for nbits over 1024 but less than 2048, and 160 for 1024 (DSA1). */ if (nbits > 2047) qbits = 256; else if ( nbits > 1024) qbits = 224; else qbits = 160; if (qbits != 160 ) log_info (_("WARNING: some OpenPGP programs can't" " handle a DSA key with this digest size\n")); snprintf (nbitsstr, sizeof nbitsstr, "%u", nbits); snprintf (qbitsstr, sizeof qbitsstr, "%u", qbits); keyparms = xtryasprintf ("(genkey(dsa(nbits %zu:%s)(qbits %zu:%s)%s))", strlen (nbitsstr), nbitsstr, strlen (qbitsstr), qbitsstr, ((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? "(transient-key)" : "" ); if (!keyparms) err = gpg_error_from_syserror (); else { err = common_gen (keyparms, PUBKEY_ALGO_DSA, "pqgy", pub_root, timestamp, expireval, is_subkey, keygen_flags, passphrase, cache_nonce_addr); xfree (keyparms); } return err; } /* * Generate an ECC key */ static gpg_error_t gen_ecc (int algo, const char *curve, kbnode_t pub_root, u32 timestamp, u32 expireval, int is_subkey, int keygen_flags, const char *passphrase, char **cache_nonce_addr) { gpg_error_t err; char *keyparms; assert (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH); if (!curve || !*curve) return gpg_error (GPG_ERR_UNKNOWN_CURVE); /* Note that we use the "comp" flag with EdDSA to request the use of a 0x40 compression prefix octet. */ if (algo == PUBKEY_ALGO_EDDSA) keyparms = xtryasprintf ("(genkey(ecc(curve %zu:%s)(flags eddsa comp%s)))", strlen (curve), curve, (((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? " transient-key" : "")); else keyparms = xtryasprintf ("(genkey(ecc(curve %zu:%s)(flags nocomp%s)))", strlen (curve), curve, (((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? " transient-key" : "")); if (!keyparms) err = gpg_error_from_syserror (); else { err = common_gen (keyparms, algo, "", pub_root, timestamp, expireval, is_subkey, keygen_flags, passphrase, cache_nonce_addr); xfree (keyparms); } return err; } /* * Generate an RSA key. */ static int gen_rsa (int algo, unsigned int nbits, KBNODE pub_root, u32 timestamp, u32 expireval, int is_subkey, int keygen_flags, const char *passphrase, char **cache_nonce_addr) { int err; char *keyparms; char nbitsstr[35]; const unsigned maxsize = (opt.flags.large_rsa ? 8192 : 4096); assert (is_RSA(algo)); if (!nbits) nbits = DEFAULT_STD_KEYSIZE; if (nbits < 1024) { nbits = 2048; log_info (_("keysize invalid; using %u bits\n"), nbits ); } else if (nbits > maxsize) { nbits = maxsize; log_info (_("keysize invalid; using %u bits\n"), nbits ); } if ((nbits % 32)) { nbits = ((nbits + 31) / 32) * 32; log_info (_("keysize rounded up to %u bits\n"), nbits ); } snprintf (nbitsstr, sizeof nbitsstr, "%u", nbits); keyparms = xtryasprintf ("(genkey(rsa(nbits %zu:%s)%s))", strlen (nbitsstr), nbitsstr, ((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY) && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))? "(transient-key)" : "" ); if (!keyparms) err = gpg_error_from_syserror (); else { err = common_gen (keyparms, algo, "ne", pub_root, timestamp, expireval, is_subkey, keygen_flags, passphrase, cache_nonce_addr); xfree (keyparms); } return err; } /**************** * check valid days: * return 0 on error or the multiplier */ static int check_valid_days( const char *s ) { if( !digitp(s) ) return 0; for( s++; *s; s++) if( !digitp(s) ) break; if( !*s ) return 1; if( s[1] ) return 0; /* e.g. "2323wc" */ if( *s == 'd' || *s == 'D' ) return 1; if( *s == 'w' || *s == 'W' ) return 7; if( *s == 'm' || *s == 'M' ) return 30; if( *s == 'y' || *s == 'Y' ) return 365; return 0; } static void print_key_flags(int flags) { if(flags&PUBKEY_USAGE_SIG) tty_printf("%s ",_("Sign")); if(flags&PUBKEY_USAGE_CERT) tty_printf("%s ",_("Certify")); if(flags&PUBKEY_USAGE_ENC) tty_printf("%s ",_("Encrypt")); if(flags&PUBKEY_USAGE_AUTH) tty_printf("%s ",_("Authenticate")); } /* Returns the key flags */ static unsigned int ask_key_flags(int algo,int subkey) { /* TRANSLATORS: Please use only plain ASCII characters for the translation. If this is not possible use single digits. The string needs to 8 bytes long. Here is a description of the functions: s = Toggle signing capability e = Toggle encryption capability a = Toggle authentication capability q = Finish */ const char *togglers=_("SsEeAaQq"); char *answer=NULL; const char *s; unsigned int current=0; unsigned int possible=openpgp_pk_algo_usage(algo); if ( strlen(togglers) != 8 ) { tty_printf ("NOTE: Bad translation at %s:%d. " "Please report.\n", __FILE__, __LINE__); togglers = "11223300"; } /* Only primary keys may certify. */ if(subkey) possible&=~PUBKEY_USAGE_CERT; /* Preload the current set with the possible set, minus authentication, since nobody really uses auth yet. */ current=possible&~PUBKEY_USAGE_AUTH; for(;;) { tty_printf("\n"); tty_printf(_("Possible actions for a %s key: "), openpgp_pk_algo_name (algo)); print_key_flags(possible); tty_printf("\n"); tty_printf(_("Current allowed actions: ")); print_key_flags(current); tty_printf("\n\n"); if(possible&PUBKEY_USAGE_SIG) tty_printf(_(" (%c) Toggle the sign capability\n"), togglers[0]); if(possible&PUBKEY_USAGE_ENC) tty_printf(_(" (%c) Toggle the encrypt capability\n"), togglers[2]); if(possible&PUBKEY_USAGE_AUTH) tty_printf(_(" (%c) Toggle the authenticate capability\n"), togglers[4]); tty_printf(_(" (%c) Finished\n"),togglers[6]); tty_printf("\n"); xfree(answer); answer = cpr_get("keygen.flags",_("Your selection? ")); cpr_kill_prompt(); if (*answer == '=') { /* Hack to allow direct entry of the capabilities. */ current = 0; for (s=answer+1; *s; s++) { if ((*s == 's' || *s == 'S') && (possible&PUBKEY_USAGE_SIG)) current |= PUBKEY_USAGE_SIG; else if ((*s == 'e' || *s == 'E') && (possible&PUBKEY_USAGE_ENC)) current |= PUBKEY_USAGE_ENC; else if ((*s == 'a' || *s == 'A') && (possible&PUBKEY_USAGE_AUTH)) current |= PUBKEY_USAGE_AUTH; else if (!subkey && *s == 'c') { /* Accept 'c' for the primary key because USAGE_CERT will will be set anyway. This is for folks who want to experiment with a cert-only primary key. */ current |= PUBKEY_USAGE_CERT; } } break; } else if (strlen(answer)>1) tty_printf(_("Invalid selection.\n")); else if(*answer=='\0' || *answer==togglers[6] || *answer==togglers[7]) break; else if((*answer==togglers[0] || *answer==togglers[1]) && possible&PUBKEY_USAGE_SIG) { if(current&PUBKEY_USAGE_SIG) current&=~PUBKEY_USAGE_SIG; else current|=PUBKEY_USAGE_SIG; } else if((*answer==togglers[2] || *answer==togglers[3]) && possible&PUBKEY_USAGE_ENC) { if(current&PUBKEY_USAGE_ENC) current&=~PUBKEY_USAGE_ENC; else current|=PUBKEY_USAGE_ENC; } else if((*answer==togglers[4] || *answer==togglers[5]) && possible&PUBKEY_USAGE_AUTH) { if(current&PUBKEY_USAGE_AUTH) current&=~PUBKEY_USAGE_AUTH; else current|=PUBKEY_USAGE_AUTH; } else tty_printf(_("Invalid selection.\n")); } xfree(answer); return current; } /* Check whether we have a key for the key with HEXGRIP. Returns 0 if there is no such key or the OpenPGP algo number for the key. */ static int check_keygrip (ctrl_t ctrl, const char *hexgrip) { gpg_error_t err; unsigned char *public; size_t publiclen; const char *algostr; if (hexgrip[0] == '&') hexgrip++; err = agent_readkey (ctrl, 0, hexgrip, &public); if (err) return 0; publiclen = gcry_sexp_canon_len (public, 0, NULL, NULL); get_pk_algo_from_canon_sexp (public, publiclen, &algostr); xfree (public); /* FIXME: Mapping of ECC algorithms is probably not correct. */ if (!algostr) return 0; else if (!strcmp (algostr, "rsa")) return PUBKEY_ALGO_RSA; else if (!strcmp (algostr, "dsa")) return PUBKEY_ALGO_DSA; else if (!strcmp (algostr, "elg")) return PUBKEY_ALGO_ELGAMAL_E; else if (!strcmp (algostr, "ecc")) return PUBKEY_ALGO_ECDH; else if (!strcmp (algostr, "ecdsa")) return PUBKEY_ALGO_ECDSA; else if (!strcmp (algostr, "eddsa")) return PUBKEY_ALGO_EDDSA; else return 0; } /* Ask for an algorithm. The function returns the algorithm id to * create. If ADDMODE is false the function won't show an option to * create the primary and subkey combined and won't set R_USAGE * either. If a combined algorithm has been selected, the subkey * algorithm is stored at R_SUBKEY_ALGO. If R_KEYGRIP is given, the * user has the choice to enter the keygrip of an existing key. That * keygrip is then stored at this address. The caller needs to free * it. */ static int ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage, char **r_keygrip) { char *keygrip = NULL; char *answer = NULL; int algo; int dummy_algo; if (!r_subkey_algo) r_subkey_algo = &dummy_algo; tty_printf (_("Please select what kind of key you want:\n")); #if GPG_USE_RSA if (!addmode) tty_printf (_(" (%d) RSA and RSA (default)\n"), 1 ); #endif if (!addmode) tty_printf (_(" (%d) DSA and Elgamal\n"), 2 ); tty_printf (_(" (%d) DSA (sign only)\n"), 3 ); #if GPG_USE_RSA tty_printf (_(" (%d) RSA (sign only)\n"), 4 ); #endif if (addmode) { tty_printf (_(" (%d) Elgamal (encrypt only)\n"), 5 ); #if GPG_USE_RSA tty_printf (_(" (%d) RSA (encrypt only)\n"), 6 ); #endif } if (opt.expert) { tty_printf (_(" (%d) DSA (set your own capabilities)\n"), 7 ); #if GPG_USE_RSA tty_printf (_(" (%d) RSA (set your own capabilities)\n"), 8 ); #endif } #if GPG_USE_ECDSA || GPG_USE_ECDH || GPG_USE_EDDSA if (opt.expert && !addmode) tty_printf (_(" (%d) ECC and ECC\n"), 9 ); if (opt.expert) tty_printf (_(" (%d) ECC (sign only)\n"), 10 ); if (opt.expert) tty_printf (_(" (%d) ECC (set your own capabilities)\n"), 11 ); if (opt.expert && addmode) tty_printf (_(" (%d) ECC (encrypt only)\n"), 12 ); #endif if (opt.expert && r_keygrip) tty_printf (_(" (%d) Existing key\n"), 13 ); for (;;) { *r_usage = 0; *r_subkey_algo = 0; xfree (answer); answer = cpr_get ("keygen.algo", _("Your selection? ")); cpr_kill_prompt (); algo = *answer? atoi (answer) : 1; if ((algo == 1 || !strcmp (answer, "rsa+rsa")) && !addmode) { algo = PUBKEY_ALGO_RSA; *r_subkey_algo = PUBKEY_ALGO_RSA; break; } else if ((algo == 2 || !strcmp (answer, "dsa+elg")) && !addmode) { algo = PUBKEY_ALGO_DSA; *r_subkey_algo = PUBKEY_ALGO_ELGAMAL_E; break; } else if (algo == 3 || !strcmp (answer, "dsa")) { algo = PUBKEY_ALGO_DSA; *r_usage = PUBKEY_USAGE_SIG; break; } else if (algo == 4 || !strcmp (answer, "rsa/s")) { algo = PUBKEY_ALGO_RSA; *r_usage = PUBKEY_USAGE_SIG; break; } else if ((algo == 5 || !strcmp (answer, "elg")) && addmode) { algo = PUBKEY_ALGO_ELGAMAL_E; *r_usage = PUBKEY_USAGE_ENC; break; } else if ((algo == 6 || !strcmp (answer, "rsa/e")) && addmode) { algo = PUBKEY_ALGO_RSA; *r_usage = PUBKEY_USAGE_ENC; break; } else if ((algo == 7 || !strcmp (answer, "dsa/*")) && opt.expert) { algo = PUBKEY_ALGO_DSA; *r_usage = ask_key_flags (algo, addmode); break; } else if ((algo == 8 || !strcmp (answer, "rsa/*")) && opt.expert) { algo = PUBKEY_ALGO_RSA; *r_usage = ask_key_flags (algo, addmode); break; } else if ((algo == 9 || !strcmp (answer, "ecc+ecc")) && opt.expert && !addmode) { algo = PUBKEY_ALGO_ECDSA; *r_subkey_algo = PUBKEY_ALGO_ECDH; break; } else if ((algo == 10 || !strcmp (answer, "ecc/s")) && opt.expert) { algo = PUBKEY_ALGO_ECDSA; *r_usage = PUBKEY_USAGE_SIG; break; } else if ((algo == 11 || !strcmp (answer, "ecc/*")) && opt.expert) { algo = PUBKEY_ALGO_ECDSA; *r_usage = ask_key_flags (algo, addmode); break; } else if ((algo == 12 || !strcmp (answer, "ecc/e")) && opt.expert && addmode) { algo = PUBKEY_ALGO_ECDH; *r_usage = PUBKEY_USAGE_ENC; break; } else if ((algo == 13 || !strcmp (answer, "keygrip")) && opt.expert && r_keygrip) { for (;;) { xfree (answer); answer = tty_get (_("Enter the keygrip: ")); tty_kill_prompt (); trim_spaces (answer); if (!*answer) { xfree (answer); answer = NULL; continue; } if (strlen (answer) != 40 && !(answer[0] == '&' && strlen (answer+1) == 40)) tty_printf (_("Not a valid keygrip (expecting 40 hex digits)\n")); else if (!(algo = check_keygrip (ctrl, answer)) ) tty_printf (_("No key with this keygrip\n")); else break; /* Okay. */ } xfree (keygrip); keygrip = answer; answer = NULL; *r_usage = ask_key_flags (algo, addmode); break; } else tty_printf (_("Invalid selection.\n")); } xfree(answer); if (r_keygrip) *r_keygrip = keygrip; return algo; } /* Ask for the key size. ALGO is the algorithm. If PRIMARY_KEYSIZE is not 0, the function asks for the size of the encryption subkey. */ static unsigned ask_keysize (int algo, unsigned int primary_keysize) { unsigned int nbits, min, def = DEFAULT_STD_KEYSIZE, max=4096; int for_subkey = !!primary_keysize; int autocomp = 0; if(opt.expert) min=512; else min=1024; if (primary_keysize && !opt.expert) { /* Deduce the subkey size from the primary key size. */ if (algo == PUBKEY_ALGO_DSA && primary_keysize > 3072) nbits = 3072; /* For performance reasons we don't support more than 3072 bit DSA. However we won't see this case anyway because DSA can't be used as an encryption subkey ;-). */ else nbits = primary_keysize; autocomp = 1; goto leave; } switch(algo) { case PUBKEY_ALGO_DSA: def=2048; max=3072; break; case PUBKEY_ALGO_ECDSA: case PUBKEY_ALGO_ECDH: min=256; def=256; max=521; break; case PUBKEY_ALGO_EDDSA: min=255; def=255; max=441; break; case PUBKEY_ALGO_RSA: min=1024; break; } tty_printf(_("%s keys may be between %u and %u bits long.\n"), openpgp_pk_algo_name (algo), min, max); for (;;) { char *prompt, *answer; if (for_subkey) prompt = xasprintf (_("What keysize do you want " "for the subkey? (%u) "), def); else prompt = xasprintf (_("What keysize do you want? (%u) "), def); answer = cpr_get ("keygen.size", prompt); cpr_kill_prompt (); nbits = *answer? atoi (answer): def; xfree(prompt); xfree(answer); if(nbitsmax) tty_printf(_("%s keysizes must be in the range %u-%u\n"), openpgp_pk_algo_name (algo), min, max); else break; } tty_printf (_("Requested keysize is %u bits\n"), nbits); leave: if (algo == PUBKEY_ALGO_DSA && (nbits % 64)) { nbits = ((nbits + 63) / 64) * 64; if (!autocomp) tty_printf (_("rounded up to %u bits\n"), nbits); } else if (algo == PUBKEY_ALGO_EDDSA) { if (nbits != 255 && nbits != 441) { if (nbits < 256) nbits = 255; else nbits = 441; if (!autocomp) tty_printf (_("rounded to %u bits\n"), nbits); } } else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA) { if (nbits != 256 && nbits != 384 && nbits != 521) { if (nbits < 256) nbits = 256; else if (nbits < 384) nbits = 384; else nbits = 521; if (!autocomp) tty_printf (_("rounded to %u bits\n"), nbits); } } else if ((nbits % 32)) { nbits = ((nbits + 31) / 32) * 32; if (!autocomp) tty_printf (_("rounded up to %u bits\n"), nbits ); } return nbits; } /* Ask for the curve. ALGO is the selected algorithm which this function may adjust. Returns a malloced string with the name of the curve. BOTH tells that gpg creates a primary and subkey. */ static char * ask_curve (int *algo, int both) { struct { const char *name; int available; int expert_only; int fix_curve; const char *pretty_name; } curves[] = { #if GPG_USE_EDDSA { "Curve25519", 0, 0, 1, "Curve 25519" }, #endif #if GPG_USE_ECDSA || GPG_USE_ECDH { "NIST P-256", 0, 1, 0, }, { "NIST P-384", 0, 0, 0, }, { "NIST P-521", 0, 1, 0, }, { "brainpoolP256r1", 0, 1, 0, "Brainpool P-256" }, { "brainpoolP384r1", 0, 1, 0, "Brainpool P-384" }, { "brainpoolP512r1", 0, 1, 0, "Brainpool P-512" }, { "secp256k1", 0, 1, 0 }, #endif }; int idx; char *answer; char *result = NULL; gcry_sexp_t keyparms; tty_printf (_("Please select which elliptic curve you want:\n")); again: keyparms = NULL; for (idx=0; idx < DIM(curves); idx++) { int rc; curves[idx].available = 0; if (!opt.expert && curves[idx].expert_only) continue; /* FIXME: The strcmp below is a temporary hack during development. It shall be removed as soon as we have proper Curve25519 support in Libgcrypt. */ gcry_sexp_release (keyparms); rc = gcry_sexp_build (&keyparms, NULL, "(public-key(ecc(curve %s)))", (!strcmp (curves[idx].name, "Curve25519") ? "Ed25519" : curves[idx].name)); if (rc) continue; if (!gcry_pk_get_curve (keyparms, 0, NULL)) continue; if (both && curves[idx].fix_curve) { /* Both Curve 25519 keys are to be created. Check that Libgcrypt also supports the real Curve25519. */ gcry_sexp_release (keyparms); rc = gcry_sexp_build (&keyparms, NULL, "(public-key(ecc(curve %s)))", curves[idx].name); if (rc) continue; if (!gcry_pk_get_curve (keyparms, 0, NULL)) continue; } curves[idx].available = 1; tty_printf (" (%d) %s\n", idx + 1, curves[idx].pretty_name? curves[idx].pretty_name:curves[idx].name); } gcry_sexp_release (keyparms); for (;;) { answer = cpr_get ("keygen.curve", _("Your selection? ")); cpr_kill_prompt (); idx = *answer? atoi (answer) : 1; if (*answer && !idx) { /* See whether the user entered the name of the curve. */ for (idx=0; idx < DIM(curves); idx++) { if (!opt.expert && curves[idx].expert_only) continue; if (!stricmp (curves[idx].name, answer) || (curves[idx].pretty_name && !stricmp (curves[idx].pretty_name, answer))) break; } if (idx == DIM(curves)) idx = -1; } else idx--; xfree(answer); answer = NULL; if (idx < 0 || idx >= DIM (curves) || !curves[idx].available) tty_printf (_("Invalid selection.\n")); else { if (curves[idx].fix_curve) { log_info ("WARNING: Curve25519 is not yet part of the" " OpenPGP standard.\n"); if (!cpr_get_answer_is_yes("experimental_curve.override", "Use this curve anyway? (y/N) ") ) goto again; } /* If the user selected a signing algorithm and Curve25519 we need to update the algo and and the curve name. */ if ((*algo == PUBKEY_ALGO_ECDSA || *algo == PUBKEY_ALGO_EDDSA) && curves[idx].fix_curve) { *algo = PUBKEY_ALGO_EDDSA; result = xstrdup ("Ed25519"); } else result = xstrdup (curves[idx].name); break; } } if (!result) result = xstrdup (curves[0].name); return result; } /**************** * Parse an expire string and return its value in seconds. * Returns (u32)-1 on error. * This isn't perfect since scan_isodatestr returns unix time, and * OpenPGP actually allows a 32-bit time *plus* a 32-bit offset. * Because of this, we only permit setting expirations up to 2106, but * OpenPGP could theoretically allow up to 2242. I think we'll all * just cope for the next few years until we get a 64-bit time_t or * similar. */ u32 parse_expire_string( const char *string ) { int mult; u32 seconds; u32 abs_date = 0; u32 curtime = make_timestamp (); time_t tt; if (!*string) seconds = 0; else if (!strncmp (string, "seconds=", 8)) seconds = atoi (string+8); else if ((abs_date = scan_isodatestr(string)) && (abs_date+86400/2) > curtime) seconds = (abs_date+86400/2) - curtime; else if ((tt = isotime2epoch (string)) != (time_t)(-1)) seconds = (u32)tt - curtime; else if ((mult = check_valid_days (string))) seconds = atoi (string) * 86400L * mult; else seconds = (u32)(-1); return seconds; } /* Parsean Creation-Date string which is either "1986-04-26" or "19860426T042640". Returns 0 on error. */ static u32 parse_creation_string (const char *string) { u32 seconds; if (!*string) seconds = 0; else if ( !strncmp (string, "seconds=", 8) ) seconds = atoi (string+8); else if ( !(seconds = scan_isodatestr (string))) { time_t tmp = isotime2epoch (string); seconds = (tmp == (time_t)(-1))? 0 : tmp; } return seconds; } /* object == 0 for a key, and 1 for a sig */ u32 ask_expire_interval(int object,const char *def_expire) { u32 interval; char *answer; switch(object) { case 0: if(def_expire) BUG(); tty_printf(_("Please specify how long the key should be valid.\n" " 0 = key does not expire\n" " = key expires in n days\n" " w = key expires in n weeks\n" " m = key expires in n months\n" " y = key expires in n years\n")); break; case 1: if(!def_expire) BUG(); tty_printf(_("Please specify how long the signature should be valid.\n" " 0 = signature does not expire\n" " = signature expires in n days\n" " w = signature expires in n weeks\n" " m = signature expires in n months\n" " y = signature expires in n years\n")); break; default: BUG(); } /* Note: The elgamal subkey for DSA has no expiration date because * it must be signed with the DSA key and this one has the expiration * date */ answer = NULL; for(;;) { u32 curtime; xfree(answer); if(object==0) answer = cpr_get("keygen.valid",_("Key is valid for? (0) ")); else { char *prompt; #define PROMPTSTRING _("Signature is valid for? (%s) ") /* This will actually end up larger than necessary because of the 2 bytes for '%s' */ prompt=xmalloc(strlen(PROMPTSTRING)+strlen(def_expire)+1); sprintf(prompt,PROMPTSTRING,def_expire); #undef PROMPTSTRING answer = cpr_get("siggen.valid",prompt); xfree(prompt); if(*answer=='\0') answer=xstrdup(def_expire); } cpr_kill_prompt(); trim_spaces(answer); curtime = make_timestamp (); interval = parse_expire_string( answer ); if( interval == (u32)-1 ) { tty_printf(_("invalid value\n")); continue; } if( !interval ) { tty_printf((object==0) ? _("Key does not expire at all\n") : _("Signature does not expire at all\n")); } else { tty_printf(object==0 ? _("Key expires at %s\n") : _("Signature expires at %s\n"), asctimestamp((ulong)(curtime + interval) ) ); #if SIZEOF_TIME_T <= 4 && !defined (HAVE_UNSIGNED_TIME_T) if ( (time_t)((ulong)(curtime+interval)) < 0 ) tty_printf (_("Your system can't display dates beyond 2038.\n" "However, it will be correctly handled up to" " 2106.\n")); else #endif /*SIZEOF_TIME_T*/ if ( (time_t)((unsigned long)(curtime+interval)) < curtime ) { tty_printf (_("invalid value\n")); continue; } } if( cpr_enabled() || cpr_get_answer_is_yes("keygen.valid.okay", _("Is this correct? (y/N) ")) ) break; } xfree(answer); return interval; } u32 ask_expiredate() { u32 x = ask_expire_interval(0,NULL); return x? make_timestamp() + x : 0; } static PKT_user_id * uid_from_string (const char *string) { size_t n; PKT_user_id *uid; n = strlen (string); uid = xmalloc_clear (sizeof *uid + n); uid->len = n; strcpy (uid->name, string); uid->ref = 1; return uid; } +/* Return true if the user id UID already exists in the keyblock. */ +static int +uid_already_in_keyblock (kbnode_t keyblock, const char *uid) +{ + PKT_user_id *uidpkt = uid_from_string (uid); + kbnode_t node; + int result = 0; + + for (node=keyblock; node && !result; node=node->next) + if (!is_deleted_kbnode (node) + && node->pkt->pkttype == PKT_USER_ID + && !cmp_user_ids (uidpkt, node->pkt->pkt.user_id)) + result = 1; + free_user_id (uidpkt); + return result; +} + + /* Ask for a user ID. With a MODE of 1 an extra help prompt is printed for use during a new key creation. If KEYBLOCK is not NULL the function prevents the creation of an already existing user ID. IF FULL is not set some prompts are not shown. */ static char * ask_user_id (int mode, int full, KBNODE keyblock) { char *answer; char *aname, *acomment, *amail, *uid; if ( !mode ) { /* TRANSLATORS: This is the new string telling the user what gpg is now going to do (i.e. ask for the parts of the user ID). Note that if you do not translate this string, a different string will be used, which might still have a correct translation. */ const char *s1 = N_("\n" "GnuPG needs to construct a user ID to identify your key.\n" "\n"); const char *s2 = _(s1); if (!strcmp (s1, s2)) { /* There is no translation for the string thus we to use the old info text. gettext has no way to tell whether a translation is actually available, thus we need to to compare again. */ /* TRANSLATORS: This string is in general not anymore used but you should keep your existing translation. In case the new string is not translated this old string will be used. */ const char *s3 = N_("\n" "You need a user ID to identify your key; " "the software constructs the user ID\n" "from the Real Name, Comment and Email Address in this form:\n" " \"Heinrich Heine (Der Dichter) \"\n\n"); const char *s4 = _(s3); if (strcmp (s3, s4)) s2 = s3; /* A translation exists - use it. */ } tty_printf ("%s", s2) ; } uid = aname = acomment = amail = NULL; for(;;) { char *p; int fail=0; if( !aname ) { for(;;) { xfree(aname); aname = cpr_get("keygen.name",_("Real name: ")); trim_spaces(aname); cpr_kill_prompt(); if( opt.allow_freeform_uid ) break; if( strpbrk( aname, "<>" ) ) tty_printf(_("Invalid character in name\n")); else if( digitp(aname) ) tty_printf(_("Name may not start with a digit\n")); else if( strlen(aname) < 5 ) tty_printf(_("Name must be at least 5 characters long\n")); else break; } } if( !amail ) { for(;;) { xfree(amail); amail = cpr_get("keygen.email",_("Email address: ")); trim_spaces(amail); cpr_kill_prompt(); if( !*amail || opt.allow_freeform_uid ) break; /* no email address is okay */ else if ( !is_valid_mailbox (amail) ) tty_printf(_("Not a valid email address\n")); else break; } } if (!acomment) { if (full) { for(;;) { xfree(acomment); acomment = cpr_get("keygen.comment",_("Comment: ")); trim_spaces(acomment); cpr_kill_prompt(); if( !*acomment ) break; /* no comment is okay */ else if( strpbrk( acomment, "()" ) ) tty_printf(_("Invalid character in comment\n")); else break; } } else { xfree (acomment); acomment = xstrdup (""); } } xfree(uid); uid = p = xmalloc(strlen(aname)+strlen(amail)+strlen(acomment)+12+10); p = stpcpy(p, aname ); if( *acomment ) p = stpcpy(stpcpy(stpcpy(p," ("), acomment),")"); if( *amail ) p = stpcpy(stpcpy(stpcpy(p," <"), amail),">"); /* Append a warning if the RNG is switched into fake mode. */ if ( random_is_faked () ) strcpy(p, " (insecure!)" ); /* print a note in case that UTF8 mapping has to be done */ for(p=uid; *p; p++ ) { if( *p & 0x80 ) { tty_printf(_("You are using the '%s' character set.\n"), get_native_charset() ); break; } } tty_printf(_("You selected this USER-ID:\n \"%s\"\n\n"), uid); if( !*amail && !opt.allow_freeform_uid && (strchr( aname, '@' ) || strchr( acomment, '@'))) { fail = 1; tty_printf(_("Please don't put the email address " "into the real name or the comment\n") ); } if (!fail && keyblock) { - PKT_user_id *uidpkt = uid_from_string (uid); - KBNODE node; - - for (node=keyblock; node && !fail; node=node->next) - if (!is_deleted_kbnode (node) - && node->pkt->pkttype == PKT_USER_ID - && !cmp_user_ids (uidpkt, node->pkt->pkt.user_id)) - fail = 1; - if (fail) - tty_printf (_("Such a user ID already exists on this key!\n")); - free_user_id (uidpkt); + if (uid_already_in_keyblock (keyblock, uid)) + { + tty_printf (_("Such a user ID already exists on this key!\n")); + fail = 1; + } } for(;;) { /* TRANSLATORS: These are the allowed answers in lower and uppercase. Below you will find the matching string which should be translated accordingly and the letter changed to match the one in the answer string. n = Change name c = Change comment e = Change email o = Okay (ready, continue) q = Quit */ const char *ansstr = _("NnCcEeOoQq"); if( strlen(ansstr) != 10 ) BUG(); if( cpr_enabled() ) { answer = xstrdup (ansstr + (fail?8:6)); answer[1] = 0; } else if (full) { answer = cpr_get("keygen.userid.cmd", fail? _("Change (N)ame, (C)omment, (E)mail or (Q)uit? ") : _("Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? ")); cpr_kill_prompt(); } else { answer = cpr_get("keygen.userid.cmd", fail? _("Change (N)ame, (E)mail, or (Q)uit? ") : _("Change (N)ame, (E)mail, or (O)kay/(Q)uit? ")); cpr_kill_prompt(); } if( strlen(answer) > 1 ) ; else if( *answer == ansstr[0] || *answer == ansstr[1] ) { xfree(aname); aname = NULL; break; } else if( *answer == ansstr[2] || *answer == ansstr[3] ) { xfree(acomment); acomment = NULL; break; } else if( *answer == ansstr[4] || *answer == ansstr[5] ) { xfree(amail); amail = NULL; break; } else if( *answer == ansstr[6] || *answer == ansstr[7] ) { if( fail ) { tty_printf(_("Please correct the error first\n")); } else { xfree(aname); aname = NULL; xfree(acomment); acomment = NULL; xfree(amail); amail = NULL; break; } } else if( *answer == ansstr[8] || *answer == ansstr[9] ) { xfree(aname); aname = NULL; xfree(acomment); acomment = NULL; xfree(amail); amail = NULL; xfree(uid); uid = NULL; break; } xfree(answer); } xfree(answer); if (!amail && !acomment) break; xfree(uid); uid = NULL; } if( uid ) { char *p = native_to_utf8( uid ); xfree( uid ); uid = p; } return uid; } /* MODE 0 - standard 1 - Ask for passphrase of the card backup key. */ #if 0 static DEK * do_ask_passphrase (STRING2KEY **ret_s2k, int mode, int *r_canceled) { DEK *dek = NULL; STRING2KEY *s2k; const char *errtext = NULL; const char *custdesc = NULL; tty_printf(_("You need a Passphrase to protect your secret key.\n\n") ); if (mode == 1) custdesc = _("Please enter a passphrase to protect the off-card " "backup of the new encryption key."); s2k = xmalloc_secure( sizeof *s2k ); for(;;) { s2k->mode = opt.s2k_mode; s2k->hash_algo = S2K_DIGEST_ALGO; dek = passphrase_to_dek_ext (NULL, 0, opt.s2k_cipher_algo, s2k, 2, errtext, custdesc, NULL, r_canceled); if (!dek && *r_canceled) { xfree(dek); dek = NULL; xfree(s2k); s2k = NULL; break; } else if( !dek ) { errtext = N_("passphrase not correctly repeated; try again"); tty_printf(_("%s.\n"), _(errtext)); } else if( !dek->keylen ) { xfree(dek); dek = NULL; xfree(s2k); s2k = NULL; tty_printf(_( "You don't want a passphrase - this is probably a *bad* idea!\n" "I will do it anyway. You can change your passphrase at any time,\n" "using this program with the option \"--edit-key\".\n\n")); break; } else break; /* okay */ } *ret_s2k = s2k; return dek; } #endif /* 0 */ /* Basic key generation. Here we divert to the actual generation routines based on the requested algorithm. */ static int do_create (int algo, unsigned int nbits, const char *curve, KBNODE pub_root, u32 timestamp, u32 expiredate, int is_subkey, int keygen_flags, const char *passphrase, char **cache_nonce_addr) { gpg_error_t err; /* Fixme: The entropy collecting message should be moved to a libgcrypt progress handler. */ if (!opt.batch) tty_printf (_( "We need to generate a lot of random bytes. It is a good idea to perform\n" "some other action (type on the keyboard, move the mouse, utilize the\n" "disks) during the prime generation; this gives the random number\n" "generator a better chance to gain enough entropy.\n") ); if (algo == PUBKEY_ALGO_ELGAMAL_E) err = gen_elg (algo, nbits, pub_root, timestamp, expiredate, is_subkey, keygen_flags, passphrase, cache_nonce_addr); else if (algo == PUBKEY_ALGO_DSA) err = gen_dsa (nbits, pub_root, timestamp, expiredate, is_subkey, keygen_flags, passphrase, cache_nonce_addr); else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH) err = gen_ecc (algo, curve, pub_root, timestamp, expiredate, is_subkey, keygen_flags, passphrase, cache_nonce_addr); else if (algo == PUBKEY_ALGO_RSA) err = gen_rsa (algo, nbits, pub_root, timestamp, expiredate, is_subkey, keygen_flags, passphrase, cache_nonce_addr); else BUG(); return err; } /* Generate a new user id packet or return NULL if canceled. If KEYBLOCK is not NULL the function prevents the creation of an - already existing user ID. */ + already existing user ID. If UIDSTR is not NULL the user is not + asked but UIDSTR is used to create the user id packet; if the user + id already exists NULL is returned. UIDSTR is expected to be utf-8 + encoded and should have already been checked for a valid length + etc. */ PKT_user_id * -generate_user_id (KBNODE keyblock) +generate_user_id (KBNODE keyblock, const char *uidstr) { + PKT_user_id *uid; char *p; - p = ask_user_id (1, 1, keyblock); - if (!p) - return NULL; /* Canceled. */ - return uid_from_string (p); + if (uidstr) + { + if (uid_already_in_keyblock (keyblock, uidstr)) + return NULL; /* Already exists. */ + uid = uid_from_string (uidstr); + } + else + { + p = ask_user_id (1, 1, keyblock); + if (!p) + return NULL; /* Canceled. */ + uid = uid_from_string (p); + xfree (p); + } + return uid; } /* Append R to the linked list PARA. */ static void append_to_parameter (struct para_data_s *para, struct para_data_s *r) { assert (para); while (para->next) para = para->next; para->next = r; } /* Release the parameter list R. */ static void release_parameter_list (struct para_data_s *r) { struct para_data_s *r2; for (; r ; r = r2) { r2 = r->next; if (r->key == pPASSPHRASE && *r->u.value) wipememory (r->u.value, strlen (r->u.value)); xfree (r); } } static struct para_data_s * get_parameter( struct para_data_s *para, enum para_name key ) { struct para_data_s *r; for( r = para; r && r->key != key; r = r->next ) ; return r; } static const char * get_parameter_value( struct para_data_s *para, enum para_name key ) { struct para_data_s *r = get_parameter( para, key ); return (r && *r->u.value)? r->u.value : NULL; } /* This is similar to get_parameter_value but also returns the empty string. This is required so that quick_generate_keypair can use an empty Passphrase to specify no-protection. */ static const char * get_parameter_passphrase (struct para_data_s *para) { struct para_data_s *r = get_parameter (para, pPASSPHRASE); return r ? r->u.value : NULL; } static int get_parameter_algo( struct para_data_s *para, enum para_name key, int *r_default) { int i; struct para_data_s *r = get_parameter( para, key ); if (r_default) *r_default = 0; if (!r) return -1; /* Note that we need to handle the ECC algorithms specified as strings directly because Libgcrypt folds them all to ECC. */ if (!ascii_strcasecmp (r->u.value, "default")) { /* Note: If you change this default algo, remember to change it also in gpg.c:gpgconf_list. */ i = DEFAULT_STD_ALGO; if (r_default) *r_default = 1; } else if (digitp (r->u.value)) i = atoi( r->u.value ); else if (!strcmp (r->u.value, "ELG-E") || !strcmp (r->u.value, "ELG")) i = PUBKEY_ALGO_ELGAMAL_E; else if (!ascii_strcasecmp (r->u.value, "EdDSA")) i = PUBKEY_ALGO_EDDSA; else if (!ascii_strcasecmp (r->u.value, "ECDSA")) i = PUBKEY_ALGO_ECDSA; else if (!ascii_strcasecmp (r->u.value, "ECDH")) i = PUBKEY_ALGO_ECDH; else i = map_pk_gcry_to_openpgp (gcry_pk_map_name (r->u.value)); if (i == PUBKEY_ALGO_RSA_E || i == PUBKEY_ALGO_RSA_S) i = 0; /* we don't want to allow generation of these algorithms */ return i; } /* * Parse the usage parameter and set the keyflags. Returns -1 on * error, 0 for no usage given or 1 for usage available. */ static int parse_parameter_usage (const char *fname, struct para_data_s *para, enum para_name key) { struct para_data_s *r = get_parameter( para, key ); char *p, *pn; unsigned int use; if( !r ) return 0; /* none (this is an optional parameter)*/ use = 0; pn = r->u.value; while ( (p = strsep (&pn, " \t,")) ) { if ( !*p) ; else if ( !ascii_strcasecmp (p, "sign") ) use |= PUBKEY_USAGE_SIG; else if ( !ascii_strcasecmp (p, "encrypt") ) use |= PUBKEY_USAGE_ENC; else if ( !ascii_strcasecmp (p, "auth") ) use |= PUBKEY_USAGE_AUTH; else { log_error("%s:%d: invalid usage list\n", fname, r->lnr ); return -1; /* error */ } } r->u.usage = use; return 1; } static int parse_revocation_key (const char *fname, struct para_data_s *para, enum para_name key) { struct para_data_s *r = get_parameter( para, key ); struct revocation_key revkey; char *pn; int i; if( !r ) return 0; /* none (this is an optional parameter) */ pn = r->u.value; revkey.class=0x80; revkey.algid=atoi(pn); if(!revkey.algid) goto fail; /* Skip to the fpr */ while(*pn && *pn!=':') pn++; if(*pn!=':') goto fail; pn++; for(i=0;iu.revkey,&revkey,sizeof(struct revocation_key)); return 0; fail: log_error("%s:%d: invalid revocation key\n", fname, r->lnr ); return -1; /* error */ } static u32 get_parameter_u32( struct para_data_s *para, enum para_name key ) { struct para_data_s *r = get_parameter( para, key ); if( !r ) return 0; if( r->key == pKEYCREATIONDATE ) return r->u.creation; if( r->key == pKEYEXPIRE || r->key == pSUBKEYEXPIRE ) return r->u.expire; if( r->key == pKEYUSAGE || r->key == pSUBKEYUSAGE ) return r->u.usage; return (unsigned int)strtoul( r->u.value, NULL, 10 ); } static unsigned int get_parameter_uint( struct para_data_s *para, enum para_name key ) { return get_parameter_u32( para, key ); } static struct revocation_key * get_parameter_revkey( struct para_data_s *para, enum para_name key ) { struct para_data_s *r = get_parameter( para, key ); return r? &r->u.revkey : NULL; } static int proc_parameter_file( struct para_data_s *para, const char *fname, struct output_control_s *outctrl, int card ) { struct para_data_s *r; const char *s1, *s2, *s3; size_t n; char *p; int is_default = 0; int have_user_id = 0; int err, algo; /* Check that we have all required parameters. */ r = get_parameter( para, pKEYTYPE ); if(r) { algo = get_parameter_algo (para, pKEYTYPE, &is_default); if (openpgp_pk_test_algo2 (algo, PUBKEY_USAGE_SIG)) { log_error ("%s:%d: invalid algorithm\n", fname, r->lnr ); return -1; } } else { log_error ("%s: no Key-Type specified\n",fname); return -1; } err = parse_parameter_usage (fname, para, pKEYUSAGE); if (!err) { /* Default to algo capabilities if key-usage is not provided and no default algorithm has been requested. */ r = xmalloc_clear(sizeof(*r)); r->key = pKEYUSAGE; r->u.usage = (is_default ? (PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG) : openpgp_pk_algo_usage(algo)); append_to_parameter (para, r); } else if (err == -1) return -1; else { r = get_parameter (para, pKEYUSAGE); if (r && (r->u.usage & ~openpgp_pk_algo_usage (algo))) { log_error ("%s:%d: specified Key-Usage not allowed for algo %d\n", fname, r->lnr, algo); return -1; } } is_default = 0; r = get_parameter( para, pSUBKEYTYPE ); if(r) { algo = get_parameter_algo (para, pSUBKEYTYPE, &is_default); if (openpgp_pk_test_algo (algo)) { log_error ("%s:%d: invalid algorithm\n", fname, r->lnr ); return -1; } err = parse_parameter_usage (fname, para, pSUBKEYUSAGE); if (!err) { /* Default to algo capabilities if subkey-usage is not provided */ r = xmalloc_clear (sizeof(*r)); r->key = pSUBKEYUSAGE; r->u.usage = (is_default ? PUBKEY_USAGE_ENC : openpgp_pk_algo_usage (algo)); append_to_parameter (para, r); } else if (err == -1) return -1; else { r = get_parameter (para, pSUBKEYUSAGE); if (r && (r->u.usage & ~openpgp_pk_algo_usage (algo))) { log_error ("%s:%d: specified Subkey-Usage not allowed" " for algo %d\n", fname, r->lnr, algo); return -1; } } } if( get_parameter_value( para, pUSERID ) ) have_user_id=1; else { /* create the formatted user ID */ s1 = get_parameter_value( para, pNAMEREAL ); s2 = get_parameter_value( para, pNAMECOMMENT ); s3 = get_parameter_value( para, pNAMEEMAIL ); if( s1 || s2 || s3 ) { n = (s1?strlen(s1):0) + (s2?strlen(s2):0) + (s3?strlen(s3):0); r = xmalloc_clear( sizeof *r + n + 20 ); r->key = pUSERID; p = r->u.value; if( s1 ) p = stpcpy(p, s1 ); if( s2 ) p = stpcpy(stpcpy(stpcpy(p," ("), s2 ),")"); if( s3 ) p = stpcpy(stpcpy(stpcpy(p," <"), s3 ),">"); append_to_parameter (para, r); have_user_id=1; } } if(!have_user_id) { log_error("%s: no User-ID specified\n",fname); return -1; } /* Set preferences, if any. */ keygen_set_std_prefs(get_parameter_value( para, pPREFERENCES ), 0); /* Set keyserver, if any. */ s1=get_parameter_value( para, pKEYSERVER ); if(s1) { struct keyserver_spec *spec; spec = parse_keyserver_uri (s1, 1); if(spec) { free_keyserver_spec(spec); opt.def_keyserver_url=s1; } else { log_error("%s:%d: invalid keyserver url\n", fname, r->lnr ); return -1; } } /* Set revoker, if any. */ if (parse_revocation_key (fname, para, pREVOKER)) return -1; /* Make KEYCREATIONDATE from Creation-Date. */ r = get_parameter (para, pCREATIONDATE); if (r && *r->u.value) { u32 seconds; seconds = parse_creation_string (r->u.value); if (!seconds) { log_error ("%s:%d: invalid creation date\n", fname, r->lnr ); return -1; } r->u.creation = seconds; r->key = pKEYCREATIONDATE; /* Change that entry. */ } /* Make KEYEXPIRE from Expire-Date. */ r = get_parameter( para, pEXPIREDATE ); if( r && *r->u.value ) { u32 seconds; seconds = parse_expire_string( r->u.value ); if( seconds == (u32)-1 ) { log_error("%s:%d: invalid expire date\n", fname, r->lnr ); return -1; } r->u.expire = seconds; r->key = pKEYEXPIRE; /* change hat entry */ /* also set it for the subkey */ r = xmalloc_clear( sizeof *r + 20 ); r->key = pSUBKEYEXPIRE; r->u.expire = seconds; append_to_parameter (para, r); } do_generate_keypair( para, outctrl, card ); return 0; } /**************** * Kludge to allow non interactive key generation controlled * by a parameter file. * Note, that string parameters are expected to be in UTF-8 */ static void read_parameter_file( const char *fname ) { static struct { const char *name; enum para_name key; } keywords[] = { { "Key-Type", pKEYTYPE}, { "Key-Length", pKEYLENGTH }, { "Key-Curve", pKEYCURVE }, { "Key-Usage", pKEYUSAGE }, { "Subkey-Type", pSUBKEYTYPE }, { "Subkey-Length", pSUBKEYLENGTH }, { "Subkey-Curve", pSUBKEYCURVE }, { "Subkey-Usage", pSUBKEYUSAGE }, { "Name-Real", pNAMEREAL }, { "Name-Email", pNAMEEMAIL }, { "Name-Comment", pNAMECOMMENT }, { "Expire-Date", pEXPIREDATE }, { "Creation-Date", pCREATIONDATE }, { "Passphrase", pPASSPHRASE }, { "Preferences", pPREFERENCES }, { "Revoker", pREVOKER }, { "Handle", pHANDLE }, { "Keyserver", pKEYSERVER }, { NULL, 0 } }; IOBUF fp; byte *line; unsigned int maxlen, nline; char *p; int lnr; const char *err = NULL; struct para_data_s *para, *r; int i; struct output_control_s outctrl; memset( &outctrl, 0, sizeof( outctrl ) ); outctrl.pub.afx = new_armor_context (); if( !fname || !*fname) fname = "-"; fp = iobuf_open (fname); if (fp && is_secured_file (iobuf_get_fd (fp))) { iobuf_close (fp); fp = NULL; gpg_err_set_errno (EPERM); } if (!fp) { log_error (_("can't open '%s': %s\n"), fname, strerror(errno) ); return; } iobuf_ioctl (fp, IOBUF_IOCTL_NO_CACHE, 1, NULL); lnr = 0; err = NULL; para = NULL; maxlen = 1024; line = NULL; while ( iobuf_read_line (fp, &line, &nline, &maxlen) ) { char *keyword, *value; lnr++; if( !maxlen ) { err = "line too long"; break; } for( p = line; isspace(*(byte*)p); p++ ) ; if( !*p || *p == '#' ) continue; keyword = p; if( *keyword == '%' ) { for( ; !isspace(*(byte*)p); p++ ) ; if( *p ) *p++ = 0; for( ; isspace(*(byte*)p); p++ ) ; value = p; trim_trailing_ws( value, strlen(value) ); if( !ascii_strcasecmp( keyword, "%echo" ) ) log_info("%s\n", value ); else if( !ascii_strcasecmp( keyword, "%dry-run" ) ) outctrl.dryrun = 1; else if( !ascii_strcasecmp( keyword, "%ask-passphrase" ) ) ; /* Dummy for backward compatibility. */ else if( !ascii_strcasecmp( keyword, "%no-ask-passphrase" ) ) ; /* Dummy for backward compatibility. */ else if( !ascii_strcasecmp( keyword, "%no-protection" ) ) outctrl.keygen_flags |= KEYGEN_FLAG_NO_PROTECTION; else if( !ascii_strcasecmp( keyword, "%transient-key" ) ) outctrl.keygen_flags |= KEYGEN_FLAG_TRANSIENT_KEY; else if( !ascii_strcasecmp( keyword, "%commit" ) ) { outctrl.lnr = lnr; if (proc_parameter_file( para, fname, &outctrl, 0 )) print_status_key_not_created (get_parameter_value (para, pHANDLE)); release_parameter_list( para ); para = NULL; } else if( !ascii_strcasecmp( keyword, "%pubring" ) ) { if( outctrl.pub.fname && !strcmp( outctrl.pub.fname, value ) ) ; /* still the same file - ignore it */ else { xfree( outctrl.pub.newfname ); outctrl.pub.newfname = xstrdup( value ); outctrl.use_files = 1; } } else if( !ascii_strcasecmp( keyword, "%secring" ) ) { /* Ignore this command. */ } else log_info("skipping control '%s' (%s)\n", keyword, value ); continue; } if( !(p = strchr( p, ':' )) || p == keyword ) { err = "missing colon"; break; } if( *p ) *p++ = 0; for( ; isspace(*(byte*)p); p++ ) ; if( !*p ) { err = "missing argument"; break; } value = p; trim_trailing_ws( value, strlen(value) ); for(i=0; keywords[i].name; i++ ) { if( !ascii_strcasecmp( keywords[i].name, keyword ) ) break; } if( !keywords[i].name ) { err = "unknown keyword"; break; } if( keywords[i].key != pKEYTYPE && !para ) { err = "parameter block does not start with \"Key-Type\""; break; } if( keywords[i].key == pKEYTYPE && para ) { outctrl.lnr = lnr; if (proc_parameter_file( para, fname, &outctrl, 0 )) print_status_key_not_created (get_parameter_value (para, pHANDLE)); release_parameter_list( para ); para = NULL; } else { for( r = para; r; r = r->next ) { if( r->key == keywords[i].key ) break; } if( r ) { err = "duplicate keyword"; break; } } r = xmalloc_clear( sizeof *r + strlen( value ) ); r->lnr = lnr; r->key = keywords[i].key; strcpy( r->u.value, value ); r->next = para; para = r; } if( err ) log_error("%s:%d: %s\n", fname, lnr, err ); else if( iobuf_error (fp) ) { log_error("%s:%d: read error\n", fname, lnr); } else if( para ) { outctrl.lnr = lnr; if (proc_parameter_file( para, fname, &outctrl, 0 )) print_status_key_not_created (get_parameter_value (para, pHANDLE)); } if( outctrl.use_files ) { /* close open streams */ iobuf_close( outctrl.pub.stream ); /* Must invalidate that ugly cache to actually close it. */ if (outctrl.pub.fname) iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)outctrl.pub.fname); xfree( outctrl.pub.fname ); xfree( outctrl.pub.newfname ); } release_parameter_list( para ); iobuf_close (fp); release_armor_context (outctrl.pub.afx); } /* Helper for quick_generate_keypair. */ static struct para_data_s * quickgen_set_para (struct para_data_s *para, int for_subkey, int algo, int nbits, const char *curve) { struct para_data_s *r; r = xmalloc_clear (sizeof *r + 20); r->key = for_subkey? pSUBKEYUSAGE : pKEYUSAGE; strcpy (r->u.value, for_subkey ? "encrypt" : "sign"); r->next = para; para = r; r = xmalloc_clear (sizeof *r + 20); r->key = for_subkey? pSUBKEYTYPE : pKEYTYPE; sprintf (r->u.value, "%d", algo); r->next = para; para = r; if (curve) { r = xmalloc_clear (sizeof *r + strlen (curve)); r->key = for_subkey? pSUBKEYCURVE : pKEYCURVE; strcpy (r->u.value, curve); r->next = para; para = r; } else { r = xmalloc_clear (sizeof *r + 20); r->key = for_subkey? pSUBKEYLENGTH : pKEYLENGTH; sprintf (r->u.value, "%u", nbits); r->next = para; para = r; } return para; } /* * Unattended generation of a standard key. */ void quick_generate_keypair (const char *uid) { gpg_error_t err; struct para_data_s *para = NULL; struct para_data_s *r; struct output_control_s outctrl; int use_tty; memset (&outctrl, 0, sizeof outctrl); use_tty = (!opt.batch && !opt.answer_yes && !cpr_enabled () && gnupg_isatty (fileno (stdin)) && gnupg_isatty (fileno (stdout)) && gnupg_isatty (fileno (stderr))); r = xmalloc_clear (sizeof *r + strlen (uid)); r->key = pUSERID; strcpy (r->u.value, uid); r->next = para; para = r; uid = trim_spaces (r->u.value); if (!*uid || (!opt.allow_freeform_uid && !is_valid_user_id (uid))) { log_error (_("Key generation failed: %s\n"), gpg_strerror (GPG_ERR_INV_USER_ID)); goto leave; } /* If gpg is directly used on the console ask whether a key with the given user id shall really be created. */ if (use_tty) { tty_printf (_("About to create a key for:\n \"%s\"\n\n"), uid); if (!cpr_get_answer_is_yes_def ("quick_keygen.okay", _("Continue? (Y/n) "), 1)) goto leave; } /* Check whether such a user ID already exists. */ { KEYDB_HANDLE kdbhd; KEYDB_SEARCH_DESC desc; memset (&desc, 0, sizeof desc); desc.mode = KEYDB_SEARCH_MODE_EXACT; desc.u.name = uid; kdbhd = keydb_new (); err = keydb_search (kdbhd, &desc, 1, NULL); keydb_release (kdbhd); if (gpg_err_code (err) != GPG_ERR_NOT_FOUND) { log_info (_("A key for \"%s\" already exists\n"), uid); if (opt.answer_yes) ; else if (!use_tty || !cpr_get_answer_is_yes_def ("quick_keygen.force", _("Create anyway? (y/N) "), 0)) { log_inc_errorcount (); /* we used log_info */ goto leave; } log_info (_("creating anyway\n")); } } para = quickgen_set_para (para, 0, DEFAULT_STD_ALGO, DEFAULT_STD_KEYSIZE, DEFAULT_STD_CURVE); para = quickgen_set_para (para, 1, DEFAULT_STD_SUBALGO, DEFAULT_STD_SUBKEYSIZE, DEFAULT_STD_SUBCURVE); /* If the pinentry loopback mode is not and we have a static passphrase (i.e. set with --passphrase{,-fd,-file} while in batch mode), we use that passphrase for the new key. */ if (opt.pinentry_mode != PINENTRY_MODE_LOOPBACK && have_static_passphrase ()) { const char *s = get_static_passphrase (); r = xmalloc_clear (sizeof *r + strlen (s)); r->key = pPASSPHRASE; strcpy (r->u.value, s); r->next = para; para = r; } proc_parameter_file (para, "[internal]", &outctrl, 0); leave: release_parameter_list (para); } /* * Generate a keypair (fname is only used in batch mode) If * CARD_SERIALNO is not NULL the function will create the keys on an * OpenPGP Card. If CARD_BACKUP_KEY has been set and CARD_SERIALNO is * NOT NULL, the encryption key for the card is generated on the host, * imported to the card and a backup file created by gpg-agent. If * FULL is not set only the basic prompts are used (except for batch * mode). */ void generate_keypair (ctrl_t ctrl, int full, const char *fname, const char *card_serialno, int card_backup_key) { unsigned int nbits; char *uid = NULL; int algo; unsigned int use; int both = 0; u32 expire; struct para_data_s *para = NULL; struct para_data_s *r; struct output_control_s outctrl; #ifndef ENABLE_CARD_SUPPORT (void)card_backup_key; #endif memset( &outctrl, 0, sizeof( outctrl ) ); if (opt.batch && card_serialno) { /* We don't yet support unattended key generation. */ log_error (_("can't do this in batch mode\n")); return; } if (opt.batch) { read_parameter_file( fname ); return; } if (card_serialno) { #ifdef ENABLE_CARD_SUPPORT r = xcalloc (1, sizeof *r + strlen (card_serialno) ); r->key = pSERIALNO; strcpy( r->u.value, card_serialno); r->next = para; para = r; algo = PUBKEY_ALGO_RSA; r = xcalloc (1, sizeof *r + 20 ); r->key = pKEYTYPE; sprintf( r->u.value, "%d", algo ); r->next = para; para = r; r = xcalloc (1, sizeof *r + 20 ); r->key = pKEYUSAGE; strcpy (r->u.value, "sign"); r->next = para; para = r; r = xcalloc (1, sizeof *r + 20 ); r->key = pSUBKEYTYPE; sprintf( r->u.value, "%d", algo ); r->next = para; para = r; r = xcalloc (1, sizeof *r + 20 ); r->key = pSUBKEYUSAGE; strcpy (r->u.value, "encrypt"); r->next = para; para = r; r = xcalloc (1, sizeof *r + 20 ); r->key = pAUTHKEYTYPE; sprintf( r->u.value, "%d", algo ); r->next = para; para = r; if (card_backup_key) { r = xcalloc (1, sizeof *r + 1); r->key = pCARDBACKUPKEY; strcpy (r->u.value, "1"); r->next = para; para = r; } #endif /*ENABLE_CARD_SUPPORT*/ } else if (full) /* Full featured key generation. */ { int subkey_algo; char *curve = NULL; /* Fixme: To support creating a primary key by keygrip we better also define the keyword for the parameter file. Note that the subkey case will never be asserted if a keygrip has been given. */ algo = ask_algo (ctrl, 0, &subkey_algo, &use, NULL); if (subkey_algo) { /* Create primary and subkey at once. */ both = 1; if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH) { curve = ask_curve (&algo, both); r = xmalloc_clear( sizeof *r + 20 ); r->key = pKEYTYPE; sprintf( r->u.value, "%d", algo); r->next = para; para = r; nbits = 0; r = xmalloc_clear (sizeof *r + strlen (curve)); r->key = pKEYCURVE; strcpy (r->u.value, curve); r->next = para; para = r; } else { r = xmalloc_clear( sizeof *r + 20 ); r->key = pKEYTYPE; sprintf( r->u.value, "%d", algo); r->next = para; para = r; nbits = ask_keysize (algo, 0); r = xmalloc_clear( sizeof *r + 20 ); r->key = pKEYLENGTH; sprintf( r->u.value, "%u", nbits); r->next = para; para = r; } r = xmalloc_clear( sizeof *r + 20 ); r->key = pKEYUSAGE; strcpy( r->u.value, "sign" ); r->next = para; para = r; r = xmalloc_clear( sizeof *r + 20 ); r->key = pSUBKEYTYPE; sprintf( r->u.value, "%d", subkey_algo); r->next = para; para = r; r = xmalloc_clear( sizeof *r + 20 ); r->key = pSUBKEYUSAGE; strcpy( r->u.value, "encrypt" ); r->next = para; para = r; if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH) { if (algo == PUBKEY_ALGO_EDDSA && subkey_algo == PUBKEY_ALGO_ECDH) { /* Need to switch to a different curve for the encryption key. */ xfree (curve); curve = xstrdup ("Curve25519"); } r = xmalloc_clear (sizeof *r + strlen (curve)); r->key = pSUBKEYCURVE; strcpy (r->u.value, curve); r->next = para; para = r; } } else /* Create only a single key. */ { /* For ECC we need to ask for the curve before storing the algo because ask_curve may change the algo. */ if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH) { curve = ask_curve (&algo, 0); nbits = 0; r = xmalloc_clear (sizeof *r + strlen (curve)); r->key = pKEYCURVE; strcpy (r->u.value, curve); r->next = para; para = r; } r = xmalloc_clear( sizeof *r + 20 ); r->key = pKEYTYPE; sprintf( r->u.value, "%d", algo ); r->next = para; para = r; if (use) { r = xmalloc_clear( sizeof *r + 25 ); r->key = pKEYUSAGE; sprintf( r->u.value, "%s%s%s", (use & PUBKEY_USAGE_SIG)? "sign ":"", (use & PUBKEY_USAGE_ENC)? "encrypt ":"", (use & PUBKEY_USAGE_AUTH)? "auth":"" ); r->next = para; para = r; } nbits = 0; } if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH) { /* The curve has already been set. */ } else { nbits = ask_keysize (both? subkey_algo : algo, nbits); r = xmalloc_clear( sizeof *r + 20 ); r->key = both? pSUBKEYLENGTH : pKEYLENGTH; sprintf( r->u.value, "%u", nbits); r->next = para; para = r; } xfree (curve); } else /* Default key generation. */ { tty_printf ( _("Note: Use \"%s %s\"" " for a full featured key generation dialog.\n"), NAME_OF_INSTALLED_GPG, "--full-gen-key" ); para = quickgen_set_para (para, 0, DEFAULT_STD_ALGO, DEFAULT_STD_KEYSIZE, DEFAULT_STD_CURVE); para = quickgen_set_para (para, 1, DEFAULT_STD_SUBALGO, DEFAULT_STD_SUBKEYSIZE, DEFAULT_STD_SUBCURVE); } expire = full? ask_expire_interval (0, NULL) : 0; r = xcalloc (1, sizeof *r + 20); r->key = pKEYEXPIRE; r->u.expire = expire; r->next = para; para = r; r = xcalloc (1, sizeof *r + 20); r->key = pSUBKEYEXPIRE; r->u.expire = expire; r->next = para; para = r; uid = ask_user_id (0, full, NULL); if (!uid) { log_error(_("Key generation canceled.\n")); release_parameter_list( para ); return; } r = xcalloc (1, sizeof *r + strlen (uid)); r->key = pUSERID; strcpy (r->u.value, uid); r->next = para; para = r; proc_parameter_file (para, "[internal]", &outctrl, !!card_serialno); release_parameter_list (para); } #if 0 /* not required */ /* Generate a raw key and return it as a secret key packet. The function will ask for the passphrase and return a protected as well as an unprotected copy of a new secret key packet. 0 is returned on success and the caller must then free the returned values. */ static int generate_raw_key (int algo, unsigned int nbits, u32 created_at, PKT_secret_key **r_sk_unprotected, PKT_secret_key **r_sk_protected) { int rc; DEK *dek = NULL; STRING2KEY *s2k = NULL; PKT_secret_key *sk = NULL; int i; size_t nskey, npkey; gcry_sexp_t s_parms, s_key; int canceled; npkey = pubkey_get_npkey (algo); nskey = pubkey_get_nskey (algo); assert (nskey <= PUBKEY_MAX_NSKEY && npkey < nskey); if (nbits < 512) { nbits = 512; log_info (_("keysize invalid; using %u bits\n"), nbits ); } if ((nbits % 32)) { nbits = ((nbits + 31) / 32) * 32; log_info(_("keysize rounded up to %u bits\n"), nbits ); } dek = do_ask_passphrase (&s2k, 1, &canceled); if (canceled) { rc = gpg_error (GPG_ERR_CANCELED); goto leave; } sk = xmalloc_clear (sizeof *sk); sk->timestamp = created_at; sk->version = 4; sk->pubkey_algo = algo; if ( !is_RSA (algo) ) { log_error ("only RSA is supported for offline generated keys\n"); rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED); goto leave; } rc = gcry_sexp_build (&s_parms, NULL, "(genkey(rsa(nbits %d)))", (int)nbits); if (rc) log_bug ("gcry_sexp_build failed: %s\n", gpg_strerror (rc)); rc = gcry_pk_genkey (&s_key, s_parms); gcry_sexp_release (s_parms); if (rc) { log_error ("gcry_pk_genkey failed: %s\n", gpg_strerror (rc) ); goto leave; } rc = key_from_sexp (sk->skey, s_key, "private-key", "nedpqu"); gcry_sexp_release (s_key); if (rc) { log_error ("key_from_sexp failed: %s\n", gpg_strerror (rc) ); goto leave; } for (i=npkey; i < nskey; i++) sk->csum += checksum_mpi (sk->skey[i]); if (r_sk_unprotected) *r_sk_unprotected = copy_secret_key (NULL, sk); rc = genhelp_protect (dek, s2k, sk); if (rc) goto leave; if (r_sk_protected) { *r_sk_protected = sk; sk = NULL; } leave: if (sk) free_secret_key (sk); xfree (dek); xfree (s2k); return rc; } #endif /* ENABLE_CARD_SUPPORT */ /* Create and delete a dummy packet to start off a list of kbnodes. */ static void start_tree(KBNODE *tree) { PACKET *pkt; pkt=xmalloc_clear(sizeof(*pkt)); pkt->pkttype=PKT_NONE; *tree=new_kbnode(pkt); delete_kbnode(*tree); } static void do_generate_keypair (struct para_data_s *para, struct output_control_s *outctrl, int card) { gpg_error_t err; KBNODE pub_root = NULL; const char *s; PKT_public_key *pri_psk = NULL; PKT_public_key *sub_psk = NULL; struct revocation_key *revkey; int did_sub = 0; u32 timestamp; char *cache_nonce = NULL; if (outctrl->dryrun) { log_info("dry-run mode - key generation skipped\n"); return; } if ( outctrl->use_files ) { if ( outctrl->pub.newfname ) { iobuf_close(outctrl->pub.stream); outctrl->pub.stream = NULL; if (outctrl->pub.fname) iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)outctrl->pub.fname); xfree( outctrl->pub.fname ); outctrl->pub.fname = outctrl->pub.newfname; outctrl->pub.newfname = NULL; if (is_secured_filename (outctrl->pub.fname) ) { outctrl->pub.stream = NULL; gpg_err_set_errno (EPERM); } else outctrl->pub.stream = iobuf_create (outctrl->pub.fname, 0); if (!outctrl->pub.stream) { log_error(_("can't create '%s': %s\n"), outctrl->pub.newfname, strerror(errno) ); return; } if (opt.armor) { outctrl->pub.afx->what = 1; push_armor_filter (outctrl->pub.afx, outctrl->pub.stream); } } assert( outctrl->pub.stream ); if (opt.verbose) log_info (_("writing public key to '%s'\n"), outctrl->pub.fname ); } /* We create the packets as a tree of kbnodes. Because the structure we create is known in advance we simply generate a linked list. The first packet is a dummy packet which we flag as deleted. The very first packet must always be a KEY packet. */ start_tree (&pub_root); timestamp = get_parameter_u32 (para, pKEYCREATIONDATE); if (!timestamp) timestamp = make_timestamp (); /* Note that, depending on the backend (i.e. the used scdaemon version), the card key generation may update TIMESTAMP for each key. Thus we need to pass TIMESTAMP to all signing function to make sure that the binding signature is done using the timestamp of the corresponding (sub)key and not that of the primary key. An alternative implementation could tell the signing function the node of the subkey but that is more work than just to pass the current timestamp. */ if (!card) err = do_create (get_parameter_algo( para, pKEYTYPE, NULL ), get_parameter_uint( para, pKEYLENGTH ), get_parameter_value (para, pKEYCURVE), pub_root, timestamp, get_parameter_u32( para, pKEYEXPIRE ), 0, outctrl->keygen_flags, get_parameter_passphrase (para), &cache_nonce); else err = gen_card_key (PUBKEY_ALGO_RSA, 1, 1, pub_root, ×tamp, get_parameter_u32 (para, pKEYEXPIRE)); /* Get the pointer to the generated public key packet. */ if (!err) { pri_psk = pub_root->next->pkt->pkt.public_key; assert (pri_psk); } if (!err && (revkey = get_parameter_revkey (para, pREVOKER))) err = write_direct_sig (pub_root, pri_psk, revkey, timestamp, cache_nonce); if (!err && (s = get_parameter_value (para, pUSERID))) { write_uid (pub_root, s ); err = write_selfsigs (pub_root, pri_psk, get_parameter_uint (para, pKEYUSAGE), timestamp, cache_nonce); } /* Write the auth key to the card before the encryption key. This is a partial workaround for a PGP bug (as of this writing, all versions including 8.1), that causes it to try and encrypt to the most recent subkey regardless of whether that subkey is actually an encryption type. In this case, the auth key is an RSA key so it succeeds. */ if (!err && card && get_parameter (para, pAUTHKEYTYPE)) { err = gen_card_key (PUBKEY_ALGO_RSA, 3, 0, pub_root, ×tamp, get_parameter_u32 (para, pKEYEXPIRE)); if (!err) err = write_keybinding (pub_root, pri_psk, NULL, PUBKEY_USAGE_AUTH, timestamp, cache_nonce); } if (!err && get_parameter (para, pSUBKEYTYPE)) { sub_psk = NULL; if (!card) { err = do_create (get_parameter_algo (para, pSUBKEYTYPE, NULL), get_parameter_uint (para, pSUBKEYLENGTH), get_parameter_value (para, pSUBKEYCURVE), pub_root, timestamp, get_parameter_u32 (para, pSUBKEYEXPIRE), 1, outctrl->keygen_flags, get_parameter_passphrase (para), &cache_nonce); /* Get the pointer to the generated public subkey packet. */ if (!err) { kbnode_t node; for (node = pub_root; node; node = node->next) if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) sub_psk = node->pkt->pkt.public_key; assert (sub_psk); } } else { if ((s = get_parameter_value (para, pCARDBACKUPKEY))) { /* A backup of the encryption key has been requested. Generate the key in software and import it then to the card. Write a backup file. */ err = gen_card_key_with_backup (PUBKEY_ALGO_RSA, 2, 0, pub_root, timestamp, get_parameter_u32 (para, pKEYEXPIRE), para); } else { err = gen_card_key (PUBKEY_ALGO_RSA, 2, 0, pub_root, ×tamp, get_parameter_u32 (para, pKEYEXPIRE)); } } if (!err) err = write_keybinding (pub_root, pri_psk, sub_psk, get_parameter_uint (para, pSUBKEYUSAGE), timestamp, cache_nonce); did_sub = 1; } if (!err && outctrl->use_files) /* Direct write to specified files. */ { err = write_keyblock (outctrl->pub.stream, pub_root); if (err) log_error ("can't write public key: %s\n", gpg_strerror (err)); } else if (!err) /* Write to the standard keyrings. */ { KEYDB_HANDLE pub_hd = keydb_new (); err = keydb_locate_writable (pub_hd, NULL); if (err) log_error (_("no writable public keyring found: %s\n"), gpg_strerror (err)); if (!err && opt.verbose) { log_info (_("writing public key to '%s'\n"), keydb_get_resource_name (pub_hd)); } if (!err) { err = keydb_insert_keyblock (pub_hd, pub_root); if (err) log_error (_("error writing public keyring '%s': %s\n"), keydb_get_resource_name (pub_hd), gpg_strerror (err)); } keydb_release (pub_hd); if (!err) { int no_enc_rsa; PKT_public_key *pk; no_enc_rsa = ((get_parameter_algo (para, pKEYTYPE, NULL) == PUBKEY_ALGO_RSA) && get_parameter_uint (para, pKEYUSAGE) && !((get_parameter_uint (para, pKEYUSAGE) & PUBKEY_USAGE_ENC)) ); pk = find_kbnode (pub_root, PKT_PUBLIC_KEY)->pkt->pkt.public_key; keyid_from_pk (pk, pk->main_keyid); register_trusted_keyid (pk->main_keyid); update_ownertrust (pk, ((get_ownertrust (pk) & ~TRUST_MASK) | TRUST_ULTIMATE )); gen_standard_revoke (pk, cache_nonce); if (!opt.batch) { tty_printf (_("public and secret key created and signed.\n") ); tty_printf ("\n"); list_keyblock_direct (pub_root, 0, 1, 1); } if (!opt.batch && (get_parameter_algo (para, pKEYTYPE, NULL) == PUBKEY_ALGO_DSA || no_enc_rsa ) && !get_parameter (para, pSUBKEYTYPE) ) { tty_printf(_("Note that this key cannot be used for " "encryption. You may want to use\n" "the command \"--edit-key\" to generate a " "subkey for this purpose.\n") ); } } } if (err) { if (opt.batch) log_error ("key generation failed: %s\n", gpg_strerror (err) ); else tty_printf (_("Key generation failed: %s\n"), gpg_strerror (err) ); write_status_error (card? "card_key_generate":"key_generate", err); print_status_key_not_created ( get_parameter_value (para, pHANDLE) ); } else { PKT_public_key *pk = find_kbnode (pub_root, PKT_PUBLIC_KEY)->pkt->pkt.public_key; print_status_key_created (did_sub? 'B':'P', pk, get_parameter_value (para, pHANDLE)); } release_kbnode (pub_root); xfree (cache_nonce); } /* Add a new subkey to an existing key. Returns 0 if a new key has been generated and put into the keyblocks. */ gpg_error_t generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock) { gpg_error_t err = 0; kbnode_t node; PKT_public_key *pri_psk = NULL; PKT_public_key *sub_psk = NULL; int algo; unsigned int use; u32 expire; unsigned int nbits = 0; char *curve = NULL; u32 cur_time; char *hexgrip = NULL; char *serialno = NULL; /* Break out the primary key. */ node = find_kbnode (keyblock, PKT_PUBLIC_KEY); if (!node) { log_error ("Oops; primary key missing in keyblock!\n"); err = gpg_error (GPG_ERR_BUG); goto leave; } pri_psk = node->pkt->pkt.public_key; cur_time = make_timestamp (); if (pri_psk->timestamp > cur_time) { ulong d = pri_psk->timestamp - cur_time; log_info ( d==1 ? _("key has been created %lu second " "in future (time warp or clock problem)\n") : _("key has been created %lu seconds " "in future (time warp or clock problem)\n"), d ); if (!opt.ignore_time_conflict) { err = gpg_error (GPG_ERR_TIME_CONFLICT); goto leave; } } if (pri_psk->version < 4) { log_info (_("Note: creating subkeys for v3 keys " "is not OpenPGP compliant\n")); err = gpg_error (GPG_ERR_CONFLICT); goto leave; } err = hexkeygrip_from_pk (pri_psk, &hexgrip); if (err) goto leave; if (agent_get_keyinfo (NULL, hexgrip, &serialno)) { tty_printf (_("Secret parts of primary key are not available.\n")); goto leave; } if (serialno) tty_printf (_("Secret parts of primary key are stored on-card.\n")); xfree (hexgrip); hexgrip = NULL; algo = ask_algo (ctrl, 1, NULL, &use, &hexgrip); assert (algo); if (hexgrip) nbits = 0; else if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_EDDSA || algo == PUBKEY_ALGO_ECDH) curve = ask_curve (&algo, 0); else nbits = ask_keysize (algo, 0); expire = ask_expire_interval (0, NULL); if (!cpr_enabled() && !cpr_get_answer_is_yes("keygen.sub.okay", _("Really create? (y/N) "))) { err = gpg_error (GPG_ERR_CANCELED); goto leave; } if (hexgrip) err = do_create_from_keygrip (ctrl, algo, hexgrip, keyblock, cur_time, expire, 1); else err = do_create (algo, nbits, curve, keyblock, cur_time, expire, 1, 0, NULL, NULL); if (err) goto leave; /* Get the pointer to the generated public subkey packet. */ for (node = keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) sub_psk = node->pkt->pkt.public_key; /* Write the binding signature. */ err = write_keybinding (keyblock, pri_psk, sub_psk, use, cur_time, NULL); if (err) goto leave; write_status_text (STATUS_KEY_CREATED, "S"); leave: xfree (curve); xfree (hexgrip); xfree (serialno); if (err) log_error (_("Key generation failed: %s\n"), gpg_strerror (err) ); return err; } #ifdef ENABLE_CARD_SUPPORT /* Generate a subkey on a card. */ gpg_error_t generate_card_subkeypair (kbnode_t pub_keyblock, int keyno, const char *serialno) { gpg_error_t err = 0; kbnode_t node; PKT_public_key *pri_pk = NULL; int algo; unsigned int use; u32 expire; u32 cur_time; struct para_data_s *para = NULL; assert (keyno >= 1 && keyno <= 3); para = xtrycalloc (1, sizeof *para + strlen (serialno) ); if (!para) { err = gpg_error_from_syserror (); goto leave; } para->key = pSERIALNO; strcpy (para->u.value, serialno); /* Break out the primary secret key */ node = find_kbnode (pub_keyblock, PKT_PUBLIC_KEY); if (!node) { log_error ("Oops; publkic key lost!\n"); err = gpg_error (GPG_ERR_INTERNAL); goto leave; } pri_pk = node->pkt->pkt.public_key; cur_time = make_timestamp(); if (pri_pk->timestamp > cur_time) { ulong d = pri_pk->timestamp - cur_time; log_info (d==1 ? _("key has been created %lu second " "in future (time warp or clock problem)\n") : _("key has been created %lu seconds " "in future (time warp or clock problem)\n"), d ); if (!opt.ignore_time_conflict) { err = gpg_error (GPG_ERR_TIME_CONFLICT); goto leave; } } if (pri_pk->version < 4) { log_info (_("Note: creating subkeys for v3 keys " "is not OpenPGP compliant\n")); err = gpg_error (GPG_ERR_NOT_SUPPORTED); goto leave; } algo = PUBKEY_ALGO_RSA; expire = ask_expire_interval (0, NULL); if (keyno == 1) use = PUBKEY_USAGE_SIG; else if (keyno == 2) use = PUBKEY_USAGE_ENC; else use = PUBKEY_USAGE_AUTH; if (!cpr_enabled() && !cpr_get_answer_is_yes("keygen.cardsub.okay", _("Really create? (y/N) "))) { err = gpg_error (GPG_ERR_CANCELED); goto leave; } /* Note, that depending on the backend, the card key generation may update CUR_TIME. */ err = gen_card_key (algo, keyno, 0, pub_keyblock, &cur_time, expire); /* Get the pointer to the generated public subkey packet. */ if (!err) { PKT_public_key *sub_pk = NULL; for (node = pub_keyblock; node; node = node->next) if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY) sub_pk = node->pkt->pkt.public_key; assert (sub_pk); err = write_keybinding (pub_keyblock, pri_pk, sub_pk, use, cur_time, NULL); } leave: if (err) log_error (_("Key generation failed: %s\n"), gpg_strerror (err) ); else write_status_text (STATUS_KEY_CREATED, "S"); release_parameter_list (para); return err; } #endif /* !ENABLE_CARD_SUPPORT */ /* * Write a keyblock to an output stream */ static int write_keyblock( IOBUF out, KBNODE node ) { for( ; node ; node = node->next ) { if(!is_deleted_kbnode(node)) { int rc = build_packet( out, node->pkt ); if( rc ) { log_error("build_packet(%d) failed: %s\n", node->pkt->pkttype, gpg_strerror (rc) ); return rc; } } } return 0; } /* Note that timestamp is an in/out arg. */ static gpg_error_t gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root, u32 *timestamp, u32 expireval) { #ifdef ENABLE_CARD_SUPPORT gpg_error_t err; struct agent_card_genkey_s info; PACKET *pkt; PKT_public_key *pk; if (algo != PUBKEY_ALGO_RSA) return gpg_error (GPG_ERR_PUBKEY_ALGO); pk = xtrycalloc (1, sizeof *pk ); if (!pk) return gpg_error_from_syserror (); pkt = xtrycalloc (1, sizeof *pkt); if (!pkt) { xfree (pk); return gpg_error_from_syserror (); } /* Note: SCD knows the serialnumber, thus there is no point in passing it. */ err = agent_scd_genkey (&info, keyno, 1, NULL, *timestamp); /* The code below is not used because we force creation of * the a card key (3rd arg). * if (gpg_err_code (rc) == GPG_ERR_EEXIST) * { * tty_printf ("\n"); * log_error ("WARNING: key does already exists!\n"); * tty_printf ("\n"); * if ( cpr_get_answer_is_yes( "keygen.card.replace_key", * _("Replace existing key? "))) * rc = agent_scd_genkey (&info, keyno, 1); * } */ if (!err && (!info.n || !info.e)) { log_error ("communication error with SCD\n"); gcry_mpi_release (info.n); gcry_mpi_release (info.e); err = gpg_error (GPG_ERR_GENERAL); } if (err) { log_error ("key generation failed: %s\n", gpg_strerror (err)); xfree (pkt); xfree (pk); return err; } /* Send the learn command so that the agent creates a shadow key for card key. We need to do that now so that we are able to create the self-signatures. */ err = agent_scd_learn (NULL, 0); if (err) { /* Oops: Card removed during generation. */ log_error (_("OpenPGP card not available: %s\n"), gpg_strerror (err)); xfree (pkt); xfree (pk); return err; } if (*timestamp != info.created_at) log_info ("NOTE: the key does not use the suggested creation date\n"); *timestamp = info.created_at; pk->timestamp = info.created_at; pk->version = 4; if (expireval) pk->expiredate = pk->timestamp + expireval; pk->pubkey_algo = algo; pk->pkey[0] = info.n; pk->pkey[1] = info.e; pkt->pkttype = is_primary ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY; pkt->pkt.public_key = pk; add_kbnode (pub_root, new_kbnode (pkt)); return 0; #else (void)algo; (void)keyno; (void)is_primary; (void)pub_root; (void)timestamp; (void)expireval; return gpg_error (GPG_ERR_NOT_SUPPORTED); #endif /*!ENABLE_CARD_SUPPORT*/ } static int gen_card_key_with_backup (int algo, int keyno, int is_primary, KBNODE pub_root, u32 timestamp, u32 expireval, struct para_data_s *para) { #if ENABLE_CARD_SUPPORT && 0 /* FIXME: Move this to gpg-agent. */ int rc; const char *s; PACKET *pkt; PKT_secret_key *sk, *sk_unprotected = NULL, *sk_protected = NULL; PKT_public_key *pk; size_t n; int i; unsigned int nbits; /* Get the size of the key directly from the card. */ { struct agent_card_info_s info; memset (&info, 0, sizeof info); if (!agent_scd_getattr ("KEY-ATTR", &info) && info.key_attr[1].algo) nbits = info.key_attr[1].nbits; else nbits = 1024; /* All pre-v2.0 cards. */ agent_release_card_info (&info); } /* Create a key of this size in memory. */ rc = generate_raw_key (algo, nbits, timestamp, &sk_unprotected, &sk_protected); if (rc) return rc; /* Store the key to the card. */ rc = save_unprotected_key_to_card (sk_unprotected, keyno); if (rc) { log_error (_("storing key onto card failed: %s\n"), gpg_strerror (rc)); free_secret_key (sk_unprotected); free_secret_key (sk_protected); write_status_errcode ("save_key_to_card", rc); return rc; } /* Get rid of the secret key parameters and store the serial numer. */ sk = sk_unprotected; n = pubkey_get_nskey (sk->pubkey_algo); for (i=pubkey_get_npkey (sk->pubkey_algo); i < n; i++) { gcry_mpi_release (sk->skey[i]); sk->skey[i] = NULL; } i = pubkey_get_npkey (sk->pubkey_algo); sk->skey[i] = gcry_mpi_set_opaque (NULL, xstrdup ("dummydata"), 10*8); sk->is_protected = 1; sk->protect.s2k.mode = 1002; s = get_parameter_value (para, pSERIALNO); assert (s); for (sk->protect.ivlen=0; sk->protect.ivlen < 16 && *s && s[1]; sk->protect.ivlen++, s += 2) sk->protect.iv[sk->protect.ivlen] = xtoi_2 (s); /* Now write the *protected* secret key to the file. */ { char name_buffer[50]; char *fname; IOBUF fp; mode_t oldmask; keyid_from_sk (sk, NULL); snprintf (name_buffer, sizeof name_buffer, "sk_%08lX%08lX.gpg", (ulong)sk->keyid[0], (ulong)sk->keyid[1]); fname = make_filename (backup_dir, name_buffer, NULL); /* Note that the umask call is not anymore needed because iobuf_create now takes care of it. However, it does not harm and thus we keep it. */ oldmask = umask (077); if (is_secured_filename (fname)) { fp = NULL; gpg_err_set_errno (EPERM); } else fp = iobuf_create (fname, 1); umask (oldmask); if (!fp) { rc = gpg_error_from_syserror (); log_error (_("can't create backup file '%s': %s\n"), fname, strerror(errno) ); xfree (fname); free_secret_key (sk_unprotected); free_secret_key (sk_protected); return rc; } pkt = xcalloc (1, sizeof *pkt); pkt->pkttype = PKT_SECRET_KEY; pkt->pkt.secret_key = sk_protected; sk_protected = NULL; rc = build_packet (fp, pkt); if (rc) { log_error("build packet failed: %s\n", gpg_strerror (rc)); iobuf_cancel (fp); } else { unsigned char array[MAX_FINGERPRINT_LEN]; char *fprbuf, *p; iobuf_close (fp); iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname); log_info (_("Note: backup of card key saved to '%s'\n"), fname); fingerprint_from_sk (sk, array, &n); p = fprbuf = xmalloc (MAX_FINGERPRINT_LEN*2 + 1 + 1); for (i=0; i < n ; i++, p += 2) sprintf (p, "%02X", array[i]); *p++ = ' '; *p = 0; write_status_text_and_buffer (STATUS_BACKUP_KEY_CREATED, fprbuf, fname, strlen (fname), 0); xfree (fprbuf); } free_packet (pkt); xfree (pkt); xfree (fname); if (rc) { free_secret_key (sk_unprotected); return rc; } } /* Create the public key from the secret key. */ pk = xcalloc (1, sizeof *pk ); pk->timestamp = sk->timestamp; pk->version = sk->version; if (expireval) pk->expiredate = sk->expiredate = sk->timestamp + expireval; pk->pubkey_algo = sk->pubkey_algo; n = pubkey_get_npkey (sk->pubkey_algo); for (i=0; i < n; i++) pk->pkey[i] = mpi_copy (sk->skey[i]); /* Build packets and add them to the node lists. */ pkt = xcalloc (1,sizeof *pkt); pkt->pkttype = is_primary ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY; pkt->pkt.public_key = pk; add_kbnode(pub_root, new_kbnode( pkt )); pkt = xcalloc (1,sizeof *pkt); pkt->pkttype = is_primary ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY; pkt->pkt.secret_key = sk; add_kbnode(sec_root, new_kbnode( pkt )); return 0; #else # if __GCC__ && ENABLE_CARD_SUPPORT # warning Card support still missing # endif (void)algo; (void)keyno; (void)is_primary; (void)pub_root; (void)timestamp; (void)expireval; (void)para; return gpg_error (GPG_ERR_NOT_SUPPORTED); #endif /*!ENABLE_CARD_SUPPORT*/ } #if 0 int save_unprotected_key_to_card (PKT_public_key *sk, int keyno) { int rc; unsigned char *rsa_n = NULL; unsigned char *rsa_e = NULL; unsigned char *rsa_p = NULL; unsigned char *rsa_q = NULL; size_t rsa_n_len, rsa_e_len, rsa_p_len, rsa_q_len; unsigned char *sexp = NULL; unsigned char *p; char numbuf[55], numbuf2[50]; assert (is_RSA (sk->pubkey_algo)); assert (!sk->is_protected); /* Copy the parameters into straight buffers. */ gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_n, &rsa_n_len, sk->skey[0]); gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_e, &rsa_e_len, sk->skey[1]); gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_p, &rsa_p_len, sk->skey[3]); gcry_mpi_aprint (GCRYMPI_FMT_USG, &rsa_q, &rsa_q_len, sk->skey[4]); if (!rsa_n || !rsa_e || !rsa_p || !rsa_q) { rc = GPG_ERR_INV_ARG; goto leave; } /* Put the key into an S-expression. */ sexp = p = xmalloc_secure (30 + rsa_n_len + rsa_e_len + rsa_p_len + rsa_q_len + 4*sizeof (numbuf) + 25 + sizeof(numbuf) + 20); p = stpcpy (p,"(11:private-key(3:rsa(1:n"); sprintf (numbuf, "%u:", (unsigned int)rsa_n_len); p = stpcpy (p, numbuf); memcpy (p, rsa_n, rsa_n_len); p += rsa_n_len; sprintf (numbuf, ")(1:e%u:", (unsigned int)rsa_e_len); p = stpcpy (p, numbuf); memcpy (p, rsa_e, rsa_e_len); p += rsa_e_len; sprintf (numbuf, ")(1:p%u:", (unsigned int)rsa_p_len); p = stpcpy (p, numbuf); memcpy (p, rsa_p, rsa_p_len); p += rsa_p_len; sprintf (numbuf, ")(1:q%u:", (unsigned int)rsa_q_len); p = stpcpy (p, numbuf); memcpy (p, rsa_q, rsa_q_len); p += rsa_q_len; p = stpcpy (p,"))(10:created-at"); sprintf (numbuf2, "%lu", (unsigned long)sk->timestamp); sprintf (numbuf, "%lu:", (unsigned long)strlen (numbuf2)); p = stpcpy (stpcpy (stpcpy (p, numbuf), numbuf2), "))"); /* Fixme: Unfortunately we don't have the serialnumber available - thus we can't pass it down to the agent. */ rc = agent_scd_writekey (keyno, NULL, sexp, p - sexp); leave: xfree (sexp); xfree (rsa_n); xfree (rsa_e); xfree (rsa_p); xfree (rsa_q); return rc; } #endif /*ENABLE_CARD_SUPPORT*/ diff --git a/g10/main.h b/g10/main.h index 01eeb7ffa..a89f71113 100644 --- a/g10/main.h +++ b/g10/main.h @@ -1,405 +1,407 @@ /* main.h * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, * 2008, 2009, 2010 Free Software Foundation, Inc. * * 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 . */ #ifndef G10_MAIN_H #define G10_MAIN_H #include "types.h" #include "iobuf.h" #include "keydb.h" #include "util.h" /* It could be argued that the default cipher should be 3DES rather than AES128, and the default compression should be 0 (i.e. uncompressed) rather than 1 (zip). However, the real world issues of speed and size come into play here. */ #if GPG_USE_AES128 # define DEFAULT_CIPHER_ALGO CIPHER_ALGO_AES #elif GPG_USE_CAST5 # define DEFAULT_CIPHER_ALGO CIPHER_ALGO_CAST5 #else # define DEFAULT_CIPHER_ALGO CIPHER_ALGO_3DES #endif #define DEFAULT_DIGEST_ALGO ((GNUPG)? DIGEST_ALGO_SHA256:DIGEST_ALGO_SHA1) #define DEFAULT_S2K_DIGEST_ALGO DIGEST_ALGO_SHA1 #ifdef HAVE_ZIP # define DEFAULT_COMPRESS_ALGO COMPRESS_ALGO_ZIP #else # define DEFAULT_COMPRESS_ALGO COMPRESS_ALGO_NONE #endif #define S2K_DIGEST_ALGO (opt.s2k_digest_algo?opt.s2k_digest_algo:DEFAULT_S2K_DIGEST_ALGO) /* Various data objects. */ typedef struct { int header_okay; PK_LIST pk_list; DEK *symkey_dek; STRING2KEY *symkey_s2k; cipher_filter_context_t cfx; } encrypt_filter_context_t; struct groupitem { char *name; strlist_t values; struct groupitem *next; }; /*-- gpg.c --*/ extern int g10_errors_seen; #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 ) void g10_exit(int rc) __attribute__ ((noreturn)); #else void g10_exit(int rc); #endif void print_pubkey_algo_note (pubkey_algo_t algo); void print_cipher_algo_note (cipher_algo_t algo); void print_digest_algo_note (digest_algo_t algo); void print_md5_rejected_note (void); /*-- armor.c --*/ char *make_radix64_string( const byte *data, size_t len ); /*-- misc.c --*/ void trap_unaligned(void); int disable_core_dumps(void); void register_secured_file (const char *fname); void unregister_secured_file (const char *fname); int is_secured_file (int fd); int is_secured_filename (const char *fname); u16 checksum_u16( unsigned n ); u16 checksum( byte *p, unsigned n ); u16 checksum_mpi( gcry_mpi_t a ); u32 buffer_to_u32( const byte *buffer ); const byte *get_session_marker( size_t *rlen ); enum gcry_cipher_algos map_cipher_openpgp_to_gcry (cipher_algo_t algo); #define openpgp_cipher_open(_a,_b,_c,_d) \ gcry_cipher_open((_a),map_cipher_openpgp_to_gcry((_b)),(_c),(_d)) #define openpgp_cipher_get_algo_keylen(_a) \ gcry_cipher_get_algo_keylen(map_cipher_openpgp_to_gcry((_a))) #define openpgp_cipher_get_algo_blklen(_a) \ gcry_cipher_get_algo_blklen(map_cipher_openpgp_to_gcry((_a))) int openpgp_cipher_blocklen (cipher_algo_t algo); int openpgp_cipher_test_algo(cipher_algo_t algo); const char *openpgp_cipher_algo_name (cipher_algo_t algo); pubkey_algo_t map_pk_gcry_to_openpgp (enum gcry_pk_algos algo); int openpgp_pk_test_algo (pubkey_algo_t algo); int openpgp_pk_test_algo2 (pubkey_algo_t algo, unsigned int use); int openpgp_pk_algo_usage ( int algo ); const char *openpgp_pk_algo_name (pubkey_algo_t algo); enum gcry_md_algos map_md_openpgp_to_gcry (digest_algo_t algo); int openpgp_md_test_algo (digest_algo_t algo); const char *openpgp_md_algo_name (int algo); struct expando_args { PKT_public_key *pk; PKT_public_key *pksk; byte imagetype; int validity_info; const char *validity_string; const byte *namehash; }; char *pct_expando(const char *string,struct expando_args *args); void deprecated_warning(const char *configname,unsigned int configlineno, const char *option,const char *repl1,const char *repl2); void deprecated_command (const char *name); void obsolete_option (const char *configname, unsigned int configlineno, const char *name); void obsolete_scdaemon_option (const char *configname, unsigned int configlineno, const char *name); int string_to_cipher_algo (const char *string); int string_to_digest_algo (const char *string); const char *compress_algo_to_string(int algo); int string_to_compress_algo(const char *string); int check_compress_algo(int algo); int default_cipher_algo(void); int default_compress_algo(void); const char *compliance_option_string(void); void compliance_failure(void); struct parse_options { char *name; unsigned int bit; char **value; char *help; }; char *optsep(char **stringp); char *argsplit(char *string); int parse_options(char *str,unsigned int *options, struct parse_options *opts,int noisy); const char *get_libexecdir (void); int path_access(const char *file,int mode); int pubkey_get_npkey (pubkey_algo_t algo); int pubkey_get_nskey (pubkey_algo_t algo); int pubkey_get_nsig (pubkey_algo_t algo); int pubkey_get_nenc (pubkey_algo_t algo); /* Temporary helpers. */ unsigned int pubkey_nbits( int algo, gcry_mpi_t *pkey ); int mpi_print (estream_t stream, gcry_mpi_t a, int mode); unsigned int ecdsa_qbits_from_Q (unsigned int qbits); /*-- status.c --*/ void set_status_fd ( int fd ); int is_status_enabled ( void ); void write_status ( int no ); void write_status_error (const char *where, gpg_error_t err); void write_status_errcode (const char *where, int errcode); void write_status_text ( int no, const char *text ); void write_status_strings (int no, const char *text, ...) GNUPG_GCC_A_SENTINEL(0); void write_status_buffer ( int no, const char *buffer, size_t len, int wrap ); void write_status_text_and_buffer ( int no, const char *text, const char *buffer, size_t len, int wrap ); void write_status_begin_signing (gcry_md_hd_t md); int cpr_enabled(void); char *cpr_get( const char *keyword, const char *prompt ); char *cpr_get_no_help( const char *keyword, const char *prompt ); char *cpr_get_utf8( const char *keyword, const char *prompt ); char *cpr_get_hidden( const char *keyword, const char *prompt ); void cpr_kill_prompt(void); int cpr_get_answer_is_yes_def (const char *keyword, const char *prompt, int def_yes); int cpr_get_answer_is_yes( const char *keyword, const char *prompt ); int cpr_get_answer_yes_no_quit( const char *keyword, const char *prompt ); int cpr_get_answer_okay_cancel (const char *keyword, const char *prompt, int def_answer); /*-- helptext.c --*/ void display_online_help( const char *keyword ); /*-- encode.c --*/ int setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek); int encrypt_symmetric (const char *filename ); int encrypt_store (const char *filename ); int encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename, strlist_t remusr, int use_symkey, pk_list_t provided_keys, int outputfd); void encrypt_crypt_files (ctrl_t ctrl, int nfiles, char **files, strlist_t remusr); int encrypt_filter (void *opaque, int control, iobuf_t a, byte *buf, size_t *ret_len); /*-- sign.c --*/ int complete_sig (PKT_signature *sig, PKT_public_key *pksk, gcry_md_hd_t md, const char *cache_nonce); int sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr, int do_encrypt, strlist_t remusr, const char *outfile ); int clearsign_file( const char *fname, strlist_t locusr, const char *outfile ); int sign_symencrypt_file (const char *fname, strlist_t locusr); /*-- sig-check.c --*/ int check_revocation_keys (PKT_public_key *pk, PKT_signature *sig); int check_backsig(PKT_public_key *main_pk,PKT_public_key *sub_pk, PKT_signature *backsig); int check_key_signature( KBNODE root, KBNODE node, int *is_selfsig ); int check_key_signature2( KBNODE root, KBNODE node, PKT_public_key *check_pk, PKT_public_key *ret_pk, int *is_selfsig, u32 *r_expiredate, int *r_expired ); /*-- delkey.c --*/ gpg_error_t delete_keys (strlist_t names, int secret, int allow_both); /*-- keyedit.c --*/ void keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr, strlist_t commands, int quiet, int seckey_check ); void keyedit_passwd (ctrl_t ctrl, const char *username); +void keyedit_quick_adduid (ctrl_t ctrl, const char *username, + const char *newuid); void keyedit_quick_sign (ctrl_t ctrl, const char *fpr, strlist_t uids, strlist_t locusr, int local); void show_basic_key_info (KBNODE keyblock); /*-- keygen.c --*/ u32 parse_expire_string(const char *string); u32 ask_expire_interval(int object,const char *def_expire); u32 ask_expiredate(void); void quick_generate_keypair (const char *uid); void generate_keypair (ctrl_t ctrl, int full, const char *fname, const char *card_serialno, int card_backup_key); int keygen_set_std_prefs (const char *string,int personal); PKT_user_id *keygen_get_std_prefs (void); int keygen_add_key_expire( PKT_signature *sig, void *opaque ); int keygen_add_std_prefs( PKT_signature *sig, void *opaque ); int keygen_upd_std_prefs( PKT_signature *sig, void *opaque ); int keygen_add_keyserver_url(PKT_signature *sig, void *opaque); int keygen_add_notations(PKT_signature *sig,void *opaque); int keygen_add_revkey(PKT_signature *sig, void *opaque); gpg_error_t make_backsig (PKT_signature *sig, PKT_public_key *pk, PKT_public_key *sub_pk, PKT_public_key *sub_psk, u32 timestamp, const char *cache_nonce); gpg_error_t generate_subkeypair (ctrl_t ctrl, kbnode_t pub_keyblock); #ifdef ENABLE_CARD_SUPPORT gpg_error_t generate_card_subkeypair (kbnode_t pub_keyblock, int keyno, const char *serialno); int save_unprotected_key_to_card (PKT_public_key *sk, int keyno); #endif /*-- openfile.c --*/ int overwrite_filep( const char *fname ); char *make_outfile_name( const char *iname ); char *ask_outfile_name( const char *name, size_t namelen ); int open_outfile (int inp_fd, const char *iname, int mode, int restrictedperm, iobuf_t *a); char *get_matching_datafile (const char *sigfilename); iobuf_t open_sigfile (const char *sigfilename, progress_filter_context_t *pfx); void try_make_homedir( const char *fname ); char *get_openpgp_revocdir (const char *home); /*-- seskey.c --*/ void make_session_key( DEK *dek ); gcry_mpi_t encode_session_key( int openpgp_pk_algo, DEK *dek, unsigned nbits ); gcry_mpi_t encode_md_value (PKT_public_key *pk, gcry_md_hd_t md, int hash_algo ); /*-- import.c --*/ typedef gpg_error_t (*import_screener_t)(kbnode_t keyblock, void *arg); int parse_import_options(char *str,unsigned int *options,int noisy); void import_keys (ctrl_t ctrl, char **fnames, int nnames, void *stats_hd, unsigned int options); int import_keys_stream (ctrl_t ctrl, iobuf_t inp, void *stats_hd, unsigned char **fpr, size_t *fpr_len, unsigned int options); int import_keys_es_stream (ctrl_t ctrl, estream_t fp, void *stats_handle, unsigned char **fpr, size_t *fpr_len, unsigned int options, import_screener_t screener, void *screener_arg); gpg_error_t import_old_secring (ctrl_t ctrl, const char *fname); void *import_new_stats_handle (void); void import_release_stats_handle (void *p); void import_print_stats (void *hd); int collapse_uids( KBNODE *keyblock ); /*-- export.c --*/ int parse_export_options(char *str,unsigned int *options,int noisy); int export_pubkeys (ctrl_t ctrl, strlist_t users, unsigned int options ); int export_pubkeys_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, kbnode_t *keyblock_out, unsigned int options ); gpg_error_t export_pubkey_buffer (ctrl_t ctrl, const char *keyspec, unsigned int options, kbnode_t *r_keyblock, void **r_data, size_t *r_datalen); int export_seckeys (ctrl_t ctrl, strlist_t users); int export_secsubkeys (ctrl_t ctrl, strlist_t users); /*-- dearmor.c --*/ int dearmor_file( const char *fname ); int enarmor_file( const char *fname ); /*-- revoke.c --*/ struct revocation_reason_info; int gen_standard_revoke (PKT_public_key *psk, const char *cache_nonce); int gen_revoke( const char *uname ); int gen_desig_revoke( const char *uname, strlist_t locusr); int revocation_reason_build_cb( PKT_signature *sig, void *opaque ); struct revocation_reason_info * ask_revocation_reason( int key_rev, int cert_rev, int hint ); void release_revocation_reason_info( struct revocation_reason_info *reason ); /*-- keylist.c --*/ void public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode ); void secret_key_list (ctrl_t ctrl, strlist_t list ); void print_subpackets_colon(PKT_signature *sig); void reorder_keyblock (KBNODE keyblock); void list_keyblock_direct (kbnode_t keyblock, int secret, int has_secret, int fpr); void print_fingerprint (estream_t fp, PKT_public_key *pk, int mode); void print_revokers (estream_t fp, PKT_public_key *pk); void show_policy_url(PKT_signature *sig,int indent,int mode); void show_keyserver_url(PKT_signature *sig,int indent,int mode); void show_notation(PKT_signature *sig,int indent,int mode,int which); void dump_attribs (const PKT_user_id *uid, PKT_public_key *pk); void set_attrib_fd(int fd); void print_seckey_info (PKT_public_key *pk); void print_pubkey_info (estream_t fp, PKT_public_key *pk); void print_card_key_info (estream_t fp, KBNODE keyblock); /*-- verify.c --*/ void print_file_status( int status, const char *name, int what ); int verify_signatures (ctrl_t ctrl, int nfiles, char **files ); int verify_files (ctrl_t ctrl, int nfiles, char **files ); int gpg_verify (ctrl_t ctrl, int sig_fd, int data_fd, estream_t out_fp); /*-- decrypt.c --*/ int decrypt_message (ctrl_t ctrl, const char *filename ); gpg_error_t decrypt_message_fd (ctrl_t ctrl, int input_fd, int output_fd); void decrypt_messages (ctrl_t ctrl, int nfiles, char *files[]); /*-- plaintext.c --*/ int hash_datafiles( gcry_md_hd_t md, gcry_md_hd_t md2, strlist_t files, const char *sigfilename, int textmode); int hash_datafile_by_fd ( gcry_md_hd_t md, gcry_md_hd_t md2, int data_fd, int textmode ); PKT_plaintext *setup_plaintext_name(const char *filename,IOBUF iobuf); /*-- signal.c --*/ void init_signals(void); void block_all_signals(void); void unblock_all_signals(void); /*-- server.c --*/ int gpg_server (ctrl_t); gpg_error_t gpg_proxy_pinentry_notify (ctrl_t ctrl, const unsigned char *line); #ifdef ENABLE_CARD_SUPPORT /*-- card-util.c --*/ void change_pin (int no, int allow_admin); void card_status (estream_t fp, char *serialno, size_t serialnobuflen); void card_edit (ctrl_t ctrl, strlist_t commands); gpg_error_t card_generate_subkey (KBNODE pub_keyblock); int card_store_subkey (KBNODE node, int use); #endif #define S2K_DECODE_COUNT(_val) ((16ul + ((_val) & 15)) << (((_val) >> 4) + 6)) /*-- migrate.c --*/ void migrate_secring (ctrl_t ctrl); #endif /*G10_MAIN_H*/ diff --git a/g10/packet.h b/g10/packet.h index ba43638fa..523178b5f 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -1,549 +1,549 @@ /* packet.h - OpenPGP packet definitions * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, * 2007 Free Software Foundation, Inc. * * 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 . */ #ifndef G10_PACKET_H #define G10_PACKET_H #include "types.h" #include "../common/iobuf.h" #include "../common/strlist.h" #include "dek.h" #include "filter.h" #include "../common/openpgpdefs.h" #include "../common/userids.h" #define DEBUG_PARSE_PACKET 1 /* Constants to allocate static MPI arrays. */ #define PUBKEY_MAX_NPKEY 5 #define PUBKEY_MAX_NSKEY 7 #define PUBKEY_MAX_NSIG 2 #define PUBKEY_MAX_NENC 2 /* Usage flags */ #define PUBKEY_USAGE_SIG GCRY_PK_USAGE_SIGN /* Good for signatures. */ #define PUBKEY_USAGE_ENC GCRY_PK_USAGE_ENCR /* Good for encryption. */ #define PUBKEY_USAGE_CERT GCRY_PK_USAGE_CERT /* Also good to certify keys.*/ #define PUBKEY_USAGE_AUTH GCRY_PK_USAGE_AUTH /* Good for authentication. */ #define PUBKEY_USAGE_UNKNOWN GCRY_PK_USAGE_UNKN /* Unknown usage flag. */ #define PUBKEY_USAGE_NONE 256 /* No usage given. */ #if (GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR | GCRY_PK_USAGE_CERT \ | GCRY_PK_USAGE_AUTH | GCRY_PK_USAGE_UNKN) >= 256 # error Please choose another value for PUBKEY_USAGE_NONE #endif /* Helper macros. */ #define is_RSA(a) ((a)==PUBKEY_ALGO_RSA || (a)==PUBKEY_ALGO_RSA_E \ || (a)==PUBKEY_ALGO_RSA_S ) #define is_ELGAMAL(a) ((a)==PUBKEY_ALGO_ELGAMAL_E) #define is_DSA(a) ((a)==PUBKEY_ALGO_DSA) /* A pointer to the packet object. */ typedef struct packet_struct PACKET; /* PKT_GPG_CONTROL types */ typedef enum { CTRLPKT_CLEARSIGN_START = 1, CTRLPKT_PIPEMODE = 2, CTRLPKT_PLAINTEXT_MARK =3 } ctrlpkttype_t; typedef enum { PREFTYPE_NONE = 0, PREFTYPE_SYM = 1, PREFTYPE_HASH = 2, PREFTYPE_ZIP = 3 } preftype_t; typedef struct { byte type; byte value; } prefitem_t; typedef struct { int mode; /* Must be an integer due to the GNU modes 1001 et al. */ byte hash_algo; byte salt[8]; u32 count; } STRING2KEY; typedef struct { byte version; byte cipher_algo; /* cipher algorithm used */ STRING2KEY s2k; byte seskeylen; /* keylength in byte or 0 for no seskey */ byte seskey[1]; } PKT_symkey_enc; typedef struct { u32 keyid[2]; /* 64 bit keyid */ byte version; byte pubkey_algo; /* algorithm used for public key scheme */ byte throw_keyid; gcry_mpi_t data[PUBKEY_MAX_NENC]; } PKT_pubkey_enc; typedef struct { u32 keyid[2]; /* 64 bit keyid */ byte sig_class; /* sig classification */ byte digest_algo; /* algorithm used for digest */ byte pubkey_algo; /* algorithm used for public key scheme */ byte last; /* a stupid flag */ } PKT_onepass_sig; typedef struct { size_t size; /* allocated */ size_t len; /* used */ byte data[1]; } subpktarea_t; struct revocation_key { byte class; byte algid; byte fpr[MAX_FINGERPRINT_LEN]; }; /* Object to keep information about a PKA DNS record. */ typedef struct { int valid; /* An actual PKA record exists for EMAIL. */ int checked; /* Set to true if the FPR has been checked against the actual key. */ char *uri; /* Malloced string with the URI. NULL if the URI is not available.*/ unsigned char fpr[20]; /* The fingerprint as stored in the PKA RR. */ char email[1];/* The email address from the notation data. */ } pka_info_t; /* Object to keep information pertaining to a signature. */ typedef struct { struct { unsigned checked:1; /* Signature has been checked. */ unsigned valid:1; /* Signature is good (if checked is set). */ unsigned chosen_selfsig:1; /* A selfsig that is the chosen one. */ unsigned unknown_critical:1; unsigned exportable:1; unsigned revocable:1; unsigned policy_url:1; /* At least one policy URL is present */ unsigned notation:1; /* At least one notation is present */ unsigned pref_ks:1; /* At least one preferred keyserver is present */ unsigned expired:1; unsigned pka_tried:1; /* Set if we tried to retrieve the PKA record. */ } flags; u32 keyid[2]; /* 64 bit keyid */ u32 timestamp; /* Signature made (seconds since Epoch). */ u32 expiredate; /* Expires at this date or 0 if not at all. */ byte version; byte sig_class; /* Sig classification, append for MD calculation. */ byte pubkey_algo; /* Algorithm used for public key scheme */ /* (PUBKEY_ALGO_xxx) */ byte digest_algo; /* Algorithm used for digest (DIGEST_ALGO_xxxx). */ byte trust_depth; byte trust_value; const byte *trust_regexp; struct revocation_key **revkey; int numrevkeys; pka_info_t *pka_info; /* Malloced PKA data or NULL if not available. See also flags.pka_tried. */ subpktarea_t *hashed; /* All subpackets with hashed data (v4 only). */ subpktarea_t *unhashed; /* Ditto for unhashed data. */ byte digest_start[2]; /* First 2 bytes of the digest. */ gcry_mpi_t data[PUBKEY_MAX_NSIG]; } PKT_signature; #define ATTRIB_IMAGE 1 /* This is the cooked form of attributes. */ struct user_attribute { byte type; const byte *data; u32 len; }; /* (See also keybox-search-desc.h) */ struct gpg_pkt_user_id_s { int ref; /* reference counter */ int len; /* length of the name */ struct user_attribute *attribs; int numattribs; byte *attrib_data; /* if this is not NULL, the packet is an attribute */ unsigned long attrib_len; byte *namehash; int help_key_usage; u32 help_key_expire; int help_full_count; int help_marginal_count; int is_primary; /* 2 if set via the primary flag, 1 if calculated */ int is_revoked; int is_expired; u32 expiredate; /* expires at this date or 0 if not at all */ prefitem_t *prefs; /* list of preferences (may be NULL)*/ u32 created; /* according to the self-signature */ byte selfsigversion; struct { /* TODO: Move more flags here */ unsigned int mdc:1; unsigned int ks_modify:1; unsigned int compacted:1; } flags; char name[1]; }; typedef struct gpg_pkt_user_id_s PKT_user_id; struct revoke_info { /* revoked at this date */ u32 date; /* the keyid of the revoking key (selfsig or designated revoker) */ u32 keyid[2]; /* the algo of the revoking key */ byte algo; }; /* Information pertaining to secret keys. */ struct seckey_info { int is_protected:1; /* The secret info is protected and must */ /* be decrypted before use, the protected */ /* MPIs are simply (void*) pointers to memory */ /* and should never be passed to a mpi_xxx() */ int sha1chk:1; /* SHA1 is used instead of a 16 bit checksum */ u16 csum; /* Checksum for old protection modes. */ byte algo; /* Cipher used to protect the secret information. */ STRING2KEY s2k; /* S2K parameter. */ byte ivlen; /* Used length of the IV. */ byte iv[16]; /* Initialization vector for CFB mode. */ }; /**************** * We assume that secret keys have the same number of parameters as * the public key and that the public parameters are the first items * in the PKEY array. Thus NPKEY is always less than NSKEY and it is * possible to compare the secret and public keys by comparing the * first NPKEY elements of the PKEY array. Note that since GnuPG 2.1 * we don't use secret keys anymore directly because they are managed * by gpg-agent. However for parsing OpenPGP key files we need a way * to temporary store those secret keys. We do this by putting them * into the public key structure and extending the PKEY field to NSKEY * elements; the extra secret key information are stored in the * SECKEY_INFO field. */ typedef struct { u32 timestamp; /* key made */ u32 expiredate; /* expires at this date or 0 if not at all */ u32 max_expiredate; /* must not expire past this date */ struct revoke_info revoked; byte hdrbytes; /* number of header bytes */ byte version; byte selfsigversion; /* highest version of all of the self-sigs */ byte pubkey_algo; /* algorithm used for public key scheme */ byte pubkey_usage; /* for now only used to pass it to getkey() */ byte req_usage; /* hack to pass a request to getkey() */ byte req_algo; /* Ditto */ u32 has_expired; /* set to the expiration date if expired */ u32 main_keyid[2]; /* keyid of the primary key */ u32 keyid[2]; /* calculated by keyid_from_pk() */ prefitem_t *prefs; /* list of preferences (may be NULL) */ struct { unsigned int mdc:1; /* MDC feature set. */ unsigned int disabled_valid:1;/* The next flag is valid. */ unsigned int disabled:1; /* The key has been disabled. */ unsigned int primary:1; /* This is a primary key. */ unsigned int revoked:2; /* Key has been revoked. 1 = revoked by the owner 2 = revoked by designated revoker. */ unsigned int maybe_revoked:1; /* A designated revocation is present, but without the key to check it. */ unsigned int valid:1; /* Key (especially subkey) is valid. */ unsigned int dont_cache:1; /* Do not cache this key. */ unsigned int backsig:2; /* 0=none, 1=bad, 2=good. */ unsigned int serialno_valid:1;/* SERIALNO below is valid. */ } flags; PKT_user_id *user_id; /* If != NULL: found by that uid. */ struct revocation_key *revkey; int numrevkeys; u32 trust_timestamp; byte trust_depth; byte trust_value; const byte *trust_regexp; char *serialno; /* Malloced hex string or NULL if it is likely not on a card. See also flags.serialno_valid. */ struct seckey_info *seckey_info; /* If not NULL this malloced structure describes a secret key. */ gcry_mpi_t pkey[PUBKEY_MAX_NSKEY]; /* Right, NSKEY elements. */ } PKT_public_key; /* Evaluates as true if the pk is disabled, and false if it isn't. If there is no disable value cached, fill one in. */ #define pk_is_disabled(a) \ (((a)->flags.disabled_valid)? \ ((a)->flags.disabled):(cache_disabled_value((a)))) typedef struct { int len; /* length of data */ char data[1]; } PKT_comment; typedef struct { u32 len; /* reserved */ byte new_ctb; byte algorithm; iobuf_t buf; /* IOBUF reference */ } PKT_compressed; typedef struct { u32 len; /* Remaining length of encrypted data. */ int extralen; /* This is (blocksize+2). Used by build_packet. */ byte new_ctb; /* uses a new CTB */ byte is_partial; /* partial length encoded */ byte mdc_method; /* > 0: integrity protected encrypted data packet */ iobuf_t buf; /* IOBUF reference */ } PKT_encrypted; typedef struct { byte hash[20]; } PKT_mdc; typedef struct { unsigned int trustval; unsigned int sigcache; } PKT_ring_trust; typedef struct { u32 len; /* length of encrypted data */ iobuf_t buf; /* IOBUF reference */ byte new_ctb; byte is_partial; /* partial length encoded */ int mode; u32 timestamp; int namelen; char name[1]; } PKT_plaintext; typedef struct { int control; size_t datalen; char data[1]; } PKT_gpg_control; /* combine all packets into a union */ struct packet_struct { pkttype_t pkttype; union { void *generic; PKT_symkey_enc *symkey_enc; /* PKT_SYMKEY_ENC */ PKT_pubkey_enc *pubkey_enc; /* PKT_PUBKEY_ENC */ PKT_onepass_sig *onepass_sig; /* PKT_ONEPASS_SIG */ PKT_signature *signature; /* PKT_SIGNATURE */ PKT_public_key *public_key; /* PKT_PUBLIC_[SUB)KEY */ PKT_public_key *secret_key; /* PKT_SECRET_[SUB]KEY */ PKT_comment *comment; /* PKT_COMMENT */ PKT_user_id *user_id; /* PKT_USER_ID */ PKT_compressed *compressed; /* PKT_COMPRESSED */ PKT_encrypted *encrypted; /* PKT_ENCRYPTED[_MDC] */ PKT_mdc *mdc; /* PKT_MDC */ PKT_ring_trust *ring_trust; /* PKT_RING_TRUST */ PKT_plaintext *plaintext; /* PKT_PLAINTEXT */ PKT_gpg_control *gpg_control; /* PKT_GPG_CONTROL */ } pkt; }; #define init_packet(a) do { (a)->pkttype = 0; \ (a)->pkt.generic = NULL; \ } while(0) struct notation { char *name; char *value; char *altvalue; unsigned char *bdat; size_t blen; struct { unsigned int critical:1; unsigned int ignore:1; } flags; struct notation *next; }; /*-- mainproc.c --*/ void reset_literals_seen(void); int proc_packets (ctrl_t ctrl, void *ctx, iobuf_t a ); int proc_signature_packets (ctrl_t ctrl, void *ctx, iobuf_t a, strlist_t signedfiles, const char *sigfile ); int proc_signature_packets_by_fd (ctrl_t ctrl, void *anchor, IOBUF a, int signed_data_fd ); int proc_encryption_packets (ctrl_t ctrl, void *ctx, iobuf_t a); int list_packets( iobuf_t a ); /*-- parse-packet.c --*/ int set_packet_list_mode( int mode ); #if DEBUG_PARSE_PACKET int dbg_search_packet( iobuf_t inp, PACKET *pkt, off_t *retpos, int with_uid, const char* file, int lineno ); int dbg_parse_packet( iobuf_t inp, PACKET *ret_pkt, const char* file, int lineno ); int dbg_copy_all_packets( iobuf_t inp, iobuf_t out, const char* file, int lineno ); int dbg_copy_some_packets( iobuf_t inp, iobuf_t out, off_t stopoff, const char* file, int lineno ); int dbg_skip_some_packets( iobuf_t inp, unsigned n, const char* file, int lineno ); #define search_packet( a,b,c,d ) \ dbg_search_packet( (a), (b), (c), (d), __FILE__, __LINE__ ) #define parse_packet( a, b ) \ dbg_parse_packet( (a), (b), __FILE__, __LINE__ ) #define copy_all_packets( a,b ) \ dbg_copy_all_packets((a),(b), __FILE__, __LINE__ ) #define copy_some_packets( a,b,c ) \ dbg_copy_some_packets((a),(b),(c), __FILE__, __LINE__ ) #define skip_some_packets( a,b ) \ dbg_skip_some_packets((a),(b), __FILE__, __LINE__ ) #else int search_packet( iobuf_t inp, PACKET *pkt, off_t *retpos, int with_uid ); int parse_packet( iobuf_t inp, PACKET *ret_pkt); int copy_all_packets( iobuf_t inp, iobuf_t out ); int copy_some_packets( iobuf_t inp, iobuf_t out, off_t stopoff ); int skip_some_packets( iobuf_t inp, unsigned n ); #endif int parse_signature( iobuf_t inp, int pkttype, unsigned long pktlen, PKT_signature *sig ); const byte *enum_sig_subpkt ( const subpktarea_t *subpkts, sigsubpkttype_t reqtype, size_t *ret_n, int *start, int *critical ); const byte *parse_sig_subpkt ( const subpktarea_t *buffer, sigsubpkttype_t reqtype, size_t *ret_n ); const byte *parse_sig_subpkt2 ( PKT_signature *sig, sigsubpkttype_t reqtype, size_t *ret_n ); int parse_one_sig_subpkt( const byte *buffer, size_t n, int type ); void parse_revkeys(PKT_signature *sig); int parse_attribute_subpkts(PKT_user_id *uid); void make_attribute_uidname(PKT_user_id *uid, size_t max_namelen); PACKET *create_gpg_control ( ctrlpkttype_t type, const byte *data, size_t datalen ); /*-- build-packet.c --*/ int build_packet( iobuf_t inp, PACKET *pkt ); gpg_error_t gpg_mpi_write (iobuf_t out, gcry_mpi_t a); gpg_error_t gpg_mpi_write_nohdr (iobuf_t out, gcry_mpi_t a); u32 calc_packet_length( PACKET *pkt ); void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type, const byte *buffer, size_t buflen ); void build_sig_subpkt_from_sig( PKT_signature *sig ); int delete_sig_subpkt(subpktarea_t *buffer, sigsubpkttype_t type ); void build_attribute_subpkt(PKT_user_id *uid,byte type, const void *buf,u32 buflen, const void *header,u32 headerlen); struct notation *string_to_notation(const char *string,int is_utf8); struct notation *sig_to_notation(PKT_signature *sig); void free_notation(struct notation *notation); /*-- free-packet.c --*/ void free_symkey_enc( PKT_symkey_enc *enc ); void free_pubkey_enc( PKT_pubkey_enc *enc ); void free_seckey_enc( PKT_signature *enc ); int digest_algo_from_sig( PKT_signature *sig ); void release_public_key_parts( PKT_public_key *pk ); void free_public_key( PKT_public_key *key ); void free_attributes(PKT_user_id *uid); void free_user_id( PKT_user_id *uid ); void free_comment( PKT_comment *rem ); void free_packet( PACKET *pkt ); prefitem_t *copy_prefs (const prefitem_t *prefs); PKT_public_key *copy_public_key( PKT_public_key *d, PKT_public_key *s ); PKT_signature *copy_signature( PKT_signature *d, PKT_signature *s ); PKT_user_id *scopy_user_id (PKT_user_id *sd ); int cmp_public_keys( PKT_public_key *a, PKT_public_key *b ); int cmp_signatures( PKT_signature *a, PKT_signature *b ); int cmp_user_ids( PKT_user_id *a, PKT_user_id *b ); /*-- sig-check.c --*/ int signature_check( PKT_signature *sig, gcry_md_hd_t digest ); int signature_check2( PKT_signature *sig, gcry_md_hd_t digest, u32 *r_expiredate, int *r_expired, int *r_revoked, PKT_public_key *ret_pk ); /*-- pubkey-enc.c --*/ gpg_error_t get_session_key (PKT_pubkey_enc *k, DEK *dek); gpg_error_t get_override_session_key (DEK *dek, const char *string); /*-- compress.c --*/ int handle_compressed (ctrl_t ctrl, void *ctx, PKT_compressed *cd, int (*callback)(iobuf_t, void *), void *passthru ); /*-- encr-data.c --*/ int decrypt_data (ctrl_t ctrl, void *ctx, PKT_encrypted *ed, DEK *dek ); /*-- plaintext.c --*/ int handle_plaintext( PKT_plaintext *pt, md_filter_context_t *mfx, int nooutput, int clearsig ); int ask_for_detached_datafile( gcry_md_hd_t md, gcry_md_hd_t md2, const char *inname, int textmode ); /*-- sign.c --*/ int make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk, PKT_user_id *uid, PKT_public_key *subpk, PKT_public_key *pksk, int sigclass, int digest_algo, u32 timestamp, u32 duration, int (*mksubpkt)(PKT_signature *, void *), void *opaque, const char *cache_nonce); int update_keysig_packet( PKT_signature **ret_sig, PKT_signature *orig_sig, PKT_public_key *pk, PKT_user_id *uid, PKT_public_key *subpk, PKT_public_key *pksk, int (*mksubpkt)(PKT_signature *, void *), void *opaque ); /*-- keygen.c --*/ -PKT_user_id *generate_user_id (KBNODE keyblock); +PKT_user_id *generate_user_id (kbnode_t keyblock, const char *uidstr); #endif /*G10_PACKET_H*/