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                    sR   | j tkrdS dd  D  | jr:t 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                 3   s   | ]}t  |V  qd S Nfnmatchfilterr/   gscopesr)   r*   	<genexpr>j   r2   z(ScopeSelector.matches.<locals>.<genexpr>c                 3   s   | ]}t  | V  qd S r3   r4   r7   r9   r)   r*   r;   k   r2   )r    	SCOPE_ANYr"   anyr%   allr'   r:   r)   r9   r*   matches\   s    	
zScopeSelector.matchesN)__name__
__module____qualname__r<   r+   r.   r@   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)rA   rB   rC   __doc__RESETPREPENDAPPENDOMITSET_INTSET_ENUMrK   r)   r)   r)   r*   rD   p   s   rD   c                    s  dd  |   rRtjvr2tv r2tjt| fgS tjv sDtv rtj	
nHtv rft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
r:tjt|dd ddd }nL|d
rltjt|dd ddd }n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)+-rS   )r!   endswith)vr)   r)   r*   differential   s    zparse_rhs.<locals>.differentialc                 3   s   | ]} |V  qd S r3   r)   r/   rV   rW   r)   r*   r;      r2   zparse_rhs.<locals>.<genexpr>c                    s"   g | ]}t | D ]}|qqS r)   )r   glob)r/   rV   x	prop_namer)   r*   r1      r2   zparse_rhs.<locals>.<listcomp>Nc                 S   s   g | ]}t j|fqS r)   )rD   rO   rX   r)   r)   r*   r1      r2   c                 3   s   | ]} |V  qd S r3   r)   rX   rY   r)   r*   r;      r2   rS   r   r   c                    s   g | ]} |fqS r)   r)   rX   )opr)   r*   r1      r2   )isdigitr   ALLINT_DEFAULTSrD   rQ   intENUMSr   rulesZNonIntPropertyIntValueErrorZIntPropertyNonIntValueErrorZBadEnumValueErrorrR   r$   r=   rM   r>   r!   rN   rZ   rU   rO   rP   extendZ%MixedDifferentialNonDifferentialError)rhsr]   valuesZ
operationsvalueZunglobr)   )rW   r^   r]   r*   	parse_rhs~   sF    

  ri   	Directiver]   r#   	operationrh   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 )rk   )rj   r   )r/   rl   rh   r]   r#   r)   r*   r1      s   
zparse_line.<locals>.<listcomp>)stripr   rd   Zcount_equals_signsr$   Z	empty_lhsr<   ri   )lineZlhsrf   r)   ro   r*   
parse_line   s     rr   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 r3   )rr   r   r#   r   ZPolicySyntaxErrorwarningswarn)rq   rt   ldexr)   r)   r*   syntax_check_line   s    rx   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__)rA   rB   rC   r+   __classcell__r)   r)   r~   r*   ry      s   ry   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#.* rm    = rz   c                 s   s   | ]}|  V  qd S r3   rp   r/   ru   r)   r)   r*   r;     r2   z"preprocess_text.<locals>.<genexpr>z\
c                 s   s   | ]}|  V  qd S r3   r   r   r)   r)   r*   r;   	  r2   c                 s   s   | ]}t d d|V  qdS )z\s+ N)resubr   r)   r)   r*   r;   
  r2   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 rT   Nr)   rX   r)   r)   r*   r;   8  r2   z\bmin_dtls_version = zprotocol@TLS = z\bmin_dtls_version = 0\bc                 s   s   | ]}d | V  qdS r   r)   rX   r)   r)   r*   r;   @  r2   z\bmin_tls_version = z\bmin_tls_version = 0\b)r   r   r{   joinr$   rp   findallrs   rt   ry   itemsfinditergrouplistr   ZDTLS_PROTOCOLSpopZTLS_PROTOCOLS)textZPOSTFIX_REPLACEMENTSfrtoZregexmsmZPLAIN_REPLACEMENTSr@   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j j< q>fddtj D _d S )Nc                 S   s   i | ]\}}||d  qS )r   r)   )r/   krV   r)   r)   r*   
<dictcomp>Y  r2   z)ScopedPolicy.__init__.<locals>.<dictcomp>c                 S   s   i | ]
}|g qS r)   r)   )r/   r]   r)   r)   r*   r   Z  r2   r   c                    s   g | ]}| j kr|qS r)   )rh   r/   e)	directiver)   r*   r1   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*   r1   x  s   z4ScopedPolicy.__init__.<locals>.<dictcomp>.<listcomp>r)   )r/   Zalg_listr-   r\   r*   r   x  s   )setra   copyintegersrc   r   enumsr   r`   r   r   r#   r@   rl   rD   rM   r]   rO   rh   appendrN   removeinsertrP   rQ   Zdisabled)r'   
directivesZrelevant_scopesssr   r)   )r   r'   r*   r+   V  s8    









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)
rA   rB   rC   rL   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 r3   )ospathr   accessR_OKr   ZPolicyFileNotFoundError)
policynamefnamepathsrv   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 r3   )r   r-   r)   r)   r*   is_empty  s    zUnscopedCryptoPolicy.is_emptyc                 C   s   t | j|pi S r3   )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)encodingrz   T)rt   c                 S   s   g | ]}t |D ]}|qqS r)   )rr   )r/   ru   r[   r)   r)   r*   r1     r2   z9UnscopedCryptoPolicy.read_policy_file.<locals>.<listcomp>)r   r   r   r   r   curdir
CONFIG_DIR	SHARE_DIRopenreadr   r$   rx   )	r'   rJ   r   Zpdirr(   fr   r   ru   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   rz   )
isinstancer   r   strrstrip)keyrh   r0   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:
Fr9   z9# Scope-specific properties derived for select backends:
Trn   z&# No scope-specific properties found.
)r   r   r   r   r   r   DUMPABLE_SCOPES)r'   r   Zgeneric_scopedr0   Zgeneric_allr]   rh   Zanything_scope_specificZ
scope_nameZ	scope_setZspecific_scopedZspecific_allr)   r)   r*   r.     s@    zUnscopedCryptoPolicy.__str__)N)F)
rA   rB   rC   r   r   r+   r   r   r   r.   r)   r)   r)   r*   r     s   

r   )F)collectionsenumr5   r   r   rs   r   r   r   dictfromkeysra   rc   r<   r&   r   r   EnumrD   ri   
namedtuplerj   rr   rx   FutureWarningry   r   r   r   r   r)   r)   r)   r*   <module>   sL   3B
	SF
