2

I'm trying to add new devices into a secure system. A secure system where a webserver is identified by custom CA and all clients individually are too. That is, every client connecting to the server has its own certificate. If am to add a new mobile device into the secure system, these would be the steps.

  1. The app is installed by the user from the app store
  2. Once app opens, the user sees a 16 length string (user doesn't have to login to see that). Prior to displaying it to the user, the string is sent to the webserver through websocket, hashed. The server stores this hashed string with ttl of 3 minutes.
  3. The user logs into the webserver with his credentials (has permissions to add new device) and enters the 16 length string there. The webserver hashes it and compares the hash to the saved one.
  4. The webserver replies back to the mobile app on the same websocket with a new certificate. The response is symmetric encrypted with the 16 length string.
  5. This certificate is used for future interactions with the webserver, thereby needing no human intervention.

Is this not secure enough? What would be a more standard way of doing this?

6
  • 1
    "encrypted with the 16 length string" - Since this string has to be typed by a human, it's almost certainly not a good key. You want 16 random bytes, so that'll be either 32 hex characters or 23-25 base64 characters (depending on if you pad). Alternatively, use enough random characters from any character set (ie, only upper case + digits) and run it through a KDF. It'd probably be a better idea to separate the key from the authentication string. Isn't this over TLS anyway? Sep 7, 2018 at 12:00
  • @AndrolGenhald Yes. I see that it's a bad idea to use the user typed string itself as the key. Must use a KDF. "Isn't this over TLS anyway?" - the mobile device to the webserver is not an authenticated line. I mean, the 16 length's hash can be seen by anyone in the middle. The reply too can be seen by anyone, just that it can only be decoded with a key based on the initially entered 16 length string (after it's run through KDF).
    – Srikanth
    Sep 7, 2018 at 12:30
  • 1
    @AndrolGenhald What's your threat model that justifies 128 bits of security? Are you really expecting an attacker to do 127 bits of hash guessing in 3 minutes, after breaking the login credentials of an authorized user? I highly doubt than the data in this system is worth the electricity cost of that brute force... Sep 7, 2018 at 12:38
  • 1
    @MikeOunsworth Yeah, fair, I realized that after commenting :P. On the other hand, it sounds like he's sending the certificate's private key encrypted with that key, so if it's eavesdropped it's not just 3 minutes that matters, it's the entire lifetime of the certificate. Which actually brings up another thing, it'd be better to generate the CSR on the device and send that to the server to sign, rather than doing it all on the server. Is there any particular reason you're not just using TLS? Sep 7, 2018 at 12:43
  • 1
    @AndrolGenhald lol we think very similarly. Good point about CSRs Sep 7, 2018 at 13:00

1 Answer 1

1

You haven't given us a threat model, so I'll assume a standard corporate environment, and the value of the data being protected by this scheme is less that $1 million USD.

That scheme actually sounds fine to me. Bootstrapping device enrollment is always hard because you need some sort of device secret known to both the device and the server.

You say "app store" so I assume this is an Android / iOS device rather than an IoT device. Shame, cause with an IoT device you might be able to get it manufactured with a secret known to your database, or a default cert. Instead you're generating a secret and the length (16 string characters) is a balance of security and usability.

Some thoughts:

  • I hope your websocket to upload the hash is using TLS to make the hash harder to sniff (because, why not?)
  • Since an attacker would need to brute-force the hash and steal a username/password for an authorized account, you can get away with the secret not having a full 128 bits of entropy.
  • What's the largest character set you can use for the secret without causing usability issues? Probably UPPERS and numbers? Possibly UPPERS, lowers, and numbers? You'll have to exclude characters that look similar, 1/I/l, O/0, etc.
  • When you say "The response is symmetric encrypted with the 16 length string" how are you doing this? Are you running the 16 byte string through a key derivation function to make it into a full-sized AES-128/256 key? Is the websocket using TLS and the secret is using manual encryption inside it? Have you considered opening a new websocket at this point using TLS_PSK (pre-shared key) or PAKE (password authorized key exchange) modes?
  • When you say "The webserver replies back to the mobile app on the same websocket with a new certificate." Just the certificate, or also the private key? The correct way to do this would be to generate the private key on the device (ideally in the Android / iOS secure keystore if possible) and send the server a CSR in step 2, that way no private keys are ever sent over the network, period.
1
  • 1
    "Have you considered opening a new websocket at this point using TLS_PSK (pre-shared key) or PAKE (password authorized key exchange) modes?" - this would be the most secure way of handling it. That is, a 16 byte string to be keyed in by the user. That 16 byte string fed to a KDF to open a TLS_PSK websocket to the webserver. I didn't know about TLS_PSK... Point 4: That would be perfect. That is, sending CSR only and not having to exchange private keys over the network. Thanks a lot for being so thorough.
    – Srikanth
    Sep 7, 2018 at 13:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .