
    M/e:              
          d 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 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  ej@                  e!      Z" G d d      Z#de$de	ee$   ee$   f   fdZ%de$de$de$de&de'f
dZ(dddd d!ejR                  de$ddf
d"Z*ddd!ejR                  de$ddfd#Z+de$d$e$d%e$de'fd&Z,y)'z*Tools for checking certificate revocation.    )datetime)	timedeltaN)PIPE)Optional)Tuple)x509)InvalidSignature)UnsupportedAlgorithm)default_backend)hashes)serialization)ocsp)crypto_util)errors)util)getenv)RenewableCertc                   l    e Zd ZdZddeddfdZdedefdZdded	ed
e	defdZ
ded	ededed
e	defdZy)RevocationCheckerzEThis class figures out OCSP checking on this system, and performs it.enforce_openssl_binary_usagereturnNc           	      J   d| _         || _        | j                  rt        j                  d      st        j                  d       d| _         y t        j                  g dt        t        ddt        j                               }d|j                  v r	d | _        y d	 | _        y y )
NFopensslz-openssl not installed, can't check revocationT)r   r   -headervarval)stdoutstderruniversal_newlinescheckenvz	Missing =c                     d| z   gS )NzHost= hosts    ./usr/lib/python3/dist-packages/certbot/ocsp.py<lambda>z,RevocationChecker.__init__.<locals>.<lambda>0   s    w~.>     c                 
    d| gS )NHostr#   r$   s    r&   r'   z,RevocationChecker.__init__.<locals>.<lambda>2   s
    vtn r(   )brokenuse_openssl_binaryr   
exe_existsloggerinfo
subprocessrunr   env_no_snap_for_external_callsr   	host_args)selfr   test_host_formats      r&   __init__zRevocationChecker.__init__!   s    ">""??9-KL"  *~~.Z,0RV+0d6Y6Y6[ ] .555!>!< #r(   certc                 N    | j                  |j                  |j                        S )a   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

        )ocsp_revoked_by_paths	cert_path
chain_path)r4   r7   s     r&   ocsp_revokedzRevocationChecker.ocsp_revoked4   s     ))$..$//JJr(   r:   r;   timeoutc                    | j                   ryt        j                  t        j                        }t        j                  |      |k  ryt        |      \  }}|r|sy| j                  r| j                  |||||      S t        ||||      S )aE  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

        F)r+   r   nowpytzUTCr   notAfter_determine_ocsp_serverr,   _check_ocsp_openssl_bin_check_ocsp_cryptography)r4   r:   r;   r=   r?   urlr%   s          r&   r9   z'RevocationChecker.ocsp_revoked_by_paths@   s     ;;
 ll488$	*c1*95	T3""//	:tSRYZZ'	:sGLLr(   r%   rF   c                 :   t        d      }t        d      }d }||||n|}|d|g}	n%|j                  d      r|t        d      d  }d|d|g}	ddd	d
|d|d|d|ddt        |      dg| j	                  |      z   |	z   }
t
        j                  d|       t
        j                  dj                  |
             	 t        j                  |
t
        j                        \  }}t        |||      S # t        j                  $ r t
        j                  d|       Y yw xY w)N
http_proxy
HTTP_PROXYz-urlzhttp://z-hostz-pathr   r   z	-no_noncez-issuerz-certz-CAfilez-verify_otherz-trust_otherz-timeoutr   zQuerying OCSP for %s )log*OCSP check failed for %s (are we offline?)F)r   
startswithlenstrr3   r.   debugjoinr   
run_scriptr   SubprocessErrorr/   _translate_ocsp_query)r4   r:   r;   r%   rF   r=   env_http_proxyenv_HTTP_PROXY
proxy_hosturl_optscmdoutputerrs                r&   rD   z)RevocationChecker._check_ocsp_openssl_bin]   s:     --
%)C+9+E>J}H$$Y/'I8
Wc:H&*	*
3w< !NN401 4<< 	+Y7SXXc]#	//#6<<@KFC %Y<< %% 	KKDiP	s   9(C. .)DD)F)
   )__name__
__module____qualname____doc__boolr6   r   r<   rO   intr9   rD   r#   r(   r&   r   r      s    O=T =d =&
K 
K4 
KMs M Mc M[_ M:#= #=# #=&)#=03#=>A#=FJ#=r(   r   r:   r   c                    t        | d      5 }t        j                  |j                         t	                     }ddd       	 j
                  j                  t        j                        }t        j                  j                  }|j                  D cg c]  }|j                  |k(  r| }}|d   j                  j                  }|j#                         }|j%                  d      d   j#                  d      }|r||fS t        j!                  d	||        y# 1 sw Y   xY wc c}w # t        j                  t        f$ r t        j!                  d|        Y yw xY w)
