Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Printing of Authorization bits from BSI TR 03110-4 #7

Merged
merged 5 commits into from
Oct 7, 2023

Conversation

xoryouyou
Copy link
Contributor

I've been using pycvc more often and thought it would be nice to see which rights/bits are actually set in an certificate for an AuthenticationTerminal.

The BSI TR 03110-4 specifies these bits in Table 4 in the TR 03110-4
https://www.bsi.bund.de/SharedDocs/Downloads/EN/BSI/Publications/TechGuidelines/TR03110/BSI_TR-03110_Part-4_V2-2.pdf?__blob=publicationFile&v=1

image

I've added a method decode_authorization_bits onto the CVC class to decode the bits and order them properly https://github.com/xoryouyou/pycvc/blob/main/cvc/certificates.py#L36

The actual bits are declared in a dict at https://github.com/xoryouyou/pycvc/blob/main/cvc/tools/cvc_print.py#L36
which allows the lookup and human readable usage of while checking the bits of a certificate.

I've also added a --print-bits argument to the argparse at https://github.com/xoryouyou/pycvc/blob/main/cvc/tools/cvc_print.py#L85

which then triggers an if further down in https://github.com/xoryouyou/pycvc/blob/main/cvc/tools/cvc_print.py#L134
and prints the detailed bits in formation for the given certificate.

E.g.

  CHR: ZZATTERM00001
  CHAT:
    Role:  TypeAT
        Field 'Upper Role Bit                  ' has value: False  at offset: 39
        Field 'Lower Role Bit                  ' has value: False  at offset: 38
        Field 'Write Datagroup 17              ' has value: False  at offset: 37
        Field 'Write Datagroup 18              ' has value: False  at offset: 36
        Field 'Write Datagroup 19              ' has value: False  at offset: 35
        Field 'Write Datagroup 20              ' has value: False  at offset: 34
        Field 'Write Datagroup 21              ' has value: False  at offset: 33
        Field 'Write Datagroup 22              ' has value:  True  at offset: 32
        Field 'RFU                             ' has value: False  at offset: 31
        Field 'PSA                             ' has value: False  at offset: 30
        Field 'Read Datagroup 22               ' has value: False  at offset: 29
        Field 'Read Datagroup 21               ' has value: False  at offset: 28
        Field 'Read Datagroup 20               ' has value: False  at offset: 27
        Field 'Read Datagroup 19               ' has value: False  at offset: 26
        Field 'Read Datagroup 18               ' has value: False  at offset: 25
        Field 'Read Datagroup 17               ' has value: False  at offset: 24
        Field 'Read Datagroup 16               ' has value: False  at offset: 23
        Field 'Read Datagroup 15               ' has value: False  at offset: 22
        Field 'Read Datagroup 14               ' has value: False  at offset: 21
        Field 'Read Datagroup 13               ' has value: False  at offset: 20
        Field 'Read Datagroup 12               ' has value: False  at offset: 19
        Field 'Read Datagroup 11               ' has value: False  at offset: 18
        Field 'Read Datagroup 10               ' has value: False  at offset: 17
        Field 'Read Datagroup 09               ' has value: False  at offset: 16
        Field 'Read Datagroup 08               ' has value: False  at offset: 15
        Field 'Read Datagroup 07               ' has value: False  at offset: 14
        Field 'Read Datagroup 06               ' has value: False  at offset: 13
        Field 'Read Datagroup 05               ' has value: False  at offset: 12
        Field 'Read Datagroup 04               ' has value: False  at offset: 11
        Field 'Read Datagroup 03               ' has value: False  at offset: 10
        Field 'Read Datagroup 02               ' has value: False  at offset:  9
        Field 'Read Datagroup 01               ' has value:  True  at offset:  8
        Field 'Install Qualified Certificate   ' has value: False  at offset:  7
        Field 'Install Certificate             ' has value:  True  at offset:  6
        Field 'PIN Management                  ' has value: False  at offset:  5
        Field 'CAN allowed                     ' has value: False  at offset:  4
        Field 'Privileged Terminal             ' has value: False  at offset:  3
        Field 'Restricted Identification       ' has value:  True  at offset:  2
        Field 'Municipality ID Verification    ' has value: False  at offset:  1
        Field 'Age Verification                ' has value:  True  at offset:  0
    Bytes: 0100000145

Finally I added two dummy certificates which I created with cvc-create and put as a hex string into the test code.
These certificates have known bits set and are thus suitable to be used in an assertTrue test.

As a helper function to create a hexlified cvcert I've added https://github.com/xoryouyou/pycvc/blob/main/tests/cvcert_to_hexstring.py

I have no clue if I've put things where they belong in your project but placed them by gut feeling.
Also I tried to comment everything as detailed as possible which IMHO helps when dealing with the certificates and BSI TRs :)

Would like to get your feedback on this and possibly merge the functionality if you like it.

Cleaned up the bits_test and added asserts
Also added utility to convert arbitrary files to hexstring
and added --print-bits flag
def main(args):
print("ARGS",args)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be removed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah, missed that one 😃

@@ -31,12 +31,58 @@
logger = logging.getLogger(__name__)
cert_dir = b''

# Authorization bits according to
# BSI-TR-03110-4 Chapter 2.2.3.2 Table 4
AuthorizationBits = {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not necessary to have a dict, a reverse list is sufficient.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the explicit functionality to check set bits with human readable strings like self.assertTrue(bits[AuthorizationBits["Age Verification"]])

How would you structure the code with a reverse list ?

@@ -38,6 +38,20 @@ def decode(self, data):
self.__a = ASN1().decode(self.__data)
return self

def decode_authorization_bits(self):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once CHAT bytes are exposed via chat(), I am not sure the purpose of exposing them as bits. If it for just printing them, it should be placed in the printing script and not in the API.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm with you on that and moved the function over to cvc_print.py

and adapted the tests
Removed unused debug prints
@polhenarejos polhenarejos merged commit 9d7b3ee into polhenarejos:main Oct 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants