|
18 | 18 | from .util import sigencode_der, sigencode_string |
19 | 19 | from .util import sigdecode_der, sigdecode_string |
20 | 20 | from .curves import curves, NIST256p |
21 | | -from .der import encode_integer, encode_sequence |
| 21 | +from .der import encode_integer, encode_bitstring, encode_octet_string, \ |
| 22 | + encode_oid, encode_sequence, encode_constructed |
22 | 23 |
|
23 | 24 |
|
24 | 25 | example_data = b"some data to sign" |
@@ -109,8 +110,12 @@ def st_fuzzed_sig(draw, keys_and_sigs): |
109 | 110 | params = {} |
110 | 111 | # not supported in hypothesis 2.0.0 |
111 | 112 | if sys.version_info >= (2, 7): |
| 113 | + from hypothesis import HealthCheck |
112 | 114 | # deadline=5s because NIST521p are slow to verify |
113 | 115 | params["deadline"] = 5000 |
| 116 | + params["suppress_health_check"] = [HealthCheck.data_too_large, |
| 117 | + HealthCheck.filter_too_much, |
| 118 | + HealthCheck.too_slow] |
114 | 119 |
|
115 | 120 |
|
116 | 121 | @settings(**params) |
@@ -164,6 +169,95 @@ def test_random_der_ecdsa_sig_value(params): |
164 | 169 | verifying_key.verify(sig, example_data, sigdecode=sigdecode_der) |
165 | 170 |
|
166 | 171 |
|
| 172 | +def st_der_integer(*args, **kwargs): |
| 173 | + """ |
| 174 | + Hypothesis strategy that returns a random positive integer as DER |
| 175 | + INTEGER. |
| 176 | + Parameters are passed to hypothesis.strategy.integer. |
| 177 | + """ |
| 178 | + if "min_value" not in kwargs: |
| 179 | + kwargs["min_value"] = 0 |
| 180 | + return st.builds(encode_integer, st.integers(*args, **kwargs)) |
| 181 | + |
| 182 | + |
| 183 | +@st.composite |
| 184 | +def st_der_bit_string(draw, *args, **kwargs): |
| 185 | + """ |
| 186 | + Hypothesis strategy that returns a random DER BIT STRING. |
| 187 | + Parameters are passed to hypothesis.strategy.binary. |
| 188 | + """ |
| 189 | + data = draw(st.binary(*args, **kwargs)) |
| 190 | + if data: |
| 191 | + unused = draw(st.integers(min_value=0, max_value=7)) |
| 192 | + data = bytearray(data) |
| 193 | + data[-1] &= - (2**unused) |
| 194 | + data = bytes(data) |
| 195 | + else: |
| 196 | + unused = 0 |
| 197 | + return encode_bitstring(data, unused) |
| 198 | + |
| 199 | + |
| 200 | +def st_der_octet_string(*args, **kwargs): |
| 201 | + """ |
| 202 | + Hypothesis strategy that returns a random DER OCTET STRING object. |
| 203 | + Parameters are passed to hypothesis.strategy.binary |
| 204 | + """ |
| 205 | + return st.builds(encode_octet_string, st.binary(*args, **kwargs)) |
| 206 | + |
| 207 | + |
| 208 | +def st_der_null(): |
| 209 | + """ |
| 210 | + Hypothesis strategy that returns DER NULL object. |
| 211 | + """ |
| 212 | + return st.just(b'\x05\x00') |
| 213 | + |
| 214 | + |
| 215 | +@st.composite |
| 216 | +def st_der_oid(draw): |
| 217 | + """ |
| 218 | + Hypothesis strategy that returns DER OBJECT IDENTIFIER objects. |
| 219 | + """ |
| 220 | + first = draw(st.integers(min_value=0, max_value=2)) |
| 221 | + second = draw(st.integers(min_value=0, max_value=39)) |
| 222 | + rest = draw(st.lists(st.integers(min_value=0, max_value=2**512), |
| 223 | + max_size=50)) |
| 224 | + return encode_oid(first, second, *rest) |
| 225 | + |
| 226 | + |
| 227 | +def st_der(): |
| 228 | + """ |
| 229 | + Hypothesis strategy that returns random DER structures. |
| 230 | +
|
| 231 | + A valid DER structure is any primitive object, an octet encoding |
| 232 | + of a valid DER structure, sequence of valid DER objects or a constructed |
| 233 | + encoding of any of the above. |
| 234 | + """ |
| 235 | + return st.recursive( |
| 236 | + st.just(b'') | st_der_integer(max_value=2**4096) | |
| 237 | + st_der_bit_string(max_size=1024**2) | |
| 238 | + st_der_octet_string(max_size=1024**2) | st_der_null() | st_der_oid(), |
| 239 | + lambda children: |
| 240 | + st.builds(lambda x: encode_octet_string(x), st.one_of(children)) | |
| 241 | + st.builds(lambda x: encode_bitstring(x, 0), st.one_of(children)) | |
| 242 | + st.builds(lambda x: encode_sequence(*x), |
| 243 | + st.lists(children, max_size=200)) | |
| 244 | + st.builds(lambda tag, x: |
| 245 | + encode_constructed(tag, x), |
| 246 | + st.integers(min_value=0, max_value=0x3f), |
| 247 | + st.one_of(children)) |
| 248 | + ) |
| 249 | + |
| 250 | + |
| 251 | +@settings(**params) |
| 252 | +@given(st.sampled_from(keys_and_sigs), st_der()) |
| 253 | +def test_random_der_as_signature(params, der): |
| 254 | + """Check if random DER structures are rejected as signature""" |
| 255 | + name, verifying_key, _ = params |
| 256 | + |
| 257 | + with pytest.raises(BadSignatureError): |
| 258 | + verifying_key.verify(der, example_data, sigdecode=sigdecode_der) |
| 259 | + |
| 260 | + |
167 | 261 | keys_and_string_sigs = [ |
168 | 262 | (name, verifying_key, |
169 | 263 | sigencode_string(*sigdecode_der(sig, verifying_key.curve.order), |
|
0 commit comments