o 6aM: @sdZddlmZddlmZddlZddlZddlZddlmZddlmZddlm Z ddl m Z dd l m Z dd l mZdd lmZdd lmZdd lmZddlZddlZddlmZddlmZddlmZddlmZddlmZzddlmZe ej!dWn e"e#fydZYnwe$e%Z&GdddZ'de(de ee(ee(ffddZ)de(de(de(de*de+f ddZ,d d!Z-d"d#Z.d$d%Z/dS)&z*Tools for checking certificate revocation.)datetime) timedeltaN)PIPE)Optional)Tuple)x509)InvalidSignature)UnsupportedAlgorithm)default_backend)hashes) serialization) crypto_util)errors)util)getenv) RenewableCert)ocspsignature_hash_algorithmc @sjeZdZdZdddZdedefddZdd ed ed e defd dZ d ed ededed e def ddZ dS)RevocationCheckerzEThis class figures out OCSP checking on this system, and performs it.FcCs~d|_|pt |_|jr=tdstdd|_dStjgdt t ddt d}d|j vr6dd |_ dSd d |_ dSdS) NFopensslz-openssl not installed, can't check revocationT)rr-headervarval)stdoutstderruniversal_newlinescheckenvz Missing =cSs d|gS)NzHost=hostrr./usr/lib/python3/dist-packages/certbot/ocsp.py8s z,RevocationChecker.__init__..cSsd|gS)NHostrrrrr!r":s) brokenruse_openssl_binaryr exe_existsloggerinfo subprocessrunrenv_no_snap_for_external_callsr host_args)selfenforce_openssl_binary_usagetest_host_formatrrr!__init__)s     zRevocationChecker.__init__certreturncCs||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-r1rrr! ocsp_revoked<s zRevocationChecker.ocsp_revoked r4r5timeoutcCsj|jrdStjt}t||krdSt|\}}|r |s"dS|j r.| |||||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$pytzUTCfromutcrutcnowr notAfter_determine_ocsp_serverr%_check_ocsp_openssl_bin_check_ocsp_cryptography)r-r4r5r8nowurlr rrr!r3Hs  z'RevocationChecker.ocsp_revoked_by_pathsr rBc Cstd}td}d}|dus|dur|dur|n|}|dur#d|g} n|dr0|tdd}d|d|g} ddd d |d |d |d |ddt|dg||| } td|td| z tj | tjd\} } Wnt j y{t d|YdSwt || | S)N http_proxy HTTP_PROXYz-urlzhttp://z-hostz-pathrrz -no_noncez-issuerz-certz-CAfilez -verify_otherz -trust_otherz-timeoutrzQuerying OCSP for %s )log*OCSP check failed for %s (are we offline?)F)r startswithlenstrr,r'debugjoinr run_scriptrSubprocessErrorr(_translate_ocsp_query) r-r4r5r rBr8env_http_proxyenv_HTTP_PROXY proxy_hosturl_optscmdoutputerrrrr!r?esB      z)RevocationChecker._check_ocsp_openssl_binN)F)r7) __name__ __module__ __qualname____doc__r0rboolr6rJintr3r?rrrr!r&s  rr4r2c st|d}t|t}Wdn1swYz|jtj}tjj fdd|j D}|dj j }Wntj t fyNtd|YdSw|}|dd d }|rc||fStd ||dS) 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) access_method).0 descriptionocsp_oidrr! s z*_determine_ocsp_server..rzCannot extract OCSP URI from %s)NNz:///z;Cannot process OCSP host from URL (%s) in certificate at %s)openrload_pem_x509_certificatereadr extensionsget_extension_for_classAuthorityInformationAccessAuthorityInformationAccessOIDOCSPvalueaccess_locationExtensionNotFound IndexErrorr'r(rstrip partition)r4 file_handlerr1 extension descriptionsrBr rrar!r>s$  r>r5rBr8c Cs(t|d}t|t}Wdn1swYt|d}t|t}Wdn1s7wYt}|||t }| }| t j j} z tj|| ddi|d} Wntjjyutjd|ddYdSw| jd krtd || jdSt| j} | jtjjkrtd || jdSz t| |||Wn_ty} ztt| WYd} ~ dSd} ~ wtj y} ztt| WYd} ~ dSd} ~ wt!ytd |YdSt"y} ztd |t| WYd} ~ dSd} ~ wwt#d|| j$| j$tj%j&kS)Nr]z Content-Typezapplication/ocsp-request)dataheadersr8rGT)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)'rfrrgrhr rOCSPRequestBuilderadd_certificater SHA1build public_bytesr EncodingDERrequestspost exceptionsRequestExceptionr'r( status_codeload_der_ocsp_responsecontentresponse_statusOCSPResponseStatus SUCCESSFULwarning_check_ocsp_responser rJrErrorrAssertionErrorrKcertificate_statusOCSPCertStatusREVOKED)r4r5rBr8rtissuerr1builderrequestrequest_binaryresponse response_ocspeerrorrrr!r@sd         r@cCs|j|jkr tdt|||t|jt|jr%|j|jks%|j|jkr)tdt }|j s4td|j |t ddkrBtd|j rS|j |t ddkrUtddSdS) z2Verify that the OCSP is valid for several criteriazMthe certificate in response does not correspond to the certificate in requestz._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|jksj|kr|qSr)responder_namesubjectresponder_key_hash)r_r1rrrr!rc s  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)r_p) ocsp_outputrr! 7s z(_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)groupr'r(rKr) r4r ocsp_errorsstatespatternsrrrrr)r4rr!rO2s&   rO)0rZrrloggingrr)rtypingrr cryptographyrcryptography.exceptionsrr cryptography.hazmat.backendsr cryptography.hazmat.primitivesr r r9rcertbotr rrcertbot.compat.osrcertbot.interfacesrcryptography.x509rgetattr OCSPResponse ImportErrorAttributeError getLoggerrWr'rrJr>r\r[r@rrrOrrrr!sF                  "e1" 6