使用 stdin.write() 使用 Python 自动化 stdin [英] Automate stdin with Python using stdin.write()

查看:58
本文介绍了使用 stdin.write() 使用 Python 自动化 stdin的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to automate the setup of generating self-signed SSL certificate. This is my code:

#!/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 密码,然后返回此错误:

When I run it, it still prompts me for the PEM passphrase, then returns this error:

Country Name (2 letter code) [XX]:weird input :-(
problems making Certificate Request

它应该输入上面的密码而不提示我输入任何内容.知道出了什么问题吗?

It should feed in the passphrase above and not prompt me for anything. Any ideas what's going wrong?

附注.我知道 pexpect.请不要向我推荐它.

PS. I know about pexpect. Please don't suggest it to me.

经过进一步调查,我已经弄清楚了.如果不指定 -nodes,则私钥将被加密.因此,OpenSSL 会立即提示输入 PEM 密码.这意味着我的 stdin.write() 的顺序搞砸了.我想另一种方法是使用 -nodes 并稍后加密私钥.

Upon further investigation, I've figured it out. If you don't specify -nodes, the private key will be encrypted. So, OpenSSL will prompt for a PEM passphrase immediately. This means the order of my stdin.write() gets messed up. I guess the alternative is to use -nodes and encrypt the private key later.

推荐答案

您的代码中有几个错误,例如,没有向子进程发送换行符.

There are several errors in your code e.g., no newlines are sent to the child process.

主要问题是 openssl 需要直接来自终端的密码短语(如 Python 中的 getpass.getpass()).请参阅为什么不直接使用管道 (popen()) 中的第一个原因?:

The main issue is that openssl expects the pass phrase directly from the terminal (like getpass.getpass() in Python). See the first reason in Why not just use a pipe (popen())?:

首先,应用程序可以绕过标准输出并直接打印到它的控制TTY.SSH 之类的东西会在要求您提供时执行此操作密码.这就是您无法重定向密码提示的原因因为它不通过 stdout 或 stderr.

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 工作正常:

pexpect that provides pseudo-tty works fine in this case:

#!/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 从不同的来源(标准输入、文件、管道、环境变量、命令)获取密码短语-线).我不知道它是否适用于 openssl req 命令.

An alternative is to try to use -passin option to instruct openssl to get the pass phrase from a different source (stdin, a file, pipe, envvar, command-line). I don't know whether it works with openssl req command.

这篇关于使用 stdin.write() 使用 Python 自动化 stdin的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