U
    ]Q3                  	   @   sD  d Z ddlZddlZddlmZmZ ddlmZmZ zddlm	Z	 e
e	jd W n eefk
rl   dZ	Y nX 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mZ ddlZddlZddlmZmZ ddlmZ ddlmZ ddl m!Z! ddlm"Z" e#e$Z%G dd de&Z'dd Z(dd Z)dd Z*dd Z+dd Z,dS )z*Tools for checking certificate revocation.    N)datetime	timedelta)PopenPIPE)ocspsignature_hash_algorithm)x509)default_backend)serialization)hashes)UnsupportedAlgorithmInvalidSignature)OptionalTuple)crypto_util)errors)RenewableCert)utilc                   @   s*   e Zd ZdZd
ddZdd Zdd Zd	S )RevocationCheckerzEThis class figures out OCSP checking on this system, and performs it.Fc                 C   s~   d| _ |pt | _| jrztds6td d| _ d S tdddddgttdd	}|	 \}}d
|krpdd | _
n
dd | _
d S )NFopensslz-openssl not installed, can't check revocationTr   -headervarval)stdoutstderrZuniversal_newlinesz	Missing =c                 S   s
   d|  gS )NzHost= hostr   r   ./usr/lib/python3/dist-packages/certbot/ocsp.py<lambda>1       z,RevocationChecker.__init__.<locals>.<lambda>c                 S   s   d| gS )NZHostr   r   r   r   r   r   3   r    )brokenr   use_openssl_binaryr   Z
exe_existsloggerinfor   r   Zcommunicate	host_args)selfZenforce_openssl_binary_usageZtest_host_formatZ_outerrr   r   r   __init__"   s     

  zRevocationChecker.__init__c                 C   sp   |j |j }}| jrdS tjt }|j|kr6dS t	|\}}|rJ|sNdS | j
rd| ||||S t|||S )a  Get revoked status for a particular cert version.

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

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

        F)certchainr!   pytzZUTCZfromutcr   utcnowZtarget_expiry_determine_ocsp_serverr"   _check_ocsp_openssl_bin_check_ocsp_cryptography)r&   r)   	cert_path
chain_pathnowurlr   r   r   r   ocsp_revoked5   s    
zRevocationChecker.ocsp_revokedc                 C   s   dddd|d|d|d|d|d	d
g|  | }td| td| ztj|tjd\}}W n$ tjk
r   td| Y dS X t	|||S )Nr   r   z	-no_noncez-issuerz-certz-urlz-CAfilez-verify_otherz-trust_otherr   zQuerying OCSP for %s )log*OCSP check failed for %s (are we offline?)F)
r%   r#   debugjoinr   Z
run_scriptr   ZSubprocessErrorr$   _translate_ocsp_query)r&   r0   r1   r   r3   cmdoutputr'   r   r   r   r.   T   s2         	z)RevocationChecker._check_ocsp_openssl_binN)F)__name__
__module____qualname____doc__r(   r4   r.   r   r   r   r   r      s   
r   c              	      s   t | d}t| t }W 5 Q R X z:|jtj}tjj	  fdd|j
D }|d jj
}W n( tjtfk
r   td|  Y dS X | }|dd d	}|r||fS td
||  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)

    rbc                    s   g | ]}|j  kr|qS r   )Zaccess_method).0ZdescriptionZocsp_oidr   r   
<listcomp>x   s    
z*_determine_ocsp_server.<locals>.<listcomp>r   zCannot extract OCSP URI from %s)NNz://   /z4Cannot process OCSP host from URL (%s) in cert at %s)openr   load_pem_x509_certificatereadr	   
extensionsget_extension_for_classZAuthorityInformationAccessZAuthorityInformationAccessOIDZOCSPvalueZaccess_locationExtensionNotFound
IndexErrorr#   r$   rstrip	partition)r0   file_handlerr)   	extensionZdescriptionsr3   r   r   rC   r   r-   j   s     	r-   c              
   C   s   t |d}t| t }W 5 Q R X t | d}t| t }W 5 Q R X t }|||t	 }|
 }|tjj}ztj||ddid}	W n* tjjk
