ó
Á£ô_c           @   sà  d  Z  d d l m Z d d l m 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 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 y$ d d l m  Z  e! e  j" d ƒ Wn e# e$ f k
 r‰d Z  n Xe j& e' ƒ Z( d e) f d „  ƒ  YZ* d „  Z+ d „  Z, d „  Z- d „  Z. d „  Z/ d S(   s*   Tools for checking certificate revocation.iÿÿÿÿ(   t   datetime(   t	   timedeltaN(   t   PIPE(   t   Popen(   t   x509(   t   InvalidSignature(   t   UnsupportedAlgorithm(   t   default_backend(   t   hashes(   t   serialization(   t   Optional(   t   Tuple(   t   crypto_util(   t   errors(   t   util(   t   getenv(   t   RenewableCert(   t   ocspt   signature_hash_algorithmt   RevocationCheckerc           B   s8   e  Z d  Z e d „ Z d „  Z d d „ Z d „  Z RS(   sE   This class figures out OCSP checking on this system, and performs it.c         C   sÄ   t  |  _ | p t |  _ |  j rÀ t j d ƒ sK t j d ƒ t |  _ d  St	 d d d d d g d t
 d t
 d	 t d
 t j ƒ  ƒ} | j ƒ  \ } } d | k r± d „  |  _ qÀ d „  |  _ n  d  S(   Nt   openssls-   openssl not installed, can't check revocationR   s   -headert   vart   valt   stdoutt   stderrt   universal_newlinest   envs	   Missing =c         S   s   d |  g S(   Ns   Host=(    (   t   host(    (    s0   /usr/lib/python2.7/site-packages/certbot/ocsp.pyt   <lambda>:   s    c         S   s
   d |  g S(   Nt   Host(    (   R   (    (    s0   /usr/lib/python2.7/site-packages/certbot/ocsp.pyR   <   s    (   t   Falset   brokenR   t   use_openssl_binaryR   t
   exe_existst   loggert   infot   TrueR   R   t   env_no_snap_for_external_callst   communicatet	   host_args(   t   selft   enforce_openssl_binary_usaget   test_host_formatt   _outt   err(    (    s0   /usr/lib/python2.7/site-packages/certbot/ocsp.pyt   __init__*   s    			c         C   s   |  j  | j | j ƒ S(   s   Get revoked status for a particular cert version.

        .. todo:: Make this a non-blocking call

        :param `.interfaces.RenewableCert` cert: Certificate object
        :returns: True if revoked; False if valid or the check failed or cert is expired.
        :rtype: bool

        (   t   ocsp_revoked_by_pathst	   cert_patht
   chain_path(   R(   t   cert(    (    s0   /usr/lib/python2.7/site-packages/certbot/ocsp.pyt   ocsp_revoked>   s    i
   c         C   s—   |  j  r t St j j t j ƒ  ƒ } t j | ƒ | k r> t St	 | ƒ \ } } | s^ | rb t S|  j
 r„ |  j | | | | | ƒ St | | | | ƒ S(   sE  Performs the OCSP revocation check

        :param str cert_path: Certificate filepath
        :param str chain_path: Certificate chain
        :param int timeout: Timeout (in seconds) for the OCSP query

        :returns: True if revoked; False if valid or the check failed or cert is expired.
        :rtype: bool

        (   R   R   t   pytzt   UTCt   fromutcR    t   utcnowR   t   notAftert   _determine_ocsp_serverR    t   _check_ocsp_openssl_bint   _check_ocsp_cryptography(   R(   R/   R0   t   timeoutt   nowt   urlR   (    (    s0   /usr/lib/python2.7/site-packages/certbot/ocsp.pyR.   K   s    		c         C   sj  t  d ƒ } t  d ƒ } d  } | d  k	 s6 | d  k	 rQ | d  k	 rH | n | } n  | d  k rl d | g }	 n4 | j d ƒ rŽ | t d ƒ } n  d | d | g }	 d d d	 d
 | d | d | d | d d t | ƒ d g |  j | ƒ |	 }
 t j d | ƒ t j d j |
 ƒ ƒ y" t	 j
 |
 d t j ƒ\ } } Wn% t j k
 rYt j d | ƒ t SXt | | | ƒ S(   Nt
   http_proxyt
   HTTP_PROXYs   -urls   http://s   -hosts   -pathR   R   s	   -no_nonces   -issuers   -certs   -CAfiles   -verify_others   -trust_others   -timeouts   -headers   Querying OCSP for %st    t   logs*   OCSP check failed for %s (are we offline?)(   R   t   Nonet
   startswitht   lent   strR'   R"   t   debugt   joinR   t
   run_scriptR   t   SubprocessErrorR#   R   t   _translate_ocsp_query(   R(   R/   R0   R   R=   R;   t   env_http_proxyt   env_HTTP_PROXYt
   proxy_hostt   url_optst   cmdt   outputR,   (    (    s0   /usr/lib/python2.7/site-packages/certbot/ocsp.pyR9   i   s&    
J"(   t   __name__t
   __module__t   __doc__R   R-   R2   R.   R9   (    (    (    s0   /usr/lib/python2.7/site-packages/certbot/ocsp.pyR   '   s
   	c   	      C   s  t  |  d ƒ " } t j | j ƒ  t ƒ  ƒ } Wd QXy` | j j t j ƒ } t j j	 } g  | j
 D] } | j | k ra | ^ qa } | d j j
 } Wn+ t j t f k
 rÀ t j d |  ƒ d	 SX| j ƒ  } | j d ƒ d j d ƒ } | rù | | f St j d | |  ƒ d
 S(   sÎ   Extract the OCSP server host from a certificate.

    :param str cert_path: Path to the cert we're checking OCSP for
    :rtype tuple:
    :returns: (OCSP server URL or None, OCSP server host or None)

    t   rbNi    s   Cannot extract OCSP URI from %ss   ://i   t   /s;   Cannot process OCSP host from URL (%s) in certificate at %s(   NN(   NN(   t   openR   t   load_pem_x509_certificatet   readR   t
   extensionst   get_extension_for_classt   AuthorityInformationAccesst   AuthorityInformationAccessOIDt   OCSPt   valuet   access_methodt   access_locationt   ExtensionNotFoundt
   IndexErrorR"   R#   RB   t   rstript	   partition(	   R/   t   file_handlerR1   t	   extensiont   ocsp_oidt   descriptiont   descriptionsR=   R   (    (    s0   /usr/lib/python2.7/site-packages/certbot/ocsp.pyR8      s"    	!
c      
   C   sU  t  | d ƒ " } t j | j ƒ  t ƒ  ƒ } Wd  QXt  |  d ƒ " } t j | j ƒ  t ƒ  ƒ } Wd  QXt j ƒ  } | j | | t j	 ƒ  ƒ } | j
 ƒ  } | j t j j ƒ }	 y, t j | d |	 d i d d 6d | ƒ}
 Wn. t j j k
 r
t j d |  d t ƒt SX|
 j d	 k r4t j d
 |  |
 j ƒ t St j |
 j ƒ } | j t j j k rut j d |  | j ƒ t Sy t | | | |  ƒ Wn™ t k
 r´} t j t  | ƒ ƒ n t! j" k
 rÜ} t j t  | ƒ ƒ nu t# k
 rüt j d |  ƒ nU t$ k
 r'} t j d |  t  | ƒ ƒ n* Xt j% d |  | j& ƒ | j& t j' j( k St S(   NRT   t   datat   headerss   application/ocsp-requests   Content-TypeR;   s*   OCSP check failed for %s (are we offline?)t   exc_infoiÈ   s*   OCSP check failed for %s (HTTP status: %d)s'   Invalid OCSP response status for %s: %ss)   Invalid signature on OCSP response for %ss!   Invalid OCSP response for %s: %s.s%   OCSP certificate status for %s is: %s()   RV   R   RW   RX   R   R   t   OCSPRequestBuildert   add_certificateR   t   SHA1t   buildt   public_bytesR	   t   Encodingt   DERt   requestst   postt
   exceptionst   RequestExceptionR"   R#   R$   R   t   status_codet   load_der_ocsp_responset   contentt   response_statust   OCSPResponseStatust
   SUCCESSFULt   errort   _check_ocsp_responseR   RE   R   t   ErrorR   t   AssertionErrorRF   t   certificate_statust   OCSPCertStatust   REVOKED(   R/   R0   R=   R;   Re   t   issuerR1   t   buildert   requestt   request_binaryt   responset   response_ocspt   eR~   (    (    s0   /usr/lib/python2.7/site-packages/certbot/ocsp.pyR:   ®   sJ    !!		c         C   s  |  j  | j  k r! t d ƒ ‚ n  t |  | | ƒ t |  j t | j ƒ ƒ sq |  j | j k sq |  j | j k r€ t d ƒ ‚ n  t j	 ƒ  } |  j
 s¤ t d ƒ ‚ n  |  j
 | t d d ƒ k rÏ t d ƒ ‚ n  |  j r|  j | t d d ƒ k  rt d ƒ ‚ n  d S(	   s2   Verify that the OCSP is valid for several criteriasM   the certificate in response does not correspond to the certificate in requests<   the issuer does not correspond to issuer of the certificate.s   param thisUpdate is not set.t   minutesi   s"   param thisUpdate is in the future.s    param nextUpdate is in the past.N(   t   serial_numberR   t   _check_ocsp_response_signaturet
   isinstancet   hash_algorithmt   typet   issuer_key_hasht   issuer_name_hashR    R6   t   this_updateR   t   next_update(   RŠ   t   request_ocspt   issuer_certR/   R<   (    (    s0   /usr/lib/python2.7/site-packages/certbot/ocsp.pyR   à   s    	%c   
      C   sŸ  d „  } |  j  | j k s0 |  j | | ƒ k rI t j d | ƒ | } n't j d | ƒ g  |  j D]3 } |  j  | j k s |  j | | ƒ k rc | ^ qc } | s± t d ƒ ‚ n  | d } | j | j k rÜ t d ƒ ‚ n  y1 | j j	 t
 j ƒ } t
 j j j | j k } Wn  t
 j t f k
 r/t } n X| sEt d ƒ ‚ n  | j }	 t j | j ƒ  | j | j |	 ƒ |  j }	 t j | j ƒ  |  j |  j |	 ƒ d S(	   sI   Verify an OCSP response signature against certificate issuer or responderc         S   s   t  j j |  j ƒ  ƒ j S(   N(   R   t   SubjectKeyIdentifiert   from_public_keyt
   public_keyt   digest(   R1   (    (    s0   /usr/lib/python2.7/site-packages/certbot/ocsp.pyt	   _key_hash  s    sG   OCSP response for certificate %s is signed by the certificate's issuer.sG   OCSP response for certificate %s is delegated to an external responder.s0   no matching responder certificate could be foundi    s?   responder certificate is not signed by the certificate's issuers<   responder is not authorized by issuer to sign OCSP responsesN(   t   responder_namet   subjectt   responder_key_hashR"   RF   t   certificatesR   R…   RY   RZ   R   t   ExtendedKeyUsaget   oidt   ExtendedKeyUsageOIDt   OCSP_SIGNINGR^   Ra   Rb   R   R   R   t   verify_signed_payloadRš   t	   signaturet   tbs_certificate_bytest   tbs_response_bytes(
   RŠ   R—   R/   Rœ   t   responder_certR1   t   responder_certsRf   t   delegate_authorizedt   chosen_hash(    (    s0   /usr/lib/python2.7/site-packages/certbot/ocsp.pyRŽ     s:    				!

		c   
         s  d } g  | D] } d j  |  | ƒ ^ q } ‡  f d †  | Dƒ \ } } } | r_ | j d ƒ n d }	 d | k sƒ | r} |	 sƒ | rª t j d |  ƒ t j d	 ˆ  | ƒ t S| r» |	 r» t S| rí | j d ƒ }	 |	 ré t j d
 |	 ƒ n  t St j d ˆ  | ƒ t Sd S(   s7   Parse openssl's weird output to work out what it means.t   goodt   revokedt   unknowns   {0}: (WARNING.*)?{1}c         3   s*   |  ]  } t  j | ˆ  d  t  j ƒVq d S(   t   flagsN(   t   ret   searcht   DOTALL(   t   .0t   p(   t   ocsp_output(    s0   /usr/lib/python2.7/site-packages/certbot/ocsp.pys	   <genexpr>=  s    i   s   Response verify OKs#   Revocation status for %s is unknowns   Uncertain output:
%s
stderr:
%ss   OCSP revocation warning: %ss2   Unable to properly parse OCSP output: %s
stderr:%sN(   s   goods   revokeds   unknown(	   t   formatt   groupRB   R"   R#   RF   R   R$   t   warning(
   R/   R¶   t   ocsp_errorst   statest   st   patternsR­   R®   R¯   R¹   (    (   R¶   s0   /usr/lib/python2.7/site-packages/certbot/ocsp.pyRJ   8  s$    %	
(0   RS   R    R   t   loggingR±   t
   subprocessR   R   t   cryptographyR   t   cryptography.exceptionsR   R   t   cryptography.hazmat.backendsR   t   cryptography.hazmat.primitivesR   R	   R3   Rt   t   acme.magic_typingR
   R   t   certbotR   R   R   t   certbot.compat.osR   t   certbot.interfacesR   t   cryptography.x509R   t   getattrt   OCSPResponset   ImportErrort   AttributeErrorRB   t	   getLoggerRQ   R"   t   objectR   R8   R:   R   RŽ   RJ   (    (    (    s0   /usr/lib/python2.7/site-packages/certbot/ocsp.pyt   <module>   sB   
h		2	"	6