示例#1
0
def makeinstallblock(files = [], embeddedsisfiles = [], ifblocks = []):
    '''Make a SISInstallBlock SISField out of the given lists of SISFields.

    makeinstallblock(...) -> SISInstallBlock

    files             a list of SISFileDescription SISFields (normal files)
    embeddedsisfiles  a list of SISController SISFields (embedded SIS files)
    ifblocks          a list of SISIf SISFields (conditionally installed files)

    SISInstallBlock   the returned SISInstallBlock instance

    NOTE: Any of the lists may be empty (and are, by default).'''


    # Convert lists to SISArrays.
    sa1 = sisfield.SISArray(SISFields = files,
                            SISFieldType = "SISFileDescription")
    sa2 = sisfield.SISArray(SISFields = embeddedsisfiles,
                            SISFieldType = "SISController")
    sa3 = sisfield.SISArray(SISFields = ifblocks,
                            SISFieldType = "SISIf")

    # Create a SISInstallBlock SISField and return it.
    return sisfield.SISInstallBlock(Files = sa1, EmbeddedSISFiles = sa2,
                                    IfBlocks = sa3)
示例#2
0
def makelangconditional(languages, langdepfiles):
    '''Make a SISIf and SISElseIfs for language dependent installation of files.

    makelangconditional(...) -> SISIf or None

    languages       a list of language numbers (not names, IDs or SISLanguages)
    landepfiles     a list of file lists, where each file list is a list of
                    alternative SISFileDescription SISFields for each language

    SISIf           the returned SISIf instance or None if no files'''

    if len(langdepfiles) == 0:
        # No language dependent files, leave.
        return None

    # Create a file list per language.
    filesperlang = []
    for n in xrange(len(languages)):
        filesperlang.append([])

    # Gather all files from the same language to a single list.
    for files in langdepfiles:
        if len(files) != len(languages):
            raise ValueError("%d files given but number of languages is %d" %
                             (len(files), len(languages)))

        for n in xrange(len(languages)):
            filesperlang[n].append(files[n])

    if len(languages) == 0:
        # No languages, leave. (This is down here so that errors
        # can still be caught above.)
        return None

    # Create a SISArray of SISElseIf SISFields.
    elseiffields = []
    for n in xrange(1, len(languages)):
        elseifexpfield = parseexpression("language == %d" % languages[n])
        elseiffield = sisfield.SISElseIf(Expression=elseifexpfield,
                                         InstallBlock=makeinstallblock(
                                             filesperlang[n]))
        elseiffields.append(elseiffield)
    elseiffieldarray = sisfield.SISArray(SISFields=elseiffields,
                                         SISFieldType="SISElseIf")

    # Create and return the final SISIf SISField.
    ifexpfield = parseexpression("language == %d" % languages[0])
    return sisfield.SISIf(Expression=ifexpfield,
                          InstallBlock=makeinstallblock(filesperlang[0]),
                          ElseIfs=elseiffieldarray)
示例#3
0
def makedependency(uid, fromversion, toversion, names):
    '''Make a SISDependency SISField for the given UID, version dependency.

    makedependency(...) -> SISDependency

    uid             UID, an unsigned integer
    fromversion     from-version, a triple-item list/tuple (major, minor, build)
    toversion       to-version, a triple-item list/tuple or None
    names           names for the dependency, a list of string per language

    SISDependency   the returned SISDependency SISField

    NOTE: toversion may be None, indicating any version after fromversion.'''

    # Convert parameters to SISFields.
    uidfield = sisfield.SISUid(UID1=uid)

    fromverfield = sisfield.SISVersion(Major=fromversion[0],
                                       Minor=fromversion[1],
                                       Build=fromversion[2])
    if toversion != None:
        toverfield = sisfield.SISVersion(Major=toversion[0],
                                         Minor=toversion[1],
                                         Build=toversion[2])
    else:
        toverfield = None

    verrangefield = sisfield.SISVersionRange(FromVersion=fromverfield,
                                             ToVersion=toverfield)

    l = []
    for name in names:
        l.append(sisfield.SISString(String=name))
    namesfield = sisfield.SISArray(SISFields=l, SISFieldType="SISString")

    # Create a SISDependency SISField and return it.
    return sisfield.SISDependency(UID=uidfield,
                                  VersionRange=verrangefield,
                                  DependencyNames=namesfield)
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.
        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.
        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()
