blob: 79996b6d068b2be96bc56cb7a7cdda092e9a0a55 [file] [log] [blame]
Alex Gaynorf312a5c2013-08-10 15:23:38 -04001# Licensed under the Apache License, Version 2.0 (the "License");
2# you may not use this file except in compliance with the License.
3# You may obtain a copy of the License at
4#
5# http://www.apache.org/licenses/LICENSE-2.0
6#
7# Unless required by applicable law or agreed to in writing, software
8# distributed under the License is distributed on an "AS IS" BASIS,
9# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
10# implied.
11# See the License for the specific language governing permissions and
12# limitations under the License.
13
Alex Gaynorc37feed2014-03-08 08:32:56 -080014from __future__ import absolute_import, division, print_function
15
Alex Gaynor36e651c2014-01-27 10:08:35 -080016import collections
Alex Gaynor2b3f9422013-12-24 21:55:24 -080017import os
18
19import pytest
Paul Kehrer90450f32014-03-19 12:37:17 -040020
Paul Kehrerafc1ccd2014-03-19 11:49:32 -040021import six
Alex Gaynor2b3f9422013-12-24 21:55:24 -080022
23
Alex Gaynor36e651c2014-01-27 10:08:35 -080024HashVector = collections.namedtuple("HashVector", ["message", "digest"])
25KeyedHashVector = collections.namedtuple(
26 "KeyedHashVector", ["message", "digest", "key"]
27)
28
29
Paul Kehrerc421e632014-01-18 09:22:21 -060030def select_backends(names, backend_list):
31 if names is None:
32 return backend_list
33 split_names = [x.strip() for x in names.split(',')]
34 # this must be duplicated and then removed to preserve the metadata
35 # pytest associates. Appending backends to a new list doesn't seem to work
Paul Kehreraed9e172014-01-19 12:09:27 -060036 selected_backends = []
37 for backend in backend_list:
38 if backend.name in split_names:
39 selected_backends.append(backend)
Paul Kehrerc421e632014-01-18 09:22:21 -060040
Paul Kehreraed9e172014-01-19 12:09:27 -060041 if len(selected_backends) > 0:
42 return selected_backends
Paul Kehrerc421e632014-01-18 09:22:21 -060043 else:
44 raise ValueError(
45 "No backend selected. Tried to select: {0}".format(split_names)
46 )
Paul Kehrer34c075e2014-01-13 21:52:08 -050047
48
Alex Gaynor2b3f9422013-12-24 21:55:24 -080049def check_for_iface(name, iface, item):
50 if name in item.keywords and "backend" in item.funcargs:
51 if not isinstance(item.funcargs["backend"], iface):
52 pytest.skip("{0} backend does not support {1}".format(
53 item.funcargs["backend"], name
54 ))
Donald Stufft9e1a48b2013-08-09 00:32:30 -040055
56
Paul Kehrer60fc8da2013-12-26 20:19:34 -060057def check_backend_support(item):
Paul Kehrer5a8fdf82013-12-26 20:13:45 -060058 supported = item.keywords.get("supported")
59 if supported and "backend" in item.funcargs:
60 if not supported.kwargs["only_if"](item.funcargs["backend"]):
Paul Kehrerf03334e2014-01-02 23:16:14 -060061 pytest.skip("{0} ({1})".format(
62 supported.kwargs["skip_message"], item.funcargs["backend"]
63 ))
Paul Kehrer5a8fdf82013-12-26 20:13:45 -060064 elif supported:
Paul Kehrerec495502013-12-27 15:51:40 -060065 raise ValueError("This mark is only available on methods that take a "
66 "backend")
Paul Kehrer5a8fdf82013-12-26 20:13:45 -060067
68
Paul Kehrerf7f6a9f2013-11-11 20:43:52 -060069def load_vectors_from_file(filename, loader):
70 base = os.path.join(
71 os.path.dirname(__file__), "hazmat", "primitives", "vectors",
72 )
73 with open(os.path.join(base, filename), "r") as vector_file:
74 return loader(vector_file)
75
76
Alex Gaynord3ce7032013-11-11 14:46:20 -080077def load_nist_vectors(vector_data):
Paul Kehrer749ac5b2013-11-18 18:12:41 -060078 test_data = None
79 data = []
Donald Stufft9e1a48b2013-08-09 00:32:30 -040080
81 for line in vector_data:
82 line = line.strip()
83
Paul Kehrer749ac5b2013-11-18 18:12:41 -060084 # Blank lines, comments, and section headers are ignored
85 if not line or line.startswith("#") or (line.startswith("[")
86 and line.endswith("]")):
Alex Gaynor521c42d2013-11-11 14:25:59 -080087 continue
88
Paul Kehrera43b6692013-11-12 15:35:49 -060089 if line.strip() == "FAIL":
Paul Kehrer749ac5b2013-11-18 18:12:41 -060090 test_data["fail"] = True
Paul Kehrera43b6692013-11-12 15:35:49 -060091 continue
92
Donald Stufft9e1a48b2013-08-09 00:32:30 -040093 # Build our data using a simple Key = Value format
Paul Kehrera43b6692013-11-12 15:35:49 -060094 name, value = [c.strip() for c in line.split("=")]
Donald Stufft9e1a48b2013-08-09 00:32:30 -040095
Paul Kehrer1050ddf2014-01-27 21:04:03 -060096 # Some tests (PBKDF2) contain \0, which should be interpreted as a
97 # null character rather than literal.
98 value = value.replace("\\0", "\0")
99
Donald Stufft9e1a48b2013-08-09 00:32:30 -0400100 # COUNT is a special token that indicates a new block of data
101 if name.upper() == "COUNT":
Paul Kehrer749ac5b2013-11-18 18:12:41 -0600102 test_data = {}
103 data.append(test_data)
104 continue
Donald Stufft9e1a48b2013-08-09 00:32:30 -0400105 # For all other tokens we simply want the name, value stored in
106 # the dictionary
107 else:
Paul Kehrer749ac5b2013-11-18 18:12:41 -0600108 test_data[name.lower()] = value.encode("ascii")
Donald Stufft9e1a48b2013-08-09 00:32:30 -0400109
Paul Kehrer749ac5b2013-11-18 18:12:41 -0600110 return data
Donald Stufft9e1a48b2013-08-09 00:32:30 -0400111
112
Paul Kehrer1951bf62013-09-15 12:05:43 -0500113def load_cryptrec_vectors(vector_data):
Paul Kehrere5805982013-09-27 11:26:01 -0500114 cryptrec_list = []
Paul Kehrer1951bf62013-09-15 12:05:43 -0500115
116 for line in vector_data:
117 line = line.strip()
118
119 # Blank lines and comments are ignored
120 if not line or line.startswith("#"):
121 continue
122
123 if line.startswith("K"):
Paul Kehrere5805982013-09-27 11:26:01 -0500124 key = line.split(" : ")[1].replace(" ", "").encode("ascii")
Paul Kehrer1951bf62013-09-15 12:05:43 -0500125 elif line.startswith("P"):
Paul Kehrere5805982013-09-27 11:26:01 -0500126 pt = line.split(" : ")[1].replace(" ", "").encode("ascii")
Paul Kehrer1951bf62013-09-15 12:05:43 -0500127 elif line.startswith("C"):
Paul Kehrere5805982013-09-27 11:26:01 -0500128 ct = line.split(" : ")[1].replace(" ", "").encode("ascii")
129 # after a C is found the K+P+C tuple is complete
130 # there are many P+C pairs for each K
Alex Gaynor1fe70b12013-10-16 11:59:17 -0700131 cryptrec_list.append({
132 "key": key,
133 "plaintext": pt,
134 "ciphertext": ct
135 })
Donald Stufft3359d7e2013-10-19 19:33:06 -0400136 else:
137 raise ValueError("Invalid line in file '{}'".format(line))
Paul Kehrer1951bf62013-09-15 12:05:43 -0500138 return cryptrec_list
139
140
Paul Kehrer69e06522013-10-18 17:28:39 -0500141def load_hash_vectors(vector_data):
142 vectors = []
Paul Kehrer1bb8b712013-10-27 17:00:14 -0500143 key = None
144 msg = None
145 md = None
Paul Kehrer69e06522013-10-18 17:28:39 -0500146
147 for line in vector_data:
148 line = line.strip()
149
Paul Kehrer87cd0db2013-10-18 18:01:26 -0500150 if not line or line.startswith("#") or line.startswith("["):
Paul Kehrer69e06522013-10-18 17:28:39 -0500151 continue
152
153 if line.startswith("Len"):
154 length = int(line.split(" = ")[1])
Paul Kehrer0317b042013-10-28 17:34:27 -0500155 elif line.startswith("Key"):
Alex Gaynor36e651c2014-01-27 10:08:35 -0800156 # HMAC vectors contain a key attribute. Hash vectors do not.
Paul Kehrer0317b042013-10-28 17:34:27 -0500157 key = line.split(" = ")[1].encode("ascii")
Paul Kehrer69e06522013-10-18 17:28:39 -0500158 elif line.startswith("Msg"):
Alex Gaynor36e651c2014-01-27 10:08:35 -0800159 # In the NIST vectors they have chosen to represent an empty
160 # string as hex 00, which is of course not actually an empty
161 # string. So we parse the provided length and catch this edge case.
Paul Kehrer69e06522013-10-18 17:28:39 -0500162 msg = line.split(" = ")[1].encode("ascii") if length > 0 else b""
163 elif line.startswith("MD"):
164 md = line.split(" = ")[1]
Paul Kehrer0317b042013-10-28 17:34:27 -0500165 # after MD is found the Msg+MD (+ potential key) tuple is complete
Paul Kehrer00dd5092013-10-23 09:41:49 -0500166 if key is not None:
Alex Gaynor36e651c2014-01-27 10:08:35 -0800167 vectors.append(KeyedHashVector(msg, md, key))
Paul Kehrer1bb8b712013-10-27 17:00:14 -0500168 key = None
169 msg = None
170 md = None
Paul Kehrer00dd5092013-10-23 09:41:49 -0500171 else:
Alex Gaynor36e651c2014-01-27 10:08:35 -0800172 vectors.append(HashVector(msg, md))
Paul Kehrer1bb8b712013-10-27 17:00:14 -0500173 msg = None
174 md = None
Paul Kehrer69e06522013-10-18 17:28:39 -0500175 else:
176 raise ValueError("Unknown line in hash vector")
177 return vectors
Alex Stapleton58f27ac2014-02-02 19:30:03 +0000178
179
180def load_pkcs1_vectors(vector_data):
181 """
182 Loads data out of RSA PKCS #1 vector files.
Alex Stapleton58f27ac2014-02-02 19:30:03 +0000183 """
184 private_key_vector = None
185 public_key_vector = None
186 attr = None
187 key = None
Paul Kehrerefca2802014-02-17 20:55:13 -0600188 example_vector = None
189 examples = []
Alex Stapleton58f27ac2014-02-02 19:30:03 +0000190 vectors = []
191 for line in vector_data:
Paul Kehrer7774a032014-02-17 22:56:55 -0600192 if (
193 line.startswith("# PSS Example") or
194 line.startswith("# PKCS#1 v1.5 Signature")
195 ):
Paul Kehrerefca2802014-02-17 20:55:13 -0600196 if example_vector:
197 for key, value in six.iteritems(example_vector):
Paul Kehrer26811802014-02-19 16:32:11 -0600198 hex_str = "".join(value).replace(" ", "").encode("ascii")
Paul Kehrerefca2802014-02-17 20:55:13 -0600199 example_vector[key] = hex_str
200 examples.append(example_vector)
201
202 attr = None
203 example_vector = collections.defaultdict(list)
204
205 if line.startswith("# Message to be signed"):
Paul Kehrer7d9c3062014-02-18 08:27:39 -0600206 attr = "message"
Paul Kehrerefca2802014-02-17 20:55:13 -0600207 continue
208 elif line.startswith("# Salt"):
209 attr = "salt"
210 continue
211 elif line.startswith("# Signature"):
212 attr = "signature"
213 continue
214 elif (
215 example_vector and
216 line.startswith("# =============================================")
217 ):
218 for key, value in six.iteritems(example_vector):
Paul Kehrer26811802014-02-19 16:32:11 -0600219 hex_str = "".join(value).replace(" ", "").encode("ascii")
Paul Kehrerefca2802014-02-17 20:55:13 -0600220 example_vector[key] = hex_str
221 examples.append(example_vector)
222 example_vector = None
223 attr = None
224 elif example_vector and line.startswith("#"):
225 continue
226 else:
227 if attr is not None and example_vector is not None:
228 example_vector[attr].append(line.strip())
229 continue
230
Alex Stapleton58f27ac2014-02-02 19:30:03 +0000231 if (
232 line.startswith("# Example") or
233 line.startswith("# =============================================")
234 ):
235 if key:
236 assert private_key_vector
237 assert public_key_vector
238
239 for key, value in six.iteritems(public_key_vector):
240 hex_str = "".join(value).replace(" ", "")
241 public_key_vector[key] = int(hex_str, 16)
242
243 for key, value in six.iteritems(private_key_vector):
244 hex_str = "".join(value).replace(" ", "")
245 private_key_vector[key] = int(hex_str, 16)
246
Paul Kehrerefca2802014-02-17 20:55:13 -0600247 private_key_vector["examples"] = examples
248 examples = []
249
Alex Stapleton58f27ac2014-02-02 19:30:03 +0000250 assert (
251 private_key_vector['public_exponent'] ==
252 public_key_vector['public_exponent']
253 )
254
255 assert (
256 private_key_vector['modulus'] ==
257 public_key_vector['modulus']
258 )
259
260 vectors.append(
261 (private_key_vector, public_key_vector)
262 )
263
264 public_key_vector = collections.defaultdict(list)
265 private_key_vector = collections.defaultdict(list)
266 key = None
267 attr = None
268
269 if private_key_vector is None or public_key_vector is None:
270 continue
271
272 if line.startswith("# Private key"):
273 key = private_key_vector
274 elif line.startswith("# Public key"):
275 key = public_key_vector
276 elif line.startswith("# Modulus:"):
277 attr = "modulus"
278 elif line.startswith("# Public exponent:"):
279 attr = "public_exponent"
280 elif line.startswith("# Exponent:"):
281 if key is public_key_vector:
282 attr = "public_exponent"
283 else:
284 assert key is private_key_vector
285 attr = "private_exponent"
286 elif line.startswith("# Prime 1:"):
287 attr = "p"
288 elif line.startswith("# Prime 2:"):
289 attr = "q"
Paul Kehrer09328bb2014-02-12 23:57:27 -0600290 elif line.startswith("# Prime exponent 1:"):
291 attr = "dmp1"
292 elif line.startswith("# Prime exponent 2:"):
293 attr = "dmq1"
294 elif line.startswith("# Coefficient:"):
295 attr = "iqmp"
Alex Stapleton58f27ac2014-02-02 19:30:03 +0000296 elif line.startswith("#"):
297 attr = None
298 else:
299 if key is not None and attr is not None:
300 key[attr].append(line.strip())
301 return vectors
Paul Kehrer2f2a2062014-03-10 23:30:28 -0400302
303
304def load_rsa_nist_vectors(vector_data):
305 test_data = None
Paul Kehrer62707f12014-03-18 07:19:14 -0400306 p = None
Paul Kehrerafc25182014-03-18 07:51:56 -0400307 salt_length = None
Paul Kehrer2f2a2062014-03-10 23:30:28 -0400308 data = []
309
310 for line in vector_data:
311 line = line.strip()
312
313 # Blank lines and section headers are ignored
314 if not line or line.startswith("["):
315 continue
316
317 if line.startswith("# Salt len:"):
318 salt_length = int(line.split(":")[1].strip())
319 continue
320 elif line.startswith("#"):
321 continue
322
323 # Build our data using a simple Key = Value format
324 name, value = [c.strip() for c in line.split("=")]
325
326 if name == "n":
327 n = int(value, 16)
Paul Kehrer62707f12014-03-18 07:19:14 -0400328 elif name == "e" and p is None:
Paul Kehrer2f2a2062014-03-10 23:30:28 -0400329 e = int(value, 16)
Paul Kehrer62707f12014-03-18 07:19:14 -0400330 elif name == "p":
331 p = int(value, 16)
332 elif name == "q":
333 q = int(value, 16)
Paul Kehrer2f2a2062014-03-10 23:30:28 -0400334 elif name == "SHAAlg":
Paul Kehrer62707f12014-03-18 07:19:14 -0400335 if p is None:
336 test_data = {
337 "modulus": n,
338 "public_exponent": e,
339 "salt_length": salt_length,
Paul Kehrere66f69a2014-03-18 07:57:26 -0400340 "algorithm": value,
Paul Kehrer62707f12014-03-18 07:19:14 -0400341 "fail": False
342 }
343 else:
344 test_data = {
345 "modulus": n,
346 "p": p,
347 "q": q,
Paul Kehrere66f69a2014-03-18 07:57:26 -0400348 "algorithm": value
Paul Kehrer62707f12014-03-18 07:19:14 -0400349 }
Paul Kehrerafc25182014-03-18 07:51:56 -0400350 if salt_length is not None:
351 test_data["salt_length"] = salt_length
Paul Kehrer2f2a2062014-03-10 23:30:28 -0400352 data.append(test_data)
Paul Kehrer62707f12014-03-18 07:19:14 -0400353 elif name == "e" and p is not None:
354 test_data["public_exponent"] = int(value, 16)
355 elif name == "d":
356 test_data["private_exponent"] = int(value, 16)
357 elif name == "Result":
358 test_data["fail"] = value.startswith("F")
Paul Kehrer2f2a2062014-03-10 23:30:28 -0400359 # For all other tokens we simply want the name, value stored in
360 # the dictionary
361 else:
362 test_data[name.lower()] = value.encode("ascii")
363
364 return data
Mohammed Attia987cc702014-03-12 16:07:21 +0200365
366
367def load_fips_dsa_key_pair_vectors(vector_data):
368 """
369 Loads data out of the FIPS DSA KeyPair vector files.
370 """
371 vectors = []
Mohammed Attia49b92592014-03-12 20:07:05 +0200372 # When reading_key_data is set to True it tells the loader to continue
373 # constructing dictionaries. We set reading_key_data to False during the
374 # blocks of the vectors of N=224 because we don't support it.
375 reading_key_data = True
Mohammed Attia987cc702014-03-12 16:07:21 +0200376 for line in vector_data:
377 line = line.strip()
378
379 if not line or line.startswith("#"):
380 continue
Mohammed Attia49b92592014-03-12 20:07:05 +0200381 elif line.startswith("[mod = L=1024"):
Mohammed Attia987cc702014-03-12 16:07:21 +0200382 continue
Mohammed Attia49b92592014-03-12 20:07:05 +0200383 elif line.startswith("[mod = L=2048, N=224"):
384 reading_key_data = False
Mohammed Attia987cc702014-03-12 16:07:21 +0200385 continue
Mohammed Attia49b92592014-03-12 20:07:05 +0200386 elif line.startswith("[mod = L=2048, N=256"):
387 reading_key_data = True
Mohammed Attia987cc702014-03-12 16:07:21 +0200388 continue
Mohammed Attia49b92592014-03-12 20:07:05 +0200389 elif line.startswith("[mod = L=3072"):
Mohammed Attia987cc702014-03-12 16:07:21 +0200390 continue
391
Mohammed Attia49b92592014-03-12 20:07:05 +0200392 if not reading_key_data:
Mohammed Attia987cc702014-03-12 16:07:21 +0200393 continue
394
Mohammed Attia49b92592014-03-12 20:07:05 +0200395 elif reading_key_data:
Mohammed Attia987cc702014-03-12 16:07:21 +0200396 if line.startswith("P"):
397 vectors.append({'p': int(line.split("=")[1], 16)})
Mohammed Attia22ccb872014-03-12 18:27:59 +0200398 elif line.startswith("Q"):
Mohammed Attia987cc702014-03-12 16:07:21 +0200399 vectors[-1]['q'] = int(line.split("=")[1], 16)
Mohammed Attia22ccb872014-03-12 18:27:59 +0200400 elif line.startswith("G"):
Mohammed Attia987cc702014-03-12 16:07:21 +0200401 vectors[-1]['g'] = int(line.split("=")[1], 16)
Mohammed Attia22ccb872014-03-12 18:27:59 +0200402 elif line.startswith("X") and 'x' not in vectors[-1]:
Mohammed Attia987cc702014-03-12 16:07:21 +0200403 vectors[-1]['x'] = int(line.split("=")[1], 16)
Mohammed Attia22ccb872014-03-12 18:27:59 +0200404 elif line.startswith("X") and 'x' in vectors[-1]:
Mohammed Attia987cc702014-03-12 16:07:21 +0200405 vectors.append({'p': vectors[-1]['p'],
406 'q': vectors[-1]['q'],
407 'g': vectors[-1]['g'],
408 'x': int(line.split("=")[1], 16)
409 })
Mohammed Attia22ccb872014-03-12 18:27:59 +0200410 elif line.startswith("Y"):
Mohammed Attia987cc702014-03-12 16:07:21 +0200411 vectors[-1]['y'] = int(line.split("=")[1], 16)
Mohammed Attia987cc702014-03-12 16:07:21 +0200412
413 return vectors