a
    ifoG                     @   s.  d dl Z d dlZd dlZd dlZd dlZd dlZddlmZmZ e	
dd ddiB Zddd	Zd
ZdZddhh dh dddhh dh dh dh dh dh dd
ZG dd dZG dd dejZdd Ze dd Zd!d" Zd0d$d%ZG d&d' d'eZd(d) ZG d*d+ d+Zd,d- ZG d.d/ d/ZdS )1    N   )	alg_lists
validation)Zarbitrary_dh_groupsZmin_dh_sizeZmin_dsa_sizeZmin_rsa_sizeZsha1_in_certsZ	ssh_certsZmin_ec_size   )ANYZDISABLE_ETMZDISABLE_NON_ETM)ZDEFAULTZENFORCEZRELAX)ZetmZ__ems*)tlssslopensslnssgnutlsjava-tlssshopensshopenssh-serveropenssh-clientlibsshipsecike	libreswankerberoskrb5dnssecbindr   r   >   r	   r   r   >   r	   r   r   r   r   >   r   r   r   >   r   r   r   >   r   r	   r   >   r   r   r   >   r   r   r   >   r
   r	   r   )
r   r   r   r   r   r   r   r   r   r
   c                   @   s(   e Zd ZefddZdd Zdd ZdS )ScopeSelectorc                 C   s   |   | _}|d | _| jr&|n
|dd }tjj|| jd tjj|| jd |drr|dd dn|g| _	tjj
| j	t| jd dS )a=  
        Initialize a scope selector.
        An example would be `ssh` in `ciphers@ssh = -NULL`.
        When openssh backend will request the configuration,
        it'll offer (`{'ssh', 'openssh'}`) as scopes
        and the rule above will be taken into account.
        Both patterns and scopes are cast to lowercase.
        For more examples, refer to tests/unit/parsing/test_scope_selector.py
        >>> ss = ScopeSelector('!{SSH,IPsec}')
        >>> ss.matches({'ipsec', 'libreswan'})
        False
        >>> ss.matches({'tls', 'openssl'})
        True
        !r   N)Zoriginal_pattern{,)lowerpattern
startswith	_positiver   scopeZillegal_charactersZcurly_bracketssplit_globsZresulting_globs
ALL_SCOPES)selfr    p r)   B/usr/share/crypto-policies/python/cryptopolicies/cryptopolicies.py__init__>   s    $zScopeSelector.__init__c                 C   s   d| j dS )Nz<ScopeSelector pattern=>)r    r'   r)   r)   r*   __str__Y   s    zScopeSelector.__str__c                    sh   | j tkrdS dd  D  tdd  D s2J | jrPt fdd| jD S t fdd| jD S )aE  
        Checks whether ScopeSelector matches one of the scopes.
        For more examples, refer to tests/unit/parsing/test_scope_selector.py
        >>> ScopeSelector('{SSH,IPsec}').matches({'ipsec', 'libreswan'})
        True
        >>> ScopeSelector('!{SSH,IPsec}').matches({'ipsec', 'libreswan'})
        False
        Tc                 S   s   g | ]}|  qS r)   )r   .0sr)   r)   r*   
