First public contribution.
2 # Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 # This component and the accompanying materials are made available
5 # under the terms of the License "Eclipse Public License v1.0"
6 # which accompanies this distribution, and is available
7 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
9 # Initial Contributors:
10 # Nokia Corporation - initial contribution.
15 # Script to convert the Mozilla certificate store into the store format Symbian OS understands.
17 # Mozilla certificate store and its associated license is available at
18 # http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1
22 import string, getopt, sys, subprocess, glob, os
27 inFileMozillaCerts = "certdata.txt"
28 inFileTrustMapping = "trustmapping.txt"
31 # Output path (don't change this!) and other temp files
34 outFileCaCerts = "cacerts_text.txt"
35 outFileCertClients = "certclients_text.txt"
36 outCertAppOutput = "output.txt"
49 def __init__(self, file):
51 # Read over the first CKA_CLASS record
53 self.ReadTokenValue("CKA_CLASS")
54 # Can we assert if value != "CKO_NETSCAPE_BUILTIN_ROOT_LIST"
56 # Read and parse next record, return 0 if no more records exist
58 # Read next certificate token
59 err, value = self.ReadTokenValue("CKA_CLASS")
60 if (err == ERROR_EOF):
62 if (err != ERROR_NONE or value != "CKO_CERTIFICATE"):
66 err, self.certLabel = self.ReadTokenValue("CKA_LABEL")
67 if (err != ERROR_NONE):
71 err, self.certType = self.ReadTokenValue("CKA_CERTIFICATE_TYPE")
72 if (err != ERROR_NONE):
75 # Read the cert serial number
76 err, self.certSerialNum = self.ReadTokenValue("CKA_SERIAL_NUMBER")
77 if (err != ERROR_NONE):
80 # Read the actual cert data (DER encoded)
81 err, self.certData = self.ReadTokenValue("CKA_VALUE")
82 if (err != ERROR_NONE):
85 # Read the trust details
86 err, value = self.ReadTokenValue("CKA_CLASS")
87 if (err != ERROR_NONE or value != "CKO_NETSCAPE_TRUST"):
90 # Read the trust label and match it with cert label
91 err, self.trustLabel = self.ReadTokenValue("CKA_LABEL")
92 if (err != ERROR_NONE or self.trustLabel != self.certLabel):
93 print "Certificate and Trust label mismatch or not found for cert " + self.certLabel
96 # Read the SHA1 hash (aka thumbprint)
97 err, self.trustSha1Hash = self.ReadTokenValue("CKA_CERT_SHA1_HASH")
99 # Read the trust serial number and match it with cert serial number
100 err, self.trustSerialNum = self.ReadTokenValue("CKA_SERIAL_NUMBER")
101 if (err != ERROR_NONE or self.trustSerialNum != self.certSerialNum):
102 print "Warning: Certificate and Trust serial number mismatch or not found for cert " + self.certLabel
104 # Read the trust list. This has a variable token so can't use ReadTokenValue method
105 err, self.trustTrustList = self.ReadTrustValues()
106 if (err != ERROR_NONE):
111 def ReadTrustValues(self):
112 # Keep reading lines till token "CKA_TRUST_STEP_UP_APPROVED" found
114 for line in self.file:
115 line = line.rstrip('\n')
116 fields = line.split(" ")
117 if (len(fields) == 0):
119 if (fields[0] == "CKA_TRUST_STEP_UP_APPROVED"):
120 # Done reading trust settings
121 return ERROR_NONE, trustList
123 if (fields[1] == "CK_TRUST"):
124 if ((fields[2] == "CKT_NETSCAPE_TRUSTED_DELEGATOR")):
125 trustList.append(fields[0].strip())
128 print "Error reading trust settings. " + line
129 return ERROR_GENERAL, []
134 print "Error in ReadTrustValues(). Token ('CKA_TRUST_STEP_UP_APPROVED') not found!"
135 return ERROR_GENERAL, ""
137 def ReadTokenValue(self, token):
138 # Keep reading lines till token found
139 for line in self.file:
140 line = line.rstrip('\n')
141 fields = line.split(" ")
142 if (len(fields) == 0):
144 if (fields[0] == token):
145 if (fields[1] != "MULTILINE_OCTAL"):
146 value = " ".join(fields[2:])
147 return ERROR_NONE, value
149 # Read multiline octal value till END
151 for nextline in self.file:
152 nextline = nextline.rstrip('\n')
153 if (nextline == "END"):
156 # Convert string of octal to binary data
157 # There must be an easier way than this!
158 octalWordList = nextline.split("\\")
159 for octalWord in octalWordList:
160 if (octalWord != ""):
161 value = value + chr(int(octalWord, 8))
163 print "ReadTokenValue(" + token + ") awaiting END. Unexpected end of file!"
165 return ERROR_NONE, value
167 #print "ReadTokenValue(" + token + "). Token not found!"
171 # Global function ReadTrustMapping()
173 def ReadTrustMapping(file):
176 line = line.rstrip('\n')
177 if (line == "" or line[0] == "#"):
179 fields = line.split(",")
180 if (len(fields) == 0):
182 if ((len(fields) % 2) != 1):
183 print "Error in file '%s' in line '%s'\n" % inFileTrustMapping % line
184 return GENERAL_ERROR, [[]]
185 mozTrust = fields[0].strip()
186 for index in range(1, len(fields), 2):
187 appUID = fields[index].strip()
188 appName = fields[index + 1].strip()
189 trustMapping.append([mozTrust, appUID, appName])
190 return ERROR_NONE, trustMapping
193 # Global function ReadCommandlineArgs()
195 def ReadCommandlineArgs(argv):
197 flags, args = getopt.getopt(argv[1:], "hm:t:", ["help", "mozilla=", "trust="])
198 except getopt.GetoptError, err:
200 print str(err) + "\n"
203 for flag, arg in flags:
204 if flag in ("-h", "--help"):
207 elif flag in ("-m", "--mozilla"):
208 globals()["inFileMozillaCerts"] = arg
209 elif flag in ("-t", "--trust"):
210 globals()["inFileTrustMapping"] = arg
211 print "certconvert - This script converts the Mozilla certificate store into Symbian OS certificate store."
212 print "\nInput Mozilla store file: %s" % globals()["inFileMozillaCerts"]
213 print "Input trust mapping: %s" % globals()["inFileTrustMapping"]
219 print "certconvert - This script converts the Mozilla certificate store into Symbian OS certificate store."
220 print "It uses certapp for the conversion so certapp must be in the path."
221 print "Usage: certconvert [-h] | [-m <file> -t <file>] [-o <outpath>]"
223 print "-h | --help\tshows this help"
224 print "-m | --mozilla\tis used to specify the Mozilla certificate store input file."
225 print "\t\tIf not specified default is taken as 'certdata.txt'."
226 print "-t | --trust\tis used to specify the input trust mapping input file."
227 print "\t\tThis file maps the trust settings from the Mozilla store to "
228 print "\t\tSymbian's applications and uids."
229 print "\t\tIf not specified default is taken as 'trustmapping.txt'."
235 # Read and process command line arguments
236 ReadCommandlineArgs(sys.argv)
238 # First read the trust mappings file
239 print "Reading trust mapping file...",
240 file = open(inFileTrustMapping, "r")
241 err, trustMapping = ReadTrustMapping(file)
242 if (err != ERROR_NONE):
243 print "\nError reading trust mapping file!\n"
248 print "Reading Mozilla certificate store and processing certificates",
249 inFileMoz=open(inFileMozillaCerts, "r")
250 record = CertRecord(inFileMoz)
251 inRecNum = outRecNum = 0
252 while (record.Next() == ERROR_NONE):
253 inRecNum = inRecNum + 1
254 #print "Read record %d: %s" % (inRecNum, record.certLabel)
255 # Do filtering of records (if any)
257 outRecNum = outRecNum + 1
258 # Create the human readable filecertstore entry
260 if (os.path.exists(outPath) == False):
262 if (os.path.exists(outPath + "\\certs") == False):
263 os.makedirs(outPath + "\\certs")
264 outFileSym = open(outPath + outFileCaCerts, "w")
265 outFileSym.write("StartCertStoreEntries\n")
267 outFileSym.write("\t# Entry %d\n" % outRecNum)
269 # Write out the SHA1 hash of the certificate (to make it easier to compare certs)
272 #octalWordList = record.trustSha1Hash.split("\\")
273 for index in range(0, len(record.trustSha1Hash)):
274 hexdigits = hex(ord(record.trustSha1Hash[index]))[2:]
275 hexdigits = hexdigits.zfill(2)
276 sha1hash = sha1hash + hexdigits + " "
277 outFileSym.write("\t# Thumbprint(hex) %s\n" % sha1hash)
279 outFileSym.write("\tStartEntry " + record.certLabel + "\n")
280 outFileSym.write("\t\tDeletable true\n")
281 outFileSym.write("\t\tFormat EX509Certificate\n")
282 outFileSym.write("\t\tCertOwnerType ECACertificate\n")
283 outFileSym.write("\t\tSubjectKeyId auto\n")
284 outFileSym.write("\t\tIssuerKeyId auto\n")
286 # Write out trust details
287 outFileSym.write("\t\tStartApplicationList\n")
288 for trust in record.trustTrustList:
289 # Look for the mapping
290 for mapping in trustMapping:
291 if (trust == mapping[0]):
292 # Found a mapping. Add it and keep on looking since
293 # there could be more than one app mapping
294 outFileSym.write('\t\t\tApplication "' + mapping[2] + '"\n');
295 outFileSym.write("\t\tEndApplicationList\n")
296 outFileSym.write("\t\tTrusted true\n")
297 certFileName = "certs\\\\cert%04d" % outRecNum + ".der"
298 outFileSym.write('\t\tDataFileName "' + certFileName + '"\n')
299 outFileSym.write("\tEndEntry\n\n")
300 # Write the certificate file
301 outFileCert = open(outPath + certFileName, "wb")
302 outFileCert.write(record.certData)
307 outFileSym.write("EndCertStoreEntries\n")
311 # Finally create the app to uid mapping file for Symbian OS
313 outFileSym = open(outPath + outFileCertClients, "w")
314 outFileSym.write("StartClientInfo\n")
315 for index in range(0, len(trustMapping)):
316 outFileSym.write("\t#Entry %d\n" % (index + 1))
317 outFileSym.write("\t\tUid %s\n" % trustMapping[index][1])
318 outFileSym.write('\t\tName "%s"\n' % trustMapping[index][2])
319 outFileSym.write("EndClientInfo\n")
323 print "Invoking certapp tool to create the Symbian certificate store...",
324 certappCmd = "certapp" + \
325 " --in --hca=" + outPath + outFileCaCerts + " --hcc=" + outPath + outFileCertClients + \
326 " --out --bca=" + outPath + "cacerts.dat" + " --bcc=" + outPath + "certclients.dat"
328 dummyFile = open(outPath + outCertAppOutput, "w")
329 p = subprocess.Popen(certappCmd, 0, None, None, dummyFile, dummyFile)
334 print "\ncertapp returned error code: %d" % retcode
336 print "For details see file " + outPath + outCertAppOutput
337 print "Leaving temp files untouched for debugging"
340 print "Cleaning up temp files...",
341 files = glob.glob(outPath + "certs\\*")
344 os.rmdir(outPath + "certs")
345 os.remove(outPath + outFileCaCerts)
346 os.remove(outPath + outFileCertClients)
347 os.remove(outPath + outCertAppOutput)
349 print "Done. Read %d" % inRecNum + " certificates. Written %d" % outRecNum + " certificates.\n"