package transit import ( "encoding/base64" "fmt" "github.com/hashicorp/vault/helper/certutil" "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.", }, }, 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 } // Decode the context if any contextRaw := d.Get("context").(string) var context []byte if len(contextRaw) != 0 { var err error context, err = base64.StdEncoding.DecodeString(contextRaw) if err != nil { return logical.ErrorResponse("failed to decode context as base64"), logical.ErrInvalidRequest } } // Get the policy lp, err := b.policies.getPolicy(req.Storage, name) if err != nil { return nil, err } // Error if invalid policy if lp == nil { return logical.ErrorResponse("policy not found"), logical.ErrInvalidRequest } lp.RLock() defer lp.RUnlock() // Verify if wasn't deleted before we grabbed the lock if lp.Policy() == nil { return nil, fmt.Errorf("no existing policy named %s could be found", name) } plaintext, err := lp.Policy().Decrypt(context, value) if err != nil { switch err.(type) { case certutil.UserError: return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest case certutil.InternalError: return nil, err default: return nil, err } } if plaintext == "" { return nil, fmt.Errorf("empty plaintext returned during rewrap") } ciphertext, err := lp.Policy().Encrypt(context, plaintext) if err != nil { switch err.(type) { case certutil.UserError: return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest case certutil.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. `