forked from hashicorp/vault
-
Notifications
You must be signed in to change notification settings - Fork 0
/
path_rewrap.go
138 lines (117 loc) · 3.39 KB
/
path_rewrap.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
package transit
import (
"encoding/base64"
"fmt"
"github.com/hashicorp/vault/helper/errutil"
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/logical/framework"
)
func (b *backend) pathRewrap() *framework.Path {
return &framework.Path{
Pattern: "rewrap/" + framework.GenericNameRegex("name"),
Fields: map[string]*framework.FieldSchema{
"name": &framework.FieldSchema{
Type: framework.TypeString,
Description: "Name of the key",
},
"ciphertext": &framework.FieldSchema{
Type: framework.TypeString,
Description: "Ciphertext value to rewrap",
},
"context": &framework.FieldSchema{
Type: framework.TypeString,
Description: "Context for key derivation. Required for derived keys.",
},
"nonce": &framework.FieldSchema{
Type: framework.TypeString,
Description: "Nonce for when convergent encryption is used",
},
},
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.UpdateOperation: b.pathRewrapWrite,
},
HelpSynopsis: pathRewrapHelpSyn,
HelpDescription: pathRewrapHelpDesc,
}
}
func (b *backend) pathRewrapWrite(
req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
name := d.Get("name").(string)
value := d.Get("ciphertext").(string)
if len(value) == 0 {
return logical.ErrorResponse("missing ciphertext to decrypt"), logical.ErrInvalidRequest
}
var err error
// Decode the context if any
contextRaw := d.Get("context").(string)
var context []byte
if len(contextRaw) != 0 {
context, err = base64.StdEncoding.DecodeString(contextRaw)
if err != nil {
return logical.ErrorResponse("failed to base64-decode context"), logical.ErrInvalidRequest
}
}
// Decode the nonce if any
nonceRaw := d.Get("nonce").(string)
var nonce []byte
if len(nonceRaw) != 0 {
nonce, err = base64.StdEncoding.DecodeString(nonceRaw)
if err != nil {
return logical.ErrorResponse("failed to base64-decode nonce"), logical.ErrInvalidRequest
}
}
// Get the policy
p, lock, err := b.lm.GetPolicyShared(req.Storage, name)
if lock != nil {
defer lock.RUnlock()
}
if err != nil {
return nil, err
}
// Error if invalid policy
if p == nil {
return logical.ErrorResponse("policy not found"), logical.ErrInvalidRequest
}
plaintext, err := p.Decrypt(context, nonce, value)
if err != nil {
switch err.(type) {
case errutil.UserError:
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
case errutil.InternalError:
return nil, err
default:
return nil, err
}
}
if plaintext == "" {
return nil, fmt.Errorf("empty plaintext returned during rewrap")
}
ciphertext, err := p.Encrypt(context, nonce, plaintext)
if err != nil {
switch err.(type) {
case errutil.UserError:
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
case errutil.InternalError:
return nil, err
default:
return nil, err
}
}
if ciphertext == "" {
return nil, fmt.Errorf("empty ciphertext returned")
}
// Generate the response
resp := &logical.Response{
Data: map[string]interface{}{
"ciphertext": ciphertext,
},
}
return resp, nil
}
const pathRewrapHelpSyn = `Rewrap ciphertext`
const pathRewrapHelpDesc = `
After key rotation, this function can be used to rewrap the
given ciphertext with the latest version of the named key.
If the given ciphertext is already using the latest version
of the key, this function is a no-op.
`