U
    ;gE                     @   sF  d dl mZmZmZmZ d dl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mZmZ dd	d
ddddddddddddddddgZdd	 Zdd Zdd
 Zdd Zdd Zd d Zd!d Zd"d# Zd$d Zd%d Zd&d Zd'd Zd(d Zd)d Zd*d Z d+d, Z!d-d Z"d.d Z#d/d Z$d0d Z%d1d2 Z&d3d Z'd4d5 Z(dS )6    )unicode_literalsdivisionabsolute_importprint_functionN)datetime   )Certificateint_from_bytestimezone)CIPHER_SUITE_MAP)TLSVerificationErrorTLSDisconnectErrorTLSErrordetect_client_auth_requestextract_chainget_dh_params_lengthparse_alertparse_handshake_messagesparse_session_infoparse_tls_recordsraise_client_authraise_dh_paramsraise_disconnectionraise_expired_not_yet_validraise_handshakeraise_hostnameraise_no_issuerraise_protocol_errorraise_revokedraise_self_signedraise_verificationraise_weak_signaturec                 C   s   g }d}t | D ]>\}}}|dkr$qt|D ]\}}|dkr,|} qFq,|r qPq|rd}|t|k rt|||d  }	|d }
|
|	 }|}||
| }|t| qX|S )a  
    Extracts the X.509 certificates from the server handshake bytes for use
    when debugging

    :param server_handshake_bytes:
        A byte string of the handshake data received from the server

    :return:
        A list of asn1crypto.x509.Certificate objects
    N         )r   r   lenr	   appendr   load)server_handshake_bytesoutputZchain_bytesrecord_type_record_datamessage_typemessage_datapointerZcert_lengthZ
cert_startZcert_endZ
cert_bytes r0   1/tmp/pip-unpacked-wheel-x1gypflw/oscrypto/_tls.pyr   #   s*    c                 C   sD   t | D ]6\}}}|dkrqt|D ]\}}|dkr$  dS q$qdS )a)  
    Determines if a CertificateRequest message is sent from the server asking
    the client for a certificate

    :param server_handshake_bytes:
        A byte string of the handshake data received from the server

    :return:
        A boolean - if a client certificate request was found
    r"      TF)r   r   )r(   r*   r+   r,   r-   r.   r0   r0   r1   r   K   s    c                 C   sl   d}d}t | D ]>\}}}|dkr$qt|D ]\}}|dkr,|} qFq,|r qPq|rht|dd d }|S )a  
    Determines the length of the DH params from the ServerKeyExchange

    :param server_handshake_bytes:
        A byte string of the handshake data received from the server

    :return:
        None or an integer of the bit size of the DH parameters
    Nr"      r         )r   r   r	   )r(   r)   Zdh_params_bytesr*   r+   r,   r-   r.   r0   r0   r1   r   `   s    c                 C   sV   t | D ]H\}}}|dkrqt|dkr. dS t|dd t|dd f  S dS )aV  
    Parses the handshake for protocol alerts

    :param server_handshake_bytes:
        A byte string of the handshake data received from the server

    :return:
        None or an 2-element tuple of integers:
         0: 1 (warning) or 2 (fatal)
         1: The alert description (see https://tools.ietf.org/html/rfc5246#section-7.2)
       r4   Nr   r   )r   r%   r	   )r(   r*   r+   r,   r0   r0   r1   r      s    $c                 C   sV  d}d}d}d}d}d}d}t | D ]\}	}
}|	dkr8q$t|D ]\}}|dkrRq@ddddd	d
|dd  }t|dd }|dkr|dd|  }d| }|||d  }t| }|d }|||d  dk}|d }||d }t|D ]\}}|dkrd} q
q q$q@q$t |D ]\}	}
}|	dkr2qt|D ]\}}|dkrPq:t|dd }|dkrz|dd|  }d| }t|||d  }|d | }t|||d  }|dkr
|dkr
|d | }||d }t|D ]\}}|dkrd} q
q qq:q|dk	rF|dkr2d}n||krBd}nd}|||||dS )a  
    Parse the TLS handshake from the client to the server to extract information
    including the cipher suite selected, if compression is enabled, the
    session id and if a new or reused session ticket exists.

    :param server_handshake_bytes:
        A byte string of the handshake data received from the server

    :param client_handshake_bytes:
        A byte string of the handshake data sent to the server

    :return:
        A dict with the following keys:
         - "protocol": unicode string
         - "cipher_suite": unicode string
         - "compression": boolean
         - "session_id": "new", "reused" or None
         - "session_ticket: "new", "reused" or None
    NFr"      SSLv3TLSv1zTLSv1.1zTLSv1.2zTLSv1.3)s    s   s   s   s   r   r4   "   #   r       new   Zreused)protocolcipher_suitecompression
