
\\+=                 @   s  d  Z  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 Z d d l	 m
 Z
 d d l m Z d d l m Z d d l m Z d d l m Z d d l m Z d d	 l m Z d d
 l m Z d d l m Z d d l m Z d d l m Z d d l m Z d d l m  Z  d d l m! Z! d d l m" Z" e j# e$  Z% d d d  Z& d d   Z' d d   Z( d d   Z) d d   Z* d d   Z+ d d    Z, d! d"   Z- d# d$   Z. d% d&   Z/ d' d(   Z0 d) d*   Z1 e j2 d+ d,  Z3 e j2 d- d.  Z4 e j2 d/ d0  Z5 d1 d2   Z6 d3 d4   Z7 e j2 d5 d6  Z8 e j2 d7 d8  Z9 d9 d:   Z: d; d<   Z; d= d>   Z< d? d@   Z= dA dB   Z> d S)CzCertbot client crypto utility functions.

.. todo:: Make the transition to use PSS rather than PKCS1_v1_5 when the server
    is capable of handling the signatures.

    N)InvalidSignature)default_backend)ECDSA)EllipticCurvePublicKey)PKCS1v15)RSAPublicKey)x509)crypto)SSL)crypto_util)IO)compat)errors)
interfaces)utilzkey-certbot.pemc             C   s   y t  |   } Wn> t k
 rP } z t j d d d |  WYd d } ~ Xn Xt j j t j  } t	 j
 | d t j   | j  t	 j t j j | |  d d  \ } } |  | j |  Wd QRXt j d |  |  t	 j | |  S)	a  Initializes and saves a privkey.

    Inits key and saves it in PEM format on the filesystem.

    .. note:: keyname is the attempted filename, it may be different if a file
        already exists at the path.

    :param int key_size: RSA key size in bits
    :param str key_dir: Key save directory.
    :param str keyname: Filename of key

    :returns: Key
    :rtype: :class:`certbot.util.Key`

    :raises ValueError: If unable to generate the key given key_size.

     exc_infoTNi  i  wbzGenerating key (%d bits): %s)make_key
ValueErrorloggererrorzope	component
getUtilityr   IConfigr   make_or_verify_dirr   
os_geteuidstrict_permissionsunique_fileospathjoinwritedebugZKey)Zkey_sizeZkey_dirZkeynameZkey_pemerrconfigZkey_fkey_path r(   5/usr/lib/python3/dist-packages/certbot/crypto_util.pyinit_save_key&   s    
$r*   c             C   s   t  j j t j  } t j |  j | d | j } t	 j
 | d t j   | j  t	 j t j j | d  d d  \ } } |  | j |  Wd QRXt j d |  t	 j | | d  S)	a2  Initialize a CSR with the given private key.

    :param privkey: Key to include in the CSR
    :type privkey: :class:`certbot.util.Key`

    :param set names: `str` names to include in the CSR

    :param str path: Certificate save directory.

    :returns: CSR
    :rtype: :class:`certbot.util.CSR`

    must_staplei  zcsr-certbot.pemi  r   NzCreating CSR: %spem)r   r   r   r   r   acme_crypto_utilZmake_csrr,   r+   r   r   r   r   r   r   r    r!   r"   r#   r   r$   CSR)privkeynamesr!   r&   Zcsr_pemZcsr_fZcsr_filenamer(   r(   r)   init_save_csrK   s    
$r1   c             C   s_   y, t  j t  j |   } | j | j    SWn, t  j k
 rZ t j d d d d SYn Xd S)zValidate CSR.

    Check if `csr` is a valid CSR for the given domains.

    :param str csr: CSR in PEM.

    :returns: Validity of CSR.
    :rtype: bool

    r   r   TFN)r	   load_certificate_requestFILETYPE_PEMverifyZ
