Skip to content

Commit

Permalink
- Refactored REST server to be a simple repoze.bfg application.
Browse files Browse the repository at this point in the history
- The encrypted data encrypting keys (DEKs) are now stored in a directory
  instead of the ZODB. This increases transparency in the data store and makes
  backups easier.
  • Loading branch information
strichter committed Sep 29, 2010
1 parent 55b8f22 commit 143eb48
Show file tree
Hide file tree
Showing 21 changed files with 415 additions and 474 deletions.
8 changes: 6 additions & 2 deletions CHANGES.txt
Expand Up @@ -2,10 +2,14 @@
CHANGES
=======

1.1.2 (unreleased)
2.0.0 (unreleased)
------------------

- Nothing changed yet.
- Refactored REST server to be a simple repoze.bfg application.

- The encrypted data encrypting keys (DEKs) are now stored in a directory
instead of the ZODB. This increases transparency in the data store and makes
backups easier.


1.1.1 (2010-08-27)
Expand Down
24 changes: 9 additions & 15 deletions buildout.cfg
@@ -1,7 +1,8 @@
[buildout]
develop = .
extends = http://download.zope.org/bluebream/bluebream-1.0b3.cfg
parts = test coverage-test coverage-report python paster runserver testclient ctags
parts = test coverage-test coverage-report python paster runserver testclient
ctags
versions = versions

[test]
Expand All @@ -11,12 +12,12 @@ eggs = keas.kmi [test]
[coverage-test]
recipe = zc.recipe.testrunner
eggs = keas.kmi [test]
defaults = ['--coverage', '../../coverage']
defaults = ['--coverage', '${buildout:directory}/coverage']

[coverage-report]
recipe = zc.recipe.egg
eggs = z3c.coverage
scripts = coverage=coverage-report
scripts = coveragereport=coverage-report
arguments = ('coverage', 'coverage/report')

[python]
Expand All @@ -30,19 +31,11 @@ eggs = keas.kmi

[paster]
recipe = zc.recipe.egg
eggs = Paste
PasteScript
PasteDeploy
dependent-scripts = true
eggs = keas.kmi
Paste
pyOpenSSL
zope.app.component
zope.app.publication
zope.app.publisher
zope.app.security
zope.component
zope.error
zope.publisher
zope.securitypolicy
keas.kmi
scripts = paster

[runserver]
recipe = zc.recipe.egg
Expand All @@ -57,3 +50,4 @@ eggs = keas.kmi
[versions]
setuptools = 0.6c12dev-r84273
zc.buildout = 1.5.0
zc.recipe.egg = 1.3.0
36 changes: 35 additions & 1 deletion server.ini
@@ -1,9 +1,43 @@
[app:main]
use = egg:keas.kmi
conf=zope.conf
storage-dir=keys/

[server:main]
use = egg:Paste#http
host = 0.0.0.0
port = 8080
ssl_pem = sample.pem

# Logging Configuration
[loggers]
keys = root, kmi

[handlers]
keys = console, file

[formatters]
keys = generic

[logger_root]
level = WARN
handlers = console

[logger_kmi]
level = INFO
handlers = console
propagate = 0
qualname = kmi

[handler_file]
class = FileHandler
args = ('source-cache.log',)
formatter = generic

[handler_console]
class = StreamHandler
args = (sys.stdout,)
formatter = generic

[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s] %(message)s
datefmt= %Y-%m-%d %H:%M:%S
15 changes: 5 additions & 10 deletions setup.py
Expand Up @@ -22,7 +22,7 @@ def read(*rnames):

setup (
name='keas.kmi',
version = '1.1.2dev',
version = '2.0.0dev',
author = "Stephan Richter and the Zope Community",
author_email = "zope-dev@zope.org",
description = "A Key Management Infrastructure",
Expand All @@ -36,7 +36,7 @@ def read(*rnames):
read('CHANGES.txt')
),
license = "ZPL 2.1",
keywords = "zope3 security key management infrastructure nist 800-57",
keywords = "security key management infrastructure nist 800-57",
classifiers = [
'Development Status :: 5 - Production/Stable',
'Environment :: Web Environment',
Expand All @@ -46,7 +46,7 @@ def read(*rnames):
'Natural Language :: English',
'Operating System :: OS Independent',
'Topic :: Internet :: WWW/HTTP',
'Framework :: Zope3'],
'Framework :: Repoze'],
url = 'http://pypi.python.org/pypi/keas.kmi',
packages = find_packages('src'),
include_package_data = True,
Expand All @@ -60,14 +60,9 @@ def read(*rnames):
),
install_requires = [
'M2Crypto',
'ZODB3',
'repoze.bfg',
'setuptools',
'z3c.rest',
'zope.app.wsgi',
'zope.annotation',
'zope.component',
'zope.container',
'zope.dublincore',
'transaction',
'zope.interface',
'zope.schema',
],
Expand Down
79 changes: 41 additions & 38 deletions src/keas/kmi/README.txt
Expand Up @@ -4,10 +4,14 @@ Key Management Infrastructure

This package provides a NIST SP 800-57 compliant key management
infrastructure. Part of this infrastructure is a key management facility that
provides several services related to keys.
provides several services related to keys. All keys are stored in a specified
storage directory.

>>> import tempfile
>>> storage_dir = tempfile.mkdtemp()

>>> from keas.kmi import facility
>>> keys = facility.KeyManagementFacility()
>>> keys = facility.KeyManagementFacility(storage_dir)
>>> keys
<KeyManagementFacility (0)>

Expand Down Expand Up @@ -67,8 +71,8 @@ You can now use this key encrypting key to extract the encryption keys:
... from md5 import md5
>>> hash = md5(key)

>>> keys.get(hash.hexdigest())
<Key ...>
>>> len(keys.get(hash.hexdigest()))
64

Our key management facility also supports the encryption service, which allows
you to encrypt and decrypt a string given the key encrypting key.
Expand Down Expand Up @@ -214,13 +218,10 @@ key.
So let's have a look at the call:

>>> from keas.kmi import rest
>>> from zope.publisher.browser import TestRequest

>>> request = TestRequest()
>>> request.method = 'POST'
>>> from webob import Request

>>> newCall = rest.NewView(keys, request)
>>> key3 = newCall()
>>> request = Request({})
>>> key3 = rest.create_key(keys, request).body
>>> print key3
-----BEGIN RSA PRIVATE KEY-----
...
Expand All @@ -229,7 +230,6 @@ So let's have a look at the call:
The key is available in the facility of course:

>>> hash = md5(key3)

>>> hash.hexdigest() in keys
True

Expand All @@ -240,39 +240,27 @@ We can now fetch the encryption key pair using a `POST` call to this URL::
The request sends the key encrypting key in its body. The response is the
encryption key string:

>>> import cStringIO
>>> io = cStringIO.StringIO(key3)

>>> request = TestRequest(io)
>>> request.method = 'POST'
>>> request = Request({})
>>> request.body = key3

>>> keyCall = rest.KeyView(keys, request)
>>> encKey = keyCall()
>>> len(encKey)
>>> encKey = rest.get_key(keys, request)
>>> len(encKey.body)
32

If you try to request a nonexistent key, you get a 404 error:
encryption key string:

>>> import cStringIO
>>> io = cStringIO.StringIO('xyzzy')
If you try to request a nonexistent key, you get a 404 error: encryption key
string:

>>> request = TestRequest(io)
>>> request.method = 'POST'

>>> keyCall = rest.KeyView(keys, request)
>>> print keyCall()
>>> request.body = 'xxyz'
>>> print rest.get_key(keys, request)
Key not found
>>> request.response.getStatus()
404

A `GET` request to the root shows us a server status page

>>> request = TestRequest()
>>> request.method = 'GET'

>>> newCall = rest.StatusView(keys, request)
>>> print newCall()
>>> print rest.get_status(keys, Request({}))
200 OK
Content-Type: text/plain
Content-Length: 25
<BLANKLINE>
KMS server holding 3 keys


Expand All @@ -283,7 +271,8 @@ The testing facility only manages a single key that is always constant. This
allows you to install a testing facility globally, not storing the keys in the
database and still reuse a ZODB over multiple sessions.

>>> testingKeys = testing.TestingKeyManagementFacility()
>>> storage_dir = tempfile.mkdtemp()
>>> testingKeys = testing.TestingKeyManagementFacility(storage_dir)

Of course, the key generation service is supported:

Expand All @@ -299,7 +288,9 @@ However, you will always receive the same key:
'MIIBOAIBAAJBAL+VS9lDsS9XOaeJppfK9lhxKMRFdcg50MR3aJEQK9rvDEqNwBS9'
>>> getKeySegment(testingKeys.generate())
'MIIBOAIBAAJBAL+VS9lDsS9XOaeJppfK9lhxKMRFdcg50MR3aJEQK9rvDEqNwBS9'
>>> testingKeys = testing.TestingKeyManagementFacility()

>>> storage_dir = tempfile.mkdtemp()
>>> testingKeys = testing.TestingKeyManagementFacility(storage_dir)
>>> getKeySegment(testingKeys.generate())
'MIIBOAIBAAJBAL+VS9lDsS9XOaeJppfK9lhxKMRFdcg50MR3aJEQK9rvDEqNwBS9'

Expand All @@ -314,3 +305,15 @@ We can also safely en- and decrypt:
>>> encrypted = testingKeys.encrypt(key, 'Stephan Richter')
>>> testingKeys.decrypt(key, encrypted)
'Stephan Richter'


Key Holder
----------

The key holder is a simple class designed to store a key in RAM:

>>> from keas.kmi import keyholder
>>> holder = keyholder.KeyHolder(__file__)

>>> verify.verifyObject(interfaces.IKeyHolder, holder)
True
19 changes: 0 additions & 19 deletions src/keas/kmi/apidoc.zcml

This file was deleted.

21 changes: 0 additions & 21 deletions src/keas/kmi/application.py

This file was deleted.

50 changes: 0 additions & 50 deletions src/keas/kmi/application.zcml

This file was deleted.

0 comments on commit 143eb48

Please sign in to comment.