ssot

package
v1.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 8, 2020 License: Unlicense Imports: 20 Imported by: 0

Documentation

Overview

Package ssot implements a single source of truth (SSOT) with DNS TXT records.

Signed head specification

Signed heads have the following fields:

  • PUBKEY (32-byte), the Ed25519 public key of SSOT head signer.
  • PUBKEY_ROTATE (32-byte), Ed25519 pubkey to rotate to, set to 0 if unused.
  • VALID_FROM (8-byte), the signed head is valid from the given Unix time.
  • VALID_TO (8-byte), the signed head is valid to the given Unix time.
  • COUNTER (8-byte), strictly increasing signature counter.
  • HEAD, the Codechain head to sign.
  • SIGNATURE, signature with PUBKEY.

The SIGNATURE is over all previous fields:

PUBKEY|PUBKEY_ROTATE|VALID_FROM|VALID_TO|COUNTER|HEAD

The signed head is a concatenation of

PUBKEY|PUBKEY_ROTATE|VALID_FROM|VALID_TO|COUNTER|HEAD|SIGNATURE

encoded in base64 (URL encoding without padding).

All integers (VALID_FROM, VALID_TO, COUNTER) are encoded in network order (big-endian).

CreatePkg specification

To create a new secure package for a project developed with Codechain that should be distributed with a SSOT using DNS TXT records, the following procedure is defined:

  1. Make sure the project with NAME has not been published before. That is, the directory ~/.config/ssotpub/pkgs/NAME does not exist.

  2. If TXT records are to be published automatically, check credentials.

  3. Test build (see TestBuild specification).

  4. Create a new .secpkg file which specifies the following:

    - The NAME of the project. - The fully qualified domain name (DNS) where the TXT records can be queried. - The current HEAD of the project's Codechain.

    The .secpkg file is saved to the current working directory, which is typically added to the root of the project's repository.

  5. Create the first signed head (see SignHead) for the current project's HEAD with a supplied secret key and counter set to 0.

  6. Create the directory ~/.config/ssotpub/pkgs/NAME/dists and save the current distribution to ~/.config/ssotpub/pkgs/NAME/dists/HEAD.tar.gz (`codechain createdist`).

  7. Save the signed head to ~/.config/ssotpub/pkgs/NAME/signed_head

  8. Print the distribution name: ~/.config/secpkg/pkgs/NAME/dists/HEAD.tar.gz

  9. Print DNS TXT records as defined by the .secpkg, the first signed head, and the download URL. If TXT records are to be published automatically, save credentials and publish the TXT record.

    Afterwards the administrator manually uploads the distribution HEAD.tar.gz to the download URL and publishes the new DNS TXT record in the defined zone (if not published automatically). DNSSEC should be enabled.

SignHead specification

To publish an update of a secure package with SSOT do the following:

  1. Parse the .secpkg file in the current working directory.

  2. Make sure the project with NAME has been published before. That is, the directory ~/.config/ssotpub/pkgs/NAME exists.

  3. Validate the signed head in ~/.config/ssotpub/pkgs/NAME/signed_head.

  4. Get the HEAD from .codechain/hashchain in the current working directory.

  5. If ~/.config/ssotpub/pkgs/NAME/cloudflare.json exits, check the contained Cloudflare credentials and switch on automatic publishing of TXT records.

  6. Test build (see TestBuild specification).

  7. If ROTATE is set, check if ~/.config/ssotput/pkgs/NAME/rotate_to exists. If it does, abort. Otherwise write public key to rotate to and rotate time (see below) to ~/.config/ssotput/pkgs/NAME/rotate_to.

  8. Create a new signed head with current HEAD, the counter of the previous signed head plus 1, and update the saved signed head:

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

    If ~/.config/ssotput/pkgs/NAME/rotate_to exists:

    - If rotate time has been reached use pubkey from file as PUBKEY and remove ~/.config/ssotput/pkgs/NAME/rotate_to. - Otherwise use old PUBKEY and set pubkey from file as PUBKEY_ROTATE.

  9. If the HEAD changed, save the current distribution to: ~/.config/secpkg/pkgs/NAME/dists/HEAD.tar.gz (`codechain createdist`).

  10. If the HEAD changed, lookup the download URLs and print where to upload the distribution file: ~/.config/ssotpkg/pkgs/NAME/dists/HEAD.tar.gz

  11. Print DNS TXT record as defined by the .secpkg file and the signed head. If TXT records are to be published automatically, publish the TXT record.

  12. If the HEAD changed, update the .secpkg file accordingly.

    Afterwards the administrator manually uploads the distribution HEAD.tar.gz to the download URLs and publishes the new DNS TXT record in the defined zone (if not published automatically). DNSSEC should be enabled.

