
    diV5                     f   d Z ddlmZmZmZ ddlmZ ddlmZm	Z	 ddl
mZ ddlZddlZddlZddlZ ej        e          Zg Z G d d          Z G d	 d
ej                  Z G d de          Z G d de          ZefdefdZefdee         dededeeef         fdZefdedededefdZdS )a  Obtaining card parameters (mostly key data) from external source.

This module contains a base class and a concrete implementation of
obtaining card key material (or other card-individual parameters) from
an external data source.

This is used e.g. to keep PIN/PUK data in some file on disk, avoiding
the need of manually entering the related card-individual data on every
operation with pySim-shell.
    )ListDictOptional)AES)h2bb2h)PySimLoggerNc                       e Zd ZdZg dg dg dg dg ddZdZed	ed
efd            Zededefd            Z	defdZ
deded
efdZdeded
efdZdS )CardKeyFieldCryptora  
    A Card key field encryption class that may be used by Card key provider implementations to add support for
    a column-based encryption to protect sensitive material (cryptographic key material, ADM keys, etc.).
    The sensitive material is encrypted using a "key-encryption key", occasionally also known as "transport key"
    before it is stored into a file or database (see also GSMA FS.28). The "transport key" is then used to decrypt
    the key material on demand.
    )UICC_SCP02_KIC1UICC_SCP02_KID1UICC_SCP02_KIK1)UICC_SCP03_KIC1UICC_SCP03_KID1UICC_SCP03_KIK1)SCP03_ENC_ISDRSCP03_MAC_ISDRSCP03_DEK_ISDR)SCP03_ENC_ISDASCP03_MAC_ISDASCP03_DEK_ISDA)SCP03_ENC_ECASDSCP03_MAC_ECASDSCP03_DEK_ECASD)
UICC_SCP02
UICC_SCP03
SCP03_ISDR
SCP03_ISDASCP03_ECASDs   ################dreturnc                 >    d |                                  D             S )Nc                 >    i | ]\  }}|                                 |S  upper).0kvs      E/home/jenkins/workspace/simtester-sanitize/pySim/card_key_provider.py
<dictcomp>z<CardKeyFieldCryptor.__dict_keys_to_upper.<locals>.<dictcomp>E   s&    555CAaAGGIIa555    items)r    s    r*   __dict_keys_to_upperz(CardKeyFieldCryptor.__dict_keys_to_upperC   s    55177995555r,   transport_keyscrypt_groupsc                 r    i }|                                  D ]\  }}||v r||         D ]}|||<   |||<    |S )zPApply a single transport key to multiple fields/columns, if the name is a group.r-   )r0   r1   new_dictnamekeyfields         r*   __process_transport_keysz,CardKeyFieldCryptor.__process_transport_keysG   si     '--// 	% 	%ID#|##)$/ * *E&)HUOO* "%r,   c                     |                      |                     |          | j                  | _        | j                                        D ]%\  }}t
                              d|d|           &dS )ab  
        Create new field encryptor/decryptor object and set transport keys, usually one for each column. In some cases
        it is also possible to use a single key for multiple columns (see also __CRYPT_GROUPS)

        Args:
                transport_keys : a dict indexed by field name, whose values are hex-encoded AES keys for the
                                 respective field (column) of the CSV. This is done so that different fields
                                 (columns) can use different transport keys, which is strongly recommended by
                                 GSMA FS.28
        zEncrypting/decrypting field z using AES key N),_CardKeyFieldCryptor__process_transport_keys(_CardKeyFieldCryptor__dict_keys_to_upper"_CardKeyFieldCryptor__CRYPT_GROUPSr0   r.   logdebug)selfr0   r4   r5   s       r*   __init__zCardKeyFieldCryptor.__init__S   s     #;;D<U<UVd<e<e<@<OQ Q,2244 	[ 	[ID#			tttUXUXYZZZZ	[ 	[r,   
field_nameencrypted_valc                 8   |                                 | j        vr|S t          j        t	          | j        |                                                    t          j        | j                  }t          |                    t	          |                              S )a  
        Decrypt a single field. The decryption is only applied if we have a transport key is known under the provided
        field name, otherwise the field is treated as plaintext and passed through as it is.

        Args:
                field_name : name of the field to decrypt (used to identify which key to use)
                encrypted_val : encrypted field value

        Returns:
                plaintext field value
        )	r&   r0   r   newr   MODE_CBC_CardKeyFieldCryptor__IVr   decrypt)r>   r@   rA   ciphers       r*   decrypt_fieldz!CardKeyFieldCryptor.decrypt_fieldc   {     !!T%888  T01A1A1C1CDEEs|UYU^__6>>#m"4"455666r,   plaintext_valc                 8   |                                 | j        vr|S t          j        t	          | j        |                                                    t          j        | j                  }t          |                    t	          |                              S )a  
        Encrypt a single field. The encryption is only applied if we have a transport key is known under the provided
        field name, otherwise the field is treated as non sensitive and passed through as it is.

        Args:
                field_name : name of the field to decrypt (used to identify which key to use)
                encrypted_val : encrypted field value

        Returns:
                plaintext field value
        )	r&   r0   r   rC   r   rD   rE   r   encrypt)r>   r@   rJ   rG   s       r*   encrypt_fieldz!CardKeyFieldCryptor.encrypt_fieldt   rI   r,   N)__name__
