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)
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
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)
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()
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())
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)