o
    ]A                     @   s   d Z ddlZddlZddlZddlZddlZddlZddlZddl	Zddl
ZddlZddlZddlmZmZmZ ddlmZ dZdZdZdZd	Zd
ZejjddddddZejjdZejjddZG dd deZG dd de Z!G dd de!Z"dS )ag
  
Parsing for `Tor Ed25519 certificates
<https://gitweb.torproject.org/torspec.git/tree/cert-spec.txt>`_, which are
used to for a variety of purposes...

  * validating the key used to sign server descriptors
  * validating the key used to sign hidden service v3 descriptors
  * signing and encrypting hidden service v3 indroductory points

.. versionadded:: 1.6.0

**Module Overview:**

::

  Ed25519Certificate - Ed25519 signing key certificate
    | +- Ed25519CertificateV1 - version 1 Ed25519 certificate
    |      |- is_expired - checks if certificate is presently expired
    |      |- signing_key - certificate signing key
    |      +- validate - validates a descriptor's signature
    |
    |- from_base64 - decodes a base64 encoded certificate
    |- to_base64 - base64 encoding of this certificate
    |
    |- unpack - decodes a byte encoded certificate
    +- pack - byte encoding of this certificate

  Ed25519Extension - extension included within an Ed25519Certificate

.. data:: CertType (enum)

  Purpose of Ed25519 certificate. For more information see...

    * `cert-spec.txt <https://gitweb.torproject.org/torspec.git/tree/cert-spec.txt>`_ section A.1
    * `rend-spec-v3.txt <https://gitweb.torproject.org/torspec.git/tree/rend-spec-v3.txt>`_ appendix E

  .. deprecated:: 1.8.0
     Replaced with :data:`stem.client.datatype.CertType`

  ========================  ===========
  CertType                  Description
  ========================  ===========
  **SIGNING**               signing key with an identity key
  **LINK_CERT**             TLS link certificate signed with ed25519 signing key
  **AUTH**                  authentication key signed with ed25519 signing key
  **HS_V3_DESC_SIGNING**    hidden service v3 short-term descriptor signing key
  **HS_V3_INTRO_AUTH**      hidden service v3 introductory point authentication key
  **HS_V3_INTRO_ENCRYPT**   hidden service v3 introductory point encryption key
  ========================  ===========

.. data:: ExtensionType (enum)

  Recognized exception types.

  ====================  ===========
  ExtensionType         Description
  ====================  ===========
  **HAS_SIGNING_KEY**   includes key used to sign the certificate
  ====================  ===========

.. data:: ExtensionFlag (enum)

  Flags that can be assigned to Ed25519 certificate extensions.

  ======================  ===========
  ExtensionFlag           Description
  ======================  ===========
  **AFFECTS_VALIDATION**  extension affects whether the certificate is valid
  **UNKNOWN**             extension includes flags not yet recognized by stem
  ======================  ===========
    N)FieldSizesplit)CertType    (   @   s"   Tor router descriptor signature v1s#   Tor onion service descriptor sig v36   ZSIGNINGZ	LINK_CERTZAUTHZHS_V3_DESC_SIGNINGZHS_V3_INTRO_AUTHZHS_V3_INTRO_ENCRYPT)HAS_SIGNING_KEY   AFFECTS_VALIDATIONUNKNOWNc                   @   s4   e Zd ZdZdd Zdd Zedd Zdd	 Zd
S )Ed25519Extensiona  
  Extension within an Ed25519 certificate.

  :var stem.descriptor.certificate.ExtensionType type: extension type
  :var list flags: extension attribute flags
  :var int flag_int: integer encoding of the extension attribute flags
  :var bytes data: data the extension concerns
  c                 C   s   || _ g | _|r
|nd| _|| _|r#|d dkr#| jtj |d8 }|r,| jtj |tj	kr?t
|dkrAtdt
| d S d S )Nr         r   z?Ed25519 HAS_SIGNING_KEY extension must be 32 bytes, but was %i.)typeflagsflag_intdataappendExtensionFlagr   r   ExtensionTyper
   len