zExtract 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)

    rbNr   zCannot extract OCSP URI from %s)NNz://   /z;Cannot process OCSP host from URL (%s) in certificate at %s)openr   load_pem_x509_certificatereadr   
extensionsget_extension_for_classAuthorityInformationAccessAuthorityInformationAccessOIDOCSPvalueaccess_methodaccess_locationExtensionNotFound
IndexErrorr.   r/   rstrip	partition)	r:   file_handlerr7   	extensionocsp_oiddescriptiondescriptionsrF   r%   s	            r&   rC   rC      s?    
i	 V,--l.?.?.A?CTUV	OO;;D<[<[\	55::7@ B&44@ $ B B 1o--33
 **,C=="))#.DDy
KKMsT]^'V V
B ""J/ 5yAs0   -DAD) D$,D) D!$D) )/EEr;   rF   r=   c                 (   t        |d      5 }t        j                  |j                         t	                     }d d d        t        | d      5 }t        j                  |j                         t	                     }d d d        t        j                         }|j                  t        j                               }|j                         }|j                  t        j                  j                        }		 t        j                   ||	ddi|      }
|
j*                  d	k7  r"t&        j)                  d
| |
j*                         yt        j,                  |
j.                        }|j0                  t
        j2                  j4                  k7  r"t&        j7                  d| |j0                         y	 t9        ||||        t&        j;                  d| |j<                         |j<                  t
        j>                  j@                  k(  S # 1 sw Y   xY w# 1 sw Y   xY w# t        j"                  j$                  $ r t&        j)                  d| d       Y yw xY w# tB        $ r(}t&        j7                  tE        |             Y d }~yd }~wtF        jH                  $ r(}t&        j7                  tE        |             Y d }~yd }~wtJ        $ r t&        j7                  d|        Y ytL        $ r*}t&        j7                  d| tE        |             Y d }~yd }~ww xY w)Nrd   zContent-Typezapplication/ocsp-request)dataheadersr=   rL   T)exc_infoF   z*OCSP check failed for %s (HTTP status: %d)z'Invalid OCSP response status for %s: %sz%OCSP certificate status for %s is: %sz)Invalid signature on OCSP response for %sz!Invalid OCSP response for %s: %s.)'rg   r   rh   ri   r   r   OCSPRequestBuilderadd_certificater   SHA1buildpublic_bytesr   EncodingDERrequestspost
exceptionsRequestExceptionr.   r/   status_codeload_der_ocsp_responsecontentresponse_statusOCSPResponseStatus
SUCCESSFULwarning_check_ocsp_responserP   certificate_statusOCSPCertStatusREVOKEDr
   rO   r   Errorr	   AssertionError)r:   r;   rF   r=   rv   issuerr7   builderrequestrequest_binaryresponseresponse_ocspeerrors                 r&   rE   rE      s   	j$	 X<//0A0A0C_EVWX	i	 V,--l.?.?.A?CTUV%%'G%%dFFKKMBGmmoG))-*@*@*D*DEN==>*8:T)U)02 s"@)XMaMab//0@0@AM $$(?(?(J(JJ@ = =	?O]GVYG 	< @ @	B//43F3F3N3NNNUX XV V // @)VZ[$   s1v  << s1v   OBIN   S:Is5zRR Ss_   -H-H6H +I HH5II	LJLJ;;"LL' LLr   zocsp.OCSPResponserequest_ocspzocsp.OCSPRequestissuer_certc                 |   | j                   |j                   k7  rt        d      t        | ||       t        | j                  t        |j                              r2| j                  |j                  k7  s| j                  |j                  k7  rt        d      t        j                  t        j                        j                  d      }| j                  st        d      | j                  |t        d      z   kD  rt        d      | j                  r(| j                  |t        d      z
  k  rt        d	      yy)
z2Verify that the OCSP is valid for several criteriazMthe certificate in response does not correspond to the certificate in requestz<the issuer does not correspond to issuer of the certificate.N)tzinfozparam thisUpdate is not set.   )minutesz"param thisUpdate is in the future.z param nextUpdate is in the past.)serial_numberr   _check_ocsp_response_signature
isinstancehash_algorithmtypeissuer_key_hashissuer_name_hashr   r?   r@   rA   replacethis_updater   next_update)r   r   r   r:   r?   s        r&   r   r      s    ""l&@&@@ = > 	> #=+yI }33T,:U:U5VW,,0L0LL--1N1NN[\\ ,,txx
 
