2020-09-02 07:42:03 -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 07:42:03 -04:00
wrapping "github.com/hashicorp/go-kms-wrapping"
)
// CreateDatabaseKeyVersion 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 ) CreateDatabaseKeyVersion ( ctx context . Context , rkvWrapper wrapping . Wrapper , databaseKeyId string , key [] byte , _ ... Option ) ( * DatabaseKeyVersion , error ) {
const op = "kms.(Repository).CreateDatabaseKeyVersion"
2020-09-02 07:42:03 -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 07:42:03 -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 07:42:03 -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 07:42:03 -04:00
}
if databaseKeyId == "" {
2021-07-29 18:52:56 -06:00
return nil , errors . New ( ctx , errors . InvalidParameter , op , "missing database key id" )
2020-09-02 07:42:03 -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 07:42:03 -04:00
}
kv := AllocDatabaseKeyVersion ()
id , err := newDatabaseKeyVersionId ()
if err != nil {
2021-07-29 18:52:56 -06:00
return nil , errors . Wrap ( ctx , err , op )
2020-09-02 07:42:03 -04:00
}
kv . PrivateId = id
kv . RootKeyVersionId = rootKeyVersionId
kv . Key = key
kv . DatabaseKeyId = databaseKeyId
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 07:42:03 -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 oplog 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 07:42:03 -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 database key id" , kv . DatabaseKeyId )))
2020-09-02 07:42:03 -04:00
}
2021-01-12 08:50:19 -08:00
return returnedKey .( * DatabaseKeyVersion ), nil
2020-09-02 07:42:03 -04:00
}
// LookupDatabaseKeyVersion 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 ) LookupDatabaseKeyVersion ( ctx context . Context , keyWrapper wrapping . Wrapper , privateId string , _ ... Option ) ( * DatabaseKeyVersion , error ) {
const op = "kms.(Repository).LookupDatabaseKeyVersion"
2020-09-02 07:42:03 -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 07:42:03 -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 07:42:03 -04:00
}
k := AllocDatabaseKeyVersion ()
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 07:42:03 -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 07:42:03 -04:00
}
return & k , nil
}
// DeleteDatabaseKeyVersion 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 ) DeleteDatabaseKeyVersion ( ctx context . Context , privateId string , _ ... Option ) ( int , error ) {
const op = "kms.(Repository).DeleteDatabaseKeyVersion"
2020-09-02 07:42:03 -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 07:42:03 -04:00
}
k := AllocDatabaseKeyVersion ()
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 07:42:03 -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 oplog 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 07:42:03 -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 07:42:03 -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 07:42:03 -04:00
}
return rowsDeleted , nil
}
// LatestDatabaseKeyVersion 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 ) LatestDatabaseKeyVersion ( ctx context . Context , rkvWrapper wrapping . Wrapper , databaseKeyId string , _ ... Option ) ( * DatabaseKeyVersion , error ) {
const op = "kms.(Repository).LatestDatabaseKeyVersion"
2020-09-02 07:42:03 -04:00
if databaseKeyId == "" {
2021-07-29 18:52:56 -06:00
return nil , errors . New ( ctx , errors . InvalidParameter , op , "missing database key id" )
2020-09-02 07:42:03 -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 07:42:03 -04:00
}
var foundKeys [] * DatabaseKeyVersion
if err := r . reader . SearchWhere ( ctx , & foundKeys , "database_key_id = ?" , [] interface {}{ databaseKeyId }, 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" , databaseKeyId )))
2020-09-02 07:42:03 -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 07:42:03 -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 07:42:03 -04:00
}
return foundKeys [ 0 ], nil
}
// ListDatabaseKeyVersions will lists versions of a key. Supports the WithLimit option.
2020-09-03 13:23:46 -04:00
func ( r * Repository ) ListDatabaseKeyVersions ( ctx context . Context , rkvWrapper wrapping . Wrapper , databaseKeyId string , opt ... Option ) ([] DekVersion , error ) {
2021-01-12 08:50:19 -08:00
const op = "kms.(Repository).ListDatabaseKeyVersions"
2020-09-02 07:42:03 -04:00
if databaseKeyId == "" {
2021-07-29 18:52:56 -06:00
return nil , errors . New ( ctx , errors . InvalidParameter , op , "missing database key id" )
2020-09-02 07:42:03 -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 07:42:03 -04:00
}
var versions [] * DatabaseKeyVersion
err := r . list ( ctx , & versions , "database_key_id = ?" , [] interface {}{ databaseKeyId }, opt ... )
if err != nil {
2021-07-29 18:52:56 -06:00
return nil , errors . Wrap ( ctx , err , op )
2020-09-02 07:42:03 -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 07:42:03 -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 07:42:03 -04:00
}