ValueError)selfext_typeZflag_valr    r   =/usr/lib/python3/dist-packages/stem/descriptor/certificate.py__init__   s   zEd25519Extension.__init__c                 C   sR   t  }|tjt| j7 }|tj| j7 }|tj| j7 }|| j7 }t	|S N)
	bytearrayr   SHORTpackr   r   CHARr   r   bytes)r   encodedr   r   r   r"      s   
zEd25519Extension.packc                 C   s   t | dk r
tdtj| \}} tj| \}} tj| \}} t| |\}} t ||kr9td|t |f t|||| fS )Nr   z*Ed25519 extension is missing header fieldszTEd25519 extension is truncated. It should have %i bytes of data but there's only %i.)r   r   r   r!   popr#   r   r   )content	data_sizer   r   r   r   r   r   r&      s   zEd25519Extension.popc                 C   s   t jj| dddddS )Nr   r   r   T)cache)stemutilZ
_hash_attrr   r   r   r   __hash__   s   zEd25519Extension.__hash__N)	__name__
__module____qualname____doc__r   r"   staticmethodr&   r-   r   r   r   r   r   v   s    	
r   c                   @   sb   e Zd ZdZdd Zedd Zedd Zdd	 ZdddZ	edd Z
dd Zedd ZdS )Ed25519Certificatez
  Base class for an Ed25519 certificate.

  :var int version: certificate format version
  :var unicode encoded: base64 encoded ed25519 certificate
  c                 C   s   || _ d | _d S r   )versionr%   )r   r4   r   r   r   r      s   
zEd25519Certificate.__init__c                 C   s.   t j| d }|dkrt| S td| )a  
    Parses a byte encoded ED25519 certificate.

    :param bytes content: encoded certificate

    :returns: :class:`~stem.descriptor.certificate.Ed25519Certificate` subclsss
      for the given certificate

    :raises: **ValueError** if certificate is malformed
    r   r   zLEd25519 certificate is version %i. Parser presently only supports version 1.)r   r#   r&   Ed25519CertificateV1unpackr   )r'   r4   r   r   r   r6      s   
zEd25519Certificate.unpackc              
   C   s   t jj| } | dr| dr| dd } zt| }|s#tdt	
|}| |_|W S  ttjfyD } ztd|| f d}~ww )a  
    Parses a base64 encoded ED25519 certificate.

    :param str content: base64 encoded certificate

    :returns: :class:`~stem.descriptor.certificate.Ed25519Certificate` subclsss
      for the given certificate

    :raises: **ValueError** if content is malformed
    z-----BEGIN ED25519 CERT-----
z
-----END ED25519 CERT-----   iemptyz<Ed25519 certificate wasn't propoerly base64 encoded (%s):
%sN)r*   r+   	str_tools_to_unicode
startswithendswithbase64	b64decode	TypeErrorr3   r6   r%   binasciiErrorr   )r'   Zdecodedinstanceexcr   r   r   from_base64   s   

zEd25519Certificate.from_base64c                 C   s   t dt| j )z}
    Encoded byte representation of our certificate.

    :returns: **bytes** for our encoded certificate representation
    z4Certificate encoding has not been implemented for %s)NotImplementedErrorr   r.   r,   r   r   r   r"      s   zEd25519Certificate.packFc                 C   s:   d tjjt|  d}|rd| }tjj|S )a1  
    Base64 encoded certificate data.

    :param bool pem: include `PEM header/footer
      <https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail>`_, for more
      information see `RFC 7468 <https://tools.ietf.org/html/rfc7468>`_

    :returns: **unicode** for our encoded certificate representation
       
r   s:   -----BEGIN ED25519 CERT-----
%s
-----END ED25519 CERT-----)	joinr*   r+   r9   Z_split_by_lengthr=   Z	b64encoder"   r:   )r   pemr%   r   r   r   	to_base64   s    zEd25519Certificate.to_base64c                    s    fdd}|S )Nc                    sD   | d \}}}|r|dkrt d|f t|  t| d S )Nr   zED25519 CERTz='%s' should be followed by a ED25519 CERT block, but was a %s)r   setattrr3   rD   )
descriptorentriesvalueZ
block_typeZblock_contents	attributekeywordr   r   _parse  s   z3Ed25519Certificate._from_descriptor.<locals>._parser   )rP   rO   rQ   r   rN   r   _from_descriptor  s   z#Ed25519Certificate._from_descriptorc                 C   s   | j ddS )NT)rH   )rI   r,   r   r   r   __str__  s   zEd25519Certificate.__str__c                 C   s
   t | S r   )r3   rD   )r'   r   r   r   parse  s   
