in_toto

package
v0.0.0-...-51eebe4 Latest Latest
Warning

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

Go to latest
Published: Mar 12, 2023 License: Apache-2.0 Imports: 37 Imported by: 0

Documentation

Overview

Package in_toto implements types and routines to verify a software supply chain according to the in-toto specification. See https://github.com/in-toto/docs/blob/master/in-toto-spec.md

Index

Examples

Constants

View Source
const (
	// StatementInTotoV01 is the statement type for the generalized link format
	// containing statements. This is constant for all predicate types.
	StatementInTotoV01 = "https://in-toto.io/Statement/v0.1"
	// PredicateSPDX represents a SBOM using the SPDX standard.
	// The SPDX mandates 'spdxVersion' field, so predicate type can omit
	// version.
	PredicateSPDX = "https://spdx.dev/Document"
	// PredicateCycloneDX represents a CycloneDX SBOM
	PredicateCycloneDX = "https://cyclonedx.org/bom"
	// PredicateLinkV1 represents an in-toto 0.9 link.
	PredicateLinkV1 = "https://in-toto.io/Link/v1"
)
View Source
const (
	AllowAllConstraint = "*"
)
View Source
const ISO8601DateSchema = "2006-01-02T15:04:05Z"

ISO8601DateSchema defines the format string of a timestamp following the ISO 8601 standard.

View Source
const LinkGlobFormat = "%s.????????.link"
View Source
const LinkNameFormat = "%s.%.8s.link"

LinkNameFormat represents a format string used to create the filename for a signed Link (wrapped in a Metablock). It consists of the name of the link and the first 8 characters of the signing key id. E.g.:

fmt.Sprintf(LinkNameFormat, "package",
"2f89b9272acfc8f4a0a0f094d789fdb0ba798b0fe41f2f5f417c12f0085ff498")
// returns "package.2f89b9272.link"
View Source
const LinkNameFormatShort = "%s.link"

LinkNameFormatShort is for links that are not signed, e.g.:

fmt.Sprintf(LinkNameFormatShort, "unsigned")
// returns "unsigned.link"
View Source
const PayloadType = "application/vnd.in-toto+json"

PayloadType is the payload type used for links and layouts.

View Source
const PreliminaryLinkNameFormat = ".%s.%.8s.link-unfinished"
View Source
const SublayoutLinkDirFormat = "%s.%.8s"

SublayoutLinkDirFormat represents the format of the name of the directory for sublayout links during the verification workflow.

Variables

View Source
var ErrCurveSizeSchemeMismatch = errors.New("the scheme does not match the curve size")

ErrCurveSizeSchemeMismatch gets returned, when the scheme and curve size are incompatible for example: curve size = "521" and scheme = "ecdsa-sha2-nistp224"

View Source
var ErrEmptyCommandArgs = errors.New("the command args are empty")
View Source
var ErrEmptyKeyField = errors.New("empty field in key")

ErrEmptyKeyField will be thrown if a field in our Key struct is empty.

View Source
var ErrFailedPEMParsing = errors.New("failed parsing the PEM block: unsupported PEM type")

ErrFailedPEMParsing gets returned when PKCS1, PKCS8 or PKIX key parsing fails

View Source
var ErrInspectionRunDirIsSymlink = errors.New("runDir is a symlink. This is a security risk")

ErrInspectionRunDirIsSymlink gets thrown if the runDir is a symlink

View Source
var ErrInvalidHexString = errors.New("invalid hex string")

ErrInvalidHexString will be thrown, if a string doesn't match a hex string.

View Source
var ErrInvalidKey = errors.New("invalid key")

ErrInvalidKey is returned when a given key is none of RSA, ECDSA or ED25519

View Source
var ErrInvalidPayloadType = errors.New("unknown payload type")

ErrInvalidPayloadType indicates that the envelope used an unkown payload type

View Source
var ErrInvalidSignature = errors.New("invalid signature")

ErrInvalidSignature is returned when the signature is invalid

View Source
var ErrKeyKeyTypeMismatch = errors.New("the given key does not match its key type")

ErrKeyKeyTypeMismatch will be thrown, if the specified keyType does not match the key

View Source
var ErrNoPEMBlock = errors.New("failed to decode the data as PEM block (are you sure this is a pem file?)")

ErrNoPEMBlock gets triggered when there is no PEM block in the provided file

View Source
var ErrNoPublicKey = errors.New("the given key is not a public key")

ErrNoPublicKey gets returned when the private key value is not empty.

View Source
var ErrSchemeKeyTypeMismatch = errors.New("the scheme and key type are not supported together")

