Emacsのパッケージをインストールする時には署名の検査が行われますが、署名の検査を行わないように設定に設定できます。今回はその際に設定する変数と使われ方について調べました。
TL;DR
- パッケージの署名の検査はpackage-check-signatureとpackage-unsigned-archivesの設定で検査するかどうかが決定する
- package-check-signatureに設定できる値は
nil'allow-signedt'allのいずれかを設定する - package-unsigned-archivesは署名の検査をしないパッケージアーカイブの名前のリストを設定する
package-check-signatureに設定できる値と意味
| 値 | 意味 |
| nil | 署名のチェックをしない |
| 'allow-signed | 署名があり鍵がある時だけ署名の確認を行う |
| t | 少なくとも1つの検証済み署名が必要 |
| 'all | 全ての検証済み署名が必要 |
署名ファイルがないのにpackage-refresh-contentsできる?
自分用にパッケージアーカイブを作成しました。しかし署名ファイルはまだ準備していません。それにもかかわらずなぜかpackage-refresh-contentsできてしまいました。Emacsのパッケージがインストールされるのを眺めるで確認した時にはM-x package-refresh-contentsを実行してインデックス情報であるarchive-contentsをダウンロードした時にも、パッケージをインストールする時にも署名ファイル(.sig)のダウンロードとその検査を行なっていました。今回はこの挙動の違いの理由を調べます。
package-check-signature - 署名を確認するかどうかを制御する
package-check-signatureはインストール時に署名を確認するかどうかを制御するための変数です。
(defcustom package-check-signature
(if (and (require 'epg-config)
(epg-find-configuration 'OpenPGP))
'allow-unsigned)
"Non-nil means to check package signatures when installing.
More specifically the value can be:
- nil: package signatures are ignored.
- `allow-unsigned': install a package even if it is unsigned,
but if it is signed and we have the key for it, verify the signature.
- t: accept a package only if it comes with at least one verified signature.
- `all': same as t, except when the package has several signatures,
in which case we verify all the signatures.
This also applies to the \"archive-contents\" file that lists the
contents of the archive."
:type '(choice (const nil :tag "Never")
(const allow-unsigned :tag "Allow unsigned")
(const t :tag "Check always")
(const all :tag "Check all signatures"))
:risky t
:version "27.1")
現在の値を確認します。
package-check-signatureallow-unsigned
現在の値はallow-unsignedになっていました。これは署名があれば検証するが、なければそのままインストールしてしまう設定です。このため署名を作ってない自分用のパッケージアーカイブからもインストールができる状態になっていました。
package-check-signatureに設定できる値
package-check-signatureには nil 'allow-signed t 'all が設定できます。
| 値 | 意味 |
| nil | 署名のチェックをしない |
| 'allow-signed | 署名があり鍵がある時だけ署名の確認を行う |
| t | 少なくとも1つの検証済み署名が必要 |
| 'all | 全ての検証済み署名が必要 |
使われている所
package-refresh-contents
package-refresh-contentsはpackage-archivesに設定されているパッケージアーカイブからパッケージの情報をダウンロードし読み込みます。
抜粋::
(when (and package-check-signature (file-exists-p default-keyring))
(condition-case-unless-debug error
(package-import-keyring default-keyring)
(error (message "Cannot import default keyring: %S" (cdr error))))))
package-check-signatureが設定されていればGnuPGの鍵を読み込みます。この鍵は署名の検証に使われます。なおdefault-keyringはデフォルトは以下で設定されている。
"/Applications/Emacs.app/Contents/Resources/etc/package-keyring.gpg"
package–download-one-archive
package–download-one-archiveはアーカイブからファイルをダウンロードしてキャッシュします。 アーカイブは(NAME . LOCATION)という形式のコンスセルです。 ダウンロードしたファイルはpackage-user-dir配下のpackages/NAME/FILEに保存されます。
抜粋::
(if (or (not package-check-signature)
(member name package-unsigned-archives))
;; If we don't care about the signature, save the file and
;; we're done.
(progn (let ((coding-system-for-write 'utf-8))
(write-region content nil local-file nil 'silent))
(package--update-downloads-in-progress archive))
;; If we care, check it (perhaps async) and *then* write the file.
(package--check-signature
location file content async
;; This function will be called after signature checking.
(lambda (&optional good-sigs)
(let ((coding-system-for-write 'utf-8))
(write-region content nil local-file nil 'silent))
;; Write out good signatures into archive-contents.signed file.
(when good-sigs
(write-region (mapconcat #'epg-signature-to-string good-sigs "\n")
nil (concat local-file ".signed") nil 'silent)))
(lambda () (package--update-downloads-in-progress archive))))))))
package-check-signatureとpackage-unsigned-archivesの状態をみてpackage–check-signatureされるかどうかが分岐しています。package–check-signatureは署名ファイルをダウンロードし検証します。
package-unsigned-archives - 署名を確認しないパッケージアーカイブのリスト
package-unsigned-archivesに名前が設定されたパッケージアーカイブは署名のチェックを行いません。
(defcustom package-unsigned-archives nil "List of archives where we do not check for package signatures." :type '(repeat (string :tag "Archive name")) :risky t :version "24.4")
現在の値を確認します。
package-unsigned-archivesnil
こちらは設定していませんでした。
使われているところ
(member name package-unsigned-archives) のようにこのpackage-unsigned-archivesにパッケージ名が含まれているかどうかをチェックしています。
package–download-one-archive
抜粋::
(if (or (not package-check-signature)
(member name package-unsigned-archives))
;; If we don't care about the signature, save the file and
;; we're done.
(progn (let ((coding-system-for-write 'utf-8))
(write-region content nil local-file nil 'silent))
(package--update-downloads-in-progress archive))
;; If we care, check it (perhaps async) and *then* write the file.
(package--check-signature
package-install-from-archive
抜粋::
(package--with-response-buffer location :file file
(if (or (not package-check-signature)
(member (package-desc-archive pkg-desc)
package-unsigned-archives))
;; If we don't care about the signature, unpack and we're
;; done.
(let ((save-silently t))
(package-unpack pkg-desc))
まとめ
署名の検査をする(もしくはしない)ための設定はpackage-check-signatureとpackage-unsigned-archivesの設定によって制御されていました。package-check-signatureは署名の検査を(どの程度)するか、package-unsigned-archivesはそのパッケージアーカイブが署名の検証が不要かを設定する変数でした。