Documentation

Overview

Package secpkg implements the secpkg package format.

A secure package (.secpkg file) contains a JSON object with the following keys:

{
  "Name": "the project's package name",
  "Head": "head of project's Codechain",
  "DNS": "fully qualified domain name for Codechain's TXT records",
}

Example .secpkg file for Codechain itself:

{
  "Name": "codechain",
  "Head": "53f2c26d92e173306e83d54e3103ef2e0bd87a561315bc4b49e1ee6c78dfb583",
  "DNS": "codechain.secpkg.net",
}

If in the root of a package source tree the directory .secdep exists and contains any .secpkg files, then these secure dependencies are installed and kept up-to-date by the install and update procedures specified below.

Install specification

Installing software described by a .secpkg file works as follows:

 1. Parse .secpkg file and validate it. Save head as HEAD_PKG.

 2. Make sure the project with NAME has not been installed before.
    That is, the directory ~/.config/secpkg/pkgs/NAME does not exist.

 3. Create directory ~/.config/secpkg/pkgs/NAME

 4. Save .secpkg file to ~/.config/secpkg/pkgs/NAME/.secpkg

 5. Query TXT record from _codechain-head.DNS and validate the signed head
    contained in it (see ssot package). Save head from TXT record (HEAD_SSOT).

 6. Query all TXT records from _codechain-url.DNS and save it as URLs.

 7. Store the signed head to ~/.config/secpkg/pkgs/NAME/signed_head

 8. Select next URL from URLs. If no such URL exists, exit with error.

 9. Download distribution file from URL/HEAD_SSOT.tar.gz and save it to
    ~/.config/secpkg/pkgs/NAME/dists
    If it fails: Goto 8.

10. Apply ~/.config/secpkg/pkgs/NAME/dists/HEAD_SSOT.tar.gz
    to ~/.config/secpkg/pkgs/NAME/src with `codechain apply
    -f ~/.config/secpkg/pkgs/NAME/dists/HEAD_SSOT.tar.gz -head HEAD_SSOT`
    If it fails: Goto 8.

11. Make sure HEAD_PKG is contained in
    ~/.config/secpkg/pkgs/NAME/src/.codchain/hashchain
    If it fails: Goto 8.

12. If the directory ~/.config/secpkg/pkgs/NAME/src/.secdep exists and
    contains any .secpkg files, ensure these secure dependencies are
    installed and up-to-date.

13. `cp -r ~/.config/secpkg/pkgs/NAME/src ~/.config/secpkg/pkgs/NAME/build`

14. Call `make prefix=~/.config/secpkg/local` in
    ~/.config/secpkg/pkgs/NAME/build

15. Call `make prefix= ~/.config/secpkg/local install` in
    ~/.config/secpkg/pkgs/NAME/build

16. `mv ~/.config/secpkg/pkgs/NAME/build ~/.config/secpkg/pkgs/NAME/installed`

If the installation process fails at any stage during the procedure described
above, report the error and remove the directory ~/.config/secpkg/pkgs/NAME.

For the process above to work, the projects distributed as secure packages must contain a Makefile (for GNU Make) with the "all" target building the software and the "install" target installing it.

The software must be self-contained without any external dependencies, except for the compiler. For Go software that means at least Go 1.11 must be installed (with module support) and all dependencies must be vendored.

Update specification

Updating a software package with NAME works as follows:

 1. Make sure the project with NAME has been installed before.
    That is, the directory ~/.config/secpkg/pkgs/NAME exists.
    Set SKIP_BUILD to false.

 2. Load .secpkg file from ~/.config/secpkg/pkgs/NAME/.secpkg

 3. Load signed head from ~/.config/secpkg/pkgs/NAME/signed_head (as DISK)

 4. Query TXT record from _codechain-head.DNS, if it is the same as DISK, set
    SKIP_BUILD to true.

 5. Query all TXT records from _codechain-url.DNS and save it as URLs.

 6. If not SKIP_BUILD, validate signed head from TXT (also see ssot package)
    and store HEAD:

    - pubKey from TXT must be the same as pubKey or pubKeyRotate from DISK,
      if the signed head from DISK is not expired.
    - The counter from TXT must be larger than the counter from DISK.
    - The signed head must be valid (as defined by validFrom and validTo).

    If the validation fails, abort update procedure and report error.

 7. If not SKIP_BUILD and if signed head from TXT record is the same as the
    one from DISK, set SKIP_BUILD to true.

 8. If SKIP_BUILD, check if HEAD is contained in
    ~/.config/secpkg/pkgs/NAME/src/.codchain/hashchain.
    If not, set SKIP_BUILD to false.
    This can happend if we checked for updates.

 9. Select next URL from URLs. If no such URL exists, exit with error.

10. If not SKIP_BUILD, download distribution file from URL/HEAD.tar.gz and
    save it to ~/.config/secpkg/pkgs/NAME/dists
    If it fails: Goto 9.

11. If not SKIP_BUILD, apply ~/.config/secpkg/pkgs/NAME/dists/HEAD.tar.gz
    to ~/.config/secpkg/pkgs/NAME/src with `codechain apply
    -f ~/.config/secpkg/pkgs/NAME/dists/HEAD.tar.gz -head HEAD`.
    If it fails: Goto 9.

12. If the directory ~/.config/secpkg/pkgs/NAME/src/.secdep exists and
    contains any .secpkg files, ensure these secure dependencies are
    installed and up-to-date. If at least one dependency was updated, set
    SKIP_BUILD to false.