ErrSchemeKeyTypeMismatch will be thrown, if the given scheme and key type are not supported together.

View Source
var ErrSymCycle = errors.New("symlink cycle detected")

ErrSymCycle signals a detected symlink cycle in our RecordArtifacts() function.

View Source
var ErrUnsupportedHashAlgorithm = errors.New("unsupported hash algorithm detected")

ErrUnsupportedHashAlgorithm signals a missing hash mapping in getHashMapping

View Source
var ErrUnsupportedKeyIDHashAlgorithms = errors.New("the given keyID hash algorithm is not supported")

ErrUnsupportedKeyIDHashAlgorithms will be thrown, if the specified KeyIDHashAlgorithms is not supported.

View Source
var ErrUnsupportedKeyType = errors.New("unsupported key type")

ErrUnsupportedKeyType is returned when we are dealing with a key type different to ed25519 or RSA

Functions

func InterfaceKeyStrings

func InterfaceKeyStrings(m map[string]interface{}) []string

InterfaceKeyStrings returns string keys of passed interface{} map in an unordered string slice.

func LoadLayoutCertificates

func LoadLayoutCertificates(layout Layout, intermediatePems [][]byte) (*x509.CertPool, *x509.CertPool, error)

LoadLayoutCertificates loads the root and intermediate CAs from the layout if in the layout. This will be used to check signatures that were used to sign links but not configured in the PubKeys section of the step. No configured CAs means we don't want to allow this. Returned CertPools will be empty in this case.

func LoadLinksForLayout

func LoadLinksForLayout(layout Layout, linkDir string) (map[string]map[string]Metablock, error)

LoadLinksForLayout loads for every Step of the passed Layout a Metablock containing the corresponding Link. A base path to a directory that contains the links may be passed using linkDir. Link file names are constructed, using LinkNameFormat together with the corresponding step name and authorized functionary key ids. A map of link metadata is returned and has the following format:

{
	<step name> : {
		<key id>: Metablock,
		<key id>: Metablock,
		...
	},
	<step name> : {
	<key id>: Metablock,
	<key id>: Metablock,
	...
	}
	...
}

If a link cannot be loaded at a constructed link name or is invalid, it is ignored. Only a preliminary threshold check is performed, that is, if there aren't at least Threshold links for any given step, the first return value is an empty map of Metablock maps and the second return value is the error.

func RecordArtifact

func RecordArtifact(path string, hashAlgorithms []string, lineNormalization bool) (map[string]interface{}, error)

RecordArtifact reads and hashes the contents of the file at the passed path using sha256 and returns a map in the following format:

{
	"<path>": {
		"sha256": <hex representation of hash>
	}
}

If reading the file fails, the first return value is nil and the second return value is the error. NOTE: For cross-platform consistency Windows-style line separators (CRLF) are normalized to Unix-style line separators (LF) before hashing file contents.

func RecordArtifacts

func RecordArtifacts(paths []string, hashAlgorithms []string, gitignorePatterns []string, lStripPaths []string, lineNormalization bool, followSymlinkDirs bool) (evalArtifacts map[string]interface{}, err error)

RecordArtifacts is a wrapper around recordArtifacts. RecordArtifacts initializes a set for storing visited symlinks, calls recordArtifacts and deletes the set if no longer needed. recordArtifacts walks through the passed slice of paths, traversing subdirectories, and calls RecordArtifact for each file. It returns a map in the following format:

{
	"<path>": {
		"sha256": <hex representation of hash>
	},
	"<path>": {
	"sha256": <hex representation of hash>
	},
	...
}

If recording an artifact fails the first return value is nil and the second return value is the error.

func ReduceStepsMetadata

func ReduceStepsMetadata(layout Layout,
	stepsMetadata map[string]map[string]Metablock) (map[string]Metablock,
	error)

ReduceStepsMetadata merges for each step of the passed Layout all the passed per-functionary links into a single link, asserting that the reported Materials and Products are equal across links for a given step. This function may be used at a time during the overall verification, where link threshold's have been verified and subsequent verification only needs one exemplary link per step. The function returns a map with one Metablock (link) per step:

{
	<step name> : Metablock,
	<step name> : Metablock,
	...
}

If links corresponding to the same step report different Materials or different Products, the first return value is an empty Metablock map and the second return value is the error.

func RunCommand

func RunCommand(cmdArgs []string, runDir string) (map[string]interface{}, error)

RunCommand executes the passed command in a subprocess. The first element of cmdArgs is used as executable and the rest as command arguments. It captures and returns stdout, stderr and exit code. The format of the returned map is:

{
	"return-value": <exit code>,
	"stdout": "<standard output>",
	"stderr": "<standard error>"
}

