Results 1 to 11 of 11

Thread: RFC: Secure authentication of remote-access calls

  1. #1
    Senior Member
    Join Date
    Mar 2002
    Location
    MI, U.S.
    Posts
    697

    RFC: Secure authentication of remote-access calls

    I'm not sure if there are even any crypto geeks here or not, but I figure I should probably outline this in case someone finds it useful.

    I've been playing around with a Python "fadgui", for Find-a-Drug. (Those of you that were here with DF may remember my dfGUI Linux port. Same kind of idea, except this won't be a port.)

    I've decided that I want it to be able to work with multiple machines (where dfgui only worked with one). I'm thinking of allowing people to set up multiple "clients", with separate start/stop controls for each. (There will also be the ability to have multiple servers, but that doesn't come into this discussion at the moment.) This means some kind of remote access to all the client systems (the ones running FaD). I figure I'll write a server that takes XML-RPC commands (fadguid), and have people run it on each of their clients. Then fadgui itself will use the XML-RPC channel to control (and monitor) each client.

    Since I'm writing this in Python, I figured I'd use Python's xmlrpclib and SimpleXMLRPCServer packages in fadgui and fadguid. But before I can do that correctly, I need to have some way of authenticating the fadgui machine from fadguid, so that it doesn't take commands from anyone except that machine. And it'd be nice if fadgui could also authenticate the fadguid boxes, so that it would know that it isn't connecting to a man-in-the-middle, but rather the real fadguid instance that it wants to control.

    So here's what I've come up with. I'd like to know what people think -- if you think there are possible holes in it anywhere. I DO NOT want to open up any kind of access to your machines!

    This is intended to be used for fadgui, but could just as easily be used for any other remote-call authentication that may be needed. (So I didn't think the FaD forum was appropriate. If I guessed wrong, somebody please move this thread. Thanks! )

    Setup steps, AKA distributing the keys:

    1) From the machine you will be running fadgui on, run ./fadgui.py --gen-master-key. This will generate what I call a "master" keypair. The private key in this pair will identify the fadgui machine, so KEEP IT SECRET. Don't copy it anywhere. If someone gets remote root access to your fadgui machine, they will be able to control all your FaD clients using this key, so go through the whole setup again if that happens.

    2) Copy the resulting public key file to each fadguid machine.

    3) On each fadguid machine, run ./fadguid.py --use-master-key <filename>, which will take the public key out of the public key file and put it in the fadguid config file.

    4) Still on each fadguid machine, run ./fadguid.py --gen-key. This generates a "client" public/private keypair, whose private key uniquely identifies each fadguid machine.

    5) Copy the public key from each fadguid machine back to the main fadgui machine.

    6) On the fadgui machine, do a ./fadgui.py --use-key <hostname>. This hooks up <hostname> to the public key that's stored in <hostname>.key (this should be the file you copy from each fadguid machine) in the fadgui configuration.

    Setup is now finished. Each machine has generated a public and private key pair, and each public key has been copied to (and imported on) each machine that needs it.

    On each request, the programs will do this:

    1) Call a special function over the XML-RPC link, which will return an encrypted "nonce". The nonce is just a long random value. It gets encrypted with the fadguid machine's private key.

    2) The fadgui machine will use the fadguid machine's public key to decrypt the returned data back into the nonce, and check that it's valid. (Some constant data may be included after the nonce, so that the decryption can check this data, and fail if someone used the wrong fadguid private key originally.)

    3) The fadgui machine will then re-encrypt the decrypted nonce, this time with its own private key. It will send the resulting encrypted value as the first argument for the next XML-RPC call that it makes.

    4) The fadguid machine will decrypt the first argument using the "master" public key, and if it matches any nonce that it has stored, it will consider this call authenticated. It will also remove that nonce, so it can't be used again. If authentication succeeds, the command in question is carried out. Otherwise, it won't be.

    Upsides:

    1) Uses public-key encryption (I'm thinking RSA, but I'll figure out which specific algorithm later). This isn't some home-grown XOR authentication.

    2) Will use openssl to do the actual encryption, so if a hole is found in openssl, it can be upgraded separately from fadguid.

    3) Passwords are never sent across the network in clear-text. In fact, passwords don't even exist. The nonce value acts like a one-time-password, but it's completely random.

    Downsides:

    1) Setup is slightly complicated. You have to generate a key-pair for every machine you want to monitor. You have to copy the public keys around a fair bit.

    2) If a problem in openssl is found, it will need to be upgraded. But then again, if SimpleXMLRPCServer gets another hole punched in it, you'll already need to upgrade Python anyway, so maybe this isn't a huge deal.

    3) Any holes you might find in the algorithm.

    What does everybody think? Or should I just go hire a cryptanalyst?

    Thanks!
    "If you fail to adjust your notion of fairness to the reality of the Universe, you will probably not be happy."

    -- Originally posted by Paratima

  2. #2
    Senior Member
    Join Date
    Mar 2002
    Location
    MI, U.S.
    Posts
    697
    OK, I've been thinking a bit more, and I've come up with some weaknesses. Not holes, exactly, but I could be doing a couple things a bit more securely.

    1) Don't encrypt the nonce with a private key. Anyone with the corresponding public key can decrypt it then. Instead, encrypt it with the other machine's public key. Then, you need the corresponding private key to be able to figure out the value.

    2) Instead of adding a fixed string in there to test the signature (because that's effectively all it was), I should be generating the signature, and then appending it to the encrypted value. This way, the other side can check the signature and decrypt the actual value using the other side's public key and its private key, respectively.

    So I've changed the protocol to do this:

    -----

    On each call, get_nonce() will encrypt the newly-generated random nonce value with the caller's public key. Then it will sign the result with its own private key, and append the signature to the encrypted nonce.

    When the encrypted, signed nonce comes back to the caller, it will check the signature first (using the callee's public key), then decrypt the actual nonce value (using its own private key). Then it will re-encrypt (using the callee's public key), and re-sign (using its own private key). This result will be transmitted in the actual XML-RPC call.

    When the callee gets the first parameter, it'll check the signature and decrypt the nonce, then compare the nonce to its stored list to check for authentication.

    -----

    This uses the fact that encrypt-then-authenticate (EtA) is always at least as strong as the weaker of the encryption and authentication (signature) schemes. Since I'm using the same algorithm for both, that means that EtA is as strong as whatever algorithm I use.

    The strength of AtE (authenticate, then encrypt) depends on the interaction between the encryption and authentication algorithms. It's not always as secure as EtA. And E&A (encrypt-and-authenticate, doing both in parallel) is the same -- sometimes it is as secure as EtA, sometimes it isn't.
    "If you fail to adjust your notion of fairness to the reality of the Universe, you will probably not be happy."

    -- Originally posted by Paratima

  3. #3
    dismembered Scoofy12's Avatar
    Join Date
    Apr 2002
    Location
    Between keyboard and chair
    Posts
    608
    i don't really have the expertise to evaluate your proposed protocol, but i've heard that the rule of thumb for creating security protocols (and other network protocols, even) is don't, if you can help it. its difficult to do, and you can often find some other protocol to reuse. arent there standard protocols for key exchange and secure communication? you mentioned SSL, isnt there a standard way to generate self-signed keys for SSL servers and distribute them to clients (which can be done beforehand, doesnt have to happen online)
    C-x C-c

  4. #4
    Senior Member
    Join Date
    Mar 2002
    Location
    MI, U.S.
    Posts
    697
    True. I figured this was OK because it was basically just reusing RSA, but it turns out there are a few minor problems with it, and at least one major one. Namely, an attacker acting as a man in the middle can intercept both calls, pass the first one along to the callee, receive the returned encrypted/signed nonce, then pass it back to the caller. When the attacker gets the second call, though, they can just sit on the request. Later (or immediately, it doesn't much matter), they can use the authentication "ticket" from that request to authorize a request of their own. Oops.

    So I won't be using this. I have some reading to do (someone on another forum pointed me to the Handbook of Applied Cryptography, specifically chapter 10). I'll probably post back with what I come up with, but it could be a while.

    As far as SSL goes, yes, there is a way to generate and distribute SSL keys and certs. Unfortunately, SSL isn't readily available for Python's XML-RPC, either the server or the client. I'd need a separate library to do that (M2Crypto perhaps). But I'll see if there's anything in the Handbook first -- otherwise I might just revert to SSL.
    "If you fail to adjust your notion of fairness to the reality of the Universe, you will probably not be happy."

    -- Originally posted by Paratima

  5. #5
    dismembered Scoofy12's Avatar
    Join Date
    Apr 2002
    Location
    Between keyboard and chair
    Posts
    608
    what about using SSH's public key authentication and just running the whole thing over an SSH tunnel?
    C-x C-c

  6. #6
    Senior Member
    Join Date
    Mar 2002
    Location
    MI, U.S.
    Posts
    697
    ...Yeah, maybe...

    I'd need to have 1 ssh tunnel per client machine, which would mean quite a lot of different ports (at the moment, I'm planning on using only one port -- 59684). But I suppose that's not too different from just having one connection to multiple machines.

    I'd have to have some way of spawning all the ssh tunnels, but that may not be too hard either.

    Hmm...
    "If you fail to adjust your notion of fairness to the reality of the Universe, you will probably not be happy."

    -- Originally posted by Paratima

  7. #7
    dismembered Scoofy12's Avatar
    Join Date
    Apr 2002
    Location
    Between keyboard and chair
    Posts
    608
    you wouldnt necessarily have to have multiple ports... you could do it like a web or ssh server and fork off a new process for each connection... or in the initial connection, the server could give the client a random port to connect on, and open that port up, kinda like TFTP. that way the initial connection would be the same port... but i guess youd need to open up extra firewall holes if you were doing that. but really this is an issue you have to deal with regardless of the protocol you use.

    how are you planning on implementing this? (ie, C, Java, perl, etc)
    C-x C-c

  8. #8
    Senior Member
    Join Date
    Mar 2002
    Location
    MI, U.S.
    Posts
    697
    Python, using xmlrpclib on the one machine running fadgui, and some kind of XMLRPCServer (either SimpleXMLRPCServer or Doc..., probably the Simple variant) on each node that runs FaD.

    Using ssh tunnels, I'd need one tunnel set up between the (single) machine running fadgui, and each of the (multiple) machines that run FaD. (They'd each also run a simple server, to handle the requests.) I need one connection from fadgui to the fadguid running on each FaD client, so I can control each of them.

    It's pulling information from each client, though, not having the client push it to fadgui. (So it's a completely different architecture from fadprogressd, for example.) This allows fadgui to control each client, too, instead of being totally "passive". The downside is, more packets flying around. (Poor packets! ) Between setting up the TCP session, and making it a request/response, there are 4 more packets than a single UDP status-update scheme would require. (3 to set up the session, and at least 2 to actually get the data. Plus more to do the SSL/TLS negotiation that I'm leaning toward.)

    Right, SSL/TLS. I've found one or two packages that will do what I need. Either M2Crypto or TLS Lite (perhaps with M2Crypto, if I want to use OpenSSL instead of TLS Lite's pure-Python implementation) will do SSL/TLS client and server authentication -- they both provide a TLS transport that I can use with Python's xmlrpclib (the client code). Both also make it easier to do a TLS-able XML-RPC server, though it's not like they provide a trivial implementation. (And TLS Lite is easier than M2Crypto, at least according to the documentation for each.)

    At that point, it's down to setting up a CA (which can be handled at least semi-automatically), and distributing the resulting certificates. Even though the certs contain public keys (so it doesn't matter if an attacker sees the data in transit), they must be signed by a CA key so that an attacker can't substitute an alternate public key. And this CA key must be trusted by each client, so it has to be distributed to each client somehow.

    Or, I suppose I could distribute one root CA certificate with fadguid, and keep the corresponding private key myself. That would require anyone who's setting up fadgui to generate a keypair and get the public key signed by me before it'll work -- but it also solves the "you need a "trusted" root CA cert" problem. Opinions? I'd like to leave myself out.
    "If you fail to adjust your notion of fairness to the reality of the Universe, you will probably not be happy."

    -- Originally posted by Paratima

  9. #9
    dismembered Scoofy12's Avatar
    Join Date
    Apr 2002
    Location
    Between keyboard and chair
    Posts
    608
    i think it would be easier to use self-signed certificates, generated on install. in this case you are vulnerable when the key first gets installed on the client, but after that you are ok. this is like SSH, in which the first time you exchange keys, there is no trusted third party, but after that you have a copy of the other host's public key and you can just not trust someone claiming to be a host you know but having a different key.
    C-x C-c

  10. #10
    Senior Member
    Join Date
    Mar 2002
    Location
    MI, U.S.
    Posts
    697
    Then when the self-signed certificate expires, there'd have to be some way to "remove" the certificate public key, so that when you move a new private key to each fadguid machine, fadgui will accept the new public key.

    Maybe just display the certificate's fingerprint, both when it's generated (during install) and when it's received (by fadgui) if it's different from whatever was received last time. (The first time, it will always be displayed.) If the fingerprint that's displayed matches the one that was shown when the key was generated, then you can tell fadgui that this is the correct machine, and it'll keep that fingerprint associated with that machine.

    I may not even need two different servers -- I might be able to handle the "display the fingerprint, and either accept or reject the corresponding key" code inside the client, while it's connecting to the server.

    That is a good way of thinking about it -- it's really close to what happens when you want to ssh to multiple machines using pubkey authentication. Each machine has a "fingerprint", which you must accept before ssh will do anything. (This fingerprint is generated from the host's public key. The client verifies that the host has access to the corresponding private key before it even displays the prompt.) You also have a public key that each target machine must know about beforehand, before it'll let you in as that user. "You" in this case is fadgui; each target machine is fadguid.

    So now, the only problem is authenticating fadgui to all the fadguid instances that are running (so that some ingenious cow can't come along and send a "stop" command to someone's entire network ). There'd have to be some way to distribute the fadgui public key out-of-band... maybe scp would be sufficient for that, along with a way to import the key. (In this case, the fadgui key would also be self-signed.)

    This does get rid of the overhead of the one CA certificate, and all the signing that would normally be needed. At the expense of perhaps losing some security... it may be worth it though. Maybe I'll be able to make it an option for the paranoid, to use a full CA setup.
    "If you fail to adjust your notion of fairness to the reality of the Universe, you will probably not be happy."

    -- Originally posted by Paratima

  11. #11
    dismembered Scoofy12's Avatar
    Join Date
    Apr 2002
    Location
    Between keyboard and chair
    Posts
    608
    yeah, if its too complicated, nobody will want/be able to use it
    C-x C-c

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •