summaryrefslogtreecommitdiffstats
path: root/chrome/common/extensions/docs/static/crx.html
blob: 422148b6371805c0e87cfd84e3c5c1c13bec4ccb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
<div id="pageData-name" class="pageData">CRX Package Format</div>
<div id="pageData-showTOC" class="pageData">true</div>

<p>
CRX files are ZIP files with a special header and the <code>.crx</code> file
extension.
</p>

<h2>Package header</h2>

<p>
The header contains the author's public key and the extension's signature. 
The signature is generated from the ZIP file using SHA-1 with the
author's private key. The header requires a little-endian byte ordering with 
4-byte alignment. The following table describes the fields of
the <code>.crx</code> header in order:
</p>

<table>
  <tr>
    <th>Field</th><th>Type</th><th>Length</th><th>Value</th><th>Description</th>
  </tr>
  <tr>
    <td><em>magic number</em></td><td>char[]</td><td>32 bits</td><td>Cr24</td>
    <td>
      Chrome requires this constant at the beginning of every <code>.crx</code>
      package.
    </td>
  </tr>
  <tr>
    <td><em>version</em></td><td>unsigned&nbsp;int</td><td>32 bits</td><td>2</td>
    <td>The version of the <code>*.crx</code> file format used (currently 2).</td> 
  </tr>
  <tr>
    <td><em>public key length</em></td><td>unsigned&nbsp;int</td><td>32 bits</td>
    <td><i>pubkey.length</i></td>
    <td>
      The length of the RSA public key in <em>bytes</em>.
    </td>
  </tr>
  <tr>
    <td><em>signature length</em></td><td>unsigned&nbsp;int</td><td>32 bits</td>
    <td><i>sig.length</i></td>
    <td>
      The length of the signature in <em>bytes</em>.
    </td>
  </tr>
  <tr>
    <td><em>public key</em></td><td>byte[]</td><td><i>pubkey.length</i></i></td>
    <td><i>pubkey.contents</i></td>
    <td>
      The contents of the author's RSA public key, formatted as an X509 
      SubjectPublicKeyInfo block.
    </td>
  </tr>
  <tr>
    <td><em>signature</em></td><td>byte[]</td><td><i>sig.length</i></td>
    <td><i>sig.contents</i></td>
    <td>
      The signature of the ZIP content using the author's private key. The
      signature is created using the RSA algorithm with the SHA-1 hash function.
    </td>
  </tr>
</table>

<h2>Extension contents</h2>

<p>
The extension's ZIP file is appended to the <code>*.crx</code> package after the
header. This should be the same ZIP file that the signature in the header
was generated from.
</p>

<h2>Example</h2>

<p>
The following is an example hex dump from the beginning of a <code>.crx</code> 
file.
</p>

<pre>
43 72 32 34   # "Cr24" -- the magic number
02 00 00 00   # 2 -- the crx format version number
A2 00 00 00   # 162 -- length of public key in bytes
80 00 00 00   # 128 -- length of signature in bytes
...........   # the contents of the public key
...........   # the contents of the signature
...........   # the contents of the zip file

</pre>

<h2 id="scripts">Packaging scripts</h2>
<p>
Members of the community have written the following scripts to package 
<code>.crx</code> files.
</p>

<h3 id="ruby">Ruby</h3>
<blockquote>
<a href="http://github.com/Constellation/crxmake">github: crxmake</a>
</blockquote>

<h3>Bash</h3>
<pre>
#!/bin/bash -e
#
# Purpose: Pack a Chromium extension directory into crx format

if test $# -ne 2; then
  echo "Usage: crxmake.sh &lt;extension dir&gt; &lt;pem path&gt;"
  exit 1
fi

dir=$1
key=$2
name=$(basename "$dir")
crx="$name.crx"
pub="$name.pub"
sig="$name.sig"
zip="$name.zip"
trap 'rm -f "$pub" "$sig" "$zip"' EXIT

# zip up the crx dir
cwd=$(pwd -P)
(cd "$dir" && zip -qr -9 -X "$cwd/$zip" .)

# signature
openssl sha1 -sha1 -binary -sign "$key" < "$zip" > "$sig"

# public key
openssl rsa -pubout -outform DER < "$key" > "$pub" 2>/dev/null

byte_swap () {
  # Take "abcdefgh" and return it as "ghefcdab"
  echo "${1:6:2}${1:4:2}${1:2:2}${1:0:2}"
}

crmagic_hex="4372 3234" # Cr24
version_hex="0200 0000" # 2
pub_len_hex=$(byte_swap $(printf '%08x\n' $(ls -l "$pub" | awk '{print $5}')))
sig_len_hex=$(byte_swap $(printf '%08x\n' $(ls -l "$sig" | awk '{print $5}')))
(
  echo "$crmagic_hex $version_hex $pub_len_hex $sig_len_hex" | xxd -r -p
  cat "$pub" "$sig" "$zip"
) > "$crx"
echo "Wrote $crx"
</pre>