Refresh specification

To refresh the published head of a secure package with SSOT do the following:

  1. Parse the supplied .secpkg file.

  2. Make sure the project with NAME has been published before. That is, the directory ~/.config/ssotpub/pkgs/NAME exists.

  3. Validate the signed head in ~/.config/ssotpub/pkgs/NAME/signed_head.

  4. Make sure the signed head in ~/.config/ssotpub/pkgs/NAME/signed_head matches the HEAD in the .secpkg file.

  5. If ~/.config/ssotpub/pkgs/NAME/cloudflare.json exits, check the contained Cloudflare credentials and switch on automatic publishing of TXT records.

  6. If ROTATE is set, check if ~/.config/ssotput/pkgs/NAME/rotate_to exists. If it does, abort. Otherwise write public key to rotate to and rotate time (see below) to ~/.config/ssotput/pkgs/NAME/rotate_to.

  7. Create a new signed head with the same HEAD, the counter of the previous signed head plus 1, and update the saved signed head:

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

    If ~/.config/ssotput/pkgs/NAME/rotate_to exists:

    - If rotate time has been reached use pubkey from file as PUBKEY and remove ~/.config/ssotput/pkgs/NAME/rotate_to. - Otherwise use old PUBKEY and set pubkey from file as PUBKEY_ROTATE.

  8. Print DNS TXT record as defined by the .secpkg file and the signed head. If TXT record is to be published automatically, publish the TXT record.

    Afterwards the administrator publishes the new DNS TXT record in the defined zone (if not published automatically). DNSSEC should be enabled.

TestBuild specification

To test the build of a secure package do the following:

  1. Create temporary directory TMPDIR with `build` and `local` subdirectories.

  2. `mkdir TMPDIR/build/.codechain`

  3. `cp .codechain/hashchain TMPDIR/build/.codechain`

  4. `cp -r .codechain/patches TMPDIR/build/.codechain`

  5. `cd TMPDIR/build`

  6. `codechain apply`

  7. `make prefix=TMPDIR/local`

  8. `make prefix=TMPDIR/local install`

  9. Make sure TMPDIR/local contains at least one file.

  10. `make prefix=TMPDIR/local uninstall`

  11. Make sure TMPDIR/local contains no files (but empty directories are OK).

  12. Delete temporary directory TMPDIR.

Rotate time calculation

The earliest time a PUBKEY_ROTATE can be used as PUBKEY is when the previous signed head (without PUBKEY_ROTATE) has expired. This gives clients time to learn about PUBKEY_ROTATE. To give some extra time we take the time span a signed head with PUBKEY_ROTATE is valid after the signed head without PUBKEY_ROTATE has expired and divide it by three. The rotate time is set to the end of the first third.

Index

Constants

View Source
const File = "signed_head"

File defines the default file name for a signed head.

View Source
const MaximumValidity = 30 * 24 * time.Hour // 30d

MaximumValidity of signed heads.

View Source
const MinimumValidity = 1 * time.Hour // 1h

MinimumValidity of signed heads.

View Source
const TTL = 600 // 10m

TTL of signed head TXT records