zEd25519Certificate.parseN)F)r.   r/   r0   r1   r   r2   r6   rD   r"   rI   rR   rS   rT   r   r   r   r   r3      s    


	
r3   c                       sb   e Zd ZdZd fdd	Zdd Zedd Zd	d
 Zdd Z	dd Z
edd Zdd Z  ZS )r5   a  
  Version 1 Ed25519 certificate, which are used for signing tor server
  descriptors.

  :var stem.client.datatype.CertType type: certificate purpose
  :var int type_int: integer value of the certificate purpose
  :var datetime expiration: expiration of the certificate
  :var int key_type: format of the key
  :var bytes key: key content
  :var list extensions: :class:`~stem.descriptor.certificate.Ed25519Extension` in this certificate
  :var bytes signature: certificate signature

  :param bytes signature: pre-calculated certificate signature
  :param cryptography.hazmat.primitives.asymmetric.ed25519.Ed25519PrivateKey signing_key: certificate signing key
  Nc           	         s"  t t| d |d u rtd|d u rtdt|\| _| _|r%|n
tj	 tj
td | _|r5|nd| _tj|| _|rC|ng | _|| _|rf||  }| jrc| j|krctd|| jf || _| jtjtjtjfv rxtd| j | jtjkrtd| jtjkrtd| j d S )	Nr   zCertificate type is requiredzCertificate key is required)Zhoursz6Signature calculated from its key (%s) mismatches '%s'zOEd25519 certificate cannot have a type of %i. This is reserved for CERTS cells.zcEd25519 certificate cannot have a type of 7. This is reserved for RSA identity cross-certification.z+Ed25519 certificate type %i is unrecognized)superr5   r   r   ClientCertTypegetr   type_intdatetimeZutcnowZ	timedeltaDEFAULT_EXPIRATION_HOURS
expirationkey_typer*   r+   Z_pubkey_byteskey
extensions	signaturesignr"   ZLINKZIDENTITYZAUTHENTICATEZED25519_IDENTITYr   )	r   	cert_typer[   r\   r]   r^   r_   signing_keyZcalculated_sig	__class__r   r   r   )  s.    zEd25519CertificateV1.__init__c                 C   s   t  }|tj| j7 }|tj| j7 }|tjttj	
| jd 7 }|tj| j7 }|| j7 }|tjt| j7 }| jD ]}|| 7 }qB| jrS|| j7 }t|S )N  )r    r   r#   r"   r4   rX   LONGintr*   r+   Zdatetime_to_unixr[   r\   r]   r   r^   r_   r$   )r   r%   	extensionr   r   r   r"   I  s   "


zEd25519CertificateV1.packc                 C   s  t | tt k rtdt | tt f t| t | t \}}tj|\}}tj|\}}tj|\}}tj|\}}t|t	\}}tj|\}}	|dkrXtd| g }
t
|D ]}t|	\}}	|
| q^|	rwtdt |	 t|tj|d |||
|S )Nz;Ed25519 certificate was %i bytes, but should be at least %ir   z5Ed25519 v1 parser cannot read version %i certificatesz9Ed25519 certificate had %i bytes of unused extension datare   )r   ED25519_HEADER_LENGTHED25519_SIGNATURE_LENGTHr   r   r   r#   r&   rf   ED25519_KEY_LENGTHranger   r   r5   rY   Zutcfromtimestamp)r'   headerr_   r4   ra   Zexpiration_hoursr\   r]   Zextension_countZextension_datar^   irh   r   r   r   r6   Z  s$   zEd25519CertificateV1.unpackc                 C   s   t j  | jkS )z
    Checks if this certificate is presently expired or not.

    :returns: **True** if the certificate has expired, **False** otherwise
    )rY   Znowr[   r,   r   r   r   
is_expiredv  s   zEd25519CertificateV1.is_expiredc                 C   s&   | j D ]}|jtjkr|j  S qdS )z
    Provides this certificate's signing key.

    .. versionadded:: 1.8.0

    :returns: **bytes** with the first signing key on the certificate, None if
      not present
    N)r^   r   r   r
   r   )r   rh   r   r   r   rb     s
   


