o
    6aT_                     @   s  d 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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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+e,Z-			dhde.de/de/de/d e/d!e0d"e(j1fd#d$Z2		did%d&Z3	djd(e(j1d)ee/ d*e/d+e0d!e0d"e(j4fd,d-Z5d.d/ Z6d0d1 Z7d2d3 Z8d4d5 Z9dkd7d8Z:d9d: Z;d;d< Z<d=d> Z=d?d@ Z>dAdB Z?dCdD Z@dEdF ZAejBfdGdHZCejBfdIdJZDejBfdKdLZEdMdN ZFdOdP ZGejBfdQdRZHejBfdSe/dTe.d"ee/ fdUdVZIejBfdWdXZJdYdZ ZKd[d\ ZLd]d^ ZMd_d` ZNeOdaejPZQdbdc ZRddde ZSdldfdgZTdS )mzCertbot client crypto utility functions.

.. todo:: Make the transition to use PSS rather than PKCS1_v1_5 when the server
    is capable of handling the signatures.

    N)List)Set)x509)InvalidSignature)UnsupportedAlgorithm)default_backend)ec)ECDSA)EllipticCurvePublicKey)PKCS1v15)RSAPublicKey)Encoding)NoEncryption)PrivateFormat)crypto)SSL)crypto_util)errors)
interfaces)util)osrsa	secp256r1key-certbot.pemTkey_sizekey_dirkey_typeelliptic_curvekeynamestrict_permissionsreturnc           
   
   C   s   zt | |pd|d}W n ty( } ztjddd tdt| |d}~ww t|d| tt	j
||d	d
\}}	| || W d   n1 sPw   Y  |dkratd| |	 ntd| |	 t|	|S )a  Initializes and saves a privkey.

    Inits key and saves it in PEM format on the filesystem.

    .. note:: keyname is the attempted filename, it may be different if a file
        already exists at the path.

    :param int key_size: key size in bits if key size is rsa.
    :param str key_dir: Key save directory.
    :param str key_type: Key Type [rsa, ecdsa]
    :param str elliptic_curve: Name of the elliptic curve if key type is ecdsa.
    :param str keyname: Filename of key
    :param bool strict_permissions: If true and key_dir exists, an exception is raised if
        the directory doesn't have 0700 permissions or isn't owned by the current user.

    :returns: Key
    :rtype: :class:`certbot.util.Key`

    :raises ValueError: If unable to generate the key given key_size.

    r   )bitsr   r    Texc_infoz&Encountered error while making key: %sNi  i  wbr   z Generating RSA key (%d bits): %sz"Generating ECDSA key (%d bits): %s)make_key
ValueErrorloggerdebugerrorstrr   make_or_verify_dirunique_filer   pathjoinwriteKey)
r   r   r   r   r   r   key_pemerrkey_fkey_path r6   5/usr/lib/python3/dist-packages/certbot/crypto_util.pygenerate_key*   s*   

r8   c                 C   s0   t dt tjtj}t| |||||j	dS )a  Initializes and saves a privkey.

    Inits key and saves it in PEM format on the filesystem.

    .. note:: keyname is the attempted filename, it may be different if a file
        already exists at the path.

    .. deprecated:: 1.16.0
       Use :func:`generate_key` instead.

    :param int key_size: key size in bits if key size is rsa.
    :param str key_dir: Key save directory.
    :param str key_type: Key Type [rsa, ecdsa]
    :param str elliptic_curve: Name of the elliptic curve if key type is ecdsa.
    :param str keyname: Filename of key

    :returns: Key
    :rtype: :class:`certbot.util.Key`

    :raises ValueError: If unable to generate the key given key_size.

    zecertbot.crypto_util.init_save_key is deprecated, please use certbot.crypto_util.generate_key instead.)r   r   r   r   )