__module____qualname____doc__r;   rE   staticmethoddictr:   r9   r?   strrH   rM   r$   r,   r*   r   r   -   s-         TSSSSSPPPPPPTTT N D6 6 6 6 6 \6 	 	T 	 	 	 \	[t [ [ [ [ 7 7C 7C 7 7 7 7"7 7C 7C 7 7 7 7 7 7r,   r   c                   f    e Zd ZdZej        dee         dededeeef         fd            Z	d Z
dS )	CardKeyProviderz7Base class, not containing any concrete implementation.fieldsr5   valuer!   c                     dS )a  
        Get multiple card-individual fields for identified card. This method should not fail with an exception in
        case the entry, columns or even the key column itsself is not found.

        Args:
                fields : list of valid field names such as 'ADM1', 'PIN1', ... which are to be obtained
                key : look-up key to identify card data, such as 'ICCID'
                value : value for look-up key to identify card data
        Returns:
                dictionary of {field : value, ...} strings for each requested field from 'fields'. In case nothing is
                fond None shall be returned.
        Nr$   )r>   rW   r5   rX   s       r*   getzCardKeyProvider.get   s      r,   c                 *    t          |           j        S )N)typerN   )r>   s    r*   __str__zCardKeyProvider.__str__   s    Dzz""r,   N)rN   rO   rP   rQ   abcabstractmethodr   rT   r   rZ   r]   r$   r,   r*   rV   rV      ss        AA$s) # c d38n    # # # # #r,   rV   c            
       V    e Zd ZdZdedefdZdee         dededeeef         fd	Z	d
S )CardKeyProviderCsvzSCard key provider implementation that allows to query against a specified CSV file.csv_filenamer0   c                     t                               d|z             t          |d          | _        | j        st	          d|z            || _        t          |          | _        dS )z
        Args:
                csv_filename : file name (path) of CSV file containing card-individual key/data
                transport_keys : (see class CardKeyFieldCryptor)
        z*Using CSV file as card key data source: %srzCould not open CSV file '%s'N)r<   infoopencsv_fileRuntimeErrorrb   r   crypt)r>   rb   r0   s      r*   r?   zCardKeyProviderCsv.__init__   sg     	=LMMM\3//} 	N=LMMM((88


r,   rW   r5   rX   r!   c           
         | j                             d           t          j        | j                   }|st	          d| j        z            d |j        D             |_        ||j        vrd S i }|D ]h}||         |k    rZ|D ]W}||v r7|                    || j        	                    |||                   i           =t	          d| j        d|d          i|i k    rd S |S )Nr   z+Could not open DictReader for CSV-File '%s'c                 6    g | ]}|                                 S r$   r%   )r'   r6   s     r*   
<listcomp>z*CardKeyProviderCsv.get.<locals>.<listcomp>   s     BBB5BBBr,   z
CSV-File 'z' lacks column '')
rg   seekcsv
DictReaderrh   rb   
fieldnamesupdateri   rH   )r>   rW   r5   rX   crreturn_dictrowfs           r*   rZ   zCardKeyProviderCsv.get   s    1^DM** 	bLtO``aaaBBBMBBBbm##4 	g 	gC3x5   g gACxx#**Atz/G/G3q6/R/R+STTTT*lPTPaPaPacdcdcd+efff"4r,   N
rN   rO   rP   rQ   rT   rS   r?   r   r   rZ   r$   r,   r*   ra   ra      sx        ]]9S 9$ 9 9 9 9$s) # c d38n      r,   ra   c            
       V    e Zd ZdZdedefdZdee         dededeeef         fd	Z	d
S )CardKeyProviderPgsqlzdCard key provider implementation that allows to query against a specified PostgreSQL database table.config_filenamer0   c           	      >   ddl }t                              d|z             t          |d          5 }t	          j        |t          j                  }t                              d|                    d          z             |                    d          }|                    d	          }|t          d
          |	                    |                    d          |                    d          |                    d          |                    d                    | _
        |                    d          | _        t                              dt          | j                  z             t          |          | _        ddd           dS # 1 swxY w Y   dS )z
        Args:
                config_filename : file name (path) of CSV file containing card-individual key/data
                transport_keys : (see class CardKeyFieldCryptor)
        r   Nz.Using SQL database as card key data source: %srd   )LoaderzCard key database name: %sdb_namedb_usersreaderz1user for role 'reader' not set up in config file.r4   passhost)dbnameuserpasswordr   table_nameszCard key database tables: %s)psycopg2r<   re   rf   yamlload