示例#6
0
    def tostring(self):
        '''Convert this SIS instance to a (possibly very large) string.'''

        # Generate a SISInfo SISField.
        infofield = sisfield.SISInfo(UID=self.uid,
                                     VendorUniqueName=self.vendorname,
                                     Names=self.names,
                                     VendorNames=self.vendornames,
                                     Version=self.version,
                                     CreationTime=self.creationtime,
                                     InstallType=sisfield.EInstInstallation,
                                     InstallFlags=0)

        # Generate an empty SISSupportedOptions SISField.
        # Option lists are not supported by SimpleSISWriter.
        sa = sisfield.SISArray(SISFields=[], SISFieldType="SISSupportedOption")
        optfield = sisfield.SISSupportedOptions(Options=sa)

        # Convert language numbers to SISArray of SISLanguages
        # and generate a SISSupportedLanguages SISField.
        langfieldlist = []
        for lang in self.languages:
            langfieldlist.append(sisfield.SISLanguage(Language=lang))
        sa = sisfield.SISArray(SISFields=langfieldlist,
                               SISFieldType="SISLanguage")
        langfield = sisfield.SISSupportedLanguages(Languages=sa)

        # Generate SISPrerequisites SISField.
        sa1 = sisfield.SISArray(SISFields=self.targetdevices,
                                SISFieldType="SISDependency")
        sa2 = sisfield.SISArray(SISFields=self.dependencies,
                                SISFieldType="SISDependency")
        prereqfield = sisfield.SISPrerequisites(TargetDevices=sa1,
                                                Dependencies=sa2)

        # Generate SISProperties SISField.
        sa = sisfield.SISArray(SISFields=self.properties,
                               SISFieldType="SISProperty")
        propfield = sisfield.SISProperties(Properties=sa)

        # Generate SISInstallBlock SISField.
        iffield = makelangconditional(self.languages, self.langdepfiles)
        if iffield:
            # Some language dependent files
            iffieldlist = [iffield]
        else:
            # No language dependent files
            iffieldlist = []
        ibfield = makeinstallblock(self.files, [], iffieldlist)

        # Generate a data index field. No embedded SIS files, index is 0.
        didxfield = sisfield.SISDataIndex(DataIndex=0)

        # Generate a SISController SISField without any signatures.
        ctrlfield = sisfield.SISController(Info=infofield,
                                           Options=optfield,
                                           Languages=langfield,
                                           Prerequisites=prereqfield,
                                           Properties=propfield,
                                           Logo=self.logo,
                                           InstallBlock=ibfield)

        # Calculate metadata signature for each certificate.
        certfieldlist = []
        for cert in self.certificates:
            # Calculate a signature of the SISController so far.
            string = ctrlfield.tostring()
            string = sisfield.stripheaderandpadding(string)
            signature, algoid = signstring(cert[0], cert[2], string)

            # Create a SISCertificateChain SISField from certificate data.
            sf1 = sisfield.SISBlob(Data=cryptutil.certtobinary(cert[1]))
            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])
            certfieldlist.append(
                sisfield.SISSignatureCertificateChain(Signatures=sa,
                                                      CertificateChain=sf2))

            # Add certificate to SISController SISField.
            ctrlfield.setsignatures(certfieldlist)

        # Finally add a data index field to SISController SISField.
        # and wrap it in SISCompressed SISField.
        ctrlfield.DataIndex = didxfield
        ctrlcompfield = sisfield.SISCompressed(
            Data=ctrlfield, CompressionAlgorithm=sisfield.ECompressDeflate)

        # Generate SISData SISField.
        sa = sisfield.SISArray(SISFields=self.filedata,
                               SISFieldType="SISFileData")
        dufield = sisfield.SISDataUnit(FileData=sa)
        sa = sisfield.SISArray(SISFields=[dufield])
        datafield = sisfield.SISData(DataUnits=sa)

        # Calculate SISController checksum.
        # TODO: Requires an extra tostring() conversion.
        ctrlcs = symbianutil.crc16ccitt(ctrlcompfield.tostring())
        ctrlcsfield = sisfield.SISControllerChecksum(Checksum=ctrlcs)

        # Calculate SISData checksum.
        # TODO: Requires an extra tostring() conversion.
        datacs = symbianutil.crc16ccitt(datafield.tostring())
        datacsfield = sisfield.SISDataChecksum(Checksum=datacs)

        # Generate SISContents SISField.
        contentsfield = sisfield.SISContents(ControllerChecksum=ctrlcsfield,
                                             DataChecksum=datacsfield,
                                             Controller=ctrlcompfield,
                                             Data=datafield)

        # Generate a SIS UID string.
        uidstring = symbianutil.uidstostring(0x10201a7aL, 0x00000000L,
                                             self.uid.UID1)

        # Return the completed SIS file as a string.
        return uidstring + contentsfield.tostring()
