Example #1
0
    def get_certificate_by_digest(self, digest):
        '''
		Obtain certificate by its digest.
		Firstly, look at the certificate store in a memory.
		Secondly, look at the certificate store at the local drive.
		Lastly, use AA API to fetch certficate.
		'''
        try:
            return self.Certs[digest]
        except KeyError:
            pass

        cert_fname = os.path.join(self.Directory, "certs",
                                  digest.hex() + '.cert')

        cert = None
        try:
            f = open(cert_fname, 'rb')
            data = f.read()
            cert = itss.CITS103097v121Certificate(data)

        except FileNotFoundError:
            cert = None

        if cert is None:
            r = requests.get(self.AA_url +
                             '/cits/digest/{}'.format(digest.hex()))
            cert = itss.CITS103097v121Certificate(r.content)
            self.store_certificate(cert)

        self.Certs[digest] = cert
        return cert
Example #2
0
    def load(self):
        assert (self.EC is None)
        assert (self.AT is None)

        ok = self.HSM.load()
        if not ok:
            return False

        try:
            ecraw = open(os.path.join(self.Directory, 'itss.ec'), 'rb').read()
        except FileNotFoundError:
            pass
        else:
            self.EC = itss.CITS103097v121Certificate(ecraw)

        try:
            atraw = open(os.path.join(self.Directory, 'itss.at'), 'rb').read()
        except FileNotFoundError:
            pass
        else:
            self.AT = itss.CITS103097v121Certificate(atraw)

        return True
Example #3
0
    def enroll(self, enrollment_id):
        '''
		Send Enrollment request to Enrollment Authority and process the response.
		The process is described in CITS / ETSI TS 102 941 V1.1.1
		'''

        verification_public_key = self.HSM.get_public_key()
        verification_public_numbers = verification_public_key.public_numbers()

        response_encryption_private_key = cryptography.hazmat.primitives.asymmetric.ec.generate_private_key(
            cryptography.hazmat.primitives.asymmetric.ec.SECP256R1(),
            cryptography.hazmat.backends.default_backend())

        response_encryption_public_key = response_encryption_private_key.public_key(
        )
        response_encryption_public_numbers = response_encryption_public_key.public_numbers(
        )

        requestTime = int((datetime.datetime.utcnow() -
                           datetime.datetime(2004, 1, 1)).total_seconds())
        expiration = requestTime + 3600  # 1 hour

        EnrolmentRequest = \
        {
         # The canonical certificate or the public/private key pair that uniquely identifies the ITS-S
         'signerEnrolRequest':
         {
          'type': 3, # SignerIdType.certificate (fixed)
          'digest': b'12345678',
          'id': enrollment_id.encode('utf-8'), # Can be used to link request with a preauthorization at EA
         },
         'enrolCertRequest':
         {
          'versionAndType': 2, # explicitCert (fixed)
          'requestTime': requestTime,
          'subjectType': 3, # SecDataExchCsr (fixed)
          'cf': (b'\0',0), # useStartValidity, shall not be set to include the encryption_key flag
          'enrolCertSpecificData': {
           'eaId': 'EAName', # Name (What to set?)
           'permittedSubjectTypes': 0, # secDataExchAnonymousSubj (or secDataExchidentifiedLocalizedSubj)
           'permissions': { # PsidSspArray
            'type': 1, # ArrayType / specified
            'permissions-list': [] # shall contain a list of the ETSI ITS-AIDs to be supported.
           },
           'region': {
            'region-type': 0 # RegionType / from-issuer
           }
          },
          'expiration': requestTime,
          'verificationKey': {
           'algorithm': 1, # PKAlgorithm ecdsaNistp256WithSha256 (fixed)
           'public-key': {
            'type': 'uncompressed', # EccPublicKeyType uncompressed
            'x': (
             'ecdsa-nistp256-with-sha256-X',
             verification_public_numbers.x
            ),
            'y': (
             'ecdsa-nistp256-with-sha256-Y',
             verification_public_numbers.y
            )
           }
          },
          'responseEncryptionKey': {
           'algorithm': 1, # PKAlgorithm ecdsaNistp256WithSha256
           'public-key': {
            'type': 'compressedLsbY0', # EccPublicKeyType compressedLsbY0
            'x': (
             'ecdsa-nistp256-with-sha256-X',
             response_encryption_public_numbers.x,
            )
           }
          },
         }
        }

        encoded_er = b''
        encoded_er += struct.pack(">B", 0xa0) + self.asn1.encode(
            'SignerIdentifier', EnrolmentRequest['signerEnrolRequest'])[1:]
        encoded_er += struct.pack(">B", 0xa1) + self.asn1.encode(
            'ToBeSignedEnrolmentCertificateRequest',
            EnrolmentRequest['enrolCertRequest'])[1:]

        # Sign with ecdsa_nistp256_with_sha256
        r, s = self.HSM.sign(encoded_er)

        EnrolmentRequest['signature'] = {
            'r': {
                'type': 'xCoordinateOnly',
                'x': ('ecdsa-nistp256-with-sha256-X', r),
            },
            's': ('ecdsa-nistp256-with-sha256-s', s)
        }
        encoded_er += struct.pack(">B", 0xa2) + self.asn1.encode(
            'Signature', EnrolmentRequest['signature'])[1:]

        encoded_er = itss.encode_der_SEQUENCE(encoded_er)

        # Send request to Enrollment Authority
        r = requests.put(self.EA_url + '/cits/ts_102941_v111/ea/enroll',
                         data=encoded_er)

        EnrolmentResponse = self.asn1.decode('EnrolmentResponse', r.content)
        if EnrolmentResponse[0] != 'successfulEnrolment':
            print("Enrollment failed!")
            pprint.pprint(EnrolmentResponse)
            sys.exit(1)

        print("Enrollment finished successfuly.")
        self.EC = itss.CITS103097v121Certificate(
            EnrolmentResponse[1]['signedCertChain']['rootCertificate'])