Variables

View Source
var ErrSignedHeadExpired = errors.New("ssot: signed head is expired")

ErrSignedHeadExpired is returned if the validity of a signed head is expired.

View Source
var ErrSignedHeadFuture = errors.New("ssot: signed head is valid in the future")

ErrSignedHeadFuture is returned if the validity of a signed head is in the future.

View Source
var ErrSignedHeadSignature = errors.New("ssot: signed head signature does not verify")

ErrSignedHeadSignature is returned if a signed head signature does not verify.

View Source
var ErrValidityTooLong = errors.New("ssot: validity is too long")

ErrValidityTooLong is returned if the validity is too long.

View Source
var ErrValidityTooShort = errors.New("ssot: validity is too short")

ErrValidityTooShort is returned if the validity is too short.

Functions

func LookupURLs added in v1.1.0

func LookupURLs(ctx context.Context, dns string) ([]string, error)

LookupURLs looks up all URLs from dns and returns it.

func ReadRotateTo

func ReadRotateTo(filename string) (string, bool, error)

ReadRotateTo reads "rotate to" file from given filename and returns the public key to rotate to and a bool indicating if the rotation time has been reached.

func TXTPrintURL

func TXTPrintURL(dns, url string)

TXTPrintURL prints the TXT record to publish the url.

Types

type SignedHead

type SignedHead struct {
	// contains filtered or unexported fields
}

SignedHead is a signed Codechain head ready for publication as a SSOT with DNS TXT records.

func Load

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

Load and verify a base64 encoded signed head from filename.

func LookupHead

func LookupHead(ctx context.Context, dns string) (*SignedHead, error)

LookupHead and verify base64 encoded signed head from dns.

func SignHead

func SignHead(
	head [32]byte,
	counter uint64,
	secKey [64]byte,
	pubKeyRotate *[32]byte,
	validity time.Duration,
) (*SignedHead, error)

SignHead signs the given Codechain head.

func Unmarshal

func Unmarshal(signedHead string) (*SignedHead, error)

Unmarshal and verify a base64 encoded signed head.

func (*SignedHead) Counter

func (sh *SignedHead) Counter() uint64

Counter returns the counter of signed head.

func (*SignedHead) Head

func (sh *SignedHead) Head() string

Head returns the signed head.

func (*SignedHead) HeadBuf

func (sh *SignedHead) HeadBuf() [32]byte

HeadBuf returns the signed head.

func (*SignedHead) Marshal

func (sh *SignedHead) Marshal() string

Marshal signed head with signature and encode it as base64.

func (*SignedHead) MarshalText

func (sh *SignedHead) MarshalText() string

MarshalText marshals signed head as text (for status output).

func (*SignedHead) PubKey

func (sh *SignedHead) PubKey() string

PubKey returns the public key in base64 notation.

func (*SignedHead) PubKeyRotate

func (sh *SignedHead) PubKeyRotate() string

PubKeyRotate returns the public key rotate in base64 notation.

func (*SignedHead) RotateFile

func (sh *SignedHead) RotateFile(pkgDir string) error

RotateFile rotates the pkgDir/signed_head to pkgDir/previous_signed_head and saves signed head sh to pkgDir/signed_head.

func (*SignedHead) TXTPrintHead

func (sh *SignedHead) TXTPrintHead(dns string)

TXTPrintHead prints the TXT record to publish the signed head.

func (*SignedHead) Valid

func (sh *SignedHead) Valid() error

Valid checks if the signed head sh is currently valid (as defined by validFrom and validTo). It returns nil, if the signed check is valid and an error otherwise.

func (*SignedHead) WriteRotateTo

func (sh *SignedHead) WriteRotateTo(
	filename string,
	secKeyRotate *[64]byte,
	sigRotate *[64]byte,
	commentRotate []byte,
	validity time.Duration,
) error

WriteRotateTo writes "rotate to" file to given filename.

Directories

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

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL