3 گa:@sdZddlmZddlmZddlZddlZddlZddlmZddlmZddlm Z ddl m Z dd l m Z dd l mZdd lmZdd lmZdd lmZddlmZddlZddlZddlmZddlmZddlmZddlmZddlmZej e!Z"GdddZ#e$e ee$ee$fdddZ%e$e$e$e&e'dddZ(dde j)e$dddd Z*de j)e$dd!d"d#Z+e$e$e$e'd$d%d&Z,dS)'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@s`eZdZdZdeddddZeeddd Zdeee ed d d Z eeeee edddZ dS)RevocationCheckerzEThis class figures out OCSP checking on this system, and performs it.FN)enforce_openssl_binary_usagereturncCsxd|_||_|jrttjds0tjdd|_dStjdddddgttddtj d }d |j krjd d |_ n d d |_ dS)NFopensslz-openssl not installed, can't check revocationTr z-headervarval)stdoutstderrZuniversal_newlinesZcheckenvz Missing =cSs d|gS)NzHost=)hostrr/usr/lib/python3.6/ocsp.py1sz,RevocationChecker.__init__..cSsd|gS)NZHostr)rrrrr3s) brokenuse_openssl_binaryrZ exe_existsloggerinfo subprocessZrunrZenv_no_snap_for_external_callsr host_args)selfrZtest_host_formatrrr__init__"s    zRevocationChecker.__init__)certrcCs|j|j|jS)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)r&r(rrr ocsp_revoked5s zRevocationChecker.ocsp_revoked )r*r+timeoutrcCsn|jr dStjjtj}tj||kr,dSt|\}}| sD| rHdS|j r`|j |||||St ||||S)aEPerforms 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 pytzZUTCZfromutcrutcnowrZnotAfter_determine_ocsp_serverr!_check_ocsp_openssl_bin_check_ocsp_cryptography)r&r*r+r.nowurlrrrrr)As   z'RevocationChecker.ocsp_revoked_by_paths)r*r+rr5r.rc Cstd}td}d}|dk s$|dk r4|dk r0|n|}|dkrFd|g} n&|jdr`|tdd}d|d|g} ddd d |d |d |d |ddt|dg|j|| } tjd|tjdj| ytj | tjd\} } Wn"t j k rtj d|dSXt || | S)NZ http_proxyZ HTTP_PROXYz-urlzhttp://z-hostz-pathrr z -no_noncez-issuerz-certz-CAfilez -verify_otherz -trust_otherz-timeoutz-headerzQuerying OCSP for %s )logz*OCSP check failed for %s (are we offline?)F)r startswithlenstrr%r"debugjoinrZ run_scriptrZSubprocessErrorr#_translate_ocsp_query) r&r*r+rr5r.Zenv_http_proxyZenv_HTTP_PROXYZ proxy_hostZurl_optscmdoutputerrrrrr2^s&   4  z)RevocationChecker._check_ocsp_openssl_bin)F)r-) __name__ __module__ __qualname____doc__boolr'rr,r:intr)r2rrrrrs  r)r*rcst|d}tj|jt}WdQRXy:|jjtj}tjj fdd|j D}|dj j }Wn&tj t fk rtjd|d SX|j}|jddjd }|r||fStjd ||d S) 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) rbNcsg|]}|jkr|qSr)Z access_method).0 description)ocsp_oidrr sz*_determine_ocsp_server..rzCannot extract OCSP URI from %sz:///z;Cannot process OCSP host from URL (%s) in certificate at %s)NN)NN)openrload_pem_x509_certificatereadr extensionsget_extension_for_classZAuthorityInformationAccessZAuthorityInformationAccessOIDZOCSPvalueZaccess_locationExtensionNotFound IndexErrorr"r#rstrip partition)r* file_handlerr( extensionZ descriptionsr5rr)rJrr1s   r1)r*r+r5r.rc'Cst|d}tj|jt}WdQRXt|d}tj|jt}WdQRXtj}|j||tj }|j }|j t j j} ytj|| ddi|d} Wn(tjjk rtjd|dddSX| jd krtjd || jdStj| j} | jtjjkrtjd || jdSyt| |||Wntk rV} ztjt| WYdd} ~ Xntj k r} ztjt| WYdd} ~ Xntt!k rtjd |YnTt"k r} ztjd |t| WYdd} ~ Xn Xtj#d|| j$| j$tj%j&kSdS)NrGz Content-Typezapplication/ocsp-request)dataZheadersr.z*OCSP check failed for %s (are we offline?)T)exc_infoFz*OCSP check failed for %s (HTTP status: %d)z'Invalid OCSP response status for %s: %sz)Invalid signature on OCSP response for %sz!Invalid OCSP response for %s: %s.z%OCSP certificate status for %s is: %s)'rNrrOrPr r ZOCSPRequestBuilderZadd_certificater ZSHA1ZbuildZ public_bytesr ZEncodingZDERrequestsZpost exceptionsZRequestExceptionr"r#Z status_codeZload_der_ocsp_responseZcontentZresponse_statusZOCSPResponseStatusZ SUCCESSFULwarning_check_ocsp_responser r:rErrorrAssertionErrorr;Zcertificate_statusZOCSPCertStatusZREVOKED)r*r+r5r.rXissuerr(ZbuilderZrequestZrequest_binaryZresponse response_ocspeerrorrrrr3sJ      $ r3zocsp.OCSPResponsezocsp.OCSPRequest)rd request_ocsp issuer_certr*rcCs|j|jkrtdt|||t|jt|j sL|j|jksL|j|jkrTtdtj }|j sjtd|j |t ddkrtd|j r|j |t ddkrtddS) z2Verify that the OCSP is valid for several criteriazMthe certificate in response does not correspond to the certificate in requestztjd||}ntjd|fddjD}|slt d|d }|j |jkrt d y"|j j tj }tjjj|jk}Wntjtfk rd }YnX|st d |j}tj|j|j|j|j}|st d tj|jjj|dS)zIVerify an OCSP response signature against certificate issuer or responder)r(rcSstjj|jjS)N)rZSubjectKeyIdentifierZfrom_public_key public_keyZdigest)r(rrr _key_hashsz1_check_ocsp_response_signature.._key_hashzGOCSP response for certificate %s is signed by the certificate's issuer.zGOCSP response for certificate %s is delegated to an external responder.cs*g|]"}j|jks"j|kr|qSr)responder_namesubjectresponder_key_hash)rHr()rnrdrrrKs z2_check_ocsp_response_signature..z0no matching responder certificate could be foundrz?responder certificate is not signed by the certificate's issuerFz.c3s |]}tj|tjdVqdS))flagsN)researchDOTALL)rHp)rtrr 4sz(_translate_ocsp_query..NzResponse verify OKz#Revocation status for %s is unknownzUncertain output: %s stderr: %sFzOCSP revocation warning: %sTz2Unable to properly parse OCSP output: %s stderr:%s)rvrwrx)groupr"r#r;r_) r*rtruZstatesZpatternsrvrwrxr_r)r*rtrr=/s$    r=)-rDrrZloggingr|r$rZtypingrrZ cryptographyrZcryptography.exceptionsrr Zcryptography.hazmat.backendsr Zcryptography.hazmat.primitivesr r Zcryptography.x509r r/r]ZcertbotrrrZcertbot.compat.osrZcertbot.interfacesrZ getLoggerrAr"rr:r1rFrEr3rrr`rjr=rrrrs>                  e 1"8