os/security/cryptoservices/browserrootcertificates/certconvert.py
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
#
sl@0
     2
# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     3
# All rights reserved.
sl@0
     4
# This component and the accompanying materials are made available
sl@0
     5
# under the terms of the License "Eclipse Public License v1.0"
sl@0
     6
# which accompanies this distribution, and is available
sl@0
     7
# at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     8
#
sl@0
     9
# Initial Contributors:
sl@0
    10
# Nokia Corporation - initial contribution.
sl@0
    11
#
sl@0
    12
# Contributors:
sl@0
    13
#
sl@0
    14
# Description: 
sl@0
    15
# Script to convert the Mozilla certificate store into the store format Symbian OS understands.
sl@0
    16
#
sl@0
    17
# Mozilla certificate store and its associated license is available at
sl@0
    18
# http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1
sl@0
    19
#
sl@0
    20
#
sl@0
    21
sl@0
    22
import string, getopt, sys, subprocess, glob, os
sl@0
    23
sl@0
    24
#
sl@0
    25
# Default input files
sl@0
    26
#
sl@0
    27
inFileMozillaCerts = "certdata.txt"
sl@0
    28
inFileTrustMapping = "trustmapping.txt"
sl@0
    29
sl@0
    30
#
sl@0
    31
# Output path (don't change this!) and other temp files
sl@0
    32
#
sl@0
    33
outPath = ".\\"
sl@0
    34
outFileCaCerts = "cacerts_text.txt"
sl@0
    35
outFileCertClients = "certclients_text.txt"
sl@0
    36
outCertAppOutput = "output.txt"
sl@0
    37
sl@0
    38
#
sl@0
    39
# Constants
sl@0
    40
#
sl@0
    41
ERROR_NONE = 0
sl@0
    42
ERROR_EOF = -1
sl@0
    43
ERROR_GENERAL = -2
sl@0
    44
sl@0
    45
#
sl@0
    46
# Class CertRecord
sl@0
    47
#
sl@0
    48
class CertRecord:
sl@0
    49
    def __init__(self, file):
sl@0
    50
        self.file = file
sl@0
    51
        # Read over the first CKA_CLASS record
sl@0
    52
        value = ""
sl@0
    53
        self.ReadTokenValue("CKA_CLASS")
sl@0
    54
        # Can we assert if value != "CKO_NETSCAPE_BUILTIN_ROOT_LIST"
sl@0
    55
sl@0
    56
    # Read and parse next record, return 0 if no more records exist
sl@0
    57
    def Next(self):
sl@0
    58
        # Read next certificate token
sl@0
    59
        err, value = self.ReadTokenValue("CKA_CLASS")
sl@0
    60
        if (err == ERROR_EOF):
sl@0
    61
            return err
sl@0
    62
        if (err != ERROR_NONE or value != "CKO_CERTIFICATE"):
sl@0
    63
            return err
sl@0
    64
sl@0
    65
        # Read the cert label
sl@0
    66
        err, self.certLabel = self.ReadTokenValue("CKA_LABEL")
sl@0
    67
        if (err != ERROR_NONE):
sl@0
    68
            return err
sl@0
    69
sl@0
    70
        # Read the cert type
sl@0
    71
        err, self.certType = self.ReadTokenValue("CKA_CERTIFICATE_TYPE")
sl@0
    72
        if (err != ERROR_NONE):
sl@0
    73
            return err
sl@0
    74
sl@0
    75
        # Read the cert serial number
sl@0
    76
        err, self.certSerialNum = self.ReadTokenValue("CKA_SERIAL_NUMBER")
sl@0
    77
        if (err != ERROR_NONE):
sl@0
    78
            return err
sl@0
    79
sl@0
    80
        # Read the actual cert data (DER encoded)
sl@0
    81
        err, self.certData = self.ReadTokenValue("CKA_VALUE")
sl@0
    82
        if (err != ERROR_NONE):
sl@0
    83
            return err
sl@0
    84
sl@0
    85
        # Read the trust details
