U
    sĶ@g9O  ć                   @   sę   d Z ddlZddlZddlZddlZddlmZmZ ddlm	Z	m
Z
 ddlmZ edredrddlmZmZmZmZ dd	lmZmZmZmZmZ nd
ZddlmZ ddlmZ ddlmZmZm Z m!Z! dd Z"G dd deZ#dS )z-
Tests for L{twisted.conch.scripts.ckeygen}.
é    N)ŚBytesIOŚStringIO)ŚunicodeŚ_PY3)ŚrequireModuleZcryptographyZpyasn1)ŚKeyŚBadKeyErrorŚBadFingerPrintFormatŚFingerprintFormats)ŚchangePassPhraseŚdisplayPublicKeyŚprintFingerprintŚ_saveKeyŚenumrepresentationzBcryptography and pyasn1 required for twisted.conch.scripts.ckeygen)ŚFilePath)ŚTestCase)ŚpublicRSA_opensshŚprivateRSA_opensshŚprivateRSA_openssh_encryptedŚprivateECDSA_opensshc                     s   t    fdd}|S )a@  
    Return a callable to patch C{getpass.getpass}.  Yields a passphrase each
    time called. Use case is to provide an old, then new passphrase(s) as if
    requested interactively.

    @param passphrases: The list of passphrases returned, one per each call.

    @return: A callable to patch C{getpass.getpass}.
    c                    s   t  S ©N)Śnext©Ś_©Śpassphrases© śA/usr/lib/python3/dist-packages/twisted/conch/test/test_ckeygen.pyŚfakeGetpass.   s    z makeGetpass.<locals>.fakeGetpass)Śiter)r   r   r   r   r   ŚmakeGetpass"   s    
r    c                   @   s  e Zd ZdZdd Zd?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d+d, Zd-d. Zd/d0 Zd1d2 Zd3d4 Zd5d6 Zd7d8 Zd9d: Zd;d< Z d=d> Z!dS )@ŚKeyGenTestszN
    Tests for various functions used to implement the I{ckeygen} script.
    c                 C   s*   t rt | _nt | _|  td| j” dS )zX
        Patch C{sys.stdout} so tests can make assertions about what's printed.
        ŚstdoutN)r   r   r"   r   ŚpatchŚsys©Śselfr   r   r   ŚsetUp9   s    
zKeyGenTests.setUpNc              
   C   s   |   ” }|d kr(t dd|d|dg” nt dd|d|dd|g” t |”}t |d ”}|dkrt|  | ” d” n|  | ” | ” ” |  | 	” ” d S )	NŚckeygenś-tś-fz--no-passphrasez-bz.pubŚecdsaZEC)
ŚmktempŚ
subprocessŚcallr   ZfromFileŚassertEqualŚtypeŚupperZ
assertTrueZisPublic)r&   ZkeyTypeZkeySizeŚfilenameZprivKeyŚpubKeyr   r   r   Ś_testrunE   s     ’
zKeyGenTests._testrunc                 C   sF   |   dd” |   d” |   dd” |   d” |   dd” |   d” d S )Nr+   Z384ZdsaZ2048Zrsa)r4   r%   r   r   r   Śtest_keygenerationU   s    

zKeyGenTests.test_keygenerationc              
   C   sT   |   ” }|  tj”6 ttjd}tjdddd|g|d W 5 Q R X W 5 Q R X d S )NŚrbr(   r)   Zfoor*   )Śstderr)r,   ŚassertRaisesr-   ZCalledProcessErrorŚopenŚosŚdevnullZ
check_call)r&   r2   r;   r   r   r   Śtest_runBadKeytype_   s    žzKeyGenTests.test_runBadKeytypec                 C   s"   t ddi}|  |d tj” dS )z
        L{enumrepresentation} takes a dictionary as input and returns a
        dictionary with its attributes changed to enum representation.
        Śformatśmd5-hexN)r   ŚassertIsr
   ZMD5_HEX©r&   Zoptionsr   r   r   Śtest_enumrepresentationi   s    
