Skip to content
This repository was archived by the owner on Mar 15, 2018. It is now read-only.

Commit 540bfe3

Browse files
author
Andy McKay
committed
a proof of concept on signing (bug 791741)
1 parent 9da027e commit 540bfe3

File tree

7 files changed

+148
-24
lines changed

7 files changed

+148
-24
lines changed

apps/amo/tests/__init__.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -409,8 +409,12 @@ def manifest_copy_over(self, dest, name):
409409

410410
@staticmethod
411411
def sample_key():
412-
path = 'mkt/webapps/tests/sample.key'
413-
return os.path.join(settings.ROOT, path)
412+
return os.path.join(settings.ROOT,
413+
'mkt/webapps/tests/sample.key')
414+
415+
def sample_packaged_key(self):
416+
return os.path.join(settings.ROOT,
417+
'mkt/webapps/tests/sample.packaged.pem')
414418

415419
def mozball_image(self):
416420
return os.path.join(settings.ROOT,

lib/crypto/packaged.py

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1+
import os
2+
3+
from django.conf import settings
14
from django.core.files.storage import default_storage as storage
25

36
from celeryutils import task
47
import commonware.log
8+
from django_statsd.clients import statsd
9+
from xpisign import xpisign
510

611
import amo
712
from versions.models import Version
@@ -13,6 +18,25 @@ class SigningError(Exception):
1318
pass
1419

1520

21+
def sign_app(src, dest):
22+
if settings.SIGNED_APPS_SERVER_ACTIVE:
23+
# At some point this will be implemented, but not now.
24+
raise NotImplementedError
25+
26+
if not os.path.exists(settings.SIGNED_APPS_KEY):
27+
raise ValueError('The signed apps key cannot be found.')
28+
29+
# TODO: stop doing this and use the signing server.
30+
try:
31+
# Not sure this will work too well on S3.
32+
xpisign(storage.open(src, 'r'), settings.SIGNED_APPS_KEY,
33+
storage.open(dest, 'w'))
34+
except:
35+
# TODO: figure out some likely errors that can occur.
36+
log.error('Signing failed', exc_info=True)
37+
raise
38+
39+
1640
@task
1741
def sign(version_id, reviewer=False):
1842
version = Version.objects.get(pk=version_id)
@@ -40,17 +64,7 @@ def sign(version_id, reviewer=False):
4064
return path
4165

4266
# When we know how to sign, we will sign. For the moment, let's copy.
43-
dest = storage.open(path, 'w')
44-
src = storage.open(file_obj.file_path, 'r')
45-
# I'm not sure if this makes sense with an S3 backend.
46-
while 1:
47-
buffer = src.read(1024 * 1024)
48-
if buffer:
49-
dest.write(buffer)
50-
else:
51-
break
52-
53-
dest.close()
54-
src.close()
67+
with statsd.timer('services.sign.app'):
68+
sign_app(file_obj.file_path, path)
5569
log.info('Signing complete.')
5670
return path

lib/crypto/receipt.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def sign(receipt):
3838
request = urllib2.Request(destination, data, headers)
3939

4040
try:
41-
with statsd.timer('services.sign'):
41+
with statsd.timer('services.sign.receipt'):
4242
response = urllib2.urlopen(request, timeout=timeout)
4343
except urllib2.HTTPError, error:
4444
# Will occur when a 3xx or greater code is returned

lib/crypto/tests.py

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from nose.tools import eq_, raises
1212

1313
import amo.tests
14+
from files.utils import SafeUnzip
1415
from lib.crypto import packaged
1516
from lib.crypto.receipt import crack, sign, SigningError
1617
from mkt.webapps.models import Webapp
@@ -89,6 +90,10 @@ def setup_files(self):
8990

9091
class TestPackaged(PackagedApp, amo.tests.TestCase):
9192

93+
def setUp(self):
94+
super(TestPackaged, self).setUp()
95+
self.setup_files()
96+
9297
@raises(packaged.SigningError)
9398
def test_not_app(self):
9499
self.app.update(type=amo.ADDON_EXTENSION)
@@ -108,15 +113,35 @@ def test_already_exists(self):
108113
storage.open(self.file.signed_file_path, 'w')
109114
assert packaged.sign(self.version.pk)
110115

116+
@raises(NotImplementedError)
117+
def test_server_active(self):
118+
with self.settings(SIGNED_APPS_SERVER_ACTIVE=True):
119+
packaged.sign(self.version.pk)
120+
121+
@raises(ValueError)
122+
def test_no_key(self):
123+
key = self.sample_packaged_key() + '.nope'
124+
with self.settings(SIGNED_APPS_KEY=key):
125+
packaged.sign(self.version.pk)
126+
127+
def is_signed(self, path):
128+
unz = SafeUnzip(path)
129+
assert unz.is_valid()
130+
assert unz.is_signed()
131+
111132
def test_good(self):
112-
self.setup_files()
113-
path = packaged.sign(self.version.pk)
114-
# TODO: This will change when we actually sign things.
115-
assert os.stat(path).st_size == (
116-
os.stat(self.file.file_path).st_size)
133+
with self.settings(SIGNED_APPS_KEY=self.sample_packaged_key()):
134+
self.is_signed(packaged.sign(self.version.pk))
117135

118136
def test_reviewer(self):
119-
self.setup_files()
120-
path = packaged.sign(self.version.pk, True)
121-
assert os.stat(path).st_size == (
122-
os.stat(self.file.file_path).st_size)
137+
# For the moment there is no real difference between reviewers
138+
# and users.
139+
with self.settings(SIGNED_APPS_KEY=self.sample_packaged_key()):
140+
self.is_signed(packaged.sign(self.version.pk, True))
141+
142+
@mock.patch('lib.crypto.packaged.xpisign')
143+
@raises(ValueError)
144+
def test_raises(self, xpisign):
145+
xpisign.side_effect = ValueError
146+
with self.settings(SIGNED_APPS_KEY=self.sample_packaged_key()):
147+
self.is_signed(packaged.sign(self.version.pk))

lib/settings_base.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,11 @@ def lazy_langs(languages):
230230
SIGNED_APPS_PATH = NETAPP_STORAGE + '/signed-apps'
231231
# Special reviewer signed ones for special people.
232232
SIGNED_APPS_REVIEWER_PATH = NETAPP_STORAGE + '/signed-apps-reviewer'
233+
# The path to the key used for signed apps receipt key if the signing server
234+
# is not active.
235+
SIGNED_APPS_KEY = ''
236+
# A seperate signing server for signing packaged apps.
237+
SIGNED_APPS_SERVER_ACTIVE = False
233238

234239
# Absolute path to a writable directory shared by all servers. No trailing
235240
# slash.
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
Certificate:
2+
Data:
3+
Version: 3 (0x2)
4+
Serial Number:
5+
d1:b6:bf:af:06:17:8c:be
6+
Signature Algorithm: sha1WithRSAEncryption
7+
Issuer: C=US, ST=California, O=M2Crypto, CN=Heikki Toivonen
8+
Validity
9+
Not Before: Jul 28 04:31:41 2009 GMT
10+
Not After : Jul 26 04:31:41 2019 GMT
11+
Subject: C=US, ST=California, O=M2Crypto, CN=localhost
12+
Subject Public Key Info:
13+
Public Key Algorithm: rsaEncryption
14+
RSA Public Key: (1024 bit)
15+
Modulus (1024 bit):
16+
00:d4:99:6f:33:3f:e6:ac:0a:34:d8:0e:45:97:f3:
17+
2b:6a:50:2a:84:30:0a:52:9c:15:30:9f:05:29:3a:
18+
21:f4:c1:c3:01:9e:2f:55:56:4e:35:ac:f1:16:1e:
19+
26:8d:b5:26:b7:99:78:92:ea:1c:74:46:ab:41:12:
20+
ef:cc:53:62:cc:59:5c:9e:c4:86:df:d9:25:35:55:
21+
05:4b:16:ff:d9:90:e3:f4:51:b4:b4:fa:c5:98:4b:
22+
60:f0:60:7f:14:4e:1e:dd:61:9b:22:a2:9c:21:17:
23+
43:a3:cb:07:80:f5:75:59:9c:55:1c:fe:e0:66:d4:
24+
70:77:5e:13:06:0c:05:c7:1f
25+
Exponent: 65537 (0x10001)
26+
X509v3 extensions:
27+
X509v3 Basic Constraints:
28+
CA:FALSE
29+
Netscape Comment:
30+
OpenSSL Generated Certificate
31+
X509v3 Subject Key Identifier:
32+
04:05:3D:6A:A7:E8:D7:52:BD:2F:C4:52:30:7C:2C:BD:D3:81:46:C6
33+
X509v3 Authority Key Identifier:
34+
keyid:AD:64:45:74:8F:83:C7:2C:D5:D7:A0:85:91:10:40:9A:9C:96:CF:EE
35+
36+
Signature Algorithm: sha1WithRSAEncryption
37+
ac:2b:ad:86:36:96:5c:fb:34:2c:02:ca:d9:5f:a7:8e:b6:58:
38+
24:1d:27:b6:8e:81:aa:69:0e:60:26:64:2e:72:a1:ff:d8:ba:
39+
bb:7e:5d:46:c7:07:2d:a8:c8:4c:df:1e:ba:c8:bc:21:5b:f2:
40+
b3:01:4c:d6:3b:10:fd:49:70:e6:83:01:f3:24:e2:a9:97:d7:
41+
c3:9c:5b:2d:d7:64:2b:e5:e2:0e:3e:d9:8c:e6:93:86:39:32:
42+
50:43:5f:36:4a:3b:b0:05:e7:65:a3:b3:ef:50:56:7f:7e:dc:
43+
f0:65:83:ac:42:7e:97:a0:c0:7e:63:c6:c8:c6:35:d3:60:d1:
44+
4f:51
45+
-----BEGIN CERTIFICATE-----
46+
MIICkTCCAfqgAwIBAgIJANG2v68GF4y+MA0GCSqGSIb3DQEBBQUAME8xCzAJBgNV
47+
BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMREwDwYDVQQKEwhNMkNyeXB0bzEY
48+
MBYGA1UEAxMPSGVpa2tpIFRvaXZvbmVuMB4XDTA5MDcyODA0MzE0MVoXDTE5MDcy
49+
NjA0MzE0MVowSTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExETAP
50+
BgNVBAoTCE0yQ3J5cHRvMRIwEAYDVQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcN
51+
AQEBBQADgY0AMIGJAoGBANSZbzM/5qwKNNgORZfzK2pQKoQwClKcFTCfBSk6IfTB
52+
wwGeL1VWTjWs8RYeJo21JreZeJLqHHRGq0ES78xTYsxZXJ7Eht/ZJTVVBUsW/9mQ
53+
4/RRtLT6xZhLYPBgfxROHt1hmyKinCEXQ6PLB4D1dVmcVRz+4GbUcHdeEwYMBccf
54+
AgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2Vu
55+
ZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBQEBT1qp+jXUr0vxFIwfCy904FG
56+
xjAfBgNVHSMEGDAWgBStZEV0j4PHLNXXoIWREECanJbP7jANBgkqhkiG9w0BAQUF
57+
AAOBgQCsK62GNpZc+zQsAsrZX6eOtlgkHSe2joGqaQ5gJmQucqH/2Lq7fl1Gxwct
58+
qMhM3x66yLwhW/KzAUzWOxD9SXDmgwHzJOKpl9fDnFst12Qr5eIOPtmM5pOGOTJQ
59+
Q182SjuwBedlo7PvUFZ/ftzwZYOsQn6XoMB+Y8bIxjXTYNFPUQ==
60+
-----END CERTIFICATE-----
61+
-----BEGIN RSA PRIVATE KEY-----
62+
MIICXgIBAAKBgQDUmW8zP+asCjTYDkWX8ytqUCqEMApSnBUwnwUpOiH0wcMBni9V
63+
Vk41rPEWHiaNtSa3mXiS6hx0RqtBEu/MU2LMWVyexIbf2SU1VQVLFv/ZkOP0UbS0
64+
+sWYS2DwYH8UTh7dYZsiopwhF0OjyweA9XVZnFUc/uBm1HB3XhMGDAXHHwIDAQAB
65+
AoGBALBHrSm8kYMTT2/anZ/5tIUJhcdnohePbg6LvJbLqf4tb4l25V6IGn9tL9Yc
66+
F/GmRD02VwDSd9d+BWAG2Kj+d0rfdCLfKY9O8PVVm0DF6grLZ7ugItYqUHRDYOdV
67+
MOVOQrx+mCIzHtoEtQ6HLqmqt2rIX731L1TA7OLNm3XHyISJAkEA/mgNNNg0e23G
68+
64z83yxxwPEnBrnKd1+xjH9QJ0Z9SJJuF4sNXRIFA4YUNvv2MNe3gMS4Hg9w78HL
69+
PwcEzLnO9QJBANXuWAZGV58CdkM2w7H9+ukxMbQeLSnmgjpdddo31qqbfgFAYZMK
70+
LppRqyosj+a2qQ6vua0ndstTImSi7KPmCUMCQQDbwr5Fu836ISYIK830aswIw0fX
71+
A37mB3+zwfZXNwjaO8NmCvQMRZiXJqcnqBdOsckOLuBs9yGzuk/7rfBzeL5RAkA2
72+
uBcly7o/vsZ3HLvjfB5ApUecVZehvwcSXLN3VI8A5nLNaSVMEe+nozoPuIQ6NAB7
73+
9DCe/JgjG6mRaibzKTS3AkEAjTl5MTKkYR78+2u3NRU/ypa1iKCicSvI/Ryw7p/z
74+
Q8XmVA0CmNRvltf9gA1gJ04ZijBPtl+s09uppaCw9L3vuA==
75+
-----END RSA PRIVATE KEY-----

requirements/prod.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ statsd==1.0.0
4949
-e git://github.com/jbalogh/schematic.git@f996182b857769541cfa7659d4f9e864360cddf4#egg=schematic
5050
-e git://github.com/jbalogh/test-utils.git@3c2214d193d1b0c0d74c77b3731c8afb0173e669#egg=test-utils
5151
-e git://github.com/fwenzel/django-mozilla-product-details.git@36ef06539d6b34c4f345fd0d3e16937d0db9a752#egg=django-mozilla-product-details
52+
-e git://github.com/nmaier/xpisign.py.git@f825b34ea83cf68ea66dcd9e47e0c7e5f38b6bd5#egg=xpisign
5253

5354
## Forked.
5455
-e git://github.com/andymckay/django-piston-oauth2.git@6cb1ad61e3f437e7ca080ee00ae7b80de7d010f0#egg=django-piston-oauth2

0 commit comments

Comments
 (0)