
_c           @   s  d  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 m	 Z	 d d l
 m Z d d l m Z d d l m Z m Z d d l m Z d d	 l m Z d d
 l m Z m Z m Z d d l m Z d d l m 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* e j+ e,  Z- d d d d  Z. d   Z/ d   Z0 d   Z1 d   Z2 d d d d  Z4 d   Z5 d   Z6 d   Z7 d    Z8 d!   Z9 d"   Z: d#   Z; e j< d$  Z= e j< d%  Z> e j< d&  Z? d'   Z@ d(   ZA e j< d)  ZB e j< d*  ZC d+   ZD d,   ZE d-   ZF d.   ZG e jH d/ e jI  ZJ d0   ZK d1   ZL eM d2  ZN d S(3   s   Certbot 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.

iN(   t   x509(   t   InvalidSignaturet   UnsupportedAlgorithm(   t   default_backend(   t   ec(   t   ECDSAt   EllipticCurvePublicKey(   t   PKCS1v15(   t   RSAPublicKey(   t   Encodingt   NoEncryptiont   PrivateFormat(   t   crypto(   t   SSL(   t   crypto_util(   t   IO(   t   errors(   t
   interfaces(   t   util(   t   ost   rsat	   secp256r1s   key-certbot.pemc   
      C   s  y% t  d |  d | p d d |  } Wn, t k
 rS } t j d d t |  n Xt j j t j	  } t
 j | d | j  t
 j t j j | |  d d	  \ } }	 |  | j |  Wd
 QX| d k r t j d |  |	  n t j d |  |	  t
 j |	 |  S(   si  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: key size in bits if key size is rsa.
    :param str key_dir: Key save directory.
    :param str key_type: Key Type [rsa, ecdsa]
    :param str elliptic_curve: Name of the elliptic curve if key type is ecdsa.
    :param str keyname: Filename of key

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

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

    t   bitst   elliptic_curveR   t   key_typet    t   exc_infoi  i  t   wbNR   s    Generating RSA key (%d bits): %ss"   Generating ECDSA key (%d bits): %s(   t   make_keyt
   ValueErrort   loggert   errort   Truet   zopet	   componentt
   getUtilityR   t   IConfigR   t   make_or_verify_dirt   strict_permissionst   unique_fileR   t   patht   joint   writet   debugt   Key(
   t   key_sizet   key_dirR   R   t   keynamet   key_pemt   errt   configt   key_ft   key_path(    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyt   init_save_key'   s     
$c         C   s   t  j j t j  } t j |  j | d | j } t	 j
 | d | j  t	 j t j j | d  d d  \ } } |  | j |  Wd QXt j d |  t	 j | | d  S(	   s2  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`

    t   must_staplei  s   csr-certbot.pemi  R   Ns   Creating CSR: %st   pem(   R!   R"   R#   R   R$   t   acme_crypto_utilt   make_csrR7   R6   R   R%   R&   R'   R   R(   R)   R*   R   R+   t   CSR(   t   privkeyt   namesR(   R2   t   csr_pemt   csr_ft   csr_filename(    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyt   init_save_csrT   s    $c         C   s[   y, t  j t  j |   } | j | j    SWn( t  j k
 rV t j d d t t	 SXd S(   s   Validate 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   N(
   R   t   load_certificate_requestt   FILETYPE_PEMt   verifyt
   get_pubkeyt   ErrorR   R+   R    t   False(   t   csrt   req(    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyt	   valid_csrw   s    c         C   sj   t  j t  j |   } t  j t  j |  } y | j |  SWn( t  j k
 re t j d d t t	 SXd S(   s   Does 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   N(
   R   RA   RB   t   load_privatekeyRC   RE   R   R+   R    RF   (   RG   R;   RH   t   pkey(    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyt   csr_matches_pubkey   s    
c         C   s   t  j } t  j } y | t  j |  } WnV t  j k
 r y | | |  } Wq t  j k
 r| t j d j |     q Xn Xt |  } t  j | |  } | t	 j
 d |  d | d d  | f S(   s/  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

    s   Failed to parse CSR file: {0}t   filet   datat   formR7   (   R   RB   RA   t   FILETYPE_ASN1RE   R   t   formatt"   _get_names_from_loaded_cert_or_reqt   dump_certificate_requestR   R:   (   t   csrfileRN   t   PEMt   loadRG   t   domainst   data_pem(    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyt   import_csr_file   s    		 i   c         C   s  | d k rU |  d k  r3 t  j d j |     n  t j   } | j t j |   n)| d k rfyg | j   } | d k r t j	 d t
 t | j   d    d	 t    } n t  j d
 j |    Wn\ t k
 r t  j d
 j |    n4 t k
 r&} t j | t  j t |     n X| j d t j d t j d t    } t j t j |  } n t  j d j |    t j t j |  S(   sD  Generate PEM encoded RSA|EC key.

    :param int bits: Number of bits if key_type=rsa. At least 1024 for RSA.

    :param str ec_curve: The elliptic curve to use.

    :returns: new RSA or ECDSA key in PEM form with specified number of bits
              or of type ec_curve when key_type ecdsa is used.
    :rtype: str
    R   i   s   Unsupported RSA key length: {}t   ecdsat	   SECP256R1t	   SECP384R1t	   SECP512R1t   curvet   backends   Unsupported elliptic curve: {}t   encodingRQ   t   encryption_algorithms0   Invalid key_type specified: {}.  Use [rsa|ecdsa](   R[   R\   R]   N(   R   RE   RQ   R   t   PKeyt   generate_keyt   TYPE_RSAt   upperR   t   generate_private_keyt   getattrt   NoneR   t	   TypeErrorR   t   sixt
   raise_fromt   strt   private_bytesR	   RU   R   t   TraditionalOpenSSLR
   RJ   RB   t   dump_privatekey(   R   R   R   t   keyt   namet   _keyt   et   _key_pem(    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyR      s0    	%			c         C   s?   y t  j t  j |   j   SWn t t  j f k
 r: t SXd S(   s   Is valid RSA private key?

    :param str privkey: Private key file contents in PEM

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

    N(   R   RJ   RB   t   checkRi   RE   RF   (   R;   (    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyt   valid_privkey   s
    	c         C   s+   t  |   t |   t |  j |  j  d S(   s  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 renewable_cert: cert to verify
    :type renewable_cert: certbot.interfaces.RenewableCert

    :raises errors.Error: If verification fails.
    N(   t   verify_renewable_cert_sigt   verify_fullchaint   verify_cert_matches_priv_keyt	   cert_pathR4   (   t   renewable_cert(    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyt   verify_renewable_cert   s    

c         C   s   y t  |  j d  " } t j | j   t    } Wd QXt  |  j d  " } t j | j   t    } Wd QX| j   } t j	   ! t
 | | j | j | j  Wd QXWnM t t t f k
 r } d j |  j |  } t j |  t j |   n Xd S(   s   Verifies the signature of a RenewableCert object.

    :param renewable_cert: cert to verify
    :type renewable_cert: certbot.interfaces.RenewableCert

    :raises errors.Error: If signature verification fails.
    t   rbNsb   verifying the signature of the certificate located at {0} has failed.                 Details: {1}(   t   opent
   chain_pathR    t   load_pem_x509_certificatet   readR   Rz   t
   public_keyt   warningst   catch_warningst   verify_signed_payloadt	   signaturet   tbs_certificate_bytest   signature_hash_algorithmt   IOErrorR   R   RQ   R   t	   exceptionR   RE   (   R{   t
   chain_filet   chaint	   cert_filet   certt   pkRs   t	   error_str(    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyRw     s    !!c         C   s   t  j    t  j d  t |  t  r[ |  j | t   |  } | j |  | j   nP t |  t	  r |  j | t
 |   } | j |  | j   n t j d   Wd QXd S(   s  Check the signature of a payload.

    :param RSAPublicKey/EllipticCurvePublicKey public_key: the public_key to check signature
    :param bytes signature: the signature bytes
    :param bytes payload: the payload bytes
    :param cryptography.hazmat.primitives.hashes.HashAlgorithm
           signature_hash_algorithm: algorithm used to hash the payload

    :raises InvalidSignature: If signature verification fails.
    :raises errors.Error: If public key type is not supported
    t   ignores   Unsupported public key typeN(   R   R   t   simplefiltert
   isinstanceR   t   verifierR   t   updateRC   R   R   R   RE   (   R   R   t   payloadR   R   (    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyR      s    c         C   s   y: t  j t  j  } | j |   | j |  | j   WnM t t  j f k
 r } d j |  | |  } t	 j
 |  t j |   n Xd S(   s    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.
    s   verifying the certificate located at {0} matches the                 private key located at {1} has failed.                 Details: {2}N(   R   t   Contextt   SSLv23_METHODt   use_certificate_filet   use_privatekey_filet   check_privatekeyR   RE   RQ   R   R   R   (   Rz   R4   t   contextRs   R   (    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyRy   ?  s    	c   	      C   s
  y t  |  j   } | j   } Wd QXt  |  j   } | j   } Wd QXt  |  j   } | j   } Wd QX| | | k r d } | j |  j  } t j |   n  WnY t	 k
 r } d j |  } t
 j |  t j |   n t j k
 r} |  n Xd S(   s    Verifies that fullchain is indeed cert concatenated with chain.

    :param renewable_cert: cert to verify
    :type renewable_cert: certbot.interfaces.RenewableCert

    :raises errors.Error: If cert and chain do not combine to fullchain.
    Ns.   fullchain does not match cert + chain for {0}!s8   reading one of cert, chain, or fullchain has failed: {0}(   R~   R   R   Rz   t   fullchain_pathRQ   t   lineagenameR   RE   R   R   R   (	   R{   R   R   R   R   t   fullchain_filet	   fullchainR   Rs   (    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyRx   U  s"    c         C   s   g  } xZ t  j t  j f D]F } y t  j | |   | f SWq t  j k
 r^ } | j |  q Xq Wt j d j d j d   | D     d S(   s:   Load PEM/DER certificate.

    :raises errors.Error:

    s   Unable to load: {0}t   ,c         s   s   |  ] } t  |  Vq d  S(   N(   Rl   (   t   .0R   (    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pys	   <genexpr>  s    N(	   R   RB   RP   t   load_certificateRE   t   appendR   RQ   R)   (   RN   t   openssl_errorst	   file_typeR   (    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyt   pyopenssl_load_certificatep  s    c         C   sB   y | | |   SWn* t  j k
 r= t j d d t   n Xd  S(   NR   R   (   R   RE   R   R   R    (   t   cert_or_req_strt	   load_funct   typ(    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyt   _load_cert_or_req  s
    c         C   s   t  j t |  | |   S(   N(   R8   t   _pyopenssl_cert_or_req_sanR   (   R   R   R   (    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyt   _get_sans_from_cert_or_req  s    	c         C   s   t  |  t j |  S(   s   Get 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

    (   R   R   R   (   R   R   (    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyt   get_sans_from_cert  s    
c         C   s   t  |  | |  } t |  S(   N(   R   RR   (   t   cert_or_reqR   R   t   loaded_cert_or_req(    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyt   _get_names_from_cert_or_req  s    c         C   s   t  j |   S(   N(   R8   t    _pyopenssl_cert_or_req_all_names(   R   (    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyRR     s    c         C   s   t  |  t j |  S(   s   Get 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

    (   R   R   R   (   RG   R   (    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyt   get_names_from_cert  s    
c         C   s   t  j |  |  S(   s   Dump certificate chain into a bundle.

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

    (   R8   t   dump_pyopenssl_chain(   R   t   filetype(    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyR     s    	c         C   s   t  |  t j j  S(   s   When 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`

    (   t   _notAfterBeforeR   t   X509t   get_notBefore(   Rz   (    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyt	   notBefore  s    	c         C   s   t  |  t j j  S(   s   When 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`

    (   R   R   R   t   get_notAfter(   Rz   (    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyt   notAfter  s    	c         C   s   t  |  d  " } t j t j | j    } Wd QX| |  } | d d !d | d d !d | d d !d | d d	 !d
 | d	 d !d
 | d g } d j |  } t j r | j d  } n | } t	 j
 |  S(   sP  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`

    R}   Ni    i   t   -i   i   t   Ti
   t   :i   R   t   ascii(   R~   R   R   RB   R   R)   Rj   t   PY3t   decodet	   pyrfc3339t   parse(   Rz   t   methodt   fR    t	   timestampt   reformatted_timestampt   timestamp_bytest   timestamp_str(    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyR     s    !	c         C   sJ   t  j   } t |  d  # } | j | j   j d   Wd QX| j   S(   sN  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
    t   rs   UTF-8N(   t   hashlibt   sha256R~   R   R   t   encodet	   hexdigest(   t   filenameR   t   file_d(    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyt	   sha256sum  s    "s@   -----BEGIN CERTIFICATE-----?
.+??
-----END CERTIFICATE-----?
c         C   s   t  j |  j    } t |  d k  r= t j d d   n  g  | D]0 } t j t j t j	 t j |   j
   ^ qD } | d d j | d  f S(   s  Split 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

    :raises errors.Error: If there are less than 2 certificates in the chain.

    i   s/   failed to parse fullchain into cert and chain: s!   less than 2 certificates in chaini    R   i   (   t   CERT_PEM_REGEXt   findallR   t   lenR   RE   R   t   dump_certificateRB   R   R   R)   (   t   fullchain_pemt   certsR   t   certs_normalized(    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyt   cert_and_chain_from_fullchain  s    	:c         C   s=   t  |  d  " } t j t j | j    } Wd QX| j   S(   s   Retrieve the serial number of a certificate from certificate path

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

    :returns: serial number of the certificate
    :rtype: int
    R}   N(   R~   R   R   RB   R   t   get_serial_number(   Rz   R   R    (    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyt   get_serial_from_cert1  s    	!c         C   s   x |  D] } g  t  j | j    D] } t j | t    ^ q# } xC | D]; } | j j t j j	  } | rK | d j
 | k rK | SqK Wq W| r t j d |  n  |  d S(   s  Chooses the first certificate chain from fullchains which contains an
    Issuer Subject Common Name matching issuer_cn.

    :param fullchains: The list of fullchains in PEM chain format.
    :type fullchains: `list` of `str`
    :param `str` issuer_cn: The exact Subject Common Name to match against any
        issuer in the certificate chain.

    :returns: The best-matching fullchain, PEM-encoded, or the first if none match.
    :rtype: `str`
    i    s   Certbot has been configured to prefer certificate chains with issuer '%s', but no chain from the CA matched this issuer. Using the default certificate chain instead.(   R   R   R   R    R   R   t   issuert   get_attributes_for_oidt   NameOIDt   COMMON_NAMEt   valueR   t   info(   t
   fullchainst	   issuer_cnt   warn_on_no_matchR   R   R   t   cert_issuer_cn(    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyt   find_chain_with_issuer?  s    4	
(O   t   __doc__R   t   loggingR   t   ret   cryptographyR    t   cryptography.exceptionsR   R   t   cryptography.hazmat.backendsR   t)   cryptography.hazmat.primitives.asymmetricR   t,   cryptography.hazmat.primitives.asymmetric.ecR   R   t1   cryptography.hazmat.primitives.asymmetric.paddingR   t-   cryptography.hazmat.primitives.asymmetric.rsaR   t,   cryptography.hazmat.primitives.serializationR	   R
   R   t   OpenSSLR   R   R   Rj   t   zope.componentR!   t   acmeR   R8   t   acme.magic_typingR   t   certbotR   R   R   t   certbot.compatR   t	   getLoggert   __name__R   R5   R@   RI   RL   RY   Rh   R   Rv   R|   Rw   R   Ry   Rx   R   RB   R   R   R   R   RR   R   R   R   R   R   R   t   compilet   DOTALLR   R   R   RF   R   (    (    (    s7   /usr/lib/python2.7/site-packages/certbot/crypto_util.pyt   <module>   sl   ,	#			*																