get_pubkeyErrorr   r$   )csrreqr(   r(   r)   	valid_csro   s    r8   c             C   sn   t  j t  j |   } t  j t  j |  } y | j |  SWn, t  j k
 ri t j d d d d SYn Xd S)zDoes private key correspond to the subject public key in the CSR?

    :param str csr: CSR in PEM.
    :param str privkey: Private key file contents (PEM)

    :returns: Correspondence of private key to CSR subject public key.
    :rtype: bool

    r   r   TFN)r	   r2   r3   load_privatekeyr4   r5   r   r$   )r6   r/   r7   Zpkeyr(   r(   r)   csr_matches_pubkey   s    
r:   c             C   s   t  j } t  j } y | t  j |  } WnX t  j k
 r y | | |  } Wn- t  j k
 r} t j d j |     Yn XYn Xt |  } t  j | |  } | t	 j
 d |  d | d d  | f S)a/  Import a CSR file, which can be either PEM or DER.

    :param str csrfile: CSR filename
    :param str data: contents of the CSR file

    :returns: (`crypto.FILETYPE_PEM`,
               util.CSR object representing the CSR,
               list of domains requested in the CSR)
    :rtype: tuple

    zFailed to parse CSR file: {0}filedataZformr,   )r	   r3   r2   FILETYPE_ASN1r5   r   format"_get_names_from_loaded_cert_or_reqZdump_certificate_requestr   r.   )Zcsrfiler<   ZPEMloadr6   ZdomainsZdata_pemr(   r(   r)   import_csr_file   s    		"rA   c             C   sD   |  d k s t   t j   } | j t j |   t j t j |  S)zGenerate PEM encoded RSA key.

    :param int bits: Number of bits, at least 1024.

    :returns: new RSA key in PEM form with specified number of bits
    :rtype: str

    i   )AssertionErrorr	   ZPKeyZgenerate_keyZTYPE_RSAZdump_privatekeyr3   )bitskeyr(   r(   r)   r      s    	r   c             C   sC   y t  j t  j |   j   SWn t t  j f k
 r> d SYn Xd S)zIs valid RSA private key?

    :param str privkey: Private key file contents in PEM

    :returns: Validity of private key.
    :rtype: bool

    FN)r	   r9   r3   Zcheck	TypeErrorr5   )r/   r(   r(   r)   valid_privkey   s
    	rF   c             C   s+   t  |   t |   t |  j |  j  d S)a  For checking that your certs were not corrupted on disk.

    Several things are checked:
        1. Signature verification for the cert.
        2. That fullchain matches cert and chain when concatenated.
        3. Check that the private key matches the certificate.

    :param `.storage.RenewableCert` renewable_cert: cert to verify

    :raises errors.Error: If verification fails.
    N)verify_renewable_cert_sigverify_fullchainverify_cert_matches_priv_keycertr/   )renewable_certr(   r(   r)   verify_renewable_cert   s    

rL   c       	      C   s  yBt  |  j d  " } t j | j   t    } Wd QRXt  |  j d  " } t j | j   t    } Wd QRX| j   } t j	    t j
 d  t | t  r | j | j t   | j  } | j | j  | j   nY t | t  r+| j | j t | j   } | j | j  | j   n t j d   Wd QRXWn_ t t t f k
 r} z6 d j |  j |  } t j |  t j |   WYd d } ~ Xn Xd S)z Verifies the signature of a `.storage.RenewableCert` object.

    :param `.storage.RenewableCert` renewable_cert: cert to verify

    :raises errors.Error: If signature verification fails.
    rbNignorezUnsupported public key typez[verifying the signature of the cert located at {0} has failed.                 Details: {1})openchainr   Zload_pem_x509_certificatereadr   rJ   Z
