mirror of
https://github.com/ceph/ceph-csi.git
synced 2024-12-30 00:40:21 +00:00
133 lines
5.0 KiB
Go
133 lines
5.0 KiB
Go
|
/*
|
||
|
* 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)
|