2

I have following python code:

import subprocess
p=subprocess.Popen(["openssl","genrsa","-aes256","-out","ise.key.pem","2048"],stdin=subprocess.PIPE,stdout=subprocess.PIPE)
inputdata="123456"
p.communicate(input=inputata)
p.communicate(input=inputata)

output of above code is:

    pan@pan:~/python-scripts$ Generating RSA private key, 2048 bit long modulus
........................+++
...................................+++
e is 65537 (0x10001)
Enter pass phrase for ise.key.pem:
User interface error
140617148802712:error:0906906F:PEM routines:PEM_ASN1_write_bio:read key:pem_lib.c:379:

I want that input should be give by python there should not be any user interaction :

I know certificate can be generated by python pyOpenSSL library but I want to use normal linux command

My python version is:

Python 2.7.12 (default, Dec  4 2017, 14:50:18) 
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "enter code here`license" for more information.

I saw following link but it didn't help

Python execute command line,sending input and reading output

If you run the command in shell it runs as below:

pan@pan:~/python-scripts$ openssl genrsa -aes256 -out ise.key.pem 2048
Generating RSA private key, 2048 bit long modulus
..............................................................+++
..+++
e is 65537 (0x10001)
Enter pass phrase for ise.key.pem:
Verifying - Enter pass phrase for ise.key.pem:
  • shell=True allows to work around the wrong entering of your process: list of arguments should be `["openssl","genrsa","-aes256","-out","ise.key.pem","2048"]`. But the real issue is that piping input to a password entering routine doesn't always work. You have to generate a keyboard event at a lower level. – Jean-François Fabre May 15 '18 at 16:03
  • I suggest that you try the above, then [edit] your question to remove the useless part about shell=True which makes your question twofold. – Jean-François Fabre May 15 '18 at 16:04
  • Have you seen this? https://stackoverflow.com/a/165662/8765205 – marcel.js May 15 '18 at 18:38

2 Answers2

0

In his comment, Jean-François Fabre is right about this:

But the real issue is that piping input to a password entering routine doesn't always work.

But not about this:

You have to generate a keyboard event at a lower level.

Though it would be true in general, in the case at hand the command openssl genrsa … offers the option -passout stdin to read the password from standard input:

openssl genrsa -aes256 -out ise.key.pem -passout stdin 2048

So, this Python script works:

import subprocess
p=subprocess.Popen(["openssl","genrsa","-aes256","-out","ise.key.pem",
                    "-passout","stdin","2048"], stdin=subprocess.PIPE,
                                                stdout=subprocess.PIPE)
inputdata="123456"
p.communicate(input=inputdata)

Note that one cannot call communicate() with timeout=None more than once, since it waits for process to terminate. But it isn't necessary either, because with -passout stdin the command doesn't ask for verifying, thus no need to enter the pass phrase a second time.

Armali
  • 18,255
  • 14
  • 57
  • 171
  • How to generate a keyboard event at a lower level? I tried "openssl genrsa -aes256 -out ise.key.pem -passout stdin 2048" but it didn't work – Pankaj Sheoran May 17 '18 at 01:49
  • @Pankaj Sheoran - See the expanded answer. To _generate a keyboard event at a lower level_ would be far more cumbersome and far less portable. – Armali May 17 '18 at 06:37
0

I usually don't like subprocess for this kind of tasks ... I would prefer to use pexpect to emulate human behaviour (typing in data ... and so on).

This one is a rough example to do the job

import pexpect

def main():
        inputdata="123456"
        c = pexpect.spawn("/usr/bin/openssl", ["genrsa","-aes256","-out","ise.key.pem","2048"])
        c.expect("Enter.*:")
        c.sendline(inputdata)
        c.expect("Verifying.*:")
        c.sendline(inputdata)
        c.expect(pexpect.EOF)
        c.close()
        c.kill(0)
        print "Done"

if __name__=='__main__':
        main()