Exemple #1
0
    def __init__(self, **kw):
        if len(kw) != len(self.__fields__):
            raise exceptions.ProtocolError("Field length mismatch")

        for key, _ in self.__fields__:
            val = kw.get(key, None)
            if val is None:
                raise exceptions.ProtocolError("Missing required argument "
                                               "'%s'" % key)
            setattr(self, key, val)
Exemple #2
0
 def _do_deserialize(cls, serialized):
     stream = io.BytesIO(serialized)
     unpacker = msgpack.Unpacker(stream)
     version = unpacker.unpack()
     if version != PROTOCOL_VERSION:
         raise exceptions.ProtocolError(
             "Wrong version, expected %d got %d" %
             (PROTOCOL_VERSION, version))
     magic = unpacker.unpack()
     if magic != cls.__magic__:
         raise exceptions.ProtocolError("Wrong magic, expected %d got %d" %
                                        (cls.__magic__, magic))
     kw = dict()
     for name, type_info in cls.__fields__:
         kw[name] = unpacker.unpack()
     return cls(**kw), unpacker
Exemple #3
0
    def deserialize(cls, buf):
        if cls.__magic__ is None or cls.__fields__ is None:
            raise exceptions.ProtocolError(
                "Deserialization can only be performed on classes "
                "implementing __fields__ and __magic__")

        u = unpacker_class(buf)

        if u.unpack_fstring(1) != cls.__magic__:
            raise exceptions.ProtocolError("Wrong magic byte for " +
                                           cls.__name__ + " (should be '" +
                                           hex(ord(cls.__magic__)) + "')")

        kw = dict()

        for name, field in cls.__fields__:
            kw[name] = field.unpack(u)

        return cls(**kw)
Exemple #4
0
    def serialize(self):
        if self.__magic__ is None or self.__fields__ is None:
            raise exceptions.ProtocolError(
                "Serialization can only be performed on classes implementing "
                "__fields__ and __magic__")

        p = packer_class()

        p.pack_fstring(1, self.__magic__)

        for name, field in self.__fields__:
            value = getattr(self, name)
            field.pack(p, value)

        return p.get_buffer()
Exemple #5
0
def create_response(challenge, server_name, signer_plug=None):
    """Called by a client with the challenge provided by the server
    to generate a response using the local ssh-agent"""

    b = ssh.base64url_decode(challenge)

    if b[0] == 'v':
        # this is version 0 challenge
        hmac_challenge = protocol.VerifiablePayload.deserialize(b)
        challenge = protocol.Challenge.deserialize(hmac_challenge.payload)
        to_sign = hmac_challenge.payload
        version_1 = False
    elif b[0] == '\x01':
        # version 1
        challenge = msgpack_protocol.Challenge.deserialize(b)
        to_sign = b
        version_1 = True
    else:
        raise exceptions.ProtocolError("invalid first byte of challenge")

    if challenge.server_name != server_name:
        s = ("Possible MITM attack. Challenge originates from '%s' "
             "and not '%s'" % (challenge.server_name, server_name))
        raise exceptions.InvalidInputException(s)

    if not signer_plug:
        signer_plug = ssh.AgentSigner()

    signature = signer_plug.sign(to_sign, challenge.fingerprint)

    signer_plug.close()

    if version_1:
        response = msgpack_protocol.Response(challenge=b, signature=signature)
    else:
        response = protocol.Response(signature=signature,
                                     hmac_challenge=hmac_challenge)

    return ssh.base64url_encode(response.serialize())
Exemple #6
0
    def create_token(self, response):
        """
        This method verifies that the response given from the client
        is valid and if so returns a token used for authentication.
        """
        s = ssh.base64url_decode(response)

        if s[0] == 'r':
            # this is a version 0 response
            version_1 = False
            if self.lowest_supported_version > 0:
                raise exceptions.ProtocolVersionError(
                    "Client needs to support at least version %d" %
                    self.lowest_supported_version)
            r = protocol.Response.deserialize(s)
            if not r.hmac_challenge.verify(self._hmac):
                raise exceptions.InvalidInputException(
                    "Challenge hmac verification failed, not matching  secret")
            challenge = protocol.Challenge.deserialize(
                r.hmac_challenge.payload)
        elif s[0] == '\x01':
            # this is a version 1 response
            version_1 = True
            r = msgpack_protocol.Response.deserialize(s)
            challenge = msgpack_protocol.Challenge.deserialize_authenticated(
                r.challenge, self.secret)
        else:
            raise exceptions.ProtocolError("invalid first byte of response")

        # verify the integrity of the challenge in the response
        if self.server_name != challenge.server_name:
            s = "Got challenge with the wrong server_name encoded"
            raise exceptions.InvalidInputException(s)

        key = self.key_provider.get_key(challenge.username)

        if version_1:
            if not key.verify_signature(r.signature, r.challenge):
                raise exceptions.InvalidInputException(
                    "Client did not provide proof that it controls "
                    "the secret key")
        else:
            if not key.verify_signature(r.signature, r.hmac_challenge.payload):
                raise exceptions.InvalidInputException(
                    "Client did not provide proof that it controls "
                    "the secret key")

        if challenge.valid_from > self.now_func():
            s = time.strftime("%Y-%m-%d %H:%M:%S UTC",
                              time.gmtime(challenge.valid_from))
            raise exceptions.InvalidInputException("Response with challenge "
                                                   "created as %s too new " %
                                                   s)

        if challenge.valid_to < self.now_func():
            s = time.strftime("%Y-%m-%d %H:%M:%S UTC",
                              time.gmtime(challenge.valid_from))
            raise exceptions.InvalidInputException("Response with challenge "
                                                   "created as %s too old " %
                                                   s)

        expire_time = int(self.now_func()) + self.token_lifetime

        return self._make_token(challenge.username, expire_time)