Ai
1 Star 0 Fork 1

mysnapcore/mysnapd

forked from tupelo-shen/mysnapd 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
asserts.go 41.03 KB
一键复制 编辑 原始数据 按行查看 历史
tupelo-shen 提交于 2022-11-07 17:55 +08:00 . fix: aspects & asserts commit
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
* Copyright (C) 2015-2022 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package asserts
import (
"bufio"
"bytes"
"crypto"
"fmt"
"io"
"sort"
"strconv"
"strings"
"unicode/utf8"
"gitee.com/mysnapcore/mysnapd/osutil"
"gitee.com/mysnapcore/mysnapd/snap/naming"
)
type typeFlags int
const (
noAuthority typeFlags = 1 << iota
sequenceForming
)
// MetaHeaders is a list of headers in assertions which are about the assertion
// itself.
var MetaHeaders = [...]string{
"type",
"format",
"authority-id",
"revision",
"body-length",
"sign-key-sha3-384",
}
// AssertionType describes a known assertion type with its name and metadata.
type AssertionType struct {
// Name of the type.
Name string
// PrimaryKey holds the names of the headers that constitute the
// unique primary key for this assertion type.
PrimaryKey []string
// OptionalPrimaryKeyDefaults holds the default values for
// optional primary key headers.
// Optional primary key headers can be added to types defined
// in previous versions of snapd, as long as they are added at
// the end of the old primary key together with a default value set in
// this map. So they must form a contiguous suffix of PrimaryKey with
// each member having a default value set in this map.
// Optional primary key headers are not supported for sequence
// forming types.
OptionalPrimaryKeyDefaults map[string]string
assembler func(assert assertionBase) (Assertion, error)
flags typeFlags
}
func (at *AssertionType) validate() {
if len(at.OptionalPrimaryKeyDefaults) != 0 && at.flags&sequenceForming != 0 {
panic(fmt.Sprintf("assertion type %q cannot be both sequence forming and have optional primary keys", at.Name))
}
noptional := 0
for _, k := range at.PrimaryKey {
defl := at.OptionalPrimaryKeyDefaults[k]
if noptional > 0 {
if defl == "" {
panic(fmt.Sprintf("assertion type %q primary key header %q has no default, optional primary keys must be a proper suffix of the primary key", at.Name, k))
}
}
if defl != "" {
noptional++
}
}
if len(at.OptionalPrimaryKeyDefaults) != noptional {
panic(fmt.Sprintf("assertion type %q has defaults values for unknown primary key headers", at.Name))
}
}
// MaxSupportedFormat returns the maximum supported format iteration for the type.
func (at *AssertionType) MaxSupportedFormat() int {
return maxSupportedFormat[at.Name]
}
// SequencingForming returns true if the assertion type has a positive
// integer >= 1 as the last component (preferably called "sequence")
// of its primary key over which the assertions of the type form
// sequences, usually without gaps, one sequence per sequence key (the
// primary key prefix omitting the sequence number).
// See SequenceMember.
func (at *AssertionType) SequenceForming() bool {
return at.flags&sequenceForming != 0
}
// AcceptablePrimaryKey returns whether the given key could be an acceptable primary key for this type, allowing for the omission of optional primary key headers.
func (at *AssertionType) AcceptablePrimaryKey(key []string) bool {
n := len(at.PrimaryKey)
nopt := len(at.OptionalPrimaryKeyDefaults)
ninp := len(key)
if ninp > n || ninp < (n-nopt) {
return false
}
return true
}
// Understood assertion types.
var (
AccountType = &AssertionType{"account", []string{"account-id"}, nil, assembleAccount, 0}
AccountKeyType = &AssertionType{"account-key", []string{"public-key-sha3-384"}, nil, assembleAccountKey, 0}
RepairType = &AssertionType{"repair", []string{"brand-id", "repair-id"}, nil, assembleRepair, sequenceForming}
ModelType = &AssertionType{"model", []string{"series", "brand-id", "model"}, nil, assembleModel, 0}
SerialType = &AssertionType{"serial", []string{"brand-id", "model", "serial"}, nil, assembleSerial, 0}
BaseDeclarationType = &AssertionType{"base-declaration", []string{"series"}, nil, assembleBaseDeclaration, 0}
SnapDeclarationType = &AssertionType{"snap-declaration", []string{"series", "snap-id"}, nil, assembleSnapDeclaration, 0}
SnapBuildType = &AssertionType{"snap-build", []string{"snap-sha3-384"}, nil, assembleSnapBuild, 0}
SnapRevisionType = &AssertionType{"snap-revision", []string{"snap-sha3-384", "provenance"}, map[string]string{"provenance": naming.DefaultProvenance}, assembleSnapRevision, 0}
SnapDeveloperType = &AssertionType{"snap-developer", []string{"snap-id", "publisher-id"}, nil, assembleSnapDeveloper, 0}
SystemUserType = &AssertionType{"system-user", []string{"brand-id", "email"}, nil, assembleSystemUser, 0}
ValidationType = &AssertionType{"validation", []string{"series", "snap-id", "approved-snap-id", "approved-snap-revision"}, nil, assembleValidation, 0}
ValidationSetType = &AssertionType{"validation-set", []string{"series", "account-id", "name", "sequence"}, nil, assembleValidationSet, sequenceForming}
StoreType = &AssertionType{"store", []string{"store"}, nil, assembleStore, 0}
PreseedType = &AssertionType{"preseed", []string{"series", "brand-id", "model", "system-label"}, nil, assemblePreseed, 0}
// ...
)
// Assertion types without a definite authority set (on the wire and/or self-signed).
var (
DeviceSessionRequestType = &AssertionType{"device-session-request", []string{"brand-id", "model", "serial"}, nil, assembleDeviceSessionRequest, noAuthority}
SerialRequestType = &AssertionType{"serial-request", nil, nil, assembleSerialRequest, noAuthority}
AccountKeyRequestType = &AssertionType{"account-key-request", []string{"public-key-sha3-384"}, nil, assembleAccountKeyRequest, noAuthority}
)
var typeRegistry = map[string]*AssertionType{
AccountType.Name: AccountType,
AccountKeyType.Name: AccountKeyType,
ModelType.Name: ModelType,
SerialType.Name: SerialType,
BaseDeclarationType.Name: BaseDeclarationType,
SnapDeclarationType.Name: SnapDeclarationType,
SnapBuildType.Name: SnapBuildType,
SnapRevisionType.Name: SnapRevisionType,
SnapDeveloperType.Name: SnapDeveloperType,
SystemUserType.Name: SystemUserType,
ValidationType.Name: ValidationType,
ValidationSetType.Name: ValidationSetType,
RepairType.Name: RepairType,
StoreType.Name: StoreType,
// no authority
DeviceSessionRequestType.Name: DeviceSessionRequestType,
SerialRequestType.Name: SerialRequestType,
AccountKeyRequestType.Name: AccountKeyRequestType,
PreseedType.Name: PreseedType,
}
// Type returns the AssertionType with name or nil
func Type(name string) *AssertionType {
return typeRegistry[name]
}
// TypeNames returns a sorted list of known assertion type names.
func TypeNames() []string {
names := make([]string, 0, len(typeRegistry))
for k := range typeRegistry {
names = append(names, k)
}
sort.Strings(names)
return names
}
var maxSupportedFormat = map[string]int{}
func init() {
// register maxSupportedFormats while breaking initialisation loop
// 1: plugs and slots
// 2: support for $SLOT()/$PLUG()/$MISSING
// 3: support for on-store/on-brand/on-model device scope constraints
// 4: support for plug-names/slot-names constraints
// 5: alt attr matcher usage (was unused before, has new behavior now)
maxSupportedFormat[SnapDeclarationType.Name] = 5
// 1: support to limit to device serials
// 2: support for user-presence constraint
maxSupportedFormat[SystemUserType.Name] = 2
for _, at := range typeRegistry {
at.validate()
}
}
func MockMaxSupportedFormat(assertType *AssertionType, maxFormat int) (restore func()) {
prev := maxSupportedFormat[assertType.Name]
maxSupportedFormat[assertType.Name] = maxFormat
return func() {
maxSupportedFormat[assertType.Name] = prev
}
}
func MockOptionalPrimaryKey(assertType *AssertionType, key, defaultValue string) (restore func()) {
osutil.MustBeTestBinary("mocking new assertion optional primary keys can be done only from tests")
oldPrimaryKey := assertType.PrimaryKey
oldOptionalPrimaryKeyDefaults := assertType.OptionalPrimaryKeyDefaults
newOptionalPrimaryKeyDefaults := make(map[string]string, len(oldOptionalPrimaryKeyDefaults)+1)
for k, defl := range oldOptionalPrimaryKeyDefaults {
newOptionalPrimaryKeyDefaults[k] = defl
}
assertType.PrimaryKey = append(assertType.PrimaryKey, key)
assertType.OptionalPrimaryKeyDefaults = newOptionalPrimaryKeyDefaults
newOptionalPrimaryKeyDefaults[key] = defaultValue
return func() {
assertType.PrimaryKey = oldPrimaryKey
assertType.OptionalPrimaryKeyDefaults = oldOptionalPrimaryKeyDefaults
}
}
var formatAnalyzer = map[*AssertionType]func(headers map[string]interface{}, body []byte) (formatnum int, err error){
SnapDeclarationType: snapDeclarationFormatAnalyze,
SystemUserType: systemUserFormatAnalyze,
}
// MaxSupportedFormats returns a mapping between assertion type names
// and corresponding max supported format if it is >= min. Typical
// usage passes 1 or 0 for min.
func MaxSupportedFormats(min int) (maxFormats map[string]int) {
if min == 0 {
maxFormats = make(map[string]int, len(typeRegistry))
} else {
maxFormats = make(map[string]int)
}
for name := range typeRegistry {
m := maxSupportedFormat[name]
if m >= min {
maxFormats[name] = m
}
}
return maxFormats
}
// SuggestFormat returns a minimum format that supports the features that would be used by an assertion with the given components.
func SuggestFormat(assertType *AssertionType, headers map[string]interface{}, body []byte) (formatnum int, err error) {
analyzer := formatAnalyzer[assertType]
if analyzer == nil {
// no analyzer, format 0 is all there is
return 0, nil
}
formatnum, err = analyzer(headers, body)
if err != nil {
return 0, fmt.Errorf("assertion %s: %v", assertType.Name, err)
}
return formatnum, nil
}
// HeadersFromPrimaryKey constructs a headers mapping from the
// primaryKey values and the assertion type, it errors if primaryKey
// does not cover all the non-optional primary key headers or provides
// too many values.
func HeadersFromPrimaryKey(assertType *AssertionType, primaryKey []string) (headers map[string]string, err error) {
if !assertType.AcceptablePrimaryKey(primaryKey) {
return nil, fmt.Errorf("primary key has wrong length for %q assertion", assertType.Name)
}
ninp := len(primaryKey)
headers = make(map[string]string, len(assertType.PrimaryKey))
for i, name := range assertType.PrimaryKey {
var keyVal string
if i < ninp {
keyVal = primaryKey[i]
if keyVal == "" {
return nil, fmt.Errorf("primary key %q header cannot be empty", name)
}
} else {
keyVal = assertType.OptionalPrimaryKeyDefaults[name]
}
headers[name] = keyVal
}
return headers, nil
}
// HeadersFromSequenceKey constructs a headers mapping from the
// sequenceKey values and the sequence forming assertion type,
// it errors if sequenceKey has the wrong length; the length must be
// one less than the primary key of the given assertion type.
func HeadersFromSequenceKey(assertType *AssertionType, sequenceKey []string) (headers map[string]string, err error) {
if !assertType.SequenceForming() {
return nil, fmt.Errorf("internal error: HeadersFromSequenceKey should only be used for sequence forming assertion types, got: %s", assertType.Name)
}
if len(sequenceKey) != len(assertType.PrimaryKey)-1 {
return nil, fmt.Errorf("sequence key has wrong length for %q assertion", assertType.Name)
}
headers = make(map[string]string, len(sequenceKey))
for i, val := range sequenceKey {
key := assertType.PrimaryKey[i]
if val == "" {
return nil, fmt.Errorf("sequence key %q header cannot be empty", key)
}
headers[key] = val
}
return headers, nil
}
// PrimaryKeyFromHeaders extracts the tuple of values from headers
// corresponding to a primary key under the assertion type, it errors
// if there are missing primary key headers unless they are optional
// in which case it fills in their default values.
func PrimaryKeyFromHeaders(assertType *AssertionType, headers map[string]string) (primaryKey []string, err error) {
return keysFromHeaders(assertType.PrimaryKey, headers, assertType.OptionalPrimaryKeyDefaults)
}
func keysFromHeaders(keys []string, headers map[string]string, defaults map[string]string) (keyValues []string, err error) {
keyValues = make([]string, len(keys))
for i, k := range keys {
keyVal := headers[k]
if keyVal == "" {
keyVal = defaults[k]
if keyVal == "" {
return nil, fmt.Errorf("must provide primary key: %v", k)
}
}
keyValues[i] = keyVal
}
return keyValues, nil
}
// ReducePrimaryKey produces a primary key prefix by omitting any
// suffix of optional primary key headers default values.
// Too short or long primary keys are returned as is.
func ReducePrimaryKey(assertType *AssertionType, primaryKey []string) []string {
n := len(assertType.PrimaryKey)
nopt := len(assertType.OptionalPrimaryKeyDefaults)
ninp := len(primaryKey)
if ninp > n || ninp < (n-nopt) {
return primaryKey
}
reduced := make([]string, n-nopt, n)
copy(reduced, primaryKey[:n-nopt])
rest := ninp - (n - nopt)
for i := ninp - 1; i >= n-nopt; i-- {
defl := assertType.OptionalPrimaryKeyDefaults[assertType.PrimaryKey[i]]
if primaryKey[i] != defl {
break
}
// it matches the default value, leave it out
rest--
}
reduced = append(reduced, primaryKey[n-nopt:n-nopt+rest]...)
return reduced
}
// Ref expresses a reference to an assertion.
type Ref struct {
Type *AssertionType
PrimaryKey []string
}
func (ref *Ref) String() string {
pkStr := "-"
n := len(ref.Type.PrimaryKey)
nopt := len(ref.Type.OptionalPrimaryKeyDefaults)
ninp := len(ref.PrimaryKey)
if ninp > n || ninp < (n-nopt) {
pkStr = "???"
} else if n > 0 {
pkStr = ref.PrimaryKey[n-nopt-1]
if n > 1 {
sfx := []string{pkStr + ";"}
for i, k := range ref.Type.PrimaryKey[:n-nopt-1] {
sfx = append(sfx, fmt.Sprintf("%s:%s", k, ref.PrimaryKey[i]))
}
// optional primary keys
for i := n - nopt; i < ninp; i++ {
v := ref.PrimaryKey[i]
k := ref.Type.PrimaryKey[i]
defl := ref.Type.OptionalPrimaryKeyDefaults[k]
if v != defl {
sfx = append(sfx, fmt.Sprintf("%s:%s", k, v))
}
}
pkStr = strings.Join(sfx, " ")
}
}
return fmt.Sprintf("%s (%s)", ref.Type.Name, pkStr)
}
// Unique returns a unique string representing the reference that can be used as a key in maps.
func (ref *Ref) Unique() string {
return fmt.Sprintf("%s/%s", ref.Type.Name, strings.Join(ReducePrimaryKey(ref.Type, ref.PrimaryKey), "/"))
}
// Resolve resolves the reference using the given find function.
func (ref *Ref) Resolve(find func(assertType *AssertionType, headers map[string]string) (Assertion, error)) (Assertion, error) {
headers, err := HeadersFromPrimaryKey(ref.Type, ref.PrimaryKey)
if err != nil {
return nil, fmt.Errorf("%q assertion reference primary key has the wrong length (expected %v): %v", ref.Type.Name, ref.Type.PrimaryKey, ref.PrimaryKey)
}
return find(ref.Type, headers)
}
const RevisionNotKnown = -1
// AtRevision represents an assertion at a given revision, possibly
// not known (RevisionNotKnown).
type AtRevision struct {
Ref
Revision int
}
func (at *AtRevision) String() string {
s := at.Ref.String()
if at.Revision == RevisionNotKnown {
return s
}
return fmt.Sprintf("%s at revision %d", s, at.Revision)
}
// AtSequence references a sequence forming assertion at a given sequence point,
// possibly <=0 (meaning not specified) and revision, possibly not known
// (RevisionNotKnown).
// Setting Pinned = true means pinning at the given sequence point (which must be
// set, i.e. > 0). Pinned sequence forming assertion will be updated to the
// latest revision at the specified sequence point.
type AtSequence struct {
Type *AssertionType
SequenceKey []string
Sequence int
Pinned bool
Revision int
}
// Unique returns a unique string representing the sequence by its sequence key
// that can be used as a key in maps.
func (at *AtSequence) Unique() string {
return fmt.Sprintf("%s/%s", at.Type.Name, strings.Join(at.SequenceKey, "/"))
}
func (at *AtSequence) String() string {
var pkStr string
if len(at.SequenceKey) != len(at.Type.PrimaryKey)-1 {
pkStr = "???"
} else {
n := 0
// omit series if present in the primary key
if at.Type.PrimaryKey[0] == "series" {
n++
}
pkStr = strings.Join(at.SequenceKey[n:], "/")
if at.Sequence > 0 {
sep := "/"
if at.Pinned {
sep = "="
}
pkStr = fmt.Sprintf("%s%s%d", pkStr, sep, at.Sequence)
}
}
sk := fmt.Sprintf("%s %s", at.Type.Name, pkStr)
if at.Revision == RevisionNotKnown {
return sk
}
return fmt.Sprintf("%s at revision %d", sk, at.Revision)
}
// Resolve resolves the sequence with known sequence number using the given find function.
func (at *AtSequence) Resolve(find func(assertType *AssertionType, headers map[string]string) (Assertion, error)) (Assertion, error) {
if at.Sequence <= 0 {
hdrs, err := HeadersFromSequenceKey(at.Type, at.SequenceKey)
if err != nil {
return nil, fmt.Errorf("%q assertion reference sequence key %v is invalid: %v", at.Type.Name, at.SequenceKey, err)
}
return nil, &NotFoundError{
Type: at.Type,
Headers: hdrs,
}
}
pkey := append(at.SequenceKey, fmt.Sprintf("%d", at.Sequence))
headers, err := HeadersFromPrimaryKey(at.Type, pkey)
if err != nil {
return nil, fmt.Errorf("%q assertion reference primary key has the wrong length (expected %v): %v", at.Type.Name, at.Type.PrimaryKey, pkey)
}
return find(at.Type, headers)
}
// Assertion represents an assertion through its general elements.
type Assertion interface {
// Type returns the type of this assertion
Type() *AssertionType
// Format returns the format iteration of this assertion
Format() int
// SupportedFormat returns whether the assertion uses a supported
// format iteration. If false the assertion might have been only
// partially parsed.
SupportedFormat() bool
// Revision returns the revision of this assertion
Revision() int
// AuthorityID returns the authority responsible for this
// assertion
AuthorityID() string
// Header retrieves the header with name
Header(name string) interface{}
// Headers returns the complete headers
Headers() map[string]interface{}
// HeaderString retrieves the string value of header with name or ""
HeaderString(name string) string
// Body returns the body of this assertion
Body() []byte
// Signature returns the signed content and its unprocessed signature
Signature() (content, signature []byte)
// SignKeyID returns the key id for the key that signed this assertion.
SignKeyID() string
// Prerequisites returns references to the prerequisite assertions for the validity of this one.
Prerequisites() []*Ref
// Ref returns a reference representing this assertion.
Ref() *Ref
// At returns an AtRevision referencing this assertion at its revision.
At() *AtRevision
}
// SequenceMember is implemented by assertions of sequence forming types.
type SequenceMember interface {
Assertion
// Sequence returns the sequence number of this assertion.
Sequence() int
}
// customSigner represents an assertion with special arrangements for its signing key (e.g. self-signed), rather than the usual case where an assertion is signed by its authority.
type customSigner interface {
// signKey returns the public key material for the key that signed this assertion. See also SignKeyID.
signKey() PublicKey
}
// MediaType is the media type for encoded assertions on the wire.
const MediaType = "application/x.ubuntu.assertion"
// assertionBase is the concrete base to hold representation data for actual assertions.
type assertionBase struct {
headers map[string]interface{}
body []byte
// parsed format iteration
format int
// parsed revision
revision int
// preserved content
content []byte
// unprocessed signature
signature []byte
}
// HeaderString retrieves the string value of header with name or ""
func (ab *assertionBase) HeaderString(name string) string {
s, _ := ab.headers[name].(string)
return s
}
// Type returns the assertion type.
func (ab *assertionBase) Type() *AssertionType {
return Type(ab.HeaderString("type"))
}
// Format returns the assertion format iteration.
func (ab *assertionBase) Format() int {
return ab.format
}
// SupportedFormat returns whether the assertion uses a supported
// format iteration. If false the assertion might have been only
// partially parsed.
func (ab *assertionBase) SupportedFormat() bool {
return ab.format <= maxSupportedFormat[ab.HeaderString("type")]
}
// Revision returns the assertion revision.
func (ab *assertionBase) Revision() int {
return ab.revision
}
// AuthorityID returns the authority-id a.k.a the authority responsible for the assertion.
func (ab *assertionBase) AuthorityID() string {
return ab.HeaderString("authority-id")
}
// Header returns the value of an header by name.
func (ab *assertionBase) Header(name string) interface{} {
v := ab.headers[name]
if v == nil {
return nil
}
return copyHeader(v)
}
// Headers returns the complete headers.
func (ab *assertionBase) Headers() map[string]interface{} {
return copyHeaders(ab.headers)
}
// Body returns the body of the assertion.
func (ab *assertionBase) Body() []byte {
return ab.body
}
// Signature returns the signed content and its unprocessed signature.
func (ab *assertionBase) Signature() (content, signature []byte) {
return ab.content, ab.signature
}
// SignKeyID returns the key id for the key that signed this assertion.
func (ab *assertionBase) SignKeyID() string {
return ab.HeaderString("sign-key-sha3-384")
}
// Prerequisites returns references to the prerequisite assertions for the validity of this one.
func (ab *assertionBase) Prerequisites() []*Ref {
return nil
}
// Ref returns a reference representing this assertion.
func (ab *assertionBase) Ref() *Ref {
assertType := ab.Type()
primKey := make([]string, len(assertType.PrimaryKey))
for i, name := range assertType.PrimaryKey {
primKey[i] = ab.HeaderString(name)
}
return &Ref{
Type: assertType,
PrimaryKey: primKey,
}
}
// At returns an AtRevision referencing this assertion at its revision.
func (ab *assertionBase) At() *AtRevision {
return &AtRevision{Ref: *ab.Ref(), Revision: ab.Revision()}
}
// expected interface is implemented
var _ Assertion = (*assertionBase)(nil)
// Decode parses a serialized assertion.
//
// The expected serialisation format looks like:
//
// HEADER ("\n\n" BODY?)? "\n\n" SIGNATURE
//
// where:
//
// HEADER is a set of header entries separated by "\n"
// BODY can be arbitrary text,
// SIGNATURE is the signature
//
// Both BODY and HEADER must be UTF8.
//
// A header entry for a single line value (no '\n' in it) looks like:
//
// NAME ": " SIMPLEVALUE
//
// The format supports multiline text values (with '\n's in them) and
// lists or maps, possibly nested, with string scalars in them.
//
// For those a header entry looks like:
//
// NAME ":\n" MULTI(baseindent)
//
// where MULTI can be
//
// * (baseindent + 4)-space indented value (multiline text)
//
// * entries of a list each of the form:
//
// " "*baseindent " -" ( " " SIMPLEVALUE | "\n" MULTI )
//
// * entries of map each of the form:
//
// " "*baseindent " " NAME ":" ( " " SIMPLEVALUE | "\n" MULTI )
//
// baseindent starts at 0 and then grows with nesting matching the
// previous level introduction (e.g. the " "*baseindent " -" bit)
// length minus 1.
//
// In general the following headers are mandatory:
//
// type
// authority-id (except for on the wire/self-signed assertions like serial-request)
//
// Further for a given assertion type all the primary key headers
// must be non empty and must not contain '/'.
//
// The following headers expect string representing integer values and
// if omitted otherwise are assumed to be 0:
//
// revision (a positive int)
// body-length (expected to be equal to the length of BODY)
// format (a positive int for the format iteration of the type used)
//
// Times are expected to be in the RFC3339 format: "2006-01-02T15:04:05Z07:00".
//
func Decode(serializedAssertion []byte) (Assertion, error) {
// copy to get an independent backstorage that can't be mutated later
assertionSnapshot := make([]byte, len(serializedAssertion))
copy(assertionSnapshot, serializedAssertion)
contentSignatureSplit := bytes.LastIndex(assertionSnapshot, nlnl)
if contentSignatureSplit == -1 {
return nil, fmt.Errorf("assertion content/signature separator not found")
}
content := assertionSnapshot[:contentSignatureSplit]
signature := assertionSnapshot[contentSignatureSplit+2:]
headersBodySplit := bytes.Index(content, nlnl)
var body, head []byte
if headersBodySplit == -1 {
head = content
} else {
body = content[headersBodySplit+2:]
if len(body) == 0 {
body = nil
}
head = content[:headersBodySplit]
}
headers, err := parseHeaders(head)
if err != nil {
return nil, fmt.Errorf("parsing assertion headers: %v", err)
}
return assemble(headers, body, content, signature)
}
// Maximum assertion component sizes.
const (
MaxBodySize = 2 * 1024 * 1024
MaxHeadersSize = 128 * 1024
MaxSignatureSize = 128 * 1024
)
// Decoder parses a stream of assertions bundled by separating them with double newlines.
type Decoder struct {
rd io.Reader
initialBufSize int
b *bufio.Reader
err error
maxHeadersSize int
maxSigSize int
defaultMaxBodySize int
typeMaxBodySize map[*AssertionType]int
}
// initBuffer finishes a Decoder initialization by setting up the bufio.Reader,
// it returns the *Decoder for convenience of notation.
func (d *Decoder) initBuffer() *Decoder {
d.b = bufio.NewReaderSize(d.rd, d.initialBufSize)
return d
}
const defaultDecoderBufSize = 4096
// NewDecoder returns a Decoder to parse the stream of assertions from the reader.
func NewDecoder(r io.Reader) *Decoder {
return (&Decoder{
rd: r,
initialBufSize: defaultDecoderBufSize,
maxHeadersSize: MaxHeadersSize,
maxSigSize: MaxSignatureSize,
defaultMaxBodySize: MaxBodySize,
}).initBuffer()
}
// NewDecoderWithTypeMaxBodySize returns a Decoder to parse the stream of assertions from the reader enforcing optional per type max body sizes or the default one as fallback.
func NewDecoderWithTypeMaxBodySize(r io.Reader, typeMaxBodySize map[*AssertionType]int) *Decoder {
return (&Decoder{
rd: r,
initialBufSize: defaultDecoderBufSize,
maxHeadersSize: MaxHeadersSize,
maxSigSize: MaxSignatureSize,
defaultMaxBodySize: MaxBodySize,
typeMaxBodySize: typeMaxBodySize,
}).initBuffer()
}
func (d *Decoder) peek(size int) ([]byte, error) {
buf, err := d.b.Peek(size)
if err == bufio.ErrBufferFull {
rebuf, reerr := d.b.Peek(d.b.Buffered())
if reerr != nil {
panic(reerr)
}
mr := io.MultiReader(bytes.NewBuffer(rebuf), d.rd)
d.b = bufio.NewReaderSize(mr, (size/d.initialBufSize+1)*d.initialBufSize)
buf, err = d.b.Peek(size)
}
if err != nil && d.err == nil {
d.err = err
}
return buf, d.err
}
// NB: readExact and readUntil use peek underneath and their returned
// buffers are valid only until the next reading call
func (d *Decoder) readExact(size int) ([]byte, error) {
buf, err := d.peek(size)
d.b.Discard(len(buf))
if len(buf) == size {
return buf, nil
}
if err == io.EOF {
return buf, io.ErrUnexpectedEOF
}
return buf, err
}
func (d *Decoder) readUntil(delim []byte, maxSize int) ([]byte, error) {
last := 0
size := d.initialBufSize
for {
buf, err := d.peek(size)
if i := bytes.Index(buf[last:], delim); i >= 0 {
d.b.Discard(last + i + len(delim))
return buf[:last+i+len(delim)], nil
}
// report errors only once we have consumed what is buffered
if err != nil && len(buf) == d.b.Buffered() {
d.b.Discard(len(buf))
return buf, err
}
last = size - len(delim) + 1
size *= 2
if size > maxSize {
return nil, fmt.Errorf("maximum size exceeded while looking for delimiter %q", delim)
}
}
}
// Decode parses the next assertion from the stream.
// It returns the error io.EOF at the end of a well-formed stream.
func (d *Decoder) Decode() (Assertion, error) {
// read the headers and the nlnl separator after them
headAndSep, err := d.readUntil(nlnl, d.maxHeadersSize)
if err != nil {
if err == io.EOF {
if len(headAndSep) != 0 {
return nil, io.ErrUnexpectedEOF
}
return nil, io.EOF
}
return nil, fmt.Errorf("error reading assertion headers: %v", err)
}
headLen := len(headAndSep) - len(nlnl)
headers, err := parseHeaders(headAndSep[:headLen])
if err != nil {
return nil, fmt.Errorf("parsing assertion headers: %v", err)
}
typeStr, _ := headers["type"].(string)
typ := Type(typeStr)
length, err := checkIntWithDefault(headers, "body-length", 0)
if err != nil {
return nil, fmt.Errorf("assertion: %v", err)
}
if typMaxBodySize := d.typeMaxBodySize[typ]; typMaxBodySize != 0 && length > typMaxBodySize {
return nil, fmt.Errorf("assertion body length %d exceeds maximum body size %d for %q assertions", length, typMaxBodySize, typ.Name)
} else if length > d.defaultMaxBodySize {
return nil, fmt.Errorf("assertion body length %d exceeds maximum body size", length)
}
// save the headers before we try to read more, and setup to capture
// the whole content in a buffer
contentBuf := bytes.NewBuffer(make([]byte, 0, len(headAndSep)+length))
contentBuf.Write(headAndSep)
if length > 0 {
// read the body if length != 0
body, err := d.readExact(length)
if err != nil {
return nil, err
}
contentBuf.Write(body)
}
// try to read the end of body a.k.a content/signature separator
endOfBody, err := d.readUntil(nlnl, d.maxSigSize)
if err != nil && err != io.EOF {
return nil, fmt.Errorf("error reading assertion trailer: %v", err)
}
var sig []byte
if bytes.Equal(endOfBody, nlnl) {
// we got the nlnl content/signature separator, read the signature now and the assertion/assertion nlnl separation
sig, err = d.readUntil(nlnl, d.maxSigSize)
if err != nil && err != io.EOF {
return nil, fmt.Errorf("error reading assertion signature: %v", err)
}
} else {
// we got the signature directly which is a ok format only if body length == 0
if length > 0 {
return nil, fmt.Errorf("missing content/signature separator")
}
sig = endOfBody
contentBuf.Truncate(headLen)
}
// normalize sig ending newlines
if bytes.HasSuffix(sig, nlnl) {
sig = sig[:len(sig)-1]
}
finalContent := contentBuf.Bytes()
var finalBody []byte
if length > 0 {
finalBody = finalContent[headLen+len(nlnl):]
}
finalSig := make([]byte, len(sig))
copy(finalSig, sig)
return assemble(headers, finalBody, finalContent, finalSig)
}
func checkIteration(headers map[string]interface{}, name string) (int, error) {
iternum, err := checkIntWithDefault(headers, name, 0)
if err != nil {
return -1, err
}
if iternum < 0 {
return -1, fmt.Errorf("%s should be positive: %v", name, iternum)
}
return iternum, nil
}
func checkFormat(headers map[string]interface{}) (int, error) {
return checkIteration(headers, "format")
}
func checkRevision(headers map[string]interface{}) (int, error) {
return checkIteration(headers, "revision")
}
// Assemble assembles an assertion from its components.
func Assemble(headers map[string]interface{}, body, content, signature []byte) (Assertion, error) {
err := checkHeaders(headers)
if err != nil {
return nil, err
}
return assemble(headers, body, content, signature)
}
func checkAuthority(_ *AssertionType, headers map[string]interface{}) error {
if _, err := checkNotEmptyString(headers, "authority-id"); err != nil {
return err
}
return nil
}
func checkNoAuthority(assertType *AssertionType, headers map[string]interface{}) error {
if _, ok := headers["authority-id"]; ok {
return fmt.Errorf("%q assertion cannot have authority-id set", assertType.Name)
}
return nil
}
// assemble is the internal variant of Assemble, assumes headers are already checked for supported types
func assemble(headers map[string]interface{}, body, content, signature []byte) (Assertion, error) {
length, err := checkIntWithDefault(headers, "body-length", 0)
if err != nil {
return nil, fmt.Errorf("assertion: %v", err)
}
if length != len(body) {
return nil, fmt.Errorf("assertion body length and declared body-length don't match: %v != %v", len(body), length)
}
if !utf8.Valid(body) {
return nil, fmt.Errorf("assertion body is not utf8")
}
if _, err := checkDigest(headers, "sign-key-sha3-384", crypto.SHA3_384); err != nil {
return nil, fmt.Errorf("assertion: %v", err)
}
typ, err := checkNotEmptyString(headers, "type")
if err != nil {
return nil, fmt.Errorf("assertion: %v", err)
}
assertType := Type(typ)
if assertType == nil {
return nil, fmt.Errorf("unknown assertion type: %q", typ)
}
if assertType.flags&noAuthority == 0 {
if err := checkAuthority(assertType, headers); err != nil {
return nil, fmt.Errorf("assertion: %v", err)
}
} else {
if err := checkNoAuthority(assertType, headers); err != nil {
return nil, err
}
}
formatnum, err := checkFormat(headers)
if err != nil {
return nil, fmt.Errorf("assertion: %v", err)
}
for _, primKey := range assertType.PrimaryKey {
if _, ok := headers[primKey]; !ok {
if defl := assertType.OptionalPrimaryKeyDefaults[primKey]; defl != "" {
headers[primKey] = defl
}
}
if _, err := checkPrimaryKey(headers, primKey); err != nil {
return nil, fmt.Errorf("assertion %s: %v", assertType.Name, err)
}
}
revision, err := checkRevision(headers)
if err != nil {
return nil, fmt.Errorf("assertion: %v", err)
}
if len(signature) == 0 {
return nil, fmt.Errorf("empty assertion signature")
}
assert, err := assertType.assembler(assertionBase{
headers: headers,
body: body,
format: formatnum,
revision: revision,
content: content,
signature: signature,
})
if err != nil {
return nil, fmt.Errorf("assertion %s: %v", assertType.Name, err)
}
return assert, nil
}
func writeHeader(buf *bytes.Buffer, headers map[string]interface{}, name string) {
appendEntry(buf, fmt.Sprintf("%s:", name), headers[name], 0)
}
func assembleAndSign(assertType *AssertionType, headers map[string]interface{}, body []byte, privKey PrivateKey) (Assertion, error) {
err := checkAssertType(assertType)
if err != nil {
return nil, err
}
withAuthority := assertType.flags&noAuthority == 0
err = checkHeaders(headers)
if err != nil {
return nil, err
}
// there's no hint at all that we will need non-textual bodies,
// make sure we actually enforce that
if !utf8.Valid(body) {
return nil, fmt.Errorf("assertion body is not utf8")
}
finalHeaders := copyHeaders(headers)
bodyLength := len(body)
finalBody := make([]byte, bodyLength)
copy(finalBody, body)
finalHeaders["type"] = assertType.Name
finalHeaders["body-length"] = strconv.Itoa(bodyLength)
finalHeaders["sign-key-sha3-384"] = privKey.PublicKey().ID()
if withAuthority {
if err = checkAuthority(assertType, finalHeaders); err != nil {
return nil, err
}
} else {
if err := checkNoAuthority(assertType, finalHeaders); err != nil {
return nil, err
}
}
formatnum, err := checkFormat(finalHeaders)
if err != nil {
return nil, err
}
if formatnum > assertType.MaxSupportedFormat() {
return nil, fmt.Errorf("cannot sign %q assertion with format %d higher than max supported format %d", assertType.Name, formatnum, assertType.MaxSupportedFormat())
}
suggestedFormat, err := SuggestFormat(assertType, finalHeaders, finalBody)
if err != nil {
return nil, err
}
if suggestedFormat > formatnum {
return nil, fmt.Errorf("cannot sign %q assertion with format set to %d lower than min format %d covering included features", assertType.Name, formatnum, suggestedFormat)
}
revision, err := checkRevision(finalHeaders)
if err != nil {
return nil, err
}
buf := bytes.NewBufferString("type: ")
buf.WriteString(assertType.Name)
if formatnum > 0 {
writeHeader(buf, finalHeaders, "format")
} else {
delete(finalHeaders, "format")
}
if withAuthority {
writeHeader(buf, finalHeaders, "authority-id")
}
if revision > 0 {
writeHeader(buf, finalHeaders, "revision")
} else {
delete(finalHeaders, "revision")
}
written := map[string]bool{
"type": true,
"format": true,
"authority-id": true,
"revision": true,
"body-length": true,
"sign-key-sha3-384": true,
}
for _, primKey := range assertType.PrimaryKey {
defl := assertType.OptionalPrimaryKeyDefaults[primKey]
_, ok := finalHeaders[primKey]
if !ok && defl != "" {
// optional but expected to be set in headers
// in the result assertion
finalHeaders[primKey] = defl
continue
}
value, err := checkPrimaryKey(finalHeaders, primKey)
if err != nil {
return nil, err
}
if value != defl {
writeHeader(buf, finalHeaders, primKey)
}
written[primKey] = true
}
// emit other headers in lexicographic order
otherKeys := make([]string, 0, len(finalHeaders))
for name := range finalHeaders {
if !written[name] {
otherKeys = append(otherKeys, name)
}
}
sort.Strings(otherKeys)
for _, k := range otherKeys {
writeHeader(buf, finalHeaders, k)
}
// body-length and body
if bodyLength > 0 {
writeHeader(buf, finalHeaders, "body-length")
} else {
delete(finalHeaders, "body-length")
}
// signing key reference
writeHeader(buf, finalHeaders, "sign-key-sha3-384")
if bodyLength > 0 {
buf.Grow(bodyLength + 2)
buf.Write(nlnl)
buf.Write(finalBody)
} else {
finalBody = nil
}
content := buf.Bytes()
signature, err := signContent(content, privKey)
if err != nil {
return nil, fmt.Errorf("cannot sign assertion: %v", err)
}
// be 'cat' friendly, add a ignored newline to the signature which is the last part of the encoded assertion
signature = append(signature, '\n')
assert, err := assertType.assembler(assertionBase{
headers: finalHeaders,
body: finalBody,
format: formatnum,
revision: revision,
content: content,
signature: signature,
})
if err != nil {
return nil, fmt.Errorf("cannot assemble assertion %s: %v", assertType.Name, err)
}
return assert, nil
}
// SignWithoutAuthority assembles an assertion without a set authority with the provided information and signs it with the given private key.
func SignWithoutAuthority(assertType *AssertionType, headers map[string]interface{}, body []byte, privKey PrivateKey) (Assertion, error) {
if assertType.flags&noAuthority == 0 {
return nil, fmt.Errorf("cannot sign assertions needing a definite authority with SignWithoutAuthority")
}
return assembleAndSign(assertType, headers, body, privKey)
}
// Encode serializes an assertion.
func Encode(assert Assertion) []byte {
content, signature := assert.Signature()
needed := len(content) + 2 + len(signature)
buf := bytes.NewBuffer(make([]byte, 0, needed))
buf.Write(content)
buf.Write(nlnl)
buf.Write(signature)
return buf.Bytes()
}
// Encoder emits a stream of assertions bundled by separating them with double newlines.
type Encoder struct {
wr io.Writer
nextSep []byte
}
// NewEncoder returns a Encoder to emit a stream of assertions to a writer.
func NewEncoder(w io.Writer) *Encoder {
return &Encoder{wr: w}
}
func (enc *Encoder) writeSep(last byte) error {
if last != '\n' {
_, err := enc.wr.Write(nl)
if err != nil {
return err
}
}
enc.nextSep = nl
return nil
}
// WriteEncoded writes the encoded assertion into the stream with the required separator.
func (enc *Encoder) WriteEncoded(encoded []byte) error {
sz := len(encoded)
if sz == 0 {
return fmt.Errorf("internal error: encoded assertion cannot be empty")
}
_, err := enc.wr.Write(enc.nextSep)
if err != nil {
return err
}
_, err = enc.wr.Write(encoded)
if err != nil {
return err
}
return enc.writeSep(encoded[sz-1])
}
// WriteContentSignature writes the content and signature of an assertion into the stream with all the required separators.
func (enc *Encoder) WriteContentSignature(content, signature []byte) error {
if len(content) == 0 {
return fmt.Errorf("internal error: content cannot be empty")
}
sz := len(signature)
if sz == 0 {
return fmt.Errorf("internal error: signature cannot be empty")
}
_, err := enc.wr.Write(enc.nextSep)
if err != nil {
return err
}
_, err = enc.wr.Write(content)
if err != nil {
return err
}
_, err = enc.wr.Write(nlnl)
if err != nil {
return err
}
_, err = enc.wr.Write(signature)
if err != nil {
return err
}
return enc.writeSep(signature[sz-1])
}
// Encode emits the assertion into the stream with the required separator.
// Errors here are always about writing given that Encode() itself cannot error.
func (enc *Encoder) Encode(assert Assertion) error {
return enc.WriteContentSignature(assert.Signature())
}
// SignatureCheck checks the signature of the assertion against the given public key. Useful for assertions with no authority.
func SignatureCheck(assert Assertion, pubKey PublicKey) error {
content, encodedSig := assert.Signature()
sig, err := decodeSignature(encodedSig)
if err != nil {
return err
}
err = pubKey.verify(content, sig)
if err != nil {
return fmt.Errorf("failed signature verification: %v", err)
}
return nil
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/mysnapcore/mysnapd.git
git@gitee.com:mysnapcore/mysnapd.git
mysnapcore
mysnapd
mysnapd
v0.1.0

搜索帮助