’z#KeyGenTests.test_enumrepresentationc                 C   s"   t ddi}|  |d tj” dS )zF
        Test for format L{FingerprintFormats.SHA256-BASE64}.
        r=   śsha256-base64N)r   r?   r
   ZSHA256_BASE64r@   r   r   r   Śtest_enumrepresentationsha256s   s    
’z)KeyGenTests.test_enumrepresentationsha256c              	   C   s:   |   t”}tddi W 5 Q R X |  d|jjd ” dS )z9
        Test for unsupported fingerprint format
        r=   ś
sha-base64ś*Unsupported fingerprint format: sha-base64r   N)r8   r	   r   r/   Ś	exceptionŚargs)r&   Śemr   r   r   Ś test_enumrepresentationBadFormat}   s
    
’z,KeyGenTests.test_enumrepresentationBadFormatc                 C   s:   |   ” }t| t” t|dd |  | j ” d” dS )z¹
        L{printFingerprint} writes a line to standard out giving the number of
        bits of the key, its fingerprint, and the basename of the file from it
        was read.
        r>   ©r2   r=   z:2048 85:25:04:32:58:55:96:9f:57:ee:fb:a8:1a:ea:69:da temp
N©r,   r   Ś
setContentr   r   r/   r"   Śgetvalue©r&   r2   r   r   r   Śtest_printFingerprint   s    ’žz!KeyGenTests.test_printFingerprintc                 C   s:   |   ” }t| t” t|dd |  | j ” d” dS )z
        L{printFigerprint} will print key fingerprint in
        L{FingerprintFormats.SHA256-BASE64} format if explicitly specified.
        rB   rJ   z72048 FBTCOoknq0mHy+kpfnY9tDdcAJuWtCpuQMaV3EsvbUI= temp
NrK   rN   r   r   r   Śtest_printFingerprintsha256   s    ’žz'KeyGenTests.test_printFingerprintsha256c              	   C   sR   |   ” }t| t” |  t”}t|dd W 5 Q R X |  d|jj	d ” dS )zx
        L{printFigerprint} raises C{keys.BadFingerprintFormat} when unsupported
        formats are requested.
        rD   rJ   rE   r   N)
r,   r   rL   r   r8   r	   r   r/   rF   rG   )r&   r2   rH   r   r   r   Ś)test_printFingerprintBadFingerPrintFormat„   s    
’z5KeyGenTests.test_printFingerprintBadFingerPrintFormatc                 C   s   t |  ” }| ”  | d”j}t t”}t||ddd |  	| j
 ” d||f ” |  	| | d” ” dd”|” |  	t | d” ” ”| ” ” dS )z
        L{_saveKey} writes the private and public parts of a key to two
        different files and writes a report of this to standard out.
        Śid_rsaŚ
passphraser>   ©r2   Śpassr=   zŗYour identification has been saved in %s
Your public key has been saved in %s.pub
The key fingerprint in <FingerprintFormats=MD5_HEX> is:
85:25:04:32:58:55:96:9f:57:ee:fb:a8:1a:ea:69:da
Nś
id_rsa.pub©r   r,   ŚmakedirsŚchildŚpathr   Ś
fromStringr   r   r/   r"   rM   Ś
getContentŚpublic©r&   Śbaser2   Śkeyr   r   r   Śtest_saveKey³   s6    
’žżž  ’żžzKeyGenTests.test_saveKeyc                 C   s   t |  ” }| ”  | d”j}t t”}t||ddd |  	| j
 ” d||f ” |  	| | d” ” dd”|” |  	t | d” ” ”| ” ” dS )z³
        L{_saveKey} writes the private and public parts of a key to two
        different files and writes a report of this to standard out.
        Test with ECDSA key.
        Śid_ecdsarS   r>   rT   zŗYour identification has been saved in %s