warningswarnDeprecationWarningzope	component
getUtilityr   IConfigr8   r   )r   r   r   r   r   configr6   r6   r7   init_save_keyZ   s   
rA   Fprivkeynamesr.   must_staplec                 C   s   t j| j||d}t|d| ttj|ddd\}}| |	| W d   n1 s0w   Y  t
d| t||dS )	a:  Initialize a CSR with the given private key.

    :param privkey: Key to include in the CSR
    :type privkey: :class:`certbot.util.Key`
    :param set names: `str` names to include in the CSR
    :param str path: Certificate save directory.
    :param bool must_staple: If true, include the TLS Feature extension "OCSP Must Staple"
    :param bool strict_permissions: If true and path exists, an exception is raised if
        the directory doesn't have 0755 permissions or isn't owned by the current user.

    :returns: CSR
    :rtype: :class:`certbot.util.CSR`

    )rD   i  zcsr-certbot.pemi  r%   NzCreating CSR: %spem)acme_crypto_utilmake_csrrE   r   r,   r-   r   r.   r/   r0   r(   r)   CSR)rB   rC   r.   rD   r   csr_pemcsr_fcsr_filenamer6   r6   r7   generate_csr{   s   rL   c                 C   s0   t dt tjtj}t| |||j	|j
dS )aw  Initialize a CSR with the given private key.

    .. deprecated:: 1.16.0
       Use :func:`generate_csr` instead.

    :param privkey: Key to include in the CSR
    :type privkey: :class:`certbot.util.Key`

    :param set names: `str` names to include in the CSR

    :param str path: Certificate save directory.

    :returns: CSR
    :rtype: :class:`certbot.util.CSR`

    zecertbot.crypto_util.init_save_csr is deprecated, please use certbot.crypto_util.generate_csr instead.)rD   r   )r9   r:   r;   r<   r=   r>   r   r?   rL   rD   r   )rB   rC   r.   r@   r6   r6   r7   init_save_csr   s   rM   c                 C   sD   zt t j| }|| W S  t jy!   tjddd Y dS w )zValidate CSR.

    Check if `csr` is a valid CSR for the given domains.

    :param str csr: CSR in PEM.

    :returns: Validity of CSR.
    :rtype: bool

    r"   Tr#   F)r   load_certificate_requestFILETYPE_PEMverify
get_pubkeyErrorr(   r)   )csrreqr6   r6   r7   	valid_csr   s   rU   c                 C   sN   t t j| }t t j|}z||W S  t jy&   tjddd Y dS w )zDoes private key correspond to the subject public key in the CSR?

    :param str csr: CSR in PEM.
    :param str privkey: Private key file contents (PEM)

    :returns: Correspondence of private key to CSR subject public key.
    :rtype: bool

    r"   Tr#   F)r   rN   rO   load_privatekeyrP   rR   r(   r)   )rS   rB   rT   pkeyr6   r6   r7   csr_matches_pubkey   s   
rX   c                 C   s   t j}t j}z|t j|}W n" t jy0   z|||}W n t jy-   td| w Y nw t|}t ||}|t	j
| |dd|fS )a/  Import a CSR file, which can be either PEM or DER.

    :param str csrfile: CSR filename
    :param str data: contents of the CSR file

    :returns: (`crypto.FILETYPE_PEM`,
               util.CSR object representing the CSR,
               list of domains requested in the CSR)
    :rtype: tuple

    zFailed to parse CSR file: {0}rE   )filedataform)r   rO   rN   FILETYPE_ASN1rR   r   format"_get_names_from_loaded_cert_or_reqdump_certificate_requestr   rH   )csrfilerZ   PEMloadrS   domainsdata_pemr6   r6   r7   import_csr_file   s   re      c              
   C   s  |dkr| dk rt d| t }|tj|  nd|dkrxz"| }|dv r9tj	t
t| d t d}nt d|W n" tyQ   t d| tyd } z|t t|d}~ww |jtjtjt d	}ttj|}nt d
|ttj|S )aD  Generate PEM encoded RSA|EC key.

    :param int bits: Number of bits if key_type=rsa. At least 1024 for RSA.

    :param str ec_curve: The elliptic curve to use.

    :returns: new RSA or ECDSA key in PEM form with specified number of bits
              or of type ec_curve when key_type ecdsa is used.
    :rtype: str
    r   rf   zUnsupported RSA key length: {}ecdsa)	SECP256R1	SECP384R1	SECP521R1N)curvebackendzUnsupported elliptic curve: {})encodingr]   encryption_algorithmz0Invalid key_type specified: {}.  Use [rsa|ecdsa])r   rR   r]   r   PKeyr8   TYPE_RSAupperr   generate_private_keygetattrr   	TypeErrorr   r+   private_bytesr   ra   r   TraditionalOpenSSLr   rV   rO   dump_privatekey)r!   r   r   keyname_keye_key_pemr6   r6   r7   r&      s:   r&   c              	   C   s0   z
