2015-11-10 18:33:36 +01:00
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
2017-01-24 17:16:58 +01:00
* Copyright (C) 2015-2017 Canonical Ltd
2015-11-10 18:33:36 +01:00
*
* 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 (
2016-01-27 21:21:11 +01:00
"bufio"
2015-11-10 18:33:36 +01:00
"bytes"
2016-08-01 23:10:40 +02:00
"crypto"
2015-11-10 18:33:36 +01:00
"fmt"
2016-01-22 18:47:51 +01:00
"io"
2015-11-18 18:08:59 +01:00
"sort"
2015-11-10 18:33:36 +01:00
"strconv"
2016-08-16 13:03:03 +02:00
"strings"
2016-08-25 11:36:59 +02:00
"unicode/utf8"
2015-11-10 18:33:36 +01:00
)
2016-07-29 18:14:18 +02:00
type typeFlags int
const (
2016-08-12 11:28:39 +02:00
noAuthority typeFlags = iota + 1
2016-07-29 18:14:18 +02:00
)
2019-08-09 16:18:46 -05:00
// MetaHeaders is a list of headers in assertions which are about the assertion
// itself.
2019-08-20 09:56:16 -05:00
var MetaHeaders = [ ... ] string {
2019-08-09 16:18:46 -05:00
"type" ,
"format" ,
"authority-id" ,
"revision" ,
"body-length" ,
"sign-key-sha3-384" ,
}
2016-01-20 20:22:00 +01:00
// AssertionType describes a known assertion type with its name and metadata.
type AssertionType struct {
2016-01-20 21:29:00 +01:00
// Name of the type.
Name string
// PrimaryKey holds the names of the headers that constitute the
// unique primary key for this assertion type.
2016-01-20 20:44:45 +01:00
PrimaryKey [ ] string
2016-01-21 10:11:32 +01:00
2016-01-21 10:20:06 +01:00
assembler func ( assert assertionBase ) ( Assertion , error )
2016-07-29 18:14:18 +02:00
flags typeFlags
2016-01-20 20:22:00 +01:00
}
2015-11-10 18:33:36 +01:00
2016-10-14 14:53:38 +02:00
// MaxSupportedFormat returns the maximum supported format iteration for the type.
func ( at * AssertionType ) MaxSupportedFormat ( ) int {
return maxSupportedFormat [ at . Name ]
}
2016-01-20 20:44:45 +01:00
// Understood assertion types.
2016-01-20 20:22:00 +01:00
var (
2016-07-29 18:14:18 +02:00
AccountType = & AssertionType { "account" , [ ] string { "account-id" } , assembleAccount , 0 }
2016-08-15 14:37:14 +02:00
AccountKeyType = & AssertionType { "account-key" , [ ] string { "public-key-sha3-384" } , assembleAccountKey , 0 }
2017-05-23 13:27:47 +02:00
RepairType = & AssertionType { "repair" , [ ] string { "brand-id" , "repair-id" } , assembleRepair , 0 }
2016-07-29 18:14:18 +02:00
ModelType = & AssertionType { "model" , [ ] string { "series" , "brand-id" , "model" } , assembleModel , 0 }
SerialType = & AssertionType { "serial" , [ ] string { "brand-id" , "model" , "serial" } , assembleSerial , 0 }
2016-09-30 23:26:36 +02:00
BaseDeclarationType = & AssertionType { "base-declaration" , [ ] string { "series" } , assembleBaseDeclaration , 0 }
2016-07-29 18:14:18 +02:00
SnapDeclarationType = & AssertionType { "snap-declaration" , [ ] string { "series" , "snap-id" } , assembleSnapDeclaration , 0 }
SnapBuildType = & AssertionType { "snap-build" , [ ] string { "snap-sha3-384" } , assembleSnapBuild , 0 }
SnapRevisionType = & AssertionType { "snap-revision" , [ ] string { "snap-sha3-384" } , assembleSnapRevision , 0 }
2017-03-10 07:30:05 +00:00
SnapDeveloperType = & AssertionType { "snap-developer" , [ ] string { "snap-id" , "publisher-id" } , assembleSnapDeveloper , 0 }
2016-09-22 21:14:59 +02:00
SystemUserType = & AssertionType { "system-user" , [ ] string { "brand-id" , "email" } , assembleSystemUser , 0 }
2016-08-23 19:10:24 -03:00
ValidationType = & AssertionType { "validation" , [ ] string { "series" , "snap-id" , "approved-snap-id" , "approved-snap-revision" } , assembleValidation , 0 }
2017-08-16 14:54:28 +01:00
StoreType = & AssertionType { "store" , [ ] string { "store" } , assembleStore , 0 }
2015-11-17 17:12:08 +01:00
2015-11-10 18:33:36 +01:00
// ...
)
2016-08-12 11:28:39 +02:00
// Assertion types without a definite authority set (on the wire and/or self-signed).
2016-07-29 18:14:18 +02:00
var (
2016-08-30 19:42:01 +02:00
DeviceSessionRequestType = & AssertionType { "device-session-request" , [ ] string { "brand-id" , "model" , "serial" } , assembleDeviceSessionRequest , noAuthority }
SerialRequestType = & AssertionType { "serial-request" , nil , assembleSerialRequest , noAuthority }
2016-08-30 17:10:45 +01:00
AccountKeyRequestType = & AssertionType { "account-key-request" , [ ] string { "public-key-sha3-384" } , assembleAccountKeyRequest , noAuthority }
2016-07-29 18:14:18 +02:00
)
2016-01-20 21:22:39 +01:00
var typeRegistry = map [ string ] * AssertionType {
2016-05-24 17:47:15 +02:00
AccountType . Name : AccountType ,
2016-02-15 19:11:57 +01:00
AccountKeyType . Name : AccountKeyType ,
ModelType . Name : ModelType ,
2016-05-24 18:13:53 +02:00
SerialType . Name : SerialType ,
2016-09-30 23:26:36 +02:00
BaseDeclarationType . Name : BaseDeclarationType ,
2016-02-15 19:11:57 +01:00
SnapDeclarationType . Name : SnapDeclarationType ,
SnapBuildType . Name : SnapBuildType ,
SnapRevisionType . Name : SnapRevisionType ,
2017-03-10 07:30:05 +00:00
SnapDeveloperType . Name : SnapDeveloperType ,
2016-09-22 14:44:22 +02:00
SystemUserType . Name : SystemUserType ,
2016-08-23 19:10:24 -03:00
ValidationType . Name : ValidationType ,
2017-04-19 07:58:58 +02:00
RepairType . Name : RepairType ,
2017-08-16 14:54:28 +01:00
StoreType . Name : StoreType ,
2016-08-12 11:28:39 +02:00
// no authority
2016-08-30 19:42:01 +02:00
DeviceSessionRequestType . Name : DeviceSessionRequestType ,
SerialRequestType . Name : SerialRequestType ,
AccountKeyRequestType . Name : AccountKeyRequestType ,
2016-01-20 21:22:39 +01:00
}
2016-01-20 21:18:47 +01:00
2017-01-20 16:55:42 +01:00
// Type returns the AssertionType with name or nil
func Type ( name string ) * AssertionType {
return typeRegistry [ name ]
}
2017-06-30 10:13:04 +01:00
// 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
}
2016-10-14 14:53:38 +02:00
var maxSupportedFormat = map [ string ] int { }
func init ( ) {
// register maxSupportedFormats while breaking initialisation loop
2017-01-24 17:16:58 +01:00
// 1: plugs and slots
// 2: support for $SLOT()/$PLUG()/$MISSING
2018-09-14 13:53:46 +02:00
// 3: support for on-store/on-brand/on-model device scope constraints
2019-11-27 17:29:30 +01:00
// 4: support for plug-names/slot-names constraints
maxSupportedFormat [ SnapDeclarationType . Name ] = 4
2020-05-06 12:16:02 +02:00
// 1: support to limit to device serials
maxSupportedFormat [ SystemUserType . Name ] = 1
2016-10-14 14:53:38 +02:00
}
2016-10-14 21:25:53 +02:00
func MockMaxSupportedFormat ( assertType * AssertionType , maxFormat int ) ( restore func ( ) ) {
prev := maxSupportedFormat [ assertType . Name ]
maxSupportedFormat [ assertType . Name ] = maxFormat
return func ( ) {
maxSupportedFormat [ assertType . Name ] = prev
}
}
2017-01-20 16:55:42 +01:00
var formatAnalyzer = map [ * AssertionType ] func ( headers map [ string ] interface { } , body [ ] byte ) ( formatnum int , err error ) {
SnapDeclarationType : snapDeclarationFormatAnalyze ,
}
2020-04-19 17:18:45 +02:00
// 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
}
2017-01-20 16:55:42 +01:00
// 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
}
2017-02-01 20:56:02 +01:00
formatnum , err = analyzer ( headers , body )
if err != nil {
return 0 , fmt . Errorf ( "assertion %s: %v" , assertType . Name , err )
}
return formatnum , nil
2016-01-20 20:22:00 +01:00
}
2017-09-12 16:34:53 +02:00
// HeadersFromPrimaryKey constructs a headers mapping from the
// primaryKey values and the assertion type, it errors if primaryKey
// has the wrong length.
func HeadersFromPrimaryKey ( assertType * AssertionType , primaryKey [ ] string ) ( headers map [ string ] string , err error ) {
if len ( primaryKey ) != len ( assertType . PrimaryKey ) {
return nil , fmt . Errorf ( "primary key has wrong length for %q assertion" , assertType . Name )
}
headers = make ( map [ string ] string , len ( assertType . PrimaryKey ) )
for i , name := range assertType . PrimaryKey {
2017-09-12 22:30:17 +02:00
keyVal := primaryKey [ i ]
if keyVal == "" {
return nil , fmt . Errorf ( "primary key %q header cannot be empty" , name )
}
headers [ name ] = keyVal
2017-09-12 16:34:53 +02:00
}
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.
func PrimaryKeyFromHeaders ( assertType * AssertionType , headers map [ string ] string ) ( primaryKey [ ] string , err error ) {
primaryKey = make ( [ ] string , len ( assertType . PrimaryKey ) )
for i , k := range assertType . PrimaryKey {
keyVal := headers [ k ]
if keyVal == "" {
return nil , fmt . Errorf ( "must provide primary key: %v" , k )
}
primaryKey [ i ] = keyVal
}
return primaryKey , nil
}
2016-07-15 12:17:49 +02:00
// Ref expresses a reference to an assertion.
type Ref struct {
Type * AssertionType
PrimaryKey [ ] string
}
2016-08-26 08:32:09 +02:00
func ( ref * Ref ) String ( ) string {
2016-09-19 10:33:03 +02:00
pkStr := "-"
2016-09-16 23:30:28 +02:00
n := len ( ref . Type . PrimaryKey )
if n != len ( ref . PrimaryKey ) {
pkStr = "???"
} else if n > 0 {
pkStr = ref . PrimaryKey [ n - 1 ]
if n > 1 {
sfx := [ ] string { pkStr + ";" }
for i , k := range ref . Type . PrimaryKey [ : n - 1 ] {
sfx = append ( sfx , fmt . Sprintf ( "%s:%s" , k , ref . PrimaryKey [ i ] ) )
}
pkStr = strings . Join ( sfx , " " )
}
}
return fmt . Sprintf ( "%s (%s)" , ref . Type . Name , pkStr )
2016-08-26 08:32:09 +02:00
}
2016-08-16 13:03:03 +02:00
// 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 ( 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 ) {
2017-09-12 16:34:53 +02:00
headers , err := HeadersFromPrimaryKey ( ref . Type , ref . PrimaryKey )
if err != nil {
2016-08-16 13:03:03 +02:00
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 )
}
2020-04-05 16:20:52 +02:00
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 )
}
2015-11-10 18:33:36 +01:00
// Assertion represents an assertion through its general elements.
type Assertion interface {
2015-11-17 10:34:52 +01:00
// Type returns the type of this assertion
2016-01-20 20:22:00 +01:00
Type ( ) * AssertionType
2016-10-14 14:53:38 +02:00
// Format returns the format iteration of this assertion
Format ( ) int
2016-10-17 19:57:08 +02:00
// SupportedFormat returns whether the assertion uses a supported
2016-10-14 14:53:38 +02:00
// format iteration. If false the assertion might have been only
// partially parsed.
SupportedFormat ( ) bool
2015-11-17 10:34:52 +01:00
// Revision returns the revision of this assertion
2015-11-10 18:33:36 +01:00
Revision ( ) int
2015-11-17 10:34:52 +01:00
// AuthorityID returns the authority that signed this assertion
2015-11-10 18:33:36 +01:00
AuthorityID ( ) string
// Header retrieves the header with name
2016-07-27 15:21:36 +02:00
Header ( name string ) interface { }
2015-11-10 18:33:36 +01:00
2016-01-08 09:23:51 +01:00
// Headers returns the complete headers
2016-07-27 15:21:36 +02:00
Headers ( ) map [ string ] interface { }
// HeaderString retrieves the string value of header with name or ""
HeaderString ( name string ) string
2016-01-08 09:23:51 +01:00
2015-11-17 10:34:52 +01:00
// Body returns the body of this assertion
2015-11-10 18:33:36 +01:00
Body ( ) [ ] byte
2015-11-16 14:44:21 +01:00
// Signature returns the signed content and its unprocessed signature
2015-11-16 14:46:25 +01:00
Signature ( ) ( content , signature [ ] byte )
2016-07-15 12:17:49 +02:00
2016-08-12 18:19:27 +02:00
// SignKeyID returns the key id for the key that signed this assertion.
SignKeyID ( ) string
2016-07-15 12:17:49 +02:00
// Prerequisites returns references to the prerequisite assertions for the validity of this one.
Prerequisites ( ) [ ] * Ref
2016-08-19 10:39:22 +02:00
// Ref returns a reference representing this assertion.
Ref ( ) * Ref
2020-04-19 19:15:59 +02:00
// At returns an AtRevision referencing this assertion at its revision.
At ( ) * AtRevision
2015-11-10 18:33:36 +01:00
}
2016-09-02 18:54:24 +01:00
// 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 {
2016-09-01 16:39:39 +01:00
// signKey returns the public key material for the key that signed this assertion. See also SignKeyID.
signKey ( ) PublicKey
}
2016-07-11 14:53:56 +01:00
// MediaType is the media type for encoded assertions on the wire.
2016-01-26 19:24:13 +01:00
const MediaType = "application/x.ubuntu.assertion"
2015-11-30 16:23:39 +01:00
// assertionBase is the concrete base to hold representation data for actual assertions.
type assertionBase struct {
2016-07-27 15:21:36 +02:00
headers map [ string ] interface { }
2015-11-10 18:33:36 +01:00
body [ ] byte
2016-10-14 14:53:38 +02:00
// parsed format iteration
format int
2015-11-10 18:33:36 +01:00
// parsed revision
revision int
// preserved content
content [ ] byte
2015-11-16 14:44:21 +01:00
// unprocessed signature
signature [ ] byte
2015-11-10 18:33:36 +01:00
}
2016-07-27 15:21:36 +02:00
// HeaderString retrieves the string value of header with name or ""
func ( ab * assertionBase ) HeaderString ( name string ) string {
s , _ := ab . headers [ name ] . ( string )
return s
}
2015-11-10 18:33:36 +01:00
// Type returns the assertion type.
2016-01-20 20:22:00 +01:00
func ( ab * assertionBase ) Type ( ) * AssertionType {
2016-07-27 15:21:36 +02:00
return Type ( ab . HeaderString ( "type" ) )
2015-11-10 18:33:36 +01:00
}
2016-10-14 14:53:38 +02:00
// Format returns the assertion format iteration.
func ( ab * assertionBase ) Format ( ) int {
return ab . format
}
2016-10-17 19:57:08 +02:00
// SupportedFormat returns whether the assertion uses a supported
2016-10-14 14:53:38 +02:00
// format iteration. If false the assertion might have been only
// partially parsed.
func ( ab * assertionBase ) SupportedFormat ( ) bool {
return ab . format <= maxSupportedFormat [ ab . HeaderString ( "type" ) ]
}
2015-11-10 18:33:36 +01:00
// Revision returns the assertion revision.
2015-11-30 16:23:39 +01:00
func ( ab * assertionBase ) Revision ( ) int {
2015-11-10 18:33:36 +01:00
return ab . revision
}
// AuthorityID returns the authority-id a.k.a the signer id of the assertion.
2015-11-30 16:23:39 +01:00
func ( ab * assertionBase ) AuthorityID ( ) string {
2016-07-27 15:21:36 +02:00
return ab . HeaderString ( "authority-id" )
2015-11-10 18:33:36 +01:00
}
// Header returns the value of an header by name.
2016-07-27 15:21:36 +02:00
func ( ab * assertionBase ) Header ( name string ) interface { } {
v := ab . headers [ name ]
if v == nil {
return nil
}
return copyHeader ( v )
2015-11-10 18:33:36 +01:00
}
2016-01-08 09:23:51 +01:00
// Headers returns the complete headers.
2016-07-27 15:21:36 +02:00
func ( ab * assertionBase ) Headers ( ) map [ string ] interface { } {
return copyHeaders ( ab . headers )
2016-01-08 09:23:51 +01:00
}
2015-11-10 18:33:36 +01:00
// Body returns the body of the assertion.
2015-11-30 16:23:39 +01:00
func ( ab * assertionBase ) Body ( ) [ ] byte {
2015-11-10 18:33:36 +01:00
return ab . body
}
2015-11-16 14:44:21 +01:00
// Signature returns the signed content and its unprocessed signature.
2015-11-30 16:23:39 +01:00
func ( ab * assertionBase ) Signature ( ) ( content , signature [ ] byte ) {
2015-11-16 14:44:21 +01:00
return ab . content , ab . signature
2015-11-10 18:33:36 +01:00
}
2016-08-12 18:19:27 +02:00
// SignKeyID returns the key id for the key that signed this assertion.
func ( ab * assertionBase ) SignKeyID ( ) string {
2016-08-01 23:10:40 +02:00
return ab . HeaderString ( "sign-key-sha3-384" )
2016-07-15 12:17:49 +02:00
}
// Prerequisites returns references to the prerequisite assertions for the validity of this one.
func ( ab * assertionBase ) Prerequisites ( ) [ ] * Ref {
return nil
}
2016-08-19 10:39:22 +02:00
// 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 ,
}
}
2020-04-19 19:15:59 +02:00
// At returns an AtRevision referencing this assertion at its revision.
func ( ab * assertionBase ) At ( ) * AtRevision {
return & AtRevision { Ref : * ab . Ref ( ) , Revision : ab . Revision ( ) }
}
2015-11-10 18:33:36 +01:00
// sanity check
2015-11-30 16:23:39 +01:00
var _ Assertion = ( * assertionBase ) ( nil )
2015-11-10 18:33:36 +01:00
// Decode parses a serialized assertion.
2015-11-11 11:36:26 +01:00
//
// The expected serialisation format looks like:
//
// HEADER ("\n\n" BODY?)? "\n\n" SIGNATURE
//
// where:
//
2016-02-11 11:29:25 +01:00
// HEADER is a set of header entries separated by "\n"
2017-02-17 13:24:07 +01:00
// BODY can be arbitrary text,
2015-11-16 15:45:52 +01:00
// SIGNATURE is the signature
2015-11-11 11:36:26 +01:00
//
2017-02-17 13:24:07 +01:00
// Both BODY and HEADER must be UTF8.
//
2016-06-21 18:13:01 +02:00
// A header entry for a single line value (no '\n' in it) looks like:
2015-11-11 11:36:26 +01:00
//
2016-07-27 15:21:36 +02:00
// NAME ": " SIMPLEVALUE
2015-11-11 11:36:26 +01:00
//
2016-07-27 15:21:36 +02:00
// The format supports multiline text values (with '\n's in them) and
2017-02-17 15:16:11 +01:00
// lists or maps, possibly nested, with string scalars in them.
2016-02-11 11:13:07 +01:00
//
2016-07-27 15:21:36 +02:00
// For those a header entry looks like:
//
// NAME ":\n" MULTI(baseindent)
//
// where MULTI can be
//
// * (baseindent + 4)-space indented value (multiline text)
2017-02-17 13:24:07 +01:00
//
2016-07-27 15:21:36 +02:00
// * entries of a list each of the form:
//
2017-02-17 13:24:07 +01:00
// " "*baseindent " -" ( " " SIMPLEVALUE | "\n" MULTI )
//
// * entries of map each of the form:
//
2017-02-17 13:28:23 +01:00
// " "*baseindent " " NAME ":" ( " " SIMPLEVALUE | "\n" MULTI )
2016-07-27 15:21:36 +02:00
//
// baseindent starts at 0 and then grows with nesting matching the
2017-02-17 13:28:23 +01:00
// previous level introduction (e.g. the " "*baseindent " -" bit)
2016-07-27 15:21:36 +02:00
// length minus 1.
2016-02-11 11:13:07 +01:00
//
2016-07-29 18:14:18 +02:00
// In general the following headers are mandatory:
2015-11-11 11:36:26 +01:00
//
// type
2016-08-12 11:28:39 +02:00
// authority-id (except for on the wire/self-signed assertions like serial-request)
2015-11-16 14:23:58 +01:00
//
2016-06-21 18:13:01 +02:00
// Further for a given assertion type all the primary key headers
// must be non empty and must not contain '/'.
//
2016-07-27 15:21:36 +02:00
// The following headers expect string representing integer values and
// if omitted otherwise are assumed to be 0:
2015-11-16 15:45:52 +01:00
//
2015-11-11 11:36:26 +01:00
// revision (a positive int)
2015-11-16 15:45:52 +01:00
// body-length (expected to be equal to the length of BODY)
2017-02-17 13:24:07 +01:00
// format (a positive int for the format iteration of the type used)
2015-11-11 11:36:26 +01:00
//
2016-06-21 18:13:01 +02:00
// Times are expected to be in the RFC3339 format: "2006-01-02T15:04:05Z07:00".
2017-02-17 13:24:07 +01:00
//
2015-11-10 18:33:36 +01:00
func Decode(serializedAssertion []byte) (Assertion, error) {
2015-11-16 14:32:50 +01:00
// 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 )
2015-11-10 18:33:36 +01:00
if contentSignatureSplit == - 1 {
return nil , fmt . Errorf ( "assertion content/signature separator not found" )
}
2015-11-16 14:32:50 +01:00
content := assertionSnapshot [ : contentSignatureSplit ]
signature := assertionSnapshot [ contentSignatureSplit + 2 : ]
2015-11-10 18:33:36 +01:00
headersBodySplit := bytes . Index ( content , nlnl )
var body , head [ ] byte
if headersBodySplit == - 1 {
head = content
} else {
body = content [ headersBodySplit + 2 : ]
2015-11-11 18:11:54 +01:00
if len ( body ) == 0 {
body = nil
}
2015-11-10 18:33:36 +01:00
head = content [ : headersBodySplit ]
}
2016-07-27 15:21:36 +02:00
headers , err := parseHeaders ( head )
2015-11-10 18:33:36 +01:00
if err != nil {
return nil , fmt . Errorf ( "parsing assertion headers: %v" , err )
}
2016-07-27 15:21:36 +02:00
return assemble ( headers , body , content , signature )
2016-01-22 18:47:51 +01:00
}
2016-01-28 11:01:46 +01:00
// Maximum assertion component sizes.
const (
MaxBodySize = 2 * 1024 * 1024
2016-01-29 11:25:59 +01:00
MaxHeadersSize = 128 * 1024
2016-01-28 11:01:46 +01:00
MaxSignatureSize = 128 * 1024
)
2016-02-02 16:51:36 +01:00
// Decoder parses a stream of assertions bundled by separating them with double newlines.
2016-01-22 18:47:51 +01:00
type Decoder struct {
2016-01-27 21:21:11 +01:00
rd io . Reader
initialBufSize int
b * bufio . Reader
err error
2016-01-29 11:25:59 +01:00
maxHeadersSize int
2016-01-28 11:01:46 +01:00
maxSigSize int
2017-06-21 16:47:23 +02:00
defaultMaxBodySize int
typeMaxBodySize map [ * AssertionType ] int
2016-01-22 18:47:51 +01:00
}
2016-01-29 14:27:31 +01:00
// 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
2016-01-22 18:47:51 +01:00
}
2017-06-21 16:47:23 +02:00
const defaultDecoderBufSize = 4096
2016-01-28 11:01:46 +01:00
2016-01-22 18:47:51 +01:00
// NewDecoder returns a Decoder to parse the stream of assertions from the reader.
func NewDecoder ( r io . Reader ) * Decoder {
2016-01-29 14:27:31 +01:00
return ( & Decoder {
2017-06-21 16:47:23 +02:00
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 ,
2016-01-29 14:27:31 +01:00
} ) . initBuffer ( )
2016-01-22 18:47:51 +01:00
}
2016-01-27 21:21:11 +01:00
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
}
2016-01-29 13:04:47 +01:00
// NB: readExact and readUntil use peek underneath and their returned
// buffers are valid only until the next reading call
2016-01-27 21:21:11 +01:00
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
}
2016-01-28 11:01:46 +01:00
func ( d * Decoder ) readUntil ( delim [ ] byte , maxSize int ) ( [ ] byte , error ) {
2016-01-27 21:21:11 +01:00
last := 0
2016-01-28 11:01:46 +01:00
size := d . initialBufSize
2016-01-22 18:47:51 +01:00
for {
2016-01-27 21:21:11 +01:00
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
2016-01-22 18:47:51 +01:00
}
2016-01-28 11:01:46 +01:00
// report errors only once we have consumed what is buffered
2016-01-27 21:21:11 +01:00
if err != nil && len ( buf ) == d . b . Buffered ( ) {
d . b . Discard ( len ( buf ) )
return buf , err
2016-01-22 18:47:51 +01:00
}
2016-01-27 21:21:11 +01:00
last = size - len ( delim ) + 1
2016-01-28 11:01:46 +01:00
size *= 2
if size > maxSize {
2016-01-29 11:53:28 +01:00
return nil , fmt . Errorf ( "maximum size exceeded while looking for delimiter %q" , delim )
2016-01-22 18:47:51 +01:00
}
}
}
// Decode parses the next assertion from the stream.
2016-01-25 13:50:00 +01:00
// It returns the error io.EOF at the end of a well-formed stream.
2016-01-27 21:21:11 +01:00
func ( d * Decoder ) Decode ( ) ( Assertion , error ) {
2016-01-22 18:47:51 +01:00
// read the headers and the nlnl separator after them
2016-01-29 11:25:59 +01:00
headAndSep , err := d . readUntil ( nlnl , d . maxHeadersSize )
2016-01-22 18:47:51 +01:00
if err != nil {
2016-01-28 11:01:46 +01:00
if err == io . EOF {
if len ( headAndSep ) != 0 {
return nil , io . ErrUnexpectedEOF
}
return nil , io . EOF
2016-01-22 18:47:51 +01:00
}
2016-01-29 11:25:59 +01:00
return nil , fmt . Errorf ( "error reading assertion headers: %v" , err )
2015-11-11 20:55:13 +01:00
}
2016-01-29 13:04:47 +01:00
headLen := len ( headAndSep ) - len ( nlnl )
2016-07-27 15:21:36 +02:00
headers , err := parseHeaders ( headAndSep [ : headLen ] )
2016-01-22 18:47:51 +01:00
if err != nil {
return nil , fmt . Errorf ( "parsing assertion headers: %v" , err )
}
2017-06-21 16:47:23 +02:00
typeStr , _ := headers [ "type" ] . ( string )
typ := Type ( typeStr )
2016-07-15 14:05:36 +02:00
length , err := checkIntWithDefault ( headers , "body-length" , 0 )
2016-01-22 18:47:51 +01:00
if err != nil {
return nil , fmt . Errorf ( "assertion: %v" , err )
}
2017-06-21 16:47:23 +02:00
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 {
2016-01-28 11:01:46 +01:00
return nil , fmt . Errorf ( "assertion body length %d exceeds maximum body size" , length )
}
2016-01-22 18:47:51 +01:00
2016-01-29 13:04:47 +01:00
// 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 )
2016-01-22 18:47:51 +01:00
if length > 0 {
// read the body if length != 0
2016-01-29 13:04:47 +01:00
body , err := d . readExact ( length )
2016-01-22 18:47:51 +01:00
if err != nil {
return nil , err
}
2016-01-28 11:01:46 +01:00
contentBuf . Write ( body )
2016-01-22 18:47:51 +01:00
}
// try to read the end of body a.k.a content/signature separator
2016-01-28 11:01:46 +01:00
endOfBody , err := d . readUntil ( nlnl , d . maxSigSize )
2016-01-22 18:47:51 +01:00
if err != nil && err != io . EOF {
2016-01-28 11:01:46 +01:00
return nil , fmt . Errorf ( "error reading assertion trailer: %v" , err )
2016-01-22 18:47:51 +01:00
}
2016-01-29 13:04:47 +01:00
var sig [ ] byte
2016-01-22 18:47:51 +01:00
if bytes . Equal ( endOfBody , nlnl ) {
// we got the nlnl content/signature separator, read the signature now and the assertion/assertion nlnl separation
2016-01-28 11:01:46 +01:00
sig , err = d . readUntil ( nlnl , d . maxSigSize )
2016-01-22 18:47:51 +01:00
if err != nil && err != io . EOF {
2016-01-28 11:01:46 +01:00
return nil , fmt . Errorf ( "error reading assertion signature: %v" , err )
2016-01-22 18:47:51 +01:00
}
} 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
2016-01-29 13:04:47 +01:00
contentBuf . Truncate ( headLen )
2016-01-22 18:47:51 +01:00
}
// normalize sig ending newlines
if bytes . HasSuffix ( sig , nlnl ) {
sig = sig [ : len ( sig ) - 1 ]
}
2016-01-29 13:04:47 +01:00
finalContent := contentBuf . Bytes ( )
var finalBody [ ] byte
if length > 0 {
finalBody = finalContent [ headLen + len ( nlnl ) : ]
}
2016-01-28 11:01:46 +01:00
finalSig := make ( [ ] byte , len ( sig ) )
copy ( finalSig , sig )
2016-07-27 15:21:36 +02:00
return assemble ( headers , finalBody , finalContent , finalSig )
2015-11-10 18:33:36 +01:00
}
2016-10-14 14:53:38 +02:00
func checkIteration ( headers map [ string ] interface { } , name string ) ( int , error ) {
iternum , err := checkIntWithDefault ( headers , name , 0 )
2015-11-18 18:08:59 +01:00
if err != nil {
return - 1 , err
}
2016-10-14 14:53:38 +02:00
if iternum < 0 {
return - 1 , fmt . Errorf ( "%s should be positive: %v" , name , iternum )
2015-11-18 18:08:59 +01:00
}
2016-10-14 14:53:38 +02:00
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" )
2015-11-18 18:08:59 +01:00
}
2016-01-07 22:49:49 +01:00
// Assemble assembles an assertion from its components.
2016-07-27 15:21:36 +02:00
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 )
}
// 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 ) {
2016-07-15 14:05:36 +02:00
length , err := checkIntWithDefault ( headers , "body-length" , 0 )
2015-11-10 18:33:36 +01:00
if err != nil {
2015-11-26 17:35:01 +01:00
return nil , fmt . Errorf ( "assertion: %v" , err )
2015-11-10 18:33:36 +01:00
}
2015-11-11 18:15:14 +01:00
if length != len ( body ) {
return nil , fmt . Errorf ( "assertion body length and declared body-length don't match: %v != %v" , len ( body ) , length )
2015-11-10 18:33:36 +01:00
}
2016-08-25 11:36:59 +02:00
if ! utf8 . Valid ( body ) {
return nil , fmt . Errorf ( "body is not utf8" )
}
2016-08-01 23:10:40 +02:00
if _ , err := checkDigest ( headers , "sign-key-sha3-384" , crypto . SHA3_384 ) ; err != nil {
return nil , fmt . Errorf ( "assertion: %v" , err )
}
2016-07-27 15:21:36 +02:00
typ , err := checkNotEmptyString ( headers , "type" )
2015-11-10 18:33:36 +01:00
if err != nil {
2015-11-26 17:12:46 +01:00
return nil , fmt . Errorf ( "assertion: %v" , err )
2015-11-10 18:33:36 +01:00
}
2016-01-20 20:22:00 +01:00
assertType := Type ( typ )
if assertType == nil {
2016-01-21 10:19:47 +01:00
return nil , fmt . Errorf ( "unknown assertion type: %q" , typ )
2016-01-20 20:22:00 +01:00
}
2015-11-10 18:33:36 +01:00
2016-08-12 11:28:39 +02:00
if assertType . flags & noAuthority == 0 {
2016-07-29 18:14:18 +02:00
if _ , err := checkNotEmptyString ( headers , "authority-id" ) ; err != nil {
return nil , fmt . Errorf ( "assertion: %v" , err )
}
} else {
_ , ok := headers [ "authority-id" ]
if ok {
2016-08-12 11:28:39 +02:00
return nil , fmt . Errorf ( "%q assertion cannot have authority-id set" , assertType . Name )
2016-07-29 18:14:18 +02:00
}
}
2016-10-14 14:53:38 +02:00
formatnum , err := checkFormat ( headers )
if err != nil {
return nil , fmt . Errorf ( "assertion: %v" , err )
}
2016-02-04 19:16:03 +01:00
for _ , primKey := range assertType . PrimaryKey {
2016-06-14 10:36:22 +02:00
if _ , err := checkPrimaryKey ( headers , primKey ) ; err != nil {
2016-02-04 19:16:03 +01:00
return nil , fmt . Errorf ( "assertion %s: %v" , assertType . Name , err )
}
}
2015-11-18 18:08:59 +01:00
revision , err := checkRevision ( headers )
2015-11-10 18:33:36 +01:00
if err != nil {
2015-11-26 17:35:01 +01:00
return nil , fmt . Errorf ( "assertion: %v" , err )
2015-11-10 18:33:36 +01:00
}
2016-01-22 18:47:51 +01:00
if len ( signature ) == 0 {
return nil , fmt . Errorf ( "empty assertion signature" )
}
2016-01-20 20:54:07 +01:00
assert , err := assertType . assembler ( assertionBase {
2015-11-16 14:44:21 +01:00
headers : headers ,
body : body ,
2016-10-14 14:53:38 +02:00
format : formatnum ,
2015-11-16 14:44:21 +01:00
revision : revision ,
content : content ,
signature : signature ,
2015-11-17 18:02:17 +01:00
} )
if err != nil {
2016-01-20 20:22:00 +01:00
return nil , fmt . Errorf ( "assertion %s: %v" , assertType . Name , err )
2015-11-17 18:02:17 +01:00
}
return assert , nil
2015-11-10 18:33:36 +01:00
}
2016-07-27 15:21:36 +02:00
func writeHeader ( buf * bytes . Buffer , headers map [ string ] interface { } , name string ) {
appendEntry ( buf , fmt . Sprintf ( "%s:" , name ) , headers [ name ] , 0 )
2015-11-18 18:08:59 +01:00
}
2016-07-27 15:21:36 +02:00
func assembleAndSign ( assertType * AssertionType , headers map [ string ] interface { } , body [ ] byte , privKey PrivateKey ) ( Assertion , error ) {
2016-01-20 21:18:47 +01:00
err := checkAssertType ( assertType )
2016-01-20 20:23:53 +01:00
if err != nil {
return nil , err
}
2016-08-12 11:28:39 +02:00
withAuthority := assertType . flags & noAuthority == 0
2016-07-29 18:14:18 +02:00
2016-07-27 15:21:36 +02:00
err = checkHeaders ( headers )
if err != nil {
return nil , err
2015-11-18 18:08:59 +01:00
}
2016-07-27 15:21:36 +02:00
2016-08-25 11:36:59 +02:00
// 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" )
}
2016-07-27 15:21:36 +02:00
finalHeaders := copyHeaders ( headers )
2015-11-18 18:08:59 +01:00
bodyLength := len ( body )
finalBody := make ( [ ] byte , bodyLength )
copy ( finalBody , body )
2016-01-20 20:22:00 +01:00
finalHeaders [ "type" ] = assertType . Name
2015-11-18 18:08:59 +01:00
finalHeaders [ "body-length" ] = strconv . Itoa ( bodyLength )
2016-08-11 16:49:56 +02:00
finalHeaders [ "sign-key-sha3-384" ] = privKey . PublicKey ( ) . ID ( )
2015-11-18 18:08:59 +01:00
2016-07-29 18:14:18 +02:00
if withAuthority {
if _ , err := checkNotEmptyString ( finalHeaders , "authority-id" ) ; err != nil {
return nil , err
}
} else {
_ , ok := finalHeaders [ "authority-id" ]
if ok {
2016-08-12 11:28:39 +02:00
return nil , fmt . Errorf ( "%q assertion cannot have authority-id set" , assertType . Name )
2016-07-29 18:14:18 +02:00
}
2015-11-18 18:08:59 +01:00
}
2016-10-14 14:53:38 +02:00
formatnum , err := checkFormat ( finalHeaders )
if err != nil {
return nil , err
}
2016-10-14 21:44:41 +02:00
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 ( ) )
}
2017-01-20 19:28:40 +01:00
suggestedFormat , err := SuggestFormat ( assertType , finalHeaders , finalBody )
2017-01-20 16:55:42 +01:00
if err != nil {
return nil , err
}
2017-01-20 19:28:40 +01:00
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 )
2017-01-20 16:55:42 +01:00
}
2015-11-18 18:08:59 +01:00
revision , err := checkRevision ( finalHeaders )
if err != nil {
return nil , err
}
2015-11-20 16:21:59 +01:00
buf := bytes . NewBufferString ( "type: " )
2016-01-20 20:22:00 +01:00
buf . WriteString ( assertType . Name )
2015-11-20 16:21:59 +01:00
2016-10-14 14:53:38 +02:00
if formatnum > 0 {
writeHeader ( buf , finalHeaders , "format" )
} else {
delete ( finalHeaders , "format" )
}
2016-07-29 18:14:18 +02:00
if withAuthority {
writeHeader ( buf , finalHeaders , "authority-id" )
}
2015-11-18 18:08:59 +01:00
if revision > 0 {
writeHeader ( buf , finalHeaders , "revision" )
} else {
delete ( finalHeaders , "revision" )
}
2015-11-19 15:37:57 +01:00
written := map [ string ] bool {
2016-08-01 23:10:40 +02:00
"type" : true ,
2016-10-14 14:53:38 +02:00
"format" : true ,
2016-08-01 23:10:40 +02:00
"authority-id" : true ,
"revision" : true ,
"body-length" : true ,
"sign-key-sha3-384" : true ,
2015-11-18 18:08:59 +01:00
}
2016-01-20 20:54:07 +01:00
for _ , primKey := range assertType . PrimaryKey {
2016-06-14 10:36:22 +02:00
if _ , err := checkPrimaryKey ( finalHeaders , primKey ) ; err != nil {
2015-11-18 18:08:59 +01:00
return nil , err
}
writeHeader ( buf , finalHeaders , primKey )
2015-11-19 15:37:57 +01:00
written [ primKey ] = true
2015-11-18 18:08:59 +01:00
}
// emit other headers in lexicographic order
otherKeys := make ( [ ] string , 0 , len ( finalHeaders ) )
for name := range finalHeaders {
2015-11-19 15:37:57 +01:00
if ! written [ name ] {
2015-11-18 18:08:59 +01:00
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" )
}
2016-08-01 23:10:40 +02:00
// signing key reference
writeHeader ( buf , finalHeaders , "sign-key-sha3-384" )
2015-11-18 18:08:59 +01:00
if bodyLength > 0 {
buf . Grow ( bodyLength + 2 )
2015-12-17 14:57:40 +01:00
buf . Write ( nlnl )
2015-11-18 18:08:59 +01:00
buf . Write ( finalBody )
} else {
finalBody = nil
}
content := buf . Bytes ( )
2015-11-19 14:30:38 +01:00
signature , err := signContent ( content , privKey )
if err != nil {
2016-05-30 10:45:37 +02:00
return nil , fmt . Errorf ( "cannot sign assertion: %v" , err )
2015-11-19 14:30:38 +01:00
}
2015-12-03 08:54:36 +01:00
// be 'cat' friendly, add a ignored newline to the signature which is the last part of the encoded assertion
signature = append ( signature , '\n' )
2015-11-19 14:30:38 +01:00
2016-01-20 20:54:07 +01:00
assert , err := assertType . assembler ( assertionBase {
2015-11-18 18:08:59 +01:00
headers : finalHeaders ,
body : finalBody ,
2016-10-14 14:53:38 +02:00
format : formatnum ,
2015-11-18 18:08:59 +01:00
revision : revision ,
content : content ,
2015-11-19 14:30:38 +01:00
signature : signature ,
2015-11-18 18:08:59 +01:00
} )
if err != nil {
2016-01-20 20:22:00 +01:00
return nil , fmt . Errorf ( "cannot assemble assertion %s: %v" , assertType . Name , err )
2015-11-18 18:08:59 +01:00
}
return assert , nil
}
2016-08-12 11:28:39 +02:00
// 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" )
2016-07-29 18:14:18 +02:00
}
return assembleAndSign ( assertType , headers , body , privKey )
}
2015-11-17 11:02:28 +01:00
// 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 )
2015-12-17 14:57:40 +01:00
buf . Write ( nlnl )
2015-11-17 11:02:28 +01:00
buf . Write ( signature )
return buf . Bytes ( )
}
2016-01-26 13:43:15 +01:00
2016-02-02 16:47:13 +01:00
// Encoder emits a stream of assertions bundled by separating them with double newlines.
2016-01-26 13:43:15 +01:00
type Encoder struct {
2016-02-02 16:47:13 +01:00
wr io . Writer
nextSep [ ] byte
2016-01-26 13:43:15 +01:00
}
// NewEncoder returns a Encoder to emit a stream of assertions to a writer.
func NewEncoder ( w io . Writer ) * Encoder {
return & Encoder { wr : w }
}
2017-06-22 22:55:25 +02:00
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 {
2016-01-26 13:43:15 +01:00
sz := len ( encoded )
if sz == 0 {
return fmt . Errorf ( "internal error: encoded assertion cannot be empty" )
}
2016-02-02 16:47:13 +01:00
_ , err := enc . wr . Write ( enc . nextSep )
2016-01-26 13:43:15 +01:00
if err != nil {
return err
}
2016-02-02 16:47:13 +01:00
_ , err = enc . wr . Write ( encoded )
if err != nil {
return err
}
2017-06-22 22:55:25 +02:00
return enc . writeSep ( encoded [ sz - 1 ] )
}
2016-02-02 16:47:13 +01:00
2017-06-22 22:55:25 +02:00
// 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 ] )
2016-01-26 13:43:15 +01:00
}
// Encode emits the assertion into the stream with the required separator.
2016-01-27 21:21:11 +01:00
// Errors here are always about writing given that Encode() itself cannot error.
2016-01-26 13:43:15 +01:00
func ( enc * Encoder ) Encode ( assert Assertion ) error {
2017-06-22 22:55:25 +02:00
return enc . WriteContentSignature ( assert . Signature ( ) )
2016-01-26 13:43:15 +01:00
}
2016-07-29 18:14:18 +02:00
2016-08-12 11:28:39 +02:00
// SignatureCheck checks the signature of the assertion against the given public key. Useful for assertions with no authority.
2016-07-29 18:14:18 +02:00
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
}