193c364cc7ef9f357cbcc05b6c0356ea13505a37
[platform/framework/web/crosswalk.git] / src / xwalk / app / tools / android / parse_xpk.py
1 #!/usr/bin/env python
2 # Copyright (c) 2013 Intel Corporation. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 # pylint: disable=C0301
7 """The script is used to parse an XPK file.
8
9 It will do:
10 1. Check the magic file header;
11 2. Verify the signature of the XPK file;
12 3. Extract the content of the XPK file to some folder.
13
14 The format of XPK file can be found at
15 https://github.com/crosswalk-project/crosswalk-website/wiki/Crosswalk-package-management
16
17 This file is used by make_apk.py.
18 """
19
20 import optparse
21 import os
22 import struct
23 import sys
24 import zipfile
25
26 EXIT_CODE_CRYPTO_NOT_FOUND = 1
27 EXIT_CODE_NO_XPK_FILE = 2
28 EXIT_CODE_XPK_FILE_NOT_EXIST = 3
29 EXIT_CODE_MAGIC_FAILED = 4
30 EXIT_CODE_VERIFICATION_FAILED = 5
31 EXIT_CODE_XPK_FILE_IO_ERROR = 6
32
33 XPK_MAGIC_HEAD = 'CrWk'
34
35 errorMessageMap = {
36   EXIT_CODE_CRYPTO_NOT_FOUND: 'Python module Crypto('\
37       'https://www.dlitz.net/software/pycrypto/) is needed',
38   EXIT_CODE_NO_XPK_FILE: 'Please specify XPK file by --file',
39   EXIT_CODE_XPK_FILE_NOT_EXIST: 'The XPK file you specified does not exist',
40   EXIT_CODE_MAGIC_FAILED: 'The file you specified is not in XPK format',
41   EXIT_CODE_VERIFICATION_FAILED:
42       'Signature verification failed for the XPK file',
43   EXIT_CODE_XPK_FILE_IO_ERROR: 'Error happened when reading the XPK file',
44 }
45
46
47 def HandleError(err_code):
48   print('Error: %s' % errorMessageMap[err_code])
49   sys.exit(err_code)
50
51
52 try:
53   from Crypto.PublicKey import RSA
54   from Crypto.Signature import PKCS1_v1_5
55   from Crypto.Hash import SHA
56 except ImportError:
57   HandleError(EXIT_CODE_CRYPTO_NOT_FOUND)
58
59
60 def CheckMagic(input_file):
61   magic = input_file.read(4)
62   if magic != XPK_MAGIC_HEAD:
63     HandleError(EXIT_CODE_MAGIC_FAILED)
64
65
66 def GetPubkeySignature(input_file):
67   """Return (pubkey, signature) pair"""
68   pubkey_size, signature_size = struct.unpack('II', input_file.read(8))
69   return (input_file.read(pubkey_size), input_file.read(signature_size))
70
71
72 def ExtractXPKContent(input_file, zip_path):
73   zip_file = open(zip_path, 'wb')
74   zip_file.write(input_file.read())
75   zip_file.close()
76
77
78 def VerifySignature(pubkey, signature, zip_path):
79   zip_file = open(zip_path, 'rb')
80   key = RSA.importKey(pubkey)
81   content = SHA.new(zip_file.read())
82   zip_file.close()
83   verifier = PKCS1_v1_5.new(key)
84   if not verifier.verify(content, signature):
85     HandleError(EXIT_CODE_VERIFICATION_FAILED)
86
87
88 def main():
89   option_parser = optparse.OptionParser()
90   option_parser.add_option('--file', '-f', help='Path to the xpk file')
91   option_parser.add_option('--out', '-o', help='Path to extract the xpk to')
92
93   opts, _ = option_parser.parse_args()
94
95   if opts.file == None:
96     HandleError(EXIT_CODE_NO_XPK_FILE)
97
98   app_name = os.path.splitext(os.path.basename(opts.file))[0]
99
100   if opts.out == None:
101     opts.out = app_name
102
103   if os.path.isfile(opts.file):
104     zip_path = None
105     try:
106       xpk_file = open(opts.file, 'rb')
107       CheckMagic(xpk_file)
108       pubkey, signature = GetPubkeySignature(xpk_file)
109       zip_path = '%s.zip' % app_name
110       ExtractXPKContent(xpk_file, zip_path)
111       VerifySignature(pubkey, signature, zip_path)
112       zipfile.ZipFile(zip_path).extractall(opts.out)
113     except SystemExit as ec:
114       return ec.code
115     except IOError:
116       HandleError(EXIT_CODE_XPK_FILE_IO_ERROR)
117     finally:
118       xpk_file.close()
119       if zip_path and os.path.isfile(zip_path):
120         os.remove(zip_path)
121   else:
122     HandleError(EXIT_CODE_XPK_FILE_NOT_EXIST)
123
124
125 if __name__ == '__main__':
126   sys.exit(main())