If the command cannot be executed or no pipes for stdout or stderr can be created the first return value is nil and the second return value is the error. NOTE: Since stdout and stderr are captured, they cannot be seen during the command execution.

func RunInspections

func RunInspections(layout Layout, runDir string, lineNormalization bool) (map[string]Metablock, error)

RunInspections iteratively executes the command in the Run field of all inspections of the passed layout, creating unsigned link metadata that records all files found in the current working directory as materials (before command execution) and products (after command execution). A map with inspection names as keys and Metablocks containing the generated link metadata as values is returned. The format is:

{
	<inspection name> : Metablock,
	<inspection name> : Metablock,
	...
}

If executing the inspection command fails, or if the executed command has a non-zero exit code, the first return value is an empty Metablock map and the second return value is the error.

func UnpackRule

func UnpackRule(rule []string) (map[string]string, error)

UnpackRule parses the passed rule and extracts and returns the information required for rule processing. It can be used to verify if a rule has a valid format. Available rule formats are:

MATCH <pattern> [IN <source-path-prefix>] WITH (MATERIALS|PRODUCTS)
	[IN <destination-path-prefix>] FROM <step>,
CREATE <pattern>,
DELETE <pattern>,
MODIFY <pattern>,
ALLOW <pattern>,
DISALLOW <pattern>

Rule tokens are normalized to lower case before returning. The returned map has the following format:

{
	"type": "match" | "create" | "delete" |"modify" | "allow" | "disallow"
	"pattern": "<file name pattern>",
	"srcPrefix": "<path or empty string>", // MATCH rule only
	"dstPrefix": "<path or empty string>", // MATCH rule only
	"dstType": "materials" | "products">, // MATCH rule only
	"dstName": "<step name>", // Match rule only
}

If the rule does not match any of the available formats the first return value is nil and the second return value is the error.

func ValidateMetablock

func ValidateMetablock(mb Metablock) error

ValidateMetablock ensures that a passed Metablock object is valid. It indirectly validates the Link or Layout that the Metablock object contains.

func VerifyArtifacts

func VerifyArtifacts(items []interface{},
	itemsMetadata map[string]Metablock) error

VerifyArtifacts iteratively applies the material and product rules of the passed items (step or inspection) to enforce and authorize artifacts (materials or products) reported by the corresponding link and to guarantee that artifacts are linked together across links. In the beginning all artifacts are placed in a queue according to their type. If an artifact gets consumed by a rule it is removed from the queue. An artifact can only be consumed once in the course of processing the set of rules in ExpectedMaterials or ExpectedProducts.

Rules of type MATCH, ALLOW, CREATE, DELETE, MODIFY and DISALLOW are supported.

All rules except for DISALLOW consume queued artifacts on success, and leave the queue unchanged on failure. Hence, it is left to a terminal DISALLOW rule to fail overall verification, if artifacts are left in the queue that should have been consumed by preceding rules.

func VerifyCertificateTrust

func VerifyCertificateTrust(cert *x509.Certificate, rootCertPool, intermediateCertPool *x509.CertPool) ([][]*x509.Certificate, error)

VerifyCertificateTrust verifies that the certificate has a chain of trust to a root in rootCertPool, possibly using any intermediates in intermediateCertPool

func VerifyLayoutExpiration

func VerifyLayoutExpiration(layout Layout) error

VerifyLayoutExpiration verifies that the passed Layout has not expired. It returns an error if the (zulu) date in the Expires field is in the past.

func VerifyLayoutSignatures

func VerifyLayoutSignatures(layoutMb Metablock,
	layoutKeys map[string]Key) error

VerifyLayoutSignatures verifies for each key in the passed key map the corresponding signature of the Layout in the passed Metablock's Signed field. Signatures and keys are associated by key id. If the key map is empty, or the Metablock's Signature field does not have a signature for one or more of the passed keys, or a matching signature is invalid, an error is returned.

func VerifyLinkSignatureThesholds

func VerifyLinkSignatureThesholds(layout Layout,
	stepsMetadata map[string]map[string]Metablock, rootCertPool, intermediateCertPool *x509.CertPool) (
	map[string]map[string]Metablock, error)

VerifyLinkSignatureThesholds verifies that for each step of the passed layout, there are at least Threshold links, validly signed by different authorized functionaries. The returned map of link metadata per steps contains only links with valid signatures from distinct functionaries and has the format:

{
	<step name> : {
	<key id>: Metablock,
	<key id>: Metablock,
	...
	},
	<step name> : {
	<key id>: Metablock,
	<key id>: Metablock,
	...
	}
	...
}

