os/security/cryptoservices/browserrootcertificates/certconvert.py
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/security/cryptoservices/browserrootcertificates/certconvert.py	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,349 @@
     1.4 +#
     1.5 +# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
     1.6 +# All rights reserved.
     1.7 +# This component and the accompanying materials are made available
     1.8 +# under the terms of the License "Eclipse Public License v1.0"
     1.9 +# which accompanies this distribution, and is available
    1.10 +# at the URL "http://www.eclipse.org/legal/epl-v10.html".
    1.11 +#
    1.12 +# Initial Contributors:
    1.13 +# Nokia Corporation - initial contribution.
    1.14 +#
    1.15 +# Contributors:
    1.16 +#
    1.17 +# Description: 
    1.18 +# Script to convert the Mozilla certificate store into the store format Symbian OS understands.
    1.19 +#
    1.20 +# Mozilla certificate store and its associated license is available at
    1.21 +# http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1
    1.22 +#
    1.23 +#
    1.24 +
    1.25 +import string, getopt, sys, subprocess, glob, os
    1.26 +
    1.27 +#
    1.28 +# Default input files
    1.29 +#
    1.30 +inFileMozillaCerts = "certdata.txt"
    1.31 +inFileTrustMapping = "trustmapping.txt"
    1.32 +
    1.33 +#
    1.34 +# Output path (don't change this!) and other temp files
    1.35 +#
    1.36 +outPath = ".\\"
    1.37 +outFileCaCerts = "cacerts_text.txt"
    1.38 +outFileCertClients = "certclients_text.txt"
    1.39 +outCertAppOutput = "output.txt"
    1.40 +
    1.41 +#
    1.42 +# Constants
    1.43 +#
    1.44 +ERROR_NONE = 0
    1.45 +ERROR_EOF = -1
    1.46 +ERROR_GENERAL = -2
    1.47 +
    1.48 +#
    1.49 +# Class CertRecord
    1.50 +#
    1.51 +class CertRecord:
    1.52 +    def __init__(self, file):
    1.53 +        self.file = file
    1.54 +        # Read over the first CKA_CLASS record
    1.55 +        value = ""
    1.56 +        self.ReadTokenValue("CKA_CLASS")
    1.57 +        # Can we assert if value != "CKO_NETSCAPE_BUILTIN_ROOT_LIST"
    1.58 +
    1.59 +    # Read and parse next record, return 0 if no more records exist
    1.60 +    def Next(self):
    1.61 +        # Read next certificate token
    1.62 +        err, value = self.ReadTokenValue("CKA_CLASS")
    1.63 +        if (err == ERROR_EOF):
    1.64 +            return err
    1.65 +        if (err != ERROR_NONE or value != "CKO_CERTIFICATE"):
    1.66 +            return err
    1.67 +
    1.68 +        # Read the cert label
    1.69 +        err, self.certLabel = self.ReadTokenValue("CKA_LABEL")
    1.70 +        if (err != ERROR_NONE):
    1.71 +            return err
    1.72 +
    1.73 +        # Read the cert type
    1.74 +        err, self.certType = self.ReadTokenValue("CKA_CERTIFICATE_TYPE")
    1.75 +        if (err != ERROR_NONE):
    1.76 +            return err
    1.77 +
    1.78 +        # Read the cert serial number
    1.79 +        err, self.certSerialNum = self.ReadTokenValue("CKA_SERIAL_NUMBER")
    1.80 +        if (err != ERROR_NONE):
    1.81 +            return err
    1.82 +
    1.83 +        # Read the actual cert data (DER encoded)
    1.84 +        err, self.certData = self.ReadTokenValue("CKA_VALUE")
    1.85 +        if (err != ERROR_NONE):
    1.86 +            return err
    1.87 +
    1.88 +        # Read the trust details
    1.89 +        err, value = self.ReadTokenValue("CKA_CLASS")
    1.90 +        if (err != ERROR_NONE or value != "CKO_NETSCAPE_TRUST"):
    1.91 +            return err
    1.92 +
    1.93 +        # Read the trust label and match it with cert label
    1.94 +        err, self.trustLabel = self.ReadTokenValue("CKA_LABEL")
    1.95 +        if (err != ERROR_NONE or self.trustLabel != self.certLabel):
    1.96 +            print "Certificate and Trust label mismatch or not found for cert " + self.certLabel
    1.97 +            return err
    1.98 +
    1.99 +        # Read the SHA1 hash (aka thumbprint)
   1.100 +        err, self.trustSha1Hash = self.ReadTokenValue("CKA_CERT_SHA1_HASH")
   1.101 +
   1.102 +        # Read the trust serial number and match it with cert serial number
   1.103 +        err, self.trustSerialNum = self.ReadTokenValue("CKA_SERIAL_NUMBER")
   1.104 +        if (err != ERROR_NONE or self.trustSerialNum != self.certSerialNum):
   1.105 +            print "Warning: Certificate and Trust serial number mismatch or not found for cert " + self.certLabel
   1.106 +
   1.107 +        # Read the trust list. This has a variable token so can't use ReadTokenValue method
   1.108 +        err, self.trustTrustList = self.ReadTrustValues()
   1.109 +        if (err != ERROR_NONE):
   1.110 +            return err
   1.111 +
   1.112 +        return ERROR_NONE
   1.113 +
   1.114 +    def ReadTrustValues(self):
   1.115 +        # Keep reading lines till token "CKA_TRUST_STEP_UP_APPROVED" found
   1.116 +        trustList = []
   1.117 +        for line in self.file:
   1.118 +            line = line.rstrip('\n')
   1.119 +            fields = line.split(" ")
   1.120 +            if (len(fields) == 0):
   1.121 +                continue
   1.122 +            if (fields[0] == "CKA_TRUST_STEP_UP_APPROVED"):
   1.123 +                # Done reading trust settings
   1.124 +                return ERROR_NONE, trustList
   1.125 +                break
   1.126 +            if (fields[1] == "CK_TRUST"):
   1.127 +                if ((fields[2] == "CKT_NETSCAPE_TRUSTED_DELEGATOR")):
   1.128 +                    trustList.append(fields[0].strip())
   1.129 +            else:
   1.130 +                # Something is wrong
   1.131 +                print "Error reading trust settings. " + line
   1.132 +                return ERROR_GENERAL, []
   1.133 +
   1.134 +        # End of file?
   1.135 +        if (line == ""):
   1.136 +            return ERROR_EOF, ""
   1.137 +        print "Error in ReadTrustValues(). Token ('CKA_TRUST_STEP_UP_APPROVED') not found!"
   1.138 +        return ERROR_GENERAL, ""
   1.139 +
   1.140 +    def ReadTokenValue(self, token):
   1.141 +        # Keep reading lines till token found
   1.142 +        for line in self.file:
   1.143 +            line = line.rstrip('\n')
   1.144 +            fields = line.split(" ")
   1.145 +            if (len(fields) == 0):
   1.146 +                continue
   1.147 +            if (fields[0] == token):
   1.148 +                if (fields[1] != "MULTILINE_OCTAL"):
   1.149 +                    value = " ".join(fields[2:])
   1.150 +                    return ERROR_NONE, value
   1.151 +                else:
   1.152 +                    # Read multiline octal value till END
   1.153 +                    value=""
   1.154 +                    for nextline in self.file:
   1.155 +                        nextline = nextline.rstrip('\n')
   1.156 +                        if (nextline == "END"):
   1.157 +                            break
   1.158 +                        if (nextline != ""):
   1.159 +                            # Convert string of octal to binary data
   1.160 +                            # There must be an easier way than this!
   1.161 +                            octalWordList = nextline.split("\\")
   1.162 +                            for octalWord in octalWordList:
   1.163 +                                if (octalWord != ""):
   1.164 +                                    value = value + chr(int(octalWord, 8))
   1.165 +                        else:
   1.166 +                            print "ReadTokenValue(" + token + ") awaiting END. Unexpected end of file!"
   1.167 +                            return ERROR_EOF, ""
   1.168 +                    return ERROR_NONE, value
   1.169 +
   1.170 +        #print "ReadTokenValue(" + token + "). Token not found!"
   1.171 +        return ERROR_EOF, ""
   1.172 +
   1.173 +#
   1.174 +# Global function ReadTrustMapping()
   1.175 +#
   1.176 +def ReadTrustMapping(file):
   1.177 +    trustMapping = []
   1.178 +    for line in file:
   1.179 +        line = line.rstrip('\n')
   1.180 +        if (line == "" or line[0] == "#"):
   1.181 +            continue
   1.182 +        fields = line.split(",")
   1.183 +        if (len(fields) == 0):
   1.184 +            continue
   1.185 +        if ((len(fields) % 2) != 1):
   1.186 +            print "Error in file '%s' in line '%s'\n" % inFileTrustMapping % line
   1.187 +            return GENERAL_ERROR, [[]]
   1.188 +        mozTrust = fields[0].strip()
   1.189 +        for index in range(1, len(fields), 2):
   1.190 +            appUID = fields[index].strip()
   1.191 +            appName = fields[index + 1].strip()
   1.192 +            trustMapping.append([mozTrust, appUID, appName])
   1.193 +    return ERROR_NONE, trustMapping
   1.194 +
   1.195 +#
   1.196 +# Global function ReadCommandlineArgs()
   1.197 +#
   1.198 +def ReadCommandlineArgs(argv):
   1.199 +    try:
   1.200 +        flags, args = getopt.getopt(argv[1:], "hm:t:", ["help", "mozilla=", "trust="])
   1.201 +    except getopt.GetoptError, err:
   1.202 +        # Print usage
   1.203 +        print str(err) + "\n"
   1.204 +        PrintUsage()
   1.205 +        sys.exit(-1)
   1.206 +    for flag, arg in flags:
   1.207 +        if flag in ("-h", "--help"):
   1.208 +            PrintUsage()
   1.209 +            sys.exit()
   1.210 +        elif flag in ("-m", "--mozilla"):
   1.211 +            globals()["inFileMozillaCerts"] = arg
   1.212 +        elif flag in ("-t", "--trust"):
   1.213 +            globals()["inFileTrustMapping"] = arg
   1.214 +    print "certconvert - This script converts the Mozilla certificate store into Symbian OS certificate store."
   1.215 +    print "\nInput Mozilla store file: %s" % globals()["inFileMozillaCerts"]
   1.216 +    print "Input trust mapping: %s" % globals()["inFileTrustMapping"]
   1.217 +
   1.218 +#
   1.219 +#
   1.220 +#
   1.221 +def PrintUsage():
   1.222 +    print "certconvert - This script converts the Mozilla certificate store into Symbian OS certificate store."
   1.223 +    print "It uses certapp for the conversion so certapp must be in the path."
   1.224 +    print "Usage: certconvert [-h] | [-m <file> -t <file>] [-o <outpath>]"
   1.225 +    print "where:"
   1.226 +    print "-h | --help\tshows this help"
   1.227 +    print "-m | --mozilla\tis used to specify the Mozilla certificate store input file."
   1.228 +    print "\t\tIf not specified default is taken as 'certdata.txt'."
   1.229 +    print "-t | --trust\tis used to specify the input trust mapping input file."
   1.230 +    print "\t\tThis file maps the trust settings from the Mozilla store to "
   1.231 +    print "\t\tSymbian's applications and uids."
   1.232 +    print "\t\tIf not specified default is taken as 'trustmapping.txt'."
   1.233 +
   1.234 +#
   1.235 +# Main starts here
   1.236 +#
   1.237 +
   1.238 +# Read and process command line arguments
   1.239 +ReadCommandlineArgs(sys.argv)
   1.240 +
   1.241 +# First read the trust mappings file
   1.242 +print "Reading trust mapping file...",
   1.243 +file = open(inFileTrustMapping, "r")
   1.244 +err, trustMapping = ReadTrustMapping(file)
   1.245 +if (err != ERROR_NONE):
   1.246 +    print "\nError reading trust mapping file!\n"
   1.247 +    sys.exit(-1)
   1.248 +file.close()
   1.249 +print "done."
   1.250 +
   1.251 +print "Reading Mozilla certificate store and processing certificates",
   1.252 +inFileMoz=open(inFileMozillaCerts, "r")
   1.253 +record = CertRecord(inFileMoz)
   1.254 +inRecNum = outRecNum = 0
   1.255 +while (record.Next() == ERROR_NONE):
   1.256 +    inRecNum = inRecNum + 1
   1.257 +    #print "Read record %d: %s" % (inRecNum, record.certLabel)
   1.258 +    # Do filtering of records (if any)
   1.259 +    
   1.260 +    outRecNum = outRecNum + 1
   1.261 +    # Create the human readable filecertstore entry
   1.262 +    if (outRecNum == 1):
   1.263 +        if (os.path.exists(outPath) == False):
   1.264 +            os.makedirs(outPath)
   1.265 +        if (os.path.exists(outPath + "\\certs") == False):
   1.266 +            os.makedirs(outPath + "\\certs")
   1.267 +        outFileSym = open(outPath + outFileCaCerts, "w")
   1.268 +        outFileSym.write("StartCertStoreEntries\n")
   1.269 +
   1.270 +    outFileSym.write("\t# Entry %d\n" % outRecNum)
   1.271 +
   1.272 +    # Write out the SHA1 hash of the certificate (to make it easier to compare certs)
   1.273 +    # Convert to hex
   1.274 +    sha1hash = ""
   1.275 +    #octalWordList = record.trustSha1Hash.split("\\")
   1.276 +    for index in range(0, len(record.trustSha1Hash)):
   1.277 +        hexdigits = hex(ord(record.trustSha1Hash[index]))[2:]
   1.278 +        hexdigits = hexdigits.zfill(2)
   1.279 +        sha1hash = sha1hash + hexdigits + " "
   1.280 +    outFileSym.write("\t# Thumbprint(hex) %s\n" % sha1hash)
   1.281 +
   1.282 +    outFileSym.write("\tStartEntry " + record.certLabel + "\n")
   1.283 +    outFileSym.write("\t\tDeletable true\n")
   1.284 +    outFileSym.write("\t\tFormat EX509Certificate\n")
   1.285 +    outFileSym.write("\t\tCertOwnerType ECACertificate\n")
   1.286 +    outFileSym.write("\t\tSubjectKeyId auto\n")
   1.287 +    outFileSym.write("\t\tIssuerKeyId auto\n")
   1.288 +
   1.289 +    # Write out trust details
   1.290 +    outFileSym.write("\t\tStartApplicationList\n")
   1.291 +    for trust in record.trustTrustList:
   1.292 +        # Look for the mapping
   1.293 +        for mapping in trustMapping:
   1.294 +            if (trust == mapping[0]):
   1.295 +                # Found a mapping. Add it and keep on looking since
   1.296 +                # there could be more than one app mapping
   1.297 +                outFileSym.write('\t\t\tApplication "' + mapping[2] + '"\n');
   1.298 +    outFileSym.write("\t\tEndApplicationList\n")
   1.299 +    outFileSym.write("\t\tTrusted true\n")
   1.300 +    certFileName = "certs\\\\cert%04d" % outRecNum + ".der"
   1.301 +    outFileSym.write('\t\tDataFileName "' + certFileName + '"\n')
   1.302 +    outFileSym.write("\tEndEntry\n\n")
   1.303 +    # Write the certificate file
   1.304 +    outFileCert = open(outPath + certFileName, "wb")
   1.305 +    outFileCert.write(record.certData)
   1.306 +    outFileCert.close()
   1.307 +    print ".",
   1.308 +
   1.309 +if (outRecNum > 0):
   1.310 +    outFileSym.write("EndCertStoreEntries\n")
   1.311 +    outFileSym.close()
   1.312 +print "done."
   1.313 +
   1.314 +# Finally create the app to uid mapping file for Symbian OS
   1.315 +if (outRecNum > 0):
   1.316 +    outFileSym = open(outPath + outFileCertClients, "w")
   1.317 +    outFileSym.write("StartClientInfo\n")
   1.318 +    for index in range(0, len(trustMapping)):
   1.319 +        outFileSym.write("\t#Entry %d\n" % (index + 1))
   1.320 +        outFileSym.write("\t\tUid %s\n" % trustMapping[index][1])
   1.321 +        outFileSym.write('\t\tName "%s"\n' % trustMapping[index][2])
   1.322 +    outFileSym.write("EndClientInfo\n")
   1.323 +    outFileSym.close()
   1.324 +inFileMoz.close()
   1.325 +
   1.326 +print "Invoking certapp tool to create the Symbian certificate store...",
   1.327 +certappCmd = "certapp" + \
   1.328 +             " --in --hca=" + outPath + outFileCaCerts + " --hcc=" + outPath + outFileCertClients + \
   1.329 +             " --out --bca=" + outPath + "cacerts.dat" + " --bcc=" + outPath + "certclients.dat"
   1.330 +
   1.331 +dummyFile = open(outPath + outCertAppOutput, "w")
   1.332 +p = subprocess.Popen(certappCmd, 0, None, None, dummyFile, dummyFile)
   1.333 +retcode = p.wait()
   1.334 +dummyFile.close()
   1.335 +
   1.336 +if (retcode != 0):
   1.337 +    print "\ncertapp returned error code: %d" % retcode
   1.338 +    print certappCmd
   1.339 +    print "For details see file " + outPath + outCertAppOutput
   1.340 +    print "Leaving temp files untouched for debugging"
   1.341 +else:
   1.342 +    print "done."
   1.343 +    print "Cleaning up temp files...",
   1.344 +    files = glob.glob(outPath + "certs\\*")
   1.345 +    for file in files:
   1.346 +       os.remove(file)
   1.347 +    os.rmdir(outPath + "certs")
   1.348 +    os.remove(outPath + outFileCaCerts)
   1.349 +    os.remove(outPath + outFileCertClients)
   1.350 +    os.remove(outPath + outCertAppOutput)
   1.351 +    print "done."
   1.352 +    print "Done. Read %d" % inRecNum + " certificates. Written %d" % outRecNum + " certificates.\n"