forked from hashicorp/go-kms-wrapping
-
Notifications
You must be signed in to change notification settings - Fork 2
/
data_key_version.go
138 lines (123 loc) · 4.61 KB
/
data_key_version.go
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
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package kms
import (
"context"
"fmt"
"time"
"github.com/hashicorp/go-dbw"
wrapping "github.com/openbao/go-kms-wrapping/v2"
"github.com/openbao/go-kms-wrapping/v2/extras/structwrapping"
)
// dataKeyVersion represents a version of a DataKey
type dataKeyVersion struct {
// PrivateId is used to access the key version
PrivateId string `json:"private_id,omitempty" gorm:"primary_key"`
// DataKeyId for the key version
DataKeyId string `json:"data_key_id,omitempty" gorm:"default:null"`
// RootKeyVersionId of the version of the root key data.
RootKeyVersionId string `json:"root_key_version_id,omitempty" gorm:"default:null"`
// Key is the plain-text of the key data. We are NOT storing this plain-text key
// in the db.
Key []byte `json:"key,omitempty" gorm:"-" wrapping:"pt,key_data"`
// CtKey is the ciphertext key data stored in the database
CtKey []byte `json:"ct_key,omitempty" gorm:"column:key;not_null" wrapping:"ct,key_data"`
// Version of the key data. This is not used for optimistic locking, since
// key versions are immutable. It's just the version of the key.
Version uint32 `json:"version,omitempty" gorm:"default:null"`
// CreateTime from the RDBMS
CreateTime time.Time `json:"create_time,omitempty" gorm:"default:current_timestamp"`
// tableNamePrefix defines the prefix to use before the table name and
// allows us to support custom prefixes as well as multi KMSs within a
// single schema.
tableNamePrefix string `gorm:"-"`
}
// newDataKeyVersion creates a new in memory data key version. No options
// are currently supported.
func newDataKeyVersion(dataKeyId string, key []byte, rootKeyVersionId string, _ ...Option) (*dataKeyVersion, error) {
const op = "kms.newDataKeyVersion"
if dataKeyId == "" {
return nil, fmt.Errorf("%s: missing data key id: %w", op, ErrInvalidParameter)
}
if len(key) == 0 {
return nil, fmt.Errorf("%s: missing key: %w", op, ErrInvalidParameter)
}
if rootKeyVersionId == "" {
return nil, fmt.Errorf("%s: missing root key version id: %w", op, ErrInvalidParameter)
}
k := &dataKeyVersion{
DataKeyId: dataKeyId,
RootKeyVersionId: rootKeyVersionId,
Key: key,
}
return k, nil
}
// Clone creates a clone of the DataKeyVersion
func (k *dataKeyVersion) Clone() *dataKeyVersion {
clone := &dataKeyVersion{
PrivateId: k.PrivateId,
DataKeyId: k.DataKeyId,
RootKeyVersionId: k.RootKeyVersionId,
Version: k.Version,
CreateTime: k.CreateTime,
tableNamePrefix: k.tableNamePrefix,
}
clone.Key = make([]byte, len(k.Key))
copy(clone.Key, k.Key)
clone.CtKey = make([]byte, len(k.CtKey))
copy(clone.CtKey, k.CtKey)
return clone
}
// vetForWrite validates the data key version before it's written.
func (k *dataKeyVersion) vetForWrite(ctx context.Context, opType dbw.OpType) error {
const op = "kms.(dataKeyVersion).vetForWrite"
if k.PrivateId == "" {
return fmt.Errorf("%s: missing private id: %w", op, ErrInvalidParameter)
}
switch opType {
case dbw.CreateOp:
if k.CtKey == nil {
return fmt.Errorf("%s: missing key: %w", op, ErrInvalidParameter)
}
if k.DataKeyId == "" {
return fmt.Errorf("%s: missing data key id: %w", op, ErrInvalidParameter)
}
if k.RootKeyVersionId == "" {
return fmt.Errorf("%s: missing root key version id: %w", op, ErrInvalidParameter)
}
case dbw.UpdateOp:
return fmt.Errorf("%s: key is immutable: %w", op, ErrInvalidParameter)
}
return nil
}
// TableName returns the table name
func (k *dataKeyVersion) TableName() string {
const tableName = "data_key_version"
return fmt.Sprintf("%s_%s", k.tableNamePrefix, tableName)
}
// Encrypt will encrypt the data key version's key
func (k *dataKeyVersion) Encrypt(ctx context.Context, cipher wrapping.Wrapper) error {
const op = "kms.(dataKeyVersion).Encrypt"
if cipher == nil {
return fmt.Errorf("%s: missing cipher: %w", op, ErrInvalidParameter)
}
if err := structwrapping.WrapStruct(ctx, cipher, k, nil); err != nil {
return fmt.Errorf("%s: %w", op, err)
}
return nil
}
// Decrypt will decrypt the data key version's key
func (k *dataKeyVersion) Decrypt(ctx context.Context, cipher wrapping.Wrapper) error {
const op = "kms.(dataKeyVersion).Decrypt"
if cipher == nil {
return fmt.Errorf("%s: missing cipher: %w", op, ErrInvalidParameter)
}
if err := structwrapping.UnwrapStruct(ctx, cipher, k, nil); err != nil {
return fmt.Errorf("%s: %w", op, err)
}
return nil
}
// GetPrivateId returns the key's private id
func (k *dataKeyVersion) GetPrivateId() string { return k.PrivateId }
// GetKey returns the key bytes
func (k *dataKeyVersion) GetKey() []byte { return k.Key }