我正在尝试自动生成自签名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密码,然后返回此错误:
Country Name (2 letter code) [XX]:weird input :-(
problems making Certificate Request
它应该输入上面的密码而不是提示我做任何事情。任何想法出了什么问题?
PS。我知道pexpect。请不要向我提出建议。
编辑:经过进一步调查,我已经弄明白了。如果您没有指定-nodes,私钥将被加密。因此,OpenSSL将立即提示输入PEM密码。这意味着我的stdin.write()的顺序搞砸了。我想替代方法是使用-nodes并稍后加密私钥。
答案 0 :(得分:3)
您的代码中存在多个错误,例如,没有新行发送到子进程。
主要问题是openssl
期望直接来自终端的密码短语(如Python中的getpass.getpass()
)。请参阅Why not just use a pipe (popen())?中的第一个原因:
提供伪tty的首先,应用程序可以绕过stdout并直接打印到它 控制TTY。像SSH这样的东西会在它要求时执行此操作 密码这就是您无法重定向密码提示的原因 因为它不通过stdout或stderr。
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 :(得分:1)
两个问题:
write()
方法不会自动插入换行符。您需要在字符串中添加"\n"
或在要输入程序的每行输入后将write()
单独的"\n"
字符串添加出来。例如:proc.stdin.write(pass_phrase + "\n")