Merge "Adding script for rewrapping p11 KEKs"
This commit is contained in:
commit
84cc3f7a38
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([
|
||||
Attribute(CKA_CLASS, CKO_SECRET_KEY),
|
||||
Attribute(CKA_KEY_TYPE, CKK_AES),
|
||||
Attribute(CKA_LABEL, mkek_label)
|
||||
Attribute(CKA_LABEL, str(mkek_label))
|
||||
])
|
||||
rv = self.lib.C_FindObjectsInit(
|
||||
session, ck_attributes.template, len(ck_attributes.template)
|
||||
@ -542,6 +542,44 @@ class PKCS11(object):
|
||||
self.check_error(rv)
|
||||
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):
|
||||
# generate a non-persistent key that is extractable
|
||||
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_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):
|
||||
self.assertRaises(NotImplementedError,
|
||||
self.plugin.generate_asymmetric,
|
||||
|
@ -27,6 +27,7 @@ console_scripts =
|
||||
barbican-keystone-listener = barbican.cmd.keystone_listener:main
|
||||
barbican-worker = barbican.cmd.worker:main
|
||||
barbican-worker-retry-scheduler = barbican.cmd.worker_retry_scheduler:main
|
||||
pkcs11-kek-rewrap = barbican.cmd.pkcs11_kek_rewrap:main
|
||||
|
||||
barbican.secretstore.plugin =
|
||||
store_crypto = barbican.plugin.store_crypto:StoreCryptoAdapterPlugin
|
||||
|
Loading…
Reference in New Issue
Block a user