def access_keys(): access_key_data = request.get_json() identity = access_key_data['identity'] csr_data = base64.decodebytes(access_key_data['csr'].encode()) signature = base64.decodebytes(access_key_data['signature'].encode()) key_string = database_functions.get_key(DATABASE_FILE, identity) # ...and we need to restore the key to the full PEM format that the RSA functions are expecting. restored_key = KeyEx_helpers.fixkey(key_string) # Now we can import that restored key string into a full RSA key object, get the SAH256 hash for the # message (the device ID), and create a verifier object to check the signature... pbkey = serialization.load_pem_public_key(restored_key.encode(), backend=default_backend()) # Validate that the signature is valid for the csr_data signed by this device... try: pbkey.verify( signature, csr_data, padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH), hashes.SHA256()) # We're okay – so sign it... with open(CA_KEY, 'rb') as f: ca_key_data = f.read() ca_key = serialization.load_pem_private_key(ca_key_data, b'rabbit', default_backend()) csr = x509.load_pem_x509_csr(csr_data, default_backend()) with open(CA_CRT, 'rb') as f: ca_crt_data = f.read() ca_crt = x509.load_pem_x509_certificate(ca_crt_data, default_backend()) if isinstance(csr.signature_hash_algorithm, hashes.SHA256): cert = x509.CertificateBuilder().subject_name(csr.subject).issuer_name(ca_crt.issuer).public_key\ (csr.public_key()).serial_number(x509.random_serial_number()).not_valid_before\ (datetime.datetime.utcnow()).not_valid_after(datetime.datetime.utcnow() + datetime.timedelta(days=365))\ .sign(ca_key, hashes.SHA256(), default_backend()) return_data = { 'certificate': base64.encodebytes( cert.public_bytes(serialization.Encoding.PEM)).decode(), 'CA_certificate': base64.encodebytes(ca_crt_data).decode() } rv = KeyExReturn.OK(json.dumps(return_data)) return rv() except (InvalidSignature, ValueError, TypeError) as e: rv = KeyExReturn.CSRVerificationError() return rv()
def validate(): validation_data = request.get_json() identity = validation_data['identity'] # Because the signatures are composed of arbitrary byte-streams we need to base64 encode them before trying to put # them into a JSON object - and so we must reverse that process here... signature = base64.decodebytes(validation_data['signature'].encode()) # Next we need to get the key string associated with the public key for the device that's claiming to have the # specified identity... key_string = database_functions.get_key(DATABASE_FILE, identity) # ...and we need to restore the key to the full PEM format that the RSA functions are expecting. restored_key = KeyEx_helpers.fixkey(key_string) # Now we can import that restored key string into a full RSA key object, get the SAH256 hash for the # message (the device ID), and create a verifier object to check the signature... pbkey = serialization.load_pem_public_key(restored_key.encode(), backend=default_backend()) # If the verifier passes the device key we have is a valid public key for the private key that the device is using try: pbkey.verify( signature, identity.encode(), padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH), hashes.SHA256()) # If we get here without throwing an exception then the signature was valid: so we'll return our own identity, # signed with our private key with open(SERVER_PRIVATE_KEY_FILE, "rb") as key_file: private_key = serialization.load_pem_private_key( key_file.read(), password=None, backend=default_backend()) signature = private_key.sign( SERVER_IDENTITY.encode(), padding.PSS(mgf=padding.MGF1(hashes.SHA256()), salt_length=padding.PSS.MAX_LENGTH), hashes.SHA256()) # Note that as before - we must use base64 encoding before we can serialize this into JSON. return_data = { 'identity': SERVER_IDENTITY, 'signature': base64.encodebytes(signature).decode() } # Lastly we return the data, with a HTTP 200 rv = KeyExReturn.OK(json.dumps(return_data)) return rv() # If we threw an exception then the key didn't validate - so we must return a signature validation error (HTTP 400) except (InvalidSignature, ValueError, TypeError) as e: rv = KeyExReturn.SignatureVerificationError() return rv()
def get_pub_key(identity): # Given that we only need to pass one value – we won't use JSON – but rather use a simple # argument...e.g. .../get_key/a3ca9020-b2dc-4d4d-bbf9-42320c7730a0 # Get the key - if we have it... key_string = database_functions.get_key(DATABASE_FILE, identity) if key_string is None: # We don't have a key for this identity... rv = KeyExReturn.IDNotFound() else: # We have the key - so now we need to restore the key to the full PEM format # that RSA functions will expecting... restored_key = KeyEx_helpers.fixkey(key_string) # And to return this complete key to the C2 server we need to first Base64 encode it. encoded_key = base64.encodebytes(restored_key.encode()) rv = KeyExReturn.OK(encoded_key) return rv()
def status(): return_data = {'active': server_active, 'identity': SERVER_IDENTITY} rv = KeyExReturn.OK(json.dumps(return_data)) return rv()