12

I have two servers with a pair of RSA public and private keys.

We do not use a CA for the internal communication yet and therefore we need to exchange keys without CA.

I need to establish a trust between two servers: I need to copy a public key form the first server to the second server and the public key from the second server to the first server.

Note that it is not Diffie–Hellman key exchange (that explained very well in "Diffie-Hellman Key Exchange" in plain English).

The simplest way is just manually copy the public keys from one server to another.

An additional option is to use the following homegrown flow:

  1. Generate a one-time token on the first server
  2. Copy the token manually to the second server
  3. The first server accesses the second server via an API. Ase the token for the API authentication. The API implementation exchanges public keys between servers

Any suggestions to improve the flow?

Do we have some best practices flow, since homegrown flows are usually bad for security?

10
  • 9
    This is usually what CAs are for: they are a trusted third party that can be used to verify both public keys (or certificates rather). If you don't have a CA, then any trusted third party (common storage, manual copying, etc...) will do.
    – Marc
    May 25, 2020 at 5:37
  • 31
    If you can manually copy stuff to the other machine, then why not just copy the public keys? Why do the token exchange?
    – Limit
    May 25, 2020 at 6:26
  • 24
    Copy the public keys over, then compare a hash of them at either end. If the hash is the same - job done. I think you're over-thinking this. May 25, 2020 at 7:27
  • 11
    TBH I think there's some missing information about the threat model. Michael, what exactly are you trying to protect against? Are you concerned about someone intercepting and manipulating files while you are copying them to each server? Or is this merely about an adversary interfering with the connection between the two servers? Or something else? And why do you keep chasing after a solution that doesn't involve a CA?
    – David Z
    May 25, 2020 at 22:32
  • 3
    Is this not what ssh-copy-id is for? May 26, 2020 at 13:51

8 Answers 8

28

This will mean a lot of unneeded overhead. I'd suggest following:

  • Since you don't have certificates issued by CA, create your own CA. Namely, create a self-signed certificate and add it to a key store on both servers, so that your certificate is trusted.
  • Issue certificates to each server and sign them with private key of your own CA.
  • Make your servers use their certificates when communicating with the others.

Thus you will actually use PKI.

In the future, when you get certificates from the real (commonly known) CAs, the only thing you will need to do will be to replace your own self-signed CA certificate by (also self-signed) certificate of a real CA.

17
  • Thanks, could you please suggest a solution without CA?
    – Michael
    May 25, 2020 at 12:57
  • 16
    @Michael This solution doesn't use a CA, just a self signed certificate. You might be able to get more useful answers if you say why you don't want a solution involving a CA, since in most cases this would be perfectly valid. May 25, 2020 at 14:50
  • 4
    @Michael you are asking how to provide authentification for certificates to your servers. That by definition would make you a "certificate authority", regardless of which scheme you use. This doesn't mean you need a full CA infrastructure - the cleanest solution would probably be using a self-signed root certificate like mentallurg describes.
    – ManfP
    May 25, 2020 at 16:23
  • @ManP: I suppose that by We do not use CA the OP means that they have not purchased certificates from any known CA. May be he supposes that any other CA (like self signed certificate with proper certificate attributes) is actually also CA, even if nobody else trusts it :)
    – mentallurg
    May 25, 2020 at 16:36
  • 2
    @Michael: it doesn't have to be an external CA, and it doesn't even have to be literally a self-signed certificate. If the reason you want to avoid a CA is that you are not currently using certificates at all, just some protocol (like ssh) which can operate with raw keys, then the step "sign the certificates with the private key of your own CA" could just as easily be "scp the public keys into .ssh/authorized_keys on the server". Maybe by some degenerate definition of CA, someone who does that is a CA, but it needn't involve any actual certificates or you learning to use PKI. May 26, 2020 at 0:31
13

No, I don't think that the solution is good. Let’s go through it:

  1. This is fine
  2. If we can manually copy, why not copy the public keys directly?
  3. Here's the real problem. As this is done on an insecure connection, you can't be sure that the first server actually talks to the second server.