If for any step of the layout there are not enough links available, the first return value is an empty map of Metablock maps and the second return value is the error.

func VerifySignature

func VerifySignature(key Key, sig Signature, unverified []byte) error

VerifySignature will verify unverified byte data via a passed key and signature. Supported key types are:

  • rsa
  • ed25519
  • ecdsa

When encountering an RSA key, VerifySignature will decode the PEM block in the key and will call rsa.VerifyPSS() for verifying the RSA signature. When encountering an ed25519 key, VerifySignature will decode the hex string encoded public key and will use ed25519.Verify() for verifying the ed25519 signature. When the given key is an ecdsa key, VerifySignature will unmarshall the ASN1 object and will use the retrieved ecdsa components 'r' and 's' for verifying the signature. On success it will return nil. In case of an unsupported key type or any other error it will return an error.

Note that in-toto-golang has different requirements to an ecdsa key. In in-toto-golang we use the string 'ecdsa' as string for the key type. In the key scheme we use: ecdsa-sha2-nistp256.

func VerifyStepCommandAlignment

func VerifyStepCommandAlignment(layout Layout,
	stepsMetadata map[string]map[string]Metablock)

VerifyStepCommandAlignment (soft) verifies that for each step of the passed layout the command executed, as per the passed link, matches the expected command, as per the layout. Soft verification means that, in case a command does not align, a warning is issued.

func VerifySublayouts

func VerifySublayouts(layout Layout,
	stepsMetadataVerified map[string]map[string]Metablock,
	superLayoutLinkPath string, intermediatePems [][]byte, lineNormalization bool) (map[string]map[string]Metablock, error)

VerifySublayouts checks if any step in the supply chain is a sublayout, and if so, recursively resolves it and replaces it with a summary link summarizing the steps carried out in the sublayout.

Types

type CertificateConstraint

type CertificateConstraint struct {
	CommonName    string   `json:"common_name"`
	DNSNames      []string `json:"dns_names"`
	Emails        []string `json:"emails"`
	Organizations []string `json:"organizations"`
	Roots         []string `json:"roots"`
	URIs          []string `json:"uris"`
}

CertificateConstraint defines the attributes a certificate must have to act as a functionary. A wildcard `*` allows any value in the specified attribute, where as an empty array or value asserts that the certificate must have nothing for that attribute. A certificate must have every value defined in a constraint to match.

func (CertificateConstraint) Check

func (cc CertificateConstraint) Check(cert *x509.Certificate, rootCAIDs []string, rootCertPool, intermediateCertPool *x509.CertPool) error

Check tests the provided certificate against the constraint. An error is returned if the certificate fails any of the constraints. nil is returned if the certificate passes all of the constraints.

type CycloneDXStatement

type CycloneDXStatement struct {
	StatementHeader
	Predicate interface{} `json:"predicate"`
}

CycloneDXStatement defines a cyclonedx sbom in the predicate. It is not currently serialized just as its SPDX counterpart. It is an empty interface, like the generic Statement.

type DSSESigner

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

DSSESigner provides signature generation and validation based on the SSL Signing Spec: https://github.com/secure-systems-lab/signing-spec as describe by: https://github.com/MarkLodato/ITE/tree/media-type/ITE/5 It wraps the generic SSL envelope signer and enforces the correct payload type both during signature generation and validation.

func NewDSSESigner

func NewDSSESigner(p ...dsse.SignVerifier) (*DSSESigner, error)

func (*DSSESigner) SignPayload

func (s *DSSESigner) SignPayload(ctx context.Context, body []byte) (*dsse.Envelope, error)

func (*DSSESigner) Verify

func (s *DSSESigner) Verify(ctx context.Context, e *dsse.Envelope) error

type Inspection

type Inspection struct {
	Type string   `json:"_type"`
	Run  []string `json:"run"`
	SupplyChainItem
}

Inspection represents an in-toto supply chain inspection, whose command in the Run field is executed during final product verification, generating unsigned link metadata. Materials and products used/produced by the inspection are constrained by the artifact rules in the inspection's ExpectedMaterials and ExpectedProducts fields.

type Key

type Key struct {
	KeyID               string   `json:"keyid"`
	KeyIDHashAlgorithms []string `json:"keyid_hash_algorithms"`
	KeyType             string   `json:"keytype"`
	KeyVal              KeyVal   `json:"keyval"`
	Scheme              string   `json:"scheme"`
}

Key represents a generic in-toto key that contains key metadata, such as an identifier, supported hash algorithms to create the identifier, the key type and the supported signature scheme, and the actual key value.

func (*Key) LoadKey

func (k *Key) LoadKey(path string, scheme string, KeyIDHashAlgorithms []string) error

LoadKey loads the key file at specified file path into the key object. It automatically derives the PEM type and the key type. Right now the following PEM types are supported:

  • PKCS1 for private keys
  • PKCS8 for private keys
  • PKIX for public keys

The following key types are supported and will be automatically assigned to the key type field:

  • ed25519
  • rsa
  • ecdsa

The following schemes are supported:

  • ed25519 -> ed25519
  • rsa -> rsassa-pss-sha256
  • ecdsa -> ecdsa-sha256-nistp256

Note that, this behavior is consistent with the securesystemslib, except for ecdsa. We do not use the scheme string as key type in in-toto-golang. Instead we are going with a ecdsa/ecdsa-sha2-nistp256 pair.

On success it will return nil. The following errors can happen:

  • path not found or not readable
  • no PEM block in the loaded file
  • no valid PKCS8/PKCS1 private key or PKIX public key
  • errors while marshalling
  • unsupported key types

func (*Key) LoadKeyDefaults

func (k *Key) LoadKeyDefaults(path string) error

func (*Key) LoadKeyReader

func (k *Key) LoadKeyReader(r io.Reader, scheme string, KeyIDHashAlgorithms []string) error

LoadKeyReader loads the key from a supplied reader. The logic matches LoadKey otherwise.

func (*Key) LoadKeyReaderDefaults

func (k *Key) LoadKeyReaderDefaults(r io.Reader) error

type KeyVal

type KeyVal struct {
	Private     string `json:"private"`
	Public      string `json:"public"`
	Certificate string `json:"certificate,omitempty"`
}

KeyVal contains the actual values of a key, as opposed to key metadata such as a key identifier or key type. For RSA keys, the key value is a pair of public and private keys in PEM format stored as strings. For public keys the Private field may be an empty string.

type Layout

type Layout struct {
	Type            string         `json:"_type"`
	Steps           []Step         `json:"steps"`
	Inspect         []Inspection   `json:"inspect"`
	Keys            map[string]Key `json:"keys"`
	RootCas         map[string]Key `json:"rootcas,omitempty"`
	IntermediateCas map[string]Key `json:"intermediatecas,omitempty"`
	Expires         string         `json:"expires"`
	Readme          string         `json:"readme"`
}

Layout represents the definition of a software supply chain. It lists the sequence of steps required in the software supply chain and the functionaries authorized to perform these steps. Functionaries are identified by their public keys. In addition, the layout may list a sequence of inspections that are executed during in-toto supply chain verification. A layout should be contained in a generic Metablock object, which provides functionality for signing and signature verification, and reading from and writing to disk.

func SubstituteParameters

func SubstituteParameters(layout Layout,
	parameterDictionary map[string]string) (Layout, error)

SubstituteParameters performs parameter substitution in steps and inspections in the following fields: - Expected Materials and Expected Products of both - Run of inspections - Expected Command of steps The substitution marker is '{}' and the keyword within the braces is replaced by a value found in the substitution map passed, parameterDictionary. The layout with parameters substituted is returned to the calling function.

func (*Layout) RootCAIDs

func (l *Layout) RootCAIDs() []string

RootCAIDs returns a slice of all of the Root CA IDs

type Link struct {
	Type        string                 `json:"_type"`
	Name        string                 `json:"name"`
	Materials   map[string]interface{} `json:"materials"`
	Products    map[string]interface{} `json:"products"`
	ByProducts  map[string]interface{} `json:"byproducts"`
	Command     []string               `json:"command"`
	Environment map[string]interface{} `json:"environment"`
}

Link represents the evidence of a supply chain step performed by a functionary. It should be contained in a generic Metablock object, which provides functionality for signing and signature verification, and reading from and writing to disk.

type LinkStatement

type LinkStatement struct {
	StatementHeader
	Predicate Link `json:"predicate"`
}

LinkStatement is the definition for an entire link statement.

type Metablock

type Metablock struct {
	// NOTE: Whenever we want to access an attribute of `Signed` we have to
	// perform type assertion, e.g. `metablock.Signed.(Layout).Keys`
	// Maybe there is a better way to store either Layouts or Links in `Signed`?
	// The notary folks seem to have separate container structs:
	// https://github.com/theupdateframework/notary/blob/master/tuf/data/root.go#L10-L14
	// https://github.com/theupdateframework/notary/blob/master/tuf/data/targets.go#L13-L17
	// I implemented it this way, because there will be several functions that
	// receive or return a Metablock, where the type of Signed has to be inferred
	// on runtime, e.g. when iterating over links for a layout, and a link can
	// turn out to be a layout (sublayout)
	Signed     interface{} `json:"signed"`
	Signatures []Signature `json:"signatures"`
}

Metablock is a generic container for signable in-toto objects such as Layout or Link. It has two fields, one that contains the signable object and one that contains corresponding signatures. Metablock also provides functionality for signing and signature verification, and reading from and writing to disk.

func GetSummaryLink(layout Layout, stepsMetadataReduced map[string]Metablock,
	stepName string) (Metablock, error)

GetSummaryLink merges the materials of the first step (as mentioned in the layout) and the products of the last step and returns a new link. This link reports the materials and products and summarizes the overall software supply chain. NOTE: The assumption is that the steps mentioned in the layout are to be performed sequentially. So, the first step mentioned in the layout denotes what comes into the supply chain and the last step denotes what goes out.

func InTotoRecordStart

func InTotoRecordStart(name string, materialPaths []string, key Key, hashAlgorithms, gitignorePatterns []string, lStripPaths []string, lineNormalization bool, followSymlinkDirs bool) (Metablock, error)

InTotoRecordStart begins the creation of a link metablock file in two steps, in order to provide evidence for supply chain steps that cannot be carries out by a single command. InTotoRecordStart collects the hashes of the materials before any commands are run, signs the unfinished link, and returns the link.

func InTotoRecordStop

func InTotoRecordStop(prelimLinkMb Metablock, productPaths []string, key Key, hashAlgorithms, gitignorePatterns []string, lStripPaths []string, lineNormalization bool, followSymlinkDirs bool) (Metablock, error)

InTotoRecordStop ends the creation of a metatadata link file created by InTotoRecordStart. InTotoRecordStop takes in a signed unfinished link metablock created by InTotoRecordStart and records the hashes of any products creted by commands run between InTotoRecordStart and InTotoRecordStop. The resultant finished link metablock is then signed by the provided key and returned.

func InTotoRun

func InTotoRun(name string, runDir string, materialPaths []string, productPaths []string,
	cmdArgs []string, key Key, hashAlgorithms []string, gitignorePatterns []string,
	lStripPaths []string, lineNormalization bool, followSymlinkDirs bool) (Metablock, error)

InTotoRun executes commands, e.g. for software supply chain steps or inspections of an in-toto layout, and creates and returns corresponding link metadata. Link metadata contains recorded products at the passed productPaths and materials at the passed materialPaths. The returned link is wrapped in a Metablock object. If command execution or artifact recording fails the first return value is an empty Metablock and the second return value is the error.

func InTotoVerify

func InTotoVerify(layoutMb Metablock, layoutKeys map[string]Key,
	linkDir string, stepName string, parameterDictionary map[string]string, intermediatePems [][]byte, lineNormalization bool) (
	Metablock, error)

InTotoVerify can be used to verify an entire software supply chain according to the in-toto specification. It requires the metadata of the root layout, a map that contains public keys to verify the root layout signatures, a path to a directory from where it can load link metadata files, which are treated as signed evidence for the steps defined in the layout, a step name, and a paramater dictionary used for parameter substitution. The step name only matters for sublayouts, where it's important to associate the summary of that step with a unique name. The verification routine is as follows:

1. Verify layout signature(s) using passed key(s) 2. Verify layout expiration date 3. Substitute parameters in layout 4. Load link metadata files for steps of layout 5. Verify signatures and signature thresholds for steps of layout 6. Verify sublayouts recursively 7. Verify command alignment for steps of layout (only warns) 8. Verify artifact rules for steps of layout 9. Execute inspection commands (generates link metadata for each inspection) 10. Verify artifact rules for inspections of layout

InTotoVerify returns a summary link wrapped in a Metablock object and an error value. If any of the verification routines fail, verification is aborted and error is returned. In such an instance, the first value remains an empty Metablock object.

NOTE: Artifact rules of type "create", "modify" and "delete" are currently not supported.

Example
package main

import (
	"fmt"
	"os"
)

/*
NOTE: The example code requires the following files to be in the current
working directory: `demo.layout` (root layout), `alice.pub` (layout
signature verification key), `write-code.776a00e2.link` and
`package.2f89b927.link` (link metadata files), and `foo.tar.gz` (target file of
final product). You can copy these files from
https://github.com/in-toto/in-toto-golang/tree/master/test/data.
*/

const LayoutPath = "demo.layout"
const LayoutKeyPath = "alice.pub"
const LinkDirectory = "."

func main() {
	// Load the layout verification key and create a map as is required by
	// InTotoVerify.  The layout represents the root of trust so it is a good
	// idea to sign it using multiple keys.
	var pubKey Key
	err := pubKey.LoadKey(LayoutKeyPath, "rsassa-pss-sha256", []string{"sha256", "sha512"})
	if err != nil {
		fmt.Printf("Unable to load public key: %s", err)
	}
	var layoutKeys = map[string]Key{
		pubKey.KeyID: pubKey,
	}

	// Perform in-toto software supply chain verification, using the provided
	// test data.
	var layoutMb Metablock
	if err := layoutMb.Load(LayoutPath); err != nil {
		fmt.Printf("Unable to load layout metadata: %s", err)
	}
	if err := validateLayout(layoutMb.Signed.(Layout)); err != nil {
		fmt.Printf("Invalid metadata found: %s", err)
	}
	if _, err := InTotoVerify(layoutMb, layoutKeys, LinkDirectory, "",
		make(map[string]string), [][]byte{}, testOSisWindows()); err != nil {
		fmt.Printf("In-toto verification failed: %s", err)
	} else {
		fmt.Println("In-toto verification succeeded!")
	}

	// During verification the inspection "untar" was executed, generating a
	// corresponding link metadata file "untar.link". You can safely remove it.
	err = os.Remove("untar.link")
	if err != nil {
		fmt.Printf("Unable to remove untar.link: %s", err)
	}
}
Output:

In-toto verification succeeded!

func InTotoVerifyWithDirectory

func InTotoVerifyWithDirectory(layoutMb Metablock, layoutKeys map[string]Key,
	linkDir string, runDir string, stepName string, parameterDictionary map[string]string, intermediatePems [][]byte, lineNormalization bool) (
	Metablock, error)

InTotoVerifyWithDirectory provides the same functionality as IntotoVerify, but adds the possibility to select a local directory from where the inspections are run.

func (*Metablock) Dump

func (mb *Metablock) Dump(path string) error

Dump JSON serializes and writes the Metablock on which it was called to the passed path. It returns an error if JSON serialization or writing fails.

func (*Metablock) GetSignableRepresentation

func (mb *Metablock) GetSignableRepresentation() ([]byte, error)

GetSignableRepresentation returns the canonical JSON representation of the Signed field of the Metablock on which it was called. If canonicalization fails the first return value is nil and the second return value is the error.

func (*Metablock) GetSignatureForKeyID

func (mb *Metablock) GetSignatureForKeyID(keyID string) (Signature, error)

GetSignatureForKeyID returns the signature that was created by the provided keyID, if it exists.

func (*Metablock) Load

func (mb *Metablock) Load(path string) error

Load parses JSON formatted metadata at the passed path into the Metablock object on which it was called. It returns an error if it cannot parse a valid JSON formatted Metablock that contains a Link or Layout.

func (*Metablock) Sign

func (mb *Metablock) Sign(key Key) error

Sign creates a signature over the signed portion of the metablock using the Key object provided. It then appends the resulting signature to the signatures field as provided. It returns an error if the Signed object cannot be canonicalized, or if the key is invalid or not supported.

func (*Metablock) VerifySignature

func (mb *Metablock) VerifySignature(key Key) error

VerifySignature verifies the first signature, corresponding to the passed Key, that it finds in the Signatures field of the Metablock on which it was called. It returns an error if Signatures does not contain a Signature corresponding to the passed Key, the object in Signed cannot be canonicalized, or the Signature is invalid.

type ProvenanceStatement

type ProvenanceStatement struct {
	StatementHeader
	Predicate slsa02.ProvenancePredicate `json:"predicate"`
}

ProvenanceStatement is the definition for an entire provenance statement with SLSA 0.2 predicate. Deprecated: Only version-specific provenance structs will be maintained (ProvenanceStatementSLSA01, ProvenanceStatementSLSA02).

type ProvenanceStatementSLSA01

type ProvenanceStatementSLSA01 struct {
	StatementHeader
	Predicate slsa01.ProvenancePredicate `json:"predicate"`
}

ProvenanceStatementSLSA01 is the definition for an entire provenance statement with SLSA 0.1 predicate.

type ProvenanceStatementSLSA02

type ProvenanceStatementSLSA02 struct {
	StatementHeader
	Predicate slsa02.ProvenancePredicate `json:"predicate"`
}

ProvenanceStatementSLSA02 is the definition for an entire provenance statement with SLSA 0.2 predicate.

type SPDXStatement

type SPDXStatement struct {
	StatementHeader
	Predicate interface{} `json:"predicate"`
}

SPDXStatement is the definition for an entire SPDX statement. This is currently not implemented. Some tooling exists here: https://github.com/spdx/tools-golang, but this software is still in early state. This struct is the same as the generic Statement struct but is added for completeness

type Set

type Set map[string]struct{}

