2020-09-02 14:37:19 -04:00
package kms
import (
"context"
"fmt"
"strings"
"github.com/hashicorp/boundary/internal/db"
2020-11-05 16:54:03 -05:00
"github.com/hashicorp/boundary/internal/errors"
2020-09-02 14:37:19 -04:00
wrapping "github.com/hashicorp/go-kms-wrapping"
)
// CreateSessionKeyVersion inserts into the repository and returns the new key
// version with its PrivateId. There are no valid options at this time.
2021-01-12 08:50:19 -08:00
func ( r * Repository ) CreateSessionKeyVersion ( ctx context . Context , rkvWrapper wrapping . Wrapper , sessionKeyId string , key [] byte , _ ... Option ) ( * SessionKeyVersion , error ) {
const op = "kms.(Repository).CreateSessionKeyVersion"
2020-09-02 14:37:19 -04:00
if rkvWrapper == nil {
2021-07-29 18:52:56 -06:00
return nil , errors . New ( ctx , errors . InvalidParameter , op , "missing root key version wrapper" )
2020-09-02 14:37:19 -04:00
}
rootKeyVersionId := rkvWrapper . KeyID ()
switch {
case ! strings . HasPrefix ( rootKeyVersionId , RootKeyVersionPrefix ):
2021-07-29 18:52:56 -06:00
return nil , errors . New ( ctx , errors . InvalidParameter , op , fmt . Sprintf ( "root key version id %s doesn't start with prefix %s" , rootKeyVersionId , RootKeyVersionPrefix ))
2020-09-02 14:37:19 -04:00
case rootKeyVersionId == "" :
2021-07-29 18:52:56 -06:00
return nil , errors . New ( ctx , errors . InvalidParameter , op , "missing root key version id" )
2020-09-02 14:37:19 -04:00
}
if sessionKeyId == "" {
2021-07-29 18:52:56 -06:00
return nil , errors . New ( ctx , errors . InvalidParameter , op , "missing session key id" )
2020-09-02 14:37:19 -04:00
}
if len ( key ) == 0 {
2021-07-29 18:52:56 -06:00
return nil , errors . New ( ctx , errors . InvalidParameter , op , "missing key" )
2020-09-02 14:37:19 -04:00
}
kv := AllocSessionKeyVersion ()
id , err := newSessionKeyVersionId ()
if err != nil {
2021-07-29 18:52:56 -06:00
return nil , errors . Wrap ( ctx , err , op )
2020-09-02 14:37:19 -04:00
}
kv . PrivateId = id
kv . RootKeyVersionId = rootKeyVersionId
kv . Key = key
kv . SessionKeyId = sessionKeyId
if err := kv . Encrypt ( ctx , rkvWrapper ); err != nil {
2021-07-29 18:52:56 -06:00
return nil , errors . Wrap ( ctx , err , op )
2020-09-02 14:37:19 -04:00
}
var returnedKey interface {}
_ , err = r . writer . DoTx (
ctx ,
db . StdRetryCnt ,
db . ExpBackoff {},
func ( _ db . Reader , w db . Writer ) error {
returnedKey = kv . Clone ()
// no session entries for root key version
if err := w . Create ( ctx , returnedKey ); err != nil {
2021-07-29 18:52:56 -06:00
return errors . Wrap ( ctx , err , op )
2020-09-02 14:37:19 -04:00
}
return nil
},
)
if err != nil {
2021-07-29 18:52:56 -06:00
return nil , errors . Wrap ( ctx , err , op , errors . WithMsg ( fmt . Sprintf ( "failed for %s session key id" , kv . SessionKeyId )))
2020-09-02 14:37:19 -04:00
}
2021-01-12 08:50:19 -08:00
return returnedKey .( * SessionKeyVersion ), nil
2020-09-02 14:37:19 -04:00
}
// LookupSessionKeyVersion will look up a key version in the repository. If
// the key version is not found, it will return nil, nil.
2021-01-12 08:50:19 -08:00
func ( r * Repository ) LookupSessionKeyVersion ( ctx context . Context , keyWrapper wrapping . Wrapper , privateId string , _ ... Option ) ( * SessionKeyVersion , error ) {
const op = "kms.(Repository).LookupSessionKeyVersion"
2020-09-02 14:37:19 -04:00
if privateId == "" {
2021-07-29 18:52:56 -06:00
return nil , errors . New ( ctx , errors . InvalidParameter , op , "missing private id" )
2020-09-02 14:37:19 -04:00
}
if keyWrapper == nil {
2021-07-29 18:52:56 -06:00
return nil , errors . New ( ctx , errors . InvalidParameter , op , "missing key wrapper" )
2020-09-02 14:37:19 -04:00
}
k := AllocSessionKeyVersion ()
k . PrivateId = privateId
if err := r . reader . LookupById ( ctx , & k ); err != nil {
2021-07-29 18:52:56 -06:00
return nil , errors . Wrap ( ctx , err , op , errors . WithMsg ( fmt . Sprintf ( "failed for %s" , privateId )))
2020-09-02 14:37:19 -04:00
}
if err := k . Decrypt ( ctx , keyWrapper ); err != nil {
2021-07-29 18:52:56 -06:00
return nil , errors . Wrap ( ctx , err , op )
2020-09-02 14:37:19 -04:00
}
return & k , nil
}
// DeleteSessionKeyVersion deletes the key version for the provided id from the
// repository returning a count of the number of records deleted. All options
// are ignored.
2021-01-12 08:50:19 -08:00
func ( r * Repository ) DeleteSessionKeyVersion ( ctx context . Context , privateId string , _ ... Option ) ( int , error ) {
const op = "kms.(Repository).DeleteSessionKeyVersion"
2020-09-02 14:37:19 -04:00
if privateId == "" {
2021-07-29 18:52:56 -06:00
return db . NoRowsAffected , errors . New ( ctx , errors . InvalidParameter , op , "missing private id" )
2020-09-02 14:37:19 -04:00
}
k := AllocSessionKeyVersion ()
k . PrivateId = privateId
if err := r . reader . LookupById ( ctx , & k ); err != nil {
2021-07-29 18:52:56 -06:00
return db . NoRowsAffected , errors . Wrap ( ctx , err , op , errors . WithMsg ( fmt . Sprintf ( "failed for %s" , privateId )))
2020-09-02 14:37:19 -04:00
}
var rowsDeleted int
_ , err := r . writer . DoTx (
ctx ,
db . StdRetryCnt ,
db . ExpBackoff {},
func ( _ db . Reader , w db . Writer ) ( err error ) {
dk := k . Clone ()
// no session entries for the key version
rowsDeleted , err = w . Delete ( ctx , dk )
2021-01-12 08:50:19 -08:00
if err != nil {
2021-07-29 18:52:56 -06:00
return errors . Wrap ( ctx , err , op )
2020-09-02 14:37:19 -04:00
}
2021-01-12 08:50:19 -08:00
if rowsDeleted > 1 {
2021-07-29 18:52:56 -06:00
return errors . New ( ctx , errors . MultipleRecords , op , "more than 1 resource would have been deleted" )
2021-01-12 08:50:19 -08:00
}
return nil
2020-09-02 14:37:19 -04:00
},
)
if err != nil {
2021-07-29 18:52:56 -06:00
return db . NoRowsAffected , errors . Wrap ( ctx , err , op , errors . WithMsg ( fmt . Sprintf ( "failed for %s" , privateId )))
2020-09-02 14:37:19 -04:00
}
return rowsDeleted , nil
}
// LatestSessionKeyVersion searches for the key version with the highest
2021-01-12 08:50:19 -08:00
// version number. When no results are found, it returns nil with an
// errors.RecordNotFound error.
func ( r * Repository ) LatestSessionKeyVersion ( ctx context . Context , rkvWrapper wrapping . Wrapper , sessionKeyId string , _ ... Option ) ( * SessionKeyVersion , error ) {
const op = "kms.(Repository).LatestSessionKeyVersion"
2020-09-02 14:37:19 -04:00
if sessionKeyId == "" {
2021-07-29 18:52:56 -06:00
return nil , errors . New ( ctx , errors . InvalidParameter , op , "missing session key id" )
2020-09-02 14:37:19 -04:00
}
if rkvWrapper == nil {
2021-07-29 18:52:56 -06:00
return nil , errors . New ( ctx , errors . InvalidParameter , op , "missing root key version wrapper" )
2020-09-02 14:37:19 -04:00
}
var foundKeys [] * SessionKeyVersion
if err := r . reader . SearchWhere ( ctx , & foundKeys , "session_key_id = ?" , [] interface {}{ sessionKeyId }, db . WithLimit ( 1 ), db . WithOrder ( "version desc" )); err != nil {
2021-07-29 18:52:56 -06:00
return nil , errors . Wrap ( ctx , err , op , errors . WithMsg ( fmt . Sprintf ( "failed for %s" , sessionKeyId )))
2020-09-02 14:37:19 -04:00
}
if len ( foundKeys ) == 0 {
2021-07-29 18:52:56 -06:00
return nil , errors . E ( ctx , errors . WithCode ( errors . RecordNotFound ), errors . WithOp ( op ))
2020-09-02 14:37:19 -04:00
}
if err := foundKeys [ 0 ]. Decrypt ( ctx , rkvWrapper ); err != nil {
2021-07-29 18:52:56 -06:00
return nil , errors . Wrap ( ctx , err , op )
2020-09-02 14:37:19 -04:00
}
return foundKeys [ 0 ], nil
}
// ListSessionKeyVersions will lists versions of a key. Supports the WithLimit option.
2020-09-03 13:23:46 -04:00
func ( r * Repository ) ListSessionKeyVersions ( ctx context . Context , rkvWrapper wrapping . Wrapper , sessionKeyId string , opt ... Option ) ([] DekVersion , error ) {
2021-01-12 08:50:19 -08:00
const op = "kms.(Repository).ListSessionKeyVersions"
2020-09-02 14:37:19 -04:00
if sessionKeyId == "" {
2021-07-29 18:52:56 -06:00
return nil , errors . New ( ctx , errors . InvalidParameter , op , "missing session key id" )
2020-09-02 14:37:19 -04:00
}
if rkvWrapper == nil {
2021-07-29 18:52:56 -06:00
return nil , errors . New ( ctx , errors . InvalidParameter , op , "missing root key version wrapper" )
2020-09-02 14:37:19 -04:00
}
var versions [] * SessionKeyVersion
err := r . list ( ctx , & versions , "session_key_id = ?" , [] interface {}{ sessionKeyId }, opt ... )
if err != nil {
2021-07-29 18:52:56 -06:00
return nil , errors . Wrap ( ctx , err , op )
2020-09-02 14:37:19 -04:00
}
for i , k := range versions {
if err := k . Decrypt ( ctx , rkvWrapper ); err != nil {
2021-07-29 18:52:56 -06:00
return nil , errors . Wrap ( ctx , err , op , errors . WithMsg ( fmt . Sprintf ( "error decrypting key num %d" , i )))
2020-09-02 14:37:19 -04:00
}
}
2020-09-03 13:23:46 -04:00
dekVersions := make ([] DekVersion , 0 , len ( versions ))
for _ , version := range versions {
dekVersions = append ( dekVersions , version )
}
return dekVersions , nil
2020-09-02 14:37:19 -04:00
}