[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
scratch/package-security 7f29c9e 1/3: Support package checksum verificat
From: |
Stefan Kangas |
Subject: |
scratch/package-security 7f29c9e 1/3: Support package checksum verification |
Date: |
Tue, 8 Sep 2020 12:51:57 -0400 (EDT) |
branch: scratch/package-security
commit 7f29c9e37177fe4fb47c420678c35a6b6705cc3d
Author: Stefan Kangas <stefankangas@gmail.com>
Commit: Stefan Kangas <stefan@marxist.se>
Support package checksum verification
This is the first step towards protecting users of package.el against
metadata replay attacks. (Bug#19479)
* lisp/emacs-lisp/package.el (package-verify-checksums): New
defcustom.
(package-desc, package--ac-desc)
(package--add-to-archive-contents, package-install-from-archive): New
fields 'size' and 'checksums'.
(package-desc-filename): New function.
(bad-checksum, bad-size): New error types.
(package-insecure-hash-algorithms): New constant.
(package--verify-package-checksum)
(package--verify-package-size): New function to verify that the
checksum and size of a package corresponds to the checksum and size
data in the "archive-contents" file on the package archive.
(package--show-verify-checksum-error): New function to show
details of an error on checksum verification.
* lisp/emacs-lisp/package-x.el (package-upload-buffer-internal):
Update to use above new fields 'size' and 'checksums'.
* test/lisp/emacs-lisp/package-tests.el (package-test-refresh-contents)
(package-test-install-single-from-archive)
(package-test-list-filter-by-archive)
(package-test-list-filter-by-status): Update tests.
(with-install-using-checksum): New macro.
(package-test-install-wrong-size-single)
(package-test-install-wrong-size-tar): New tests for size checking.
(package-test-install-with-checksum/single-valid)
(package-test-install-with-checksum/single-invalid)
(package-test-install-with-checksum/tar-valid)
(package-test-install-with-checksum/tar-invalid): New tests for
installing packages with checksums.
(package-test-verification-text)
(package-tests-valid-md5-checksum)
(package-tests-valid-sha256-checksum)
(package-tests-valid-sha512-checksum): New variables.
(package-tests--run-verify-checksums-test): New macro.
(package-test-verify-package-checksums-nil/ignore-invalid)
(package-test-verify-package-checksums-allow-missing)
(package-test-verify-package-checksums-allow-missing/missing)
(package-test-verify-package-checksums-allow-missing/ignore-unsupported)
(package-test-verify-package-checksums-t)
(package-test-verify-package-checksums-t/invalid-fails)
(package-test-verify-package-checksums-t/missing-fails)
(package-test-verify-package-checksums-all)
(package-test-verify-package-checksums-all/invalid-fails)
(package-test-verify-package-checksums-all/missing-fails)
(package-test-verify-package-checksums-all/no-supported-hash-fails)
(package-test-verify-package-checksums-all/ignore-unsupported)
(package-test-verify-package-size): New tests for the checksum
support.
* test/lisp/emacs-lisp/package-resources/archive-contents:
* test/lisp/emacs-lisp/package-resources/checksum-invalid-1.0.el:
* test/lisp/emacs-lisp/package-resources/checksum-valid-123.el:
* test/lisp/emacs-lisp/package-resources/checksum-valid-tar-0.99.tar:
* test/lisp/emacs-lisp/package-resources/checksum-valid-tar-0.99.tar:
New test data files.
* doc/emacs/package.texi (Package Installation): Document package
checksum checking.
* etc/NEWS: Announce it.
---
doc/emacs/package.texi | 14 +-
etc/NEWS | 15 ++
lisp/emacs-lisp/package-x.el | 4 +-
lisp/emacs-lisp/package.el | 162 ++++++++++++++--
.../emacs-lisp/package-resources/archive-contents | 36 +++-
.../package-resources/checksum-invalid-1.0.el | 17 ++
.../package-resources/checksum-invalid-tar-0.1.tar | Bin 0 -> 10240 bytes
.../package-resources/checksum-valid-123.el | 17 ++
.../package-resources/checksum-valid-tar-0.99.tar | Bin 0 -> 10240 bytes
.../package-resources/wrong-size-single-1.0.el | 1 +
.../package-resources/wrong-size-tar-1.0.tar | Bin 0 -> 10240 bytes
test/lisp/emacs-lisp/package-tests.el | 203 ++++++++++++++++++++-
12 files changed, 448 insertions(+), 21 deletions(-)
diff --git a/doc/emacs/package.texi b/doc/emacs/package.texi
index 453d9eb..49ef20b 100644
--- a/doc/emacs/package.texi
+++ b/doc/emacs/package.texi
@@ -316,8 +316,20 @@ name of the package archive directory. You can alter this
list if you
wish to use third party package archives---but do so at your own risk,
and use only third parties that you think you can trust!
-@anchor{Package Signing}
+@anchor{Package Checksums}
@cindex package security
+@cindex package checksums
+ The maintainers of package archives can add package checksums to
+their packages. When downloading a package that has a checksum, it
+is used to verify that the correct version of that file has been
+downloaded. By default, Emacs will verify these checksums
+automatically when available, and ignore it when not. You can control
+this with the user option @code{package-verify-checksums}. If you
+want to install only packages with a valid checksum, you can set this
+option to @code{t}. This improves security, but requires that all
+package archives you use distribute checksums.
+
+@anchor{Package Signing}
@cindex package signing
The maintainers of package archives can increase the trust that you
can have in their packages by @dfn{signing} them. They generate a
diff --git a/etc/NEWS b/etc/NEWS
index fd6cdbe..4e2719d 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -567,6 +567,21 @@ See the new user options 'package-name-column-width',
'package-version-column-width', 'package-status-column-width', and
'package-archive-column-width'.
+*** The package system now supports package checksums.
+This improves the security of the Emacs package system. If the
+package archives you use implements package checksums, you will
+automatically benefit from this by default.
+
+The user option 'package-verify-checksums' controls how and when the
+package system will use checksums. The default is 'allow-missing',
+which will check them when they are available yet allow installation
+if they are missing.
+
+For improved security, you might want to set this to 't' or
+'all'. Make sure that the package archives you use support checksums
+before setting these values, or you will be unable to install
+packages.
+
** gdb-mi
+++
diff --git a/lisp/emacs-lisp/package-x.el b/lisp/emacs-lisp/package-x.el
index c01b6ef..964cf07 100644
--- a/lisp/emacs-lisp/package-x.el
+++ b/lisp/emacs-lisp/package-x.el
@@ -219,7 +219,9 @@ if it exists."
(let ((contents (or (package--archive-contents-from-url archive-url)
(package--archive-contents-from-file)))
(new-desc (package-make-ac-desc
- split-version requires desc file-type extras)))
+ split-version requires desc file-type extras
+ ;; FIXME: Use better values than nil nil.
+ nil nil)))
(if (> (car contents) package-archive-version)
(error "Unrecognized archive version %d" (car contents)))
(let ((elt (assq pkg-name (cdr contents))))
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index a173fc0..79256b7 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -335,6 +335,31 @@ default directory."
:risky t
:version "26.1")
+(defcustom package-verify-checksums 'allow-missing
+ "Non-nil means to verify the checksum of a package before installing it.
+
+This can be one of:
+- t Require a valid checksum; refuse to install
+ package if the checksum is missing or invalid.
+ Verify only one checksum.
+- `all' Same as t, but verify all available (and supported)
+ checksums.
+- `allow-missing' Same as t if a checksum exists, but install a
+ package even if there is no checksum.
+- nil Ignore checksums.
+
+The package checksums are automatically fetched from package
+archives with the package data on `package-refresh-contents'.
+
+Note that setting this to nil is intended for debugging, and
+should normally not be used since it will decrease security."
+ :type '(choice (const nil :tag "Never")
+ (const allow-missing :tag "Allow missing")
+ (const t :tag "Require valid checksum")
+ (const t :tag "Require valid checksum, and check all"))
+ :risky t
+ :version "28.1")
+
(defcustom package-check-signature 'allow-unsigned
"Non-nil means to check package signatures when installing.
More specifically the value can be:
@@ -449,6 +474,8 @@ synchronously."
requirements)))
(kind (plist-get rest-plist :kind))
(archive (plist-get rest-plist :archive))
+ (checksums (plist-get rest-plist :checksums))
+ (size (plist-get rest-plist :size))
(extras (let (alist)
(while rest-plist
(unless (memq (car rest-plist) '(:kind :archive))
@@ -486,6 +513,13 @@ Slots:
`extras' Optional alist of additional keyword-value pairs.
+`size' Size of the package in bytes.
+
+`checksums' Checksums for the package file. Alist of ((ALGORITHM
+ . CHECKSUM)) where ALGORITHM is a symbol specifying a
+ `secure-hash' algorithm, and CHECKSUM is a string
+ containing the checksum.
+
`signed' Flag to indicate that the package is signed by provider."
name
version
@@ -495,7 +529,9 @@ Slots:
archive
dir
extras
- signed)
+ signed
+ size
+ checksums)
(defun package--from-builtin (bi-desc)
"Create a `package-desc' object from BI-DESC.
@@ -558,6 +594,13 @@ Signal an error if the kind is none of the above."
('dir "")
(kind (error "Unknown package kind: %s" kind))))
+(defun package-desc-filename (pkg-desc)
+ "Return file-name of package-desc object PKG-DESC.
+This is the concatenation of `package-desc-full-name' and
+`package-desc-suffix'."
+ (concat (package-desc-full-name pkg-desc)
+ (package-desc-suffix pkg-desc)))
+
(defun package-desc--keywords (pkg-desc)
"Return keywords of package-desc object PKG-DESC.
These keywords come from the foo-pkg.el file, and in general
@@ -1334,6 +1377,93 @@ errors signaled by ERROR-FORM or by BODY).
url))
(insert-file-contents-literally url)))))
+(define-error 'bad-checksum "Failed to verify checksum")
+
+(defun package--show-verify-checksum-error (pkg-desc details)
+ "Show error on failed checksum verification of PKG-DESC with DETAILS.
+Error is displayed in a new buffer named \"*Error*\"."
+ (with-output-to-temp-buffer "*Error*"
+ (with-current-buffer standard-output
+ (insert (format "Failed to verify checksum of package `%s':\n\n"
+ (package-desc-name pkg-desc)))
+ (insert details))))
+
+(defconst package-insecure-hash-algorithms '(md5 sha1)
+ "List of hash algorithms that are not considered secure.")
+
+(defun package--verify-package-checksum (pkg-desc)
+ "Verify checksums of `package-desc' object PKG-DESC.
+This assumes that the we are in a buffer containing package.
+
+The value of `package-verify-checksums' decides what this
+function does:
+- t Verify that there is at least one valid checksum.
+- `all' Like t, but check all supported checksums.
+- `allow-missing' Verify checksum if it exists, otherwise do
+ nothing.
+- nil Do nothing.
+
+Signal an error of type `bad-checksum' if the verification."
+ (cl-flet*
+ ((supported-hashes
+ (lambda ()
+ (or (seq-filter
+ (lambda (h)
+ (and (memql (car h) (secure-hash-algorithms))
+ (not (memql (car h) package-insecure-hash-algorithms))))
+ (package-desc-checksums pkg-desc))
+ ;; Failed; signal error.
+ (package--show-verify-checksum-error
+ pkg-desc
+ (concat
+ (if (package-desc-checksums pkg-desc)
+ (concat
+ "No supported checksums found\n\n"
+ (format-message "Package archive had: %s\n"
+ (package-desc-checksums pkg-desc))
+ (format-message "Emacs supports: %s\n"
+ (secure-hash-algorithms)))
+ "Package archive had no checksums for this package\n")))
+ (signal 'bad-checksum "no supported checksums found"))))
+ (do-check
+ (lambda (&optional all)
+ (dolist (hash (seq-take (supported-hashes)
+ (if all most-positive-fixnum 1)))
+ (let* ((algorithm (car hash))
+ (expected (cdr hash))
+ (actual (secure-hash algorithm (current-buffer))))
+ (if (equal expected actual) t
+ ;; Failed; signal error.
+ (package--show-verify-checksum-error
+ pkg-desc
+ (concat
+ (format-message "\nChecksum mismatch (%s)\n\n" algorithm)
+ (format-message "Expected: %s\n" expected)
+ (format-message "Result: %s\n" actual)))
+ (signal 'bad-checksum (list "checksum mismatch" expected
actual))))))))
+ (pcase package-verify-checksums
+ ('nil nil)
+ ('allow-missing (when (package-desc-checksums pkg-desc) (do-check)))
+ ('t (do-check))
+ ('all (do-check 'all))
+ (_ (user-error "Value of `package-verify-checksums' is invalid: `%s'"
+ package-verify-checksums)))))
+
+(define-error 'bad-size "Package size mismatch")
+
+(defun package--verify-package-size (pkg-desc)
+ "Verify package size of `package-desc' object PKG-DESC.
+This assumes that the we are in a buffer containing package."
+ (when-let ((expected (package-desc-size pkg-desc))
+ (actual (string-bytes (buffer-string))))
+ (unless (equal expected actual)
+ (with-output-to-temp-buffer "*Error*"
+ (with-current-buffer standard-output
+ (insert (format "Mismatch in package size for `%s':\n"
+ (package-desc-name pkg-desc)))
+ (insert (format "Expected %s bytes, but received %s" expected
actual))))
+ (signal 'bad-size (list "size mismatch" expected actual)))))
+
(define-error 'bad-signature "Failed to verify signature")
(defun package--check-signature-content (content string &optional sig-file)
@@ -1461,14 +1591,19 @@ the table."
(version-list-< table-version version))
(puthash name version package--compatibility-table)))))
-;; Package descriptor objects used inside the "archive-contents" file.
-;; Changing this defstruct implies changing the format of the
-;; "archive-contents" files.
(cl-defstruct (package--ac-desc
- (:constructor package-make-ac-desc (version reqs summary kind
extras))
+ (:constructor
+ package-make-ac-desc (version reqs summary kind extras size
checksums))
(:copier nil)
(:type vector))
- version reqs summary kind extras)
+ "Package descriptor object used inside the \"archive-contents\" file.
+Changing this defstruct implies changing the format of the
+\"archive-contents\" files.
+
+This is mainly used in `package--add-to-archive-contents' to make
+the code that parses the \"archive-contents\" file more
+readable."
+ version reqs summary kind extras size checksums)
(defun package--append-to-alist (pkg-desc alist)
"Append an entry for PKG-DESC to the start of ALIST and return it.
@@ -1506,10 +1641,14 @@ Also, add the originating archive to the `package-desc'
structure."
:summary (package--ac-desc-summary (cdr package))
:kind (package--ac-desc-kind (cdr package))
:archive archive
+ ;; Older "archive-contents" files might not have the
+ ;; below elements.
:extras (and (> (length (cdr package)) 4)
- ;; Older archive-contents files have only 4
- ;; elements here.
- (package--ac-desc-extras (cdr package)))))
+ (package--ac-desc-extras (cdr package)))
+ :size (and (> (length (cdr package)) 5)
+ (package--ac-desc-size (cdr package)))
+ :checksums (and (> (length (cdr package)) 6)
+ (package--ac-desc-checksums (cdr package)))))
(pinned-to-archive (assoc name package-pinned-packages)))
;; Skip entirely if pinned to another archive.
(when (not (and pinned-to-archive
@@ -1979,9 +2118,10 @@ if all the in-between dependencies are also in
PACKAGE-LIST."
(when (eq (package-desc-kind pkg-desc) 'dir)
(error "Can't install directory package from archive"))
(let* ((location (package-archive-base pkg-desc))
- (file (concat (package-desc-full-name pkg-desc)
- (package-desc-suffix pkg-desc))))
+ (file (package-desc-filename pkg-desc)))
(package--with-response-buffer location :file file
+ (package--verify-package-size pkg-desc)
+ (package--verify-package-checksum pkg-desc)
(if (or (not (package-check-signature))
(member (package-desc-archive pkg-desc)
package-unsigned-archives))
diff --git a/test/lisp/emacs-lisp/package-resources/archive-contents
b/test/lisp/emacs-lisp/package-resources/archive-contents
index e2f9230..724972d 100644
--- a/test/lisp/emacs-lisp/package-resources/archive-contents
+++ b/test/lisp/emacs-lisp/package-resources/archive-contents
@@ -14,4 +14,38 @@
(multi-file .
[(0 2 3)
nil "Example of a multi-file tar package" tar
- ((:url . "http://puddles.li"))]))
+ ((:url . "http://puddles.li"))])
+ (checksum-valid .
+ [(123)
+ nil "A single-file package with a valid checksum." single
+ nil
+ 343
+ ((sha512 .
"a889917427569cc6817db5db08a88390d44ec010acdf6810c2dfaba04b9a03f00315378c3f03d5f4d531833028ad61db54c4c56106662585da6a0dde602f5c0d"))])
+ (checksum-valid-tar .
+ [(0 99)
+ nil "A multi-file package with a valid checksum." tar
+ nil
+ 10240
+ ((sha512 .
"2be7c37a16db32a2b08fc917ed5f4241814e2665bda1bd15328c2e5a842e45b81f6f31274697248ffaabf8010796685acb3342c5920af53ddd1e75d7fd764bd1"))])
+ (checksum-invalid .
+ [(1 0)
+ nil "A single-file package with an invalid checksum."
single
+ nil
+ 365
+ ((sha512 . "not-a-valid-checksum"))])
+ (checksum-invalid-tar .
+ [(0 1)
+ nil "A multi-file package with an invalid checksum."
tar
+ nil
+ 10240
+ ((sha512 . "not-a-valid-checksum"))])
+ (wrong-size-single .
+ [(1 0)
+ nil "A single-file package with an invalid size." single
+ nil
+ 1])
+ (wrong-size-tar .
+ [(1 0)
+ nil "A multi-file package with an invalid size." tar
+ nil
+ 1]))
diff --git a/test/lisp/emacs-lisp/package-resources/checksum-invalid-1.0.el
b/test/lisp/emacs-lisp/package-resources/checksum-invalid-1.0.el
new file mode 100644
index 0000000..c3d4790
--- /dev/null
+++ b/test/lisp/emacs-lisp/package-resources/checksum-invalid-1.0.el
@@ -0,0 +1,17 @@
+;;; checksum-invalid.el --- A package with an invalid checksum in
archive-contents
+
+;; Version: 1.0
+
+;;; Commentary:
+
+;; This package has an invalid checksum in archive-contents and is
+;; just used to verify that package.el refuses to install.
+
+;;; Code:
+
+(defun p-equal-to-np-p ()
+ (error "FIXME"))
+
+(provide 'checksum-invalid)
+
+;;; checksum-invalid.el ends here
diff --git
a/test/lisp/emacs-lisp/package-resources/checksum-invalid-tar-0.1.tar
b/test/lisp/emacs-lisp/package-resources/checksum-invalid-tar-0.1.tar
new file mode 100644
index 0000000..8adc7f5
Binary files /dev/null and
b/test/lisp/emacs-lisp/package-resources/checksum-invalid-tar-0.1.tar differ
diff --git a/test/lisp/emacs-lisp/package-resources/checksum-valid-123.el
b/test/lisp/emacs-lisp/package-resources/checksum-valid-123.el
new file mode 100644
index 0000000..8cfc387
--- /dev/null
+++ b/test/lisp/emacs-lisp/package-resources/checksum-valid-123.el
@@ -0,0 +1,17 @@
+;;; checksum-valid.el --- A package with an valid checksum in archive-contents
+
+;; Version: 123
+
+;;; Commentary:
+
+;; This package has an valid checksum in archive-contents and is
+;; used to verify that package.el installs it.
+
+;;; Code:
+
+(defun p-equal-to-np-p ()
+ (error "FIXME"))
+
+(provide 'checksum-valid)
+
+;;; checksum-valid.el ends here
diff --git a/test/lisp/emacs-lisp/package-resources/checksum-valid-tar-0.99.tar
b/test/lisp/emacs-lisp/package-resources/checksum-valid-tar-0.99.tar
new file mode 100644
index 0000000..e468754
Binary files /dev/null and
b/test/lisp/emacs-lisp/package-resources/checksum-valid-tar-0.99.tar differ
diff --git a/test/lisp/emacs-lisp/package-resources/wrong-size-single-1.0.el
b/test/lisp/emacs-lisp/package-resources/wrong-size-single-1.0.el
new file mode 100644
index 0000000..a4e3daf
--- /dev/null
+++ b/test/lisp/emacs-lisp/package-resources/wrong-size-single-1.0.el
@@ -0,0 +1 @@
+;; This file just has the wrong size (i.e. not 1 as specified).
diff --git a/test/lisp/emacs-lisp/package-resources/wrong-size-tar-1.0.tar
b/test/lisp/emacs-lisp/package-resources/wrong-size-tar-1.0.tar
new file mode 100644
index 0000000..61d47c6
Binary files /dev/null and
b/test/lisp/emacs-lisp/package-resources/wrong-size-tar-1.0.tar differ
diff --git a/test/lisp/emacs-lisp/package-tests.el
b/test/lisp/emacs-lisp/package-tests.el
index dd8ae39..f4b7528 100644
--- a/test/lisp/emacs-lisp/package-tests.el
+++ b/test/lisp/emacs-lisp/package-tests.el
@@ -43,6 +43,9 @@
(setq package-menu-async nil)
+;; Silence byte-compiler.
+(defvar epg-config--program-alist)
+
(defvar package-test-user-dir nil
"Directory to use for installing packages during testing.")
@@ -298,14 +301,33 @@ Must called from within a `tar-mode' buffer."
(with-package-test ()
(package-initialize)
(package-refresh-contents)
- (should (eq 4 (length package-archive-contents)))))
+ (should (eq 10 (length package-archive-contents)))))
(ert-deftest package-test-install-single-from-archive ()
"Install a single package from a package archive."
(with-package-test ()
(package-initialize)
(package-refresh-contents)
- (package-install 'simple-single)))
+ (package-install 'simple-single)
+ (should (package-installed-p 'simple-single))))
+
+(ert-deftest package-test-install-wrong-size-single ()
+ "Install a tar package with invalid size."
+ (should-error
+ (with-package-test ()
+ (package-initialize)
+ (package-refresh-contents)
+ (package-install 'wrong-size-single))
+ :type 'bad-size))
+
+(ert-deftest package-test-install-wrong-size-tar ()
+ "Install a tar package with invalid size."
+ (should-error
+ (with-package-test ()
+ (package-initialize)
+ (package-refresh-contents)
+ (package-install 'wrong-size-tar))
+ :type 'bad-size))
(ert-deftest package-test-install-prioritized ()
"Install a lower version from a higher-prioritized archive."
@@ -384,8 +406,8 @@ Must called from within a `tar-mode' buffer."
;; the testing environment currently only has one.
(package-menu-filter-by-archive "gnu")
(goto-char (point-min))
- (should (looking-at "^\\s-+multi-file"))
- (should (= (count-lines (point-min) (point-max)) 4))
+ (should (looking-at "^\\s-+checksum-invalid"))
+ (should (= (count-lines (point-min) (point-max)) 10))
(should-error (package-menu-filter-by-archive "non-existent archive"))))
(ert-deftest package-test-list-filter-by-keyword ()
@@ -411,7 +433,7 @@ Must called from within a `tar-mode' buffer."
(package-menu-filter-by-status "available")
(goto-char (point-min))
(should (re-search-forward "^\\s-+multi-file" nil t))
- (should (= (count-lines (point-min) (point-max)) 4))
+ (should (= (count-lines (point-min) (point-max)) 10))
;; No installed packages in default environment.
(should-error (package-menu-filter-by-status "installed"))))
@@ -668,6 +690,169 @@ Must called from within a `tar-mode' buffer."
"Status: Installed in ['`‘]signed-good-1.0/['’]."
nil t))))))
+
+;;; Tests for package checksum verification.
+
+(defmacro with-install-using-checksum (ok fail package)
+ "Test installing PACKAGE while setting `package-verify-checksums'."
+ (declare (indent 2))
+ `(progn
+ (dolist (opt ,ok)
+ (let ((package-verify-checksums opt))
+ (with-package-test ()
+ (package-initialize)
+ (package-refresh-contents)
+ (package-install ,package)
+ (package-installed-p ,package))))
+ (dolist (opt ,fail)
+ (let ((package-verify-checksums opt))
+ (should-error
+ (with-package-test ()
+ (package-initialize)
+ (package-refresh-contents)
+ (package-install ,package))
+ :type 'bad-checksum)))))
+
+(ert-deftest package-test-install-with-checksum/single-valid ()
+ "Install a single package with valid checksum."
+ (with-install-using-checksum '(nil allow-missing t all) '() 'checksum-valid))
+
+(ert-deftest package-test-install-with-checksum/single-invalid ()
+ "Install a tar package with invalid checksum."
+ (with-install-using-checksum '(nil) '(allow-missing t all)
'checksum-invalid))
+
+(ert-deftest package-test-install-with-checksum/tar-valid ()
+ "Install a tar package with valid checksum."
+ (with-install-using-checksum '(nil allow-missing t all) '()
'checksum-valid-tar))
+
+(ert-deftest package-test-install-with-checksum/tar-invalid ()
+ "Install a tar package with invalid checksum."
+ (with-install-using-checksum '(nil) '(allow-missing t all)
'checksum-invalid-tar))
+
+(defconst package-test-verification-text
+ "Example text for testing checksum verification.")
+(defconst package-tests-valid-md5-checksum
+ ;; (secure-hash 'md5 package-test-verification-text)
+ "abe6375809e532f081b808b3aa052dfb")
+(defconst package-tests-valid-sha256-checksum
+ ;; (secure-hash 'sha256 package-test-verification-text)
+ "6875aa4523e45ddef627b4edf1296f1d7dd0c22ddd6a6584f0228215d25eefcd")
+(defconst package-tests-valid-sha512-checksum
+ ;; (secure-hash 'sha512 package-test-verification-text)
+ (concat "bdc631f9e675b1ea34570f0a4bb44568dc5cecac905eea737f5f451bc52fd0c6"
+ "81b0d8b3dc2a942b9950fbe9096ebdf517668245c9b5a7bbdea8487a8f9cdce6"))
+
+(defmacro package-tests--run-verify-checksums-test (verify-checksums checksums)
+ "Run a test for `package-verify-checksums'."
+ (declare (indent 1))
+ `(with-temp-buffer
+ (insert package-test-verification-text)
+ (let ((package-verify-checksums ,verify-checksums)
+ (pkg (package-desc-create :name 'foobar
+ :version '(1 0)
+ :summary "Just a package with checksum."
+ :kind 'single
+ :checksums ,checksums)))
+ (package--verify-package-checksum pkg))))
+
+(ert-deftest package-test-verify-package-checksums-nil/ignore-invalid ()
+ "Ignore all checksums even when invalid."
+ (package-tests--run-verify-checksums-test nil
+ '((sha512 . "invalid")
+ (invalid . "invalid"))))
+
+(ert-deftest package-test-verify-package-checksums-nil/ignore-empty ()
+ "Ignore all checksums even when empty."
+ (package-tests--run-verify-checksums-test nil
+ nil))
+
+(ert-deftest package-test-verify-package-checksums-allow-missing ()
+ "Verify checksums (allow-missing) -- verify if available."
+ (package-tests--run-verify-checksums-test 'allow-missing
+ `((sha512 . ,package-tests-valid-sha512-checksum))))
+
+(ert-deftest package-test-verify-package-checksums-allow-missing/missing ()
+ "Verify checksums (allow-missing) -- allow missing."
+ (package-tests--run-verify-checksums-test 'allow-missing
+ nil))
+
+(ert-deftest
package-test-verify-package-checksums-allow-missing/ignore-unsupported ()
+ "Verify checksums (t) -- ignore unsupported algorithm."
+ (package-tests--run-verify-checksums-test 'allow-missing
+ `((ignore . "not supported")
+ (sha512 . ,package-tests-valid-sha512-checksum))))
+
+(ert-deftest package-test-verify-package-checksums-t ()
+ "Verify checksums (t) -- succeed when valid."
+ (package-tests--run-verify-checksums-test t
+ `((sha512 . ,package-tests-valid-sha512-checksum))))
+
+(ert-deftest package-test-verify-package-checksums-t/invalid-fails ()
+ "Verify checksums (t) -- fail on invalid."
+ (should-error
+ (package-tests--run-verify-checksums-test t
+ '((sha512 . "invalid")))
+ :type 'bad-checksum))
+
+(ert-deftest package-test-verify-package-checksums-t/missing-fails ()
+ "Verify checksums (t) -- fail on missing."
+ (should-error
+ (package-tests--run-verify-checksums-test t
+ nil)
+ :type 'bad-checksum))
+
+(ert-deftest package-test-verify-package-checksums-t/ignore-unsupported ()
+ "Verify checksums (t) -- ignore unsupported algorithm."
+ (package-tests--run-verify-checksums-test t
+ `((ignore . "not supported")
+ (sha512 . ,package-tests-valid-sha512-checksum))))
+
+(ert-deftest package-test-verify-package-checksums-all ()
+ "Verify checksums (all) -- succeed on valid."
+ (package-tests--run-verify-checksums-test 'all
+ `((md5 . ,package-tests-valid-md5-checksum)
+ (sha256 . ,package-tests-valid-sha256-checksum)
+ (sha512 . ,package-tests-valid-sha512-checksum))))
+
+(ert-deftest package-test-verify-package-checksums-all/invalid-fails ()
+ "Verify checksums (all) -- fail if one checksum is invalid."
+ (should-error
+ (package-tests--run-verify-checksums-test 'all
+ `((md5 . ,package-tests-valid-md5-checksum)
+ (sha256 . "invalid")
+ (sha512 . ,package-tests-valid-sha512-checksum)))
+ :type 'bad-checksum))
+
+(ert-deftest package-test-verify-package-checksums-all/missing-fails ()
+ "Verify checksums (all) -- fail on missing checksums."
+ (should-error
+ (package-tests--run-verify-checksums-test 'all
+ nil)
+ :type 'bad-checksum))
+
+(ert-deftest package-test-verify-package-checksums-all/no-supported-hash-fails
()
+ "Verify checksums (all) -- fail if we have no supported hash."
+ (should-error
+ (package-tests--run-verify-checksums-test 'all
+ '((unsupported . "invalid")))
+ :type 'bad-checksum))
+
+(ert-deftest package-test-verify-package-checksums-all/ignore-unsupported ()
+ "Verify checksums (all) -- succed if one hash algorithm is unsupported.
+If the rest succeed, just ignore the unsupported one."
+ (package-tests--run-verify-checksums-test 'all
+ `((md5 . ,package-tests-valid-md5-checksum)
+ (sha256 . ,package-tests-valid-sha256-checksum)
+ (sha512 . ,package-tests-valid-sha512-checksum)
+ (ignore . "not supported"))))
+
+(ert-deftest package-test-verify-package-size ()
+ (with-temp-buffer
+ (let ((pkg-desc (package-desc-create :size 6)))
+ (insert "123456")
+ (package--verify-package-size pkg-desc)
+ (insert "7")
+ (should-error (package--verify-package-size pkg-desc)))))
;;; Tests for package-x features.
@@ -681,7 +866,9 @@ Must called from within a `tar-mode' buffer."
'single
'((:authors ("J. R. Hacker" . "jrh@example.com"))
(:maintainer "J. R. Hacker" .
"jrh@example.com")
- (:url . "http://doodles.au"))))
+ (:url . "http://doodles.au"))
+ nil
+ nil))
"Expected contents of the archive entry from the \"simple-single\" package.")
(defvar package-x-test--single-archive-entry-1-4
@@ -690,7 +877,9 @@ Must called from within a `tar-mode' buffer."
"A single-file package with no dependencies"
'single
'((:authors ("J. R. Hacker" . "jrh@example.com"))
- (:maintainer "J. R. Hacker" .
"jrh@example.com"))))
+ (:maintainer "J. R. Hacker" .
"jrh@example.com"))
+ nil
+ nil))
"Expected contents of the archive entry from the updated \"simple-single\"
package.")
(ert-deftest package-x-test-upload-buffer ()