Your public key has been saved in %s.pub
The key fingerprint in <FingerprintFormats=MD5_HEX> is:
1e:ab:83:a6:f2:04:22:99:7c:64:14:d2:ab:fa:f5:16
Nzid_ecdsa.pub)r   r,   rX   rY   rZ   r   r[   r   r   r/   r"   rM   r\   r]   r^   r   r   r   Śtest_saveKeyECDSAĻ   s6    
’žżž  ’żžzKeyGenTests.test_saveKeyECDSAc                 C   s   t |  ” }| ”  | d”j}t t”}t||ddd |  	| j
 ” d||f ” |  	| | d” ” dd”|” |  	t | d” ” ”| ” ” dS )z
        L{_saveKey} will generate key fingerprint in
        L{FingerprintFormats.SHA256-BASE64} format if explicitly specified.
        rR   rS   rB   rT   z½Your identification has been saved in %s
Your public key has been saved in %s.pub
The key fingerprint in <FingerprintFormats=SHA256_BASE64> is:
FBTCOoknq0mHy+kpfnY9tDdcAJuWtCpuQMaV3EsvbUI=
NrV   rW   r^   r   r   r   Śtest_saveKeysha256ģ   s6    
’žżž  ’żžzKeyGenTests.test_saveKeysha256c              	   C   sj   t |  ” }| ”  | d”j}t t”}|  t	”}t
||ddd W 5 Q R X |  d|jjd ” dS )zq
        L{_saveKey} raises C{keys.BadFingerprintFormat} when unsupported
        formats are requested.
        rR   rS   rD   rT   rE   r   N)r   r,   rX   rY   rZ   r   r[   r   r8   r	   r   r/   rF   rG   )r&   r_   r2   r`   rH   r   r   r   Ś test_saveKeyBadFingerPrintformat  s    
’
’z,KeyGenTests.test_saveKeyBadFingerPrintformatc                 C   s`   t |  ” }| ”  | d”j}t t”}t||ddd |  	| | d” 
” dd”|” dS )śq
        L{_saveKey} will choose an empty string for the passphrase if
        no-passphrase is C{True}.
        rR   Tr>   ©r2   zno-passphraser=   Nó    )r   r,   rX   rY   rZ   r   r[   r   r   r/   r\   r^   r   r   r   Śtest_saveKeyEmptyPassphrase  s    
’  ’żz'KeyGenTests.test_saveKeyEmptyPassphrasec                 C   s^   t |  ” }| ”  | d”j}t t”}t||ddd |  	| | d” 
” d”|” dS )rf   rb   Tr>   rg   N)r   r,   rX   rY   rZ   r   r[   r   r   r/   r\   r^   r   r   r   Ś test_saveKeyECDSAEmptyPassphrase)  s    
’ ’żz,KeyGenTests.test_saveKeyECDSAEmptyPassphrasec                    s   t |  ” }| ”  | d”j ddl}|  |jjj	d fdd” t
 t”}t|dddd	 | d” ” }| |dd
”}|  ||” dS )zd
        When no path is specified, it will ask for the path used to store the
        key.
        Z
custom_keyr   NZ	raw_inputc                    s    S r   r   r   ©ZkeyPathr   r   Ś<lambda>E  rh   z4KeyGenTests.test_saveKeyNoFilename.<locals>.<lambda>Tr>   rg   rh   )r   r,   rX   rY   rZ   Śtwisted.conch.scripts.ckeygenr#   ZconchZscriptsr(   r   r[   r   r   r\   r/   )r&   r_   Ztwistedr`   ZpersistedKeyContentZpersistedKeyr   rk   r   Śtest_saveKeyNoFilename;  s    
’z"KeyGenTests.test_saveKeyNoFilenamec                 C   sf   |   ” }t t”}t| t” td|i | j 	”  
d”}t|trP| d”}|  || d”” dS )zl
        L{displayPublicKey} prints out the public key associated with a given
        private key.
        r2   Ś
