You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
906 lines
32 KiB
906 lines
32 KiB
diff -uNr ansible-2.3.0.0.ORIG/lib/ansible/executor/process/worker.py ansible-2.3.0.0/lib/ansible/executor/process/worker.py
|
|
--- ansible-2.3.0.0.ORIG/lib/ansible/executor/process/worker.py 2017-05-23 14:23:12.313595450 +0100
|
|
+++ ansible-2.3.0.0/lib/ansible/executor/process/worker.py 2017-05-23 14:24:22.116598926 +0100
|
|
@@ -26,14 +26,6 @@
|
|
|
|
from jinja2.exceptions import TemplateNotFound
|
|
|
|
-# TODO: not needed if we use the cryptography library with its default RNG
|
|
-# engine
|
|
-HAS_ATFORK=True
|
|
-try:
|
|
- from Crypto.Random import atfork
|
|
-except ImportError:
|
|
- HAS_ATFORK=False
|
|
-
|
|
from ansible.errors import AnsibleConnectionFailure
|
|
from ansible.executor.task_executor import TaskExecutor
|
|
from ansible.executor.task_result import TaskResult
|
|
@@ -95,9 +87,6 @@
|
|
#pr = cProfile.Profile()
|
|
#pr.enable()
|
|
|
|
- if HAS_ATFORK:
|
|
- atfork()
|
|
-
|
|
try:
|
|
# execute the task and build a TaskResult from the result
|
|
display.debug("running TaskExecutor() for %s/%s" % (self._host, self._task))
|
|
diff -uNr ansible-2.3.0.0.ORIG/lib/ansible/modules/cloud/amazon/ec2_win_password.py ansible-2.3.0.0/lib/ansible/modules/cloud/amazon/ec2_win_password.py
|
|
--- ansible-2.3.0.0.ORIG/lib/ansible/modules/cloud/amazon/ec2_win_password.py 2017-05-23 14:23:12.299595449 +0100
|
|
+++ ansible-2.3.0.0/lib/ansible/modules/cloud/amazon/ec2_win_password.py 2017-05-23 14:29:51.003615305 +0100
|
|
@@ -93,9 +93,10 @@
|
|
'''
|
|
|
|
from base64 import b64decode
|
|
-from Crypto.Cipher import PKCS1_v1_5
|
|
-from Crypto.PublicKey import RSA
|
|
import datetime
|
|
+from cryptography.hazmat.backends import default_backend
|
|
+from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15
|
|
+from cryptography.hazmat.primitives.serialization import load_pem_private_key
|
|
|
|
try:
|
|
import boto.ec2
|
|
@@ -103,6 +104,9 @@
|
|
except ImportError:
|
|
HAS_BOTO = False
|
|
|
|
+BACKEND = default_backend()
|
|
+
|
|
+
|
|
def main():
|
|
argument_spec = ec2_argument_spec()
|
|
argument_spec.update(dict(
|
|
@@ -151,15 +155,12 @@
|
|
else:
|
|
try:
|
|
with f:
|
|
- key = RSA.importKey(f.read(), key_passphrase)
|
|
- except (ValueError, IndexError, TypeError) as e:
|
|
+ key = load_pem_private_key(f.read(), key_passphrase, BACKEND)
|
|
+ except (ValueError, TypeError) as e:
|
|
module.fail_json(msg = "unable to parse key file")
|
|
|
|
- cipher = PKCS1_v1_5.new(key)
|
|
- sentinel = 'password decryption failed!!!'
|
|
-
|
|
try:
|
|
- decrypted = cipher.decrypt(decoded, sentinel)
|
|
+ decrypted = key.decrypt(decoded, PKCS1v15())
|
|
except ValueError as e:
|
|
decrypted = None
|
|
|
|
diff -uNr ansible-2.3.0.0.ORIG/lib/ansible/parsing/vault/__init__.py ansible-2.3.0.0/lib/ansible/parsing/vault/__init__.py
|
|
--- ansible-2.3.0.0.ORIG/lib/ansible/parsing/vault/__init__.py 2017-05-23 14:23:12.311595449 +0100
|
|
+++ ansible-2.3.0.0/lib/ansible/parsing/vault/__init__.py 2017-05-23 14:31:23.267619901 +0100
|
|
@@ -25,7 +25,6 @@
|
|
import sys
|
|
import tempfile
|
|
import random
|
|
-from io import BytesIO
|
|
from subprocess import call
|
|
from hashlib import sha256
|
|
from binascii import hexlify
|
|
@@ -35,32 +34,14 @@
|
|
# Note: Only used for loading obsolete VaultAES files. All files are written
|
|
# using the newer VaultAES256 which does not require md5
|
|
|
|
-try:
|
|
- from Crypto.Hash import SHA256, HMAC
|
|
- HAS_HASH = True
|
|
-except ImportError:
|
|
- HAS_HASH = False
|
|
-
|
|
-# Counter import fails for 2.0.1, requires >= 2.6.1 from pip
|
|
-try:
|
|
- from Crypto.Util import Counter
|
|
- HAS_COUNTER = True
|
|
-except ImportError:
|
|
- HAS_COUNTER = False
|
|
-
|
|
-# KDF import fails for 2.0.1, requires >= 2.6.1 from pip
|
|
-try:
|
|
- from Crypto.Protocol.KDF import PBKDF2
|
|
- HAS_PBKDF2 = True
|
|
-except ImportError:
|
|
- HAS_PBKDF2 = False
|
|
-
|
|
-# AES IMPORTS
|
|
-try:
|
|
- from Crypto.Cipher import AES as AES
|
|
- HAS_AES = True
|
|
-except ImportError:
|
|
- HAS_AES = False
|
|
+from cryptography.exceptions import InvalidSignature
|
|
+from cryptography.hazmat.backends import default_backend
|
|
+from cryptography.hazmat.primitives import hashes, padding
|
|
+from cryptography.hazmat.primitives.hmac import HMAC
|
|
+from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
|
+from cryptography.hazmat.primitives.ciphers import (
|
|
+ Cipher as C_Cipher, algorithms, modes
|
|
+)
|
|
|
|
from ansible.compat.six import PY3, binary_type
|
|
from ansible.compat.six.moves import zip
|
|
@@ -73,26 +54,8 @@
|
|
from ansible.utils.display import Display
|
|
display = Display()
|
|
|
|
-# OpenSSL pbkdf2_hmac
|
|
-HAS_PBKDF2HMAC = False
|
|
-try:
|
|
- from cryptography.hazmat.primitives.hashes import SHA256 as c_SHA256
|
|
- from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
|
- from cryptography.hazmat.backends import default_backend
|
|
- HAS_PBKDF2HMAC = True
|
|
-except ImportError:
|
|
- pass
|
|
-except Exception as e:
|
|
- display.vvvv("Optional dependency 'cryptography' raised an exception, falling back to 'Crypto'.")
|
|
- import traceback
|
|
- display.vvvv("Traceback from import of cryptography was {0}".format(traceback.format_exc()))
|
|
-
|
|
-HAS_ANY_PBKDF2HMAC = HAS_PBKDF2 or HAS_PBKDF2HMAC
|
|
-
|
|
-
|
|
-CRYPTO_UPGRADE = "ansible-vault requires a newer version of pycrypto than the one installed on your platform." \
|
|
- " You may fix this with OS-specific commands such as: yum install python-devel; rpm -e --nodeps python-crypto; pip install pycrypto"
|
|
|
|
+BACKEND = default_backend()
|
|
b_HEADER = b'$ANSIBLE_VAULT'
|
|
CIPHER_WHITELIST = frozenset((u'AES', u'AES256'))
|
|
CIPHER_WRITE_WHITELIST = frozenset((u'AES256',))
|
|
@@ -100,12 +63,6 @@
|
|
# (used in VaultFile header) to a cipher class
|
|
|
|
|
|
-def check_prereqs():
|
|
-
|
|
- if not HAS_AES or not HAS_COUNTER or not HAS_ANY_PBKDF2HMAC or not HAS_HASH:
|
|
- raise AnsibleError(CRYPTO_UPGRADE)
|
|
-
|
|
-
|
|
class AnsibleVaultError(AnsibleError):
|
|
pass
|
|
|
|
@@ -410,8 +367,6 @@
|
|
|
|
def encrypt_file(self, filename, output_file=None):
|
|
|
|
- check_prereqs()
|
|
-
|
|
# A file to be encrypted into a vaultfile could be any encoding
|
|
# so treat the contents as a byte string.
|
|
|
|
@@ -424,8 +379,6 @@
|
|
|
|
def decrypt_file(self, filename, output_file=None):
|
|
|
|
- check_prereqs()
|
|
-
|
|
# follow the symlink
|
|
filename = os.path.realpath(filename)
|
|
|
|
@@ -440,8 +393,6 @@
|
|
def create_file(self, filename):
|
|
""" create a new encrypted file """
|
|
|
|
- check_prereqs()
|
|
-
|
|
# FIXME: If we can raise an error here, we can probably just make it
|
|
# behave like edit instead.
|
|
if os.path.isfile(filename):
|
|
@@ -451,8 +402,6 @@
|
|
|
|
def edit_file(self, filename):
|
|
|
|
- check_prereqs()
|
|
-
|
|
# follow the symlink
|
|
filename = os.path.realpath(filename)
|
|
|
|
@@ -471,7 +420,6 @@
|
|
|
|
def plaintext(self, filename):
|
|
|
|
- check_prereqs()
|
|
ciphertext = self.read_data(filename)
|
|
|
|
try:
|
|
@@ -483,8 +431,6 @@
|
|
|
|
def rekey_file(self, filename, b_new_password):
|
|
|
|
- check_prereqs()
|
|
-
|
|
# follow the symlink
|
|
filename = os.path.realpath(filename)
|
|
|
|
@@ -581,10 +527,6 @@
|
|
|
|
# Note: strings in this class should be byte strings by default.
|
|
|
|
- def __init__(self):
|
|
- if not HAS_AES:
|
|
- raise AnsibleError(CRYPTO_UPGRADE)
|
|
-
|
|
def _aes_derive_key_and_iv(self, b_password, b_salt, key_length, iv_length):
|
|
|
|
""" Create a key and an initialization vector """
|
|
@@ -620,41 +562,22 @@
|
|
' switch to the newer VaultAES256 format', version='2.3')
|
|
# http://stackoverflow.com/a/14989032
|
|
|
|
- b_ciphertext = unhexlify(b_vaulttext)
|
|
-
|
|
- in_file = BytesIO(b_ciphertext)
|
|
- in_file.seek(0)
|
|
- out_file = BytesIO()
|
|
+ b_vaultdata = unhexlify(b_vaulttext)
|
|
+ b_tmpsalt = b_vaultdata[:16]
|
|
+ b_ciphertext = b_vaultdata[16:]
|
|
|
|
- bs = AES.block_size
|
|
- b_tmpsalt = in_file.read(bs)
|
|
+ bs = algorithms.AES.block_size // 8
|
|
b_salt = b_tmpsalt[len(b'Salted__'):]
|
|
b_key, b_iv = self._aes_derive_key_and_iv(b_password, b_salt, key_length, bs)
|
|
- cipher = AES.new(b_key, AES.MODE_CBC, b_iv)
|
|
- b_next_chunk = b''
|
|
- finished = False
|
|
-
|
|
- while not finished:
|
|
- b_chunk, b_next_chunk = b_next_chunk, cipher.decrypt(in_file.read(1024 * bs))
|
|
- if len(b_next_chunk) == 0:
|
|
- if PY3:
|
|
- padding_length = b_chunk[-1]
|
|
- else:
|
|
- padding_length = ord(b_chunk[-1])
|
|
+ cipher = C_Cipher(algorithms.AES(b_key), modes.CBC(b_iv), BACKEND).decryptor()
|
|
+ unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder()
|
|
|
|
- b_chunk = b_chunk[:-padding_length]
|
|
- finished = True
|
|
-
|
|
- out_file.write(b_chunk)
|
|
- out_file.flush()
|
|
-
|
|
- # reset the stream pointer to the beginning
|
|
- out_file.seek(0)
|
|
- b_out_data = out_file.read()
|
|
- out_file.close()
|
|
+ b_plaintext = unpadder.update(
|
|
+ cipher.update(b_ciphertext) + cipher.finalize()
|
|
+ ) + unpadder.finalize()
|
|
|
|
# split out sha and verify decryption
|
|
- b_split_data = b_out_data.split(b"\n", 1)
|
|
+ b_split_data = b_plaintext.split(b"\n", 1)
|
|
b_this_sha = b_split_data[0]
|
|
b_plaintext = b_split_data[1]
|
|
b_test_sha = to_bytes(sha256(b_plaintext).hexdigest())
|
|
@@ -676,19 +599,16 @@
|
|
|
|
# Note: strings in this class should be byte strings by default.
|
|
|
|
- def __init__(self):
|
|
-
|
|
- check_prereqs()
|
|
-
|
|
@staticmethod
|
|
def _create_key(b_password, b_salt, keylength, ivlength):
|
|
- hash_function = SHA256
|
|
-
|
|
- # make two keys and one iv
|
|
- pbkdf2_prf = lambda p, s: HMAC.new(p, s, hash_function).digest()
|
|
+ kdf = PBKDF2HMAC(
|
|
+ algorithm=hashes.SHA256(),
|
|
+ length=2 * keylength + ivlength,
|
|
+ salt=b_salt,
|
|
+ iterations=10000,
|
|
+ backend=BACKEND)
|
|
+ b_derivedkey = kdf.derive(b_password)
|
|
|
|
- b_derivedkey = PBKDF2(b_password, b_salt, dkLen=(2 * keylength) + ivlength,
|
|
- count=10000, prf=pbkdf2_prf)
|
|
return b_derivedkey
|
|
|
|
@classmethod
|
|
@@ -696,55 +616,31 @@
|
|
# 16 for AES 128, 32 for AES256
|
|
keylength = 32
|
|
|
|
- # match the size used for counter.new to avoid extra work
|
|
- ivlength = 16
|
|
+ # AES is a 128-bit block cipher, so IVs and counter nonces are 16 bytes
|
|
+ ivlength = algorithms.AES.block_size // 8
|
|
|
|
- if HAS_PBKDF2HMAC:
|
|
- backend = default_backend()
|
|
- kdf = PBKDF2HMAC(
|
|
- algorithm=c_SHA256(),
|
|
- length=2 * keylength + ivlength,
|
|
- salt=b_salt,
|
|
- iterations=10000,
|
|
- backend=backend)
|
|
- b_derivedkey = kdf.derive(b_password)
|
|
- else:
|
|
- b_derivedkey = cls._create_key(b_password, b_salt, keylength, ivlength)
|
|
+ b_derivedkey = cls._create_key(b_password, b_salt, keylength, ivlength)
|
|
|
|
b_key1 = b_derivedkey[:keylength]
|
|
b_key2 = b_derivedkey[keylength:(keylength * 2)]
|
|
b_iv = b_derivedkey[(keylength * 2):(keylength * 2) + ivlength]
|
|
|
|
- return b_key1, b_key2, hexlify(b_iv)
|
|
+ return b_key1, b_key2, b_iv
|
|
|
|
def encrypt(self, b_plaintext, b_password):
|
|
b_salt = os.urandom(32)
|
|
b_key1, b_key2, b_iv = self._gen_key_initctr(b_password, b_salt)
|
|
|
|
- # PKCS#7 PAD DATA http://tools.ietf.org/html/rfc5652#section-6.3
|
|
- bs = AES.block_size
|
|
- padding_length = (bs - len(b_plaintext) % bs) or bs
|
|
- b_plaintext += to_bytes(padding_length * chr(padding_length), encoding='ascii', errors='strict')
|
|
-
|
|
- # COUNTER.new PARAMETERS
|
|
- # 1) nbits (integer) - Length of the counter, in bits.
|
|
- # 2) initial_value (integer) - initial value of the counter. "iv" from _gen_key_initctr
|
|
-
|
|
- ctr = Counter.new(128, initial_value=int(b_iv, 16))
|
|
-
|
|
- # AES.new PARAMETERS
|
|
- # 1) AES key, must be either 16, 24, or 32 bytes long -- "key" from _gen_key_initctr
|
|
- # 2) MODE_CTR, is the recommended mode
|
|
- # 3) counter=<CounterObject>
|
|
-
|
|
- cipher = AES.new(b_key1, AES.MODE_CTR, counter=ctr)
|
|
-
|
|
- # ENCRYPT PADDED DATA
|
|
- b_ciphertext = cipher.encrypt(b_plaintext)
|
|
+ cipher = C_Cipher(algorithms.AES(b_key1), modes.CTR(b_iv), BACKEND)
|
|
+ encryptor = cipher.encryptor()
|
|
+ padder = padding.PKCS7(algorithms.AES.block_size).padder()
|
|
+ b_ciphertext = encryptor.update(padder.update(b_plaintext) + padder.finalize())
|
|
+ b_ciphertext += encryptor.finalize()
|
|
|
|
# COMBINE SALT, DIGEST AND DATA
|
|
- hmac = HMAC.new(b_key2, b_ciphertext, SHA256)
|
|
- b_vaulttext = b'\n'.join([hexlify(b_salt), to_bytes(hmac.hexdigest()), hexlify(b_ciphertext)])
|
|
+ hmac = HMAC(b_key2, hashes.SHA256(), BACKEND)
|
|
+ hmac.update(b_ciphertext)
|
|
+ b_vaulttext = b'\n'.join([hexlify(b_salt), hexlify(hmac.finalize()), hexlify(b_ciphertext)])
|
|
b_vaulttext = hexlify(b_vaulttext)
|
|
return b_vaulttext
|
|
|
|
@@ -757,48 +653,21 @@
|
|
b_key1, b_key2, b_iv = self._gen_key_initctr(b_password, b_salt)
|
|
|
|
# EXIT EARLY IF DIGEST DOESN'T MATCH
|
|
- hmacDecrypt = HMAC.new(b_key2, b_ciphertext, SHA256)
|
|
- if not self._is_equal(b_cryptedHmac, to_bytes(hmacDecrypt.hexdigest())):
|
|
+ hmac = HMAC(b_key2, hashes.SHA256(), BACKEND)
|
|
+ hmac.update(b_ciphertext)
|
|
+ try:
|
|
+ hmac.verify(unhexlify(b_cryptedHmac))
|
|
+ except InvalidSignature:
|
|
return None
|
|
- # SET THE COUNTER AND THE CIPHER
|
|
- ctr = Counter.new(128, initial_value=int(b_iv, 16))
|
|
- cipher = AES.new(b_key1, AES.MODE_CTR, counter=ctr)
|
|
-
|
|
- # DECRYPT PADDED DATA
|
|
- b_plaintext = cipher.decrypt(b_ciphertext)
|
|
-
|
|
- # UNPAD DATA
|
|
- if PY3:
|
|
- padding_length = b_plaintext[-1]
|
|
- else:
|
|
- padding_length = ord(b_plaintext[-1])
|
|
|
|
- b_plaintext = b_plaintext[:-padding_length]
|
|
- return b_plaintext
|
|
+ cipher = C_Cipher(algorithms.AES(b_key1), modes.CTR(b_iv), BACKEND)
|
|
+ decryptor = cipher.decryptor()
|
|
+ unpadder = padding.PKCS7(128).unpadder()
|
|
+ b_plaintext = unpadder.update(
|
|
+ decryptor.update(b_ciphertext) + decryptor.finalize()
|
|
+ ) + unpadder.finalize()
|
|
|
|
- @staticmethod
|
|
- def _is_equal(b_a, b_b):
|
|
- """
|
|
- Comparing 2 byte arrrays in constant time
|
|
- to avoid timing attacks.
|
|
-
|
|
- It would be nice if there was a library for this but
|
|
- hey.
|
|
- """
|
|
- if not (isinstance(b_a, binary_type) and isinstance(b_b, binary_type)):
|
|
- raise TypeError('_is_equal can only be used to compare two byte strings')
|
|
-
|
|
- # http://codahale.com/a-lesson-in-timing-attacks/
|
|
- if len(b_a) != len(b_b):
|
|
- return False
|
|
-
|
|
- result = 0
|
|
- for b_x, b_y in zip(b_a, b_b):
|
|
- if PY3:
|
|
- result |= b_x ^ b_y
|
|
- else:
|
|
- result |= ord(b_x) ^ ord(b_y)
|
|
- return result == 0
|
|
+ return b_plaintext
|
|
|
|
|
|
# Keys could be made bytes later if the code that gets the data is more
|
|
diff -uNr ansible-2.3.0.0.ORIG/test/runner/requirements/integration.txt ansible-2.3.0.0/test/runner/requirements/integration.txt
|
|
--- ansible-2.3.0.0.ORIG/test/runner/requirements/integration.txt 2017-05-23 14:23:12.379595453 +0100
|
|
+++ ansible-2.3.0.0/test/runner/requirements/integration.txt 2017-05-23 14:24:22.118598926 +0100
|
|
@@ -1,8 +1,8 @@
|
|
+cryptography
|
|
jinja2
|
|
jmespath
|
|
junit-xml
|
|
ordereddict ; python_version < '2.7'
|
|
paramiko
|
|
passlib
|
|
-pycrypto
|
|
pyyaml
|
|
diff -uNr ansible-2.3.0.0.ORIG/test/runner/requirements/network-integration.txt ansible-2.3.0.0/test/runner/requirements/network-integration.txt
|
|
--- ansible-2.3.0.0.ORIG/test/runner/requirements/network-integration.txt 2017-05-23 14:23:12.379595453 +0100
|
|
+++ ansible-2.3.0.0/test/runner/requirements/network-integration.txt 2017-05-23 14:24:22.119598926 +0100
|
|
@@ -1,5 +1,5 @@
|
|
+cryptography
|
|
jinja2
|
|
junit-xml
|
|
paramiko
|
|
-pycrypto
|
|
pyyaml
|
|
diff -uNr ansible-2.3.0.0.ORIG/test/runner/requirements/sanity.txt ansible-2.3.0.0/test/runner/requirements/sanity.txt
|
|
--- ansible-2.3.0.0.ORIG/test/runner/requirements/sanity.txt 2017-05-23 14:23:12.379595453 +0100
|
|
+++ ansible-2.3.0.0/test/runner/requirements/sanity.txt 2017-05-23 14:26:01.910603896 +0100
|
|
@@ -1,5 +1,7 @@
|
|
+cryptography
|
|
jinja2
|
|
mock
|
|
+paramiko
|
|
pep8
|
|
pylint
|
|
pytest
|
|
diff -uNr ansible-2.3.0.0.ORIG/test/runner/requirements/units.txt ansible-2.3.0.0/test/runner/requirements/units.txt
|
|
--- ansible-2.3.0.0.ORIG/test/runner/requirements/units.txt 2017-05-23 14:23:12.379595453 +0100
|
|
+++ ansible-2.3.0.0/test/runner/requirements/units.txt 2017-05-23 14:24:22.119598926 +0100
|
|
@@ -1,10 +1,10 @@
|
|
boto
|
|
boto3
|
|
+cryptography
|
|
jinja2
|
|
mock
|
|
nose
|
|
passlib
|
|
-pycrypto
|
|
pytest
|
|
pytest-mock
|
|
pytest-xdist
|
|
diff -uNr ansible-2.3.0.0.ORIG/test/runner/requirements/windows-integration.txt ansible-2.3.0.0/test/runner/requirements/windows-integration.txt
|
|
--- ansible-2.3.0.0.ORIG/test/runner/requirements/windows-integration.txt 2017-05-23 14:23:12.379595453 +0100
|
|
+++ ansible-2.3.0.0/test/runner/requirements/windows-integration.txt 2017-05-23 14:24:22.119598926 +0100
|
|
@@ -1,4 +1,6 @@
|
|
+cryptography
|
|
jinja2
|
|
junit-xml
|
|
+paramiko
|
|
pywinrm
|
|
pyyaml
|
|
diff -uNr ansible-2.3.0.0.ORIG/test/units/parsing/vault/test_vault_editor.py ansible-2.3.0.0/test/units/parsing/vault/test_vault_editor.py
|
|
--- ansible-2.3.0.0.ORIG/test/units/parsing/vault/test_vault_editor.py 2017-05-23 14:23:12.324595450 +0100
|
|
+++ ansible-2.3.0.0/test/units/parsing/vault/test_vault_editor.py 2017-05-23 14:24:22.120598926 +0100
|
|
@@ -22,7 +22,6 @@
|
|
|
|
import os
|
|
import tempfile
|
|
-from nose.plugins.skip import SkipTest
|
|
|
|
from ansible.compat.tests import unittest
|
|
from ansible.compat.tests.mock import patch
|
|
@@ -32,27 +31,6 @@
|
|
from ansible.module_utils._text import to_bytes, to_text
|
|
|
|
|
|
-# Counter import fails for 2.0.1, requires >= 2.6.1 from pip
|
|
-try:
|
|
- from Crypto.Util import Counter
|
|
- HAS_COUNTER = True
|
|
-except ImportError:
|
|
- HAS_COUNTER = False
|
|
-
|
|
-# KDF import fails for 2.0.1, requires >= 2.6.1 from pip
|
|
-try:
|
|
- from Crypto.Protocol.KDF import PBKDF2
|
|
- HAS_PBKDF2 = True
|
|
-except ImportError:
|
|
- HAS_PBKDF2 = False
|
|
-
|
|
-# AES IMPORTS
|
|
-try:
|
|
- from Crypto.Cipher import AES as AES
|
|
- HAS_AES = True
|
|
-except ImportError:
|
|
- HAS_AES = False
|
|
-
|
|
v10_data = """$ANSIBLE_VAULT;1.0;AES
|
|
53616c7465645f5fd0026926a2d415a28a2622116273fbc90e377225c12a347e1daf4456d36a77f9
|
|
9ad98d59f61d06a4b66718d855f16fb7bdfe54d1ec8aeaa4d06c2dc1fa630ae1846a029877f0eeb1
|
|
@@ -423,9 +401,6 @@
|
|
|
|
def test_decrypt_1_0(self):
|
|
# Skip testing decrypting 1.0 files if we don't have access to AES, KDF or Counter.
|
|
- if not HAS_AES or not HAS_COUNTER or not HAS_PBKDF2:
|
|
- raise SkipTest
|
|
-
|
|
v10_file = tempfile.NamedTemporaryFile(delete=False)
|
|
with v10_file as f:
|
|
f.write(to_bytes(v10_data))
|
|
@@ -451,9 +426,6 @@
|
|
assert fdata.strip() == "foo", "incorrect decryption of 1.0 file: %s" % fdata.strip()
|
|
|
|
def test_decrypt_1_1(self):
|
|
- if not HAS_AES or not HAS_COUNTER or not HAS_PBKDF2:
|
|
- raise SkipTest
|
|
-
|
|
v11_file = tempfile.NamedTemporaryFile(delete=False)
|
|
with v11_file as f:
|
|
f.write(to_bytes(v11_data))
|
|
@@ -478,10 +450,6 @@
|
|
assert fdata.strip() == "foo", "incorrect decryption of 1.0 file: %s" % fdata.strip()
|
|
|
|
def test_rekey_migration(self):
|
|
- # Skip testing rekeying files if we don't have access to AES, KDF or Counter.
|
|
- if not HAS_AES or not HAS_COUNTER or not HAS_PBKDF2:
|
|
- raise SkipTest
|
|
-
|
|
v10_file = tempfile.NamedTemporaryFile(delete=False)
|
|
with v10_file as f:
|
|
f.write(to_bytes(v10_data))
|
|
diff -uNr ansible-2.3.0.0.ORIG/test/units/parsing/vault/test_vault.py ansible-2.3.0.0/test/units/parsing/vault/test_vault.py
|
|
--- ansible-2.3.0.0.ORIG/test/units/parsing/vault/test_vault.py 2017-05-23 14:23:12.324595450 +0100
|
|
+++ ansible-2.3.0.0/test/units/parsing/vault/test_vault.py 2017-05-23 14:24:22.120598926 +0100
|
|
@@ -38,28 +38,6 @@
|
|
from ansible.module_utils._text import to_bytes, to_text
|
|
|
|
|
|
-# Counter import fails for 2.0.1, requires >= 2.6.1 from pip
|
|
-try:
|
|
- from Crypto.Util import Counter
|
|
- HAS_COUNTER = True
|
|
-except ImportError:
|
|
- HAS_COUNTER = False
|
|
-
|
|
-# KDF import fails for 2.0.1, requires >= 2.6.1 from pip
|
|
-try:
|
|
- from Crypto.Protocol.KDF import PBKDF2
|
|
- HAS_PBKDF2 = True
|
|
-except ImportError:
|
|
- HAS_PBKDF2 = False
|
|
-
|
|
-# AES IMPORTS
|
|
-try:
|
|
- from Crypto.Cipher import AES as AES
|
|
- HAS_AES = True
|
|
-except ImportError:
|
|
- HAS_AES = False
|
|
-
|
|
-
|
|
class TestVaultIsEncrypted(unittest.TestCase):
|
|
def test_bytes_not_encrypted(self):
|
|
b_data = b"foobar"
|
|
@@ -181,38 +159,6 @@
|
|
self.assertIsInstance(b_key, six.binary_type)
|
|
self.assertEqual(b_key, b_key_2)
|
|
|
|
- def test_is_equal_is_equal(self):
|
|
- self.assertTrue(self.vault_cipher._is_equal(b'abcdefghijklmnopqrstuvwxyz', b'abcdefghijklmnopqrstuvwxyz'))
|
|
-
|
|
- def test_is_equal_unequal_length(self):
|
|
- self.assertFalse(self.vault_cipher._is_equal(b'abcdefghijklmnopqrstuvwxyz', b'abcdefghijklmnopqrstuvwx and sometimes y'))
|
|
-
|
|
- def test_is_equal_not_equal(self):
|
|
- self.assertFalse(self.vault_cipher._is_equal(b'abcdefghijklmnopqrstuvwxyz', b'AbcdefghijKlmnopQrstuvwxZ'))
|
|
-
|
|
- def test_is_equal_empty(self):
|
|
- self.assertTrue(self.vault_cipher._is_equal(b'', b''))
|
|
-
|
|
- def test_is_equal_non_ascii_equal(self):
|
|
- utf8_data = to_bytes(u'私はガラスを食べられます。それは私を傷つけません。')
|
|
- self.assertTrue(self.vault_cipher._is_equal(utf8_data, utf8_data))
|
|
-
|
|
- def test_is_equal_non_ascii_unequal(self):
|
|
- utf8_data = to_bytes(u'私はガラスを食べられます。それは私を傷つけません。')
|
|
- utf8_data2 = to_bytes(u'Pot să mănânc sticlă și ea nu mă rănește.')
|
|
-
|
|
- # Test for the len optimization path
|
|
- self.assertFalse(self.vault_cipher._is_equal(utf8_data, utf8_data2))
|
|
- # Test for the slower, char by char comparison path
|
|
- self.assertFalse(self.vault_cipher._is_equal(utf8_data, utf8_data[:-1] + b'P'))
|
|
-
|
|
- def test_is_equal_non_bytes(self):
|
|
- """ Anything not a byte string should raise a TypeError """
|
|
- self.assertRaises(TypeError, self.vault_cipher._is_equal, u"One fish", b"two fish")
|
|
- self.assertRaises(TypeError, self.vault_cipher._is_equal, b"One fish", u"two fish")
|
|
- self.assertRaises(TypeError, self.vault_cipher._is_equal, 1, b"red fish")
|
|
- self.assertRaises(TypeError, self.vault_cipher._is_equal, b"blue fish", 2)
|
|
-
|
|
|
|
class TestVaultLib(unittest.TestCase):
|
|
def setUp(self):
|
|
@@ -267,8 +213,6 @@
|
|
self.assertEqual(self.v.b_version, b"9.9", msg="version was not properly set")
|
|
|
|
def test_encrypt_decrypt_aes(self):
|
|
- if not HAS_AES or not HAS_COUNTER or not HAS_PBKDF2:
|
|
- raise SkipTest
|
|
self.v.cipher_name = u'AES'
|
|
self.v.b_password = b'ansible'
|
|
# AES encryption code has been removed, so this is old output for
|
|
@@ -282,8 +226,6 @@
|
|
self.assertEqual(b_plaintext, b"foobar", msg="decryption failed")
|
|
|
|
def test_encrypt_decrypt_aes256(self):
|
|
- if not HAS_AES or not HAS_COUNTER or not HAS_PBKDF2:
|
|
- raise SkipTest
|
|
self.v.cipher_name = u'AES256'
|
|
plaintext = u"foobar"
|
|
b_vaulttext = self.v.encrypt(plaintext)
|
|
@@ -292,8 +234,6 @@
|
|
self.assertEqual(b_plaintext, b"foobar", msg="decryption failed")
|
|
|
|
def test_encrypt_decrypt_aes256_existing_vault(self):
|
|
- if not HAS_AES or not HAS_COUNTER or not HAS_PBKDF2:
|
|
- raise SkipTest
|
|
self.v.cipher_name = u'AES256'
|
|
b_orig_plaintext = b"Setec Astronomy"
|
|
vaulttext = u'''$ANSIBLE_VAULT;1.1;AES256
|
|
@@ -314,8 +254,6 @@
|
|
# FIXME This test isn't working quite yet.
|
|
raise SkipTest
|
|
|
|
- if not HAS_AES or not HAS_COUNTER or not HAS_PBKDF2:
|
|
- raise SkipTest
|
|
self.v.cipher_name = 'AES256'
|
|
# plaintext = "Setec Astronomy"
|
|
enc_data = '''$ANSIBLE_VAULT;1.1;AES256
|
|
@@ -350,8 +288,6 @@
|
|
self.v.decrypt(b_invalid_ciphertext)
|
|
|
|
def test_encrypt_encrypted(self):
|
|
- if not HAS_AES or not HAS_COUNTER or not HAS_PBKDF2:
|
|
- raise SkipTest
|
|
self.v.cipher_name = u'AES'
|
|
b_vaulttext = b"$ANSIBLE_VAULT;9.9;TEST\n%s" % hexlify(b"ansible")
|
|
vaulttext = to_text(b_vaulttext, errors='strict')
|
|
@@ -359,8 +295,6 @@
|
|
self.assertRaises(errors.AnsibleError, self.v.encrypt, vaulttext)
|
|
|
|
def test_decrypt_decrypted(self):
|
|
- if not HAS_AES or not HAS_COUNTER or not HAS_PBKDF2:
|
|
- raise SkipTest
|
|
plaintext = u"ansible"
|
|
self.assertRaises(errors.AnsibleError, self.v.decrypt, plaintext)
|
|
|
|
@@ -368,9 +302,6 @@
|
|
self.assertRaises(errors.AnsibleError, self.v.decrypt, b_plaintext)
|
|
|
|
def test_cipher_not_set(self):
|
|
- # not setting the cipher should default to AES256
|
|
- if not HAS_AES or not HAS_COUNTER or not HAS_PBKDF2:
|
|
- raise SkipTest
|
|
plaintext = u"ansible"
|
|
self.v.encrypt(plaintext)
|
|
self.assertEquals(self.v.cipher_name, "AES256")
|
|
diff -uNr ansible-2.3.0.0.ORIG/test/utils/docker/centos6/Dockerfile ansible-2.3.0.0/test/utils/docker/centos6/Dockerfile
|
|
--- ansible-2.3.0.0.ORIG/test/utils/docker/centos6/Dockerfile 2017-05-23 14:23:12.321595450 +0100
|
|
+++ ansible-2.3.0.0/test/utils/docker/centos6/Dockerfile 2017-05-23 14:24:22.121598926 +0100
|
|
@@ -9,6 +9,8 @@
|
|
file \
|
|
gcc \
|
|
git \
|
|
+ libffi \
|
|
+ libffi-devel \
|
|
make \
|
|
mercurial \
|
|
mysql \
|
|
@@ -16,6 +18,7 @@
|
|
mysql-server \
|
|
openssh-clients \
|
|
openssh-server \
|
|
+ openssl-devel \
|
|
python-coverage \
|
|
python-devel \
|
|
python-httplib2 \
|
|
@@ -40,8 +43,6 @@
|
|
&& \
|
|
yum clean all
|
|
|
|
-RUN rpm -e --nodeps python-crypto && pip install --upgrade pycrypto
|
|
-
|
|
RUN /bin/sed -i -e 's/^\(Defaults\s*requiretty\)/#--- \1/' /etc/sudoers
|
|
RUN mkdir /etc/ansible/
|
|
RUN /bin/echo -e '[local]\nlocalhost ansible_connection=local' > /etc/ansible/hosts
|
|
diff -uNr ansible-2.3.0.0.ORIG/test/utils/docker/centos7/Dockerfile ansible-2.3.0.0/test/utils/docker/centos7/Dockerfile
|
|
--- ansible-2.3.0.0.ORIG/test/utils/docker/centos7/Dockerfile 2017-05-23 14:23:12.321595450 +0100
|
|
+++ ansible-2.3.0.0/test/utils/docker/centos7/Dockerfile 2017-05-23 14:24:22.121598926 +0100
|
|
@@ -17,15 +17,20 @@
|
|
bzip2 \
|
|
dbus-python \
|
|
file \
|
|
+ gcc \
|
|
git \
|
|
iproute \
|
|
+ libffi \
|
|
+ libffi-devel \
|
|
make \
|
|
mariadb-server \
|
|
mercurial \
|
|
MySQL-python \
|
|
openssh-clients \
|
|
openssh-server \
|
|
+ openssl-devel \
|
|
python-coverage \
|
|
+ python-devel \
|
|
python-httplib2 \
|
|
python-jinja2 \
|
|
python-keyczar \
|
|
diff -uNr ansible-2.3.0.0.ORIG/test/utils/docker/fedora24/Dockerfile ansible-2.3.0.0/test/utils/docker/fedora24/Dockerfile
|
|
--- ansible-2.3.0.0.ORIG/test/utils/docker/fedora24/Dockerfile 2017-05-23 14:23:12.321595450 +0100
|
|
+++ ansible-2.3.0.0/test/utils/docker/fedora24/Dockerfile 2017-05-23 14:24:22.121598926 +0100
|
|
@@ -17,18 +17,23 @@
|
|
dbus-python \
|
|
file \
|
|
findutils \
|
|
+ gcc \
|
|
git \
|
|
glibc-locale-source \
|
|
iproute \
|
|
+ libffi \
|
|
+ libffi-devel \
|
|
make \
|
|
mariadb-server \
|
|
mercurial \
|
|
MySQL-python \
|
|
openssh-clients \
|
|
openssh-server \
|
|
+ openssl-devel \
|
|
procps \
|
|
python2-dnf \
|
|
python-coverage \
|
|
+ python-devel \
|
|
python-httplib2 \
|
|
python-jinja2 \
|
|
python-keyczar \
|
|
diff -uNr ansible-2.3.0.0.ORIG/test/utils/docker/fedora25/Dockerfile ansible-2.3.0.0/test/utils/docker/fedora25/Dockerfile
|
|
--- ansible-2.3.0.0.ORIG/test/utils/docker/fedora25/Dockerfile 2017-05-23 14:23:12.321595450 +0100
|
|
+++ ansible-2.3.0.0/test/utils/docker/fedora25/Dockerfile 2017-05-23 14:24:22.121598926 +0100
|
|
@@ -20,12 +20,15 @@
|
|
git \
|
|
glibc-locale-source \
|
|
iproute \
|
|
+ libffi \
|
|
+ libffi-devel \
|
|
make \
|
|
mariadb-server \
|
|
mercurial \
|
|
MySQL-python \
|
|
openssh-clients \
|
|
openssh-server \
|
|
+ openssl-devel \
|
|
procps \
|
|
python2-dnf \
|
|
python-coverage \
|
|
diff -uNr ansible-2.3.0.0.ORIG/test/utils/docker/opensuse42.1/Dockerfile ansible-2.3.0.0/test/utils/docker/opensuse42.1/Dockerfile
|
|
--- ansible-2.3.0.0.ORIG/test/utils/docker/opensuse42.1/Dockerfile 2017-05-23 14:23:12.321595450 +0100
|
|
+++ ansible-2.3.0.0/test/utils/docker/opensuse42.1/Dockerfile 2017-05-23 14:24:22.121598926 +0100
|
|
@@ -21,6 +21,8 @@
|
|
openssh \
|
|
postgresql-server \
|
|
python-coverage \
|
|
+ python-cryptography \
|
|
+ python-devel \
|
|
python-httplib2 \
|
|
python-jinja2 \
|
|
python-keyczar \
|
|
diff -uNr ansible-2.3.0.0.ORIG/test/utils/docker/opensuse42.2/Dockerfile ansible-2.3.0.0/test/utils/docker/opensuse42.2/Dockerfile
|
|
--- ansible-2.3.0.0.ORIG/test/utils/docker/opensuse42.2/Dockerfile 2017-05-23 14:23:12.321595450 +0100
|
|
+++ ansible-2.3.0.0/test/utils/docker/opensuse42.2/Dockerfile 2017-05-23 14:24:22.122598926 +0100
|
|
@@ -21,6 +21,7 @@
|
|
openssh \
|
|
postgresql-server \
|
|
python-coverage \
|
|
+ python-cryptography \
|
|
python-httplib2 \
|
|
python-jinja2 \
|
|
python-keyczar \
|
|
diff -uNr ansible-2.3.0.0.ORIG/test/utils/docker/ubuntu1204/Dockerfile ansible-2.3.0.0/test/utils/docker/ubuntu1204/Dockerfile
|
|
--- ansible-2.3.0.0.ORIG/test/utils/docker/ubuntu1204/Dockerfile 2017-05-23 14:23:12.321595450 +0100
|
|
+++ ansible-2.3.0.0/test/utils/docker/ubuntu1204/Dockerfile 2017-05-23 14:24:22.122598926 +0100
|
|
@@ -17,6 +17,8 @@
|
|
gawk \
|
|
gcc \
|
|
git \
|
|
+ libffi-dev \
|
|
+ libssl-dev \
|
|
libxml2-utils \
|
|
locales \
|
|
make \
|
|
@@ -50,8 +52,6 @@
|
|
&& \
|
|
apt-get clean
|
|
|
|
-RUN pip install --upgrade pycrypto
|
|
-
|
|
# helpful things taken from the ubuntu-upstart Dockerfile:
|
|
# https://github.com/tianon/dockerfiles/blob/4d24a12b54b75b3e0904d8a285900d88d3326361/sbin-init/ubuntu/upstart/14.04/Dockerfile
|
|
ADD init-fake.conf /etc/init/fake-container-events.conf
|
|
diff -uNr ansible-2.3.0.0.ORIG/test/utils/docker/ubuntu1404/Dockerfile ansible-2.3.0.0/test/utils/docker/ubuntu1404/Dockerfile
|
|
--- ansible-2.3.0.0.ORIG/test/utils/docker/ubuntu1404/Dockerfile 2017-05-23 14:23:12.321595450 +0100
|
|
+++ ansible-2.3.0.0/test/utils/docker/ubuntu1404/Dockerfile 2017-05-23 14:24:22.122598926 +0100
|
|
@@ -16,6 +16,8 @@
|
|
fakeroot \
|
|
gawk \
|
|
git \
|
|
+ libffi-dev \
|
|
+ libssl-dev \
|
|
libxml2-utils \
|
|
locales \
|
|
make \
|
|
diff -uNr ansible-2.3.0.0.ORIG/test/utils/docker/ubuntu1604/Dockerfile ansible-2.3.0.0/test/utils/docker/ubuntu1604/Dockerfile
|
|
--- ansible-2.3.0.0.ORIG/test/utils/docker/ubuntu1604/Dockerfile 2017-05-23 14:23:12.321595450 +0100
|
|
+++ ansible-2.3.0.0/test/utils/docker/ubuntu1604/Dockerfile 2017-05-23 14:24:22.122598926 +0100
|
|
@@ -17,6 +17,8 @@
|
|
gawk \
|
|
git \
|
|
iproute2 \
|
|
+ libffi-dev \
|
|
+ libssl-dev \
|
|
libxml2-utils \
|
|
locales \
|
|
lsb-release \
|
|
diff -uNr ansible-2.3.0.0.ORIG/test/utils/docker/ubuntu1604py3/Dockerfile ansible-2.3.0.0/test/utils/docker/ubuntu1604py3/Dockerfile
|
|
--- ansible-2.3.0.0.ORIG/test/utils/docker/ubuntu1604py3/Dockerfile 2017-05-23 14:23:12.321595450 +0100
|
|
+++ ansible-2.3.0.0/test/utils/docker/ubuntu1604py3/Dockerfile 2017-05-23 14:24:22.122598926 +0100
|
|
@@ -15,6 +15,8 @@
|
|
gawk \
|
|
git \
|
|
iproute2 \
|
|
+ libffi-dev \
|
|
+ libssl-dev \
|
|
libxml2-utils \
|
|
locales \
|
|
lsb-release \
|
|
diff -uNr ansible-2.3.0.0.ORIG/test/utils/shippable/other.sh ansible-2.3.0.0/test/utils/shippable/other.sh
|
|
--- ansible-2.3.0.0.ORIG/test/utils/shippable/other.sh 2017-05-23 14:23:12.320595450 +0100
|
|
+++ ansible-2.3.0.0/test/utils/shippable/other.sh 2017-05-23 14:24:22.123598926 +0100
|
|
@@ -12,6 +12,8 @@
|
|
retry.py apt-get install -qq \
|
|
shellcheck \
|
|
python2.4 \
|
|
+ libssl-dev \
|
|
+ libffi-dev \
|
|
|
|
ln -sf x86_64-linux-gnu-gcc-4.9 /usr/bin/x86_64-linux-gnu-gcc
|
|
|
|
diff -uNr ansible-2.3.0.0.ORIG/test/utils/tox/requirements.txt ansible-2.3.0.0/test/utils/tox/requirements.txt
|
|
--- ansible-2.3.0.0.ORIG/test/utils/tox/requirements.txt 2017-05-23 14:23:12.321595450 +0100
|
|
+++ ansible-2.3.0.0/test/utils/tox/requirements.txt 2017-05-23 14:24:22.123598926 +0100
|
|
@@ -11,7 +11,7 @@
|
|
redis
|
|
python-memcached
|
|
python-systemd
|
|
-pycrypto
|
|
+cryptography
|
|
botocore
|
|
boto3
|
|
pytest
|