使用stdin.write()使用Python自动化stdin
我正在尝试自动设置生成自签名SSL证书。这是我的代码:使用stdin.write()使用Python自动化stdin,python,subprocess,Python,Subprocess,我正在尝试自动设置生成自签名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',
#!/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密码短语,然后返回此错误:
Country Name (2 letter code) [XX]:weird input :-(
problems making Certificate Request
它应该输入上面的密码短语,而不是提示我什么。你知道怎么回事吗
另外,我知道pexpect。请不要向我建议
编辑:经过进一步调查,我已经找到了答案。如果不指定-节点,则私钥将被加密。因此,OpenSSL将立即提示输入PEM密码短语。这意味着stdin.write()的顺序被打乱了。我想另一种选择是使用-节点,然后加密私钥 两个问题:
write()
方法不会自动插入换行符。您需要在字符串中添加“\n”
,或者在要输入到程序的每行输入之后将“\n”
字符串分开。例如:proc.stdin.write(传递短语+“\n”)
write()
方法不会自动插入换行符。您需要在字符串中添加“\n”
,或者在要输入到程序的每行输入之后将“\n”
字符串分开。例如:proc.stdin.write(传递短语+“\n”)
代码中存在多个错误,例如,没有向子进程发送换行符 主要问题是
openssl
希望密码短语直接来自终端(如Python中的getpass.getpass()
)。请参阅中的第一个原因:
首先,应用程序可以绕过标准输出并直接打印到其
控制TTY。SSH之类的东西会在它请求您时这样做
密码。这就是为什么不能重定向密码提示
因为它不经过stdout或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
命令。您的代码中有几个错误,例如,没有向子进程发送换行符
主要问题是openssl
希望密码短语直接来自终端(如Python中的getpass.getpass()
)。请参阅中的第一个原因:
首先,应用程序可以绕过标准输出并直接打印到其
控制TTY。SSH之类的东西会在它请求您时这样做
密码。这就是为什么不能重定向密码提示
因为它不经过stdout或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
命令。它看起来像是在寻找一个国家名称,但你没有给它一个。为什么:“我知道。请不要向我建议。”?因为根据我在stackoverflow上的经验,用户倾向于用一般性的回答来回答,希望它能为他们赢得分数,而不是试图真诚地回答问题。它看起来像是在寻找一个国家名称,但你没有给它一个。为什么:“我知道。请不要向我提建议。”?因为从我在stackoverflow的经历来看,用户倾向于用一般性的回答来回答,希望它能为他们赢得分数,而不是试图真诚地回答问题。OpenSSL行为怪异,在允许stdin.write()运行之前,会提示输入PEM密码,从而导致stdin.write()的顺序可能会弄乱。@PythonNoob它可能会直接打开控制PTY。OpenSSL行为怪异,在允许stdin.write()运行之前会提示输入PEM密码短语,从而导致stdin.write()的顺序被弄乱。@PythonNoob它可能会直接打开控制PTY。谢谢您的帮助。我试图避免使用pexpect,因为它不随股票Python提供。如果您不想让用户安装它,您可以将它与您的代码放在一起(不推荐)separately@PythonNoob如果你不想使用pexpect,你必须重新设计它的一部分。谢谢你的帮助。我试图避免使用pexpect,因为它不随股票Python提供。如果您不想让用户安装它,您可以将它与您的代码放在一起(不推荐)separately@PythonNoob如果你不想使用pexpect,你必须重新设计它的一部分。