Example #4
0
    def authorize(self):
        requestTime = int((datetime.datetime.utcnow() -
                           datetime.datetime(2004, 1, 1)).total_seconds())
        expiration = requestTime + 3600  # 1 hour

        AuthorizationRequest = {

            # The enrolment certificate containing the pseudonymous identifier to be used by the ITS-S
            'signerAuthRequest': {
                'type': 3,  # SignerIdType.certificate (fixed)
                'digest': self.EC.Digest,
                'id': uuid.uuid4().hex.encode(
                    'ascii'),  #TODO: Check if this is pseudorandom ID
            },
            'authCertRequest': (
                'anonRequest',
                {
                    'versionAndType': 2,  # explicitCert (fixed)
                    'requestTime': requestTime,
                    'subjectType': 0,  # SecDataExchAnon (fixed)
                    'cf': (b'\0', 0),  # useStartValidity
                    'authCertSpecificData': {
                        'additional-data': b'ahoj',
                        'permissions': {  # PsidSspArray
                            'type': 1,  # ArrayType / specified
                            'permissions-list': [
                            ]  # shall contain a list of the ETSI ITS-AIDs to be supported.
                        },
                        'region': {
                            'region-type': 0  # RegionType / from-issuer
                        }
                    },
                    'responseEncryptionKey': {
                        'algorithm': 1,  # PKAlgorithm ecdsaNistp256WithSha256
                        'public-key': {
                            'type':
                            'compressedLsbY0',  # EccPublicKeyType compressedLsbY0
                            'x': (
                                'ecdsa-nistp256-with-sha256-X',
                                0,  #response_encryption_public_numbers.x,
                            )
                        }
                    },
                }),
        }

        encoded_ar = b''
        encoded_ar += struct.pack(">B", 0xa0) + self.asn1.encode(
            'SignerIdentifier', AuthorizationRequest['signerAuthRequest'])[1:]
        acr = struct.pack(">B", 0xa0) + self.asn1.encode(
            'AuthCertRequest', AuthorizationRequest['authCertRequest'])[1:]
        encoded_ar += struct.pack(">B", 0xa1) + itss.encode_der_length(
            len(acr)) + acr

        # Sign with ecdsa_nistp256_with_sha256
        r, s = self.HSM.sign(encoded_ar)

        AuthorizationRequest['signature'] = {
            'r': {
                'type': 'xCoordinateOnly',
                'x': ('ecdsa-nistp256-with-sha256-X', r),
            },
            's': ('ecdsa-nistp256-with-sha256-s', s)
        }

        encoded_ar += struct.pack(">B", 0xa2) + self.asn1.encode(
            'Signature', AuthorizationRequest['signature'])[1:]
        encoded_ar = itss.encode_der_SEQUENCE(encoded_ar)

        # Send request to Authorization Authority
        r = requests.put(self.AA_url + '/cits/ts_102941_v111/aa/approve',
                         data=encoded_ar)
        if (r.status_code != 200):
            raise RuntimeError(
                "Server error when calling AA approve: {}".format(
                    r.status_code))

        AuthorizationResponse = self.asn1.decode('AuthorizationResponse',
                                                 r.content)
        if AuthorizationResponse[0] not in ('successfulExplicitAuthorization',
                                            'successfulImplicitAuthorization'):
            print("Authorization failed!")
            pprint.pprint(AuthorizationResponse)
            sys.exit(1)

        # TODO: Handle also CRL (they can be part of the AuthorizationResponse)

        print("Authorization ticket obtained successfuly.")
        self.AT = itss.CITS103097v121Certificate(
            AuthorizationResponse[1]['signedCertChain']['rootCertificate'])