File: callback.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 (132 lines) | stat: -rw-r--r-- 5,073 bytes parent folder | download | duplicates (4)
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
/*
 * callback.go - defines how the caller of an action function passes along a key
 * to be used in this package.
 *
 * Copyright 2017 Google Inc.
 * Author: Joe Richey (joerichey@google.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package actions

import (
	"log"

	"github.com/pkg/errors"

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

// ProtectorInfo is the information a caller will receive about a Protector
// before they have to return the corresponding key. This is currently a
// read-only view of metadata.ProtectorData.
type ProtectorInfo struct {
	data *metadata.ProtectorData
}

// Descriptor is the Protector's descriptor used to uniquely identify it.
func (pi *ProtectorInfo) Descriptor() string { return pi.data.GetProtectorDescriptor() }

// Source indicates the type of the descriptor (how it should be unlocked).
func (pi *ProtectorInfo) Source() metadata.SourceType { return pi.data.GetSource() }

// Name is used to describe custom passphrase and raw key descriptors.
func (pi *ProtectorInfo) Name() string { return pi.data.GetName() }

// UID is used to identify the user for login passphrases.
func (pi *ProtectorInfo) UID() int64 { return pi.data.GetUid() }

// KeyFunc is passed to a function that will require some type of key.
// The info parameter is provided so the callback knows which key to provide.
// The retry parameter indicates that a previous key provided by this callback
// was incorrect (this allows for user feedback like "incorrect passphrase").
//
// For passphrase sources, the returned key should be a passphrase. For raw
// sources, the returned key should be a 256-bit cryptographic key. Consumers
// of the callback will wipe the returned key. An error returned by the callback
// will be propagated back to the caller.
type KeyFunc func(info ProtectorInfo, retry bool) (*crypto.Key, error)

// getWrappingKey uses the provided callback to get the wrapping key
// corresponding to the ProtectorInfo. This runs the passphrase hash for
// passphrase sources or just relays the callback for raw sources.
func getWrappingKey(info ProtectorInfo, keyFn KeyFunc, retry bool) (*crypto.Key, error) {
	// For raw key sources, we can just use the key directly.
	if info.Source() == metadata.SourceType_raw_key {
		return keyFn(info, retry)
	}

	// Run the passphrase hash for other sources.
	passphrase, err := keyFn(info, retry)
	if err != nil {
		return nil, err
	}
	defer passphrase.Wipe()

	log.Printf("running passphrase hash for protector %s", info.Descriptor())
	return crypto.PassphraseHash(passphrase, info.data.Salt, info.data.Costs)
}

// unwrapProtectorKey uses the provided callback and ProtectorInfo to return
// the unwrapped protector key. This will repeatedly call keyFn to get the
// wrapping key until the correct key is returned by the callback or the
// callback returns an error.
func unwrapProtectorKey(info ProtectorInfo, keyFn KeyFunc) (*crypto.Key, error) {
	retry := false
	for {
		wrappingKey, err := getWrappingKey(info, keyFn, retry)
		if err != nil {
			return nil, err
		}

		protectorKey, err := crypto.Unwrap(wrappingKey, info.data.WrappedKey)
		wrappingKey.Wipe()

		switch errors.Cause(err) {
		case nil:
			log.Printf("valid wrapping key for protector %s", info.Descriptor())
			return protectorKey, nil
		case crypto.ErrBadAuth:
			// After the first failure, we let the callback know we are retrying.
			log.Printf("invalid wrapping key for protector %s", info.Descriptor())
			retry = true
			continue
		default:
			return nil, err
		}
	}
}

// ProtectorOption is information about a protector relative to a Policy.
type ProtectorOption struct {
	ProtectorInfo
	// LinkedMount is the mountpoint for a linked protector. It is nil if
	// the protector is not a linked protector (or there is a LoadError).
	LinkedMount *filesystem.Mount
	// LoadError is non-nil if there was an error in getting the data for
	// the protector.
	LoadError error
}

// OptionFunc is passed to a function that needs to unlock a Policy.
// The callback is used to specify which protector should be used to unlock a
// Policy. The descriptor indicates which Policy we are using, while the options
// correspond to the valid Protectors protecting the Policy.
//
// The OptionFunc should either return a valid index into options, which
// corresponds to the desired protector, or an error (which will be propagated
// back to the caller).
type OptionFunc func(policyDescriptor string, options []*ProtectorOption) (int, error)