def run(pgmname, argv): global debug # Determine system character encodings. try: # getdefaultlocale() may sometimes return None. # Fall back to ASCII encoding in that case. terminalenc = locale.getdefaultlocale()[1] + "" except TypeError: # Invalid locale, fall back to ASCII terminal encoding. terminalenc = "ascii" try: # sys.getfilesystemencoding() was introduced in Python v2.3 and # it can sometimes return None. Fall back to ASCII if something # goes wrong. filesystemenc = sys.getfilesystemencoding() + "" except (AttributeError, TypeError): filesystemenc = "ascii" try: gopt = getopt.gnu_getopt except: # Python <v2.3, GNU-style parameter ordering not supported. gopt = getopt.getopt # Parse command line arguments. short_opts = "a:k:p:e:vh" long_opts = [ "cert=", "privkey=", "passphrase=", "encoding=", "verbose", "debug", "help" ] args = gopt(argv, short_opts, long_opts) opts = dict(args[0]) pargs = args[1] if len(pargs) < 2: raise ValueError("wrong number of arguments") # Override character encoding of command line and filesystem. encs = opts.get("--encoding", opts.get("-e", "%s,%s" % (terminalenc, filesystemenc))) try: terminalenc, filesystemenc = encs.split(",") except (ValueError, TypeError): raise ValueError("invalid encoding string '%s'" % encs) # Get input SIS file names. infiles = [f.decode(terminalenc).encode(filesystemenc) for f in pargs[:-1]] # Determine output SIS file name. outfile = pargs[-1].decode(terminalenc).encode(filesystemenc) if os.path.isdir(outfile): # Output to directory, use input file name. outfile = os.path.join(outfile, os.path.basename(infiles[0])) # Get certificate and its private key file names. cert = opts.get("--cert", opts.get("-a", None)) privkey = opts.get("--privkey", opts.get("-k", None)) if cert != None and privkey != None: # Convert file names from terminal encoding to filesystem encoding. cert = cert.decode(terminalenc).encode(filesystemenc) privkey = privkey.decode(terminalenc).encode(filesystemenc) # Read certificate file. f = file(cert, "rb") certdata = f.read(MAXCERTIFICATELENGTH + 1) f.close() if len(certdata) > MAXCERTIFICATELENGTH: raise ValueError("certificate file too large") # Read private key file. f = file(privkey, "rb") privkeydata = f.read(MAXPRIVATEKEYLENGTH + 1) f.close() if len(privkeydata) > MAXPRIVATEKEYLENGTH: raise ValueError("private key file too large") elif cert == None and privkey == None: # No certificate given, use the Ensymble default certificate. # defaultcert.py is not imported when not needed. This speeds # up program start-up a little. from utils import defaultcert certdata = defaultcert.cert privkeydata = defaultcert.privkey print( "%s: warning: no certificate given, using " "insecure built-in one" % pgmname) else: raise ValueError("missing certificate or private key") # Get pass phrase. Pass phrase remains in terminal encoding. passphrase = opts.get("--passphrase", opts.get("-p", None)) if passphrase == None and privkey != None: # Private key given without "--passphrase" option, ask it. if sys.stdin.isatty(): # Standard input is a TTY, ask password interactively. passphrase = getpass.getpass("Enter private key pass phrase:") else: # Not connected to a TTY, read stdin non-interactively instead. passphrase = sys.stdin.read(MAXPASSPHRASELENGTH + 1) if len(passphrase) > MAXPASSPHRASELENGTH: raise ValueError("pass phrase too long") passphrase = passphrase.strip() # Determine verbosity. verbose = False if "--verbose" in opts.keys() or "-v" in opts.keys(): verbose = True # Determine if debug output is requested. if "--debug" in opts.keys(): debug = True # Enable debug output for OpenSSL-related functions. cryptutil.setdebug(True) # Ingredients for successful SIS generation: # # terminalenc Terminal character encoding (autodetected) # filesystemenc File system name encoding (autodetected) # infiles A list of input SIS file names, filesystemenc encoded # outfile Output SIS file name, filesystemenc encoded # cert Certificate in PEM format # privkey Certificate private key in PEM format # passphrase Pass phrase of priv. key, terminalenc encoded string # verbose Boolean indicating verbose terminal output if verbose: print print "Input SIS files %s" % " ".join( [f.decode(filesystemenc).encode(terminalenc) for f in infiles]) print "Output SIS file %s" % ( outfile.decode(filesystemenc).encode(terminalenc)) print "Certificate %s" % ( (cert and cert.decode(filesystemenc).encode(terminalenc)) or "<default>") print "Private key %s" % ( (privkey and privkey.decode(filesystemenc).encode(terminalenc)) or "<default>") print insis = [] for n in xrange(len(infiles)): # Read input SIS files. f = file(infiles[n], "rb") instring = f.read(MAXSISFILESIZE + 1) f.close() if len(instring) > MAXSISFILESIZE: raise ValueError("%s: input SIS file too large" % infiles[n]) if n == 0: # Store UIDs for later use. uids = instring[:16] # UID1, UID2, UID3 and UIDCRC # Convert input SIS file to SISFields. sf, rlen = sisfield.SISField(instring[16:], False) # Ignore extra bytes after SIS file. if len(instring) > (rlen + 16): print("%s: %s: warning: %d extra bytes after SIS file (ignored)" % (pgmname, infiles[n], (len(instring) - (rlen + 16)))) # Try to release some memory early. del instring # Check that there are no embedded SIS files. if len(sf.Data.DataUnits) > 1: raise ValueError("%s: input SIS file contains " "embedded SIS files" % infiles[n]) insis.append(sf) # Temporarily remove the SISDataIndex SISField from the first SISController. ctrlfield = insis[0].Controller.Data didxfield = ctrlfield.DataIndex ctrlfield.DataIndex = None # Remove old signatures from the first SIS file. if len(ctrlfield.getsignatures()) > 0: print( "%s: warning: removing old signatures " "from the first input SIS file" % pgmname) ctrlfield.setsignatures([]) for n in xrange(1, len(insis)): # Append SISDataUnit SISFields into SISData array of the first SIS file. insis[0].Data.DataUnits.append(insis[n].Data.DataUnits[0]) # Set data index in SISController SISField. insis[n].Controller.Data.DataIndex.DataIndex = n # Embed SISController into SISInstallBlock of the first SIS file. ctrlfield.InstallBlock.EmbeddedSISFiles.append( insis[n].Controller.Data) # Calculate a signature of the modified SISController. string = ctrlfield.tostring() string = sisfield.stripheaderandpadding(string) signature, algoid = sisfile.signstring(privkeydata, passphrase, string) # Create a SISCertificateChain SISField from certificate data. sf1 = sisfield.SISBlob(Data=cryptutil.certtobinary(certdata)) sf2 = sisfield.SISCertificateChain(CertificateData=sf1) # Create a SISSignature SISField from calculated signature. sf3 = sisfield.SISString(String=algoid) sf4 = sisfield.SISSignatureAlgorithm(AlgorithmIdentifier=sf3) sf5 = sisfield.SISBlob(Data=signature) sf6 = sisfield.SISSignature(SignatureAlgorithm=sf4, SignatureData=sf5) # Create a new SISSignatureCertificateChain SISField. sa = sisfield.SISArray(SISFields=[sf6]) sf7 = sisfield.SISSignatureCertificateChain(Signatures=sa, CertificateChain=sf2) # Set certificate, restore data index. ctrlfield.Signature0 = sf7 ctrlfield.DataIndex = didxfield # Convert SISFields to string. outstring = insis[0].tostring() # Write output SIS file. f = file(outfile, "wb") f.write(uids) f.write(outstring) f.close()
def run(pgmname, argv): global debug # Determine system character encodings. try: # getdefaultlocale() may sometimes return None. # Fall back to ASCII encoding in that case. terminalenc = locale.getdefaultlocale()[1] + "" except TypeError: # Invalid locale, fall back to ASCII terminal encoding. terminalenc = "ascii" try: # sys.getfilesystemencoding() was introduced in Python v2.3 and # it can sometimes return None. Fall back to ASCII if something # goes wrong. filesystemenc = sys.getfilesystemencoding() + "" except (AttributeError, TypeError): filesystemenc = "ascii" try: gopt = getopt.gnu_getopt except: # Python <v2.3, GNU-style parameter ordering not supported. gopt = getopt.getopt # Parse command line arguments. short_opts = "ua:k:p:b:d:e:vh" long_opts = [ "unsign", "cert=", "privkey=", "passphrase=", "execaps=", "dllcaps=", "encoding=", "verbose", "debug", "help" ] args = gopt(argv, short_opts, long_opts) opts = dict(args[0]) pargs = args[1] if len(pargs) == 0: raise ValueError("no SIS file name given") # Override character encoding of command line and filesystem. encs = opts.get("--encoding", opts.get("-e", "%s,%s" % (terminalenc, filesystemenc))) try: terminalenc, filesystemenc = encs.split(",") except (ValueError, TypeError): raise ValueError("invalid encoding string '%s'" % encs) # Get input SIS file name. infile = pargs[0].decode(terminalenc).encode(filesystemenc) # Determine output SIS file name. if len(pargs) == 1: # No output file, overwrite original SIS file. outfile = infile elif len(pargs) == 2: outfile = pargs[1].decode(terminalenc).encode(filesystemenc) if os.path.isdir(outfile): # Output to directory, use input file name. outfile = os.path.join(outfile, os.path.basename(infile)) else: raise ValueError("wrong number of arguments") # Get unsign option. unsign = False if "--unsign" in opts.keys() or "-u" in opts.keys(): unsign = True # Get certificate and its private key file names. cert = opts.get("--cert", opts.get("-a", None)) privkey = opts.get("--privkey", opts.get("-k", None)) if unsign: if cert != None or privkey != None: raise ValueError("certificate or private key given when unsigning") elif cert != None and privkey != None: # Convert file names from terminal encoding to filesystem encoding. cert = cert.decode(terminalenc).encode(filesystemenc) privkey = privkey.decode(terminalenc).encode(filesystemenc) # Read certificate file. f = file(cert, "rb") certdata = f.read(MAXCERTIFICATELENGTH + 1) f.close() if len(certdata) > MAXCERTIFICATELENGTH: raise ValueError("certificate file too large") # Read private key file. f = file(privkey, "rb") privkeydata = f.read(MAXPRIVATEKEYLENGTH + 1) f.close() if len(privkeydata) > MAXPRIVATEKEYLENGTH: raise ValueError("private key file too large") elif cert == None and privkey == None: # No certificate given, use the Ensymble default certificate. # defaultcert.py is not imported when not needed. This speeds # up program start-up a little. from utils import defaultcert certdata = defaultcert.cert privkeydata = defaultcert.privkey print ("%s: warning: no certificate given, using " "insecure built-in one" % pgmname) else: raise ValueError("missing certificate or private key") # Get pass phrase. Pass phrase remains in terminal encoding. passphrase = opts.get("--passphrase", opts.get("-p", None)) if passphrase == None and privkey != None: # Private key given without "--passphrase" option, ask it. if sys.stdin.isatty(): # Standard input is a TTY, ask password interactively. passphrase = getpass.getpass("Enter private key pass phrase:") else: # Not connected to a TTY, read stdin non-interactively instead. passphrase = sys.stdin.read(MAXPASSPHRASELENGTH + 1) if len(passphrase) > MAXPASSPHRASELENGTH: raise ValueError("pass phrase too long") passphrase = passphrase.strip() # Get EXE capabilities and normalize the names. execaps = opts.get("--execaps", opts.get("-b", None)) if execaps != None: execapmask = symbianutil.capstringtomask(execaps) execaps = symbianutil.capmasktostring(execapmask, True) else: execapmask = None # Get DLL capabilities and normalize the names. dllcaps = opts.get("--dllcaps", opts.get("-d", None)) if dllcaps != None: dllcapmask = symbianutil.capstringtomask(dllcaps) dllcaps = symbianutil.capmasktostring(dllcapmask, True) else: dllcapmask = None # Determine verbosity. verbose = False if "--verbose" in opts.keys() or "-v" in opts.keys(): verbose = True # Determine if debug output is requested. if "--debug" in opts.keys(): debug = True # Enable debug output for OpenSSL-related functions. cryptutil.setdebug(True) # Ingredients for successful SIS generation: # # terminalenc Terminal character encoding (autodetected) # filesystemenc File system name encoding (autodetected) # infile Input SIS file name, filesystemenc encoded # outfile Output SIS file name, filesystemenc encoded # cert Certificate in PEM format # privkey Certificate private key in PEM format # passphrase Pass phrase of priv. key, terminalenc encoded string # execaps, execapmask Capability names and bitmask for EXE files or None # dllcaps, dllcapmask Capability names and bitmask for DLL files or None # verbose Boolean indicating verbose terminal output if verbose: print print "Input SIS file %s" % ( infile.decode(filesystemenc).encode(terminalenc)) print "Output SIS file %s" % ( outfile.decode(filesystemenc).encode(terminalenc)) if unsign: print "Remove signatures Yes" else: print "Certificate %s" % ((cert and cert.decode(filesystemenc).encode(terminalenc)) or "<default>") print "Private key %s" % ((privkey and privkey.decode(filesystemenc).encode(terminalenc)) or "<default>") if execaps != None: print "EXE capabilities 0x%x (%s)" % (execapmask, execaps) else: print "EXE capabilities <not set>" if dllcaps != None: print "DLL capabilities 0x%x (%s)" % (dllcapmask, dllcaps) else: print "DLL capabilities <not set>" print # Read input SIS file. f = file(infile, "rb") instring = f.read(MAXSISFILESIZE + 1) f.close() if len(instring) > MAXSISFILESIZE: raise ValueError("input SIS file too large") # Convert input SIS file to SISFields. uids = instring[:16] # UID1, UID2, UID3 and UIDCRC insis, rlen = sisfield.SISField(instring[16:], False) # Ignore extra bytes after SIS file. if len(instring) > (rlen + 16): print ("%s: warning: %d extra bytes after input SIS file (ignored)" % (pgmname, (len(instring) - (rlen + 16)))) # Try to release some memory early. del instring # Check if there are embedded SIS files. Warn if there are. if len(insis.Data.DataUnits) > 1: print ("%s: warning: input SIS file contains " "embedded SIS files (ignored)" % pgmname) # Modify EXE- and DLL-files according to new capabilities. if execaps != None or dllcaps != None: # Generate FileIndex to SISFileDescription mapping. sisfiledescmap = mapfiledesc(insis.Controller.Data.InstallBlock) exemods, dllmods = modifycaps(insis, sisfiledescmap, execapmask, dllcapmask) print ("%s: %d EXE-files will be modified, " "%d DLL-files will be modified" % (pgmname, exemods, dllmods)) # Temporarily remove the SISDataIndex SISField from SISController. ctrlfield = insis.Controller.Data didxfield = ctrlfield.DataIndex ctrlfield.DataIndex = None if not unsign: # Remove old signatures. if len(ctrlfield.getsignatures()) > 0: print ("%s: warning: removing old signatures " "from input SIS file" % pgmname) ctrlfield.setsignatures([]) # Calculate a signature of the modified SISController. string = ctrlfield.tostring() string = sisfield.stripheaderandpadding(string) signature, algoid = sisfile.signstring(privkeydata, passphrase, string) # Create a SISCertificateChain SISField from certificate data. sf1 = sisfield.SISBlob(Data = cryptutil.certtobinary(certdata)) sf2 = sisfield.SISCertificateChain(CertificateData = sf1) # Create a SISSignature SISField from calculated signature. sf3 = sisfield.SISString(String = algoid) sf4 = sisfield.SISSignatureAlgorithm(AlgorithmIdentifier = sf3) sf5 = sisfield.SISBlob(Data = signature) sf6 = sisfield.SISSignature(SignatureAlgorithm = sf4, SignatureData = sf5) # Create a new SISSignatureCertificateChain SISField. sa = sisfield.SISArray(SISFields = [sf6]) sf7 = sisfield.SISSignatureCertificateChain(Signatures = sa, CertificateChain = sf2) # Set new certificate. ctrlfield.Signature0 = sf7 else: # Unsign, remove old signatures. ctrlfield.setsignatures([]) # Restore data index. ctrlfield.DataIndex = didxfield # Convert SISFields to string. outstring = insis.tostring() # Write output SIS file. f = file(outfile, "wb") f.write(uids) f.write(outstring) f.close()
def run(pgmname, argv): global debug # Determine system character encodings. try: # getdefaultlocale() may sometimes return None. # Fall back to ASCII encoding in that case. terminalenc = locale.getdefaultlocale()[1] + "" except TypeError: # Invalid locale, fall back to ASCII terminal encoding. terminalenc = "ascii" try: # sys.getfilesystemencoding() was introduced in Python v2.3 and # it can sometimes return None. Fall back to ASCII if something # goes wrong. filesystemenc = sys.getfilesystemencoding() + "" except (AttributeError, TypeError): filesystemenc = "ascii" try: gopt = getopt.gnu_getopt except: # Python <v2.3, GNU-style parameter ordering not supported. gopt = getopt.getopt # Parse command line arguments. short_opts = "a:k:p:e:vh" long_opts = [ "cert=", "privkey=", "passphrase=", "encoding=", "verbose", "debug", "help" ] args = gopt(argv, short_opts, long_opts) opts = dict(args[0]) pargs = args[1] if len(pargs) < 2: raise ValueError("wrong number of arguments") # Override character encoding of command line and filesystem. encs = opts.get("--encoding", opts.get("-e", "%s,%s" % (terminalenc, filesystemenc))) try: terminalenc, filesystemenc = encs.split(",") except (ValueError, TypeError): raise ValueError("invalid encoding string '%s'" % encs) # Get input SIS file names. infiles = [f.decode(terminalenc).encode(filesystemenc) for f in pargs[:-1]] # Determine output SIS file name. outfile = pargs[-1].decode(terminalenc).encode(filesystemenc) if os.path.isdir(outfile): # Output to directory, use input file name. outfile = os.path.join(outfile, os.path.basename(infiles[0])) # Get certificate and its private key file names. cert = opts.get("--cert", opts.get("-a", None)) privkey = opts.get("--privkey", opts.get("-k", None)) if cert != None and privkey != None: # Convert file names from terminal encoding to filesystem encoding. cert = cert.decode(terminalenc).encode(filesystemenc) privkey = privkey.decode(terminalenc).encode(filesystemenc) # Read certificate file. f = file(cert, "rb") certdata = f.read(MAXCERTIFICATELENGTH + 1) f.close() if len(certdata) > MAXCERTIFICATELENGTH: raise ValueError("certificate file too large") # Read private key file. f = file(privkey, "rb") privkeydata = f.read(MAXPRIVATEKEYLENGTH + 1) f.close() if len(privkeydata) > MAXPRIVATEKEYLENGTH: raise ValueError("private key file too large") elif cert == None and privkey == None: # No certificate given, use the Ensymble default certificate. # defaultcert.py is not imported when not needed. This speeds # up program start-up a little. from utils import defaultcert certdata = defaultcert.cert privkeydata = defaultcert.privkey print ("%s: warning: no certificate given, using " "insecure built-in one" % pgmname) else: raise ValueError("missing certificate or private key") # Get pass phrase. Pass phrase remains in terminal encoding. passphrase = opts.get("--passphrase", opts.get("-p", None)) if passphrase == None and privkey != None: # Private key given without "--passphrase" option, ask it. if sys.stdin.isatty(): # Standard input is a TTY, ask password interactively. passphrase = getpass.getpass("Enter private key pass phrase:") else: # Not connected to a TTY, read stdin non-interactively instead. passphrase = sys.stdin.read(MAXPASSPHRASELENGTH + 1) if len(passphrase) > MAXPASSPHRASELENGTH: raise ValueError("pass phrase too long") passphrase = passphrase.strip() # Determine verbosity. verbose = False if "--verbose" in opts.keys() or "-v" in opts.keys(): verbose = True # Determine if debug output is requested. if "--debug" in opts.keys(): debug = True # Enable debug output for OpenSSL-related functions. cryptutil.setdebug(True) # Ingredients for successful SIS generation: # # terminalenc Terminal character encoding (autodetected) # filesystemenc File system name encoding (autodetected) # infiles A list of input SIS file names, filesystemenc encoded # outfile Output SIS file name, filesystemenc encoded # cert Certificate in PEM format # privkey Certificate private key in PEM format # passphrase Pass phrase of priv. key, terminalenc encoded string # verbose Boolean indicating verbose terminal output if verbose: print print "Input SIS files %s" % " ".join( [f.decode(filesystemenc).encode(terminalenc) for f in infiles]) print "Output SIS file %s" % ( outfile.decode(filesystemenc).encode(terminalenc)) print "Certificate %s" % ((cert and cert.decode(filesystemenc).encode(terminalenc)) or "<default>") print "Private key %s" % ((privkey and privkey.decode(filesystemenc).encode(terminalenc)) or "<default>") print insis = [] for n in xrange(len(infiles)): # Read input SIS files. f = file(infiles[n], "rb") instring = f.read(MAXSISFILESIZE + 1) f.close() if len(instring) > MAXSISFILESIZE: raise ValueError("%s: input SIS file too large" % infiles[n]) if n == 0: # Store UIDs for later use. uids = instring[:16] # UID1, UID2, UID3 and UIDCRC # Convert input SIS file to SISFields. sf, rlen = sisfield.SISField(instring[16:], False) # Ignore extra bytes after SIS file. if len(instring) > (rlen + 16): print ("%s: %s: warning: %d extra bytes after SIS file (ignored)" % (pgmname, infiles[n], (len(instring) - (rlen + 16)))) # Try to release some memory early. del instring # Check that there are no embedded SIS files. if len(sf.Data.DataUnits) > 1: raise ValueError("%s: input SIS file contains " "embedded SIS files" % infiles[n]) insis.append(sf) # Temporarily remove the SISDataIndex SISField from the first SISController. ctrlfield = insis[0].Controller.Data didxfield = ctrlfield.DataIndex ctrlfield.DataIndex = None # Remove old signatures from the first SIS file. if len(ctrlfield.getsignatures()) > 0: print ("%s: warning: removing old signatures " "from the first input SIS file" % pgmname) ctrlfield.setsignatures([]) for n in xrange(1, len(insis)): # Append SISDataUnit SISFields into SISData array of the first SIS file. insis[0].Data.DataUnits.append(insis[n].Data.DataUnits[0]) # Set data index in SISController SISField. insis[n].Controller.Data.DataIndex.DataIndex = n # Embed SISController into SISInstallBlock of the first SIS file. ctrlfield.InstallBlock.EmbeddedSISFiles.append(insis[n].Controller.Data) # Calculate a signature of the modified SISController. string = ctrlfield.tostring() string = sisfield.stripheaderandpadding(string) signature, algoid = sisfile.signstring(privkeydata, passphrase, string) # Create a SISCertificateChain SISField from certificate data. sf1 = sisfield.SISBlob(Data = cryptutil.certtobinary(certdata)) sf2 = sisfield.SISCertificateChain(CertificateData = sf1) # Create a SISSignature SISField from calculated signature. sf3 = sisfield.SISString(String = algoid) sf4 = sisfield.SISSignatureAlgorithm(AlgorithmIdentifier = sf3) sf5 = sisfield.SISBlob(Data = signature) sf6 = sisfield.SISSignature(SignatureAlgorithm = sf4, SignatureData = sf5) # Create a new SISSignatureCertificateChain SISField. sa = sisfield.SISArray(SISFields = [sf6]) sf7 = sisfield.SISSignatureCertificateChain(Signatures = sa, CertificateChain = sf2) # Set certificate, restore data index. ctrlfield.Signature0 = sf7 ctrlfield.DataIndex = didxfield # Convert SISFields to string. outstring = insis[0].tostring() # Write output SIS file. f = file(outfile, "wb") f.write(uids) f.write(outstring) f.close()