diff options
Diffstat (limited to 'src/mailman_pgp/pgp')
| -rw-r--r-- | src/mailman_pgp/pgp/__init__.py | 60 | ||||
| -rw-r--r-- | src/mailman_pgp/pgp/inline.py | 2 | ||||
| -rw-r--r-- | src/mailman_pgp/pgp/keygen.py | 28 | ||||
| -rw-r--r-- | src/mailman_pgp/pgp/mime.py | 2 | ||||
| -rw-r--r-- | src/mailman_pgp/pgp/tests/data/keys/ecc_curve25519.priv.asc | 15 | ||||
| -rw-r--r-- | src/mailman_pgp/pgp/tests/data/keys/ecc_curve25519.pub.asc | 14 | ||||
| -rw-r--r-- | src/mailman_pgp/pgp/tests/data/keys/ecc_secp256k1.priv.asc | 16 | ||||
| -rw-r--r-- | src/mailman_pgp/pgp/tests/data/keys/ecc_secp256k1.pub.asc | 15 | ||||
| -rw-r--r-- | src/mailman_pgp/pgp/tests/test_keygen.py | 38 |
9 files changed, 141 insertions, 49 deletions
diff --git a/src/mailman_pgp/pgp/__init__.py b/src/mailman_pgp/pgp/__init__.py index 31b61b3..b41c8a1 100644 --- a/src/mailman_pgp/pgp/__init__.py +++ b/src/mailman_pgp/pgp/__init__.py @@ -24,25 +24,29 @@ from os.path import join from mailman.config import config as mailman_config from mailman.utilities.string import expand from pgpy import PGPKeyring -from pgpy.constants import PubKeyAlgorithm +from pgpy.constants import PubKeyAlgorithm, EllipticCurveOID from public import public from mailman_pgp.config import config KEYDIR_CONFIG_PATHS = ['list_keydir', 'user_keydir', 'archive_keydir'] -KEYPAIR_CONFIG_VARIABLES = ['autogenerate', 'key_type', 'key_length', - 'subkey_type', 'subkey_length'] +KEYPAIR_CONFIG_VARIABLES = ['autogenerate', 'primary_key', 'sub_key'] -# The main key needs to support signing. -KEYPAIR_KEY_TYPE_VALID = ['RSA', 'DSA', 'ECDSA'] -# The subkey needs to support encryption. -KEYPAIR_SUBKEY_TYPE_VALID = ['RSA', 'ECDH'] KEYPAIR_TYPE_MAP = { 'RSA': PubKeyAlgorithm.RSAEncryptOrSign, 'DSA': PubKeyAlgorithm.DSA, 'ECDSA': PubKeyAlgorithm.ECDSA, 'ECDH': PubKeyAlgorithm.ECDH } +ECC_OID_MAP = { + 'nistp256': EllipticCurveOID.NIST_P256, + 'nistp384': EllipticCurveOID.NIST_P384, + 'nistp521': EllipticCurveOID.NIST_P521, + 'brainpoolP256r1': EllipticCurveOID.Brainpool_P256, + 'brainpoolP384r1': EllipticCurveOID.Brainpool_P384, + 'brainpoolP512r1': EllipticCurveOID.Brainpool_P512, + 'secp256k1': EllipticCurveOID.SECP256K1 +} @public @@ -56,7 +60,7 @@ class PGP: Load [keypairs] and [keydirs] config sections. Expand paths in them. """ # Get all the [keypairs] config variables. - self.keypair_config = dict( + self._keypair_config = dict( (k, config.get('keypairs', k)) for k in KEYPAIR_CONFIG_VARIABLES) @@ -66,25 +70,41 @@ class PGP: expand(config.get('keydirs', k), None, mailman_config.paths)) for k in KEYDIR_CONFIG_PATHS) + def _parse_key_directive(self, value): + key_type, key_length = value.split(':') + key_type = key_type.upper() + key_length = key_length.lower() + + if key_type not in KEYPAIR_TYPE_MAP: + raise ValueError('Invalid key type: {}.'.format(key_type)) + + out_type = KEYPAIR_TYPE_MAP[key_type] + if key_type in ('ECDSA', 'ECDH'): + if key_length not in ECC_OID_MAP: + raise ValueError('Invalid key length: {}.'.format(key_length)) + out_length = ECC_OID_MAP[key_length] + else: + out_length = int(key_length) + return (out_type, out_length) + def _validate_config(self): """ Validate [keypairs] and [keydirs] config sections. And create keydirs if necessary. """ # Validate keypair config. - key_type = self.keypair_config['key_type'].upper() - if key_type not in KEYPAIR_KEY_TYPE_VALID: - raise ValueError('Invalid key_type. {}'.format(key_type)) - self.keypair_config['key_type'] = KEYPAIR_TYPE_MAP[key_type] - self.keypair_config['key_length'] = int( - self.keypair_config['key_length']) + self.primary_key_args = self._parse_key_directive( + self._keypair_config['primary_key']) + if not self.primary_key_args[0].can_sign: + raise ValueError( + 'Invalid primary key type: {}.'.format( + self.primary_key_args[0])) - subkey_type = self.keypair_config['subkey_type'].upper() - if subkey_type not in KEYPAIR_SUBKEY_TYPE_VALID: - raise ValueError('Invalid subkey_type. {}'.format(subkey_type)) - self.keypair_config['subkey_type'] = KEYPAIR_TYPE_MAP[subkey_type] - self.keypair_config['subkey_length'] = int( - self.keypair_config['subkey_length']) + self.sub_key_args = self._parse_key_directive( + self._keypair_config['sub_key']) + if not self.sub_key_args[0].can_encrypt: + raise ValueError( + 'Invalid sub key type: {}.'.format(self.sub_key_args[0])) # Make sure the keydir paths are directories and exist. for keydir in self.keydir_config.values(): diff --git a/src/mailman_pgp/pgp/inline.py b/src/mailman_pgp/pgp/inline.py index 5c23777..d505585 100644 --- a/src/mailman_pgp/pgp/inline.py +++ b/src/mailman_pgp/pgp/inline.py @@ -229,7 +229,7 @@ class InlineWrapper: session_key = cipher.gen_key() for key in keys: emsg = key.encrypt(emsg, cipher=cipher, - session_key=session_key, + sessionkey=session_key, **kwargs) del session_key return emsg diff --git a/src/mailman_pgp/pgp/keygen.py b/src/mailman_pgp/pgp/keygen.py index b750e28..684b81a 100644 --- a/src/mailman_pgp/pgp/keygen.py +++ b/src/mailman_pgp/pgp/keygen.py @@ -29,36 +29,42 @@ from pgpy.constants import ( class ListKeyGenerator(mp.Process): """A multiprocessing list key generator.""" - def __init__(self, keypair_config, display_name, posting_address, + def __init__(self, primary_args, subkey_args, display_name, + posting_address, request_address, key_path): super().__init__( target=self.generate, - args=(keypair_config, display_name, posting_address, + args=(primary_args, subkey_args, display_name, posting_address, request_address, key_path), daemon=True) - def generate(self, keypair_config, display_name, posting_address, + def generate(self, primary_args, subkey_args, display_name, + posting_address, request_address, key_path): """ Generate the list keypair and save it. - :param keypair_config: + :param primary_args: + :param subkey_args: :param display_name: :param posting_address: :param request_address: :param key_path: """ - key = self._create(keypair_config, display_name, posting_address, + key = self._create(primary_args, subkey_args, display_name, + posting_address, request_address) with Lock(key_path + '.lock'): self._save(key, key_path) - def _create(self, config, display_name, posting_address, request_address): + def _create(self, primary_args, subkey_args, display_name, posting_address, + request_address): """ Generate the list `PGPKey` keypair, with posting and request UIDs. Use a Sign+Certify main key and Encrypt subkey. - :param config: + :param primary_args: + :param subkey_args: :param display_name: :param posting_address: :param request_address: @@ -79,9 +85,7 @@ class ListKeyGenerator(mp.Process): ) # Generate the Sign + Certify primary key. - key_type = config['key_type'] - key_length = config['key_length'] - key = PGPKey.new(key_type, key_length) + key = PGPKey.new(*primary_args) key_params = dict(usage={KeyFlags.Sign, KeyFlags.Certify}, **common_params) # Generate the posting + request uids. @@ -89,9 +93,7 @@ class ListKeyGenerator(mp.Process): request_uid = PGPUID.new(display_name, email=request_address) # Generate the Encrypt subkey. - subkey_type = config['subkey_type'] - subkey_length = config['subkey_length'] - subkey = PGPKey.new(subkey_type, subkey_length) + subkey = PGPKey.new(*subkey_args) subkey_params = dict( usage={KeyFlags.EncryptCommunications, KeyFlags.EncryptStorage}, diff --git a/src/mailman_pgp/pgp/mime.py b/src/mailman_pgp/pgp/mime.py index 3c28132..9978b54 100644 --- a/src/mailman_pgp/pgp/mime.py +++ b/src/mailman_pgp/pgp/mime.py @@ -267,7 +267,7 @@ class MIMEWrapper: session_key = cipher.gen_key() for key in keys: pmsg = key.encrypt(pmsg, cipher=cipher, - session_key=session_key, + sessionkey=session_key, **kwargs) del session_key return pmsg diff --git a/src/mailman_pgp/pgp/tests/data/keys/ecc_curve25519.priv.asc b/src/mailman_pgp/pgp/tests/data/keys/ecc_curve25519.priv.asc new file mode 100644 index 0000000..d66c89e --- /dev/null +++ b/src/mailman_pgp/pgp/tests/data/keys/ecc_curve25519.priv.asc @@ -0,0 +1,15 @@ +-----BEGIN PGP PRIVATE KEY BLOCK----- + +lFgEWW5OExYJKwYBBAHaRw8BAQdALuKQqg42UTUC9PP8Ahk7G3p4mYL0niRdheam +OKNm8wUAAQDYPq5Xlloj4NOhY1yKfpCo6oA2K2VxyY8zD61lDb2+AA9XtDxFQ0Mg +Q3VydmUyNTUxOSAmIEVDQyBDdXJ2ZTI1NTE5IDxFQ0MtQ3VydmUyNTUxOUBleGFt +cGxlLm9yZz6IkAQTFggAOBYhBAWwDrTl6xxIhCHhX/qZ76O408i6BQJZbk4TAhsD +BQsJCAcCBhUICQoLAgQWAgMBAh4BAheAAAoJEPqZ76O408i6nHwA/0suG6HBe2NY +URbNi9b6PQXuhq3sQkBmgAEwt8Yx4HnvAP9qvcN4n3Mv/1vkgSLJzpykffPxo6o4 +2FLQ4jX8yq/EAZxdBFluThMSCisGAQQBl1UBBQEBB0BxjGFvybmP7cfNqMKYCChx +ThAAO+iY8x6MJZ1sGCnxVgMBCAcAAP9OT1RocktFhCvYwTvISq7yd2f2kRxXooZ5 +gt5OJgF54BA2iHgEGBYIACAWIQQFsA605escSIQh4V/6me+juNPIugUCWW5OEwIb +DAAKCRD6me+juNPIumkgAP0YawFWdvFTUk9X0iHzZ0o82qnFU/yf1CpPNZ/00O6w +kAEA+6GQk7kTKq249456imoEY4MiHNz5JP1N/TLPBW/YOAQ= +=+yZA +-----END PGP PRIVATE KEY BLOCK----- diff --git a/src/mailman_pgp/pgp/tests/data/keys/ecc_curve25519.pub.asc b/src/mailman_pgp/pgp/tests/data/keys/ecc_curve25519.pub.asc new file mode 100644 index 0000000..43a5f17 --- /dev/null +++ b/src/mailman_pgp/pgp/tests/data/keys/ecc_curve25519.pub.asc @@ -0,0 +1,14 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mDMEWW5OExYJKwYBBAHaRw8BAQdALuKQqg42UTUC9PP8Ahk7G3p4mYL0niRdheam +OKNm8wW0PEVDQyBDdXJ2ZTI1NTE5ICYgRUNDIEN1cnZlMjU1MTkgPEVDQy1DdXJ2 +ZTI1NTE5QGV4YW1wbGUub3JnPoiQBBMWCAA4FiEEBbAOtOXrHEiEIeFf+pnvo7jT +yLoFAlluThMCGwMFCwkIBwIGFQgJCgsCBBYCAwECHgECF4AACgkQ+pnvo7jTyLqc +fAD/Sy4bocF7Y1hRFs2L1vo9Be6GrexCQGaAATC3xjHgee8A/2q9w3ifcy//W+SB +IsnOnKR98/GjqjjYUtDiNfzKr8QBuDgEWW5OExIKKwYBBAGXVQEFAQEHQHGMYW/J +uY/tx82owpgIKHFOEAA76JjzHowlnWwYKfFWAwEIB4h4BBgWCAAgFiEEBbAOtOXr +HEiEIeFf+pnvo7jTyLoFAlluThMCGwwACgkQ+pnvo7jTyLppIAD9GGsBVnbxU1JP +V9Ih82dKPNqpxVP8n9QqTzWf9NDusJABAPuhkJO5EyqtuPeOeopqBGODIhzc+ST9 +Tf0yzwVv2DgE +=pyIj +-----END PGP PUBLIC KEY BLOCK----- diff --git a/src/mailman_pgp/pgp/tests/data/keys/ecc_secp256k1.priv.asc b/src/mailman_pgp/pgp/tests/data/keys/ecc_secp256k1.priv.asc new file mode 100644 index 0000000..901a8f4 --- /dev/null +++ b/src/mailman_pgp/pgp/tests/data/keys/ecc_secp256k1.priv.asc @@ -0,0 +1,16 @@ +-----BEGIN PGP PRIVATE KEY BLOCK----- + +lHQEWW5dURMFK4EEAAoCAwT6ABKEPpMMwAQLnHkv+eSycNslonra5Kv7lNQtEeNv +VCXQELzmVGfcKerRVH6kFWpX9c1YxpdrG72Y5mHcRx30AAD/SLMJNXahzpcQy8K1 +XjDqdfCmYpMIFf87xIlZngmLNrkQnLQ5RUNDIHNlY3AyNTZrMSAmIEVDQyBzZWNw +MjU2azEgPEVDQy1zZWNwMjU2azFAZXhhbXBsZS5vcmc+iJAEExMIADgWIQRi7dSu +UMnX5cDo6nvIw1p/AFOkvwUCWW5dUQIbAwULCQgHAgYVCAkKCwIEFgIDAQIeAQIX +gAAKCRDIw1p/AFOkv1kGAP422qrlLxwcZgcZr1k/vJW1s0oYDBlHF2y/I+Q3Kvrs +jQEAjcl/jTBYJTcDBiIRbrzKQMPgj3lEL2R2v/x0d7CdKeeceARZbl1REgUrgQQA +CgIDBOlnr/5pUVGZBipSXZXsYmNaYQzQbG/YvuyJoH5v8n59AS5nQF+XVYVtAT19 +pq3stFGqg6uHrxlJvRHxv1QehVoDAQgHAAD9Elh7gUDS/UYfF5rMUDcjuAigDFVt +MqWIZ+qowNearR8PgYh4BBgTCAAgFiEEYu3UrlDJ1+XA6Op7yMNafwBTpL8FAllu +XVECGwwACgkQyMNafwBTpL9dBQEA1GRFrTIrx3o6+PdKNMSZSKLgsrocI2NGKI5b +XZe62kEA/0eWm6fha6T/wjCQ3befbeG9QA2aITv3XLa/va4ki6p5 +=boGQ +-----END PGP PRIVATE KEY BLOCK----- diff --git a/src/mailman_pgp/pgp/tests/data/keys/ecc_secp256k1.pub.asc b/src/mailman_pgp/pgp/tests/data/keys/ecc_secp256k1.pub.asc new file mode 100644 index 0000000..edd857a --- /dev/null +++ b/src/mailman_pgp/pgp/tests/data/keys/ecc_secp256k1.pub.asc @@ -0,0 +1,15 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mE8EWW5dURMFK4EEAAoCAwT6ABKEPpMMwAQLnHkv+eSycNslonra5Kv7lNQtEeNv +VCXQELzmVGfcKerRVH6kFWpX9c1YxpdrG72Y5mHcRx30tDlFQ0Mgc2VjcDI1Nmsx +ICYgRUNDIHNlY3AyNTZrMSA8RUNDLXNlY3AyNTZrMUBleGFtcGxlLm9yZz6IkAQT +EwgAOBYhBGLt1K5QydflwOjqe8jDWn8AU6S/BQJZbl1RAhsDBQsJCAcCBhUICQoL +AgQWAgMBAh4BAheAAAoJEMjDWn8AU6S/WQYA/jbaquUvHBxmBxmvWT+8lbWzShgM +GUcXbL8j5Dcq+uyNAQCNyX+NMFglNwMGIhFuvMpAw+CPeUQvZHa//HR3sJ0p57hT +BFluXVESBSuBBAAKAgME6Wev/mlRUZkGKlJdlexiY1phDNBsb9i+7Imgfm/yfn0B +LmdAX5dVhW0BPX2mrey0UaqDq4evGUm9EfG/VB6FWgMBCAeIeAQYEwgAIBYhBGLt +1K5QydflwOjqe8jDWn8AU6S/BQJZbl1RAhsMAAoJEMjDWn8AU6S/XQUBANRkRa0y +K8d6Ovj3SjTEmUii4LK6HCNjRiiOW12XutpBAP9Hlpun4Wuk/8IwkN23n23hvUAN +miE791y2v72uJIuqeQ== +=ryPP +-----END PGP PUBLIC KEY BLOCK----- diff --git a/src/mailman_pgp/pgp/tests/test_keygen.py b/src/mailman_pgp/pgp/tests/test_keygen.py index dab6801..bbd0c84 100644 --- a/src/mailman_pgp/pgp/tests/test_keygen.py +++ b/src/mailman_pgp/pgp/tests/test_keygen.py @@ -15,32 +15,42 @@ # You should have received a copy of the GNU General Public License along with # this program. If not, see <http://www.gnu.org/licenses/>. +"""Test the out-of-process key generator.""" from os.path import exists, isfile, join from tempfile import TemporaryDirectory from unittest import TestCase +from parameterized import parameterized from pgpy import PGPKey -from pgpy.constants import PubKeyAlgorithm +from pgpy.constants import PubKeyAlgorithm, EllipticCurveOID from mailman_pgp.pgp.keygen import ListKeyGenerator -class TesKeygen(TestCase): +class TestKeygen(TestCase): def setUp(self): - self.keypair_config = { - 'key_type': PubKeyAlgorithm.RSAEncryptOrSign, - 'key_length': 1024, - 'subkey_type': PubKeyAlgorithm.RSAEncryptOrSign, - 'subkey_length': 1024 - } self.display_name = 'Display Name' self.posting_address = 'posting@address.com' self.request_address = 'posting-request@address.com' - def test_generate(self): + @parameterized.expand([ + # RSA + RSA + (PubKeyAlgorithm.RSAEncryptOrSign, 1024, + PubKeyAlgorithm.RSAEncryptOrSign, 1024), + # ECDSA + ECDH + (PubKeyAlgorithm.ECDSA, EllipticCurveOID.SECP256K1, + PubKeyAlgorithm.ECDH, EllipticCurveOID.SECP256K1), + # DSA + ECDH + (PubKeyAlgorithm.DSA, 1024, + PubKeyAlgorithm.ECDH, EllipticCurveOID.SECP256K1) + ]) + def test_generate(self, primary_key_type, primary_key_size, sub_key_type, + sub_key_size): with TemporaryDirectory() as temp_dir: key_path = join(temp_dir, 'key.asc') - keygen = ListKeyGenerator(self.keypair_config, self.display_name, + keygen = ListKeyGenerator((primary_key_type, primary_key_size), + (sub_key_type, sub_key_size), + self.display_name, self.posting_address, self.request_address, key_path) keygen.start() @@ -50,18 +60,18 @@ class TesKeygen(TestCase): key, _ = PGPKey.from_file(key_path) self.assertEqual(key.key_algorithm, - self.keypair_config['key_type']) + primary_key_type) self.assertEqual(key.key_size, - self.keypair_config['key_length']) + primary_key_size) subs = key.subkeys self.assertEqual(len(subs), 1) keyid, sub = subs.popitem() self.assertEqual(sub.key_algorithm, - self.keypair_config['subkey_type']) + sub_key_type) self.assertEqual(sub.key_size, - self.keypair_config['subkey_length']) + sub_key_size) uids = key.userids self.assertEqual(len(uids), 2) |