(
(
(
5C$$;<<  31)=#==ABB  ]%>%>yYZG[A[%[?@@ &\ r(   c                 B   dt         j                  dt        fd}| j                  |j                  k(  s| j
                   ||      k(  rt        j                  d|       |}nDt        j                  d|       | j                  D cg c]2  }| j                  |j                  k(  s| j
                   ||      k(  r|4 }}|st        d      |d   }|j                  |j                  k7  rt        d      	 |j                  j                  t         j                        }t         j                  j                  j                   |j"                  v }|st        d
      |j(                  }	|	sJ t+        j,                  |j/                         |j0                  |j2                  |	       | j(                  }
|
st        d      t+        j,                  |j/                         | j0                  | j4                  |
       yc c}w # t         j$                  t&        f$ r d	}Y w xY w)zIVerify an OCSP response signature against certificate issuer or responderr7   r   c                 p    t         j                  j                  | j                               j                  S )N)r   SubjectKeyIdentifierfrom_public_key
public_keydigest)r7   s    r&   	_key_hashz1_check_ocsp_response_signature.<locals>._key_hash   s&    ((889JKRRRr(   zGOCSP response for certificate %s is signed by the certificate's issuer.zGOCSP response for certificate %s is delegated to an external responder.z0no matching responder certificate could be foundr   z?responder certificate is not signed by the certificate's issuerFz<responder is not authorized by issuer to sign OCSP responsesz#no signature hash algorithm definedN)r   Certificatebytesresponder_namesubjectresponder_key_hashr.   rP   certificatesr   r   rj   rk   ExtendedKeyUsageoidExtendedKeyUsageOIDOCSP_SIGNINGro   rr   rs   signature_hash_algorithmr   verify_signed_payloadr   	signaturetbs_certificate_bytestbs_response_bytes)r   r   r:   r   responder_certr7   responder_certsrw   delegate_authorizedchosen_cert_hashchosen_response_hashs              r&   r   r      s   S(( SU S 	$$(;(;;//9[3II_	 $ 	^	  -:,F,F SD+::dllJ+>>)D/Q   S S  !STT
 )+  K$7$77  "@ A A	(&11II$J_J_`I"&((">">"K"Ky"^ # !_`` *BB 	))+*@*@*BND\D\*8*N*NP`	b )AA  BCC%%n&?&?&A=CZCZ&3&F&FH\^KS$ &&
3 	("'	(s   7G;7AH   HHocsp_outputocsp_errorsc                    d}|D cg c]  }dj                  | |       }}fd|D        \  }}}|r|j                  d      nd}	d|vs|r|	s|r.t        j                  d|        t        j	                  d|       y	|r|	sy	|r*|j                  d      }	|	rt        j                  d
|	       yt        j                  d|       y	c c}w )z7Parse openssl's weird output to work out what it means.)goodrevokedunknownz{0}: (WARNING.*)?{1}c              3   j   K   | ]*  }t        j                  |t         j                          , yw))flagsN)researchDOTALL).0pr   s     r&   	<genexpr>z(_translate_ocsp_query.<locals>.<genexpr>5  s%     [Qbii;biiHH[s   03   NzResponse verify OKz#Revocation status for %s is unknownzUncertain output:
%s
stderr:
%sFzOCSP revocation warning: %sTz2Unable to properly parse OCSP output: %s
stderr:%s)formatgroupr.   r/   rP   r   )
r:   r   r   statesspatternsr   r   r   r   s
    `        r&   rT   rT   0  s     ,FFLM'..y!<MHM[RZ[D'7#djjmGK/Tg'99E9;T	g	--"KK5w?L"K	1' Ns   C)-r`   r   r   loggingr   r0   r   typingr   r   cryptographyr   cryptography.exceptionsr	   r
   cryptography.hazmat.backendsr   cryptography.hazmat.primitivesr   r   cryptography.x509r   r@   r   certbotr   r   r   certbot.compat.osr   certbot.interfacesr   	getLoggerr]   r.   r   rO   rC   rb   ra   rE   r   r   r   rT   r#   r(   r&   <module>r      sF   0    	      4 8 8 1 8 "      $ ,			8	$b= b=Jc eHSM8C=4P.Q <. . .3 .QT .Y] .b!A(; !AK] !A&*&6&6!ACF!AKO!AH7^2E 7^040@0@7^MP7^UY7^tS s  QU r(   