FullLoaderrZ   
ValueErrorconnectconntablesrT   r   ri   )r>   rz   r0   r   cfgconfigr~   r   s           r*   r?   zCardKeyProviderPgsql.__init__   s    	AOSTTT/3'' 	=3Ys4?;;;FHH1FJJy4I4IIJJJzz*--H<<))D| !TUUU ((

90E0E.2hhv.>.>26((62B2B.4jj.@.@ ) B BDI !**]33DKHH3c$+6F6FFGGG,^<<DJ	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	= 	=s   EFFFrW   r5   rX   r!   c           	         dd l }ddlm}m} d }| j        D ]}| j                                         | j                                        }	|	                    d|f           |		                                }
|
g k    rt                              d|z             |                                f|
vr |d                               ||d                                                             }|dd          D ]>}| |d                               ||                                                    z  }?| |d                               ||                                           ||                                                    z  }|	                    ||f           |	                                }|	                                 |r n|d S t!          t#          ||                    }|                                D ]3}| j                            ||                    |                    ||<   4|S )	Nr   )
IdentifierSQLzISELECT column_name FROM information_schema.columns where table_name = %s;z<Card Key database seems to lack table %s, check config file!z	SELECT {}   z, {}z FROM {} WHERE {} = %s LIMIT 1;)r   psycopg2.sqlr   r   r   r   rollbackcursorexecutefetchallr<   warninglowerformatfetchonecloserS   zipkeysri   rH   rZ   )r>   rW   r5   rX   r   r   r   	db_resulttcurcols_resultqueryrv   resultr(   s                  r*   rZ   zCardKeyProviderPgsql.get   sI   00000000	 	 	AI   )""$$C KKcfgeijjj,,..Kb  Z]^^___		~[00 C$$++JJvay7H7H,I,IJJEABBZ C CV++JJqwwyy,A,ABBBSS:;;BB::aggiiCXCXBL*SYY[[BYBY[ [ [EKKx(((IIIKKK  4c&),,-- 	C 	CA
00FJJqMMBBF1IIr,   Nrw   r$   r,   r*   ry   ry      sx        nn= =T = = = =.$$s) $# $c $d38n $ $ $ $ $ $r,   ry   providerc                 x    t          | t                    st          d          |                    |            dS )zRegister a new card key provider.

    Args:
            provider : the to-be-registered provider
            provider_list : override the list of providers from the global default
    z$provider is not a card data providerN)
isinstancerV   r   append)r   provider_lists     r*   card_key_provider_registerr      s@     h00 A?@@@"""""r,   rW   r5   rX   r!   c                    |                                 }d | D             } |D ]}t          |t                    st          d          t                              d|d|dt          |          d           |                    | ||          }|r.t                              dt          |          z             |c S t          d|d|d	t          |           d          )
a  Query all registered card data providers for card-individual [key] data.

    Args:
            fields : list of valid field names such as 'ADM1', 'PIN1', ... which are to be obtained
            key : look-up key to identify card data, such as 'ICCID'
            value : value for look-up key to identify card data
            provider_list : override the list of providers from the global default
    Returns:
            dictionary of {field, value} strings for each requested field from 'fields'
    c                 6    g | ]}|                                 S r$   r%   )r'   rv   s     r*   rl   z)card_key_provider_get.<locals>.<listcomp>  s     (((Aaggii(((r,   z@Provider list contains element which is not a card data providerz!Searching for card key data (key=z, value=z, provider=)zFound card data: %sz"Unable to find card key data (key=z	, fields=)r&   r   rV   r   r<   r=   rT   rZ   )rW   r5   rX   r   pr   s         r*   card_key_provider_getr     s    ))++C(((((F  !_-- 	a_```			SVSVSVX]X]X]_bcd_e_e_e_efgggvsE** 	II+s6{{;<<<MMM	 *UXUXUXZ_Z_Z_adekalalalalm
n
nnr,   r6   c                     | g}t          |||t                    }|                    |                                           S )a  Query all registered card data providers for a single field.

    Args:
            field : name valid field such as 'ADM1', 'PIN1', ... which is to be obtained
            key : look-up key to identify card data, such as 'ICCID'
            value : value for look-up key to identify card data
            provider_list : override the list of providers from the global default
    Returns:
            dictionary of {field, value} strings for the requested field
    )r   card_key_providersrZ   r&   )r6   r5   rX   r   rW   r   s         r*   card_key_provider_get_fieldr   %  s9     WF"637IJJF::ekkmm$$$r,   )rQ   typingr   r   r   Cryptodome.Cipherr   osmocom.utilsr   r   	pySim.logr	   r^   ro   loggingr   rZ   rN   r<   r   r   ABCrV   ra   ry   r   listrT   r   r   r$   r,   r*   <module>r      s  	 	: ( ' ' ' ' ' ' ' ' ' ! ! ! ! ! ! " " " " " " " " ! ! ! ! ! ! 



 



  koh V7 V7 V7 V7 V7 V7 V7 V7p# # # # #cg # # #*# # # # # # # #J> > > > >? > > >B I[ 	# 	# 	# 	# 	# 	# Rd o o$s) o# oc ohlmprumuhv o o o o2 Qc % %s % %S %gj % % % % % %r,   