ó
Y[c           @   sF  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! e j" e# ƒ Z$ d d „ Z% d „  Z& d „  Z' d „  Z( d „  Z) d „  Z* d „  Z+ d „  Z, d „  Z- d „  Z. d „  Z/ d „  Z0 e j1 d „ Z2 e j1 d „ Z3 e j1 d  „ Z4 d! „  Z5 d" „  Z6 e j1 d# „ Z7 e j1 d$ „ Z8 d% „  Z9 d& „  Z: d' „  Z; d( „  Z< d) „  Z= d S(*   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.

iÿÿÿÿN(   t   InvalidSignature(   t   default_backend(   t   ECDSA(   t   EllipticCurvePublicKey(   t   PKCS1v15(   t   RSAPublicKey(   t   x509(   t   crypto(   t   SSL(   t   crypto_util(   t   IO(   t   errors(   t
   interfaces(   t   utils   key-certbot.pemc         C   sÚ   y t  |  ƒ } Wn, t k
 r> } t j d d t ƒ| ‚ n Xt j j t j	 ƒ } t
 j | d t j ƒ  | j ƒ t
 j t j j | | ƒ d d ƒ \ } } |  | j | ƒ Wd QXt j d |  | ƒ t
 j | | ƒ S(   sÚ  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.

    t    t   exc_infoiÀ  i€  t   wbNs   Generating key (%d bits): %s(   t   make_keyt
   ValueErrort   loggert   errort   Truet   zopet	   componentt
   getUtilityR   t   IConfigR   t   make_or_verify_dirt   ost   geteuidt   strict_permissionst   unique_filet   patht   joint   writet   debugt   Key(   t   key_sizet   key_dirt   keynamet   key_pemt   errt   configt   key_ft   key_path(    (    s7   /usr/lib/python2.7/dist-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 t j ƒ  | 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_csrR.   R-   R   R   R   R   R   R   R   R    R!   R   R"   t   CSR(   t   privkeyt   namesR   R)   t   csr_pemt   csr_ft   csr_filename(    (    s7   /usr/lib/python2.7/dist-packages/certbot/crypto_util.pyt   init_save_csrJ   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/dist-packages/certbot/crypto_util.pyt	   valid_csrn   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   R8   R9   t   load_privatekeyR:   R<   R   R"   R   R=   (   R>   R2   R?   t   pkey(    (    s7   /usr/lib/python2.7/dist-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   formR.   (   R   R9   R8   t   FILETYPE_ASN1R<   R   t   formatt"   _get_names_from_loaded_cert_or_reqt   dump_certificate_requestR   R1   (   t   csrfileRE   t   PEMt   loadR>   t   domainst   data_pem(    (    s7   /usr/lib/python2.7/dist-packages/certbot/crypto_util.pyt   import_csr_file–   s    		 c         C   sD   |  d k s t  ‚ t j ƒ  } | j t j |  ƒ t j t j | ƒ S(   s­   Generate 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   (   t   AssertionErrorR   t   PKeyt   generate_keyt   TYPE_RSAt   dump_privatekeyR9   (   t   bitst   key(    (    s7   /usr/lib/python2.7/dist-packages/certbot/crypto_util.pyR   ³   s    	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   RA   R9   t   checkt	   TypeErrorR<   R=   (   R2   (    (    s7   /usr/lib/python2.7/dist-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 `.storage.RenewableCert` renewable_cert: cert to verify

    :raises errors.Error: If verification fails.
    N(   t   verify_renewable_cert_sigt   verify_fullchaint   verify_cert_matches_priv_keyt   certR2   (   t   renewable_cert(    (    s7   /usr/lib/python2.7/dist-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
 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 QXWnM t t t f k
 rŽ} d j |  j | ƒ } t j | ƒ t j | ƒ ‚ n Xd S(   sÂ    Verifies the signature of a `.storage.RenewableCert` object.

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

    :raises errors.Error: If signature verification fails.
    t   rbNt   ignores   Unsupported public key types[   verifying the signature of the cert located at {0} has failed.                 Details: {1}(   t   opent   chainR   t   load_pem_x509_certificatet   readR   R^   t
   public_keyt   warningst   catch_warningst   simplefiltert
   isinstanceR   t   verifiert	   signatureR   t   signature_hash_algorithmt   updatet   tbs_certificate_bytesR:   R   R   R   R<   t   IOErrorR   R    RH   R   t	   exception(	   R_   t
   chain_fileRd   t	   cert_fileR^   t   pkRl   t   et	   error_str(    (    s7   /usr/lib/python2.7/dist-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 cert 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_privatekeyRq   R<   RH   R   Rr   R   (   t	   cert_pathR+   t   contextRv   Rw   (    (    s7   /usr/lib/python2.7/dist-packages/certbot/crypto_util.pyR]     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 `.storage.RenewableCert` renewable_cert: cert to verify

    :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}(   Rc   Rd   Rf   R^   t	   fullchainRH   t   lineagenameR   R<   Rq   R   Rr   (	   R_   Rs   Rd   Rt   R^   t   fullchain_fileR   Rw   Rv   (    (    s7   /usr/lib/python2.7/dist-packages/certbot/crypto_util.pyR\     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(   t   str(   t   .0R   (    (    s7   /usr/lib/python2.7/dist-packages/certbot/crypto_util.pys	   <genexpr>G  s    N(	   R   R9   RG   t   load_certificateR<   t   appendR   RH   R    (   RE   t   openssl_errorst	   file_typeR   (    (    s7   /usr/lib/python2.7/dist-packages/certbot/crypto_util.pyt   pyopenssl_load_certificate8  s    c         C   sB   y | | |  ƒ SWn* t  j k
 r= t j d d t ƒ‚  n Xd  S(   NR   R   (   R   R<   R   R   R   (   t   cert_or_req_strt	   load_funct   typ(    (    s7   /usr/lib/python2.7/dist-packages/certbot/crypto_util.pyt   _load_cert_or_reqJ  s
    c         C   s   t  j t |  | | ƒ ƒ S(   N(   R/   t   _pyopenssl_cert_or_req_sanR   (   RŠ   R‹   RŒ   (    (    s7   /usr/lib/python2.7/dist-packages/certbot/crypto_util.pyt   _get_sans_from_cert_or_reqS  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/dist-packages/certbot/crypto_util.pyt   get_sans_from_certZ  s    
c         C   s   t  |  | | ƒ } t | ƒ S(   N(   R   RI   (   t   cert_or_reqR‹   RŒ   t   loaded_cert_or_req(    (    s7   /usr/lib/python2.7/dist-packages/certbot/crypto_util.pyt   _get_names_from_cert_or_reqh  s    c         C   s   t  j |  ƒ S(   N(   R/   t    _pyopenssl_cert_or_req_all_names(   R’   (    (    s7   /usr/lib/python2.7/dist-packages/certbot/crypto_util.pyRI   m  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…   (   R>   RŒ   (    (    s7   /usr/lib/python2.7/dist-packages/certbot/crypto_util.pyt   get_names_from_certr  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`).

    (   R/   t   dump_pyopenssl_chain(   Rd   t   filetype(    (    s7   /usr/lib/python2.7/dist-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(   R}   (    (    s7   /usr/lib/python2.7/dist-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(   R}   (    (    s7   /usr/lib/python2.7/dist-packages/certbot/crypto_util.pyt   notAfter˜  s    	c         C   sÁ   t  |  ƒ " } 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`

    Ni    i   t   -i   i   t   Ti
   t   :i   R   t   ascii(   Rc   R   R…   R9   Rf   R    t   sixt   PY3t   decodet	   pyrfc3339t   parse(   R}   t   methodt   fR   t	   timestampt   reformatted_timestampt   timestamp_str(    (    s7   /usr/lib/python2.7/dist-packages/certbot/crypto_util.pyR˜   ¤  s    	c         C   sA   t  j ƒ  } t |  d ƒ  } | j | j ƒ  ƒ Wd QX| j ƒ  S(   s²   Compute a sha256sum of a file.

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

    :returns: sha256 digest of the file in hexadecimal
    :rtype: str
    Ra   N(   t   hashlibt   sha256Rc   Ro   Rf   t	   hexdigest(   t   filenameR­   R¨   (    (    s7   /usr/lib/python2.7/dist-packages/certbot/crypto_util.pyt	   sha256sumÀ  s    c         C   sJ   t  j t  j t  j t  j |  ƒ ƒ j ƒ  } |  t | ƒ j ƒ  } | | 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

    (   R   t   dump_certificateR9   R…   R¤   t   lent   lstrip(   t   fullchain_pemR^   Rd   (    (    s7   /usr/lib/python2.7/dist-packages/certbot/crypto_util.pyt   cert_and_chain_from_fullchainÍ  s    	(>   t   __doc__R¬   t   loggingR   Rh   R¥   R¢   t   zope.componentR   t   cryptography.exceptionsR    t   cryptography.hazmat.backendsR   t,   cryptography.hazmat.primitives.asymmetric.ecR   R   t1   cryptography.hazmat.primitives.asymmetric.paddingR   t-   cryptography.hazmat.primitives.asymmetric.rsaR   t   cryptographyR   t   OpenSSLR   R   t   acmeR	   R/   t   acme.magic_typingR
   t   certbotR   R   R   t	   getLoggert   __name__R   R,   R7   R@   RC   RP   R   RZ   R`   R[   R]   R\   R‰   R9   R   R   R   R“   RI   R•   R–   R›   R   R˜   R°   Rµ   (    (    (    s7   /usr/lib/python2.7/dist-packages/certbot/crypto_util.pyt   <module>   s\   %	$							%										