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
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
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'])
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'])