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"