t t j|  W S  tt jfy   Y dS w )zIs valid RSA private key?

    :param str privkey: Private key file contents in PEM

    :returns: Validity of private key.
    :rtype: bool

    F)r   rV   rO   checkrt   rR   )rB   r6   r6   r7   valid_privkey,  s   	r~   c                 C   s"   t |  t|  t| j| j dS )a  For checking that your certs were not corrupted on disk.

    Several things are checked:
        1. Signature verification for the cert.
        2. That fullchain matches cert and chain when concatenated.
        3. Check that the private key matches the certificate.

    :param renewable_cert: cert to verify
    :type renewable_cert: certbot.interfaces.RenewableCert

    :raises errors.Error: If verification fails.
    N)verify_renewable_cert_sigverify_fullchainverify_cert_matches_priv_key	cert_pathr5   )renewable_certr6   r6   r7   verify_renewable_cert<  s   r   c              
   C   s  zet | jd}t| t }W d   n1 sw   Y  t | jd}t| t }W d   n1 s:w   Y  | }t	  t
||j|j|j W d   W dS 1 s^w   Y  W dS  tttfy } zd| j|}t| t|d}~ww )zVerifies the signature of a RenewableCert object.

    :param renewable_cert: cert to verify
    :type renewable_cert: certbot.interfaces.RenewableCert

    :raises errors.Error: If signature verification fails.
    rbNzbverifying the signature of the certificate located at {0} has failed.                 Details: {1})open
chain_pathr   load_pem_x509_certificatereadr   r   
public_keyr9   catch_warningsverify_signed_payload	signaturetbs_certificate_bytessignature_hash_algorithmIOErrorr'   r   r]   r(   	exceptionr   rR   )r   
chain_filechain	cert_filecertpkr{   	error_strr6   r6   r7   r   N  s*   
&


r   c                 C   s   t  I t d t| tr!| |t |}|| |  nt| t	r8| |t
|}|| |  ntdW d   dS W d   dS 1 sPw   Y  dS )a  Check the signature of a payload.

    :param RSAPublicKey/EllipticCurvePublicKey public_key: the public_key to check signature
    :param bytes signature: the signature bytes
    :param bytes payload: the payload bytes
    :param cryptography.hazmat.primitives.hashes.HashAlgorithm            signature_hash_algorithm: algorithm used to hash the payload

    :raises InvalidSignature: If signature verification fails.
    :raises errors.Error: If public key type is not supported
    ignorezUnsupported public key typeN)r9   r   simplefilter
isinstancer   verifierr   updaterP   r
   r	   r   rR   )r   r   payloadr   r   r6   r6   r7   r   f  s&   








"r   c              
   C   sp   zt t j}||  || |  W dS  tt jfy7 } zd| ||}t	
| t|d}~ww )z Verifies that the private key and cert match.

    :param str cert_path: path to a cert in PEM format
    :param str key_path: path to a private key file

    :raises errors.Error: If they don't match.
    zverifying the certificate located at {0} matches the                 private key located at {1} has failed.                 Details: {2}N)r   ContextSSLv23_METHODuse_certificate_fileuse_privatekey_filecheck_privatekeyr   rR   r]   r(   r   r   )r   r5   contextr{   r   r6   r6   r7   r     s   



r   c           	   
   C   s  zat | j}| }W d   n1 sw   Y  t | j}| }W d   n1 s.w   Y  t | j}| }W d   n1 sGw   Y  || |kr_d}|| j}t|W dS  t	y| } zd|}t
| t|d}~w tjy } z|d}~ww )z Verifies that fullchain is indeed cert concatenated with chain.

    :param renewable_cert: cert to verify
    :type renewable_cert: certbot.interfaces.RenewableCert

    :raises errors.Error: If cert and chain do not combine to fullchain.
    Nz.fullchain does not match cert + chain for {0}!z8reading one of cert, chain, or fullchain has failed: {0})r   r   r   r   fullchain_pathr]   lineagenamer   rR   r   r(   r   )	r   r   r   r   r   fullchain_file	fullchainr   r{   r6   r6   r7   r     s0   






r   c                 C   s|   g }t jt jfD ]%}zt || |fW   S  t jy- } z|| W Y d}~qd}~ww tdddd |D )z:Load PEM/DER certificate.

    :raises errors.Error:

    NzUnable to load: {0},c                 s   s    | ]}t |V  qd S N)r+   ).0r*   r6   r6   r7   	<genexpr>  s    
z-pyopenssl_load_certificate.<locals>.<genexpr>)	r   rO   r\   load_certificaterR   appendr   r]   r/   )rZ   openssl_errors	file_typer*   r6   r6   r7   pyopenssl_load_certificate  s   r   c              
   C   sH   z||| W S  t jy# } ztjddd tdt|  d }~ww )Nr"   Tr#   z6Encountered error while loading certificate or csr: %s)r   rR   r(   r)   r*   r+   )cert_or_req_str	load_functypr3   r6   r6   r7   _load_cert_or_req  s   r   c                 C   s   t t| ||S r   )rF   _pyopenssl_cert_or_req_sanr   )r   r   r   r6   r6   r7   _get_sans_from_cert_or_req  s   r   c                 C      t | tj|S )zGet a list of Subject Alternative Names from a certificate.

    :param str cert: Certificate (encoded).
    :param typ: `crypto.FILETYPE_PEM` or `crypto.FILETYPE_ASN1`

    :returns: A list of Subject Alternative Names.
    :rtype: list

    )r   r   r   )r   r   r6   r6   r7   get_sans_from_cert     
r   c                 C   s   t | ||}t|S r   )r   r^   )cert_or_reqr   r   loaded_cert_or_reqr6   r6   r7   _get_names_from_cert_or_req  s   r   c                 C   s
   t | S r   )rF    _pyopenssl_cert_or_req_all_names)r   r6   r6   r7   r^     s   
r^   c                 C   r   )zGet a list of domains from a cert, including the CN if it is set.

    :param str cert: Certificate (encoded).
    :param typ: `crypto.FILETYPE_PEM` or `crypto.FILETYPE_ASN1`

    :returns: A list of domain names.
    :rtype: list

    )r   r   r   rS   r   r6   r6   r7   get_names_from_cert  r   r   rS   r   c                 C   r   )zGet a list of domains from a CSR, including the CN if it is set.

    :param str cert: CSR (encoded).
    :param typ: `crypto.FILETYPE_PEM` or `crypto.FILETYPE_ASN1`
    :returns: A list of domain names.
    :rtype: list

    )r   r   rN   r   r6   r6   r7   get_names_from_req     	r   c                 C   s   t | |S )zDump certificate chain into a bundle.

    :param list chain: List of `crypto.X509` (or wrapped in
        :class:`josepy.util.ComparableX509`).

    )rF   dump_pyopenssl_chain)r   filetyper6   r6   r7   r   
  s   	r   c                 C      t | tjjS )zWhen does the cert at cert_path start being valid?

    :param str cert_path: path to a cert in PEM format

    :returns: the notBefore value from the cert at cert_path
    :rtype: :class:`datetime.datetime`

    )_notAfterBeforer   X509get_notBeforer   r6   r6   r7   	notBefore  r   r   c                 C   r   )zWhen does the cert at cert_path stop being valid?

    :param str cert_path: path to a cert in PEM format

    :returns: the notAfter value from the cert at cert_path
    :rtype: :class:`datetime.datetime`

    )r   r   r   get_notAfterr   r6   r6   r7   notAfter"  r   r   c                 C   s   t | d}ttj| }W d   n1 sw   Y  ||}|dd d|dd d|dd d|dd	 d
|d	d d
|dd g}d|}|d}t|S )aP  Internal helper function for finding notbefore/notafter.

    :param str cert_path: path to a cert in PEM format
    :param function method: one of ``crypto.X509.get_notBefore``
        or ``crypto.X509.get_notAfter``

    :returns: the notBefore or notAfter value from the cert at cert_path
    :rtype: :class:`datetime.datetime`

    r   Nr         -         T
      :       ascii)	r   r   r   rO   r   r/   decode	pyrfc3339parse)r   methodfr   	timestampreformatted_timestamptimestamp_bytestimestamp_strr6   r6   r7   r   .  s   