sl@0
    86
        err, value = self.ReadTokenValue("CKA_CLASS")
sl@0
    87
        if (err != ERROR_NONE or value != "CKO_NETSCAPE_TRUST"):
sl@0
    88
            return err
sl@0
    89
sl@0
    90
        # Read the trust label and match it with cert label
sl@0
    91
        err, self.trustLabel = self.ReadTokenValue("CKA_LABEL")
sl@0
    92
        if (err != ERROR_NONE or self.trustLabel != self.certLabel):
sl@0
    93
            print "Certificate and Trust label mismatch or not found for cert " + self.certLabel
sl@0
    94
            return err
sl@0
    95
sl@0
    96
        # Read the SHA1 hash (aka thumbprint)
sl@0
    97
        err, self.trustSha1Hash = self.ReadTokenValue("CKA_CERT_SHA1_HASH")
sl@0
    98
sl@0
    99
        # Read the trust serial number and match it with cert serial number
sl@0
   100
        err, self.trustSerialNum = self.ReadTokenValue("CKA_SERIAL_NUMBER")
sl@0
   101
        if (err != ERROR_NONE or self.trustSerialNum != self.certSerialNum):
sl@0
   102
            print "Warning: Certificate and Trust serial number mismatch or not found for cert " + self.certLabel
sl@0
   103
sl@0
   104
        # Read the trust list. This has a variable token so can't use ReadTokenValue method
sl@0
   105
        err, self.trustTrustList = self.ReadTrustValues()
sl@0
   106
        if (err != ERROR_NONE):
sl@0
   107
            return err
sl@0
   108
sl@0
   109
        return ERROR_NONE
sl@0
   110
sl@0
   111
    def ReadTrustValues(self):
sl@0
   112
        # Keep reading lines till token "CKA_TRUST_STEP_UP_APPROVED" found
sl@0
   113
        trustList = []
sl@0
   114
        for line in self.file:
sl@0
   115
            line = line.rstrip('\n')
sl@0
   116
            fields = line.split(" ")
sl@0
   117
            if (len(fields) == 0):
sl@0
   118
                continue
sl@0
   119
            if (fields[0] == "CKA_TRUST_STEP_UP_APPROVED"):
sl@0
   120
                # Done reading trust settings
sl@0
   121
                return ERROR_NONE, trustList
sl@0
   122
                break
sl@0
   123
            if (fields[1] == "CK_TRUST"):
sl@0
   124
                if ((fields[2] == "CKT_NETSCAPE_TRUSTED_DELEGATOR")):
sl@0
   125
                    trustList.append(fields[0].strip())
sl@0
   126
            else:
sl@0
   127
                # Something is wrong
sl@0
   128
                print "Error reading trust settings. " + line
sl@0
   129
                return ERROR_GENERAL, []
sl@0
   130
sl@0
   131
        # End of file?
sl@0
   132
        if (line == ""):
sl@0
   133
            return ERROR_EOF, ""
sl@0
   134
        print "Error in ReadTrustValues(). Token ('CKA_TRUST_STEP_UP_APPROVED') not found!"
sl@0
   135
        return ERROR_GENERAL, ""
sl@0
   136
sl@0
   137
    def ReadTokenValue(self, token):
sl@0
   138
        # Keep reading lines till token found
sl@0
   139
        for line in self.file:
sl@0
   140
            line = line.rstrip('\n')
sl@0
   141
            fields = line.split(" ")
sl@0
   142
            if (len(fields) == 0):
sl@0
   143
                continue
sl@0
   144
            if (fields[0] == token):
sl@0
   145
                if (fields[1] != "MULTILINE_OCTAL"):
sl@0
   146
                    value = " ".join(fields[2:])
sl@0
   147
                    return ERROR_NONE, value
sl@0
   148
                else:
sl@0
   149
                    # Read multiline octal value till END
sl@0
   150
                    value=""
sl@0
   151
                    for nextline in self.file:
sl@0
   152
                        nextline = nextline.rstrip('\n')
