diff --git a/in_toto/keylib.go b/in_toto/keylib.go index 073cab15..ea999ab2 100644 --- a/in_toto/keylib.go +++ b/in_toto/keylib.go @@ -14,6 +14,29 @@ import ( "reflect" ) +func ParseRSAPublicKeyFromPEM(pemBytes []byte) (*rsa.PublicKey, error) { + // TODO: There could be more key data in _, which we silently ignore here. + // Should we handle it / fail / say something about it? + data, _ := pem.Decode([]byte(pemBytes)) + if data == nil { + return nil, fmt.Errorf("Could not find a public key PEM block") + } + + pub, err := x509.ParsePKIXPublicKey(data.Bytes) + if err != nil { + return nil, err + } + + //ParsePKIXPublicKey might return an rsa, dsa, or ecdsa public key + rsaPub, isRsa := pub.(*rsa.PublicKey) + if !isRsa { + return nil, fmt.Errorf("We currently only support rsa keys: got '%s'", + reflect.TypeOf(pub)) + } + + return rsaPub, nil +} + func (k *Key) LoadPublicKey(path string) error { keyFile, err := os.Open(path) defer keyFile.Close() @@ -27,24 +50,13 @@ func (k *Key) LoadPublicKey(path string) error { return err } - // Parse just to see if this is a pem formatted key - // TODO: There could be more key data in _, which we silently ignore here. - // Should we handle it / fail / say something about it? - data, _ := pem.Decode([]byte(keyBytes)) - if data == nil { - return fmt.Errorf("No valid public rsa key found at '%s'", path) - } - - // Parse just to see if this is indeed an rsa public key - pub, err := x509.ParsePKIXPublicKey(data.Bytes) + // We only parse to see if this is indeed a pem formatted rsa public key, + // but don't use the returned *rsa.PublicKey. Instead, we continue with + // the original keyBytes from above. + _, err = ParseRSAPublicKeyFromPEM(keyBytes) if err != nil { return err } - _, isRsa := pub.(*rsa.PublicKey) - if !isRsa { - return fmt.Errorf("We currently only support rsa keys: got '%s'", - reflect.TypeOf(pub)) - } // Strip leading and trailing data from PEM file like securesystemslib does // TODO: Should we instead use the parsed public key to reconstruct the PEM? @@ -54,7 +66,7 @@ func (k *Key) LoadPublicKey(path string) error { keyEnd := strings.Index(string(keyBytes), keyFooter) + len(keyFooter) // Fail if header and footer are not present - // TODO: Is this necessary? pem.Decode or ParsePKIXPublicKey should already + // TODO: Is this necessary? ParseRSAPublicKeyFromPEM should already // return an error if header and footer are not present if keyStart == -1 || keyEnd == -1 { return fmt.Errorf("No valid public rsa key found at '%s'", path) @@ -112,21 +124,11 @@ func VerifySignature(key Key, sig Signature, data []byte) error { if err != nil { return err } - - block, _ := pem.Decode(pemBytes) - if block == nil { - return fmt.Errorf("Could not find a public key PEM block") - } - - pub, err := x509.ParsePKIXPublicKey(block.Bytes) + rsaPub, err := ParseRSAPublicKeyFromPEM(pemBytes) if err != nil { return err } - rsaPub, ok := pub.(*rsa.PublicKey) - if !ok { - return fmt.Errorf("Expected '*rsa.PublicKey' got '%s", reflect.TypeOf(pub)) - } hashed := sha256.Sum256(data) diff --git a/in_toto/model.go b/in_toto/model.go index 187816ab..988e2e84 100644 --- a/in_toto/model.go +++ b/in_toto/model.go @@ -38,25 +38,25 @@ type Link struct { const LinkNameFormat = "%s.%.8s.link" const LinkNameFormatShort = "%s.link" -type Inspection struct { - Type string `json:"_type"` - Run []string `json:"run"` - // TODO: Abstraction for Steps and Inspections? + +type SupplyChainItem struct { Name string `json:"name"` ExpectedMaterials [][]string `json:"expected_materials"` ExpectedProducts [][]string `json:"expected_products"` } +type Inspection struct { + Type string `json:"_type"` + Run []string `json:"run"` + SupplyChainItem +} + type Step struct { Type string `json:"_type"` PubKeys []string `json:"pubkeys"` ExpectedCommand []string `json:"expected_command"` Threshold int `json:"threshold"` - - // TODO: Abstraction for Steps and Inspections? - Name string `json:"name"` - ExpectedMaterials [][]string `json:"expected_materials"` - ExpectedProducts [][]string `json:"expected_products"` + SupplyChainItem } type Layout struct { @@ -68,6 +68,27 @@ type Layout struct { Readme string `json:"readme"` } +// Go does not allow to pass `[]T` (slice with certain type) to a function +// that accepts `[]interface{}` (slice with generic type) +// We have to manually create the interface slice first, see +// https://golang.org/doc/faq#convert_slice_of_interface +// TODO: Is there a better way to do polymorphism for steps and inspections? +func (l *Layout) StepsAsInterfaceSlice() []interface{} { + stepsI := make([]interface{}, len(l.Steps)) + for i, v := range l.Steps { + stepsI[i] = v + } + return stepsI +} +func (l *Layout) InspectAsInterfaceSlice() []interface{} { + inspectionsI := make([]interface{}, len(l.Inspect)) + for i, v := range l.Inspect { + inspectionsI[i] = v + } + return inspectionsI +} + + 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` diff --git a/in_toto/verifylib.go b/in_toto/verifylib.go index e27a6208..3de1dcbf 100644 --- a/in_toto/verifylib.go +++ b/in_toto/verifylib.go @@ -477,15 +477,8 @@ func InTotoVerify(layoutPath string, layoutKeys map[string]Key, return err } - // Go does not allow to pass []Step as []interface{} - // We have to manually copy first :( - // https://golang.org/doc/faq#convert_slice_of_interface - stepsI := make([]interface{}, len(layout.Steps)) - for i, v := range layout.Steps { - stepsI[i] = v - } // Verify artifact rules - if err := VerifyArtifacts(stepsI, stepsMetadataReduced); err != nil { + if err := VerifyArtifacts(layout.StepsAsInterfaceSlice(), stepsMetadataReduced); err != nil { return err } @@ -500,18 +493,9 @@ func InTotoVerify(layoutPath string, layoutKeys map[string]Key, inspectionMetadata[k] = v } - // Convert []Inspections to []interace{} (see `stepsI` above) - inspectionsI := make([]interface{}, len(layout.Inspect)) - for i, v := range layout.Inspect { - inspectionsI[i] = v - } - - if err := VerifyArtifacts(inspectionsI, inspectionMetadata); err != nil { + if err := VerifyArtifacts(layout.InspectAsInterfaceSlice(), inspectionMetadata); err != nil { return err } return nil } - - -