session_idsession_ticket)r   r   r	   r   _parse_hello_extensions)r(   Zclient_handshake_bytesr?   r@   rA   rB   rC   Zserver_session_idZclient_session_idr*   r+   r,   r-   r.   Zsession_id_lengthZcipher_suite_startZcipher_suite_bytesZcompression_startZextensions_length_startZextensions_dataextension_typeZextension_dataZcipher_suite_lengthZcompression_lengthr0   r0   r1   r      s    








c                 c   s   d}t | }||k r| ||d  dkr*qt| |d |d  }| ||d  | |d |d  | |d |d |  fV  |d| 7 }qdS )a  
    Creates a generator returning tuples of information about each record
    in a byte string of data from a TLS client or server. Stops as soon as it
    find a ChangeCipherSpec message since all data from then on is encrypted.

    :param data:
        A byte string of TLS records

    :return:
        A generator that yields 3-element tuples:
        [0] Byte string of record type
        [1] Byte string of protocol version
        [2] Byte string of record data
    r   r      r$      Nr%   r	   datar/   data_lenlengthr0   r0   r1   r     s    c                 c   sh   d}t | }||k rdt| |d |d  }| ||d  | |d |d |  fV  |d| 7 }qdS )a`  
    Creates a generator returning tuples of information about each message in
    a byte string of data from a TLS handshake record

    :param data:
        A byte string of a TLS handshake record data

    :return:
        A generator that yields 2-element tuples:
        [0] Byte string of message type
        [1] Byte string of message data
    r   r      NrH   rI   r0   r0   r1   r   #  s    c                 c   s   | dkrdS t | dd }d}d| }|}||k rt | ||d  }t | |d |d  }|| |d |d |  fV  |d| 7 }q,dS )a  
    Creates a generator returning tuples of information about each extension
    from a byte string of extension data contained in a ServerHello ores
    ClientHello message

    :param data:
        A byte string of a extension data from a TLS ServerHello or ClientHello
        message

    :return:
        A generator that yields 2-element tuples:
        [0] Byte string of extension type
        [1] Byte string of extension data
        Nr   r4   rM   )r	   )rJ   Zextentions_lengthZextensions_startZextensions_endr/   rE   Zextension_lengthr0   r0   r1   rD   <  s    rD   c                 C   s   t d|p|ddk}|r(d| }nd| }d| }d| j}d| j}|r`|d| 7 }|rp|rp|d	7 }|r|d
| 7 }t|| dS )z
    Raises a TLSVerificationError due to a hostname mismatch

    :param certificate:
        An asn1crypto.x509.Certificate object

    :raises:
        TLSVerificationError
    z^\d+\.\d+\.\d+\.\d+$:zIP address %szdomain name %sz:Server certificate verification failed - %s does not matchz, z valid domains: %sz orz valid IP addresses: %sN)rematchfindjoin	valid_ipsvalid_domainsr   )certificatehostnameZis_ipZhostname_typemessagerU   rV   r0   r0   r1   r   ^  s    