public_keywarningscatch_warningssimplefilter
isinstancer   verifierZ	signaturer   Zsignature_hash_algorithmupdateZtbs_certificate_bytesr4   r   r   r   r5   IOErrorr   r   r>   r   	exception)	rK   
chain_filerP   	cert_filerJ   ZpkrV   e	error_strr(   r(   r)   rG      s.    ""rG   c             C   s   y: t  j t  j  } | j |   | j |  | j   Wn_ t t  j f k
 r } z6 d j |  | |  } t	 j
 |  t j |   WYd d } ~ Xn Xd S)z Verifies that the private key and cert match.

    :param str cert_path: path to a cert in PEM format
    :param str key_path: path to a private key file

    :raises errors.Error: If they don't match.
    zverifying the cert located at {0} matches the                 private key located at {1} has failed.                 Details: {2}N)r
   ZContextZSSLv23_METHODZuse_certificate_fileZuse_privatekey_fileZcheck_privatekeyrX   r5   r>   r   rY   r   )	cert_pathr'   contextr\   r]   r(   r(   r)   rI   	  s    	rI   c       	      C   s.  y t  |  j   } | j   } Wd QRXt  |  j   } | j   } Wd QRXt  |  j   } | j   } Wd QRX| | | k r d } | j |  j  } t j |   Wn} t	 k
 r } z0 d j |  } t
 j |  t j |   WYd d } ~ Xn. t j k
 r)} z |  WYd d } ~ Xn Xd S)z Verifies that fullchain is indeed cert concatenated with chain.

    :param `.storage.RenewableCert` renewable_cert: cert to verify

    :raises errors.Error: If cert and chain do not combine to fullchain.
    Nz.fullchain does not match cert + chain for {0}!z8reading one of cert, chain, or fullchain has failed: {0})rO   rP   rQ   rJ   	fullchainr>   Zlineagenamer   r5   rX   r   rY   )	rK   rZ   rP   r[   rJ   Zfullchain_filer`   r]   r\   r(   r(   r)   rH     s"    !rH   c             C   s   g  } xl t  j t  j f D]X } y t  j | |   | f SWq t  j k
 rp } z | j |  WYd d } ~ Xq Xq Wt j d j d j d d   | D     d S)z:Load PEM/DER certificate.

    :raises errors.Error:

    NzUnable to load: {0},c             s   s   |  ] } t  |  Vq d  S)N)str).0r   r(   r(   r)   	<genexpr>H  s    z-pyopenssl_load_certificate.<locals>.<genexpr>)	r	   r3   r=   load_certificater5   appendr   r>   r"   )r<   Zopenssl_errorsZ	file_typer   r(   r(   r)   pyopenssl_load_certificate9  s    $rg   c             C   sC   y | | |   SWn+ t  j k
 r> t j d d d   Yn Xd  S)Nr   r   T)r	   r5   r   r   )cert_or_req_str	load_functypr(   r(   r)   _load_cert_or_reqK  s
    rk   c             C   s   t  j t |  | |   S)N)r-   Z_pyopenssl_cert_or_req_sanrk   )rh   ri   rj   r(   r(   r)   _get_sans_from_cert_or_reqT  s    	rl   c             C   s   t  |  t j |  S)zGet a list of Subject Alternative Names from a certificate.

    :param str cert: Certificate (encoded).
    :param typ: `crypto.FILETYPE_PEM` or `crypto.FILETYPE_ASN1`

    :returns: A list of Subject Alternative Names.
    :rtype: list

    )rl   r	   re   )rJ   rj   r(   r(   r)   get_sans_from_cert[  s    
rm   c             C   s   t  |  | |  } t |  S)N)rk   r?   )Zcert_or_reqri   rj   loaded_cert_or_reqr(   r(   r)   _get_names_from_cert_or_reqi  s    ro   c             C   s   t  j |   S)N)r-   Z _pyopenssl_cert_or_req_all_names)rn   r(   r(   r)   r?   n  s    r?   c             C   s   t  |  t j |  S)zGet a list of domains from a cert, including the CN if it is set.

    :param str cert: Certificate (encoded).
    :param typ: `crypto.FILETYPE_PEM` or `crypto.FILETYPE_ASN1`

    :returns: A list of domain names.
    :rtype: list

    )ro   r	   re   )r6   rj   r(   r(   r)   get_names_from_certs  s    
rp   c             C   s   t  j |  |  S)zDump certificate chain into a bundle.

    :param list chain: List of `crypto.X509` (or wrapped in
        :class:`josepy.util.ComparableX509`).

    )r-   dump_pyopenssl_chain)rP   Zfiletyper(   r(   r)   rq     s    	rq   c             C   s   t  |  t j j  S)zWhen does the cert at cert_path start being valid?

    :param str cert_path: path to a cert in PEM format

    :returns: the notBefore value from the cert at cert_path
    :rtype: :class:`datetime.datetime`

    )_notAfterBeforer	   X509Zget_notBefore)r^   r(   r(   r)   	notBefore  s    	rt   c             C   s   t  |  t j j  S)zWhen does the cert at cert_path stop being valid?

    :param str cert_path: path to a cert in PEM format

    :returns: the notAfter value from the cert at cert_path
    :rtype: :class:`datetime.datetime`

    )rr   r	   rs   Zget_notAfter)r^   r(   r(   r)   notAfter  s    	ru   c             C   s   t  |   " } t j t j | j    } Wd QRX| |  } | d d  d | d d  d | d d  d | d d  d	 | d d
  d	 | d
 d  g } d j |  } t j r | j d  } t	 j
 |  S)aP  Internal helper function for finding notbefore/notafter.

    :param str cert_path: path to a cert in PEM format
    :param function method: one of ``crypto.X509.get_notBefore``
        or ``crypto.X509.get_notAfter``

    :returns: the notBefore or notAfter value from the cert at cert_path
    :rtype: :class:`datetime.datetime`

    Nr         -         T
      :       ascii)rO   r	   re   r3   rQ   r"   sixZPY3decode	pyrfc3339parse)r^   methodfr   Z	timestampZreformatted_timestampZtimestamp_strr(   r(   r)   rr     s      #	rr   c          
   C   sK   t  j   } t |  d  # } | j | j   j d   Wd QRX| j   S)aN  Compute a sha256sum of a file.

    NB: In given file, platform specific newlines characters will be converted
    into their equivalent unicode counterparts before calculating the hash.

    :param str filename: path to the file whose hash will be computed

    :returns: sha256 digest of the file in hexadecimal
    :rtype: str
    rzUTF-8N)hashlibsha256rO   rW   rQ   encodeZ	hexdigest)filenamer   Zfile_dr(   r(   r)   	sha256sum  s    #r   c             C   sP   t  j t  j t  j t  j |    j   } |  t |  d  j   } | | f S)zSplit fullchain_pem into cert_pem and chain_pem

    :param str fullchain_pem: concatenated cert + chain

    :returns: tuple of string cert_pem and chain_pem
    :rtype: tuple

    N)r	   Zdump_certificater3   re   r   lenlstrip)Zfullchain_pemrJ   rP   r(   r(   r)   cert_and_chain_from_fullchain  s    	r   )?__doc__r   Zloggingr    rR   r   r   Zzope.componentr   Zcryptography.exceptionsr   Zcryptography.hazmat.backendsr   Z,cryptography.hazmat.primitives.asymmetric.ecr   r   Z1cryptography.hazmat.primitives.asymmetric.paddingr   Z-cryptography.hazmat.primitives.asymmetric.rsar   Zcryptographyr   ZOpenSSLr	   r
   Zacmer   r-   Zacme.magic_typingr   Zcertbotr   r   r   r   Z	getLogger__name__r   r*   r1   r8   r:   rA   r   rF   rL   rG   rI   rH   rg   r3   rk   rl   rm   ro   r?   rp   rq   rt   ru   rr   r   r   r(   r(   r(   r)   <module>   s^   %$%	