From 6ffc9457945a9484d2757cc4b01de35426502d0a Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 15 Dec 2019 19:31:39 -0800 Subject: keyring: support filesystem keyring with v1 encryption policies Linux v5.4 and later allows fscrypt keys to be added/removed directly to/from the filesystem via the new ioctls FS_IOC_ADD_ENCRYPTION_KEY and FS_IOC_REMOVE_ENCRYPTION_KEY. Among other benefits, these fix the key visibility problems that many users have been running into, where system services and containers can't access encrypted files. Allow the user to opt-in to using these new ioctls for their existing encrypted directories by setting in their /etc/fscrypt.conf: "use_fs_keyring_for_v1_policies": true Note that it can't really be on by default, since for v1 policies the ioctls require root, whereas user keyrings don't. I.e., setting this to true means that users will need to use 'sudo fscrypt unlock', not 'fscrypt unlock'. v2 policies won't have this restriction. --- metadata/config_test.go | 3 +- metadata/metadata.pb.go | 133 ++++++++++++++++++++++++++---------------------- metadata/metadata.proto | 1 + 3 files changed, 75 insertions(+), 62 deletions(-) (limited to 'metadata') diff --git a/metadata/config_test.go b/metadata/config_test.go index d184a87..3c20c51 100644 --- a/metadata/config_test.go +++ b/metadata/config_test.go @@ -49,7 +49,8 @@ var testConfigString = `{ "padding": "32", "contents": "AES_256_XTS", "filenames": "AES_256_CTS" - } + }, + "use_fs_keyring_for_v1_policies": false } ` diff --git a/metadata/metadata.pb.go b/metadata/metadata.pb.go index bd3ee2a..aa4eeff 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_fa046c95c3cd6aa1, []int{0} + return fileDescriptor_metadata_ff272c42a9f0f3d3, []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_fa046c95c3cd6aa1, []int{3, 0} + return fileDescriptor_metadata_ff272c42a9f0f3d3, []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_fa046c95c3cd6aa1, []int{0} + return fileDescriptor_metadata_ff272c42a9f0f3d3, []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_fa046c95c3cd6aa1, []int{1} + return fileDescriptor_metadata_ff272c42a9f0f3d3, []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_fa046c95c3cd6aa1, []int{2} + return fileDescriptor_metadata_ff272c42a9f0f3d3, []int{2} } func (m *ProtectorData) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ProtectorData.Unmarshal(m, b) @@ -302,7 +302,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_fa046c95c3cd6aa1, []int{3} + return fileDescriptor_metadata_ff272c42a9f0f3d3, []int{3} } func (m *EncryptionOptions) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_EncryptionOptions.Unmarshal(m, b) @@ -355,7 +355,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_fa046c95c3cd6aa1, []int{4} + return fileDescriptor_metadata_ff272c42a9f0f3d3, []int{4} } func (m *WrappedPolicyKey) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_WrappedPolicyKey.Unmarshal(m, b) @@ -403,7 +403,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_fa046c95c3cd6aa1, []int{5} + return fileDescriptor_metadata_ff272c42a9f0f3d3, []int{5} } func (m *PolicyData) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PolicyData.Unmarshal(m, b) @@ -446,20 +446,21 @@ func (m *PolicyData) GetWrappedPolicyKeys() []*WrappedPolicyKey { // Data stored in the config file type Config struct { - Source SourceType `protobuf:"varint,1,opt,name=source,proto3,enum=metadata.SourceType" json:"source,omitempty"` - HashCosts *HashingCosts `protobuf:"bytes,2,opt,name=hash_costs,json=hashCosts,proto3" json:"hash_costs,omitempty"` - Compatibility string `protobuf:"bytes,3,opt,name=compatibility,proto3" json:"compatibility,omitempty"` - Options *EncryptionOptions `protobuf:"bytes,4,opt,name=options,proto3" json:"options,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Source SourceType `protobuf:"varint,1,opt,name=source,proto3,enum=metadata.SourceType" json:"source,omitempty"` + HashCosts *HashingCosts `protobuf:"bytes,2,opt,name=hash_costs,json=hashCosts,proto3" json:"hash_costs,omitempty"` + Compatibility string `protobuf:"bytes,3,opt,name=compatibility,proto3" json:"compatibility,omitempty"` + Options *EncryptionOptions `protobuf:"bytes,4,opt,name=options,proto3" json:"options,omitempty"` + UseFsKeyringForV1Policies bool `protobuf:"varint,5,opt,name=use_fs_keyring_for_v1_policies,json=useFsKeyringForV1Policies,proto3" json:"use_fs_keyring_for_v1_policies,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } 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_fa046c95c3cd6aa1, []int{6} + return fileDescriptor_metadata_ff272c42a9f0f3d3, []int{6} } func (m *Config) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Config.Unmarshal(m, b) @@ -507,6 +508,13 @@ func (m *Config) GetOptions() *EncryptionOptions { return nil } +func (m *Config) GetUseFsKeyringForV1Policies() bool { + if m != nil { + return m.UseFsKeyringForV1Policies + } + return false +} + func init() { proto.RegisterType((*HashingCosts)(nil), "metadata.HashingCosts") proto.RegisterType((*WrappedKeyData)(nil), "metadata.WrappedKeyData") @@ -519,49 +527,52 @@ func init() { proto.RegisterEnum("metadata.EncryptionOptions_Mode", EncryptionOptions_Mode_name, EncryptionOptions_Mode_value) } -func init() { proto.RegisterFile("metadata/metadata.proto", fileDescriptor_metadata_fa046c95c3cd6aa1) } - -var fileDescriptor_metadata_fa046c95c3cd6aa1 = []byte{ - // 656 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0xef, 0x6a, 0xdb, 0x3c, - 0x14, 0xc6, 0x5f, 0xdb, 0x69, 0xd2, 0x9c, 0xfc, 0x79, 0x5d, 0xb5, 0x6f, 0x5f, 0xb3, 0x7d, 0x09, - 0xde, 0x06, 0x65, 0x94, 0x8e, 0x66, 0x74, 0x6c, 0x30, 0x06, 0x5d, 0x5a, 0xb6, 0xae, 0x94, 0x75, - 0x4a, 0xe8, 0x36, 0x18, 0x04, 0xd5, 0x56, 0x1b, 0x51, 0xdb, 0x12, 0x96, 0x42, 0xf0, 0xb7, 0x7d, - 0xdb, 0x05, 0xec, 0x5a, 0xb6, 0x8b, 0xd8, 0x55, 0x0d, 0xc9, 0xb1, 0xe3, 0xb4, 0x50, 0xba, 0x7d, - 0x31, 0x47, 0x8f, 0xa4, 0xf3, 0x1c, 0xfd, 0xa4, 0x63, 0xf8, 0x3f, 0xa6, 0x8a, 0x84, 0x44, 0x91, - 0x27, 0x45, 0xb0, 0x23, 0x52, 0xae, 0x38, 0x5a, 0x2d, 0xc6, 0xfe, 0x17, 0x68, 0xbf, 0x25, 0x72, - 0xc2, 0x92, 0xcb, 0x01, 0x97, 0x4a, 0x22, 0x04, 0x35, 0xc5, 0x62, 0xea, 0xd9, 0x3d, 0x6b, 0xcb, - 0xc1, 0x26, 0x46, 0x9b, 0x50, 0x8f, 0x69, 0xcc, 0xd3, 0xcc, 0x73, 0x8c, 0x3a, 0x1f, 0xa1, 0x1e, - 0xb4, 0x04, 0x49, 0x49, 0x14, 0xd1, 0x88, 0xc9, 0xd8, 0xab, 0x99, 0xc9, 0xaa, 0xe4, 0x7f, 0x86, - 0xee, 0xc7, 0x94, 0x08, 0x41, 0xc3, 0x63, 0x9a, 0x1d, 0x10, 0x45, 0x50, 0x17, 0xec, 0xa3, 0x33, - 0xcf, 0xea, 0x59, 0x5b, 0x6d, 0x6c, 0x1f, 0x9d, 0xa1, 0x07, 0xd0, 0xa1, 0x49, 0x90, 0x66, 0x42, - 0xd1, 0x70, 0x7c, 0x45, 0x33, 0x63, 0xdc, 0xc6, 0xed, 0x52, 0x3c, 0xa6, 0x99, 0x2e, 0x6a, 0x12, - 0x93, 0xc0, 0xd8, 0xb7, 0xb1, 0x89, 0xfd, 0xef, 0x36, 0x74, 0x4e, 0x53, 0xae, 0x68, 0xa0, 0x78, - 0x6a, 0x52, 0xef, 0xc2, 0x86, 0x28, 0x84, 0x71, 0x48, 0x65, 0x90, 0x32, 0xa1, 0x78, 0x6a, 0xcc, - 0x9a, 0x78, 0xbd, 0x9c, 0x3b, 0x28, 0xa7, 0xd0, 0x36, 0xd4, 0x25, 0x9f, 0xa6, 0x41, 0x7e, 0xde, - 0x6e, 0x7f, 0x63, 0xa7, 0x04, 0x35, 0x34, 0xfa, 0x28, 0x13, 0x14, 0xcf, 0xd7, 0xe8, 0x32, 0x12, - 0x12, 0x53, 0x53, 0x46, 0x13, 0x9b, 0x18, 0x6d, 0xc3, 0x4a, 0xa0, 0xc1, 0x99, 0xd3, 0xb7, 0xfa, - 0x9b, 0x8b, 0x04, 0x55, 0xac, 0x38, 0x5f, 0xa4, 0x33, 0x48, 0x12, 0x29, 0x6f, 0x25, 0x3f, 0x88, - 0x8e, 0x91, 0x0b, 0xce, 0x94, 0x85, 0x5e, 0xdd, 0xd0, 0xd3, 0x21, 0x7a, 0x01, 0xad, 0x59, 0x4e, - 0xcd, 0x10, 0x69, 0x98, 0xcc, 0xde, 0x22, 0xf3, 0x32, 0x52, 0x0c, 0xb3, 0x72, 0xec, 0xff, 0xb0, - 0x61, 0xed, 0x30, 0x47, 0xc7, 0x78, 0xf2, 0xde, 0x7c, 0x25, 0xf2, 0xa0, 0x21, 0x48, 0x18, 0xb2, - 0xe4, 0xd2, 0xc0, 0x70, 0x70, 0x31, 0x44, 0x2f, 0x61, 0x35, 0xe0, 0x89, 0xa2, 0x89, 0x92, 0x73, - 0x04, 0xbd, 0x85, 0xcf, 0x8d, 0x44, 0x3b, 0x27, 0x3c, 0xa4, 0xb8, 0xdc, 0x81, 0x5e, 0x41, 0xf3, - 0x82, 0x45, 0x54, 0x83, 0x90, 0x86, 0xca, 0x5d, 0xb6, 0x2f, 0xb6, 0xf8, 0xdf, 0x2c, 0xa8, 0x69, - 0x0d, 0xb5, 0xa0, 0x11, 0xd2, 0x0b, 0x32, 0x8d, 0x94, 0xfb, 0x0f, 0xfa, 0x17, 0x5a, 0xfb, 0x87, - 0xc3, 0x71, 0x7f, 0xef, 0xd9, 0xf8, 0xd3, 0x68, 0xe8, 0x5a, 0x55, 0xe1, 0xcd, 0xe0, 0xc4, 0xb5, - 0xab, 0xc2, 0xe0, 0xf5, 0xc0, 0x75, 0x96, 0x84, 0xd1, 0xd0, 0xad, 0x15, 0xc2, 0x6e, 0xff, 0xb9, - 0x59, 0xb1, 0xb2, 0x24, 0x8c, 0x86, 0x6e, 0x1d, 0xb5, 0x61, 0x75, 0x3f, 0x64, 0x24, 0x51, 0xd3, - 0xd8, 0x6d, 0xfa, 0x5f, 0x2d, 0x70, 0xe7, 0x58, 0x4f, 0x79, 0xc4, 0x82, 0x4c, 0x3f, 0xbb, 0xbf, - 0x78, 0x50, 0xd7, 0xae, 0xce, 0xfe, 0x83, 0xab, 0xfb, 0x69, 0x01, 0xe4, 0xde, 0xe6, 0x35, 0x3f, - 0x82, 0xee, 0x15, 0xcd, 0x6e, 0xda, 0x76, 0xae, 0x68, 0x56, 0x31, 0xdc, 0x83, 0x06, 0xcf, 0xe9, - 0xce, 0xcd, 0xee, 0xdf, 0x72, 0x01, 0xb8, 0x58, 0x8b, 0xde, 0xc1, 0x7a, 0x51, 0xa7, 0x30, 0x9e, - 0xba, 0x5c, 0x7d, 0x87, 0xce, 0x56, 0xab, 0x7f, 0xef, 0x46, 0xbd, 0x25, 0x13, 0xbc, 0x36, 0xbb, - 0xa6, 0x48, 0xff, 0x97, 0x05, 0xf5, 0x01, 0x4f, 0x2e, 0xd8, 0x65, 0xa5, 0x9f, 0xac, 0x3b, 0xf4, - 0xd3, 0x1e, 0xc0, 0x84, 0xc8, 0xc9, 0x38, 0x6f, 0x20, 0xfb, 0xd6, 0x06, 0x6a, 0xea, 0x95, 0xf9, - 0x2f, 0xea, 0x21, 0x74, 0x02, 0x1e, 0x0b, 0xa2, 0xd8, 0x39, 0x8b, 0x98, 0xca, 0xe6, 0xfd, 0xb8, - 0x2c, 0x56, 0xc1, 0xd4, 0xee, 0x0e, 0xe6, 0xf1, 0x07, 0x80, 0x45, 0xa5, 0xcb, 0xef, 0x12, 0x41, - 0x57, 0x90, 0x78, 0x2c, 0x88, 0x94, 0x62, 0x92, 0x12, 0x49, 0x5d, 0x0b, 0xfd, 0x07, 0x6b, 0xc1, - 0x54, 0x2a, 0xbe, 0x24, 0xdb, 0x7a, 0x5f, 0x4a, 0x66, 0x9a, 0xa9, 0xeb, 0x9c, 0xd7, 0xcd, 0x3f, - 0xf7, 0xe9, 0xef, 0x00, 0x00, 0x00, 0xff, 0xff, 0x4b, 0xbe, 0x84, 0xbc, 0x8e, 0x05, 0x00, 0x00, +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, } diff --git a/metadata/metadata.proto b/metadata/metadata.proto index 735181e..e682212 100644 --- a/metadata/metadata.proto +++ b/metadata/metadata.proto @@ -97,4 +97,5 @@ message Config { HashingCosts hash_costs = 2; string compatibility = 3; EncryptionOptions options = 4; + bool use_fs_keyring_for_v1_policies = 5; } -- cgit v1.2.3 From 2b25de6d445faefc28629603dd754aec9f744e60 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 15 Dec 2019 19:31:39 -0800 Subject: 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. --- metadata/checks.go | 35 ++++++++-- metadata/config_test.go | 41 +++++++++++- metadata/constants.go | 18 +++-- metadata/metadata.pb.go | 123 +++++++++++++++++++---------------- metadata/metadata.proto | 2 + metadata/policy.go | 170 +++++++++++++++++++++++++++++++++++------------- metadata/policy_test.go | 63 +++++++++++++++--- 7 files changed, 329 insertions(+), 123 deletions(-) (limited to 'metadata') 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") + } +} -- cgit v1.2.3