aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--metadata/checks.go197
-rw-r--r--metadata/config.go41
-rw-r--r--metadata/config_test.go19
-rw-r--r--metadata/constants.go51
-rw-r--r--metadata/metadata.pb.go151
-rw-r--r--metadata/metadata.proto31
-rw-r--r--metadata/policy.go46
-rw-r--r--metadata/policy_test.go9
8 files changed, 412 insertions, 133 deletions
diff --git a/metadata/checks.go b/metadata/checks.go
new file mode 100644
index 0000000..5d0ce59
--- /dev/null
+++ b/metadata/checks.go
@@ -0,0 +1,197 @@
+/*
+ * checks.go - Some sanity check methods for our metadata structures
+ *
+ * Copyright 2017 Google Inc.
+ * Author: Joe Richey (joerichey@google.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package metadata
+
+import (
+ "log"
+
+ "github.com/golang/protobuf/proto"
+
+ "fscrypt/util"
+)
+
+// Metadata is the interface to all of the protobuf structures that can be
+// checked with the IsValid method.
+type Metadata interface {
+ IsValid() bool
+ proto.Message
+}
+
+// checkValidLength returns true if expected == actual, otherwise it logs an
+// InvalidLengthError.
+func checkValidLength(name string, expected int, actual int) bool {
+ if expected != actual {
+ log.Print(util.InvalidLengthError(name, expected, actual))
+ return false
+ }
+ return true
+}
+
+// IsValid ensures the mode has a name and isn't empty.
+func (m EncryptionOptions_Mode) IsValid() bool {
+ if m.String() == "" {
+ log.Print("Encryption mode cannot be the empty string")
+ return false
+ }
+ if m == EncryptionOptions_default {
+ log.Print("Encryption mode must be set to a non-default value")
+ return false
+ }
+ return true
+}
+
+// IsValid ensures the source has a name and isn't empty.
+func (s SourceType) IsValid() bool {
+ if s.String() == "" {
+ log.Print("SourceType cannot be the empty string")
+ return false
+ }
+ if s == SourceType_default {
+ log.Print("SourceType must be set to a non-default value")
+ return false
+ }
+ return true
+}
+
+// IsValid ensures the hash costs will be accepted by Argon2.
+func (h *HashingCosts) IsValid() bool {
+ if h == nil {
+ log.Print("HashingCosts not initialized")
+ return false
+ }
+ if h.Time == 0 {
+ log.Print("Hashing time cost not initialized")
+ return false
+ }
+ if h.Parallelism == 0 {
+ log.Print("Hashing parallelism cost not initialized")
+ return false
+ }
+ minMemory := 8 * h.Parallelism
+ if h.Memory < minMemory {
+ log.Printf("Hashing memory cost must be at least %d", minMemory)
+ return false
+ }
+ return true
+}
+
+// IsValid ensures our buffers are the correct length (or just exist).
+func (w *WrappedKeyData) IsValid() bool {
+ if w == nil {
+ log.Print("WrappedKeyData not initialized")
+ return false
+ }
+ if len(w.EncryptedKey) == 0 {
+ log.Print("EncryptedKey not initialized")
+ return false
+ }
+ return checkValidLength("IV", IVLen, len(w.IV)) &&
+ checkValidLength("HMAC", HMACLen, len(w.Hmac))
+}
+
+// IsValid ensures our ProtectorData has the correct fields for its source.
+func (p *ProtectorData) IsValid() bool {
+ if p == nil {
+ log.Print("ProtectorData not initialized")
+ return false
+ }
+
+ // Source specific checks
+ switch p.Source {
+ case SourceType_pam_passphrase:
+ if p.Uid < 0 {
+ log.Print("The UID should never be negative")
+ return false
+ }
+ fallthrough
+ case SourceType_custom_passphrase:
+ if !p.Costs.IsValid() || !checkValidLength("Salt", SaltLen, len(p.Salt)) {
+ return false
+ }
+ }
+
+ // Generic checks
+ return p.Source.IsValid() &&
+ p.WrappedKey.IsValid() &&
+ checkValidLength("EncryptedKey", InternalKeyLen, len(p.WrappedKey.EncryptedKey)) &&
+ checkValidLength("ProtectorDescriptor", DescriptorLen, len(p.ProtectorDescriptor))
+
+}
+
+// IsValid ensures each of the options is valid.
+func (e *EncryptionOptions) IsValid() bool {
+ if e == nil {
+ log.Print("EncryptionOptions not initialized")
+ return false
+ }
+ if _, ok := util.Index(e.Padding, paddingArray); !ok {
+ log.Printf("Padding of %d is invalid", e.Padding)
+ return false
+ }
+
+ return e.Contents.IsValid() && e.Filenames.IsValid()
+}
+
+// IsValid ensures the fields are valid and have the correct lengths.
+func (w *WrappedPolicyKey) IsValid() bool {
+ if w == nil {
+ log.Print("WrappedPolicyKey not initialized")
+ return false
+ }
+ return w.WrappedKey.IsValid() &&
+ checkValidLength("EncryptedKey", PolicyKeyLen, len(w.WrappedKey.EncryptedKey)) &&
+ checkValidLength("ProtectorDescriptor", DescriptorLen, len(w.ProtectorDescriptor))
+}
+
+// IsValid ensures the fields and each wrapped key are valid.
+func (p *PolicyData) IsValid() bool {
+ if p == nil {
+ log.Print("PolicyData not initialized")
+ return false
+ }
+ // Check each wrapped key
+ for _, w := range p.WrappedPolicyKeys {
+ if !w.IsValid() {
+ return false
+ }
+ }
+ return p.Options.IsValid() &&
+ checkValidLength("KeyDescriptor", DescriptorLen, len(p.KeyDescriptor))
+}
+
+// IsValid ensures the Config has all the necessary info for its Source.
+func (c *Config) IsValid() bool {
+ // General checks
+ if c == nil {
+ log.Print("Config not initialized")
+ return false
+ }
+ if !c.Source.IsValid() || !c.Options.IsValid() {
+ return false
+ }
+
+ // Source specific checks
+ switch c.Source {
+ case SourceType_pam_passphrase, SourceType_custom_passphrase:
+ return c.HashCosts.IsValid()
+ default:
+ return true
+ }
+}
diff --git a/metadata/config.go b/metadata/config.go
index 47b6cce..8c7be55 100644
--- a/metadata/config.go
+++ b/metadata/config.go
@@ -19,7 +19,7 @@
*/
// Package metadata contains all of the on disk structures.
-// These structures are definied in meatadata.proto. The package also
+// These structures are defined in metadata.proto. The package also
// contains functions for manipulating these structures, specifically:
// * Reading and Writing the Config file to disk
// * Getting and Setting Policies for directories
@@ -27,21 +27,48 @@
package metadata
//go:generate protoc --go_out=. metadata.proto
-import "github.com/golang/protobuf/jsonpb"
+import (
+ "io"
+ "strings"
+
+ "github.com/golang/protobuf/jsonpb"
+)
// WriteConfig outputs the Config data as nicely formatted JSON
-func WriteConfig(config *Config) (string, error) {
+func WriteConfig(config *Config, out io.Writer) error {
m := jsonpb.Marshaler{
- EmitDefaults: false,
+ EmitDefaults: true,
EnumsAsInts: false,
Indent: "\t",
OrigName: true,
}
- return m.MarshalToString(config)
+ if err := m.Marshal(out, config); err != nil {
+ return err
+ }
+
+ _, err := out.Write([]byte{'\n'})
+ return err
}
// ReadConfig writes the JSON data into the config structure
-func ReadConfig(input string) (*Config, error) {
+func ReadConfig(in io.Reader) (*Config, error) {
config := new(Config)
- return config, jsonpb.UnmarshalString(input, config)
+ // Allow (and ignore) unknown fields for forwards compatibility.
+ u := jsonpb.Unmarshaler{
+ AllowUnknownFields: true,
+ }
+ return config, u.Unmarshal(in, config)
+}
+
+// HasCompatibilityOption returns true if the specified string is in the list of
+// compatibility options. This assumes the compatibility options are in a comma
+// separated string.
+func (c *Config) HasCompatibilityOption(option string) bool {
+ options := strings.Split(c.Compatibility, ",")
+ for _, o := range options {
+ if o == option {
+ return true
+ }
+ }
+ return false
}
diff --git a/metadata/config_test.go b/metadata/config_test.go
index 1903785..206098e 100644
--- a/metadata/config_test.go
+++ b/metadata/config_test.go
@@ -20,6 +20,7 @@
package metadata
import (
+ "bytes"
"reflect"
"testing"
)
@@ -42,27 +43,31 @@ var testConfigString = `{
"memory": "4096",
"parallelism": "8"
},
+ "compatibility": "",
"options": {
"padding": "32",
- "contents_mode": "XTS",
- "filenames_mode": "CTS"
+ "contents": "XTS",
+ "filenames": "CTS"
}
-}`
+}
+`
// Makes sure that writing a config and reading it back gives the same thing.
func TestWrite(t *testing.T) {
- str, err := WriteConfig(testConfig)
+ var b bytes.Buffer
+ err := WriteConfig(testConfig, &b)
if err != nil {
t.Fatal(err)
}
- t.Logf("json encoded config:\n%s", str)
- if str != testConfigString {
+ t.Logf("json encoded config:\n%s", b.String())
+ if b.String() != testConfigString {
t.Errorf("did not match: %s", testConfigString)
}
}
func TestRead(t *testing.T) {
- cfg, err := ReadConfig(testConfigString)
+ buf := bytes.NewBufferString(testConfigString)
+ cfg, err := ReadConfig(buf)
if err != nil {
t.Fatal(err)
}
diff --git a/metadata/constants.go b/metadata/constants.go
new file mode 100644
index 0000000..6e4a08d
--- /dev/null
+++ b/metadata/constants.go
@@ -0,0 +1,51 @@
+/*
+ * constants.go - Some metadata constants used throughout fscrypt
+ *
+ * Copyright 2017 Google Inc.
+ * Author: Joe Richey (joerichey@google.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package metadata
+
+import (
+ "crypto/sha256"
+
+ "golang.org/x/sys/unix"
+)
+
+// Lengths for our keys, buffers, and strings used in fscrypt.
+const (
+ // DescriptorLen is the length of all Protector and Policy descriptors.
+ DescriptorLen = 2 * unix.FS_KEY_DESCRIPTOR_SIZE
+ // We always use 256-bit keys internally (compared to 512-bit policy keys).
+ InternalKeyLen = 32
+ IVLen = 16
+ SaltLen = 16
+ // We use SHA256 for the HMAC, and len(HMAC) == len(hash size).
+ HMACLen = sha256.Size
+ // PolicyKeyLen is the length of all keys passed directly to the Keyring
+ PolicyKeyLen = unix.FS_MAX_KEY_SIZE
+)
+
+var (
+ // DefaultOptions use the supported encryption modes and max padding.
+ DefaultOptions = &EncryptionOptions{
+ Padding: 32,
+ Contents: EncryptionOptions_XTS,
+ Filenames: EncryptionOptions_CTS,
+ }
+ // DefaultSource is the source we use if none is specified.
+ DefaultSource = SourceType_custom_passphrase
+)
diff --git a/metadata/metadata.pb.go b/metadata/metadata.pb.go
index bf30309..7173eb2 100644
--- a/metadata/metadata.pb.go
+++ b/metadata/metadata.pb.go
@@ -38,20 +38,20 @@ const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
type SourceType int32
const (
- SourceType_none SourceType = 0
+ SourceType_default SourceType = 0
SourceType_pam_passphrase SourceType = 1
SourceType_custom_passphrase SourceType = 2
SourceType_raw_key SourceType = 3
)
var SourceType_name = map[int32]string{
- 0: "none",
+ 0: "default",
1: "pam_passphrase",
2: "custom_passphrase",
3: "raw_key",
}
var SourceType_value = map[string]int32{
- "none": 0,
+ "default": 0,
"pam_passphrase": 1,
"custom_passphrase": 2,
"raw_key": 3,
@@ -62,25 +62,25 @@ func (x SourceType) String() string {
}
func (SourceType) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0} }
-// Type of encryption, should match the declarations of unix.FS_ENCRYPTION_MODE
-type EncryptionMode int32
+// Type of encryption; should match declarations of unix.FS_ENCRYPTION_MODE
+type EncryptionOptions_Mode int32
const (
- EncryptionMode_default EncryptionMode = 0
- EncryptionMode_XTS EncryptionMode = 1
- EncryptionMode_GCM EncryptionMode = 2
- EncryptionMode_CBC EncryptionMode = 3
- EncryptionMode_CTS EncryptionMode = 4
+ EncryptionOptions_default EncryptionOptions_Mode = 0
+ EncryptionOptions_XTS EncryptionOptions_Mode = 1
+ EncryptionOptions_GCM EncryptionOptions_Mode = 2
+ EncryptionOptions_CBC EncryptionOptions_Mode = 3
+ EncryptionOptions_CTS EncryptionOptions_Mode = 4
)
-var EncryptionMode_name = map[int32]string{
+var EncryptionOptions_Mode_name = map[int32]string{
0: "default",
1: "XTS",
2: "GCM",
3: "CBC",
4: "CTS",
}
-var EncryptionMode_value = map[string]int32{
+var EncryptionOptions_Mode_value = map[string]int32{
"default": 0,
"XTS": 1,
"GCM": 2,
@@ -88,10 +88,10 @@ var EncryptionMode_value = map[string]int32{
"CTS": 4,
}
-func (x EncryptionMode) String() string {
- return proto.EnumName(EncryptionMode_name, int32(x))
+func (x EncryptionOptions_Mode) String() string {
+ return proto.EnumName(EncryptionOptions_Mode_name, int32(x))
}
-func (EncryptionMode) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{1} }
+func (EncryptionOptions_Mode) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{3, 0} }
// Cost parameters to be used in our hashing functions.
type HashingCosts struct {
@@ -162,9 +162,9 @@ func (m *WrappedKeyData) GetHmac() []byte {
// The associated data for each protector
type ProtectorData struct {
ProtectorDescriptor string `protobuf:"bytes,1,opt,name=protector_descriptor,json=protectorDescriptor" json:"protector_descriptor,omitempty"`
- Name string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"`
- Source SourceType `protobuf:"varint,3,opt,name=source,enum=metadata.SourceType" json:"source,omitempty"`
+ Source SourceType `protobuf:"varint,2,opt,name=source,enum=metadata.SourceType" json:"source,omitempty"`
// These are only used by some of the protector types
+ Name string `protobuf:"bytes,3,opt,name=name" json:"name,omitempty"`
Costs *HashingCosts `protobuf:"bytes,4,opt,name=costs" json:"costs,omitempty"`
Salt []byte `protobuf:"bytes,5,opt,name=salt,proto3" json:"salt,omitempty"`
Uid int64 `protobuf:"varint,6,opt,name=uid" json:"uid,omitempty"`
@@ -183,18 +183,18 @@ func (m *ProtectorData) GetProtectorDescriptor() string {
return ""
}
-func (m *ProtectorData) GetName() string {
+func (m *ProtectorData) GetSource() SourceType {
if m != nil {
- return m.Name
+ return m.Source
}
- return ""
+ return SourceType_default
}
-func (m *ProtectorData) GetSource() SourceType {
+func (m *ProtectorData) GetName() string {
if m != nil {
- return m.Source
+ return m.Name
}
- return SourceType_none
+ return ""
}
func (m *ProtectorData) GetCosts() *HashingCosts {
@@ -225,11 +225,11 @@ func (m *ProtectorData) GetWrappedKey() *WrappedKeyData {
return nil
}
-// Encryption policy specifics, should match struct fscrypt_policy
+// Encryption policy specifics, corresponds to the fscrypt_policy struct
type EncryptionOptions struct {
- Padding int64 `protobuf:"varint,1,opt,name=padding" json:"padding,omitempty"`
- ContentsMode EncryptionMode `protobuf:"varint,2,opt,name=contents_mode,json=contentsMode,enum=metadata.EncryptionMode" json:"contents_mode,omitempty"`
- FilenamesMode EncryptionMode `protobuf:"varint,3,opt,name=filenames_mode,json=filenamesMode,enum=metadata.EncryptionMode" json:"filenames_mode,omitempty"`
+ Padding int64 `protobuf:"varint,1,opt,name=padding" json:"padding,omitempty"`
+ Contents EncryptionOptions_Mode `protobuf:"varint,2,opt,name=contents,enum=metadata.EncryptionOptions_Mode" json:"contents,omitempty"`
+ Filenames EncryptionOptions_Mode `protobuf:"varint,3,opt,name=filenames,enum=metadata.EncryptionOptions_Mode" json:"filenames,omitempty"`
}
func (m *EncryptionOptions) Reset() { *m = EncryptionOptions{} }
@@ -244,18 +244,18 @@ func (m *EncryptionOptions) GetPadding() int64 {
return 0
}
-func (m *EncryptionOptions) GetContentsMode() EncryptionMode {
+func (m *EncryptionOptions) GetContents() EncryptionOptions_Mode {
if m != nil {
- return m.ContentsMode
+ return m.Contents
}
- return EncryptionMode_default
+ return EncryptionOptions_default
}
-func (m *EncryptionOptions) GetFilenamesMode() EncryptionMode {
+func (m *EncryptionOptions) GetFilenames() EncryptionOptions_Mode {
if m != nil {
- return m.FilenamesMode
+ return m.Filenames
}
- return EncryptionMode_default
+ return EncryptionOptions_default
}
type WrappedPolicyKey struct {
@@ -332,7 +332,7 @@ func (m *Config) GetSource() SourceType {
if m != nil {
return m.Source
}
- return SourceType_none
+ return SourceType_default
}
func (m *Config) GetHashCosts() *HashingCosts {
@@ -365,51 +365,50 @@ func init() {
proto.RegisterType((*PolicyData)(nil), "metadata.PolicyData")
proto.RegisterType((*Config)(nil), "metadata.Config")
proto.RegisterEnum("metadata.SourceType", SourceType_name, SourceType_value)
- proto.RegisterEnum("metadata.EncryptionMode", EncryptionMode_name, EncryptionMode_value)
+ proto.RegisterEnum("metadata.EncryptionOptions_Mode", EncryptionOptions_Mode_name, EncryptionOptions_Mode_value)
}
func init() { proto.RegisterFile("metadata.proto", fileDescriptor0) }
var fileDescriptor0 = []byte{
- // 629 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0x51, 0x6f, 0xd3, 0x30,
- 0x10, 0xc7, 0x97, 0xa4, 0x6b, 0xd7, 0x6b, 0x1b, 0x65, 0xde, 0x98, 0x22, 0x78, 0xa9, 0x0a, 0x48,
- 0xd3, 0x34, 0x4d, 0x62, 0x68, 0x0f, 0x3c, 0x20, 0x04, 0x1d, 0x82, 0x31, 0x0d, 0x26, 0x6f, 0x1a,
- 0x20, 0x21, 0x55, 0x5e, 0xe2, 0xad, 0x56, 0x93, 0xd8, 0xb2, 0x5d, 0x55, 0x79, 0xe3, 0x3b, 0xf0,
- 0x39, 0x78, 0xe5, 0x43, 0xf0, 0xa9, 0x90, 0x9d, 0x34, 0x4d, 0x37, 0x04, 0x83, 0x97, 0xe8, 0xee,
- 0x7c, 0xb9, 0xff, 0xdd, 0xcf, 0x27, 0x83, 0x9f, 0x52, 0x4d, 0x62, 0xa2, 0xc9, 0x9e, 0x90, 0x5c,
- 0x73, 0xb4, 0x36, 0xf7, 0x07, 0x5f, 0xa0, 0xfb, 0x96, 0xa8, 0x31, 0xcb, 0xae, 0x87, 0x5c, 0x69,
- 0x85, 0x10, 0x34, 0x34, 0x4b, 0x69, 0xe8, 0xf6, 0x9d, 0x6d, 0x0f, 0x5b, 0x1b, 0x6d, 0x41, 0x33,
- 0xa5, 0x29, 0x97, 0x79, 0xe8, 0xd9, 0x68, 0xe9, 0xa1, 0x3e, 0x74, 0x04, 0x91, 0x24, 0x49, 0x68,
- 0xc2, 0x54, 0x1a, 0x36, 0xec, 0x61, 0x3d, 0x34, 0xf8, 0x0c, 0xfe, 0x47, 0x49, 0x84, 0xa0, 0xf1,
- 0x31, 0xcd, 0x0f, 0x89, 0x26, 0xc8, 0x07, 0xf7, 0xe8, 0x22, 0x74, 0xfa, 0xce, 0x76, 0x17, 0xbb,
- 0x47, 0x17, 0xe8, 0x21, 0xf4, 0x68, 0x16, 0xc9, 0x5c, 0x68, 0x1a, 0x8f, 0x26, 0x34, 0xb7, 0xc2,
- 0x5d, 0xdc, 0xad, 0x82, 0xc7, 0x34, 0x37, 0x4d, 0x8d, 0x53, 0x12, 0x59, 0xf9, 0x2e, 0xb6, 0xf6,
- 0xe0, 0x9b, 0x0b, 0xbd, 0x53, 0xc9, 0x35, 0x8d, 0x34, 0x97, 0xb6, 0xf4, 0x13, 0xd8, 0x14, 0xf3,
- 0xc0, 0x28, 0xa6, 0x2a, 0x92, 0x4c, 0x68, 0x2e, 0xad, 0x58, 0x1b, 0x6f, 0x54, 0x67, 0x87, 0xd5,
- 0x91, 0x29, 0x9c, 0x91, 0x72, 0xda, 0x36, 0xb6, 0x36, 0xda, 0x85, 0xa6, 0xe2, 0x53, 0x19, 0x51,
- 0x2b, 0xe7, 0xef, 0x6f, 0xee, 0x55, 0xf0, 0xce, 0x6c, 0xfc, 0x3c, 0x17, 0x14, 0x97, 0x39, 0x68,
- 0x17, 0x56, 0x23, 0x03, 0xce, 0x4e, 0xdf, 0xd9, 0xdf, 0x5a, 0x24, 0xd7, 0xb1, 0xe2, 0x22, 0xc9,
- 0xe8, 0x29, 0x92, 0xe8, 0x70, 0xb5, 0x18, 0xc4, 0xd8, 0x28, 0x00, 0x6f, 0xca, 0xe2, 0xb0, 0x69,
- 0xe9, 0x19, 0x13, 0x3d, 0x83, 0xce, 0xac, 0xa0, 0x66, 0x89, 0xb4, 0x6c, 0xe5, 0x70, 0x51, 0x79,
- 0x19, 0x29, 0x86, 0x59, 0xe5, 0x0f, 0xbe, 0x3b, 0xb0, 0xfe, 0xba, 0x40, 0xc7, 0x78, 0xf6, 0xc1,
- 0x7e, 0x15, 0x0a, 0xa1, 0x25, 0x48, 0x1c, 0xb3, 0xec, 0xda, 0xc2, 0xf0, 0xf0, 0xdc, 0x45, 0xcf,
- 0xa1, 0x17, 0xf1, 0x4c, 0xd3, 0x4c, 0xab, 0x51, 0xca, 0xe3, 0x82, 0x84, 0x5f, 0x17, 0x5b, 0x54,
- 0x3b, 0xe1, 0x31, 0xc5, 0xdd, 0x79, 0xba, 0xf1, 0xd0, 0x0b, 0xf0, 0xaf, 0x58, 0x42, 0x0d, 0xb7,
- 0xf2, 0x7f, 0xef, 0x2f, 0xff, 0xf7, 0xaa, 0x7c, 0xe3, 0x0e, 0xbe, 0x3a, 0x10, 0x94, 0xe3, 0x9c,
- 0xf2, 0x84, 0x45, 0xb9, 0xb9, 0xee, 0xff, 0xb8, 0xc8, 0x1b, 0xc8, 0xdc, 0x7f, 0x40, 0xf6, 0xc3,
- 0x01, 0x28, 0xb4, 0xed, 0x16, 0x3d, 0x06, 0x7f, 0x42, 0xf3, 0xdb, 0xb2, 0xbd, 0x09, 0xcd, 0x6b,
- 0x82, 0x07, 0xd0, 0xe2, 0x05, 0xdd, 0x52, 0xec, 0xc1, 0xef, 0x46, 0x2e, 0x2f, 0x00, 0xcf, 0x73,
- 0xd1, 0x3b, 0xd8, 0x98, 0xf7, 0x29, 0xac, 0xa6, 0x69, 0x57, 0x85, 0x5e, 0xdf, 0xdb, 0xee, 0xec,
- 0xdf, 0xbf, 0xd5, 0x6f, 0xc5, 0x04, 0xaf, 0xcf, 0x6e, 0x44, 0xd4, 0xe0, 0xa7, 0x03, 0xcd, 0x21,
- 0xcf, 0xae, 0xd8, 0x75, 0x6d, 0x67, 0x9d, 0x3b, 0xec, 0xec, 0x01, 0xc0, 0x98, 0xa8, 0xf1, 0xa8,
- 0x58, 0x5c, 0xf7, 0x8f, 0x8b, 0xdb, 0x36, 0x99, 0xc5, 0xd3, 0xf0, 0xc8, 0xec, 0x4a, 0x2a, 0x88,
- 0x66, 0x97, 0x2c, 0x61, 0xba, 0x78, 0x0d, 0xda, 0x78, 0x39, 0x58, 0x07, 0xd3, 0xb8, 0x3b, 0x98,
- 0x9d, 0xf7, 0x00, 0x8b, 0x4e, 0xd1, 0x1a, 0x34, 0x32, 0x9e, 0xd1, 0x60, 0x05, 0x21, 0xf0, 0x05,
- 0x49, 0x47, 0x82, 0x28, 0x25, 0xc6, 0x92, 0x28, 0x1a, 0x38, 0xe8, 0x1e, 0xac, 0x47, 0x53, 0xa5,
- 0xf9, 0x52, 0xd8, 0x45, 0x1d, 0x68, 0x49, 0x32, 0x33, 0x40, 0x03, 0x6f, 0xe7, 0x25, 0xf8, 0xcb,
- 0x9b, 0x67, 0x8e, 0x63, 0x7a, 0x45, 0xa6, 0x89, 0x0e, 0x56, 0x50, 0x0b, 0xbc, 0x4f, 0xe7, 0x67,
- 0x81, 0x63, 0x8c, 0x37, 0xc3, 0x93, 0xc0, 0x35, 0xc6, 0xf0, 0xd5, 0x30, 0xf0, 0xac, 0x71, 0x7e,
- 0x16, 0x34, 0x2e, 0x9b, 0xf6, 0xad, 0x7c, 0xfa, 0x2b, 0x00, 0x00, 0xff, 0xff, 0x53, 0xcd, 0x67,
- 0x08, 0x3d, 0x05, 0x00, 0x00,
+ // 615 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0xd1, 0x6a, 0xdb, 0x3c,
+ 0x14, 0xc7, 0x3f, 0xdb, 0x69, 0xd2, 0x9c, 0x24, 0xc6, 0x55, 0xfb, 0x15, 0xb3, 0xdd, 0x04, 0x6f,
+ 0x83, 0x32, 0x4a, 0x61, 0x1d, 0x65, 0x0c, 0xc6, 0x2e, 0x96, 0x8e, 0xad, 0x2b, 0x65, 0x9d, 0x5a,
+ 0xba, 0x0d, 0x06, 0x41, 0xb5, 0xd5, 0x46, 0xc4, 0xb6, 0x84, 0xa4, 0x10, 0x7c, 0xb7, 0x77, 0xd8,
+ 0xbb, 0xec, 0x21, 0xf6, 0x1c, 0x7b, 0x90, 0x21, 0xd9, 0x71, 0x92, 0x06, 0x4a, 0xb6, 0x9b, 0x70,
+ 0xf4, 0x97, 0xce, 0xf9, 0x1f, 0xfd, 0x72, 0x2c, 0xf0, 0x33, 0xaa, 0x49, 0x42, 0x34, 0x39, 0x10,
+ 0x92, 0x6b, 0x8e, 0x36, 0x67, 0xeb, 0xe8, 0x1b, 0x74, 0xdf, 0x13, 0x35, 0x62, 0xf9, 0xed, 0x80,
+ 0x2b, 0xad, 0x10, 0x82, 0x86, 0x66, 0x19, 0x0d, 0xdd, 0xbe, 0xb3, 0xe7, 0x61, 0x1b, 0xa3, 0x5d,
+ 0x68, 0x66, 0x34, 0xe3, 0xb2, 0x08, 0x3d, 0xab, 0x56, 0x2b, 0xd4, 0x87, 0x8e, 0x20, 0x92, 0xa4,
+ 0x29, 0x4d, 0x99, 0xca, 0xc2, 0x86, 0xdd, 0x5c, 0x94, 0xa2, 0xaf, 0xe0, 0x7f, 0x96, 0x44, 0x08,
+ 0x9a, 0x9c, 0xd2, 0xe2, 0x98, 0x68, 0x82, 0x7c, 0x70, 0x4f, 0xae, 0x42, 0xa7, 0xef, 0xec, 0x75,
+ 0xb1, 0x7b, 0x72, 0x85, 0x1e, 0x41, 0x8f, 0xe6, 0xb1, 0x2c, 0x84, 0xa6, 0xc9, 0x70, 0x4c, 0x0b,
+ 0x6b, 0xdc, 0xc5, 0xdd, 0x5a, 0x3c, 0xa5, 0x85, 0x69, 0x6a, 0x94, 0x91, 0xd8, 0xda, 0x77, 0xb1,
+ 0x8d, 0xa3, 0x1f, 0x2e, 0xf4, 0xce, 0x25, 0xd7, 0x34, 0xd6, 0x5c, 0xda, 0xd2, 0xcf, 0x60, 0x47,
+ 0xcc, 0x84, 0x61, 0x42, 0x55, 0x2c, 0x99, 0xd0, 0x5c, 0x5a, 0xb3, 0x36, 0xde, 0xae, 0xf7, 0x8e,
+ 0xeb, 0x2d, 0xb4, 0x0f, 0x4d, 0xc5, 0x27, 0x32, 0x2e, 0xef, 0xeb, 0x1f, 0xee, 0x1c, 0xd4, 0xa0,
+ 0x2e, 0xac, 0x7e, 0x59, 0x08, 0x8a, 0xab, 0x33, 0xa6, 0x8d, 0x9c, 0x64, 0xd4, 0xb6, 0xd1, 0xc6,
+ 0x36, 0x46, 0xfb, 0xb0, 0x11, 0x1b, 0x70, 0xf6, 0xf6, 0x9d, 0xc3, 0xdd, 0x79, 0x81, 0x45, 0xac,
+ 0xb8, 0x3c, 0x64, 0x2a, 0x28, 0x92, 0xea, 0x70, 0xa3, 0xbc, 0x88, 0x89, 0x51, 0x00, 0xde, 0x84,
+ 0x25, 0x61, 0xd3, 0xd2, 0x33, 0x21, 0x7a, 0x09, 0x9d, 0x69, 0x49, 0xcd, 0x12, 0x69, 0xd9, 0xca,
+ 0xe1, 0xbc, 0xf2, 0x32, 0x52, 0x0c, 0xd3, 0x7a, 0x1d, 0xfd, 0x76, 0x60, 0xeb, 0x6d, 0x89, 0x8e,
+ 0xf1, 0xfc, 0xa3, 0xfd, 0x55, 0x28, 0x84, 0x96, 0x20, 0x49, 0xc2, 0xf2, 0x5b, 0x0b, 0xc3, 0xc3,
+ 0xb3, 0x25, 0x7a, 0x05, 0x9b, 0x31, 0xcf, 0x35, 0xcd, 0xb5, 0xaa, 0x10, 0xf4, 0xe7, 0x3e, 0x2b,
+ 0x85, 0x0e, 0xce, 0x78, 0x42, 0x71, 0x9d, 0x81, 0x5e, 0x43, 0xfb, 0x86, 0xa5, 0xd4, 0x80, 0x50,
+ 0x96, 0xca, 0x3a, 0xe9, 0xf3, 0x94, 0xe8, 0x05, 0x34, 0x8c, 0x84, 0x3a, 0xd0, 0x4a, 0xe8, 0x0d,
+ 0x99, 0xa4, 0x3a, 0xf8, 0x0f, 0xb5, 0xc0, 0xfb, 0x72, 0x79, 0x11, 0x38, 0x26, 0x78, 0x37, 0x38,
+ 0x0b, 0x5c, 0x13, 0x0c, 0xde, 0x0c, 0x02, 0xcf, 0x06, 0x97, 0x17, 0x41, 0x23, 0xfa, 0xee, 0x40,
+ 0x50, 0x51, 0x38, 0xe7, 0x29, 0x8b, 0x0b, 0x33, 0x25, 0xff, 0xf0, 0xff, 0xdf, 0x21, 0xed, 0xfe,
+ 0x05, 0xe9, 0x9f, 0x0e, 0x40, 0xe9, 0x6d, 0x87, 0xef, 0x09, 0xf8, 0x63, 0x5a, 0xac, 0xda, 0xf6,
+ 0xc6, 0xb4, 0x58, 0x30, 0x3c, 0x82, 0x16, 0x2f, 0x61, 0x54, 0x66, 0x0f, 0xef, 0xe1, 0x85, 0x67,
+ 0x67, 0xd1, 0x07, 0xd8, 0x9e, 0xf5, 0x29, 0xac, 0xa7, 0x69, 0xd7, 0x20, 0xf7, 0xf6, 0x3a, 0x87,
+ 0x0f, 0x56, 0xfa, 0xad, 0x99, 0xe0, 0xad, 0xe9, 0x1d, 0x45, 0x45, 0xbf, 0x1c, 0x68, 0x0e, 0x78,
+ 0x7e, 0xc3, 0x6e, 0x17, 0xc6, 0xdf, 0x59, 0x63, 0xfc, 0x8f, 0x00, 0x46, 0x44, 0x8d, 0x86, 0xe5,
+ 0xbc, 0xbb, 0xf7, 0xce, 0x7b, 0xdb, 0x9c, 0x2c, 0x5f, 0x94, 0xc7, 0xd0, 0x8b, 0x79, 0x26, 0x88,
+ 0x66, 0xd7, 0x2c, 0x65, 0xba, 0xa8, 0x3e, 0x9f, 0x65, 0x71, 0x11, 0x4c, 0x63, 0x7d, 0x30, 0x4f,
+ 0x3f, 0x01, 0xcc, 0x3b, 0x5d, 0x9e, 0x23, 0x04, 0xbe, 0x20, 0xd9, 0x50, 0x10, 0xa5, 0xc4, 0x48,
+ 0x12, 0x45, 0x03, 0x07, 0xfd, 0x0f, 0x5b, 0xf1, 0x44, 0x69, 0xbe, 0x24, 0xbb, 0x26, 0x4f, 0x92,
+ 0xa9, 0x61, 0x1a, 0x78, 0xd7, 0x4d, 0xfb, 0x44, 0x3e, 0xff, 0x13, 0x00, 0x00, 0xff, 0xff, 0xfc,
+ 0x6e, 0x6d, 0x55, 0x34, 0x05, 0x00, 0x00,
}
diff --git a/metadata/metadata.proto b/metadata/metadata.proto
index f3103f8..f402fa1 100644
--- a/metadata/metadata.proto
+++ b/metadata/metadata.proto
@@ -38,7 +38,7 @@ message WrappedKeyData {
// Specifies the method in which an outside secret is obtained for a Protector
enum SourceType {
- none = 0;
+ default = 0;
pam_passphrase = 1;
custom_passphrase = 2;
raw_key = 3;
@@ -47,10 +47,10 @@ enum SourceType {
// The associated data for each protector
message ProtectorData {
string protector_descriptor = 1;
- string name = 2;
- SourceType source = 3;
+ SourceType source = 2;
// These are only used by some of the protector types
+ string name = 3;
HashingCosts costs = 4;
bytes salt = 5;
int64 uid = 6;
@@ -58,20 +58,21 @@ message ProtectorData {
WrappedKeyData wrapped_key = 7;
}
-// Type of encryption, should match the declarations of unix.FS_ENCRYPTION_MODE
-enum EncryptionMode {
- default = 0;
- XTS = 1;
- GCM = 2;
- CBC = 3;
- CTS = 4;
-}
-
-// Encryption policy specifics, should match struct fscrypt_policy
+// Encryption policy specifics, corresponds to the fscrypt_policy struct
message EncryptionOptions {
int64 padding = 1;
- EncryptionMode contents_mode = 2;
- EncryptionMode filenames_mode = 3;
+
+ // Type of encryption; should match declarations of unix.FS_ENCRYPTION_MODE
+ enum Mode {
+ default = 0;
+ XTS = 1;
+ GCM = 2;
+ CBC = 3;
+ CTS = 4;
+ }
+
+ Mode contents = 2;
+ Mode filenames = 3;
}
message WrappedPolicyKey {
diff --git a/metadata/policy.go b/metadata/policy.go
index 8c67f52..102c587 100644
--- a/metadata/policy.go
+++ b/metadata/policy.go
@@ -23,6 +23,8 @@ package metadata
import (
"encoding/hex"
"errors"
+ "fmt"
+ "log"
"os"
"unsafe"
@@ -31,16 +33,14 @@ import (
"fscrypt/util"
)
-// DescriptorLen is the length of all Protector and Policy descriptors.
-const DescriptorLen = 2 * unix.FS_KEY_DESCRIPTOR_SIZE
-
// Encryption specific errors
var (
- ErrEncryptionNotSupported = errors.New("filesystem encryption is not supported")
- ErrEncryptionDisabled = errors.New("filesystem encryption has been disabled in the kernel config")
- ErrNotEncrypted = errors.New("file or directory not encrypted")
- ErrEncrypted = errors.New("file or directory already encrypted")
- ErrBadEncryptionOptions = errors.New("invalid encryption options provided")
+ prefix = "filesystem encryption: "
+ ErrEncryptionNotSupported = errors.New(prefix + "not supported")
+ ErrEncryptionDisabled = errors.New(prefix + "disabled in the kernel config")
+ ErrNotEncrypted = errors.New(prefix + "file or directory not encrypted")
+ ErrEncrypted = errors.New(prefix + "file or directory already encrypted")
+ ErrBadEncryptionOptions = errors.New(prefix + "invalid options provided")
)
// policyIoctl is a wrapper for the ioctl syscall. If opens the file at the path
@@ -76,13 +76,6 @@ func policyIoctl(path string, request uintptr, policy *unix.FscryptPolicy) error
}
}
-// DefaultOptions use the only supported encryption modes and maximum padding.
-var DefaultOptions = &EncryptionOptions{
- Padding: 32,
- ContentsMode: EncryptionMode_XTS,
- FilenamesMode: EncryptionMode_CTS,
-}
-
// Maps EncryptionOptions.Padding <-> FscryptPolicy.Flags
var (
paddingArray = []int64{4, 8, 16, 32}
@@ -101,17 +94,20 @@ func GetPolicy(path string) (*PolicyData, error) {
// Convert the padding flag into an amount of padding
paddingFlag := int64(policy.Flags & unix.FS_POLICY_FLAGS_PAD_MASK)
+
+ // This lookup should always succeed
padding, ok := util.Lookup(paddingFlag, flagsArray, paddingArray)
if !ok {
- return nil, util.SystemErrorF("invalid padding flag: %x", paddingFlag)
+ log.Printf("padding flag of %x not found", paddingFlag)
+ util.NeverError(util.SystemError("invalid padding flag"))
}
return &PolicyData{
KeyDescriptor: hex.EncodeToString(policy.Master_key_descriptor[:]),
Options: &EncryptionOptions{
- Padding: padding,
- ContentsMode: EncryptionMode(policy.Contents_encryption_mode),
- FilenamesMode: EncryptionMode(policy.Filenames_encryption_mode),
+ Padding: padding,
+ Contents: EncryptionOptions_Mode(policy.Contents_encryption_mode),
+ Filenames: EncryptionOptions_Mode(policy.Filenames_encryption_mode),
},
}, nil
}
@@ -123,23 +119,25 @@ func SetPolicy(path string, data *PolicyData) error {
// Convert the padding value to a flag
paddingFlag, ok := util.Lookup(data.Options.Padding, paddingArray, flagsArray)
if !ok {
- return util.InvalidInputF("padding of %d", data.Options.Padding)
+ return util.InvalidInput(fmt.Sprintf("padding of %d", data.Options.Padding))
}
// Convert the policyDescriptor to a byte array
if len(data.KeyDescriptor) != DescriptorLen {
- return util.InvalidLengthError("policy descriptor", DescriptorLen, len(data.KeyDescriptor))
+ return util.InvalidLengthError(
+ "policy descriptor", DescriptorLen, len(data.KeyDescriptor))
}
descriptorBytes, err := hex.DecodeString(data.KeyDescriptor)
if err != nil {
- return util.InvalidInputF("policy descriptor of %s: %v", data.KeyDescriptor, err)
+ return util.InvalidInput(
+ fmt.Sprintf("policy descriptor of %s: %v", data.KeyDescriptor, err))
}
policy := unix.FscryptPolicy{
Version: 0, // Version must always be zero
- Contents_encryption_mode: uint8(data.Options.ContentsMode),
- Filenames_encryption_mode: uint8(data.Options.FilenamesMode),
+ Contents_encryption_mode: uint8(data.Options.Contents),
+ Filenames_encryption_mode: uint8(data.Options.Filenames),
Flags: uint8(paddingFlag),
}
copy(policy.Master_key_descriptor[:], descriptorBytes)
diff --git a/metadata/policy_test.go b/metadata/policy_test.go
index 593f3da..6dc2567 100644
--- a/metadata/policy_test.go
+++ b/metadata/policy_test.go
@@ -34,12 +34,13 @@ var goodPolicy = &PolicyData{
Options: DefaultOptions,
}
-// Creates a temporary directory in BASE_TEST_DIR for testing. Fails if the
-// base directory is not specified.
+// Creates a temporary directory in TEST_FILESYSTEM_ROOT for testing. Fails if
+// the root directory is not specified.
func createTestDirectory() (directory string, err error) {
- baseDirectory := os.Getenv("BASE_TEST_DIR")
+ baseDirectory := os.Getenv("TEST_FILESYSTEM_ROOT")
if s, err := os.Stat(baseDirectory); err != nil || !s.IsDir() {
- return "", fmt.Errorf("invalid directory %q. Set BASE_TEST_DIR to be a valid directory", baseDirectory)
+ return "", fmt.Errorf("invalid directory %q: "+
+ "set TEST_FILESYSTEM_ROOT to be a valid directory", baseDirectory)
}
directoryPath := filepath.Join(baseDirectory, "test")