ŚasciiŚopensshN)r,   r   r[   r   r   rL   r   r   r"   rM   ŚstripŚ
isinstancer   Śencoder/   ŚtoString©r&   r2   r3   Z	displayedr   r   r   Śtest_displayPublicKeyO  s    


žz!KeyGenTests.test_displayPublicKeyc                 C   sh   |   ” }t t”}t| t” t|dd | j 	”  
d”}t|trR| d”}|  || d”” dS )z
        L{displayPublicKey} prints out the public key associated with a given
        private key using the given passphrase when it's encrypted.
        Ś	encrypted©r2   rU   ro   rp   rq   N)r,   r   r[   r   r   rL   r   r   r"   rM   rr   rs   r   rt   r/   ru   rv   r   r   r   Śtest_displayPublicKeyEncrypted`  s    


žz*KeyGenTests.test_displayPublicKeyEncryptedc                 C   sx   |   ” }t t”}t| t” |  tddd ” t	d|i | j
 ”  d”}t|trb| d”}|  || d”” dS )	z
        L{displayPublicKey} prints out the public key associated with a given
        private key, asking for the passphrase when it's encrypted.
        Śgetpassc                 S   s   dS )Nrx   r   )Śxr   r   r   rl   y  rh   zLKeyGenTests.test_displayPublicKeyEncryptedPassphrasePrompt.<locals>.<lambda>r2   ro   rp   rq   N)r,   r   r[   r   r   rL   r   r#   r{   r   r"   rM   rr   rs   r   rt   r/   ru   rv   r   r   r   Ś.test_displayPublicKeyEncryptedPassphrasePromptq  s    


žz:KeyGenTests.test_displayPublicKeyEncryptedPassphrasePromptc                 C   s.   |   ” }t| t” |  tt|dd” dS )z
        L{displayPublicKey} fails with a L{BadKeyError} when trying to decrypt
        an encrypted key with the wrong password.
        Śwrongry   N)r,   r   rL   r   r8   r   r   rN   r   r   r   Ś$test_displayPublicKeyWrongPassphrase  s     žz0KeyGenTests.test_displayPublicKeyWrongPassphrasec                 C   sl   t ddd}|  td|” |  ” }t| t” td|i |  | j	 
”  d”d” |  tt| ” ” dS )zt
        L{changePassPhrase} allows a user to change the passphrase of a
        private key interactively.
        rx   Śnewpassr{   r2   ro   ś;Your identification has been saved with the new passphrase.N©r    r#   r{   r,   r   rL   r   r   r/   r"   rM   rr   ŚassertNotEqualr\   )r&   ZoldNewConfirmr2   r   r   r   Śtest_changePassphrase  s    ž
’z!KeyGenTests.test_changePassphrasec                 C   sl   t dd}|  td|” |  ” }t| t” t|dd |  | j	 
”  d”d” |  tt| ” ” dS )z
        L{changePassPhrase} allows a user to change the passphrase of a
        private key, providing the old passphrase and prompting for new one.
        r   r{   rx   ry   ro   r   Nr   )r&   Z
newConfirmr2   r   r   r   Śtest_changePassphraseWithOld¢  s    
ž
’z(KeyGenTests.test_changePassphraseWithOldc                 C   sV   |   ” }t| t” t|ddd |  | j ”  d”d” |  	tt| 
” ” dS )z¢
        L{changePassPhrase} allows a user to change the passphrase of a private
        key by providing both old and new passphrases without prompting.
        rx   Ś
newencrypt)r2   rU   r   ro   r   N)r,   r   rL   r   r   r/   r"   rM   rr   r   r\   rN   r   r   r   Śtest_changePassphraseWithBothµ  s    ’’ž
’z)KeyGenTests.test_changePassphraseWithBothc                 C   sR   |   ” }t| t” |  tt|dd”}|  dt|” |  tt| 	” ” dS )z
        L{changePassPhrase} exits if passed an invalid old passphrase when
        trying to change the passphrase of a private key.
        r~   ry   z1Could not change passphrase: old passphrase errorN)
