a
    á `ÓR  ã                   @   s$  d Z ddlZddlZddlZddlZddlmZ ddlmZm	Z	 ddl
mZ ddlmZ ddlmZmZ ddlmZ dd	lmZ dd
lmZmZm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* e +e,¡Z-dOdd„Z.dd„ Z/dd„ Z0dd„ Z1dd„ Z2dPd!d"„Z3d#d$„ Z4d%d&„ Z5d'd(„ Z6d)d*„ Z7d+d,„ Z8d-d.„ Z9d/d0„ Z:ej;fd1d2„Z<ej;fd3d4„Z=ej;fd5d6„Z>d7d8„ Z?d9d:„ Z@ej;fd;d<„ZAej;fd=d>„ZBd?d@„ ZCdAdB„ ZDdCdD„ ZEdEdF„ ZFe GdGejH¡ZIdHdI„ ZJdJdK„ ZKdQdMdN„ZLdS )Rz¦Certbot 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)Úx509)ÚInvalidSignatureÚUnsupportedAlgorithm)Údefault_backend)Úec)ÚECDSAÚEllipticCurvePublicKey)ÚPKCS1v15)ÚRSAPublicKey)ÚEncodingÚNoEncryptionÚPrivateFormat)Úcrypto)ÚSSL)Úcrypto_util)ÚIO)Úerrors)Ú
interfaces)Úutil)ÚosÚrsaÚ	secp256r1úkey-certbot.pemc           
   
   C   sè   zt | |pd|d}W n6 tyL } ztjddd |‚W Y d}~n
d}~0 0 tj tj¡}t	 
|d|j¡ t	 tj ||¡dd	¡\}}	| | |¡ W d  ƒ n1 s¬0    Y  |d
krÎt d| |	¡ nt d| |	¡ t	 |	|¡S )ai  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

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

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

    r   )ÚbitsÚelliptic_curveÚkey_typeÚ T©Úexc_infoNiÀ  i€  Úwbr   z Generating RSA key (%d bits): %sz"Generating ECDSA key (%d bits): %s)Úmake_keyÚ
ValueErrorÚloggerÚerrorÚzopeÚ	componentÚ
getUtilityr   ÚIConfigr   Úmake_or_verify_dirÚstrict_permissionsÚunique_filer   ÚpathÚjoinÚwriteÚdebugZKey)
Zkey_sizeZkey_dirr   r   ZkeynameZkey_pemÚerrÚconfigZkey_fÚkey_path© r2   ú5/usr/lib/python3/dist-packages/certbot/crypto_util.pyÚinit_save_key'   s$    
ÿ
ÿ(r4   c                 C   s–   t j tj¡}tj| j||jd}t	 
|d|j¡ t	 tj |d¡dd¡\}}| | |¡ W d  ƒ n1 sr0    Y  t d|¡ t	 ||d¡S )	a2  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.

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

    )Úmust_stapleií  zcsr-certbot.pemi¤  r   NzCreating CSR: %sÚpem)r$   r%   r&   r   r'   Úacme_crypto_utilZmake_csrr6   r5   r   r(   r)   r*   r   r+   r,   r-   r"   r.   ÚCSR)ÚprivkeyÚnamesr+   r0   Zcsr_pemZcsr_fZcsr_filenamer2   r2   r3   Úinit_save_csrT   s    
ÿÿ(r;   c                 C   sH   zt  t j| ¡}| | ¡ ¡W S  t jyB   tjddd Y dS 0 dS )zŸValidate 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   FN)r   Úload_certificate_requestÚFILETYPE_PEMÚverifyZ
get_pubkeyÚErrorr"   r.   )ÚcsrÚreqr2   r2   r3   Ú	valid_csrw   s    ÿrB   c                 C   sR   t  t j| ¡}t  t j|¡}z| |¡W S  t jyL   tjddd Y dS 0 dS )zùDoes 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   FN)r   r<   r=   Úload_privatekeyr>   r?   r"   r.   )r@   r9   rA   Zpkeyr2   r2   r3   Úcsr_matches_pubkey‹   s    
ÿrD   c                 C   s   t j}t j}z|t j|ƒ}W nH t jyd   z|||ƒ}W n$ t jy^   t d | ¡¡‚Y n0 Y n0 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}r6   )ÚfileÚdataZform)r   r=   r<   ÚFILETYPE_ASN1r?   r   ÚformatÚ"_get_names_from_loaded_cert_or_reqZdump_certificate_requestr   r8   )ZcsrfilerF   ÚPEMÚloadr@   ZdomainsZdata_pemr2   r2   r3   Úimport_csr_fileŸ   s    rL   é   c              
   C   s&  |dkr8| dk r t  d | ¡¡‚t ¡ }| tj| ¡ nà|dkrzD| ¡ }|dv rttj	t
t| ¡ dƒƒ tƒ d}nt  d |¡¡‚W nZ ty¨   t  d |¡¡‚Y n: tyà } z"t |t  t|ƒ¡¡‚W Y d}~n
d}~0 0 |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   rM   zUnsupported RSA key length: {}Zecdsa)Z	SECP256R1Z	SECP384R1Z	SECP521R1N)ZcurveZbackendzUnsupported elliptic curve: {})ÚencodingrH   Zencryption_algorithmz0Invalid key_type specified: {}.  Use [rsa|ecdsa])r   r?   rH   r   ZPKeyZgenerate_keyZTYPE_RSAÚupperr   Zgenerate_private_keyÚgetattrr   Ú	TypeErrorr   ÚsixZ
raise_fromÚstrZprivate_bytesr   rJ   r   ZTraditionalOpenSSLr   rC   r=   Zdump_privatekey)r   r   r   ÚkeyÚnameZ_keyÚeZ_key_pemr2   r2   r3   r    ¼   s4    
þ,ýr    c              	   C   s4   zt  t j| ¡ ¡ W S  tt jfy.   Y dS 0 dS )z’Is valid RSA private key?

    :param str privkey: Private key file contents in PEM

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

    FN)r   rC   r=   ZcheckrQ   r?   )r9   r2   r2   r3   Úvalid_privkeyæ   s    	ÿ
rW   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_pathr1   )Úrenewable_certr2   r2   r3   Úverify_renewable_certö   s    r]   c              
   C   s  zÄt | jdƒ"}t | ¡ tƒ ¡}W d  ƒ n1 s60    Y  t | jdƒ"}t | ¡ tƒ ¡}W d  ƒ n1 st0    Y  | ¡ }t 	¡ $ t
||j|j|jƒ W d  ƒ n1 s¸0    Y  W nN tttfy } z.d | j|¡}t |¡ t |¡‚W Y d}~n
d}~0 0 dS )zØVerifies 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_keyÚwarningsÚcatch_warningsÚverify_signed_payloadÚ	signatureZtbs_certificate_bytesÚsignature_hash_algorithmÚIOErrorr!   r   rH   r"   Ú	exceptionr   r?   )r\   Ú
chain_fileÚchainÚ	cert_fileÚcertZpkrV   Ú	error_strr2   r2   r3   rX     s     00
ÿ&ÿ
rX   c                 C   sœ   t  ¡ € t  d¡ t| tƒrB|  |tƒ |¡}| |¡ | ¡  n8t| t	ƒrp|  |t
|ƒ¡}| |¡ | ¡  n
t d¡‚W d  ƒ n1 sŽ0    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)rd   re   ÚsimplefilterÚ
isinstancer
   Úverifierr	   Úupdater>   r   r   r   r?   )rc   rg   Zpayloadrh   rs   r2   r2   r3   rf      s    


ÿ


ÿ

rf   c              
   C   s~   z,t  t j¡}| | ¡ | |¡ | ¡  W nL tt jfyx } z.d | ||¡}t	 
|¡ t |¡‚W Y d}~n
d}~0 0 dS )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.
    zˆverifying the certificate located at {0} matches the                 private key located at {1} has failed.                 Details: {2}N)r   ZContextZSSLv23_METHODZuse_certificate_fileZuse_privatekey_fileZcheck_privatekeyri   r?   rH   r"   rj   r   )r[   r1   ÚcontextrV   ro   r2   r2   r3   rZ   ?  s    

ý
rZ   c           	   
   C   s4  zÀt | jƒ}| ¡ }W d  ƒ n1 s*0    Y  t | jƒ}| ¡ }W d  ƒ n1 s\0    Y  t | jƒ}| ¡ }W d  ƒ n1 sŽ0    Y  || |kr¾d}| | j¡}t |¡‚W nn t	y } z*d |¡}t
 |¡ t |¡‚W Y d}~n4d}~0  tjy. } z|‚W Y d}~n
d}~0 0 dS )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`   rb   r[   Zfullchain_pathrH   Zlineagenamer   r?   ri   r"   rj   )	r\   rk   rl   rm   rn   Zfullchain_fileZ	fullchainro   rV   r2   r2   r3   rY   U  s"    &&&

rY   c                 C   s‚   g }t jt jfD ]L}zt  || ¡|fW   S  t jyZ } z| |¡ W Y d}~qd}~0 0 qt d d dd„ |D ƒ¡¡¡‚dS )z:Load PEM/DER certificate.

    :raises errors.Error:

    NzUnable to load: {0}ú,c                 s   s   | ]}t |ƒV  qd S ©N)rS   )Ú.0r#   r2   r2   r3   Ú	<genexpr>~  s   z-pyopenssl_load_certificate.<locals>.<genexpr>)	r   r=   rG   Úload_certificater?   Úappendr   rH   r,   )rF   Zopenssl_errorsZ	file_typer#   r2   r2   r3   Úpyopenssl_load_certificatep  s    "ÿr|   c                 C   s6   z||| ƒW S  t jy0   tjddd ‚ Y n0 d S )Nr   Tr   )r   r?   r"   r#   ©Zcert_or_req_strÚ	load_funcÚtypr2   r2   r3   Ú_load_cert_or_req‚  s
    r€   c                 C   s   t  t| ||ƒ¡S rw   )r7   Z_pyopenssl_cert_or_req_sanr€   r}   r2   r2   r3   Ú_get_sans_from_cert_or_req‹  s    ÿr   c                 C   s   t | tj|ƒS )zóGet 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   rz   )rn   r   r2   r2   r3   Úget_sans_from_cert’  s    
