File: keyring.go

package info (click to toggle)
fscrypt 0.3.5-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,064 kB
  • sloc: sh: 970; makefile: 159; ansic: 84
file content (175 lines) | stat: -rw-r--r-- 6,143 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/*
 * keyring.go - Add/remove encryption policy keys to/from kernel
 *
 * Copyright 2019 Google LLC
 * Author: Eric Biggers (ebiggers@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 keyring manages adding, removing, and getting the status of
// encryption policy keys to/from the kernel.  Most public functions are in
// keyring.go, and they delegate to either user_keyring.go or fs_keyring.go,
// depending on whether a user keyring or a filesystem keyring is being used.
//
// v2 encryption policies always use the filesystem keyring.
// v1 policies use the user keyring by default, but can be configured to use the
// filesystem keyring instead (requires root and kernel v5.4+).
package keyring

import (
	"encoding/hex"
	"os/user"
	"strconv"

	"github.com/pkg/errors"
	"golang.org/x/sys/unix"

	"github.com/google/fscrypt/crypto"
	"github.com/google/fscrypt/filesystem"
	"github.com/google/fscrypt/metadata"
	"github.com/google/fscrypt/util"
)

// Keyring error values
var (
	ErrKeyAddedByOtherUsers  = errors.New("other users have added the key too")
	ErrKeyFilesOpen          = errors.New("some files using the key are still open")
	ErrKeyNotPresent         = errors.New("key not present or already removed")
	ErrV2PoliciesUnsupported = errors.New("kernel is too old to support v2 encryption policies")
)

// Options are the options which specify *which* keyring the key should be
// added/removed/gotten to, and how.
type Options struct {
	// Mount is the filesystem to which the key should be
	// added/removed/gotten.
	Mount *filesystem.Mount
	// User is the user for whom the key should be added/removed/gotten.
	User *user.User
	// UseFsKeyringForV1Policies is true if keys for v1 encryption policies
	// should be put in the filesystem's keyring (if supported) rather than
	// in the user's keyring.  Note that this makes AddEncryptionKey and
	// RemoveEncryptionKey require root privileges.
	UseFsKeyringForV1Policies bool
}

func shouldUseFsKeyring(descriptor string, options *Options) (bool, error) {
	// For v1 encryption policy keys, use the filesystem keyring if
	// use_fs_keyring_for_v1_policies is set in /etc/fscrypt.conf and the
	// kernel supports it.
	if len(descriptor) == hex.EncodedLen(unix.FSCRYPT_KEY_DESCRIPTOR_SIZE) {
		return options.UseFsKeyringForV1Policies && IsFsKeyringSupported(options.Mount), nil
	}
	// For v2 encryption policy keys, always use the filesystem keyring; the
	// kernel doesn't support any other way.
	if !IsFsKeyringSupported(options.Mount) {
		return true, ErrV2PoliciesUnsupported
	}
	return true, nil
}

// buildKeyDescription builds the description for an fscrypt key of type
// "logon". For ext4 and f2fs, it uses the legacy filesystem-specific prefixes
// for compatibility with kernels before v4.8 and v4.6 respectively. For other
// filesystems it uses the generic prefix "fscrypt".
func buildKeyDescription(options *Options, descriptor string) string {
	switch options.Mount.FilesystemType {
	case "ext4", "f2fs":
		return options.Mount.FilesystemType + ":" + descriptor
	default:
		return unix.FSCRYPT_KEY_DESC_PREFIX + descriptor
	}
}

// AddEncryptionKey adds an encryption policy key to a kernel keyring.  It uses
// either the filesystem keyring for the target Mount or the user keyring for
// the target User.
func AddEncryptionKey(key *crypto.Key, descriptor string, options *Options) error {
	if err := util.CheckValidLength(metadata.PolicyKeyLen, key.Len()); err != nil {
		return errors.Wrap(err, "policy key")
	}
	useFsKeyring, err := shouldUseFsKeyring(descriptor, options)
	if err != nil {
		return err
	}
	if useFsKeyring {
		return fsAddEncryptionKey(key, descriptor, options.Mount, options.User)
	}
	return userAddKey(key, buildKeyDescription(options, descriptor), options.User)
}

// RemoveEncryptionKey removes an encryption policy key from a kernel keyring.
// It uses either the filesystem keyring for the target Mount or the user
// keyring for the target User.
func RemoveEncryptionKey(descriptor string, options *Options, allUsers bool) error {
	useFsKeyring, err := shouldUseFsKeyring(descriptor, options)
	if err != nil {
		return err
	}
	if useFsKeyring {
		user := options.User
		if allUsers {
			user = nil
		}
		return fsRemoveEncryptionKey(descriptor, options.Mount, user)
	}
	return userRemoveKey(buildKeyDescription(options, descriptor), options.User)
}

// KeyStatus is an enum that represents the status of a key in a kernel keyring.
type KeyStatus int

// The possible values of KeyStatus.
const (
	KeyStatusUnknown = 0 + iota
	KeyAbsent
	KeyAbsentButFilesBusy
	KeyPresent
	KeyPresentButOnlyOtherUsers
)

func (status KeyStatus) String() string {
	switch status {
	case KeyStatusUnknown:
		return "Unknown"
	case KeyAbsent:
		return "Absent"
	case KeyAbsentButFilesBusy:
		return "AbsentButFilesBusy"
	case KeyPresent:
		return "Present"
	case KeyPresentButOnlyOtherUsers:
		return "PresentButOnlyOtherUsers"
	default:
		return strconv.Itoa(int(status))
	}
}

// GetEncryptionKeyStatus gets the status of an encryption policy key in a
// kernel keyring.  It uses either the filesystem keyring for the target Mount
// or the user keyring for the target User.
func GetEncryptionKeyStatus(descriptor string, options *Options) (KeyStatus, error) {
	useFsKeyring, err := shouldUseFsKeyring(descriptor, options)
	if err != nil {
		return KeyStatusUnknown, err
	}
	if useFsKeyring {
		return fsGetEncryptionKeyStatus(descriptor, options.Mount, options.User)
	}
	_, _, err = userFindKey(buildKeyDescription(options, descriptor), options.User)
	if err != nil {
		return KeyAbsent, nil
	}
	return KeyPresent, nil
}