[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[tor-commits] [stem/master] Convert Ed25519Extension to a field
commit 064336ee318cd1e8201184400f04ad1af27ebe92
Author: Damian Johnson <atagar@xxxxxxxxxxxxxx>
Date: Wed Oct 23 15:23:42 2019 -0700
Convert Ed25519Extension to a field
So much cleaner! Moving unpacking into this class simplifies
Ed25519CertificateV1's from_base64(), and lays the groundwork for packing.
---
stem/descriptor/certificate.py | 66 ++++++++++++++++++++++---------------
test/unit/descriptor/certificate.py | 10 +++---
2 files changed, 44 insertions(+), 32 deletions(-)
diff --git a/stem/descriptor/certificate.py b/stem/descriptor/certificate.py
index 92f75719..dcf0c227 100644
--- a/stem/descriptor/certificate.py
+++ b/stem/descriptor/certificate.py
@@ -72,7 +72,6 @@ used to for a variety of purposes...
import base64
import binascii
-import collections
import datetime
import hashlib
import re
@@ -83,7 +82,7 @@ import stem.prereq
import stem.util.enum
import stem.util.str_tools
-from stem.client.datatype import Size, split
+from stem.client.datatype import Field, Size, split
# TODO: Importing under an alternate name until we can deprecate our redundant
# CertType enum in Stem 2.x.
@@ -107,16 +106,50 @@ ExtensionType = stem.util.enum.Enum(('HAS_SIGNING_KEY', 4),)
ExtensionFlag = stem.util.enum.UppercaseEnum('AFFECTS_VALIDATION', 'UNKNOWN')
-class Ed25519Extension(collections.namedtuple('Ed25519Extension', ['type', 'flags', 'flag_int', 'data'])):
+class Ed25519Extension(Field):
"""
Extension within an Ed25519 certificate.
- :var int type: extension type
+ :var stem.descriptor.certificate.ExtensionType type: extension type
:var list flags: extension attribute flags
:var int flag_int: integer encoding of the extension attribute flags
:var bytes data: data the extension concerns
"""
+ def __init__(self, ext_type, flag_val, data):
+ self.type = ext_type
+ self.flags = []
+ self.flag_int = flag_val
+ self.data = data
+
+ if flag_val % 2 == 1:
+ self.flags.append(ExtensionFlag.AFFECTS_VALIDATION)
+ flag_val -= 1
+
+ if flag_val:
+ self.flags.append(ExtensionFlag.UNKNOWN)
+
+ if ext_type == ExtensionType.HAS_SIGNING_KEY and len(data) != 32:
+ raise ValueError('Ed25519 HAS_SIGNING_KEY extension must be 32 bytes, but was %i.' % len(data))
+
+ @staticmethod
+ def pop(content):
+ if len(content) < 4:
+ raise ValueError('Ed25519 extension is missing header fields')
+
+ data_size, content = Size.SHORT.pop(content)
+ ext_type, content = Size.CHAR.pop(content)
+ flags, content = Size.CHAR.pop(content)
+ data, content = split(content, data_size)
+
+ if len(data) != data_size:
+ raise ValueError("Ed25519 extension is truncated. It should have %i bytes of data but there's only %i." % (data_size, len(data)))
+
+ return Ed25519Extension(ext_type, flags, data), content
+
+ def __hash__(self):
+ return stem.util._hash_attr(self, 'type', 'flag_int', 'data', cache = True)
+
class Ed25519Certificate(object):
"""
@@ -270,29 +303,8 @@ class Ed25519CertificateV1(Ed25519Certificate):
extensions = []
for i in range(extension_count):
- if len(extension_data) < 4:
- raise ValueError('Ed25519 extension is missing header field data')
-
- extension_length, extension_data = Size.SHORT.pop(extension_data)
- extension_type, extension_data = Size.CHAR.pop(extension_data)
- extension_flags, extension_data = Size.CHAR.pop(extension_data)
- extension_value, extension_data = split(extension_data, extension_length)
-
- if extension_length != len(extension_value):
- raise ValueError("Ed25519 extension is truncated. It should have %i bytes of data but there's only %i." % (extension_length, len(extension_value)))
- elif extension_type == ExtensionType.HAS_SIGNING_KEY and len(extension_value) != 32:
- raise ValueError('Ed25519 HAS_SIGNING_KEY extension must be 32 bytes, but was %i.' % len(extension_value))
-
- flags, remaining_flags = [], extension_flags
-
- if remaining_flags % 2 == 1:
- flags.append(ExtensionFlag.AFFECTS_VALIDATION)
- remaining_flags -= 1
-
- if remaining_flags:
- flags.append(ExtensionFlag.UNKNOWN)
-
- extensions.append(Ed25519Extension(extension_type, flags, extension_flags, extension_value))
+ extension, extension_data = Ed25519Extension.pop(extension_data)
+ extensions.append(extension)
if extension_data:
raise ValueError('Ed25519 certificate had %i bytes of unused extension data' % len(extension_data))
diff --git a/test/unit/descriptor/certificate.py b/test/unit/descriptor/certificate.py
index 7fd5e731..dc7ff184 100644
--- a/test/unit/descriptor/certificate.py
+++ b/test/unit/descriptor/certificate.py
@@ -13,7 +13,7 @@ import stem.prereq
import test.require
from stem.client.datatype import CertType
-from stem.descriptor.certificate import ED25519_SIGNATURE_LENGTH, ExtensionType, ExtensionFlag, Ed25519Certificate, Ed25519CertificateV1, Ed25519Extension
+from stem.descriptor.certificate import ED25519_SIGNATURE_LENGTH, ExtensionType, Ed25519Certificate, Ed25519CertificateV1, Ed25519Extension
from test.unit.descriptor import get_resource
from cryptography.hazmat.primitives import serialization
@@ -69,8 +69,8 @@ class TestEd25519Certificate(unittest.TestCase):
self.assertEqual(b'\x01' * ED25519_SIGNATURE_LENGTH, cert.signature)
self.assertEqual([
- Ed25519Extension(type = ExtensionType.HAS_SIGNING_KEY, flags = [ExtensionFlag.AFFECTS_VALIDATION, ExtensionFlag.UNKNOWN], flag_int = 7, data = signing_key),
- Ed25519Extension(type = 5, flags = [ExtensionFlag.UNKNOWN], flag_int = 4, data = b''),
+ Ed25519Extension(ExtensionType.HAS_SIGNING_KEY, 7, signing_key),
+ Ed25519Extension(5, 4, b''),
], cert.extensions)
self.assertEqual(ExtensionType.HAS_SIGNING_KEY, cert.extensions[0].type)
@@ -90,7 +90,7 @@ class TestEd25519Certificate(unittest.TestCase):
self.assertEqual(datetime.datetime(2015, 8, 28, 17, 0), cert.expiration)
self.assertEqual(1, cert.key_type)
self.assertEqual(EXPECTED_CERT_KEY, cert.key)
- self.assertEqual([Ed25519Extension(type = 4, flags = [], flag_int = 0, data = EXPECTED_EXTENSION_DATA)], cert.extensions)
+ self.assertEqual([Ed25519Extension(4, 0, EXPECTED_EXTENSION_DATA)], cert.extensions)
self.assertEqual(EXPECTED_SIGNATURE, cert.signature)
def test_non_base64(self):
@@ -141,7 +141,7 @@ class TestEd25519Certificate(unittest.TestCase):
Include an extension without as much data as it specifies.
"""
- exc_msg = 'Ed25519 extension is missing header field data'
+ exc_msg = 'Ed25519 extension is missing header fields'
self.assertRaisesWith(ValueError, exc_msg, Ed25519Certificate.from_base64, certificate(extension_data = [b'']))
exc_msg = "Ed25519 extension is truncated. It should have 20480 bytes of data but there's only 2."
_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits