0

I am using Python subprocess module but the results are unexpected. I have successfully determined the correct command line strings (using another language) but cannot get a Python equivalent to work.

So I wrote some code in VBA which uses a Windows COM type library to spawn process and capture stdout, stderr. Using this I managed to write my program which generates elliptic curve keys and sign a file etc. An example command line which would run fine would be this

C:\Progra~1\OpenSSL-Win64\bin\openssl.exe ecparam -genkey -name secp384r1 -out n:\ECDSA\2017-11-30T203401\ec_key.pem

I am trying to convert the code to Python so that it runs on a linux box. I am using the same strategy in that I am spawning shells (because i have figured out all the right arguments in the VBA equivalent). I am not using a Python API like pyOpenSSL.

So I am using the subprocess module. I have never used this and am having trouble, initially I couldn't get the thing to work at all. I have managed to get something working but it looks like instead of executing the whole statement and generating a file (in the case given) it is instead dropping me into the OpenSSL prompt. That is to say it is not processing the arguments correctly. Here is my Python code

import os
import subprocess 
import sys 


class Expando(object):
    pass


def RunShellAndWait(sExe, aArgs):
    print(sExe + ' ' + ' '.join(aArgs))

    # https://stackoverflow.com/questions/4760215/running-shell-command-from-python-and-capturing-the-output#answer-4760517

    if (sys.platform[:3]=='win'):

        suinfo = subprocess.STARTUPINFO()
        suinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW

        SW_SHOWMAXIMIZED = 3
        suinfo.wShowWindow = SW_SHOWMAXIMIZED
        try:
            result = subprocess.run(args=aArgs,executable=sExe,stdin=subprocess.PIPE,stdout=subprocess.PIPE, stderr=subprocess.PIPE,startupinfo=suinfo)

        except:
            print( "something went wrong with subprocess.run \r\nexec " + sExe +  ' ' + ' '.join(aArgs))
    else:
        suinfo = None 


    retVal=Expando()
    retVal.returnCode = result.returncode
    retVal.sStdOut = result.stdout.decode('utf-8')
    retVal.sStdErr = result.stderr.decode('utf-8')
    return retVal

def OpenSSL_GenECDSAKeys(sBatchDir, sEcdsaKeyFile, sEcdsaPublicKeyDerFile,sEcdsaPublicKeyPemFile):
    if os.path.isfile(sOPENSSL_BIN)!=True:
        print("Cannot find OpenSSL.exe! " + sOPENSSL_BIN)
        return false
    if os.path.isfile(sEcdsaKeyFile)==True:
        os.removefile (sEcdsaKeyFile)

    try:
        aGenKeyArgs = [' ecparam -genkey -name secp384r1 -out ' + sEcdsaKeyFile]
        aGenKeyStatus = RunShellAndWait(sOPENSSL_BIN, aGenKeyArgs)
    ...

I concude that it is dropping into interactive mode because with stdout capture says "OpenSSL>" which is OpenSLL interactive prompt, i.e. I can just run OpenSSL.exe on its own and I get that prompt. Also the expected file is not generated.

I tried experiment with Popen but it did not like it. I am hoping someone has trodden this path before me and can point out a pitfall.

So the question is how to get OpenSSL to acknowledge and process the given arguments instead of dropping into interactive mode.

S Meaden
  • 8,050
  • 3
  • 34
  • 65
  • 1
    Pass either a string (with `shell=True`), or a list with one argument per element (otherwise) -- *not* an array with a single string that contains all your arguments space-separated. Frankly, I'm surprised this drops to a prompt rather than failing more loudly; unfortunately, as-implemented, it can't be tested on non-Windows platforms, which narrows the set of folks able to respond. (On which point, you might consider adjusting the title and tag so folks can see that without clicking through first). – Charles Duffy Dec 01 '17 at 00:23
  • @CharlesDuffy : ok, edited title and tags, will look at suggestion tomorrow. Thanks. – S Meaden Dec 01 '17 at 00:32
  • Windows always uses a command line string. The point of using an argument list is to allow `subprocess.list2cmdline` to create a command line that quotes and escapes the arguments according to Microsoft VC++ rules for parsing a command line into a C/C++ `main` `argv` list. It also facilitates writing cross-platform code. – Eryk Sun Dec 01 '17 at 00:59
  • @Charles Duffy, passing the arguments as a string looks to have worked without use `shell=true` (and I'm glad as `shell=true` is a security issue). Thanks. – S Meaden Dec 05 '17 at 18:58

0 Answers0