ÿr‚   c                 C   s   t | ||ƒ}t|ƒS rw   )r€   rI   )Zcert_or_reqr~   r   Úloaded_cert_or_reqr2   r2   r3   Ú_get_names_from_cert_or_req   s    r„   c                 C   s
   t  | ¡S rw   )r7   Z _pyopenssl_cert_or_req_all_names)rƒ   r2   r2   r3   rI   ¥  s    rI   c                 C   s   t | tj|ƒS )zìGet 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   rz   )r@   r   r2   r2   r3   Úget_names_from_certª  s    
ÿr…   c                 C   s   t  | |¡S )z–Dump certificate chain into a bundle.

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

    )r7   Údump_pyopenssl_chain)rl   Zfiletyper2   r2   r3   r†   ¸  s    	r†   c                 C   s   t | tjjƒS )zÕWhen 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   ÚX509Zget_notBefore©r[   r2   r2   r3   Ú	notBeforeÄ  s    	rŠ   c                 C   s   t | tjjƒS )zÓWhen 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ˆ   Zget_notAfterr‰   r2   r2   r3   ÚnotAfterÐ  s    	r‹   c                 C   s¸   t | dƒ"}t tj| ¡ ¡}W d  ƒ n1 s20    Y  ||ƒ}|dd… d|dd… d|dd… d|dd	… d
|d	d… d
|dd… g}d |¡}tjrª| d¡}n|}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   rz   r=   rb   r,   rR   ZPY3ÚdecodeÚ	pyrfc3339Úparse)r[   ÚmethodÚfr   Z	timestampZreformatted_timestampZtimestamp_bytesZtimestamp_strr2   r2   r3   r‡   Ü  s    0þ
r‡   c                 C   sN   t  ¡ }t| dƒ$}| | ¡  d¡¡ W d  ƒ n1 s<0    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_   rt   rb   ÚencodeZ	hexdigest)Úfilenamer   Zfile_dr2   r2   r3   Ú	sha256sumú  s    2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 r2   )r   Zdump_certificater=   rz   r–   )rx   rn   r2   r2   r3   Ú
<listcomp>*  s   ÿÿz1cert_and_chain_from_fullchain.<locals>.<listcomp>r   r   é   N)ÚCERT_PEM_REGEXÚfindallrž   Úlenr   r?   r,   )Zfullchain_pemÚcertsZcerts_normalizedr2   r2   r3   Úcert_and_chain_from_fullchain  s    
ÿr¨   c                 C   sD   t | dƒ"}t tj| ¡ ¡}W d  ƒ n1 s20    Y  | ¡ S )z¾Retrieve 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   rz   r=   rb   Zget_serial_number)r[   rš   r   r2   r2   r3   Úget_serial_from_cert1  s    	0r©   Fc                 C   sl   | D ]N}t  | ¡ ¡}t |d tƒ ¡}|j tjj	¡}|r|d j
|kr|  S q|rdt 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   z¥Certbot 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   ra   r   ZissuerZget_attributes_for_oidZNameOIDZCOMMON_NAMEÚvaluer"   Úinfo)Z
fullchainsZ	issuer_cnZwarn_on_no_matchrl   r§   Ztop_certZtop_issuer_cnr2   r2   r3   Úfind_chain_with_issuer?  s    
þr­   )r   r   r   )rM   r   N)F)MÚ__doc__rœ   Zloggingrd   ÚreZcryptographyr   Zcryptography.exceptionsr   r   Zcryptography.hazmat.backendsr   Z)cryptography.hazmat.primitives.asymmetricr   Z,cryptography.hazmat.primitives.asymmetric.ecr   r   Z1cryptography.hazmat.primitives.asymmetric.paddingr	   Z-cryptography.hazmat.primitives.asymmetric.rsar
   Z,cryptography.hazmat.primitives.serializationr   r   r   ZOpenSSLr   r   r—   rR   Zzope.componentr$   Zacmer   r7   Zacme.magic_typingr   Zcertbotr   r   r   Zcertbot.compatr   Z	getLoggerÚ__name__r"   r4   r;   rB   rD   rL   r    rW   r]   rX   rf   rZ   rY   r|   r=   r€   r   r‚   r„   rI   r…   r†   rŠ   r‹   r‡   r    ÚcompileÚDOTALLr¤   r¨   r©   r­   r2   r2   r2   r3   Ú<module>   st   
 ÿ
-#
*ÿ

ÿ
û	