z Ed25519CertificateV1.signing_keyc                 C   s   t jjddstdt|t jjjr+t	t
| }t jj|j}| | nt|t jjjrAt
|}t jj|j}n	tdt|j ddlm} ddlm} z|| j}||| W d	S  |yp   tdw )
a)  
    Validate our descriptor content matches its ed25519 signature. Supported
    descriptor types include...

      * :class:`~stem.descriptor.server_descriptor.RelayDescriptor`
      * :class:`~stem.descriptor.hidden_service.HiddenServiceDescriptorV3`

    :param stem.descriptor.__init__.Descriptor descriptor: descriptor to validate

    :raises:
      * **ValueError** if signing key or descriptor are invalid
      * **TypeError** if descriptor type is unsupported
      * **ImportError** if cryptography module or ed25519 support unavailable
    T)Zed25519zKCertificate validation requires the cryptography module and ed25519 supportzWCertificate validation only supported for server and hidden service descriptors, not %sr   Ed25519PublicKeyInvalidSignaturezNDescriptor Ed25519 certificate signature invalid (signature forged or corrupt)N) r*   ZprereqZis_crypto_availableImportError
isinstancerK   server_descriptorRelayDescriptorhashlibZsha256r5   _signed_contentZdigestr+   r9   Z_decode_b64Zed25519_signature!_validate_server_desc_signing_keyhidden_serviceHiddenServiceDescriptorV3r_   r?   r   r.   1cryptography.hazmat.primitives.asymmetric.ed25519rq   cryptography.exceptionsrs   from_public_bytesr]   verifyr   )r   rK   Zsigned_contentr_   rq   rs   r]   r   r   r   validate  s$   
zEd25519CertificateV1.validatec                 C   st   t | tjjjrt}d}nt | tjjjrt}d}n	t	dt
| j t||  tj}|s3t	d||d S )zu
    Provides this descriptor's signing constant, appended with the portion of
    the descriptor that's signed.
    s   (.+router-sig-ed25519 )s   (.+)signature zBUG: %s type unexpectedz+Malformed descriptor missing signature liner   )ru   r*   rK   rv   rw   SIG_PREFIX_SERVER_DESCr{   r|   SIG_PREFIX_HS_V3r   r   r.   researchZ	get_bytesDOTALLgroup)rK   prefixZregexmatchr   r   r   ry     s   z$Ed25519CertificateV1._signed_contentc                 C   s   ddl m} ddlm} |jrttjj	
|jd }n|  }|s'tdz||}|| jttjj	
| jd t   W d S  |yO   tdw )Nr   rp   rr      =z0Server descriptor missing an ed25519 signing keyzJEd25519KeyCertificate signing key is invalid (signature forged or corrupt))r}   rq   r~   rs   Zed25519_master_keyr=   r>   r*   r+   r9   Z	_to_bytesrb   r   r   r   r_   r%   rj   )r   rK   rq   rs   rb   r]   r   r   r   rz     s   
0z6Ed25519CertificateV1._validate_server_desc_signing_key)NNNNNNN)r.   r/   r0   r1   r   r"   r2   r6   ro   rb   r   ry   rz   __classcell__r   r   rc   r   r5     s     
	'
r5   )#r1   r=   r@   rY   rx   r   Zstem.descriptor.hidden_servicer*   Z!stem.descriptor.server_descriptorZstem.prereqZ	stem.utilZstem.util.enumZstem.util.str_toolsZstem.client.datatyper   r   r   r   rV   rk   ri   rj   r   r   rZ   r+   enumZUppercaseEnumEnumr   r   r   objectr3   r5   r   r   r   r   <module>   sB   H	5m