commit 359d6833de7ac2481aa0ab5c47a1019514060dd6 Author: Damian Johnson atagar@torproject.org Date: Thu Oct 17 16:33:05 2019 -0700
Merge CertType enumerations
I accidently had two enumerations for the same thing...
stem.client.datatype.CertType stem.descriptor.certificate.CertType
The first is the better enumeration in that it's integer backed. Expanding the values it encompasses and deprecating the certificate.py copy. --- stem/client/datatype.py | 51 +++++++++++++++++------- stem/descriptor/certificate.py | 65 +++++++++++++++---------------- stem/descriptor/hidden_service.py | 5 ++- test/unit/client/cell.py | 6 +-- test/unit/client/certificate.py | 2 +- test/unit/descriptor/certificate.py | 12 ++++-- test/unit/descriptor/server_descriptor.py | 5 ++- 7 files changed, 87 insertions(+), 59 deletions(-)
diff --git a/stem/client/datatype.py b/stem/client/datatype.py index 76957819..73def712 100644 --- a/stem/client/datatype.py +++ b/stem/client/datatype.py @@ -83,16 +83,33 @@ users.** See our :class:`~stem.client.Relay` the API you probably want.
.. data:: CertType (enum)
- Relay certificate type. - - ===================== =========== - CertType Description - ===================== =========== - **LINK** link key certificate certified by RSA1024 identity - **IDENTITY** RSA1024 Identity certificate - **AUTHENTICATE** RSA1024 AUTHENTICATE cell link certificate - **UNKNOWN** unrecognized certificate type - ===================== =========== + Certificate purpose. For more information see... + + * `tor-spec.txt https://gitweb.torproject.org/torspec.git/tree/tor-spec.txt`_ section 4.2 + * `cert-spec.txt https://gitweb.torproject.org/torspec.git/tree/cert-spec.txt`_ section A.1 + * `rend-spec-v3.txt https://gitweb.torproject.org/torspec.git/tree/rend-spec-v3.txt`_ appendix E + + .. versionchanged:: 1.8.0 + Added the ED25519_SIGNING, LINK_CERT, ED25519_AUTHENTICATE, + ED25519_IDENTITY, HS_V3_DESC_SIGNING, HS_V3_INTRO_AUTH, NTOR_ONION_KEY, + and HS_V3_NTOR_ENC certificate types. + + ========================= =========== + CertType Description + ========================= =========== + **LINK** link key certificate certified by RSA1024 identity + **IDENTITY** RSA1024 Identity certificate + **AUTHENTICATE** RSA1024 AUTHENTICATE cell link certificate + **ED25519_SIGNING** Ed25519 signing key, signed with identity key + **LINK_CERT** TLS link certificate, signed with ed25519 signing key + **ED25519_AUTHENTICATE** Ed25519 AUTHENTICATE cell key, signed with ed25519 signing key + **ED25519_IDENTITY** Ed25519 identity, signed with RSA identity + **HS_V3_DESC_SIGNING** hidden service v3 short-term descriptor signing key + **HS_V3_INTRO_AUTH** hidden service v3 introduction point authentication key + **NTOR_ONION_KEY** ntor onion key cross-certifying ed25519 identity key + **HS_V3_NTOR_ENC** hidden service v3 ntor-extra encryption key + **UNKNOWN** unrecognized certificate type + ========================= ===========
.. data:: CloseReason (enum)
@@ -201,9 +218,17 @@ RelayCommand = _IntegerEnum( )
CertType = _IntegerEnum( - ('LINK', 1), - ('IDENTITY', 2), - ('AUTHENTICATE', 3), + ('LINK', 1), # (tor-spec.txt section 4.2) + ('IDENTITY', 2), # (tor-spec.txt section 4.2) + ('AUTHENTICATE', 3), # (tor-spec.txt section 4.2) + ('ED25519_SIGNING', 4), # (prop220 section 4.2) + ('LINK_CERT', 5), # (prop220 section 4.2) + ('ED25519_AUTHENTICATE', 6), # (prop220 section 4.2) + ('ED25519_IDENTITY', 7), # (prop220 section 4.2) + ('HS_V3_DESC_SIGNING', 8), # (rend-spec-v3.txt, "DESC_OUTER" description) + ('HS_V3_INTRO_AUTH', 9), # (rend-spec-v3.txt, "auth-key" description) + ('NTOR_ONION_KEY', 10), # (dir-spec.txt, "ntor-onion-key-crosscert" description) + ('HS_V3_NTOR_ENC', 11), # (rend-spec-v3.txt, "enc-key-cert" description) )
CloseReason = _IntegerEnum( diff --git a/stem/descriptor/certificate.py b/stem/descriptor/certificate.py index 05e0eefb..c0897b13 100644 --- a/stem/descriptor/certificate.py +++ b/stem/descriptor/certificate.py @@ -27,14 +27,14 @@ used to for a variety of purposes...
.. data:: CertType (enum)
- Purpose of Ed25519 certificate. As new certificate versions are added this - enumeration will expand. - - For more information see... + Purpose of Ed25519 certificate. For more information see...
* `cert-spec.txt https://gitweb.torproject.org/torspec.git/tree/cert-spec.txt`_ section A.1 * `rend-spec-v3.txt https://gitweb.torproject.org/torspec.git/tree/rend-spec-v3.txt`_ appendix E
+ .. deprecated:: 1.8.0 + Replaced with :data:`stem.client.datatype.CertType` + ======================== =========== CertType Description ======================== =========== @@ -80,19 +80,25 @@ import stem.descriptor.hidden_service import stem.descriptor.server_descriptor import stem.util.enum import stem.util.str_tools -import stem.util
from stem.client.datatype import Size -from cryptography.hazmat.primitives import serialization + +# TODO: Importing under an alternate name until we can deprecate our redundant +# CertType enum in Stem 2.x. + +from stem.client.datatype import CertType as ClientCertType
ED25519_HEADER_LENGTH = 40 ED25519_SIGNATURE_LENGTH = 64
CertType = stem.util.enum.UppercaseEnum( - 'RESERVED_0', 'RESERVED_1', 'RESERVED_2', 'RESERVED_3', - 'SIGNING', 'LINK_CERT', 'AUTH', 'RESERVED_RSA', - 'HS_V3_DESC_SIGNING', 'HS_V3_INTRO_AUTH', 'RESERVED_0A', - 'HS_V3_INTRO_ENC', 'HS_V3_NTOR_ENC') + 'SIGNING', + 'LINK_CERT', + 'AUTH', + 'HS_V3_DESC_SIGNING', + 'HS_V3_INTRO_AUTH', + 'HS_V3_INTRO_ENCRYPT', +)
ExtensionType = stem.util.enum.Enum(('HAS_SIGNING_KEY', 4),) ExtensionFlag = stem.util.enum.UppercaseEnum('AFFECTS_VALIDATION', 'UNKNOWN') @@ -159,7 +165,6 @@ class Ed25519Certificate(object): def _parse(descriptor, entries): value, block_type, block_contents = entries[keyword][0]
- # XXX ATAGAR This ValueError never actually surfaces if it triggers... if not block_contents or block_type != 'ED25519 CERT': raise ValueError("'%s' should be followed by a ED25519 CERT block, but was a %s" % (keyword, block_type))
@@ -176,7 +181,8 @@ class Ed25519CertificateV1(Ed25519Certificate): Version 1 Ed25519 certificate, which are used for signing tor server descriptors.
- :var CertType type: certificate purpose + :var stem.client.datatype.CertType type: certificate purpose + :var int type_int: integer value of the certificate purpose :var datetime expiration: expiration of the certificate :var int key_type: format of the key :var bytes key: key content @@ -190,17 +196,14 @@ class Ed25519CertificateV1(Ed25519Certificate): if len(decoded) < ED25519_HEADER_LENGTH + ED25519_SIGNATURE_LENGTH: raise ValueError('Ed25519 certificate was %i bytes, but should be at least %i' % (len(decoded), ED25519_HEADER_LENGTH + ED25519_SIGNATURE_LENGTH))
- cert_type = stem.util.str_tools._to_int(decoded[1:2]) - try: - self.type = CertType.keys()[cert_type] - except IndexError: - raise ValueError('Certificate has wrong cert type') - - # Catch some invalid cert types - if self.type in ('RESERVED_0', 'RESERVED_1', 'RESERVED_2', 'RESERVED_3'): - raise ValueError('Ed25519 certificate cannot have a type of %i. This is reserved to avoid conflicts with tor CERTS cells.' % cert_type) - elif self.type == ('RESERVED_RSA'): + self.type, self.type_int = ClientCertType.get(stem.util.str_tools._to_int(decoded[1:2])) + + if self.type in (ClientCertType.LINK, ClientCertType.IDENTITY, ClientCertType.AUTHENTICATE): + raise ValueError('Ed25519 certificate cannot have a type of %i. This is reserved for CERTS cells.' % self.type_int) + elif self.type == ClientCertType.ED25519_IDENTITY: raise ValueError('Ed25519 certificate cannot have a type of 7. This is reserved for RSA identity cross-certification.') + elif self.type == ClientCertType.UNKNOWN: + raise ValueError('Ed25519 certificate type %i is unrecognized' % self.type_int)
# expiration time is in hours since epoch try: @@ -363,8 +366,8 @@ class MyED25519Certificate(object): version=1): """ :var int version - :var int cert_type - :var CertType cert_type + :var stem.client.datatype.CertType cert_type + :var int cert_type_int :var datetime expiration_date :var int cert_key_type :var ED25519PublicKey certified_pub_key @@ -372,7 +375,7 @@ class MyED25519Certificate(object): :var bool include_signing_key """ self.version = version - self.cert_type = cert_type + self.cert_type, self.cert_type_int = ClientCertType.get(cert_type) self.expiration_date = expiration_date self.cert_key_type = cert_key_type self.certified_pub_key = certified_pub_key @@ -391,6 +394,7 @@ class MyED25519Certificate(object): Build the cert extensions part of the certificate """
+ from cryptography.hazmat.primitives import serialization n_extensions = 0
# If we need to include the signing key, let's create the extension body @@ -423,18 +427,11 @@ class MyED25519Certificate(object):
def encode(self): """Return a bytes representation of this certificate.""" + from cryptography.hazmat.primitives import serialization obj = bytearray()
- # Encode VERSION obj += Size.CHAR.pack(self.version) - - # Encode CERT_TYPE - try: - cert_type_int = CertType.index_of(self.cert_type) - except ValueError: - raise ValueError("Bad cert type %s" % self.cert_type) - - obj += Size.CHAR.pack(cert_type_int) + obj += Size.CHAR.pack(self.cert_type_int)
# Encode EXPIRATION_DATE expiration_seconds_since_epoch = stem.util.datetime_to_unix(self.expiration_date) diff --git a/stem/descriptor/hidden_service.py b/stem/descriptor/hidden_service.py index 49009a6a..1a2ce69c 100644 --- a/stem/descriptor/hidden_service.py +++ b/stem/descriptor/hidden_service.py @@ -45,8 +45,9 @@ import stem.util.connection import stem.util.str_tools import stem.util.tor_tools
+from stem.client.datatype import CertType from stem.descriptor import hsv3_crypto -from stem.descriptor.certificate import Ed25519Certificate, CertType +from stem.descriptor.certificate import Ed25519Certificate
from cryptography.hazmat.primitives import serialization from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey @@ -255,7 +256,7 @@ class IntroductionPointV3(object): body += b'enc-key ntor %s\n' % (base64.b64encode(enc_key_bytes))
# Build enc key cert (this does not actually need to certify anything because of #29583) - enc_key_cert = stem.descriptor.certificate.MyED25519Certificate(cert_type = CertType.HS_V3_INTRO_ENC, expiration_date = cert_expiration_date, cert_key_type = 1, certified_pub_key = self.auth_key, signing_priv_key = descriptor_signing_privkey, include_signing_key = True) + enc_key_cert = stem.descriptor.certificate.MyED25519Certificate(cert_type = CertType.HS_V3_NTOR_ENC, expiration_date = cert_expiration_date, cert_key_type = 1, certified_pub_key = self.auth_key, signing_priv_key = descriptor_signing_privkey, include_signing_key = True) enc_key_cert_b64_blob = enc_key_cert.encode_for_descriptor() body += b'enc-key-cert\n%s\n' % (enc_key_cert_b64_blob)
diff --git a/test/unit/client/cell.py b/test/unit/client/cell.py index 22843799..33df79a7 100644 --- a/test/unit/client/cell.py +++ b/test/unit/client/cell.py @@ -148,9 +148,9 @@ class TestCell(unittest.TestCase): expected_certs = ( (CertType.LINK, 1, b'0\x82\x02F0\x82\x01\xaf'), (CertType.IDENTITY, 2, b'0\x82\x01\xc90\x82\x012'), - (CertType.UNKNOWN, 4, b'\x01\x04\x00\x06m\x1f'), - (CertType.UNKNOWN, 5, b'\x01\x05\x00\x06m\n\x01'), - (CertType.UNKNOWN, 7, b'\x1a\xa5\xb3\xbd\x88\xb1C'), + (CertType.ED25519_SIGNING, 4, b'\x01\x04\x00\x06m\x1f'), + (CertType.LINK_CERT, 5, b'\x01\x05\x00\x06m\n\x01'), + (CertType.ED25519_IDENTITY, 7, b'\x1a\xa5\xb3\xbd\x88\xb1C'), )
content = test_data('new_link_cells') diff --git a/test/unit/client/certificate.py b/test/unit/client/certificate.py index a15779f5..196dd075 100644 --- a/test/unit/client/certificate.py +++ b/test/unit/client/certificate.py @@ -13,7 +13,7 @@ class TestCertificate(unittest.TestCase): ((1, b'\x7f\x00\x00\x01'), (CertType.LINK, 1, b'\x7f\x00\x00\x01')), ((2, b'\x7f\x00\x00\x01'), (CertType.IDENTITY, 2, b'\x7f\x00\x00\x01')), ((3, b'\x7f\x00\x00\x01'), (CertType.AUTHENTICATE, 3, b'\x7f\x00\x00\x01')), - ((4, b'\x7f\x00\x00\x01'), (CertType.UNKNOWN, 4, b'\x7f\x00\x00\x01')), + ((4, b'\x7f\x00\x00\x01'), (CertType.ED25519_SIGNING, 4, b'\x7f\x00\x00\x01')), ((CertType.IDENTITY, b'\x7f\x00\x00\x01'), (CertType.IDENTITY, 2, b'\x7f\x00\x00\x01')), )
diff --git a/test/unit/descriptor/certificate.py b/test/unit/descriptor/certificate.py index 6d2fd378..26e091c1 100644 --- a/test/unit/descriptor/certificate.py +++ b/test/unit/descriptor/certificate.py @@ -12,7 +12,8 @@ import stem.util.str_tools import stem.prereq import test.require
-from stem.descriptor.certificate import ED25519_SIGNATURE_LENGTH, CertType, ExtensionType, ExtensionFlag, Ed25519Certificate, Ed25519CertificateV1, Ed25519Extension +from stem.client.datatype import CertType +from stem.descriptor.certificate import ED25519_SIGNATURE_LENGTH, ExtensionType, ExtensionFlag, Ed25519Certificate, Ed25519CertificateV1, Ed25519Extension from test.unit.descriptor import get_resource
from cryptography.hazmat.primitives import serialization @@ -61,7 +62,7 @@ class TestEd25519Certificate(unittest.TestCase): self.assertEqual(Ed25519CertificateV1, type(cert)) self.assertEqual(1, cert.version) self.assertEqual(stem.util.str_tools._to_unicode(cert_bytes), cert.encoded) - self.assertEqual(CertType.SIGNING, cert.type) + self.assertEqual(CertType.ED25519_SIGNING, cert.type) self.assertEqual(datetime.datetime(1970, 1, 1, 0, 0), cert.expiration) self.assertEqual(1, cert.key_type) self.assertEqual(b'\x03' * 32, cert.key) @@ -85,7 +86,7 @@ class TestEd25519Certificate(unittest.TestCase): self.assertEqual(Ed25519CertificateV1, type(cert)) self.assertEqual(1, cert.version) self.assertEqual(ED25519_CERT, cert.encoded) - self.assertEqual(CertType.SIGNING, cert.type) + self.assertEqual(CertType.ED25519_SIGNING, cert.type) self.assertEqual(datetime.datetime(2015, 8, 28, 17, 0), cert.expiration) self.assertEqual(1, cert.key_type) self.assertEqual(EXPECTED_CERT_KEY, cert.key) @@ -126,9 +127,12 @@ class TestEd25519Certificate(unittest.TestCase): are reserved. """
- exc_msg = 'Ed25519 certificate cannot have a type of 0. This is reserved to avoid conflicts with tor CERTS cells.' + exc_msg = 'Ed25519 certificate type 0 is unrecognized' self.assertRaisesWith(ValueError, exc_msg, Ed25519Certificate.parse, certificate(cert_type = 0))
+ exc_msg = 'Ed25519 certificate cannot have a type of 1. This is reserved for CERTS cells.' + self.assertRaisesWith(ValueError, exc_msg, Ed25519Certificate.parse, certificate(cert_type = 1)) + exc_msg = 'Ed25519 certificate cannot have a type of 7. This is reserved for RSA identity cross-certification.' self.assertRaisesWith(ValueError, exc_msg, Ed25519Certificate.parse, certificate(cert_type = 7))
diff --git a/test/unit/descriptor/server_descriptor.py b/test/unit/descriptor/server_descriptor.py index 6b91d90f..d87d51e9 100644 --- a/test/unit/descriptor/server_descriptor.py +++ b/test/unit/descriptor/server_descriptor.py @@ -20,8 +20,9 @@ import stem.version import stem.util.str_tools import test.require
+from stem.client.datatype import CertType from stem.descriptor import DigestHash, DigestEncoding -from stem.descriptor.certificate import CertType, ExtensionType +from stem.descriptor.certificate import ExtensionType from stem.descriptor.server_descriptor import BridgeDistribution, RelayDescriptor, BridgeDescriptor
from test.unit.descriptor import ( @@ -366,7 +367,7 @@ Qlx9HNCqCY877ztFRC624ja2ql6A2hBcuoYMbkHjcQ4= ])
self.assertEqual(1, desc.certificate.version) - self.assertEqual(CertType.SIGNING, desc.certificate.type) + self.assertEqual(CertType.ED25519_SIGNING, desc.certificate.type) self.assertEqual(datetime.datetime(2015, 8, 28, 17, 0, 0), desc.certificate.expiration) self.assertEqual(1, desc.certificate.key_type) self.assertTrue(desc.certificate.key.startswith(b'\xa5\xb6\x1a\x80D\x0f'))