c                 C   s   d}t || dS )z
    Raises a generic TLSVerificationError

    :param certificate:
        An asn1crypto.x509.Certificate object

    :raises:
        TLSVerificationError
    z&Server certificate verification failedNr   rW   rY   r0   r0   r1   r    z  s    c                 C   s   d}t || dS )z
    Raises a TLSVerificationError when a certificate uses a weak signature
    algorithm

    :param certificate:
        An asn1crypto.x509.Certificate object

    :raises:
        TLSVerificationError
    zMServer certificate verification failed - weak certificate signature algorithmNrZ   r[   r0   r0   r1   r!     s    c                  C   s   d} t | dS )zg
    Raises a TLSError indicating client authentication is required

    :raises:
        TLSError
    z5TLS handshake failed - client authentication requiredNr   )rY   r0   r0   r1   r     s    c                 C   s   d}t || dS )z
    Raises a TLSVerificationError due to the certificate being revoked

    :param certificate:
        An asn1crypto.x509.Certificate object

    :raises:
        TLSVerificationError
    zEServer certificate verification failed - certificate has been revokedNrZ   r[   r0   r0   r1   r     s    c                 C   s   d}t || dS )z
    Raises a TLSVerificationError due to no issuer certificate found in trust
    roots

    :param certificate:
        An asn1crypto.x509.Certificate object

    :raises:
        TLSVerificationError
    zgServer certificate verification failed - certificate issuer not found in trusted root certificate storeNrZ   r[   r0   r0   r1   r     s    c                 C   s   d}t || dS )z
    Raises a TLSVerificationError due to a self-signed certificate
    roots

    :param certificate:
        An asn1crypto.x509.Certificate object

    :raises:
        TLSVerificationError
    zCServer certificate verification failed - certificate is self-signedNrZ   r[   r0   r0   r1   r     s    c                 C   s   d}t || dS )z
    Raises a TLSVerificationError due to a certificate lifetime exceeding
    the CAB forum certificate lifetime limit

    :param certificate:
        An asn1crypto.x509.Certificate object

    :raises:
        TLSVerificationError
    zIServer certificate verification failed - certificate lifetime is too longNrZ   r[   r0   r0   r1   raise_lifetime_too_long  s    r]   c                 C   sp   | d d }|d j }|d j }ttj}||krH|d}d| }n||k rb|d}d| }t|| dS )	z
    Raises a TLSVerificationError due to certificate being expired, or not yet
    being valid

    :param certificate:
        An asn1crypto.x509.Certificate object

    :raises:
        TLSVerificationError
    Ztbs_certificatevalidity	not_after
not_beforez%Y-%m-%d %H:%M:%SZzGServer certificate verification failed - certificate not valid until %sz?Server certificate verification failed - certificate expired %sN)Znativer   nowr
   utcstrftimer   )rW   r^   r_   r`   ra   Zformatted_beforerY   Zformatted_afterr0   r0   r1   r     s    




c                   C   s   t ddS )ze
    Raises a TLSDisconnectError due to a disconnection

    :raises:
        TLSDisconnectError
    z$The remote end closed the connectionN)r   r0   r0   r0   r1   r      s    c                 C   s$   t | }|rtd| tddS )z
    Raises a TLSError due to a protocol error

    :param server_handshake_bytes:
        A byte string of the handshake data received from the server

    :raises:
        TLSError
    z.TLS protocol error - server responded using %sz@TLS protocol error - server responded using a different protocolN)detect_other_protocolr   )r(   Zother_protocolr0   r0   r1   r     s    c                   C   s   t ddS )zS
    Raises a TLSError due to a handshake error

    :raises:
        TLSError
    zTLS handshake failedNr\   r0   r0   r0   r1   r     s    c                   C   s   t ddS )z_
    Raises a TLSError due to a TLS version incompatibility

    :raises:
        TLSError
    z-TLS handshake failed - protocol version errorNr\   r0   r0   r0   r1   raise_protocol_version)  s    re   c                   C   s   t ddS )zP
    Raises a TLSError due to weak DH params

    :raises:
        TLSError
    z)TLS handshake failed - weak DH parametersNr\   r0   r0   r0   r1   r   4  s    c                 C   s   | dd dkrdS | dd dkr<t d| t jr8dS d	S | dd d
krPdS | dd dkrddS | dd dks| dd dkrdS dS )a  
    Looks at the server handshake bytes to try and detect a different protocol

    :param server_handshake_bytes:
        A byte string of the handshake data received from the server

    :return:
        None, or a unicode string of "ftp", "http", "imap", "pop3", "smtp"
    r   rG   s   HTTP/HTTPrM   s   220 s
   ^[^
]*ftpFTPSMTPs   220-s   +OK ZPOP3s   * OK	   s	   * PREAUTHZIMAPN)rQ   rR   I)r(   r0   r0   r1   rd   ?  s     rd   ))
__future__r   r   r   r   rQ   r   Z_asn1r   r	   r
   Z_cipher_suitesr   errorsr   r   r   __all__r   r   r   r   r   r   r   rD   r   r    r!   r   r   r   r   r]   r   r   r   r   re   r   rd   r0   r0   r0   r1   <module>   s`   (o"