3 گag @s&dZddlZddlZddlZddlZddlmZddlmZddlmZddlm Z ddlm Z ddlm Z dd lm Z ddl Z dd lmZdd lmZdd lmZdd lmZddlmZddlmZddlmZddlmZddlmZddlmZddl m!Z!ddl"m#Z#ddl"m$Z$ddl"m%Z%ddl&Z&ddl'm(Z(ddl'm)Z)ddl*Z*ddl+Z,ddl-m.Z/ddl0m1Z1ddl0m2Z2ddl0m3Z3ddl4m5Z5e rddl6m7Z7dd l8m9Z9ej:e;Ze>e>e>e?e3j@d%d&d'ZAde=e>e>e>e>e3j@d(d)d*ZBde3j@e ee>e e>fe>e?e?e3jCd,d-d.ZDe3j@e e>e>e3jCd/d0d1ZEeFe?d2d3d4ZGeFeFe?d5d6d7ZHe>eFe e=e3jCee>fd8d9d:ZIde=e>ee>eFd<d=d>ZJe>e?d?d@dAZKe2jLddBdCdDZMe2jLddBdEdFZNe edGdHee!feFeFejOddIdJdKZPe>e>ddLdMdNZQe2jLddBdOdPZReFe e(jSe=fdQdRdSZTe(jUfeFee=eFge e(jSe(jVffe=e e(jSe(jVfdTdUdVZWe(jUfeFee=eFge e(jSe(jVffe=ee>dTdWdXZXe(jUfeFe=ee>dYdZd[ZYeFee=eFge e(jSe(jVffe=ee>d\d]d^ZZe e(jSe(jVfee>d_d`daZ[e(jUfeFe=ee>dYdbdcZ\e(jUfeFe=ee>dddedfZ]e(jUfe ee(jSee&j^fe=eFdgdhdiZ_e>ejdjdkdlZ`e>ejdjdmdnZae>ee(jSgeeFfejdodpdqZbe>e>drdsdtZcejdduejeZfe>e e>e>fdvdwdxZge>e=djdydzZhdee>e>e?e>d{d|d}ZidS)zCertbot 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)Callable)List)Optional)Set)Tuple) TYPE_CHECKING)Union)x509)InvalidSignature)UnsupportedAlgorithm)default_backend)hashes)ec) DSAPublicKey)ECDSA)EllipticCurvePublicKey)PKCS1v15) RSAPublicKey)Encoding) NoEncryption) PrivateFormat)crypto)SSL) crypto_util)errors) interfaces)util)os)Ed448PublicKey)Ed25519PublicKeyrsa secp256r1key-certbot.pemT)key_sizekey_dirkey_typeelliptic_curvekeynamestrict_permissionsreturnc Csyt||p d|d}WnDtk rZ}z(tjdddtjdt||WYdd}~XnXtj|d|tjt j j ||d d \}} ||j |WdQRX|d krtjd || ntjd || tj | |S)aInitializes 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: %sNiiwbr z Generating RSA key (%d bits): %sz"Generating ECDSA key (%d bits): %s)make_key ValueErrorloggerdebugerrorstrrmake_or_verify_dir unique_filerpathjoinwriteKey) r#r$r%r&r'r(Zkey_pemerrZkey_fkey_pathr<!/usr/lib/python3.6/crypto_util.py generate_key8s r>)r#r$r%r&r'r)cCs0tjdttjjtj}t||||||j dS)aInitializes 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() warningswarnDeprecationWarningzope component getUtilityrIConfigr>r()r#r$r%r&r'configr<r<r= init_save_keyhs  rGF)privkeynamesr6 must_stapler(r)c Csptj|j||d}tj|d|tjtjj|ddd\}}||j |WdQRXt j d|tj ||dS) 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` )rJizcsr-certbot.pemir-NzCreating CSR: %spem) acme_crypto_utilZmake_csrrKrr4r5rr6r7r8r0r1CSR)rHrIr6rJr(Zcsr_pemZcsr_fZ csr_filenamer<r<r= generate_csrs rN)rHrIr6r)cCs0tjdttjjtj}t||||j |j dS)awInitialize 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.)rJr() r?r@rArBrCrDrrErNrJr()rHrIr6rFr<r<r= init_save_csrs  rO)csrr)c CsFytjtj|}|j|jStjk r@tjddddSXdS)zValidate CSR. Check if `csr` is a valid CSR for the given domains. :param bytes csr: CSR in PEM. :returns: Validity of CSR. :rtype: bool r+T)r,FN)rload_certificate_request FILETYPE_PEMverifyZ get_pubkeyErrorr0r1)rPreqr<r<r= valid_csrs  rV)rPrHr)c CsPtjtj|}tjtj|}y |j|Stjk rJtjddddSXdS)zDoes private key correspond to the subject public key in the CSR? :param bytes csr: CSR in PEM. :param bytes privkey: Private key file contents (PEM) :returns: Correspondence of private key to CSR subject public key. :rtype: bool r+T)r,FN)rrQrRload_privatekeyrSrTr0r1)rPrHrUZpkeyr<r<r=csr_matches_pubkeys   rX)csrfiledatar)cCstj}tj}y|tj|}WnLtjk rhy|||}Wn&tjk rbtjdj|YnXYnXt|}tj||}|t j ||dd|fS)a1Import a CSR file, which can be either PEM or DER. :param str csrfile: CSR filename :param bytes 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 zFailed to parse CSR file: {0}rK)filerZZform) rrRrQ FILETYPE_ASN1rTrformat"_get_names_from_loaded_cert_or_reqZdump_certificate_requestrrM)rYrZPEMloadrPZdomainsZdata_pemr<r<r=import_csr_files  ra)r*r%r&r)cCs.|dkr8|dkr tjdj|tj}|jtj|n|dkr|sPtjdyD|j}|dkrtj t t|jd t d }ntjd j|WnTt k rtjd j|Yn2t k r}z|tjt|WYd d }~XnX|jtjtjtd }tjtj|}ntjd j|tjtj|S)aGenerate PEM encoded RSA|EC key. :param int bits: Number of bits if key_type=rsa. At least 1024 for RSA. :param str key_type: The type of key to generate, but be rsa or ecdsa :param str elliptic_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 izUnsupported RSA key length: {}Zecdsaz3When key_type == ecdsa, elliptic_curve must be set. SECP256R1 SECP384R1 SECP521R1N)ZcurveZbackendzUnsupported elliptic curve: {})encodingr]Zencryption_algorithmz0Invalid key_type specified: {}. Use [rsa|ecdsa])rcrdre)rrTr]rZPKeyr>ZTYPE_RSAupperrZgenerate_private_keygetattrr TypeErrorr r3Z private_bytesrr_rZTraditionalOpenSSLrrWrRZdump_privatekey)r*r%r&keynameZ_keyeZ_key_pemr<r<r=r. s4    " r.)rHr)c Cs2ytjtj|jSttjfk r,dSXdS)zIs valid RSA private key? :param str privkey: Private key file contents in PEM :returns: Validity of private key. :rtype: bool FN)rrWrRZcheckrirT)rHr<r<r= valid_privkey>s rm)renewable_certr)cCs"t|t|t|j|jdS)aFor 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_sigverify_fullchainverify_cert_matches_priv_key cert_pathr;)rnr<r<r=verify_renewable_certNs rscCsytt|jd}tj|jt}WdQRXt|jd}tj|jt}WdQRX|j}t||j |j |j WnJt t tfk r}z(dj|j|}tj|tj|WYdd}~XnXdS)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_certificatereadr rr public_keyverify_signed_payload signatureZtbs_certificate_bytessignature_hash_algorithmIOErrorr/r r]r0 exceptionrrT)rn chain_filechain cert_filecertZpkrl error_strr<r<r=ro`s   rorr)ryr{payloadr|r)cCsJt|tr|j||t|n(t|tr<|j||t|n tjddS)aCheck 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 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 zUnsupported public key type.N) isinstancerrSrrrrrT)ryr{rr|r<r<r=rzws  rz)rrr;r)cCs|y,tjtj}|j||j||jWnJttjfk rv}z(dj|||}t j |t j|WYdd}~XnXdS)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) rZContextZ SSLv23_METHODZuse_certificate_fileZuse_privatekey_fileZcheck_privatekeyr}rTr]r0r~r)rrr;contextrlrr<r<r=rqs     rqc Csyt|j}|j}WdQRXt|j}|j}WdQRXt|j}|j}WdQRX|||krd}|j|j}tj|Wnft k r}z$dj|}t j |tj|WYdd}~Xn(tjk r}z |WYdd}~XnXdS)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}) rurvrxrrZfullchain_pathr]Z lineagenamerrTr}r0r~) rnrrrrZfullchain_fileZ fullchainrrlr<r<r=rps"       rp)rZr)cCs~g}xTtjtjfD]D}ytj|||fStjk rT}z|j|WYdd}~XqXqWtjdjdjdd|DdS)z:Load PEM/DER certificate. :raises errors.Error: NzUnable to load: {0},css|]}t|VqdS)N)r3).0r2r<r<r= sz-pyopenssl_load_certificate..) rrRr\load_certificaterTappendrr]r7)rZZopenssl_errorsZ file_typer2r<r<r=pyopenssl_load_certificates  r)cert_or_req_str load_functypr)cCsTy |||Stjk rN}z&tjdddtjdt|WYdd}~XnXdS)Nr+T)r,z6Encountered error while loading certificate or csr: %s)rrTr0r1r2r3)rrrr:r<r<r=_load_cert_or_reqs  rcCstjt|||S)N)rLZ_pyopenssl_cert_or_req_sanr)rrrr<r<r=_get_sans_from_cert_or_reqsr)rrr)cCst|tj|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 )rrr)rrr<r<r=get_sans_from_certs r) cert_or_reqrrr)cCst|||}t|S)N)rr^)rrrloaded_cert_or_reqr<r<r=_get_names_from_cert_or_reqs r)rr)cCs tj|S)N)rLZ _pyopenssl_cert_or_req_all_names)rr<r<r=r^sr^cCst|tj|S)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 )rrr)rrr<r<r=get_names_from_certs r)rPrr)cCst|tj|S)zGet a list of domains from a CSR, including the CN if it is set. :param str csr: CSR (encoded). :param typ: `crypto.FILETYPE_PEM` or `crypto.FILETYPE_ASN1` :returns: A list of domain names. :rtype: list )rrrQ)rPrr<r<r=get_names_from_reqs r)rfiletyper)cCs tj||S)zDump certificate chain into a bundle. :param list chain: List of `crypto.X509` (or wrapped in :class:`josepy.util.ComparableX509`). )rLdump_pyopenssl_chain)rrr<r<r=rs r)rrr)cCst|tjjS)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` )_notAfterBeforerX509Z get_notBefore)rrr<r<r= notBefore+s rcCst|tjjS)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` )rrrZ get_notAfter)rrr<r<r=notAfter7s r)rrmethodr)cCst|d}tjtj|j}WdQRX||}|s>tjd|ddd|ddd|ddd |dd d |d d d |d dg }d j|}|jd}t j |S)aPInternal 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` rtNz>Error while invoking timestamp method, None has been returned.r-T : ascii) rurrrRrxrrTr7decode pyrfc3339parse)rrrfr Z timestampZreformatted_timestampZtimestamp_bytesZ timestamp_strr<r<r=rCs    r)filenamer)c Cs:tj}t|d}|j|jjdWdQRX|jS)aNCompute 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 rzUTF-8N)hashlibsha256ruupdaterxencodeZ hexdigest)rrZfile_dr<r<r= sha256sum_s  rs@-----BEGIN CERTIFICATE----- ? .+? ? -----END CERTIFICATE----- ? ) fullchain_pemr)cCsLtj|j}t|dkr$tjd dd|D}|ddj|dd fS) aSplit 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. z/failed to parse fullchain into cert and chain: z!less than 2 certificates in chaincSs(g|] }tjtjtjtj|jqSr<)rZdump_certificaterRrr)rrr<r<r= sz1cert_and_chain_from_fullchain..rr+NzPfailed to parse fullchain into cert and chain: less than 2 certificates in chain)CERT_PEM_REGEXfindallrlenrrTr7)rcertsZcerts_normalizedr<r<r=cert_and_chain_from_fullchainzs rc Cs0t|d}tjtj|j}WdQRX|jS)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 rtN)rurrrRrxZget_serial_number)rrrr r<r<r=get_serial_from_certs r) fullchains issuer_cnwarn_on_no_matchr)cCslxR|D]J}tj|j}tj|dt}|jjtjj }|r|dj |kr|SqW|rdt j d||dS)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` rrzCertbot 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.) rrrr rwr ZissuerZget_attributes_for_oidZNameOIDZ COMMON_NAMEvaluer0Zwarning)rrrrrZtop_certZ top_issuer_cnr<r<r=find_chain_with_issuers r)r r!r"T)r r!r")FT)rbr N)F)j__doc__ZdatetimerZloggingreZtypingrrrrrrrr?Z cryptographyr Zcryptography.exceptionsr r Zcryptography.hazmat.backendsr Zcryptography.hazmat.primitivesr Z)cryptography.hazmat.primitives.asymmetricrZ-cryptography.hazmat.primitives.asymmetric.dsarZ,cryptography.hazmat.primitives.asymmetric.ecrrZ1cryptography.hazmat.primitives.asymmetric.paddingrZ-cryptography.hazmat.primitives.asymmetric.rsarZ,cryptography.hazmat.primitives.serializationrrrZjosepyZOpenSSLrrrZzope.componentrBZacmerrLZcertbotrrrZcertbot.compatrZ/cryptography.hazmat.primitives.asymmetric.ed448rZ1cryptography.hazmat.primitives.asymmetric.ed25519rZ getLogger__name__r0intr3boolr9r>rGrMrNrObytesrVrXrar.rmZ RenewableCertrsroZ HashAlgorithmrzrqrprrrRZX509Reqrrrrr^rrZComparableX509rrrrrcompileDOTALLrrrrr<r<r<r=s                               .!."0> 6  ,   "