aboutsummaryrefslogtreecommitdiff
path: root/metadata
diff options
context:
space:
mode:
authorEric Biggers <ebiggers@google.com>2019-12-15 19:31:39 -0800
committerEric Biggers <ebiggers@google.com>2020-01-05 10:02:13 -0800
commit2b25de6d445faefc28629603dd754aec9f744e60 (patch)
treec2e4dd53a2ed370be5b0699ede59538d508d347d /metadata
parentd0ac36dcea341ff000aca983dd80e7bef9fc30ec (diff)
Metadata support for v2 encryption policies
Linux v5.4 and later supports v2 encryption policies. These have several advantages over v1 encryption policies: - Their encryption keys can be added/removed to/from the filesystem by non-root users, thus gaining the benefits of the filesystem keyring while also retaining support for non-root use. - They use a more standard, secure, and flexible key derivation function. Because of this, some future kernel-level fscrypt features will be implemented for v2 policies only. - They prevent a denial-of-service attack where a user could associate the wrong key with another user's encrypted files. Prepare the fscrypt tool to support v2 encryption policies by: - Adding a policy_version field to the EncryptionOptions, i.e. to the config file and to the policy metadata files. - Using the kernel-specified algorithm to compute the key descriptor for v2 policies. - Handling setting and getting v2 policies. Actually adding/removing the keys for v2 policies to/from the kernel is left for the next patch.
Diffstat (limited to 'metadata')
-rw-r--r--metadata/checks.go35
-rw-r--r--metadata/config_test.go41
-rw-r--r--metadata/constants.go18
-rw-r--r--metadata/metadata.pb.go123
-rw-r--r--metadata/metadata.proto2
-rw-r--r--metadata/policy.go170
-rw-r--r--metadata/policy_test.go63
7 files changed, 329 insertions, 123 deletions
diff --git a/metadata/checks.go b/metadata/checks.go
index 4fe4531..84fd208 100644
--- a/metadata/checks.go
+++ b/metadata/checks.go
@@ -119,7 +119,7 @@ func (p *ProtectorData) CheckValidity() error {
if err := p.WrappedKey.CheckValidity(); err != nil {
return errors.Wrap(err, "wrapped protector key")
}
- if err := util.CheckValidLength(DescriptorLen, len(p.ProtectorDescriptor)); err != nil {
+ if err := util.CheckValidLength(ProtectorDescriptorLen, len(p.ProtectorDescriptor)); err != nil {
return errors.Wrap(err, "protector descriptor")
}
@@ -138,7 +138,17 @@ func (e *EncryptionOptions) CheckValidity() error {
if err := e.Contents.CheckValidity(); err != nil {
return errors.Wrap(err, "contents encryption mode")
}
- return errors.Wrap(e.Filenames.CheckValidity(), "filenames encryption mode")
+ if err := e.Filenames.CheckValidity(); err != nil {
+ return errors.Wrap(err, "filenames encryption mode")
+ }
+ // If PolicyVersion is unset, treat it as 1.
+ if e.PolicyVersion == 0 {
+ e.PolicyVersion = 1
+ }
+ if e.PolicyVersion != 1 && e.PolicyVersion != 2 {
+ return errors.Errorf("policy version of %d is invalid", e.PolicyVersion)
+ }
+ return nil
}
// CheckValidity ensures the fields are valid and have the correct lengths.
@@ -152,7 +162,7 @@ func (w *WrappedPolicyKey) CheckValidity() error {
if err := util.CheckValidLength(PolicyKeyLen, len(w.WrappedKey.EncryptedKey)); err != nil {
return errors.Wrap(err, "encrypted key")
}
- err := util.CheckValidLength(DescriptorLen, len(w.ProtectorDescriptor))
+ err := util.CheckValidLength(ProtectorDescriptorLen, len(w.ProtectorDescriptor))
return errors.Wrap(err, "wrapping protector descriptor")
}
@@ -167,11 +177,26 @@ func (p *PolicyData) CheckValidity() error {
return errors.Wrapf(err, "policy key slot %d", i)
}
}
- if err := util.CheckValidLength(DescriptorLen, len(p.KeyDescriptor)); err != nil {
+
+ if err := p.Options.CheckValidity(); err != nil {
+ return errors.Wrap(err, "policy options")
+ }
+
+ var expectedLen int
+ switch p.Options.PolicyVersion {
+ case 1:
+ expectedLen = PolicyDescriptorLenV1
+ case 2:
+ expectedLen = PolicyDescriptorLenV2
+ default:
+ return errors.Errorf("policy version of %d is invalid", p.Options.PolicyVersion)
+ }
+
+ if err := util.CheckValidLength(expectedLen, len(p.KeyDescriptor)); err != nil {
return errors.Wrap(err, "policy key descriptor")
}
- return errors.Wrap(p.Options.CheckValidity(), "policy options")
+ return nil
}
// CheckValidity ensures the Config has all the necessary info for its Source.
diff --git a/metadata/config_test.go b/metadata/config_test.go
index 3c20c51..83c1eb0 100644
--- a/metadata/config_test.go
+++ b/metadata/config_test.go
@@ -48,7 +48,8 @@ var testConfigString = `{
"options": {
"padding": "32",
"contents": "AES_256_XTS",
- "filenames": "AES_256_CTS"
+ "filenames": "AES_256_CTS",
+ "policy_version": "1"
},
"use_fs_keyring_for_v1_policies": false
}
@@ -78,3 +79,41 @@ func TestRead(t *testing.T) {
t.Errorf("did not match: %s", testConfig)
}
}
+
+// Makes sure we can parse a legacy config file that doesn't have the fields
+// that were added later.
+func TestOptionalFields(t *testing.T) {
+ contents := `{
+ "source": "custom_passphrase",
+ "hash_costs": {
+ "time": "10",
+ "memory": "4096",
+ "parallelism": "8"
+ },
+ "compatibility": "",
+ "options": {
+ "padding": "32",
+ "contents": "AES_256_XTS",
+ "filenames": "AES_256_CTS"
+ }
+ }
+ `
+ buf := bytes.NewBufferString(contents)
+ cfg, err := ReadConfig(buf)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if cfg.GetUseFsKeyringForV1Policies() {
+ t.Error("use_fs_keyring_for_v1_policies should be false, but was true")
+ }
+ if cfg.Options.PolicyVersion != 0 {
+ t.Errorf("policy version should be 0, but was %d", cfg.Options.PolicyVersion)
+ }
+ if err = cfg.CheckValidity(); err != nil {
+ t.Error(err)
+ }
+ // CheckValidity() should change an unset policy version to 1.
+ if cfg.Options.PolicyVersion != 1 {
+ t.Errorf("policy version should be 1 now, but was %d", cfg.Options.PolicyVersion)
+ }
+}
diff --git a/metadata/constants.go b/metadata/constants.go
index 8855ae3..fa6b8a7 100644
--- a/metadata/constants.go
+++ b/metadata/constants.go
@@ -27,8 +27,12 @@ import (
// Lengths for our keys, buffers, and strings used in fscrypt.
const (
- // DescriptorLen is the length of all Protector and Policy descriptors.
- DescriptorLen = 2 * unix.FSCRYPT_KEY_DESCRIPTOR_SIZE
+ // Length of policy descriptor (in hex chars) for v1 encryption policies
+ PolicyDescriptorLenV1 = 2 * unix.FSCRYPT_KEY_DESCRIPTOR_SIZE
+ // Length of protector descriptor (in hex chars)
+ ProtectorDescriptorLen = PolicyDescriptorLenV1
+ // Length of policy descriptor (in hex chars) for v2 encryption policies
+ PolicyDescriptorLenV2 = 2 * unix.FSCRYPT_KEY_IDENTIFIER_SIZE
// We always use 256-bit keys internally (compared to 512-bit policy keys).
InternalKeyLen = 32
IVLen = 16
@@ -40,11 +44,13 @@ const (
)
var (
- // DefaultOptions use the supported encryption modes and max padding.
+ // DefaultOptions use the supported encryption modes, max padding, and
+ // policy version 1.
DefaultOptions = &EncryptionOptions{
- Padding: 32,
- Contents: EncryptionOptions_AES_256_XTS,
- Filenames: EncryptionOptions_AES_256_CTS,
+ Padding: 32,
+ Contents: EncryptionOptions_AES_256_XTS,
+ Filenames: EncryptionOptions_AES_256_CTS,
+ PolicyVersion: 1,
}
// 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 aa4eeff..e6067f9 100644
--- a/metadata/metadata.pb.go
+++ b/metadata/metadata.pb.go
@@ -45,7 +45,7 @@ func (x SourceType) String() string {
return proto.EnumName(SourceType_name, int32(x))
}
func (SourceType) EnumDescriptor() ([]byte, []int) {
- return fileDescriptor_metadata_ff272c42a9f0f3d3, []int{0}
+ return fileDescriptor_metadata_0a34c99c54153da9, []int{0}
}
// Type of encryption; should match declarations of unix.FSCRYPT_MODE
@@ -87,7 +87,7 @@ func (x EncryptionOptions_Mode) String() string {
return proto.EnumName(EncryptionOptions_Mode_name, int32(x))
}
func (EncryptionOptions_Mode) EnumDescriptor() ([]byte, []int) {
- return fileDescriptor_metadata_ff272c42a9f0f3d3, []int{3, 0}
+ return fileDescriptor_metadata_0a34c99c54153da9, []int{3, 0}
}
// Cost parameters to be used in our hashing functions.
@@ -104,7 +104,7 @@ func (m *HashingCosts) Reset() { *m = HashingCosts{} }
func (m *HashingCosts) String() string { return proto.CompactTextString(m) }
func (*HashingCosts) ProtoMessage() {}
func (*HashingCosts) Descriptor() ([]byte, []int) {
- return fileDescriptor_metadata_ff272c42a9f0f3d3, []int{0}
+ return fileDescriptor_metadata_0a34c99c54153da9, []int{0}
}
func (m *HashingCosts) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_HashingCosts.Unmarshal(m, b)
@@ -159,7 +159,7 @@ func (m *WrappedKeyData) Reset() { *m = WrappedKeyData{} }
func (m *WrappedKeyData) String() string { return proto.CompactTextString(m) }
func (*WrappedKeyData) ProtoMessage() {}
func (*WrappedKeyData) Descriptor() ([]byte, []int) {
- return fileDescriptor_metadata_ff272c42a9f0f3d3, []int{1}
+ return fileDescriptor_metadata_0a34c99c54153da9, []int{1}
}
func (m *WrappedKeyData) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_WrappedKeyData.Unmarshal(m, b)
@@ -219,7 +219,7 @@ func (m *ProtectorData) Reset() { *m = ProtectorData{} }
func (m *ProtectorData) String() string { return proto.CompactTextString(m) }
func (*ProtectorData) ProtoMessage() {}
func (*ProtectorData) Descriptor() ([]byte, []int) {
- return fileDescriptor_metadata_ff272c42a9f0f3d3, []int{2}
+ return fileDescriptor_metadata_0a34c99c54153da9, []int{2}
}
func (m *ProtectorData) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_ProtectorData.Unmarshal(m, b)
@@ -293,6 +293,7 @@ type EncryptionOptions struct {
Padding int64 `protobuf:"varint,1,opt,name=padding,proto3" json:"padding,omitempty"`
Contents EncryptionOptions_Mode `protobuf:"varint,2,opt,name=contents,proto3,enum=metadata.EncryptionOptions_Mode" json:"contents,omitempty"`
Filenames EncryptionOptions_Mode `protobuf:"varint,3,opt,name=filenames,proto3,enum=metadata.EncryptionOptions_Mode" json:"filenames,omitempty"`
+ PolicyVersion int64 `protobuf:"varint,4,opt,name=policy_version,json=policyVersion,proto3" json:"policy_version,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@@ -302,7 +303,7 @@ func (m *EncryptionOptions) Reset() { *m = EncryptionOptions{} }
func (m *EncryptionOptions) String() string { return proto.CompactTextString(m) }
func (*EncryptionOptions) ProtoMessage() {}
func (*EncryptionOptions) Descriptor() ([]byte, []int) {
- return fileDescriptor_metadata_ff272c42a9f0f3d3, []int{3}
+ return fileDescriptor_metadata_0a34c99c54153da9, []int{3}
}
func (m *EncryptionOptions) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_EncryptionOptions.Unmarshal(m, b)
@@ -343,6 +344,13 @@ func (m *EncryptionOptions) GetFilenames() EncryptionOptions_Mode {
return EncryptionOptions_default
}
+func (m *EncryptionOptions) GetPolicyVersion() int64 {
+ if m != nil {
+ return m.PolicyVersion
+ }
+ return 0
+}
+
type WrappedPolicyKey struct {
ProtectorDescriptor string `protobuf:"bytes,1,opt,name=protector_descriptor,json=protectorDescriptor,proto3" json:"protector_descriptor,omitempty"`
WrappedKey *WrappedKeyData `protobuf:"bytes,2,opt,name=wrapped_key,json=wrappedKey,proto3" json:"wrapped_key,omitempty"`
@@ -355,7 +363,7 @@ func (m *WrappedPolicyKey) Reset() { *m = WrappedPolicyKey{} }
func (m *WrappedPolicyKey) String() string { return proto.CompactTextString(m) }
func (*WrappedPolicyKey) ProtoMessage() {}
func (*WrappedPolicyKey) Descriptor() ([]byte, []int) {
- return fileDescriptor_metadata_ff272c42a9f0f3d3, []int{4}
+ return fileDescriptor_metadata_0a34c99c54153da9, []int{4}
}
func (m *WrappedPolicyKey) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_WrappedPolicyKey.Unmarshal(m, b)
@@ -403,7 +411,7 @@ func (m *PolicyData) Reset() { *m = PolicyData{} }
func (m *PolicyData) String() string { return proto.CompactTextString(m) }
func (*PolicyData) ProtoMessage() {}
func (*PolicyData) Descriptor() ([]byte, []int) {
- return fileDescriptor_metadata_ff272c42a9f0f3d3, []int{5}
+ return fileDescriptor_metadata_0a34c99c54153da9, []int{5}
}
func (m *PolicyData) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PolicyData.Unmarshal(m, b)
@@ -460,7 +468,7 @@ func (m *Config) Reset() { *m = Config{} }
func (m *Config) String() string { return proto.CompactTextString(m) }
func (*Config) ProtoMessage() {}
func (*Config) Descriptor() ([]byte, []int) {
- return fileDescriptor_metadata_ff272c42a9f0f3d3, []int{6}
+ return fileDescriptor_metadata_0a34c99c54153da9, []int{6}
}
func (m *Config) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Config.Unmarshal(m, b)
@@ -527,52 +535,53 @@ func init() {
proto.RegisterEnum("metadata.EncryptionOptions_Mode", EncryptionOptions_Mode_name, EncryptionOptions_Mode_value)
}
-func init() { proto.RegisterFile("metadata/metadata.proto", fileDescriptor_metadata_ff272c42a9f0f3d3) }
-
-var fileDescriptor_metadata_ff272c42a9f0f3d3 = []byte{
- // 693 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0xdf, 0x6b, 0x13, 0x41,
- 0x10, 0xc7, 0xbd, 0x4b, 0x9a, 0x1f, 0x93, 0x1f, 0x5e, 0xb7, 0xb5, 0x9e, 0x0a, 0x12, 0xa2, 0x42,
- 0x91, 0x52, 0x49, 0xa4, 0xa2, 0x20, 0x42, 0x4d, 0x5b, 0xad, 0xa5, 0x58, 0x2f, 0xa1, 0x2a, 0x08,
- 0xc7, 0xf6, 0x6e, 0x93, 0x2c, 0xbd, 0xbb, 0x5d, 0x76, 0x37, 0x86, 0x7b, 0xf3, 0xcd, 0x27, 0x9f,
- 0xfc, 0x5b, 0xf4, 0xef, 0x93, 0xdd, 0xcb, 0xcf, 0x16, 0x4a, 0xeb, 0xcb, 0x31, 0xfb, 0xdd, 0xd9,
- 0x99, 0xd9, 0xcf, 0xce, 0x1c, 0xdc, 0x8d, 0x89, 0xc2, 0x21, 0x56, 0xf8, 0xd9, 0xd4, 0xd8, 0xe6,
- 0x82, 0x29, 0x86, 0x4a, 0xd3, 0x75, 0xf3, 0x1b, 0x54, 0xdf, 0x63, 0x39, 0xa4, 0xc9, 0xa0, 0xc3,
- 0xa4, 0x92, 0x08, 0x41, 0x5e, 0xd1, 0x98, 0xb8, 0x76, 0xc3, 0xda, 0xcc, 0x79, 0xc6, 0x46, 0x1b,
- 0x50, 0x88, 0x49, 0xcc, 0x44, 0xea, 0xe6, 0x8c, 0x3a, 0x59, 0xa1, 0x06, 0x54, 0x38, 0x16, 0x38,
- 0x8a, 0x48, 0x44, 0x65, 0xec, 0xe6, 0xcd, 0xe6, 0xa2, 0xd4, 0xfc, 0x0a, 0xf5, 0xcf, 0x02, 0x73,
- 0x4e, 0xc2, 0x23, 0x92, 0xee, 0x61, 0x85, 0x51, 0x1d, 0xec, 0xc3, 0x53, 0xd7, 0x6a, 0x58, 0x9b,
- 0x55, 0xcf, 0x3e, 0x3c, 0x45, 0x8f, 0xa0, 0x46, 0x92, 0x40, 0xa4, 0x5c, 0x91, 0xd0, 0x3f, 0x27,
- 0xa9, 0x49, 0x5c, 0xf5, 0xaa, 0x33, 0xf1, 0x88, 0xa4, 0xba, 0xa8, 0x61, 0x8c, 0x03, 0x93, 0xbe,
- 0xea, 0x19, 0xbb, 0xf9, 0xdb, 0x86, 0xda, 0x89, 0x60, 0x8a, 0x04, 0x8a, 0x09, 0x13, 0xba, 0x05,
- 0xeb, 0x7c, 0x2a, 0xf8, 0x21, 0x91, 0x81, 0xa0, 0x5c, 0x31, 0x61, 0x92, 0x95, 0xbd, 0xb5, 0xd9,
- 0xde, 0xde, 0x6c, 0x0b, 0x6d, 0x41, 0x41, 0xb2, 0x91, 0x08, 0xb2, 0xfb, 0xd6, 0xdb, 0xeb, 0xdb,
- 0x33, 0x50, 0x5d, 0xa3, 0xf7, 0x52, 0x4e, 0xbc, 0x89, 0x8f, 0x2e, 0x23, 0xc1, 0x31, 0x31, 0x65,
- 0x94, 0x3d, 0x63, 0xa3, 0x2d, 0x58, 0x09, 0x34, 0x38, 0x73, 0xfb, 0x4a, 0x7b, 0x63, 0x1e, 0x60,
- 0x11, 0xab, 0x97, 0x39, 0xe9, 0x08, 0x12, 0x47, 0xca, 0x5d, 0xc9, 0x2e, 0xa2, 0x6d, 0xe4, 0x40,
- 0x6e, 0x44, 0x43, 0xb7, 0x60, 0xe8, 0x69, 0x13, 0xbd, 0x82, 0xca, 0x38, 0xa3, 0x66, 0x88, 0x14,
- 0x4d, 0x64, 0x77, 0x1e, 0x79, 0x19, 0xa9, 0x07, 0xe3, 0xd9, 0xba, 0xf9, 0xc7, 0x86, 0xd5, 0xfd,
- 0x0c, 0x1d, 0x65, 0xc9, 0x47, 0xf3, 0x95, 0xc8, 0x85, 0x22, 0xc7, 0x61, 0x48, 0x93, 0x81, 0x81,
- 0x91, 0xf3, 0xa6, 0x4b, 0xf4, 0x1a, 0x4a, 0x01, 0x4b, 0x14, 0x49, 0x94, 0x9c, 0x20, 0x68, 0xcc,
- 0xf3, 0x5c, 0x0a, 0xb4, 0x7d, 0xcc, 0x42, 0xe2, 0xcd, 0x4e, 0xa0, 0x37, 0x50, 0xee, 0xd3, 0x88,
- 0x68, 0x10, 0xd2, 0x50, 0xb9, 0xce, 0xf1, 0xf9, 0x91, 0xe6, 0x4f, 0x0b, 0xf2, 0x5a, 0x43, 0x15,
- 0x28, 0x86, 0xa4, 0x8f, 0x47, 0x91, 0x72, 0x6e, 0xa1, 0xdb, 0x50, 0xd9, 0xdd, 0xef, 0xfa, 0xed,
- 0x9d, 0x17, 0xfe, 0x97, 0x5e, 0xd7, 0xb1, 0x16, 0x85, 0x77, 0x9d, 0x63, 0xc7, 0x5e, 0x14, 0x3a,
- 0x6f, 0x3b, 0x4e, 0x6e, 0x49, 0xe8, 0x75, 0x9d, 0xfc, 0x54, 0x68, 0xb5, 0x5f, 0x1a, 0x8f, 0x95,
- 0x25, 0xa1, 0xd7, 0x75, 0x0a, 0xa8, 0x0a, 0xa5, 0xdd, 0x90, 0xe2, 0x44, 0x8d, 0x62, 0xa7, 0xdc,
- 0xfc, 0x61, 0x81, 0x33, 0xc1, 0x7a, 0xc2, 0x22, 0x1a, 0xa4, 0xba, 0xed, 0xfe, 0xa3, 0xa1, 0x2e,
- 0x3c, 0x9d, 0x7d, 0x83, 0xa7, 0xfb, 0x6b, 0x01, 0x64, 0xb9, 0x4d, 0x37, 0x3f, 0x81, 0xfa, 0x39,
- 0x49, 0x2f, 0xa7, 0xad, 0x9d, 0x93, 0x74, 0x21, 0xe1, 0x0e, 0x14, 0x59, 0x46, 0x77, 0x92, 0xec,
- 0xc1, 0x15, 0x0f, 0xe0, 0x4d, 0x7d, 0xd1, 0x07, 0x58, 0x9b, 0xd6, 0xc9, 0x4d, 0x4e, 0x5d, 0xae,
- 0x7e, 0xc3, 0xdc, 0x66, 0xa5, 0x7d, 0xff, 0x52, 0xbd, 0x33, 0x26, 0xde, 0xea, 0xf8, 0x82, 0x22,
- 0x9b, 0xbf, 0x6c, 0x28, 0x74, 0x58, 0xd2, 0xa7, 0x83, 0x85, 0x79, 0xb2, 0xae, 0x31, 0x4f, 0x3b,
- 0x00, 0x43, 0x2c, 0x87, 0x7e, 0x36, 0x40, 0xf6, 0x95, 0x03, 0x54, 0xd6, 0x9e, 0xd9, 0x2f, 0xea,
- 0x31, 0xd4, 0x02, 0x16, 0x73, 0xac, 0xe8, 0x19, 0x8d, 0xa8, 0x4a, 0x27, 0xf3, 0xb8, 0x2c, 0x2e,
- 0x82, 0xc9, 0xdf, 0x00, 0xcc, 0x2e, 0x3c, 0x1c, 0x49, 0xe2, 0xf7, 0xa5, 0x06, 0x22, 0x68, 0x32,
- 0xf0, 0xfb, 0x4c, 0xf8, 0xdf, 0x5b, 0x19, 0x26, 0x4a, 0xa4, 0x99, 0xdd, 0x92, 0x77, 0x6f, 0x24,
- 0xc9, 0x81, 0x3c, 0xca, 0x7c, 0x0e, 0x98, 0x38, 0x6d, 0x9d, 0x4c, 0x1c, 0x9e, 0x7e, 0x02, 0x98,
- 0x5f, 0x76, 0xb9, 0xb5, 0x11, 0xd4, 0x39, 0x8e, 0x7d, 0x8e, 0xa5, 0xe4, 0x43, 0x81, 0x25, 0x71,
- 0x2c, 0x74, 0x07, 0x56, 0x83, 0x91, 0x54, 0x6c, 0x49, 0xb6, 0xf5, 0x39, 0x81, 0xc7, 0xba, 0x0a,
- 0x27, 0x77, 0x56, 0x30, 0xbf, 0xed, 0xe7, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0xd3, 0x31, 0x82,
- 0x34, 0xd1, 0x05, 0x00, 0x00,
+func init() { proto.RegisterFile("metadata/metadata.proto", fileDescriptor_metadata_0a34c99c54153da9) }
+
+var fileDescriptor_metadata_0a34c99c54153da9 = []byte{
+ // 717 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0x5d, 0x6b, 0x13, 0x4d,
+ 0x14, 0xc7, 0x9f, 0xdd, 0xa4, 0x79, 0x39, 0x79, 0x79, 0xb6, 0xd3, 0x3e, 0x7d, 0x56, 0x05, 0x09,
+ 0xd1, 0x42, 0x91, 0x52, 0x49, 0xa4, 0xa2, 0x20, 0x42, 0x4d, 0x5b, 0xad, 0xa5, 0x58, 0x37, 0x21,
+ 0x2a, 0x08, 0xcb, 0x74, 0x77, 0x92, 0x0c, 0xd9, 0xdd, 0x59, 0x66, 0x26, 0x0d, 0x7b, 0xe7, 0x9d,
+ 0x57, 0x5e, 0xf9, 0x5d, 0xfc, 0x34, 0x7e, 0x18, 0x99, 0xd9, 0xcd, 0x5b, 0x0b, 0xa5, 0xf5, 0x66,
+ 0x39, 0xf3, 0x9f, 0x33, 0xe7, 0x9c, 0xf9, 0x9d, 0x39, 0x0b, 0xff, 0x87, 0x44, 0x62, 0x1f, 0x4b,
+ 0xfc, 0x74, 0x66, 0xec, 0xc5, 0x9c, 0x49, 0x86, 0x4a, 0xb3, 0x75, 0xf3, 0x2b, 0x54, 0xdf, 0x61,
+ 0x31, 0xa2, 0xd1, 0xb0, 0xc3, 0x84, 0x14, 0x08, 0x41, 0x5e, 0xd2, 0x90, 0xd8, 0x66, 0xc3, 0xd8,
+ 0xc9, 0x39, 0xda, 0x46, 0x5b, 0x50, 0x08, 0x49, 0xc8, 0x78, 0x62, 0xe7, 0xb4, 0x9a, 0xad, 0x50,
+ 0x03, 0x2a, 0x31, 0xe6, 0x38, 0x08, 0x48, 0x40, 0x45, 0x68, 0xe7, 0xf5, 0xe6, 0xb2, 0xd4, 0xfc,
+ 0x02, 0xf5, 0x4f, 0x1c, 0xc7, 0x31, 0xf1, 0x4f, 0x49, 0x72, 0x88, 0x25, 0x46, 0x75, 0x30, 0x4f,
+ 0xfa, 0xb6, 0xd1, 0x30, 0x76, 0xaa, 0x8e, 0x79, 0xd2, 0x47, 0x8f, 0xa0, 0x46, 0x22, 0x8f, 0x27,
+ 0xb1, 0x24, 0xbe, 0x3b, 0x26, 0x89, 0x4e, 0x5c, 0x75, 0xaa, 0x73, 0xf1, 0x94, 0x24, 0xaa, 0xa8,
+ 0x51, 0x88, 0x3d, 0x9d, 0xbe, 0xea, 0x68, 0xbb, 0xf9, 0xd3, 0x84, 0xda, 0x39, 0x67, 0x92, 0x78,
+ 0x92, 0x71, 0x1d, 0xba, 0x05, 0x9b, 0xf1, 0x4c, 0x70, 0x7d, 0x22, 0x3c, 0x4e, 0x63, 0xc9, 0xb8,
+ 0x4e, 0x56, 0x76, 0x36, 0xe6, 0x7b, 0x87, 0xf3, 0x2d, 0xb4, 0x0b, 0x05, 0xc1, 0x26, 0xdc, 0x4b,
+ 0xef, 0x5b, 0x6f, 0x6f, 0xee, 0xcd, 0x41, 0x75, 0xb5, 0xde, 0x4b, 0x62, 0xe2, 0x64, 0x3e, 0xaa,
+ 0x8c, 0x08, 0x87, 0x44, 0x97, 0x51, 0x76, 0xb4, 0x8d, 0x76, 0x61, 0xcd, 0x53, 0xe0, 0xf4, 0xed,
+ 0x2b, 0xed, 0xad, 0x45, 0x80, 0x65, 0xac, 0x4e, 0xea, 0xa4, 0x22, 0x08, 0x1c, 0x48, 0x7b, 0x2d,
+ 0xbd, 0x88, 0xb2, 0x91, 0x05, 0xb9, 0x09, 0xf5, 0xed, 0x82, 0xa6, 0xa7, 0x4c, 0xf4, 0x12, 0x2a,
+ 0xd3, 0x94, 0x9a, 0x26, 0x52, 0xd4, 0x91, 0xed, 0x45, 0xe4, 0x55, 0xa4, 0x0e, 0x4c, 0xe7, 0xeb,
+ 0xe6, 0x6f, 0x13, 0xd6, 0x8f, 0x52, 0x74, 0x94, 0x45, 0x1f, 0xf4, 0x57, 0x20, 0x1b, 0x8a, 0x31,
+ 0xf6, 0x7d, 0x1a, 0x0d, 0x35, 0x8c, 0x9c, 0x33, 0x5b, 0xa2, 0x57, 0x50, 0xf2, 0x58, 0x24, 0x49,
+ 0x24, 0x45, 0x86, 0xa0, 0xb1, 0xc8, 0x73, 0x2d, 0xd0, 0xde, 0x19, 0xf3, 0x89, 0x33, 0x3f, 0x81,
+ 0x5e, 0x43, 0x79, 0x40, 0x03, 0xa2, 0x40, 0x08, 0x4d, 0xe5, 0x36, 0xc7, 0x17, 0x47, 0xd0, 0x36,
+ 0xd4, 0x63, 0x16, 0x50, 0x2f, 0x71, 0x2f, 0x09, 0x17, 0x94, 0x45, 0xd9, 0x1b, 0xaa, 0xa5, 0x6a,
+ 0x3f, 0x15, 0x9b, 0xdf, 0x0d, 0xc8, 0xab, 0xa3, 0xa8, 0x02, 0x45, 0x9f, 0x0c, 0xf0, 0x24, 0x90,
+ 0xd6, 0x3f, 0xe8, 0x5f, 0xa8, 0x1c, 0x1c, 0x75, 0xdd, 0xf6, 0xfe, 0x73, 0xf7, 0x73, 0xaf, 0x6b,
+ 0x19, 0xcb, 0xc2, 0xdb, 0xce, 0x99, 0x65, 0x2e, 0x0b, 0x9d, 0x37, 0x1d, 0x2b, 0xb7, 0x22, 0xf4,
+ 0xba, 0x56, 0x7e, 0x26, 0xb4, 0xda, 0x2f, 0xb4, 0xc7, 0xda, 0x8a, 0xd0, 0xeb, 0x5a, 0x05, 0x54,
+ 0x85, 0xd2, 0x81, 0x4f, 0x71, 0x24, 0x27, 0xa1, 0x55, 0x6e, 0x7e, 0x33, 0xc0, 0xca, 0xe8, 0x9f,
+ 0xeb, 0x12, 0xd5, 0xeb, 0xfc, 0x8b, 0x77, 0x77, 0xa5, 0xc3, 0xe6, 0x1d, 0x3a, 0xfc, 0xcb, 0x00,
+ 0x48, 0x73, 0xeb, 0x47, 0xbf, 0x0d, 0xf5, 0x31, 0x49, 0xae, 0xa7, 0xad, 0x8d, 0x49, 0xb2, 0x94,
+ 0x70, 0x1f, 0x8a, 0x2c, 0x6d, 0x42, 0x96, 0xec, 0xc1, 0x0d, 0x7d, 0x72, 0x66, 0xbe, 0xe8, 0x3d,
+ 0x6c, 0xcc, 0xea, 0xcc, 0x1a, 0x35, 0x26, 0x89, 0x6a, 0x75, 0x6e, 0xa7, 0xd2, 0xbe, 0x7f, 0xad,
+ 0xde, 0x39, 0x13, 0x67, 0x7d, 0x7a, 0x45, 0x11, 0xcd, 0x1f, 0x26, 0x14, 0x3a, 0x2c, 0x1a, 0xd0,
+ 0xe1, 0xd2, 0xd8, 0x19, 0xb7, 0x18, 0xbb, 0x7d, 0x80, 0x11, 0x16, 0x23, 0x37, 0x9d, 0x33, 0xf3,
+ 0xc6, 0x39, 0x2b, 0x2b, 0xcf, 0xf4, 0x4f, 0xf6, 0x18, 0x6a, 0x1e, 0x0b, 0x63, 0x2c, 0xe9, 0x05,
+ 0x0d, 0xa8, 0x4c, 0xb2, 0xb1, 0x5d, 0x15, 0x97, 0xc1, 0xe4, 0xef, 0x00, 0xe6, 0x00, 0x1e, 0x4e,
+ 0x04, 0x71, 0x07, 0x42, 0x01, 0xe1, 0x34, 0x1a, 0xba, 0x03, 0xc6, 0xdd, 0xcb, 0x56, 0x8a, 0x89,
+ 0x12, 0xa1, 0x47, 0xbc, 0xe4, 0xdc, 0x9b, 0x08, 0x72, 0x2c, 0x4e, 0x53, 0x9f, 0x63, 0xc6, 0xfb,
+ 0xad, 0xf3, 0xcc, 0xe1, 0xc9, 0x47, 0x80, 0xc5, 0x65, 0x57, 0x9f, 0x36, 0x82, 0x7a, 0x8c, 0x43,
+ 0x37, 0xc6, 0x42, 0xc4, 0x23, 0x8e, 0x05, 0xb1, 0x0c, 0xf4, 0x1f, 0xac, 0x7b, 0x13, 0x21, 0xd9,
+ 0x8a, 0x6c, 0xaa, 0x73, 0x1c, 0x4f, 0x55, 0x15, 0x56, 0xee, 0xa2, 0xa0, 0xff, 0xee, 0xcf, 0xfe,
+ 0x04, 0x00, 0x00, 0xff, 0xff, 0xfc, 0x97, 0x5e, 0xdf, 0xf8, 0x05, 0x00, 0x00,
}
diff --git a/metadata/metadata.proto b/metadata/metadata.proto
index e682212..81b3bf9 100644
--- a/metadata/metadata.proto
+++ b/metadata/metadata.proto
@@ -77,6 +77,8 @@ message EncryptionOptions {
Mode contents = 2;
Mode filenames = 3;
+
+ int64 policy_version = 4;
}
message WrappedPolicyKey {
diff --git a/metadata/policy.go b/metadata/policy.go
index f9af44a..b95bf42 100644
--- a/metadata/policy.go
+++ b/metadata/policy.go
@@ -42,14 +42,14 @@ var (
ErrBadEncryptionOptions = util.SystemError("invalid encryption options provided")
)
-// policyIoctl is a wrapper for the ioctl syscall. It passes the correct
-// pointers and file descriptors to the IOCTL syscall. This function also takes
-// some of the unclear errors returned by the syscall and translates then into
-// more specific error strings.
-func policyIoctl(file *os.File, request uintptr, policy *unix.FscryptPolicyV1) error {
+// policyIoctl is a wrapper around the ioctls that get and set encryption
+// policies: FS_IOC_GET_ENCRYPTION_POLICY, FS_IOC_GET_ENCRYPTION_POLICY_EX, and
+// FS_IOC_SET_ENCRYPTION_POLICY. It translates the raw errno values into more
+// descriptive errors.
+func policyIoctl(file *os.File, request uintptr, arg unsafe.Pointer) error {
// The returned errno value can sometimes give strange errors, so we
// return encryption specific errors.
- _, _, errno := unix.Syscall(unix.SYS_IOCTL, file.Fd(), request, uintptr(unsafe.Pointer(policy)))
+ _, _, errno := unix.Syscall(unix.SYS_IOCTL, file.Fd(), request, uintptr(arg))
switch errno {
case 0:
return nil
@@ -61,7 +61,6 @@ func policyIoctl(file *os.File, request uintptr, policy *unix.FscryptPolicyV1) e
// ENOENT was returned instead of ENODATA on some filesystems before v4.11.
return ErrNotEncrypted
case unix.EEXIST:
- // EINVAL was returned instead of EEXIST on some filesystems before v4.11.
return ErrEncrypted
default:
return errno
@@ -75,6 +74,42 @@ var (
unix.FSCRYPT_POLICY_FLAGS_PAD_16, unix.FSCRYPT_POLICY_FLAGS_PAD_32}
)
+// flagsToPadding returns the amount of padding specified in the policy flags.
+func flagsToPadding(flags uint8) int64 {
+ paddingFlag := int64(flags & unix.FS_POLICY_FLAGS_PAD_MASK)
+
+ // This lookup should always succeed
+ padding, ok := util.Lookup(paddingFlag, flagsArray, paddingArray)
+ if !ok {
+ log.Panicf("padding flag of %x not found", paddingFlag)
+ }
+ return padding
+}
+
+func buildV1PolicyData(policy *unix.FscryptPolicyV1) *PolicyData {
+ return &PolicyData{
+ KeyDescriptor: hex.EncodeToString(policy.Master_key_descriptor[:]),
+ Options: &EncryptionOptions{
+ Padding: flagsToPadding(policy.Flags),
+ Contents: EncryptionOptions_Mode(policy.Contents_encryption_mode),
+ Filenames: EncryptionOptions_Mode(policy.Filenames_encryption_mode),
+ PolicyVersion: 1,
+ },
+ }
+}
+
+func buildV2PolicyData(policy *unix.FscryptPolicyV2) *PolicyData {
+ return &PolicyData{
+ KeyDescriptor: hex.EncodeToString(policy.Master_key_identifier[:]),
+ Options: &EncryptionOptions{
+ Padding: flagsToPadding(policy.Flags),
+ Contents: EncryptionOptions_Mode(policy.Contents_encryption_mode),
+ Filenames: EncryptionOptions_Mode(policy.Filenames_encryption_mode),
+ PolicyVersion: 2,
+ },
+ }
+}
+
// GetPolicy returns the Policy data for the given directory or file (includes
// the KeyDescriptor and the encryption options). Returns an error if the
// path is not encrypted or the policy couldn't be retrieved.
@@ -85,28 +120,36 @@ func GetPolicy(path string) (*PolicyData, error) {
}
defer file.Close()
- var policy unix.FscryptPolicyV1
- if err = policyIoctl(file, unix.FS_IOC_GET_ENCRYPTION_POLICY, &policy); err != nil {
+ // First try the new version of the ioctl. This works for both v1 and v2 policies.
+ var arg unix.FscryptGetPolicyExArg
+ arg.Size = uint64(unsafe.Sizeof(arg.Policy))
+ policyPtr := util.Ptr(arg.Policy[:])
+ err = policyIoctl(file, unix.FS_IOC_GET_ENCRYPTION_POLICY_EX, unsafe.Pointer(&arg))
+ if err == ErrEncryptionNotSupported {
+ // Fall back to the old version of the ioctl. This works for v1 policies only.
+ err = policyIoctl(file, unix.FS_IOC_GET_ENCRYPTION_POLICY, policyPtr)
+ arg.Size = uint64(unsafe.Sizeof(unix.FscryptPolicyV1{}))
+ }
+ if err != nil {
return nil, errors.Wrapf(err, "get encryption policy %s", path)
}
-
- // Convert the padding flag into an amount of padding
- paddingFlag := int64(policy.Flags & unix.FSCRYPT_POLICY_FLAGS_PAD_MASK)
-
- // This lookup should always succeed
- padding, ok := util.Lookup(paddingFlag, flagsArray, paddingArray)
- if !ok {
- log.Panicf("padding flag of %x not found", paddingFlag)
+ switch arg.Policy[0] { // arg.policy.version
+ case unix.FSCRYPT_POLICY_V1:
+ if arg.Size != uint64(unsafe.Sizeof(unix.FscryptPolicyV1{})) {
+ // should never happen
+ return nil, errors.New("unexpected size for v1 policy")
+ }
+ return buildV1PolicyData((*unix.FscryptPolicyV1)(policyPtr)), nil
+ case unix.FSCRYPT_POLICY_V2:
+ if arg.Size != uint64(unsafe.Sizeof(unix.FscryptPolicyV2{})) {
+ // should never happen
+ return nil, errors.New("unexpected size for v2 policy")
+ }
+ return buildV2PolicyData((*unix.FscryptPolicyV2)(policyPtr)), nil
+ default:
+ return nil, errors.Errorf("unsupported encryption policy version [%d]",
+ arg.Policy[0])
}
-
- return &PolicyData{
- KeyDescriptor: hex.EncodeToString(policy.Master_key_descriptor[:]),
- Options: &EncryptionOptions{
- Padding: padding,
- Contents: EncryptionOptions_Mode(policy.Contents_encryption_mode),
- Filenames: EncryptionOptions_Mode(policy.Filenames_encryption_mode),
- },
- }, nil
}
// For improved performance, use the DIRECT_KEY flag when using ciphers that
@@ -121,6 +164,52 @@ func shouldUseDirectKeyFlag(options *EncryptionOptions) bool {
return options.Contents == EncryptionOptions_Adiantum
}
+func buildPolicyFlags(options *EncryptionOptions) uint8 {
+ // This lookup should always succeed (as policy is valid)
+ flags, ok := util.Lookup(options.Padding, paddingArray, flagsArray)
+ if !ok {
+ log.Panicf("padding of %d was not found", options.Padding)
+ }
+ if shouldUseDirectKeyFlag(options) {
+ flags |= unix.FSCRYPT_POLICY_FLAG_DIRECT_KEY
+ }
+ return uint8(flags)
+}
+
+func setV1Policy(file *os.File, options *EncryptionOptions, descriptorBytes []byte) error {
+ policy := unix.FscryptPolicyV1{
+ Version: unix.FSCRYPT_POLICY_V1,
+ Contents_encryption_mode: uint8(options.Contents),
+ Filenames_encryption_mode: uint8(options.Filenames),
+ Flags: uint8(buildPolicyFlags(options)),
+ }
+
+ // The descriptor should always be the correct length (as policy is valid)
+ if len(descriptorBytes) != unix.FSCRYPT_KEY_DESCRIPTOR_SIZE {
+ log.Panic("wrong descriptor size for v1 policy")
+ }
+ copy(policy.Master_key_descriptor[:], descriptorBytes)
+
+ return policyIoctl(file, unix.FS_IOC_SET_ENCRYPTION_POLICY, unsafe.Pointer(&policy))
+}
+
+func setV2Policy(file *os.File, options *EncryptionOptions, descriptorBytes []byte) error {
+ policy := unix.FscryptPolicyV2{
+ Version: unix.FSCRYPT_POLICY_V2,
+ Contents_encryption_mode: uint8(options.Contents),
+ Filenames_encryption_mode: uint8(options.Filenames),
+ Flags: uint8(buildPolicyFlags(options)),
+ }
+
+ // The descriptor should always be the correct length (as policy is valid)
+ if len(descriptorBytes) != unix.FSCRYPT_KEY_IDENTIFIER_SIZE {
+ log.Panic("wrong descriptor size for v2 policy")
+ }
+ copy(policy.Master_key_identifier[:], descriptorBytes)
+
+ return policyIoctl(file, unix.FS_IOC_SET_ENCRYPTION_POLICY, unsafe.Pointer(&policy))
+}
+
// SetPolicy sets up the specified directory to be encrypted with the specified
// policy. Returns an error if we cannot set the policy for any reason (not a
// directory, invalid options or KeyDescriptor, etc).
@@ -135,30 +224,21 @@ func SetPolicy(path string, data *PolicyData) error {
return errors.Wrap(err, "invalid policy")
}
- // This lookup should always succeed (as policy is valid)
- flags, ok := util.Lookup(data.Options.Padding, paddingArray, flagsArray)
- if !ok {
- log.Panicf("padding of %d was not found", data.Options.Padding)
- }
-
descriptorBytes, err := hex.DecodeString(data.KeyDescriptor)
if err != nil {
- return errors.New("invalid descriptor: " + data.KeyDescriptor)
- }
-
- if shouldUseDirectKeyFlag(data.Options) {
- flags |= unix.FSCRYPT_POLICY_FLAG_DIRECT_KEY
+ return errors.New("invalid key descriptor: " + data.KeyDescriptor)
}
- policy := unix.FscryptPolicyV1{
- Version: unix.FSCRYPT_POLICY_V1,
- Contents_encryption_mode: uint8(data.Options.Contents),
- Filenames_encryption_mode: uint8(data.Options.Filenames),
- Flags: uint8(flags),
+ switch data.Options.PolicyVersion {
+ case 1:
+ err = setV1Policy(file, data.Options, descriptorBytes)
+ case 2:
+ err = setV2Policy(file, data.Options, descriptorBytes)
+ default:
+ err = errors.Errorf("policy version of %d is invalid", data.Options.PolicyVersion)
}
- copy(policy.Master_key_descriptor[:], descriptorBytes)
- if err = policyIoctl(file, unix.FS_IOC_SET_ENCRYPTION_POLICY, &policy); err == unix.EINVAL {
+ if err == unix.EINVAL {
// Before kernel v4.11, many different errors all caused unix.EINVAL to be returned.
// We try to disambiguate this error here. This disambiguation will not always give
// the correct error due to a potential race condition on path.
@@ -195,7 +275,7 @@ func CheckSupport(path string) error {
Flags: math.MaxUint8,
}
- err = policyIoctl(file, unix.FS_IOC_SET_ENCRYPTION_POLICY, &badPolicy)
+ err = policyIoctl(file, unix.FS_IOC_SET_ENCRYPTION_POLICY, unsafe.Pointer(&badPolicy))
switch err {
case nil:
log.Panicf(`FS_IOC_SET_ENCRYPTION_POLICY succeeded when it should have failed.
diff --git a/metadata/policy_test.go b/metadata/policy_test.go
index ad9dd80..3c0704a 100644
--- a/metadata/policy_test.go
+++ b/metadata/policy_test.go
@@ -26,17 +26,30 @@ import (
"testing"
"github.com/golang/protobuf/proto"
+ "golang.org/x/sys/unix"
"github.com/google/fscrypt/util"
)
-const goodDescriptor = "0123456789abcdef"
+const goodV1Descriptor = "0123456789abcdef"
-var goodPolicy = &PolicyData{
- KeyDescriptor: goodDescriptor,
+var goodV1Policy = &PolicyData{
+ KeyDescriptor: goodV1Descriptor,
Options: DefaultOptions,
}
+var goodV2EncryptionOptions = &EncryptionOptions{
+ Padding: 32,
+ Contents: EncryptionOptions_AES_256_XTS,
+ Filenames: EncryptionOptions_AES_256_CTS,
+ PolicyVersion: 2,
+}
+
+var goodV2Policy = &PolicyData{
+ KeyDescriptor: "0123456789abcdef0123456789abcdef",
+ Options: goodV2EncryptionOptions,
+}
+
// Creates a temporary directory for testing.
func createTestDirectory(t *testing.T) (directory string, err error) {
baseDirectory, err := util.TestRoot()
@@ -83,7 +96,7 @@ func TestSetPolicyEmptyDirectory(t *testing.T) {
}
defer os.RemoveAll(directory)
- if err = SetPolicy(directory, goodPolicy); err != nil {
+ if err = SetPolicy(directory, goodV1Policy); err != nil {
t.Error(err)
}
}
@@ -96,7 +109,7 @@ func TestSetPolicyNonemptyDirectory(t *testing.T) {
}
defer os.RemoveAll(directory)
- if err = SetPolicy(directory, goodPolicy); err == nil {
+ if err = SetPolicy(directory, goodV1Policy); err == nil {
t.Error("should have failed to set policy on a nonempty directory")
}
}
@@ -109,7 +122,7 @@ func TestSetPolicyFile(t *testing.T) {
}
defer os.RemoveAll(directory)
- if err = SetPolicy(file, goodPolicy); err == nil {
+ if err = SetPolicy(file, goodV1Policy); err == nil {
t.Error("should have failed to set policy on a file")
}
}
@@ -141,15 +154,15 @@ func TestGetPolicyEmptyDirectory(t *testing.T) {
defer os.RemoveAll(directory)
var actualPolicy *PolicyData
- if err = SetPolicy(directory, goodPolicy); err != nil {
+ if err = SetPolicy(directory, goodV1Policy); err != nil {
t.Fatal(err)
}
if actualPolicy, err = GetPolicy(directory); err != nil {
t.Fatal(err)
}
- if !proto.Equal(actualPolicy, goodPolicy) {
- t.Errorf("policy %+v does not equal expected policy %+v", actualPolicy, goodPolicy)
+ if !proto.Equal(actualPolicy, goodV1Policy) {
+ t.Errorf("policy %+v does not equal expected policy %+v", actualPolicy, goodV1Policy)
}
}
@@ -165,3 +178,35 @@ func TestGetPolicyUnencrypted(t *testing.T) {
t.Error("should have failed to set policy on a file")
}
}
+
+func requireV2PolicySupport(t *testing.T, directory string) {
+ file, err := os.Open(directory)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer file.Close()
+
+ err = policyIoctl(file, unix.FS_IOC_GET_ENCRYPTION_POLICY_EX, nil)
+ if err == ErrEncryptionNotSupported {
+ t.Skip("No support for v2 encryption policies, skipping test")
+ }
+}
+
+// Tests that a non-root user cannot set a v2 encryption policy unless the key
+// has been added.
+func TestSetV2PolicyNoKey(t *testing.T) {
+ if util.IsUserRoot() {
+ t.Skip("This test cannot be run as root")
+ }
+ directory, err := createTestDirectory(t)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(directory)
+ requireV2PolicySupport(t, directory)
+
+ err = SetPolicy(directory, goodV2Policy)
+ if err == nil {
+ t.Error("shouldn't have been able to set v2 policy without key added")
+ }
+}