13. If not SKIP_BUILD, call `make prefix=~/.config/secpkg/local uninstall` in
    ~/.config/secpkg/pkgs/NAME/installed

14. If not SKIP_BUILD, `rm -rf ~/.config/secpkg/pkgs/NAME/build`

15. If not SKIP_BUILD,
    `cp -r ~/.config/secpkg/pkgs/NAME/src ~/.config/secpkg/pkgs/NAME/build`

16. If not SKIP_BUILD, call `make prefix=~/.config/secpkg/local` in
    ~/.config/secpkg/pkgs/NAME/build

17. If not SKIP_BUILD, call `make prefix= ~/.config/secpkg/local install` in
    ~/.config/secpkg/pkgs/NAME/build

18. If not SKIP_BUILD,
    `mv ~/.config/secpkg/pkgs/NAME/build ~/.config/secpkg/pkgs/NAME/installed`

19. Update signed head:

    - `cp -f ~/.config/secpkg/pkgs/NAME/signed_head
             ~/.config/secpkg/pkgs/NAME/previous_signed_head`
    - Save new signed head to ~/.config/secpkg/pkgs/NAME/signed_head (atomic).

20. The software has been successfully updated.

CheckUpdate specification

Checking if a software package with NAME needs an update works as follows:

 1. Make sure the project with NAME has been installed before.
    That is, the directory ~/.config/secpkg/pkgs/NAME exists.
    Set SKIP_CHECK and NEEDS_UPDATE to false.

 2. Load .secpkg file from ~/.config/secpkg/pkgs/NAME/.secpkg

 3. Load signed head from ~/.config/secpkg/pkgs/NAME/signed_head (as DISK)

 4. Query TXT record from _codechain-head.DNS, if it is the same as DISK, set
    SKIP_CHECK to true.

 5. If not SKIP_CHECK, validate signed head from TXT (also see ssot package)
    and store HEAD:

    - pubKey from TXT must be the same as pubKey or pubKeyRotate from DISK,
      if the signed head from DISK is not expired.
    - The counter from TXT must be larger than the counter from DISK.
    - The signed head must be valid (as defined by validFrom and validTo).

    If the validation fails, abort check update procedure and report error.

 6. If not SKIP_CHECK and if signed head from TXT record not the same as the
    one from DISK, set SKIP_CHECK and NEEDS_UPDATE to true.

 7. If not NEEDS_UPDATE, check if HEAD is contained in
    ~/.config/secpkg/pkgs/NAME/src/.codchain/hashchain.
    If not, set NEEDS_UPDATE to true.

 8. If NEEDS_UPDATE is false, check if the directory
    ~/.config/secpkg/pkgs/NAME/src/.secdep exists and contains any .secpkg
    files, ensure these secure dependencies are installed and up-to-date. If
    at least one dependency needs an update, set NEEDS_UPDATE to true.

 9. Update signed head:

    - `cp -f ~/.config/secpkg/pkgs/NAME/signed_head
             ~/.config/secpkg/pkgs/NAME/previous_signed_head`
    - Save new signed head to ~/.config/secpkg/pkgs/NAME/signed_head (atomic).

10. Return NEEDS_UPDATE.

Index

Constants

View Source
const File = ".secpkg"

File defines the default file (ending) for a secure package.

Variables

View Source
var ErrNoKey = errors.New("secpkg: package has no secretbox encryption key")

ErrNoKey is returned if a package has no secretbox encryption key.

View Source
var ErrNotInstalled = errors.New("secpkg: package not installed")

ErrNotInstalled is returned if a package is not installed.

View Source
var ErrPkgNameWhitespace = errors.New("secpkg: package name contains white space character")

ErrPkgNameWhitespace is returned if a package name contains a white space character.

Functions

func CheckUpdate

func CheckUpdate(ctx context.Context, name string) (bool, error)

CheckUpdate checks installed package with name for updates, see specification for details.

func Uninstall

func Uninstall(name string) error

Uninstall package with name.

func UpToDate

func UpToDate(name string) error

UpToDate ensures that the package with name is up-to-date, if it is installed as a secure package. If the package is not installed as a secure package a corresponding message is shown on stderr.

UpToDate times out after a while if DNS cannot be queried and return nil.

func UpToDateIfInstalled

func UpToDateIfInstalled(ctx context.Context, name string) error

UpToDateIfInstalled ensures that the package with name is up-to-date, if it is installed as a secure package. If the package is not installed as a secure package a corresponding message is shown on stderr.

func Update

func Update(ctx context.Context, name string) error

Update package with name, see specification for details.

Types

type Package

type Package struct {
	Name string // the project's package name
	Head string // head of project's Codechain
	DNS  string // fully qualified domain name for Codechain's TXT records (SSOT)
	Key  string `json:",omitempty"` // optional secretbox encryption key
}

Package defines a package in secpkg format (stored in .secpkg files).

func Load

func Load(filename string) (*Package, error)

Load a .secpkg file from filename and return the Package struct.

func New

func New(name, dns string, head [32]byte, encrypted bool) (*Package, error)

New creates a new Package.

func (*Package) GetKey

func (pkg *Package) GetKey() (*[32]byte, error)

GetKey returns the secretbox encryption key or an error if the key does not exist or is not parsable.

func (*Package) Install

func (pkg *Package) Install(ctx context.Context) error

Install pkg, see specification for details.

func (*Package) Marshal

func (pkg *Package) Marshal() string

Marshal pkg as string.

Directories

Path Synopsis
Package command implements the secpkg commands.
Package command implements the secpkg commands.