You weren't specific on how the exchange works, but using the token as simple API authentication token will not prevent a MITM attack.

In the communication between the two servers, an attacker can:

  • intercept the token when the first server sends it, forward it to authenticate & send a fake public key to the second server
  • send a fake public key to the first server in place of the real one from the second server

Or visualized:

A  ------ token ----->  E  -- authenticate with token --> B
A  <-- fake pkeyB ----  E  <------ real pkeyB ----------- B
A  --- real pkeyA --->  E  ------- fake pkeyA ----------> B

You seem to want symmetric key crypto, maybe something like Kerberos. But for the use-case you describe, copying the keys manually seems easiest (or exchanging them insecurely and manually checking the received keys fingerprint).

3
  • it is not clear to me how this is a problem. the public key is, by definition, public. doesn't that mean that if the public key is sniffed, no harm done? and if the MITM intercepts the public key and passes along a fake one to server B, i'm not sure how that is harmful either. wouldn't that just result in server B being unable to communicate? how would any of this be leveraged maliciously? May 26, 2020 at 18:07
  • 7
    @WoodrowBarlow The key being sniffed is no problem (it's a public key after all). But by injecting fake keys, the attacker can now read any encrypted communication between A and B: when A sends a message to B, they will encrypt the message with "fake pkeyB"; the attacker decrypts it (with their fake privatekeyB) and forwards the message re-encrypted with the real pkeyB; ie A and B can communicate, but an attacker can read/manipulate the messages.
    – tim
    May 26, 2020 at 18:32
  • aha. the thought that the MITM might re-encrypt so that server B is none the wiser hadn't occurred to me. +1 on this answer. thank you! May 26, 2020 at 20:09
6

The only way to establish initial trust between two servers separated by an untrusted network has to involve a manual1 step. This can be achieved either by copying it manually or by manually comparing whether the keys are transmitted correctly before trusting them. The manual comparison is typically done using a key fingerprint. It can be done by comparing a secure hash (like SHA-256) of a copied file as well.

There are other ways, but they must involve transporting a piece of information between the two servers, there's no way around it. It can be proven mathematically. Copying the key via untrusted connection and comparing a fingerprint manually is the most straightforward way, in my opinion, and also fairly standard.

Note that for a network of servers you only need to transport one key per server added to the network, for a total of N - 1 such operations for a network of N servers. If you wish to add server X to a network of servers A, B and C trusting each other's keys you only need to establish initial trust between X and, for example, A. Trust between X and B and between X and C can then be established by means of key signing.


1 The word manual here was used for simplicity. What is essentially meant is that a piece of information must be sent from one party (server) to another through a trusted channel. This trusted channel might be the operator driving to the server with key fingerprint written down on a piece of paper as it might be a trusted cable connection. Furthermore for a connection to be trusted in the context of public key exchange it only needs to be resistant to man-in-the-middle attacks, or, in other words, it needs to preserve the integrity of the message. Potential eavesdropping of the connection doesn't harm this trust, as all such an attacker could learn are the public keys.

5
  • The only way to establish initial trust - no, this is not the only way. If you have certificate and it is signed by somebody trusted (even signed by you, but added to the trust store), then public keys can be perfectly trusted.
    – mentallurg
    May 25, 2020 at 16:32
  • 5
    @mentallurg if you have a certificate signed by a trusted third party (T) and A, B are the servers (parties) it means that the trust has been already established between A and T and likewise between B and T. When I said initial trust, I mean that no such thing has happened. I apologize if I used the wording that's unclear. May 25, 2020 at 16:37
  • 2
    This is perfectly clear. Trusting the CA's public key is not different than trusting another server's public key. At some point, something had to be imported to a local key store, which is the manual step you described. May 25, 2020 at 20:14
  • 1
    @HubertJasieniecki I don't think "manually" is accurate. You can establish trust automatically with a trusted communication channel, and you can't establish trust manually without one (e.g. the wire between your keyboard and computer).
    – Fax
    May 27, 2020 at 15:21
  • @Fax You're absolutely right, "manually" isn't the best choice of wording. What matters is exactly as you say, trusted communication channel, whether it's the person driving to the remote server with the key fingerprint written down on a piece of paper, a trusted cable or anything else. Thank you this observation. I will edit my answer to improve it. May 28, 2020 at 11:07
3

If you have access to any trusted HTTPS server, post the public key of every server on it, download on the servers.

If your HTTPS server is properly configured, no MitM can change the public keys, and the servers can download securely the public key of every other server. And if cost is an issue, Let's Encrypt lets you create a public facing SSL certificate for free.

2

Public keys are safe to share unencrypted. If you need extra level of security then you may want to consider generating new key pairs first to share thouse temporary key public parts to send your original public keys and destroy temporary keys and reinitiate your session with original public keys.

But if you still need to be safe from MIM-attack by substituting your temporary and original public keys during transfer then you should rely on some trusted root storage or use hardcoded public keys to initiate session. In both of these ways security of these keys outdated with time and need to be re-issued time-to-time.

2
  • 11
    Public keys are safe to share, but OPs problem is about "establishing a trust between 2 servers". So it's not about the danger of the keys being leaked, but about ensuring that the correct keys arrive.
    – tim
    May 25, 2020 at 15:57
  • Thanks, @tim, I have updated my answer. May 26, 2020 at 1:10
2

One alternative for key distribution is DNS: keys, or rather key fingerprints, published in DNS records, protected by DNSSEC. Two standard examples of this are SSHFP (for SSH host keys) and DANE (for arbitrary services using TLS) but you can equally roll your own in TXT records or similar if that makes more sense for what you need the keys for.

Ultimately this isn't bypassing the need to have a preexisting signing authority you trust (in this case, the DNS root and DNSSEC chain from it to your domain), but it does bypass the web PKI/CA ecosystem, if that's what you want.

1

The task is no different to securely copying a file between two servers.

Assuming you have an access to both servers, you trust both servers and you trust the channel you use to access both servers (else, the whole thing is pointless).

You just copy the file using whatever means you use to connect to the servers.

Both servers are connected somehow (else, you don't need to establish trust between them). You can as well transfer the file by the possibly untrusted, but faster connection between them. In this case, you have to check the result of the transfer by calculating and comparing the hashes of the original file and the copy, using the secure connection between you and the servers. If the files are short enough, you can as well compare the files themselves and not the hashes.

4
  • If "compare the files themselves instead of hashes" is an option, it means your desktop has to receive the whole file contents from each server. In that case your untrusted server->server copy is only saving you 1 upload of the whole file. (To do the compare on the server, you have to securely transfer a copy of the file so you can compare it against the insecurely-transferred copy... in which case why do the possibly-MITMed copy at all.) May 27, 2020 at 8:46
  • For SSH public keys, yes this is clearly the most sensible thing; use your already-presumed-secure access to both servers to copy the file to your computer, then up to the other server. Even if you only have dial-up access, it's still faster and easier than comparing hashes. A line or two for ssh/authorized_keys is only a few hundred bytes. May 27, 2020 at 8:48
  • @PeterCordes in the general case it can be pretty useless to use the insecure transfer when you have a secure 2-step one. I can imagine it to make sense only in an exotic case of a big file, asymmetric bandwidth and no access to proper hashing tools.
    – fraxinus
    May 27, 2020 at 9:06
  • Yeah exactly. The point I intended to make was that the last sentence about the files being short enough is not really a useful suggestion, and may just confuse the issue. (Another thing I didn't mention earlier: your middle paragraph "just copy the file" could be better more explicit about copy to / from your local computer, in case that's not obvious to everyone.) May 27, 2020 at 9:16
0

Your proposed homegrown flow still requires a CA. In order to securely call the proposed API and not be subject to a MiTM or impersonation attack, you need to identify to the caller that the callee can be trusted - which requires a CA.

If you already have a secure way to contact both servers, use that to send them the keys - even if that way is to drive over to where the servers are located and load the keys from a USB stick. If that secure way is to SSH into them (and you don't get any certificate warnings, which means this actually isn't a secure method), then you already have access to a CA that you can utilize for internal communication.

You must log in to answer this question.

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