Adding script for rewrapping p11 KEKs
This script pulls all project available KEKs and rewraps them with a MKEK specified in the barbican config file. Change-Id: I5f130b8f6d744195e3ed6c708e96b23b200eea2b
This commit is contained in:
parent
a2003a9c10
commit
9d5b06ba7e
143
barbican/cmd/pkcs11_kek_rewrap.py
Executable file
143
barbican/cmd/pkcs11_kek_rewrap.py
Executable file
@ -0,0 +1,143 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
import sqlalchemy
|
||||||
|
from sqlalchemy import orm
|
||||||
|
from sqlalchemy.orm import scoping
|
||||||
|
|
||||||
|
from barbican.common import utils
|
||||||
|
from barbican.model import models
|
||||||
|
from barbican.plugin.crypto import p11_crypto
|
||||||
|
|
||||||
|
# Use config values from p11_crypto
|
||||||
|
CONF = p11_crypto.CONF
|
||||||
|
|
||||||
|
|
||||||
|
class KekRewrap(object):
|
||||||
|
|
||||||
|
def __init__(self, db_connection, library_path, login, slot_id,
|
||||||
|
new_mkek_label):
|
||||||
|
self.dry_run = False
|
||||||
|
self.new_label = new_mkek_label
|
||||||
|
self.db_engine = sqlalchemy.create_engine(db_connection)
|
||||||
|
self._session_creator = scoping.scoped_session(
|
||||||
|
orm.sessionmaker(
|
||||||
|
bind=self.db_engine,
|
||||||
|
autocommit=True
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.crypto_plugin = p11_crypto.P11CryptoPlugin(CONF)
|
||||||
|
self.pkcs11 = self.crypto_plugin.pkcs11
|
||||||
|
self.plugin_name = utils.generate_fullname_for(self.crypto_plugin)
|
||||||
|
|
||||||
|
def rewrap_kek(self, project, kek):
|
||||||
|
with self.db_session.begin():
|
||||||
|
meta_dict = json.loads(kek.plugin_meta)
|
||||||
|
|
||||||
|
if self.dry_run:
|
||||||
|
msg = 'Would have unwrapped key with {} and rewrapped with {}'
|
||||||
|
print(msg.format(meta_dict['mkek_label'], self.new_label))
|
||||||
|
print('Would have updated KEKDatum in db {}'.format(kek.id))
|
||||||
|
|
||||||
|
else:
|
||||||
|
hsm_session = self.pkcs11.create_working_session()
|
||||||
|
|
||||||
|
print('Rewrapping KEK {}'.format(kek.id))
|
||||||
|
print('Pre-change IV: {}, Wrapped Key: {}'.format(
|
||||||
|
meta_dict['iv'], meta_dict['wrapped_key']))
|
||||||
|
|
||||||
|
updated_meta = self.pkcs11.rewrap_kek(
|
||||||
|
iv=meta_dict['iv'],
|
||||||
|
wrapped_key=meta_dict['wrapped_key'],
|
||||||
|
hmac=meta_dict['hmac'],
|
||||||
|
mkek_label=meta_dict['mkek_label'],
|
||||||
|
hmac_label=meta_dict['hmac_label'],
|
||||||
|
key_length=32,
|
||||||
|
session=hsm_session
|
||||||
|
)
|
||||||
|
|
||||||
|
self.pkcs11.close_session(hsm_session)
|
||||||
|
print('Post-change IV: {}, Wrapped Key: {}'.format(
|
||||||
|
updated_meta['iv'], updated_meta['wrapped_key']))
|
||||||
|
|
||||||
|
# Update KEK metadata in DB
|
||||||
|
kek.plugin_meta = json.dumps(updated_meta)
|
||||||
|
|
||||||
|
def get_keks_for_project(self, project):
|
||||||
|
keks = []
|
||||||
|
with self.db_session.begin() as transaction:
|
||||||
|
print('Retrieving KEKs for Project {}'.format(project.id))
|
||||||
|
query = transaction.session.query(models.KEKDatum)
|
||||||
|
query = query.filter_by(project_id=project.id)
|
||||||
|
query = query.filter_by(plugin_name=self.plugin_name)
|
||||||
|
|
||||||
|
keks = query.all()
|
||||||
|
|
||||||
|
return keks
|
||||||
|
|
||||||
|
def get_projects(self):
|
||||||
|
print('Retrieving all available projects')
|
||||||
|
|
||||||
|
projects = []
|
||||||
|
with self.db_session.begin() as transaction:
|
||||||
|
projects = transaction.session.query(models.Project).all()
|
||||||
|
|
||||||
|
return projects
|
||||||
|
|
||||||
|
@property
|
||||||
|
def db_session(self):
|
||||||
|
return self._session_creator()
|
||||||
|
|
||||||
|
def execute(self, dry_run=True):
|
||||||
|
self.dry_run = dry_run
|
||||||
|
if self.dry_run:
|
||||||
|
print('-- Running in dry-run mode --')
|
||||||
|
|
||||||
|
projects = self.get_projects()
|
||||||
|
for project in projects:
|
||||||
|
keks = self.get_keks_for_project(project)
|
||||||
|
for kek in keks:
|
||||||
|
try:
|
||||||
|
self.rewrap_kek(project, kek)
|
||||||
|
except Exception:
|
||||||
|
print('Error occurred! SQLAlchemy automatically rolled-'
|
||||||
|
'back the transaction')
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
script_desc = ('Utility to re-wrap project KEKs after rotating an MKEK.')
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description=script_desc)
|
||||||
|
parser.add_argument(
|
||||||
|
'--dry-run',
|
||||||
|
action='store_true',
|
||||||
|
help='Displays changes that will be made (Non-destructive)'
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
rewrapper = KekRewrap(
|
||||||
|
db_connection=CONF.sql_connection,
|
||||||
|
library_path=CONF.p11_crypto_plugin.library_path,
|
||||||
|
login=CONF.p11_crypto_plugin.login,
|
||||||
|
slot_id=CONF.p11_crypto_plugin.slot_id,
|
||||||
|
new_mkek_label=CONF.p11_crypto_plugin.mkek_label
|
||||||
|
)
|
||||||
|
rewrapper.execute(args.dry_run)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@ -485,7 +485,7 @@ class PKCS11(object):
|
|||||||
ck_attributes = self.build_attributes([
|
ck_attributes = self.build_attributes([
|
||||||
Attribute(CKA_CLASS, CKO_SECRET_KEY),
|
Attribute(CKA_CLASS, CKO_SECRET_KEY),
|
||||||
Attribute(CKA_KEY_TYPE, CKK_AES),
|
Attribute(CKA_KEY_TYPE, CKK_AES),
|
||||||
Attribute(CKA_LABEL, mkek_label)
|
Attribute(CKA_LABEL, str(mkek_label))
|
||||||
])
|
])
|
||||||
rv = self.lib.C_FindObjectsInit(
|
rv = self.lib.C_FindObjectsInit(
|
||||||
session, ck_attributes.template, len(ck_attributes.template)
|
session, ck_attributes.template, len(ck_attributes.template)
|
||||||
@ -542,6 +542,44 @@ class PKCS11(object):
|
|||||||
self.check_error(rv)
|
self.check_error(rv)
|
||||||
return object_handle_ptr[0]
|
return object_handle_ptr[0]
|
||||||
|
|
||||||
|
def rewrap_kek(self, iv, wrapped_key, hmac, mkek_label, hmac_label,
|
||||||
|
key_length, session):
|
||||||
|
unwrapped_kek = self.unwrap_key(iv, hmac, wrapped_key, mkek_label,
|
||||||
|
hmac_label, session)
|
||||||
|
mkek = self.key_handles[self.current_mkek_label]
|
||||||
|
|
||||||
|
iv = self.generate_random(16, session)
|
||||||
|
mech = self.ffi.new("CK_MECHANISM *")
|
||||||
|
mech.mechanism = CKM_AES_CBC_PAD
|
||||||
|
mech.parameter = iv
|
||||||
|
mech.parameter_len = 16
|
||||||
|
|
||||||
|
padded_length = key_length + self.block_size
|
||||||
|
|
||||||
|
buf = self.ffi.new("CK_BYTE[{0}]".format(padded_length))
|
||||||
|
buf_len = self.ffi.new("CK_ULONG *", padded_length)
|
||||||
|
|
||||||
|
rv = self.lib.C_WrapKey(
|
||||||
|
session,
|
||||||
|
mech,
|
||||||
|
mkek,
|
||||||
|
unwrapped_kek,
|
||||||
|
buf,
|
||||||
|
buf_len
|
||||||
|
)
|
||||||
|
self.check_error(rv)
|
||||||
|
|
||||||
|
wrapped_kek = self.ffi.buffer(buf, buf_len[0])[:]
|
||||||
|
hmac = self.compute_hmac(wrapped_kek, session)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'iv': base64.b64encode(self.ffi.buffer(iv)[:]),
|
||||||
|
'wrapped_key': base64.b64encode(wrapped_kek),
|
||||||
|
'hmac': base64.b64encode(hmac),
|
||||||
|
'mkek_label': self.current_mkek_label,
|
||||||
|
'hmac_label': self.current_hmac_label
|
||||||
|
}
|
||||||
|
|
||||||
def generate_wrapped_kek(self, kek_label, key_length, session):
|
def generate_wrapped_kek(self, kek_label, key_length, session):
|
||||||
# generate a non-persistent key that is extractable
|
# generate a non-persistent key that is extractable
|
||||||
ck_attributes = self.build_attributes([
|
ck_attributes = self.build_attributes([
|
||||||
|
@ -232,6 +232,34 @@ class WhenTestingP11CryptoPlugin(utils.BaseTestCase):
|
|||||||
self.assertEqual(self.lib.C_UnwrapKey.call_count, 1)
|
self.assertEqual(self.lib.C_UnwrapKey.call_count, 1)
|
||||||
self.assertEqual(self.lib.C_Verify.call_count, 1)
|
self.assertEqual(self.lib.C_Verify.call_count, 1)
|
||||||
|
|
||||||
|
def test_rewrap_kek(self):
|
||||||
|
plugin_meta = {
|
||||||
|
'iv': base64.b64encode(b"\x00" * 16),
|
||||||
|
'hmac': base64.b64encode(b"\x00" * 32),
|
||||||
|
'wrapped_key': base64.b64encode(b"\x00" * 48),
|
||||||
|
'mkek_label': 'mkek',
|
||||||
|
'hmac_label': 'hmac',
|
||||||
|
}
|
||||||
|
self.lib.C_WrapKey.return_value = pkcs11.CKR_OK
|
||||||
|
self.lib.C_UnwrapKey.return_value = pkcs11.CKR_OK
|
||||||
|
self.lib.C_VerifyInit.return_value = pkcs11.CKR_OK
|
||||||
|
self.lib.C_Verify.return_value = pkcs11.CKR_OK
|
||||||
|
self.lib.C_SignInit.return_value = pkcs11.CKR_OK
|
||||||
|
self.lib.C_Sign.return_value = pkcs11.CKR_OK
|
||||||
|
|
||||||
|
self.plugin.pkcs11.rewrap_kek(
|
||||||
|
plugin_meta['iv'],
|
||||||
|
plugin_meta['wrapped_key'],
|
||||||
|
plugin_meta['hmac'],
|
||||||
|
plugin_meta['mkek_label'],
|
||||||
|
plugin_meta['hmac'],
|
||||||
|
32,
|
||||||
|
self.test_session
|
||||||
|
)
|
||||||
|
self.assertEqual(self.lib.C_UnwrapKey.call_count, 1)
|
||||||
|
self.assertEqual(self.lib.C_WrapKey.call_count, 1)
|
||||||
|
self.assertEqual(self.lib.C_Verify.call_count, 1)
|
||||||
|
|
||||||
def test_generate_asymmetric_raises_error(self):
|
def test_generate_asymmetric_raises_error(self):
|
||||||
self.assertRaises(NotImplementedError,
|
self.assertRaises(NotImplementedError,
|
||||||
self.plugin.generate_asymmetric,
|
self.plugin.generate_asymmetric,
|
||||||
|
@ -27,6 +27,7 @@ console_scripts =
|
|||||||
barbican-keystone-listener = barbican.cmd.keystone_listener:main
|
barbican-keystone-listener = barbican.cmd.keystone_listener:main
|
||||||
barbican-worker = barbican.cmd.worker:main
|
barbican-worker = barbican.cmd.worker:main
|
||||||
barbican-worker-retry-scheduler = barbican.cmd.worker_retry_scheduler:main
|
barbican-worker-retry-scheduler = barbican.cmd.worker_retry_scheduler:main
|
||||||
|
pkcs11-kek-rewrap = barbican.cmd.pkcs11_kek_rewrap:main
|
||||||
|
|
||||||
barbican.secretstore.plugin =
|
barbican.secretstore.plugin =
|
||||||
store_crypto = barbican.plugin.store_crypto:StoreCryptoAdapterPlugin
|
store_crypto = barbican.plugin.store_crypto:StoreCryptoAdapterPlugin
|
||||||
|
Loading…
Reference in New Issue
Block a user