summaryrefslogtreecommitdiffstats
path: root/ipaserver/install
diff options
context:
space:
mode:
authorNathaniel McCallum <npmccallum@redhat.com>2015-08-31 10:46:19 -0400
committerMartin Basti <mbasti@redhat.com>2017-03-01 12:51:50 +0100
commitd00ae870dda2889545c9d93e82e44526bfd4f431 (patch)
treef068d2206b2ae6cb614a0f5a12e2b091b53f26eb /ipaserver/install
parent3be696c92f6948ea0ced9784920600b73703e414 (diff)
downloadfreeipa-d00ae870dda2889545c9d93e82e44526bfd4f431.tar.gz
freeipa-d00ae870dda2889545c9d93e82e44526bfd4f431.tar.xz
freeipa-d00ae870dda2889545c9d93e82e44526bfd4f431.zip
Migrate OTP import script to python-cryptography
https://fedorahosted.org/freeipa/ticket/5192 Reviewed-By: Stanislav Laznicka <slaznick@redhat.com>
Diffstat (limited to 'ipaserver/install')
-rw-r--r--ipaserver/install/ipa_otptoken_import.py104
1 files changed, 42 insertions, 62 deletions
diff --git a/ipaserver/install/ipa_otptoken_import.py b/ipaserver/install/ipa_otptoken_import.py
index 552fdfb03..3b2e52ab2 100644
--- a/ipaserver/install/ipa_otptoken_import.py
+++ b/ipaserver/install/ipa_otptoken_import.py
@@ -29,11 +29,15 @@ import struct
from lxml import etree
import dateutil.parser
import dateutil.tz
-import nss.nss as nss
import gssapi
import six
from six.moves import xrange
+from cryptography.hazmat.primitives import hashes
+from cryptography.hazmat.primitives.kdf import pbkdf2
+from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
+from cryptography.hazmat.backends import default_backend
+
from ipaplatform.paths import paths
from ipapython import admintool
from ipalib import api, errors
@@ -119,13 +123,13 @@ def convertAlgorithm(value):
"Converts encryption URI to (mech, ivlen)."
return {
- "http://www.w3.org/2001/04/xmlenc#aes128-cbc": (nss.CKM_AES_CBC_PAD, 128),
- "http://www.w3.org/2001/04/xmlenc#aes192-cbc": (nss.CKM_AES_CBC_PAD, 192),
- "http://www.w3.org/2001/04/xmlenc#aes256-cbc": (nss.CKM_AES_CBC_PAD, 256),
- "http://www.w3.org/2001/04/xmlenc#tripledes-cbc": (nss.CKM_DES3_CBC_PAD, 64),
- "http://www.w3.org/2001/04/xmldsig-more#camellia128": (nss.CKM_CAMELLIA_CBC_PAD, 128),
- "http://www.w3.org/2001/04/xmldsig-more#camellia192": (nss.CKM_CAMELLIA_CBC_PAD, 192),
- "http://www.w3.org/2001/04/xmldsig-more#camellia256": (nss.CKM_CAMELLIA_CBC_PAD, 256),
+ "http://www.w3.org/2001/04/xmlenc#aes128-cbc": (algorithms.AES, modes.CBC, 128),
+ "http://www.w3.org/2001/04/xmlenc#aes192-cbc": (algorithms.AES, modes.CBC, 192),
+ "http://www.w3.org/2001/04/xmlenc#aes256-cbc": (algorithms.AES, modes.CBC, 256),
+ "http://www.w3.org/2001/04/xmlenc#tripledes-cbc": (algorithms.TripleDES, modes.CBC, 64),
+ "http://www.w3.org/2001/04/xmldsig-more#camellia128": (algorithms.Camellia, modes.CBC, 128),
+ "http://www.w3.org/2001/04/xmldsig-more#camellia192": (algorithms.Camellia, modes.CBC, 192),
+ "http://www.w3.org/2001/04/xmldsig-more#camellia256": (algorithms.Camellia, modes.CBC, 256),
# TODO: add support for these formats.
# "http://www.w3.org/2001/04/xmlenc#kw-aes128": "kw-aes128",
@@ -135,7 +139,7 @@ def convertAlgorithm(value):
# "http://www.w3.org/2001/04/xmldsig-more#kw-camellia128": "kw-camellia128",
# "http://www.w3.org/2001/04/xmldsig-more#kw-camellia192": "kw-camellia192",
# "http://www.w3.org/2001/04/xmldsig-more#kw-camellia256": "kw-camellia256",
- }.get(value.lower(), (None, None))
+ }.get(value.lower(), (None, None, None))
def convertEncrypted(value, decryptor=None, pconv=base64.b64decode, econv=lambda x: x):
@@ -170,50 +174,29 @@ class PBKDF2KeyDerivation(XMLKeyDerivation):
if params is None:
raise ValueError("XML file is missing PBKDF2 parameters!")
- self.salt = fetch(params, "./xenc11:Salt/xenc11:Specified/text()", base64.b64decode)
- self.iter = fetch(params, "./xenc11:IterationCount/text()", int)
- self.klen = fetch(params, "./xenc11:KeyLength/text()", int)
- self.hmod = fetch(params, "./xenc11:PRF/@Algorithm", convertHMACType, hashlib.sha1)
+ salt = fetch(params, "./xenc11:Salt/xenc11:Specified/text()", base64.b64decode)
+ itrs = fetch(params, "./xenc11:IterationCount/text()", int)
+ klen = fetch(params, "./xenc11:KeyLength/text()", int)
+ hmod = fetch(params, "./xenc11:PRF/@Algorithm", convertHMACType, hashlib.sha1)
- if self.salt is None:
+ if salt is None:
raise ValueError("XML file is missing PBKDF2 salt!")
- if self.iter is None:
+ if itrs is None:
raise ValueError("XML file is missing PBKDF2 iteration count!")
- if self.klen is None:
+ if klen is None:
raise ValueError("XML file is missing PBKDF2 key length!")
- def derive(self, masterkey):
- mac = hmac.HMAC(masterkey, None, self.hmod)
-
- # Figure out how many blocks we will have to combine
- # to expand the master key to the desired length.
- blocks = self.klen // mac.digest_size
- if self.klen % mac.digest_size != 0:
- blocks += 1
-
- # Loop through each block adding it to the derived key.
- dk = []
- for i in range(1, blocks + 1):
- # Set initial values.
- last = self.salt + struct.pack('>I', i)
- hash = [0] * mac.digest_size
+ self.kdf = pbkdf2.PBKDF2HMAC(
+ algorithm=hmod,
+ length=klen,
+ salt=salt,
+ iterations=itrs
+ )
- # Perform n iterations.
- for _j in xrange(self.iter):
- tmp = mac.copy()
- tmp.update(last)
- last = tmp.digest()
-
- # XOR the previous hash with the new hash.
- for k in range(mac.digest_size):
- hash[k] ^= ord(last[k])
-
- # Add block to derived key.
- dk.extend(hash)
-
- return ''.join([chr(c) for c in dk])[:self.klen]
+ def derive(self, masterkey):
+ return self.kdf.derive(masterkey)
def convertKeyDerivation(value):
@@ -230,13 +213,17 @@ class XMLDecryptor(object):
* RFC 6931"""
def __init__(self, key, hmac=None):
- self.__key = nss.SecItem(key)
+ self.__key = key
self.__hmac = hmac
def __call__(self, element, mac=None):
- (mech, ivlen) = fetch(element, "./xenc:EncryptionMethod/@Algorithm", convertAlgorithm)
+ (algo, mode, klen) = fetch(element, "./xenc:EncryptionMethod/@Algorithm", convertAlgorithm)
data = fetch(element, "./xenc:CipherData/xenc:CipherValue/text()", base64.b64decode)
+ # Make sure the key is the right length.
+ if len(self.__key) * 8 != klen:
+ raise ValidationError("Invalid key length!")
+
# If a MAC is present, perform validation.
if mac:
tmp = self.__hmac.copy()
@@ -244,13 +231,14 @@ class XMLDecryptor(object):
if tmp.digest() != mac:
raise ValidationError("MAC validation failed!")
- # Decrypt the data.
- slot = nss.get_best_slot(mech)
- key = nss.import_sym_key(slot, mech, nss.PK11_OriginUnwrap, nss.CKA_ENCRYPT, self.__key)
- iv = nss.param_from_iv(mech, nss.SecItem(data[0:ivlen//8]))
- ctx = nss.create_context_by_sym_key(mech, nss.CKA_DECRYPT, key, iv)
- out = ctx.cipher_op(data[ivlen // 8:])
- out += ctx.digest_final()
+ iv = data[:algo.block_size / 8]
+ data = data[len(iv):]
+
+ cipher = Cipher(algo(self.__key), mode(iv))
+ decryptor = cipher.decryptor()
+
+ out = decryptor.update(data)
+ out += decryptor.finalize()
return out
@@ -470,14 +458,6 @@ class OTPTokenImport(admintool.AdminTool):
usage = "%prog [options] <PSKC file> <output file>"
@classmethod
- def main(cls, argv):
- nss.nss_init_nodb()
- try:
- super(OTPTokenImport, cls).main(argv)
- finally:
- nss.nss_shutdown()
-
- @classmethod
def add_options(cls, parser):
super(OTPTokenImport, cls).add_options(parser)