r   c                 C   sT   t  }t| d}|| d W d   | S 1 s!w   Y  | S )aN  Compute a sha256sum of a file.

    NB: In given file, platform specific newlines characters will be converted
    into their equivalent unicode counterparts before calculating the hash.

    :param str filename: path to the file whose hash will be computed

    :returns: sha256 digest of the file in hexadecimal
    :rtype: str
    rzUTF-8N)hashlibsha256r   r   r   encode	hexdigest)filenamer   file_dr6   r6   r7   	sha256sumG  s   
r   s@   -----BEGIN CERTIFICATE-----?
.+??
-----END CERTIFICATE-----?
c                 C   sL   t |  }t|dk rtddd |D }|d d|dd fS )	a  Split fullchain_pem into cert_pem and chain_pem

    :param str fullchain_pem: concatenated cert + chain

    :returns: tuple of string cert_pem and chain_pem
    :rtype: tuple

    :raises errors.Error: If there are less than 2 certificates in the chain.

       zPfailed to parse fullchain into cert and chain: less than 2 certificates in chainc              	   S   s(   g | ]}t t jt t j| qS r6   )r   dump_certificaterO   r   r   )r   r   r6   r6   r7   
<listcomp>w  s    z1cert_and_chain_from_fullchain.<locals>.<listcomp>r   r"      N)CERT_PEM_REGEXfindallr   lenr   rR   r/   )fullchain_pemcertscerts_normalizedr6   r6   r7   cert_and_chain_from_fullchainb  s   
r   c                 C   sJ   t | d}ttj| }W d   | S 1 sw   Y  | S )zRetrieve the serial number of a certificate from certificate path

    :param str cert_path: path to a cert in PEM format

    :returns: serial number of the certificate
    :rtype: int
    r   N)r   r   r   rO   r   get_serial_number)r   r   r   r6   r6   r7   get_serial_from_cert~  s   	
r   c                 C   sl   | D ]'}t | }t|d t }|jtjj	}|r)|d j
|kr)|  S q|r2td| | d S )a'  Chooses the first certificate chain from fullchains whose topmost
    intermediate has an Issuer Common Name matching issuer_cn (in other words
    the first chain which chains to a root whose name matches issuer_cn).

    :param fullchains: The list of fullchains in PEM chain format.
    :type fullchains: `list` of `str`
    :param `str` issuer_cn: The exact Subject Common Name to match against any
        issuer in the certificate chain.

    :returns: The best-matching fullchain, PEM-encoded, or the first if none match.
    :rtype: `str`
    r   zCertbot has been configured to prefer certificate chains with issuer '%s', but no chain from the CA matched this issuer. Using the default certificate chain instead.)r   r   r   r   r   r   issuerget_attributes_for_oidNameOIDCOMMON_NAMEvaluer(   warning)
fullchains	issuer_cnwarn_on_no_matchr   r   top_certtop_issuer_cnr6   r6   r7   find_chain_with_issuer  s   r   )r   r   r   T)r   r   r   )FT)rf   r   N)F)U__doc__r   loggingretypingr   r   r9   cryptographyr   cryptography.exceptionsr   r   cryptography.hazmat.backendsr   )cryptography.hazmat.primitives.asymmetricr   ,cryptography.hazmat.primitives.asymmetric.ecr	   r
   1cryptography.hazmat.primitives.asymmetric.paddingr   -cryptography.hazmat.primitives.asymmetric.rsar   ,cryptography.hazmat.primitives.serializationr   r   r   OpenSSLr   r   r   zope.componentr<   acmer   rF   certbotr   r   r   certbot.compatr   	getLogger__name__r(   intr+   boolr1   r8   rA   rH   rL   rM   rU   rX   re   r&   r~   r   r   r   r   r   r   rO   r   r   r   r   r^   r   r   r   r   r   r   r   compileDOTALLr   r   r   r   r6   r6   r6   r7   <module>   s    

0
"

.

 	