r   tjd| dd Y dS X |	jd	krtd
| |	j dS t|	j}
|
jtjjkrtd| |
j dS zt|
|||  W n tk
rV } ztt| W 5 d }~X Y n tj k
r } ztt| W 5 d }~X Y nt t!k
r   td|  Y nT t"k
r } ztd| t| W 5 d }~X Y n X t#d| |
j$ |
j$tj%j&kS dS )NrA   zContent-Typezapplication/ocsp-request)dataZheadersr7   T)exc_infoF   z*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)'rG   r   rH   rI   r	   r   ZOCSPRequestBuilderZadd_certificater   ZSHA1ZbuildZpublic_bytesr
   ZEncodingZDERrequestsZpost
exceptionsZRequestExceptionr#   r$   Zstatus_codeZload_der_ocsp_responseZcontentZresponse_statusZOCSPResponseStatusZ
SUCCESSFULerror_check_ocsp_responser   strr   Errorr   AssertionErrorr8   Zcertificate_statusZOCSPCertStatusZREVOKED)r0   r1   r3   rQ   issuerr)   ZbuilderZrequestZrequest_binaryZresponseresponse_ocsperX   r   r   r   r/      sR    

 $ r/   c                 C   s   | j |j krtdt| || t| jt|jrJ| j|jksJ| j|jkrRtdt	 }| j
shtd| j
|tdd krtd| jr| j|tdd k rtddS )	z4Verify that the OCSP is valid for serveral criteriaszMthe certificate in response does not correspond to the certificate in requestz<the issuer does not correspond to issuer of the certificate.zparam thisUpdate is not set.   )Zminutesz"param thisUpdate is in the future.z param nextUpdate is in the past.N)Zserial_numberr\   _check_ocsp_response_signature
isinstanceZhash_algorithmtypeZissuer_key_hashZissuer_name_hashr   r,   Zthis_updater   Znext_update)r^   Zrequest_ocspissuer_certr0   r2   r   r   r   rY      s     

rY   c              	      s    j |jkrtd| |}ntd|  fdd jD }|sJtd|d }|j|jkrftdz"|jt	j
}t	jjj|jk}W n t	jtfk
r   d}Y nX |std	|j}t| |j|j|  j}t|  j j| d
S )zIVerify an OCSP response signature against certificate issuer or responderzGOCSP response for certificate %s is signed by the certificate's issuer.zGOCSP response for certificate %s is delegated to an external responder.c                    s   g | ]}|j  jkr|qS r   )subjectresponder_name)rB   r)   r^   r   r   rD      s    z2_check_ocsp_response_signature.<locals>.<listcomp>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 responsesN)rf   re   r#   r8   Zcertificatesr\   r]   rJ   rK   r   ZExtendedKeyUsageZoidZExtendedKeyUsageOIDZOCSP_SIGNINGrL   rM   rN   r   r   Zverify_signed_payloadZ
public_keyZ	signatureZtbs_certificate_bytesZtbs_response_bytes)r^   rd   r0   Zresponder_certZresponder_certsrR   Zdelegate_authorizedZchosen_hashr   rg   r   ra      s>    
  ra   c           	         s   d} fdd|D }fdd|D \}}}|r<| dnd}d|ksT|rP|sT|rrtd	  td
| dS |r~|s~dS |r| d}|rtd| dS td| dS dS )z7Parse openssl's weird output to work out what it means.)goodrevokedunknownc                    s   g | ]}d   |qS )z{0}: (WARNING.*)?{1})format)rB   s)r0   r   r   rD     s     z)_translate_ocsp_query.<locals>.<listcomp>c                 3   s    | ]}t j| t jd V  qdS ))flagsN)researchDOTALL)rB   p)ocsp_outputr   r   	<genexpr>  s     z(_translate_ocsp_query.<locals>.<genexpr>   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)groupr#   r$   r8   warning)	r0   rr   Zocsp_errorsZstatesZpatternsrh   ri   rj   rv   r   )r0   rr   r   r:     s(    
 r:   )-r@   Zloggingrn   r   r   
subprocessr   r   Zcryptography.x509r   getattrZOCSPResponseImportErrorAttributeErrorZcryptographyr   Zcryptography.hazmat.backendsr	   Zcryptography.hazmat.primitivesr
   r   Zcryptography.exceptionsr   r   r+   rV   Zacme.magic_typingr   r   Zcertbotr   r   Zcertbot.storager   r   Z	getLoggerr=   r#   objectr   r-   r/   rY   ra   r:   r   r   r   r   <module>   s8   

K1"1