sl@0
   153
                        if (nextline == "END"):
sl@0
   154
                            break
sl@0
   155
                        if (nextline != ""):
sl@0
   156
                            # Convert string of octal to binary data
sl@0
   157
                            # There must be an easier way than this!
sl@0
   158
                            octalWordList = nextline.split("\\")
sl@0
   159
                            for octalWord in octalWordList:
sl@0
   160
                                if (octalWord != ""):
sl@0
   161
                                    value = value + chr(int(octalWord, 8))
sl@0
   162
                        else:
sl@0
   163
                            print "ReadTokenValue(" + token + ") awaiting END. Unexpected end of file!"
sl@0
   164
                            return ERROR_EOF, ""
sl@0
   165
                    return ERROR_NONE, value
sl@0
   166
sl@0
   167
        #print "ReadTokenValue(" + token + "). Token not found!"
sl@0
   168
        return ERROR_EOF, ""
sl@0
   169
sl@0
   170
#
sl@0
   171
# Global function ReadTrustMapping()
sl@0
   172
#
sl@0
   173
def ReadTrustMapping(file):
sl@0
   174
    trustMapping = []
sl@0
   175
    for line in file:
sl@0
   176
        line = line.rstrip('\n')
sl@0
   177
        if (line == "" or line[0] == "#"):
sl@0
   178
            continue
sl@0
   179
        fields = line.split(",")
sl@0
   180
        if (len(fields) == 0):
sl@0
   181
            continue
sl@0
   182
        if ((len(fields) % 2) != 1):
sl@0
   183
            print "Error in file '%s' in line '%s'\n" % inFileTrustMapping % line
sl@0
   184
            return GENERAL_ERROR, [[]]
sl@0
   185
        mozTrust = fields[0].strip()
sl@0
   186
        for index in range(1, len(fields), 2):
sl@0
   187
            appUID = fields[index].strip()
sl@0
   188
            appName = fields[index + 1].strip()
sl@0
   189
            trustMapping.append([mozTrust, appUID, appName])
sl@0
   190
    return ERROR_NONE, trustMapping
sl@0
   191
sl@0
   192
#
sl@0
   193
# Global function ReadCommandlineArgs()
sl@0
   194
#
sl@0
   195
def ReadCommandlineArgs(argv):
sl@0
   196
    try:
sl@0
   197
        flags, args = getopt.getopt(argv[1:], "hm:t:", ["help", "mozilla=", "trust="])
sl@0
   198
    except getopt.GetoptError, err:
sl@0
   199
        # Print usage
sl@0
   200
        print str(err) + "\n"
sl@0
   201
        PrintUsage()
sl@0
   202
        sys.exit(-1)
sl@0
   203
    for flag, arg in flags:
sl@0
   204
        if flag in ("-h", "--help"):
sl@0
   205
            PrintUsage()
sl@0
   206
            sys.exit()
sl@0
   207
        elif flag in ("-m", "--mozilla"):
sl@0
   208
            globals()["inFileMozillaCerts"] = arg
sl@0
   209
        elif flag in ("-t", "--trust"):
sl@0
   210
            globals()["inFileTrustMapping"] = arg
sl@0
   211
    print "certconvert - This script converts the Mozilla certificate store into Symbian OS certificate store."
sl@0
   212
    print "\nInput Mozilla store file: %s" % globals()["inFileMozillaCerts"]
sl@0
   213
    print "Input trust mapping: %s" % globals()["inFileTrustMapping"]
sl@0
   214
sl@0
   215
#
sl@0
   216
#
sl@0
   217
#
sl@0
   218
def PrintUsage():
sl@0
   219
    print "certconvert - This script converts the Mozilla certificate store into Symbian OS certificate store."
sl@0
   220
    print "It uses certapp for the conversion so certapp must be in the path."
sl@0
   221
    print "Usage: certconvert [-h] | [-m <file> -t <file>] [-o <outpath>]"
sl@0
   222
    print "where:"
sl@0
   223
    print "-h | --help\tshows this help"