<listcomp>g       z)ScopeSelector.matches.<locals>.<listcomp>c                 s   s   | ]}|t v V  qd S N)r&   r/   r)   r)   r*   	<genexpr>h   r3   z(ScopeSelector.matches.<locals>.<genexpr>c                 3   s   | ]}t  |V  qd S r4   fnmatchfilterr0   gscopesr)   r*   r5   j   r3   c                 3   s   | ]}t  | V  qd S r4   r6   r9   r;   r)   r*   r5   k   r3   )r    	SCOPE_ANYallr"   anyr%   r'   r<   r)   r;   r*   matches\   s    	
zScopeSelector.matchesN)__name__
__module____qualname__r=   r+   r.   rA   r)   r)   r)   r*   r   =   s   r   c                   @   s0   e Zd ZdZdZdZdZdZdZdZ	dd	 Z
d
S )	OperationzCAn operation that comes with the right-hand value of the directive.r                  c                 C   s   d| j  S )Nz
Operation.)namer-   r)   r)   r*   __repr__z   s    zOperation.__repr__N)rB   rC   rD   __doc__RESETPREPENDAPPENDOMITSET_INTSET_ENUMrL   r)   r)   r)   r*   rE   p   s   rE   c                    s  dd  |   rxtjvr2tv r2tjt| fgS tjv sDtv rPtj	
tjvs^J tvsjJ tvsJ nHtv rtj	tv r| t vrtj	| t tj| fgS |  }t fdd|D sfdd|D }tjdfgdd |D  S t fd	d|D rg }|D ]}|d
rbtjt|dd ddd }n\|d
rtjt|dd ddd }n*|dsJ tjt|dd }|fdd|D  q,|S tj	| dS )ae  
    Parses right-hand parts of the directives
    into lists of operation/value pairs.
    For more examples, refer to tests/unit/test_parsing.py
    >>> parse_rhs('', 'cipher')
    [(Operation.RESET, None)]
    >>> parse_rhs('IDEA-CBC SEED-CBC', 'cipher')
    [(Operation.RESET, None),
     (Operation.APPEND, 'IDEA-CBC'),
     (Operation.APPEND, 'SEED-CBC')]
    >>> # 3DES-CBC gets prepended last for higher prio
    >>> parse_rhs('+*DES-CBC', 'cipher')
    [(Operation.PREPEND, 'DES-CBC'),
     (Operation.PREPEND, '3DES-CBC')]
    >>> parse_rhs('ENFORCE', '__ems')
    [(Operation.SET_ENUM, 'ENFORCE')]
    c                 S   s   |  dp| dS )N)+-rT   )r!   endswith)vr)   r)   r*   differential   s    zparse_rhs.<locals>.differentialc                 3   s   | ]} |V  qd S r4   r)   r0   rW   rX   r)   r*   r5      r3   zparse_rhs.<locals>.<genexpr>c                    s"   g | ]}t | D ]}|qqS r)   )r   glob)r0   rW   x	prop_namer)   r*   r2      r3   zparse_rhs.<locals>.<listcomp>Nc                 S   s   g | ]}t j|fqS r)   )rE   rP   rY   r)   r)   r*   r2      r3   c                 3   s   | ]} |V  qd S r4   r)   rY   rZ   r)   r*   r5      r3   rT   r   r   rU   c                    s   g | ]} |fqS r)   r)   rY   )opr)   r*   r2      r3   )isdigitr   ALLINT_DEFAULTSrE   rR   intENUMSr   rulesZNonIntPropertyIntValueErrorZIntPropertyNonIntValueErrorZBadEnumValueErrorrS   r$   r?   rN   r>   r!   rO   r[   rV   rP   rQ   extendZ%MixedDifferentialNonDifferentialError)rhsr^   valuesZ
operationsvalueZunglobr)   )rX   r_   r^   r*   	parse_rhs~   sL    

  rj   	Directiver^   r#   	operationri   c                    s   |   sg S tj|  | d\}}|  |   }}tj||  d|v rZ|ddn|tf\  fddt| D S )aQ  
    Parses configuration lines into tuples of directives.
    For more examples, refer to tests/unit/test_parsing.py
    >>> parse_line('cipher@TLS = RC4* NULL')
    [Directive(prop_name='cipher', scope='tls',
               operation=Operation.RESET, value=None),
     Directive(prop_name='cipher', scope='tls',
               operation=Operation.APPEND, value='RC4-40'),
     Directive(prop_name='cipher', scope='tls',
               operation=Operation.APPEND, value='RC4-128'),
     Directive(prop_name='cipher', scope='tls',
               operation=Operation.APPEND, value='NULL')]
    =@r   c                    s$   g | ]\}}t   ||d qS )rl   )rk   r   )r0   rm   ri   r^   r#   r)   r*   r2      s   
zparse_line.<locals>.<listcomp>)stripr   re   Zcount_equals_signsr$   Z	empty_lhsr=   rj   )lineZlhsrg   r)   rp   r*   
parse_line   s     rs   Fc              
   C   s\   z t | }|D ]}t|j qW n6 tjyV } z|s8 t| W Y d }~n
d }~0 0 d S r4   )rs   r   r#   r   ZPolicySyntaxErrorwarningswarn)rr   ru   ldexr)   r)   r*   syntax_check_line   s    ry   c                       s   e Zd Z fddZ  ZS )PolicySyntaxDeprecationWarningc                    s@   | dd}d| d}|d| d7 }|d7 }t | d S )N
z and zoption z is deprecatedz", please rewrite your rules using z; z2be advised that it is not always a 1-1 replacement)replacesuperr+   )r'   Z
deprecatedZreplacementmsg	__class__r)   r*   r+      s
    z'PolicySyntaxDeprecationWarning.__init__)rB   rC   rD   r+   __classcell__r)   r)   r   r*   rz      s   rz   c                 C   s  t dd| } | dd} ddd | dD } | dd} dd	d | dD } dd