r,   r   rL   r   r8   Ś
SystemExitr   r/   Śstrr\   ©r&   r2   Śerrorr   r   r   Ś$test_changePassphraseWrongPassphraseĒ  s     ž’
’z0KeyGenTests.test_changePassphraseWrongPassphrasec                 C   sb   |   tdtd” |  ” }t| t” |  tt	d|i”}|  
dt|” |  
tt| ” ” dS )z
        L{changePassPhrase} exits if no passphrase is specified for the
        C{getpass} call and the key is encrypted.
        r{   Ś r2   zMCould not change passphrase: Passphrase must be provided for an encrypted keyN)r#   r{   r    r,   r   rL   r   r8   r   r   r/   r   r\   r   r   r   r   Ś!test_changePassphraseEmptyGetPass×  s      ’ż
’z-KeyGenTests.test_changePassphraseEmptyGetPassc                 C   s^   |   ” }t| d” |  ttd|i”}tr2d}nd}|  |t|” |  dt| 	” ” dS )zc
        L{changePassPhrase} exits if the file specified points to an invalid
        key.
        s   foobarr2   z?Could not change passphrase: cannot guess the type of b'foobar'z>Could not change passphrase: cannot guess the type of 'foobar'N)
r,   r   rL   r8   r   r   r   r/   r   r\   )r&   r2   r   Śexpectedr   r   r   Śtest_changePassphraseBadKeyé  s      ’z'KeyGenTests.test_changePassphraseBadKeyc                 C   sh   |   ” }t| t” dd }|  td|” |  tt|dd”}|  	dt
|” |  	tt| ” ” dS )z
        L{changePassPhrase} doesn't modify the key file if an unexpected error
        happens when trying to create the key with the new passphrase.
        c                  _   s   t dd S )NZoops)ŚRuntimeError©rG   Śkwargsr   r   r   ru     s    z>KeyGenTests.test_changePassphraseCreateError.<locals>.toStringru   r   ©r2   r   z!Could not change passphrase: oopsN)r,   r   rL   r   r#   r   r8   r   r   r/   r   r\   )r&   r2   ru   r   r   r   r   Ś test_changePassphraseCreateErrorū  s      ’ž ’z,KeyGenTests.test_changePassphraseCreateErrorc                 C   sv   |   ” }t| t” dd }|  td|” |  tt|dd”}t	rJd}nd}|  
|t|” |  
tt| ” ” dS )	zq
        L{changePassPhrase} doesn't modify the key file if C{toString} returns
        an empty string.
        c                  _   s   dS )Nr   r   r   r   r   r   ru     s    zCKeyGenTests.test_changePassphraseEmptyStringError.<locals>.toStringru   r   r   z9Could not change passphrase: cannot guess the type of b''z8Could not change passphrase: cannot guess the type of ''N)r,   r   rL   r   r#   r   r8   r   r   r   r/   r   r\   )r&   r2   ru   r   r   r   r   r   Ś%test_changePassphraseEmptyStringError  s      ž’’z1KeyGenTests.test_changePassphraseEmptyStringErrorc                 C   sR   |   ” }t| t” |  tt|dd”}|  dt|” |  tt| 	” ” dS )z
        L{changePassPhrase} exits when trying to change the passphrase on a
        public key, and doesn't change the file.
        rU   r   z.Could not change passphrase: key not encryptedN)
r,   r   rL   r   r8   r   r   r/   r   r\   r   r   r   r   Śtest_changePassphrasePublicKey/  s     ž ’z*KeyGenTests.test_changePassphrasePublicKey)N)"Ś__name__Ś
__module__Ś__qualname__Ś__doc__r'   r4   r5   r<   rA   rC   rI   rO   rP   rQ   ra   rc   rd   re   ri   rj   rn   rw   rz   r}   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r!   5   s>   




r!   )$r   r{   r$   r:   r-   Śior   r   Ztwisted.python.compatr   r   Ztwisted.python.reflectr   Ztwisted.conch.ssh.keysr   r   r	   r
   rm   r   r   r   r   r   ŚskipZtwisted.python.filepathr   Ztwisted.trial.unittestr   Ztwisted.conch.test.keydatar   r   r   r   r    r!   r   r   r   r   Ś<module>   s    