sl@0
   224
    print "-m | --mozilla\tis used to specify the Mozilla certificate store input file."
sl@0
   225
    print "\t\tIf not specified default is taken as 'certdata.txt'."
sl@0
   226
    print "-t | --trust\tis used to specify the input trust mapping input file."
sl@0
   227
    print "\t\tThis file maps the trust settings from the Mozilla store to "
sl@0
   228
    print "\t\tSymbian's applications and uids."
sl@0
   229
    print "\t\tIf not specified default is taken as 'trustmapping.txt'."
sl@0
   230
sl@0
   231
#
sl@0
   232
# Main starts here
sl@0
   233
#
sl@0
   234
sl@0
   235
# Read and process command line arguments
sl@0
   236
ReadCommandlineArgs(sys.argv)
sl@0
   237
sl@0
   238
# First read the trust mappings file
sl@0
   239
print "Reading trust mapping file...",
sl@0
   240
file = open(inFileTrustMapping, "r")
sl@0
   241
err, trustMapping = ReadTrustMapping(file)
sl@0
   242
if (err != ERROR_NONE):
sl@0
   243
    print "\nError reading trust mapping file!\n"
sl@0
   244
    sys.exit(-1)
sl@0
   245
file.close()
sl@0
   246
print "done."
sl@0
   247
sl@0
   248
print "Reading Mozilla certificate store and processing certificates",
sl@0
   249
inFileMoz=open(inFileMozillaCerts, "r")
sl@0
   250
record = CertRecord(inFileMoz)
sl@0
   251
inRecNum = outRecNum = 0
sl@0
   252
while (record.Next() == ERROR_NONE):
sl@0
   253
    inRecNum = inRecNum + 1
sl@0
   254
    #print "Read record %d: %s" % (inRecNum, record.certLabel)
sl@0
   255
    # Do filtering of records (if any)
sl@0
   256
    
sl@0
   257
    outRecNum = outRecNum + 1
sl@0
   258
    # Create the human readable filecertstore entry
sl@0
   259
    if (outRecNum == 1):
sl@0
   260
        if (os.path.exists(outPath) == False):
sl@0
   261
            os.makedirs(outPath)
sl@0
   262
        if (os.path.exists(outPath + "\\certs") == False):
sl@0
   263
            os.makedirs(outPath + "\\certs")
sl@0
   264
        outFileSym = open(outPath + outFileCaCerts, "w")
sl@0
   265
        outFileSym.write("StartCertStoreEntries\n")
sl@0
   266
sl@0
   267
    outFileSym.write("\t# Entry %d\n" % outRecNum)
sl@0
   268
sl@0
   269
    # Write out the SHA1 hash of the certificate (to make it easier to compare certs)
sl@0
   270
    # Convert to hex
sl@0
   271
    sha1hash = ""
sl@0
   272
    #octalWordList = record.trustSha1Hash.split("\\")
sl@0
   273
    for index in range(0, len(record.trustSha1Hash)):
sl@0
   274
        hexdigits = hex(ord(record.trustSha1Hash[index]))[2:]
sl@0
   275
        hexdigits = hexdigits.zfill(2)
sl@0
   276
        sha1hash = sha1hash + hexdigits + " "
sl@0
   277
    outFileSym.write("\t# Thumbprint(hex) %s\n" % sha1hash)
sl@0
   278
sl@0
   279
    outFileSym.write("\tStartEntry " + record.certLabel + "\n")
sl@0
   280
    outFileSym.write("\t\tDeletable true\n")
sl@0
   281
    outFileSym.write("\t\tFormat EX509Certificate\n")
sl@0
   282
    outFileSym.write("\t\tCertOwnerType ECACertificate\n")
sl@0
   283
    outFileSym.write("\t\tSubjectKeyId auto\n")
sl@0
   284
    outFileSym.write("\t\tIssuerKeyId auto\n")
sl@0
   285
sl@0
   286
    # Write out trust details
sl@0
   287
    outFileSym.write("\t\tStartApplicationList\n")
sl@0
   288
    for trust in record.trustTrustList:
sl@0
   289
        # Look for the mapping
sl@0
   290
        for mapping in trustMapping:
sl@0
   291
            if (trust == mapping[0]):
sl@0
   292
                # Found a mapping. Add it and keep on looking since
sl@0
   293
                # there could be more than one app mapping
sl@0
   294
                outFileSym.write('\t\t\tApplication "' + mapping[2] + '"\n');
sl@0
   295
    outFileSym.write("\t\tEndApplicationList\n")
sl@0
   296
    outFileSym.write("\t\tTrusted true\n")
sl@0
   297
    certFileName = "certs\\\\cert%04d" % outRecNum + ".der"
sl@0
   298
    outFileSym.write('\t\tDataFileName "' + certFileName + '"\n')
sl@0
   299
    outFileSym.write("\tEndEntry\n\n")
sl@0
   300
    # Write the certificate file
sl@0
   301
    outFileCert = open(outPath + certFileName, "wb")
sl@0
   302
    outFileCert.write(record.certData)
sl@0
   303
    outFileCert.close()
sl@0
   304
    print ".",
sl@0
   305
sl@0
   306
if (outRecNum > 0):
sl@0
   307
    outFileSym.write("EndCertStoreEntries\n")
sl@0
   308
    outFileSym.close()
sl@0
   309
print "done."
sl@0
   310
sl@0
   311
# Finally create the app to uid mapping file for Symbian OS
sl@0
   312
if (outRecNum > 0):
sl@0
   313
    outFileSym = open(outPath + outFileCertClients, "w")
sl@0
   314
    outFileSym.write("StartClientInfo\n")
sl@0
   315
    for index in range(0, len(trustMapping)):
sl@0
   316
        outFileSym.write("\t#Entry %d\n" % (index + 1))
sl@0
   317
        outFileSym.write("\t\tUid %s\n" % trustMapping[index][1])
sl@0
   318
        outFileSym.write('\t\tName "%s"\n' % trustMapping[index][2])
sl@0
   319
    outFileSym.write("EndClientInfo\n")
sl@0
   320
    outFileSym.close()
sl@0
   321
inFileMoz.close()
sl@0
   322
sl@0
   323
print "Invoking certapp tool to create the Symbian certificate store...",
sl@0
   324
certappCmd = "certapp" + \
sl@0
   325
             " --in --hca=" + outPath + outFileCaCerts + " --hcc=" + outPath + outFileCertClients + \
sl@0
   326
             " --out --bca=" + outPath + "cacerts.dat" + " --bcc=" + outPath + "certclients.dat"
sl@0
   327
sl@0
   328
dummyFile = open(outPath + outCertAppOutput, "w")
sl@0
   329
p = subprocess.Popen(certappCmd, 0, None, None, dummyFile, dummyFile)
sl@0
   330
retcode = p.wait()
sl@0
   331
dummyFile.close()
sl@0
   332
sl@0
   333
if (retcode != 0):
sl@0
   334
    print "\ncertapp returned error code: %d" % retcode
sl@0
   335
    print certappCmd
sl@0
   336
    print "For details see file " + outPath + outCertAppOutput
sl@0
   337
    print "Leaving temp files untouched for debugging"
sl@0
   338
else:
sl@0
   339
    print "done."
sl@0
   340
    print "Cleaning up temp files...",
sl@0
   341
    files = glob.glob(outPath + "certs\\*")
sl@0
   342
    for file in files:
sl@0
   343
       os.remove(file)
sl@0
   344
    os.rmdir(outPath + "certs")
sl@0
   345
    os.remove(outPath + outFileCaCerts)
sl@0
   346
    os.remove(outPath + outFileCertClients)
sl@0
   347
    os.remove(outPath + outCertAppOutput)
sl@0
   348
    print "done."
sl@0
   349
    print "Done. Read %d" % inRecNum + " certificates. Written %d" % outRecNum + " certificates.\n"