def setup_contexts(self, mechanism, sym_key, iv): # Get a PK11 slot based on the cipher slot = nss.get_best_slot(mechanism) if sym_key is None: sym_key = slot.key_gen(mechanism, None, slot.get_best_key_length(mechanism)) # If initialization vector was supplied use it, otherwise set it to # None if iv: iv_data = nss.read_hex(iv) iv_si = nss.SecItem(iv_data) iv_param = nss.param_from_iv(mechanism, iv_si) else: iv_length = nss.get_iv_length(mechanism) if iv_length > 0: iv_data = nss.generate_random(iv_length) iv_si = nss.SecItem(iv_data) iv_param = nss.param_from_iv(mechanism, iv_si) else: iv_param = None # Create an encoding context encoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_ENCRYPT, sym_key, iv_param) # Create a decoding context decoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_DECRYPT, sym_key, iv_param) return encoding_ctx, decoding_ctx
def setup_contexts(cls, mechanism, sym_key, nonce_iv): """ Set up contexts to do wrapping/unwrapping by symmetric keys. """ # Get a PK11 slot based on the cipher slot = nss.get_best_slot(mechanism) if sym_key is None: sym_key = slot.key_gen(mechanism, None, slot.get_best_key_length(mechanism)) # If initialization vector was supplied use it, otherwise set it to # None if nonce_iv: iv_si = nss.SecItem(nonce_iv) iv_param = nss.param_from_iv(mechanism, iv_si) else: iv_data = cls.generate_nonce_iv(mechanism) if iv_data is not None: iv_si = nss.SecItem(iv_data) iv_param = nss.param_from_iv(mechanism, iv_si) else: iv_param = None # Create an encoding context encoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_ENCRYPT, sym_key, iv_param) # Create a decoding context decoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_DECRYPT, sym_key, iv_param) return encoding_ctx, decoding_ctx
def generate_sym_key(): """ This Function generate Symmetric key and nonce data """ ## Initialize NSS Database opens temporary database and the internal PKCS #112 module nss.nss_init_nodb() ## Mechanism to be used for symmetric key mechanism = nss.CKM_DES_CBC_PAD # From the Soft token that we initialized get slot to generate symmetric key slot = nss.get_best_slot(mechanism) # Generate a symmetric key on the pk11 slot, The sym_key is of type PK11SymKey sym_key = slot.key_gen(mechanism, None, slot.get_best_key_length(mechanism)) # Generate Nonce iv_length = nss.get_iv_length(mechanism) if iv_length > 0: # Generate Nonce iv_data = nss.generate_random(iv_length) # Pass this random data to NSS SecItem iv_si = nss.SecItem(iv_data) # Use the Data passed to SecItem for initialization Vector iv_param = nss.param_from_iv(mechanism, iv_si) # Random data is converted to hex pki_nonce = nss.data_to_hex(data=iv_data, separator=":") #print "generated %d bytes initialization vector: %s" % (iv_length, pki_nonce) # Create a Symmetric key Context using the Symmetric key, nonce The context should be # used for encrypt as well as decrypt encoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_ENCRYPT, sym_key, iv_param) decoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_DECRYPT, sym_key, iv_param) #return the symmetric key, nonce data, encoding context and decoding context to encrypt and # decrypt return sym_key, pki_nonce, encoding_ctx, decoding_ctx
def setup_contexts(self, mechanism, sym_key, iv): # Get a PK11 slot based on the cipher slot = nss.get_best_slot(mechanism) if sym_key is None: sym_key = slot.key_gen( mechanism, None, slot.get_best_key_length(mechanism)) # If initialization vector was supplied use it, otherwise set it to # None if iv: iv_data = nss.read_hex(iv) iv_si = nss.SecItem(iv_data) iv_param = nss.param_from_iv(mechanism, iv_si) else: iv_length = nss.get_iv_length(mechanism) if iv_length > 0: iv_data = nss.generate_random(iv_length) iv_si = nss.SecItem(iv_data) iv_param = nss.param_from_iv(mechanism, iv_si) else: iv_param = None # Create an encoding context encoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_ENCRYPT, sym_key, iv_param) # Create a decoding context decoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_DECRYPT, sym_key, iv_param) return encoding_ctx, decoding_ctx
def generate_symmetric_key(self, mechanism=nss.CKM_DES3_CBC_PAD, size=0): """ Returns a symmetric key. Note that for fixed length keys, this length should be 0. If no length is provided, then the function will either use 0 (for fixed length keys) or the maximum available length for that algorithm and the token. """ slot = nss.get_best_slot(mechanism) if size == 0: size = slot.get_best_key_length(mechanism) return slot.key_gen(mechanism, None, size)
def verify_sym_key(archived_key, archived_iv, algorithm, plain_text): """ This function verifies whether archived key is usable, Actually verifying this is senseless, reason any random data can be used for encryption, but still just for the heck of it. """ # Initialize NSS nss.nss_init_nodb() # Decode the base64 string to binary key = base64.decodestring(archived_data) # Currently we are assuming the mechanism to AES # Will need to add other mechanisms later, but # this is just an example. mechanism = nss.CKM_AES_CBC_PAD # Get the best pkcs11 slot slot = nss.get_best_slot(mechanism) # convert the binary to hex with separtor as : pki_key = nss.data_to_hex(data=key,separator=":") # create a nssSecItem object out of it. key_si = nss.SecItem(nss.read_hex(pki_key)) # Import the key to the slot sym_key = nss.import_sym_key(slot, mechanism, nss.PK11_OriginUnwrap, nss.CKA_ENCRYPT, key_si) # Same for the nonce data iv = base64.decodestring(archived_iv) iv_data = nss.data_to_hex(data=iv,separator=":") iv_si = nss.SecItem(nss.read_hex(iv_data)) iv_param = nss.param_from_iv(mechanism, iv_si) encoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_ENCRYPT,sym_key, iv_param) decoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_DECRYPT,sym_key, iv_param) cipher_text = encoding_ctx.cipher_op(plain_text) cipher_text += encoding_ctx.digest_final() print cipher_text decoded_text = decoding_ctx.cipher_op(cipher_text) decoded_text += decoding_ctx.digest_final() print decoded_text
def setup_contexts(mechanism, key, iv): # Get a PK11 slot based on the cipher slot = nss.get_best_slot(mechanism) # If key was supplied use it, otherwise generate one if key: if verbose: print("using supplied key data") print("key:\n%s" % (key)) key_si = nss.SecItem(nss.read_hex(key)) sym_key = nss.import_sym_key(slot, mechanism, nss.PK11_OriginUnwrap, nss.CKA_ENCRYPT, key_si) else: if verbose: print("generating key data") sym_key = slot.key_gen(mechanism, None, slot.get_best_key_length(mechanism)) # If initialization vector was supplied use it, otherwise set it to None if iv: if verbose: print("supplied iv:\n%s" % (iv)) iv_data = nss.read_hex(iv) iv_si = nss.SecItem(iv_data) iv_param = nss.param_from_iv(mechanism, iv_si) else: iv_length = nss.get_iv_length(mechanism) if iv_length > 0: iv_data = nss.generate_random(iv_length) iv_si = nss.SecItem(iv_data) iv_param = nss.param_from_iv(mechanism, iv_si) if verbose: print("generated %d byte initialization vector: %s" % (iv_length, nss.data_to_hex(iv_data, separator=":"))) else: iv_param = None # Create an encoding context encoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_ENCRYPT, sym_key, iv_param) # Create a decoding context decoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_DECRYPT, sym_key, iv_param) return encoding_ctx, decoding_ctx
def setup_contexts(mechanism, key, iv): # Get a PK11 slot based on the cipher slot = nss.get_best_slot(mechanism) # If key was supplied use it, otherwise generate one if key: if verbose: print "using supplied key data" print "key:\n%s" % (key) key_si = nss.SecItem(nss.read_hex(key)) sym_key = nss.import_sym_key(slot, mechanism, nss.PK11_OriginUnwrap, nss.CKA_ENCRYPT, key_si) else: if verbose: print "generating key data" sym_key = slot.key_gen(mechanism, None, slot.get_best_key_length(mechanism)) # If initialization vector was supplied use it, otherwise set it to None if iv: if verbose: print "supplied iv:\n%s" % (iv) iv_data = nss.read_hex(iv) iv_si = nss.SecItem(iv_data) iv_param = nss.param_from_iv(mechanism, iv_si) else: iv_length = nss.get_iv_length(mechanism) if iv_length > 0: iv_data = nss.generate_random(iv_length) iv_si = nss.SecItem(iv_data) iv_param = nss.param_from_iv(mechanism, iv_si) if verbose: print "generated %d byte initialization vector: %s" % \ (iv_length, nss.data_to_hex(iv_data, separator=":")) else: iv_param = None # Create an encoding context encoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_ENCRYPT, sym_key, iv_param) # Create a decoding context decoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_DECRYPT, sym_key, iv_param) return encoding_ctx, decoding_ctx
def __call__(self, element, mac=None): (mech, ivlen) = fetch(element, "./xenc:EncryptionMethod/@Algorithm", convertAlgorithm) data = fetch(element, "./xenc:CipherData/xenc:CipherValue/text()", base64.b64decode) # If a MAC is present, perform validation. if mac: tmp = self.__hmac.copy() tmp.update(data) 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() return out
def __call__(self, element, mac=None): (mech, ivlen) = fetch(element, "./xenc:EncryptionMethod/@Algorithm", convertAlgorithm) data = fetch(element, "./xenc:CipherData/xenc:CipherValue/text()", base64.b64decode) # If a MAC is present, perform validation. if mac: tmp = self.__hmac.copy() tmp.update(data) 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() return out
def forward(self, *args, **options): data = options.get('data') input_file = options.get('in') password = options.get('password') password_file = options.get('password_file') override_password = options.pop('override_password', False) # don't send these parameters to server if 'data' in options: del options['data'] if 'in' in options: del options['in'] if 'password' in options: del options['password'] if 'password_file' in options: del options['password_file'] # get data if data and input_file: raise errors.MutuallyExclusiveError( reason=_('Input data specified multiple times')) elif data: if len(data) > MAX_VAULT_DATA_SIZE: raise errors.ValidationError(name="data", error=_( "Size of data exceeds the limit. Current vault data size " "limit is %(limit)d B") % {'limit': MAX_VAULT_DATA_SIZE}) elif input_file: try: stat = os.stat(input_file) except OSError as exc: raise errors.ValidationError(name="in", error=_( "Cannot read file '%(filename)s': %(exc)s") % {'filename': input_file, 'exc': exc.args[1]}) if stat.st_size > MAX_VAULT_DATA_SIZE: raise errors.ValidationError(name="in", error=_( "Size of data exceeds the limit. Current vault data size " "limit is %(limit)d B") % {'limit': MAX_VAULT_DATA_SIZE}) data = validated_read('in', input_file, mode='rb') else: data = '' if self.api.env.in_server: backend = self.api.Backend.ldap2 else: backend = self.api.Backend.rpcclient if not backend.isconnected(): backend.connect() # retrieve vault info vault = self.api.Command.vault_show(*args, **options)['result'] vault_type = vault['ipavaulttype'][0] if vault_type == u'standard': encrypted_key = None elif vault_type == u'symmetric': # get password if password and password_file: raise errors.MutuallyExclusiveError( reason=_('Password specified multiple times')) elif password: pass elif password_file: password = validated_read('password-file', password_file, encoding='utf-8') password = password.rstrip('\n') else: if override_password: password = get_new_password() else: password = get_existing_password() if not override_password: # verify password by retrieving existing data opts = options.copy() opts['password'] = password try: self.api.Command.vault_retrieve(*args, **opts) except errors.NotFound: pass salt = vault['ipavaultsalt'][0] # generate encryption key from vault password encryption_key = generate_symmetric_key(password, salt) # encrypt data with encryption key data = encrypt(data, symmetric_key=encryption_key) encrypted_key = None elif vault_type == u'asymmetric': public_key = vault['ipavaultpublickey'][0].encode('utf-8') # generate encryption key encryption_key = base64.b64encode(os.urandom(32)) # encrypt data with encryption key data = encrypt(data, symmetric_key=encryption_key) # encrypt encryption key with public key encrypted_key = encrypt(encryption_key, public_key=public_key) else: raise errors.ValidationError( name='vault_type', error=_('Invalid vault type')) # initialize NSS database nss.nss_init(api.env.nss_dir) # retrieve transport certificate config = self.api.Command.vaultconfig_show()['result'] transport_cert_der = config['transport_cert'] nss_transport_cert = nss.Certificate(transport_cert_der) # generate session key mechanism = nss.CKM_DES3_CBC_PAD slot = nss.get_best_slot(mechanism) key_length = slot.get_best_key_length(mechanism) session_key = slot.key_gen(mechanism, None, key_length) # wrap session key with transport certificate # pylint: disable=no-member public_key = nss_transport_cert.subject_public_key_info.public_key # pylint: enable=no-member wrapped_session_key = nss.pub_wrap_sym_key(mechanism, public_key, session_key) options['session_key'] = wrapped_session_key.data nonce_length = nss.get_iv_length(mechanism) nonce = nss.generate_random(nonce_length) options['nonce'] = nonce vault_data = {} vault_data[u'data'] = base64.b64encode(data).decode('utf-8') if encrypted_key: vault_data[u'encrypted_key'] = base64.b64encode(encrypted_key)\ .decode('utf-8') json_vault_data = json.dumps(vault_data) # wrap vault_data with session key iv_si = nss.SecItem(nonce) iv_param = nss.param_from_iv(mechanism, iv_si) encoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_ENCRYPT, session_key, iv_param) wrapped_vault_data = encoding_ctx.cipher_op(json_vault_data)\ + encoding_ctx.digest_final() options['vault_data'] = wrapped_vault_data return self.api.Command.vault_archive_internal(*args, **options)
def retrieve_security_data(self, recovery_request_id, passphrase=None): """ :param recovery_request_id: identifier of key recovery request :param passphrase: passphrase to be used to wrap the data Recover the passphrase or symmetric key. We require an approved recovery request. If a passphrase is provided, the DRM will return a blob that can be decrypted with the passphrase. If not, then a symmetric key will be created to wrap the data for transport to this server. Upon receipt, the data will be unwrapped and returned unencrypted. The command returns a dict with the values described in parse_key_data_xml(), as well as the following field +-----------------+---------------+-------------------------------------- + |result name |result type |comments | +=================+===============+=======================================+ |data |String | Key data (either wrapped using | | | | passphrase or unwrapped) | +-----------------+---------------+---------------------------------------+ """ self.debug('%s.retrieve_security_data()', self.fullname) if recovery_request_id is None: raise CertificateOperationError( error=_('Bad arguments to retrieve_security_data')) # generate symmetric key slot = nss.get_best_slot(self.mechanism) session_key = slot.key_gen(self.mechanism, None, slot.get_best_key_length(self.mechanism)) # wrap this key with the transport cert public_key = self.transport_cert.subject_public_key_info.public_key wrapped_session_key = b64encode( nss.pub_wrap_sym_key(self.mechanism, public_key, session_key)) wrapped_passphrase = None if passphrase is not None: # wrap passphrase with session key wrapped_session_key = b64encode( self.symmetric_wrap(passphrase, session_key)) request = self.create_recovery_request(None, recovery_request_id, wrapped_session_key, wrapped_passphrase) # Call CMS http_status, http_reason_phrase, _http_headers, http_body = \ self._request('/kra/rest/agent/keys/retrieve', self.kra_agent_port, self.POST, etree.tostring(request.getroot(), encoding='UTF-8')) # Parse and handle errors if (http_status != 200): raise CertificateOperationError( error=_('Error in retrieving security data (%s)') % http_reason_phrase) parse_result = self.get_parse_result_xml(http_body, parse_key_data_xml) if passphrase is None: iv = nss.data_to_hex(b64decode(parse_result['nonce_data'])) parse_result['data'] = self.symmetric_unwrap( b64decode(parse_result['wrapped_data']), session_key, iv) return parse_result
def forward(self, *args, **options): name = args[-1] data = options.get('data') input_file = options.get('in') password = options.get('password') password_file = options.get('password_file') # don't send these parameters to server if 'data' in options: del options['data'] if 'in' in options: del options['in'] if 'password' in options: del options['password'] if 'password_file' in options: del options['password_file'] # get data if data and input_file: raise errors.MutuallyExclusiveError( reason=_('Input data specified multiple times')) elif input_file: data = validated_read('in', input_file, mode='rb') elif not data: data = '' if self.api.env.in_server: backend = self.api.Backend.ldap2 else: backend = self.api.Backend.rpcclient if not backend.isconnected(): backend.connect(ccache=krbV.default_context().default_ccache()) # retrieve vault info vault = self.api.Command.vault_show(*args, **options)['result'] vault_type = vault['ipavaulttype'][0] if vault_type == u'standard': encrypted_key = None elif vault_type == u'symmetric': # get password if password and password_file: raise errors.MutuallyExclusiveError( reason=_('Password specified multiple times')) elif password: pass elif password_file: password = validated_read('password-file', password_file, encoding='utf-8') password = password.rstrip('\n') else: password = self.obj.get_existing_password() # verify password by retrieving existing data opts = options.copy() opts['password'] = password try: self.api.Command.vault_retrieve(*args, **opts) except errors.NotFound: pass salt = vault['ipavaultsalt'][0] # generate encryption key from vault password encryption_key = self.obj.generate_symmetric_key( password, salt) # encrypt data with encryption key data = self.obj.encrypt(data, symmetric_key=encryption_key) encrypted_key = None elif vault_type == u'asymmetric': public_key = vault['ipavaultpublickey'][0].encode('utf-8') # generate encryption key encryption_key = base64.b64encode(os.urandom(32)) # encrypt data with encryption key data = self.obj.encrypt(data, symmetric_key=encryption_key) # encrypt encryption key with public key encrypted_key = self.obj.encrypt( encryption_key, public_key=public_key) else: raise errors.ValidationError( name='vault_type', error=_('Invalid vault type')) # initialize NSS database current_dbdir = paths.IPA_NSSDB_DIR nss.nss_init(current_dbdir) # retrieve transport certificate config = self.api.Command.vaultconfig_show()['result'] transport_cert_der = config['transport_cert'] nss_transport_cert = nss.Certificate(transport_cert_der) # generate session key mechanism = nss.CKM_DES3_CBC_PAD slot = nss.get_best_slot(mechanism) key_length = slot.get_best_key_length(mechanism) session_key = slot.key_gen(mechanism, None, key_length) # wrap session key with transport certificate public_key = nss_transport_cert.subject_public_key_info.public_key wrapped_session_key = nss.pub_wrap_sym_key(mechanism, public_key, session_key) options['session_key'] = wrapped_session_key.data nonce_length = nss.get_iv_length(mechanism) nonce = nss.generate_random(nonce_length) options['nonce'] = nonce vault_data = {} vault_data[u'data'] = base64.b64encode(data).decode('utf-8') if encrypted_key: vault_data[u'encrypted_key'] = base64.b64encode(encrypted_key)\ .decode('utf-8') json_vault_data = json.dumps(vault_data) # wrap vault_data with session key iv_si = nss.SecItem(nonce) iv_param = nss.param_from_iv(mechanism, iv_si) encoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_ENCRYPT, session_key, iv_param) wrapped_vault_data = encoding_ctx.cipher_op(json_vault_data)\ + encoding_ctx.digest_final() options['vault_data'] = wrapped_vault_data return self.api.Command.vault_archive_internal(*args, **options)
def forward(self, *args, **options): name = args[-1] output_file = options.get('out') password = options.get('password') password_file = options.get('password_file') private_key = options.get('private_key') private_key_file = options.get('private_key_file') # don't send these parameters to server if 'out' in options: del options['out'] if 'password' in options: del options['password'] if 'password_file' in options: del options['password_file'] if 'private_key' in options: del options['private_key'] if 'private_key_file' in options: del options['private_key_file'] if self.api.env.in_server: backend = self.api.Backend.ldap2 else: backend = self.api.Backend.rpcclient if not backend.isconnected(): backend.connect(ccache=krbV.default_context().default_ccache()) # retrieve vault info vault = self.api.Command.vault_show(*args, **options)['result'] vault_type = vault['ipavaulttype'][0] # initialize NSS database current_dbdir = paths.IPA_NSSDB_DIR nss.nss_init(current_dbdir) # retrieve transport certificate config = self.api.Command.vaultconfig_show()['result'] transport_cert_der = config['transport_cert'] nss_transport_cert = nss.Certificate(transport_cert_der) # generate session key mechanism = nss.CKM_DES3_CBC_PAD slot = nss.get_best_slot(mechanism) key_length = slot.get_best_key_length(mechanism) session_key = slot.key_gen(mechanism, None, key_length) # wrap session key with transport certificate public_key = nss_transport_cert.subject_public_key_info.public_key wrapped_session_key = nss.pub_wrap_sym_key(mechanism, public_key, session_key) # send retrieval request to server options['session_key'] = wrapped_session_key.data response = self.api.Command.vault_retrieve_internal(*args, **options) result = response['result'] nonce = result['nonce'] # unwrap data with session key wrapped_vault_data = result['vault_data'] iv_si = nss.SecItem(nonce) iv_param = nss.param_from_iv(mechanism, iv_si) decoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_DECRYPT, session_key, iv_param) json_vault_data = decoding_ctx.cipher_op(wrapped_vault_data)\ + decoding_ctx.digest_final() vault_data = json.loads(json_vault_data) data = base64.b64decode(vault_data[u'data'].encode('utf-8')) encrypted_key = None if 'encrypted_key' in vault_data: encrypted_key = base64.b64decode(vault_data[u'encrypted_key'] .encode('utf-8')) if vault_type == u'standard': pass elif vault_type == u'symmetric': salt = vault['ipavaultsalt'][0] # get encryption key from vault password if password and password_file: raise errors.MutuallyExclusiveError( reason=_('Password specified multiple times')) elif password: pass elif password_file: password = validated_read('password-file', password_file, encoding='utf-8') password = password.rstrip('\n') else: password = self.obj.get_existing_password() # generate encryption key from password encryption_key = self.obj.generate_symmetric_key(password, salt) # decrypt data with encryption key data = self.obj.decrypt(data, symmetric_key=encryption_key) elif vault_type == u'asymmetric': # get encryption key with vault private key if private_key and private_key_file: raise errors.MutuallyExclusiveError( reason=_('Private key specified multiple times')) elif private_key: pass elif private_key_file: private_key = validated_read('private-key-file', private_key_file, mode='rb') else: raise errors.ValidationError( name='private_key', error=_('Missing vault private key')) # decrypt encryption key with private key encryption_key = self.obj.decrypt( encrypted_key, private_key=private_key) # decrypt data with encryption key data = self.obj.decrypt(data, symmetric_key=encryption_key) else: raise errors.ValidationError( name='vault_type', error=_('Invalid vault type')) if output_file: with open(output_file, 'w') as f: f.write(data) else: response['result'] = {'data': data} return response
def retrieve_security_data(self, recovery_request_id, passphrase=None): """ :param recovery_request_id: identifier of key recovery request :param passphrase: passphrase to be used to wrap the data Recover the passphrase or symmetric key. We require an approved recovery request. If a passphrase is provided, the DRM will return a blob that can be decrypted with the passphrase. If not, then a symmetric key will be created to wrap the data for transport to this server. Upon receipt, the data will be unwrapped and returned unencrypted. The command returns a dict with the values described in parse_key_data_xml(), as well as the following field +-----------------+---------------+-------------------------------------- + |result name |result type |comments | +=================+===============+=======================================+ |data |String | Key data (either wrapped using | | | | passphrase or unwrapped) | +-----------------+---------------+---------------------------------------+ """ self.debug('%s.retrieve_security_data()', self.fullname) if recovery_request_id is None: raise CertificateOperationError( error=_('Bad arguments to retrieve_security_data')) # generate symmetric key slot = nss.get_best_slot(self.mechanism) session_key = slot.key_gen( self.mechanism, None, slot.get_best_key_length( self.mechanism)) # wrap this key with the transport cert public_key = self.transport_cert.subject_public_key_info.public_key wrapped_session_key = b64encode( nss.pub_wrap_sym_key( self.mechanism, public_key, session_key)) wrapped_passphrase = None if passphrase is not None: # wrap passphrase with session key wrapped_session_key = b64encode( self.symmetric_wrap( passphrase, session_key)) request = self.create_recovery_request(None, recovery_request_id, wrapped_session_key, wrapped_passphrase) # Call CMS http_status, http_reason_phrase, _http_headers, http_body = \ self._request('/kra/rest/agent/keys/retrieve', self.kra_agent_port, self.POST, etree.tostring(request.getroot(), encoding='UTF-8')) # Parse and handle errors if (http_status != 200): raise CertificateOperationError(error=_('Error in retrieving security data (%s)') % http_reason_phrase) parse_result = self.get_parse_result_xml(http_body, parse_key_data_xml) if passphrase is None: iv = nss.data_to_hex( b64decode( parse_result['nonce_data'])) parse_result['data'] = self.symmetric_unwrap( b64decode(parse_result['wrapped_data']), session_key, iv) return parse_result
def forward(self, *args, **options): output_file = options.get('out') password = options.get('password') password_file = options.get('password_file') private_key = options.get('private_key') private_key_file = options.get('private_key_file') # don't send these parameters to server if 'out' in options: del options['out'] if 'password' in options: del options['password'] if 'password_file' in options: del options['password_file'] if 'private_key' in options: del options['private_key'] if 'private_key_file' in options: del options['private_key_file'] if self.api.env.in_server: backend = self.api.Backend.ldap2 else: backend = self.api.Backend.rpcclient if not backend.isconnected(): backend.connect() # retrieve vault info vault = self.api.Command.vault_show(*args, **options)['result'] vault_type = vault['ipavaulttype'][0] # initialize NSS database nss.nss_init(api.env.nss_dir) # retrieve transport certificate config = self.api.Command.vaultconfig_show()['result'] transport_cert_der = config['transport_cert'] nss_transport_cert = nss.Certificate(transport_cert_der) # generate session key mechanism = nss.CKM_DES3_CBC_PAD slot = nss.get_best_slot(mechanism) key_length = slot.get_best_key_length(mechanism) session_key = slot.key_gen(mechanism, None, key_length) # wrap session key with transport certificate # pylint: disable=no-member public_key = nss_transport_cert.subject_public_key_info.public_key # pylint: enable=no-member wrapped_session_key = nss.pub_wrap_sym_key(mechanism, public_key, session_key) # send retrieval request to server options['session_key'] = wrapped_session_key.data response = self.api.Command.vault_retrieve_internal(*args, **options) result = response['result'] nonce = result['nonce'] # unwrap data with session key wrapped_vault_data = result['vault_data'] iv_si = nss.SecItem(nonce) iv_param = nss.param_from_iv(mechanism, iv_si) decoding_ctx = nss.create_context_by_sym_key(mechanism, nss.CKA_DECRYPT, session_key, iv_param) json_vault_data = decoding_ctx.cipher_op(wrapped_vault_data)\ + decoding_ctx.digest_final() vault_data = json.loads(json_vault_data.decode('utf-8')) data = base64.b64decode(vault_data[u'data'].encode('utf-8')) encrypted_key = None if 'encrypted_key' in vault_data: encrypted_key = base64.b64decode(vault_data[u'encrypted_key'] .encode('utf-8')) if vault_type == u'standard': pass elif vault_type == u'symmetric': salt = vault['ipavaultsalt'][0] # get encryption key from vault password if password and password_file: raise errors.MutuallyExclusiveError( reason=_('Password specified multiple times')) elif password: pass elif password_file: password = validated_read('password-file', password_file, encoding='utf-8') password = password.rstrip('\n') else: password = get_existing_password() # generate encryption key from password encryption_key = generate_symmetric_key(password, salt) # decrypt data with encryption key data = decrypt(data, symmetric_key=encryption_key) elif vault_type == u'asymmetric': # get encryption key with vault private key if private_key and private_key_file: raise errors.MutuallyExclusiveError( reason=_('Private key specified multiple times')) elif private_key: pass elif private_key_file: private_key = validated_read('private-key-file', private_key_file, mode='rb') else: raise errors.ValidationError( name='private_key', error=_('Missing vault private key')) # decrypt encryption key with private key encryption_key = decrypt(encrypted_key, private_key=private_key) # decrypt data with encryption key data = decrypt(data, symmetric_key=encryption_key) else: raise errors.ValidationError( name='vault_type', error=_('Invalid vault type')) if output_file: with open(output_file, 'w') as f: f.write(data) else: response['result'] = {'data': data} return response