使用Python自动化stdin,使用stdin.write()

2024-06-26 00:00:38 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试自动设置生成自签名的SSL证书。这是我的代码:

#!/usr/bin/env python   
import subprocess

pass_phrase = 'example'
common_name = 'example.com'
webmaster_email = 'webmaster@example.com'

proc = subprocess.Popen(['openssl', 'req', '-x509', '-newkey', 'rsa:2048', '-rand', '/dev/urandom', '-keyout', '/etc/pki/tls/private/server.key', '-out', '/etc/pki/tls/certs/server.crt', '-days', '180'], stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)

for i in range(2):
    proc.stdin.write(pass_phrase)
for i in range(5):
    proc.stdin.write('.')
proc.stdin.write(common_name)
proc.stdin.write(webmaster_email)
proc.stdin.flush()

stdout, stderr = proc.communicate() 

当我运行它时,它仍然提示我输入PEM密码,然后返回以下错误:

^{pr2}$

它应该输入上面的密码,而不是提示我任何东西。有什么问题吗?在

另外,我知道pexpect。请不要向我建议。在

编辑:经过进一步调查,我已经弄明白了。如果不指定-nodes,私钥将被加密。因此,OpenSSL将立即提示输入PEM密码短语。这意味着我的命令标准写入()搞砸了。我想另一种选择是使用-nodes并稍后加密私钥。在


Tags: namecom密码exampleemailstdinetcpass
2条回答

您的代码中有几个错误,例如,没有新行发送到子进程。在

主要问题是openssl直接从终端获得密码短语(就像Python中的getpass.getpass())。请参见Why not just use a pipe (popen())?中的第一个原因:

First an application may bypass stdout and print directly to its controlling TTY. Something like SSH will do this when it asks you for a password. This is why you cannot redirect the password prompt because it does not go through stdout or stderr.

提供伪tty的pexpect在这种情况下可以正常工作:

#!/usr/bin/env python
import sys
from pexpect import spawn, EOF

pass_phrase = "dummy pass Phr6se"
common_name = "example.com"
email = "username@example.com"
keyname, certname = 'server.key', 'server.crt'

cmd = 'openssl req -x509 -newkey rsa:2048 -rand /dev/urandom '.split()
cmd += ['-keyout', keyname, '-out', certname, '-days', '180']

child = spawn(cmd[0], cmd[1:], timeout=10)    
child.logfile_read = sys.stdout # show openssl output for debugging

for _ in range(2):
    child.expect('pass phrase:')
    child.sendline(pass_phrase)
for _ in range(5):
    child.sendline('.')
child.sendline(common_name)
child.sendline(email)
child.expect(EOF)
child.close()
sys.exit(child.status)

另一种方法是尝试使用-passin选项来指示openssl从不同的源(stdin、文件、管道、envvar、命令行)获取密码短语。我不知道它是否与openssl req命令一起工作。在

两个问题:

  1. 你没有按照它期望的顺序给它所期望的数据。在某种程度上,它需要一个国家代码,而你却给了它一些其他的数据。在
  2. file对象的write()方法不会自动插入新行。您需要将"\n"添加到字符串中,或者在要提供给程序的每一行输入之后write()分开{}字符串。例如:proc.stdin.write(pass_phrase + "\n")

相关问题 更多 >