Set represents a data structure for set operations. See `NewSet` for how to create a Set, and available Set receivers for useful set operations.

Under the hood Set aliases map[string]struct{}, where the map keys are the set elements and the map values are a memory-efficient way of storing the keys.

func NewSet

func NewSet(elems ...string) Set

NewSet creates a new Set, assigns it the optionally passed variadic string elements, and returns it.

func (Set) Add

func (s Set) Add(elem string)

Add adds the passed string to the set on which it was called, if the string is not a member of the set.

func (Set) Difference

func (s Set) Difference(s2 Set) Set

Difference creates and returns a new Set with the elements of the set on which it was called that are not in the passed set.

func (Set) Filter

func (s Set) Filter(pattern string) Set

Filter creates and returns a new Set with the elements of the set on which it was called that match the passed pattern. A matching error is treated like a non-match plus a warning is printed.

func (Set) Has

func (s Set) Has(elem string) bool

Has returns True if the passed string is member of the set on which it was called and False otherwise.

func (Set) Intersection

func (s Set) Intersection(s2 Set) Set

Intersection creates and returns a new Set with the elements of the set on which it was called that are also in the passed set.

func (Set) IsSubSet

func (s Set) IsSubSet(subset Set) bool

IsSubSet checks if the parameter subset is a subset of the superset s.

func (Set) Remove

func (s Set) Remove(elem string)

Remove removes the passed string from the set on which was is called, if the string is a member of the set.

func (Set) Slice

func (s Set) Slice() []string

Slice creates and returns an unordered string slice with the elements of the set on which it was called.

type Signature

type Signature struct {
	KeyID       string `json:"keyid"`
	Sig         string `json:"sig"`
	Certificate string `json:"cert,omitempty"`
}

Signature represents a generic in-toto signature that contains the identifier of the Key, which was used to create the signature and the signature data. The used signature scheme is found in the corresponding Key.

func GenerateSignature

func GenerateSignature(signable []byte, key Key) (Signature, error)

GenerateSignature will automatically detect the key type and sign the signable data with the provided key. If everything goes right GenerateSignature will return a for the key valid signature and err=nil. If something goes wrong it will return a not initialized signature and an error. Possible errors are:

  • ErrNoPEMBlock
  • ErrUnsupportedKeyType

Currently supported is only one scheme per key.

Note that in-toto-golang has different requirements to an ecdsa key. In in-toto-golang we use the string 'ecdsa' as string for the key type. In the key scheme we use: ecdsa-sha2-nistp256.

func (Signature) GetCertificate

func (sig Signature) GetCertificate() (Key, error)

GetCertificate returns the parsed x509 certificate attached to the signature, if it exists.

type Statement

type Statement struct {
	StatementHeader
	// Predicate contains type speficic metadata.
	Predicate interface{} `json:"predicate"`
}

Statement binds the attestation to a particular subject and identifies the of the predicate. This struct represents a generic statement.

type StatementHeader

type StatementHeader struct {
	Type          string    `json:"_type"`
	PredicateType string    `json:"predicateType"`
	Subject       []Subject `json:"subject"`
}

StatementHeader defines the common fields for all statements

type Step

type Step struct {
	Type                   string                  `json:"_type"`
	PubKeys                []string                `json:"pubkeys"`
	CertificateConstraints []CertificateConstraint `json:"cert_constraints,omitempty"`
	ExpectedCommand        []string                `json:"expected_command"`
	Threshold              int                     `json:"threshold"`
	SupplyChainItem
}

Step represents an in-toto step of the supply chain performed by a functionary. During final product verification in-toto looks for corresponding Link metadata, which is used as signed evidence that the step was performed according to the supply chain definition. Materials and products used/produced by the step are constrained by the artifact rules in the step's ExpectedMaterials and ExpectedProducts fields.

func (Step) CheckCertConstraints

func (s Step) CheckCertConstraints(key Key, rootCAIDs []string, rootCertPool, intermediateCertPool *x509.CertPool) error

CheckCertConstraints returns true if the provided certificate matches at least one of the constraints for this step.

type Subject

type Subject struct {
	Name   string           `json:"name"`
	Digest common.DigestSet `json:"digest"`
}

Subject describes the set of software artifacts the statement applies to.

type SupplyChainItem

type SupplyChainItem struct {
	Name              string     `json:"name"`
	ExpectedMaterials [][]string `json:"expected_materials"`
	ExpectedProducts  [][]string `json:"expected_products"`
}

SupplyChainItem summarizes common fields of the two available supply chain item types, Inspection and Step.

Directories

Path Synopsis
slsa_provenance

Jump to

Keyboard shortcuts

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