d | dD } t dd|  } t d| rtt	dd ddddd}|
 D ]`\}}d| d }t || }|rtt	|| t |d| } |D ]}| d| d| 7 } qqt dd|  } ddddddd}|
 D ]x\}}d| d }i }t || D ]}	t ||| ||	d< qj|
 D ]\}
}tt	|
| qt ||| } qFttjd d d! }|r,d"d#d |d d! D }t d$|d!  d |rd%| nd| } |  qt d&d| } ttjd d d! }|rd"d'd |d d! D }t d(|d!  d |rd%| nd| } |  qNt d)d| S )*a  
    Preprocesses text before parsing.
    Fixes line breaks, handles backwards compatibility.
    >>> preprocess_text('cipher = c1 \\ \nc2#x')
    'cipher = c1 c2'
    >>> with warnings.catch_warnings():
    ...     warnings.simplefilter("ignore")
    ...     preprocess_text('ike_protocol = IKEv2')
    'protocol@IKE = IKEv2'
    >>> with warnings.catch_warnings():
    ...     warnings.simplefilter("ignore")
    ...     preprocess_text('min_tls_version=TLS1.3')
    'protocol@TLS = -SSL2.0 -SSL3.0 -TLS1.0 -TLS1.1 -TLS1.2'
    z#.* rn    = r{   c                 s   s   | ]}|  V  qd S r4   rq   r0   rv   r)   r)   r*   r5     r3   z"preprocess_text.<locals>.<genexpr>z\
c                 s   s   | ]}|  V  qd S r4   r   r   r)   r)   r*   r5   	  r3   c                 s   s   | ]}t d d|V  qdS )z\s+ N)resubr   r)   r)   r*   r5   
  r3   z
+z\bprotocol\s*=protocolzprotocol@TLSz
cipher@TLSz
cipher@SSHz	group@SSHzprotocol@IKE)Z
tls_cipherZ
ssh_cipherZ	ssh_groupZike_protocolz\bz\s*=(.*)z

z =z7hash@DNSSec = -SHA1
sign@DNSSec = -RSA-SHA1 -ECDSA-SHA1z7hash@DNSSec = SHA1+
sign@DNSSec = RSA-SHA1+ ECDSA-SHA1+zetm@SSH = DISABLE_ETMzetm@SSH = ANYzetm@\1 = DISABLE_ETMzetm@\1 = ANY)zsha1_in_dnssec = 0zsha1_in_dnssec = 1zssh_etm = 0zssh_etm = 1zssh_etm@([^= ]+) = 0zssh_etm@([^= ]+) = 1r   Nr   r   c                 s   s   | ]}d | V  qdS rU   Nr)   rY   r)   r)   r*   r5   8  r3   z\bmin_dtls_version = zprotocol@TLS = z\bmin_dtls_version = 0\bc                 s   s   | ]}d | V  qdS r   r)   rY   r)   r)   r*   r5   @  r3   z\bmin_tls_version = z\bmin_tls_version = 0\b)r   r   r|   joinr$   rq   findallrt   ru   rz   itemsfinditergrouplistr   ZDTLS_PROTOCOLSpopZTLS_PROTOCOLS)textZPOSTFIX_REPLACEMENTSfrtoZregexmsmZPLAIN_REPLACEMENTSrA   matchZmatch_frZmatch_toZdtls_versionsnegZtls_versionsr)   r)   r*   preprocess_text   sp    r   c                   @   sJ   e Zd ZdZdddZedd Zedd Zed	d
 Zedd Z	dS )ScopedPolicya  
    An entity constructing lists of what's `.enabled` and what's `.disabled`
    when the given scopes are active.
    >>> sp = ScopedPolicy(parse_line('cipher@TLS = RC4* NULL'), {'tls'})
    >>> 'AES-192-GCM' in sp.disabled['cipher']
    True
    >>> sp.enabled['cipher']
    ['RC4-40', 'RC4-128', 'NULL']
    >>> ScopedPolicy(parse_line('min_dh_size=2048')).integers['min_dh_size']
    2048
    Nc                    s  |pt  }t _dd t D _dd tjD _	|D ] t
 j}||r> jtjkrrg j	 j< q> jtjkrj	 j } j|vr| j q> jtjkrj	 j } j|v r| j |d j q> jtjkr fddj	 j D j	 j< q> jtjkr0 jj j< q> jtjksBJ  jj j< q>tj	tt j	kspJ fddtj D _d S )Nc                 S   s   i | ]\}}||d  qS )r   r)   )r0   krW   r)   r)   r*   
<dictcomp>Y  r3   z)ScopedPolicy.__init__.<locals>.<dictcomp>c                 S   s   i | ]
}|g qS r)   r)   )r0   r^   r)   r)   r*   r   Z  r3   r   c                    s   g | ]}| j kr|qS r)   )ri   r0   e)	directiver)   r*   r2   m  s   
z)ScopedPolicy.__init__.<locals>.<listcomp>c                    s&   i | ]\ }  fd d|D qS )c                    s   g | ]}|j   vr|qS r)   )enabledr   )r^   r'   r)   r*   r2   x  s   z4ScopedPolicy.__init__.<locals>.<dictcomp>.<listcomp>r)   )r0   Zalg_listr-   r]   r*   r   x  s   )setrb   copyintegersrd   r   enumsr   ra   r   r   r#   rA   rm   rE   rN   r^   rP   ri   appendrO   removeinsertrQ   rR   rS   lenZdisabled)r'   
directivesZrelevant_scopesssr   r)   )r   r'   r*   r+   V  s<    









zScopedPolicy.__init__c                 C   s   t | jd S Nr   )r   min_tls_versionr   r-   r)   r)   r*   r   |  s    zScopedPolicy.min_tls_versionc                 C   s   t | jd S r   )r   max_tls_versionr   r-   r)   r)   r*   r     s    zScopedPolicy.max_tls_versionc                 C   s   t | jd S r   )r   min_dtls_versionr   r-   r)   r)   r*   r     s    zScopedPolicy.min_dtls_versionc                 C   s   t | jd S r   )r   max_dtls_versionr   r-   r)   r)   r*   r     s    zScopedPolicy.max_dtls_version)N)
rB   rC   rD   rM   r+   propertyr   r   r   r   r)   r)   r)   r*   r   I  s   
&


r   c                 C   s@   |D ](}t j||}t |t jr|  S qt| ||d S r4   )ospathr   accessR_OKr   ZPolicyFileNotFoundError)
policynamefnamepathsrw   r(   r)   r)   r*   lookup_file  s
    
r   c                   @   sF   e Zd ZdZdZddddZdd Zdd	d
ZdddZdd Z	dS )UnscopedCryptoPolicyz/etc/crypto-policiesz/usr/share/crypto-policiesN)	policydirc                G   sP   || _ d|g|R | _g | _| |}|D ]}|| j|dd7 }q.|| _d S )N:T)	subpolicy)r   r   r   linesread_policy_file_directives)r'   Zpolicy_namer   Zsubpolicy_namesr   Zsubpolicy_namer)   r)   r*   r+     s    
zUnscopedCryptoPolicy.__init__c                 C   s   | j  S r4   )r   r-   r)   r)   r*   is_empty  s    zUnscopedCryptoPolicy.is_emptyc                 C   s   t | j|pi S r4   )r   r   r@   r)   r)   r*   scoped  s    zUnscopedCryptoPolicy.scopedFc           	   
   C   s   | j pd}|rtj|d}t|||s*dnd tjj|tj| j|tj| j|f}t|dd}|	 }W d    n1 s0    Y  t
|}|d}|D ]}t|dd	 q|D ]}t| qd
d |D S )NZpoliciesmodulesz.polz.pmodzutf-8)encodingr{   T)ru   c                 S   s   g | ]}t |D ]}|qqS r)   )rs   )r0   rv   r\   r)   r)   r*   r2     r3   z9UnscopedCryptoPolicy.read_policy_file.<locals>.<listcomp>)r   r   r   r   r   curdir
CONFIG_DIR	SHARE_DIRopenreadr   r$   ry   )	r'   rK   r   Zpdirr(   fr   r   rv   r)   r)   r*   r     s(    
&

z%UnscopedCryptoPolicy.read_policy_filec                 C   s  dd }|   }d| j d}|d7 }|d7 }|d7 }|d7 }|d7 }i |j|j|j}| D ]\}}||||7 }qdd	}t D ]p\}}	| j |	d
}
i |
j|
j|
j}| D ]<\}}||| kr|s|d7 }d}||| d| |7 }qq|s|d7 }|S )Nc                 S   s2   t |trd|nt|}|  d|  d S )Nr   r   r{   )
isinstancer   r   strrstrip)keyri   r1   r)   r)   r*   fmt  s    z)UnscopedCryptoPolicy.__str__.<locals>.fmtz	# Policy z dump
z#
z?# Do not parse the contents of this file with automated tools,
z.# it is provided for review convenience only.
z"# Baseline values for all scopes:
Fr;   z9# Scope-specific properties derived for select backends:
Tro   z&# No scope-specific properties found.
)r   r   r   r   r   r   DUMPABLE_SCOPES)r'   r   Zgeneric_scopedr1   Zgeneric_allr^   ri   Zanything_scope_specificZ
scope_nameZ	scope_setZspecific_scopedZspecific_allr)   r)   r*   r.     s@    zUnscopedCryptoPolicy.__str__)N)F)
rB   rC   rD   r   r   r+   r   r   r   r.   r)   r)   r)   r*   r     s   

r   )F)collectionsenumr7   r   r   rt   r   r   r   dictfromkeysrb   rd   r=   r&   r   r   EnumrE   rj   
namedtuplerk   rs   ry   FutureWarningrz   r   r   r   r   r)   r)   r)   r*   <module>   sL   3B
	SF
