Coverage for tests/admin/test_x509_utils.py: 100%

117 statements  

« prev     ^ index     » next       coverage.py v7.5.3, created at 2025-10-30 06:22 +0000

1# The MIT License (MIT) 

2# 

3# Copyright (c) 2021 RSK Labs Ltd 

4# 

5# Permission is hereby granted, free of charge, to any person obtaining a copy of 

6# this software and associated documentation files (the "Software"), to deal in 

7# the Software without restriction, including without limitation the rights to 

8# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 

9# of the Software, and to permit persons to whom the Software is furnished to do 

10# so, subject to the following conditions: 

11# 

12# The above copyright notice and this permission notice shall be included in all 

13# copies or substantial portions of the Software. 

14# 

15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 

16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 

17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 

18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 

19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 

20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 

21# SOFTWARE. 

22 

23 

24from unittest import TestCase 

25from unittest.mock import patch, Mock 

26from parameterized import parameterized 

27from admin.x509_utils import split_pem_certificates, get_intel_pcs_x509_crl 

28import logging 

29 

30logging.disable(logging.CRITICAL) 

31 

32 

33class TestSplitPemCertificates(TestCase): 

34 def test_splits_ok(self): 

35 test_certs = """ 

36-----BEGIN CERTIFICATE----- 

37something 

38-----END CERTIFICATE----- 

39-----BEGIN CERTIFICATE-----somethingelse-----END CERTIFICATE----- 

40-----BEGIN CERTIFICATE-----whatis 

41thisstuff 

42-----END CERTIFICATE----- 

43""" 

44 certs = split_pem_certificates(test_certs) 

45 self.assertEqual(3, len(certs)) 

46 self.assertEqual( 

47 "-----BEGIN CERTIFICATE-----something-----END CERTIFICATE-----", 

48 certs[0].strip().replace("\n", "")) 

49 self.assertEqual( 

50 "-----BEGIN CERTIFICATE-----somethingelse-----END CERTIFICATE-----", 

51 certs[1].strip().replace("\n", "")) 

52 self.assertEqual( 

53 "-----BEGIN CERTIFICATE-----whatisthisstuff-----END CERTIFICATE-----", 

54 certs[2].strip().replace("\n", "")) 

55 

56 def test_nocerts(self): 

57 self.assertEqual([], split_pem_certificates("not a certificate in sight")) 

58 

59 def test_certs_pref_suf(self): 

60 self.assertEqual( 

61 ["-----BEGIN CERTIFICATE-----" 

62 "something-----END CERTIFICATE-----"], 

63 split_pem_certificates( 

64 "prefix\n\n\n-----BEGIN CERTIFICATE-----" 

65 "something-----END CERTIFICATE-----\n\nsuffix\n\r\tmorestuff" 

66 )) 

67 

68 

69@patch("admin.x509_utils.url_unquote") 

70@patch("admin.x509_utils.split_pem_certificates") 

71@patch("admin.x509_utils.x509.load_der_x509_crl") 

72@patch("admin.x509_utils.x509.load_pem_x509_crl") 

73@patch("admin.x509_utils.requests") 

74class TestGetIntelPcsX509CRL(TestCase): 

75 def test_ok_pem(self, requests, load_pem, load_der, split, unquote): 

76 res = Mock() 

77 requests.get.return_value = res 

78 

79 res.status_code = 200 

80 res.content = "the-crl-content" 

81 res.headers = { 

82 "Content-Type": "application/x-pem-file" 

83 } 

84 load_pem.return_value = "the-parsed-certificate" 

85 

86 self.assertEqual({ 

87 "crl": "the-parsed-certificate", 

88 "issuer_chain": None, 

89 "warning": None, 

90 }, get_intel_pcs_x509_crl("the-crl-url")) 

91 

92 load_pem.assert_called_with("the-crl-content") 

93 load_der.assert_not_called() 

94 split.assert_not_called() 

95 unquote.assert_not_called() 

96 

97 @parameterized.expand([ 

98 ("header 1", "application/pkix-crl"), 

99 ("header 2", "application/x-x509-ca-cert"), 

100 ]) 

101 def test_ok_der(self, requests, load_pem, load_der, split, unquote, _, ctype): 

102 res = Mock() 

103 requests.get.return_value = res 

104 

105 res.status_code = 200 

106 res.content = "the-crl-content" 

107 res.headers = { 

108 "Content-Type": ctype, 

109 } 

110 load_der.return_value = "the-parsed-certificate" 

111 

112 self.assertEqual({ 

113 "crl": "the-parsed-certificate", 

114 "issuer_chain": None, 

115 "warning": None, 

116 }, get_intel_pcs_x509_crl("the-crl-url")) 

117 