示例#7
0
    def __init__(self,
                 languages,
                 names,
                 uid,
                 version,
                 vendorname,
                 vendornames,
                 creationtime=None):
        # Set empty list of languages, names, files, certificates and so on.
        self.languages = []
        self.filedata = []
        self.files = []
        self.langdepfiles = []
        self.logo = None
        self.certificates = []
        self.targetdevices = []
        self.dependencies = []
        self.properties = []

        # Convert language IDs/names to language numbers.
        for lang in languages:
            try:
                langnum = symbianutil.langidtonum[lang]
            except KeyError:
                # Not a language ID, try names next.
                try:
                    langnum = symbianutil.langnametonum[lang]
                except KeyError:
                    raise ValueError("invalid language '%s'" % lang)
            self.languages.append(langnum)

        # Verify number of names and vendor names wrt. number of languages.
        if len(names) != len(self.languages):
            raise ValueError(
                "%d package names given but number of languages is %d" %
                (len(names), len(self.languages)))

        if len(vendornames) != len(self.languages):
            raise ValueError(
                "%d vendor names given but number of languages is %d" %
                (len(vendornames), len(self.languages)))

        # Convert language dependent names to a SISArray of SISStrings.
        l = []
        for name in names:
            l.append(sisfield.SISString(String=name))
        self.names = sisfield.SISArray(SISFields=l, SISFieldType="SISString")

        # Convert integer UID to SISUid SISField.
        self.uid = sisfield.SISUid(UID1=uid)

        # Convert version number triplet to SISVersion SISField.
        self.version = sisfield.SISVersion(Major=version[0],
                                           Minor=version[1],
                                           Build=version[2])

        # Convert unique vendor name to SISString SISField.
        self.vendorname = sisfield.SISString(String=vendorname)

        # Convert language dependent vendor names to a SISArray of SISStrings.
        l = []
        for name in vendornames:
            l.append(sisfield.SISString(String=name))
        self.vendornames = sisfield.SISArray(SISFields=l,
                                             SISFieldType="SISString")

        if creationtime == None:
            # If no creation time given, use the time
            # of SimpleSISWriter instantiation.
            creationtime = time.gmtime()

        # Convert standard Python time representation to SISFields.
        datefield = sisfield.SISDate(Year=creationtime.tm_year,
                                     Month=creationtime.tm_mon - 1,
                                     Day=creationtime.tm_mday)
        timefield = sisfield.SISTime(Hours=creationtime.tm_hour,
                                     Minutes=creationtime.tm_min,
                                     Seconds=creationtime.tm_sec)
        self.creationtime = sisfield.SISDateTime(Date=datefield,
                                                 Time=timefield)