Ejemplo n.º 1
0
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()
Ejemplo n.º 2
0
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()
Ejemplo n.º 3
0
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()
Ejemplo n.º 4
0
def status():
    return_data = {'active': server_active, 'identity': SERVER_IDENTITY}
    rv = KeyExReturn.OK(json.dumps(return_data))
    return rv()