118 load_der.assert_called_with("the-crl-content") 

119 load_pem.assert_not_called() 

120 split.assert_not_called() 

121 unquote.assert_not_called() 

122 

123 def test_ok_warning(self, requests, load_pem, load_der, split, unquote): 

124 res = Mock() 

125 requests.get.return_value = res 

126 

127 res.status_code = 200 

128 res.content = "the-crl-content" 

129 res.headers = { 

130 "Content-Type": "application/x-pem-file", 

131 "warning": "this-is-a-warning", 

132 } 

133 load_pem.return_value = "the-parsed-certificate" 

134 

135 self.assertEqual({ 

136 "crl": "the-parsed-certificate", 

137 "issuer_chain": None, 

138 "warning": "Getting the-crl-url: this-is-a-warning", 

139 }, get_intel_pcs_x509_crl("the-crl-url")) 

140 

141 load_pem.assert_called_with("the-crl-content") 

142 load_der.assert_not_called() 

143 split.assert_not_called() 

144 unquote.assert_not_called() 

145 

146 @patch("admin.x509_utils.x509.load_pem_x509_certificate") 

147 def test_ok_issuer_chain(self, loadcer, requests, load_pem, load_der, split, unquote): 

148 res = Mock() 

149 requests.get.return_value = res 

150 

151 res.status_code = 200 

152 res.content = "the-crl-content" 

153 res.headers = { 

154 "Content-Type": "application/x-x509-ca-cert", 

155 "SGX-PCK-CRL-Issuer-Chain": "chain0-chain1-chain2", 

156 } 

157 load_der.return_value = "the-parsed-certificate" 

158 loadcer.side_effect = lambda s: f"parsed-cert-{s.decode()}" 

159 split.side_effect = lambda s: s.split(",") 

160 unquote.side_effect = lambda s: s.replace("-", ",") 

161 

162 self.assertEqual({ 

163 "crl": "the-parsed-certificate", 

164 "issuer_chain": [ 

165 "parsed-cert-chain0", 

166 "parsed-cert-chain1", 

167 "parsed-cert-chain2", 

168 ], 

169 "warning": None, 

170 }, get_intel_pcs_x509_crl("the-crl-url")) 

171 

172 load_der.assert_called_with("the-crl-content") 

173 load_pem.assert_not_called() 

174 unquote.assert_called_with("chain0-chain1-chain2") 

175 split.assert_called_with("chain0,chain1,chain2") 

176 self.assertEqual(3, loadcer.call_count) 

177 

178 def test_error_response(self, requests, load_pem, load_der, split, unquote): 

179 res = Mock() 

180 requests.get.return_value = res 

181 

182 res.status_code = 404 

183 

184 with self.assertRaises(RuntimeError) as e: 

185 get_intel_pcs_x509_crl("the-crl-url") 

186 self.assertIn("Error fetching", str(e.exception)) 

187 

188 load_pem.assert_not_called() 

189 load_der.assert_not_called() 

190 split.assert_not_called() 

191 unquote.assert_not_called() 

192 

193 def test_error_unknown_ctype(self, requests, load_pem, load_der, split, unquote): 

194 res = Mock() 

195 requests.get.return_value = res 

196 

197 res.status_code = 200 

198 res.headers = { 

199 "Content-Type": "not-known" 

200 } 

201 

202 with self.assertRaises(RuntimeError) as e: 

203 get_intel_pcs_x509_crl("the-crl-url") 

204 self.assertIn("While", str(e.exception)) 

205 self.assertIn("Unknown", str(e.exception)) 

206 

207 load_pem.assert_not_called() 

208 load_der.assert_not_called() 

209 split.assert_not_called() 

210 unquote.assert_not_called() 

211 

212 @parameterized.expand([ 

213 ("header 1", "application/x-pem-file", "pem"), 

214 ("header 2", "application/pkix-crl", "der"), 

215 ("header 3", "application/x-x509-ca-cert", "der"), 

216 ]) 

217 def test_error_parsing(self, requests, load_pem, load_der, 

218 split, unquote, _, ctype, errct): 

219 res = Mock() 

220 requests.get.return_value = res 

221 

222 res.status_code = 200 

223 res.content = "some-content" 

224 res.headers = { 

225 "Content-Type": ctype, 

226 } 

227 

228 load_pem.side_effect = ValueError("pem parsing issue") 

229 load_der.side_effect = ValueError("der parsing issue") 

230 

231 with self.assertRaises(RuntimeError) as e: 

232 get_intel_pcs_x509_crl("the-crl-url") 

233 self.assertIn("While", str(e.exception)) 

234 self.assertIn(f"{errct} parsing", str(e.exception)) 

235 

236 split.assert_not_called() 

237 unquote.assert_not_called()