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?

mentallurg
  • 10,256
  • 5
  • 28
  • 44
Michael
  • 1,467
  • 1
  • 18
  • 36
  • 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 '20 at 05:37
  • We do not use CA for the internal communication yet and therefore we need to exchange keys without CA – Michael May 25 '20 at 05:47
  • 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 '20 at 06: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. – garethTheRed May 25 '20 at 07:27
  • Could anyone suggest a solution without CA? Is my solution good? – Michael May 25 '20 at 14:08
  • 1
    The comments about manual copying do not involve a CA. If you do not have access to your servers, please explain that with detail. (But you do, because you say you can manually copy tokens. Just manually copy the public key instead.) – Matthew Read May 25 '20 at 20:16
  • 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 '20 at 22:32
  • 3
    Is this not what `ssh-copy-id` is for? – Bernhard Döbler May 26 '20 at 13:51
  • 1
    You're asking in a very roundabout way how to reinvent running a CA from scratch, but worse. Set up an internal CA, or have your certificates signed by one you trust. – Sammitch May 26 '20 at 17:35
  • 1
    What do you mean by *"Ase the token"*? *"And the token"*? Or something else? (Please respond by [editing your question](https://security.stackexchange.com/posts/232158/edit) (***without*** "Edit:", "Update:", or similar), not here in comments)). – Peter Mortensen May 27 '20 at 12:30

8 Answers8

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.

mentallurg
  • 10,256
  • 5
  • 28
  • 44
  • Thanks, could you please suggest a solution without CA? – Michael May 25 '20 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. – Radvylf Programs May 25 '20 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 '20 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 '20 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. – Steve Jessop May 26 '20 at 00:31
  • Without a trust root of some sort which can be externally verified, "just copy the files" achieves nothing. Because now what you have is "How do I copy my certificates with someone who didn't just do all that and replace yours with theirs?" Understanding that I have 333 characters left to type ... – Julie in Austin May 29 '20 at 15:38
  • @JulieinAustin: You are not correct about "externally verified". May be you don't know how applications trust certificates. The most of the known applications have a so called **trust store**. Means, **any** certificates contained in such store are considered as **trusted**. This is used in particular to implement cases when external validation is not possible or not desired by design. Thus, since the OP cannot use external CA, I suggested to use namely this approach - use **trust store**. And since the root cert. will be trusted, then also the other certs it signed will be trusted. – mentallurg May 29 '20 at 15:50
  • @mentallurg - How do you know you stored the correct self-signed root certificate? – Julie in Austin May 29 '20 at 18:04
  • @JulieinAustin: I don't understand your question, really :) You know that because **you** did that. Or do you suggest not to trust to yourself? :) A certificate of **every** top-level CA is a *self-signed* certificate. Certificate for *security.stackexchange.com* is issued by company *Let's Encrypt*. The certificate of *Let's Encrypt* itself is issued by company *Digital Signature Trust Co.* (which is a top-level CA). And certificate to *Digital Signature Trust Co.* is issued by *Digital Signature Trust Co.* **itself**. Means, *Digital Signature Trust Co.* uses a **self-signed** certificate... – mentallurg May 30 '20 at 00:01
  • @JulieinAustin: ... Here is step by step explanation. 1) You create a self-signed certificate. Important: you set field *basicConstraints = CA:TRUE*. 2) You add this certificate to the trust stores of the both server application. For instance by using a *keytool* in console or by *KeyStore Explorer* in GUI, whatever you like. et voilà, certificate is in the trust store, and both server applications trust it from now on. – mentallurg May 30 '20 at 00:20
  • @JulieinAustin: To "How do you know you stored **the correct** self-signed root certificate?" What you mean by *correct*? You have created a self-signed certificate by your own hands. If you set extension *Basic Constraints* to *Certificate Authority: Yes*, extension *Key Usages* to *Purposes: Certificate Signing, CRL Signing*, and set validity period so that it includes current date and some future like 5 years more, then such certificate **is correct** and can can be used for issuing of other certificates. – mentallurg May 30 '20 at 00:43
  • Then why can't I just take the other certificates, which I also created with my own hands, and do likewise? Anything you can do "with your own hands" can also be done by an imposter, with there own hands. It's the reason that 3rd parties exist, having well-known signatures, so the entire chain can be validated. Hand-waving isn't security, it's just moving air around. – Julie in Austin Jun 01 '20 at 23:33
  • One of the major failings in the conceptualization of "trust" over the past 10-20 years is that it is seen as this thing which solves problems, rather than creates them. "Trust" is a statement of dependency on the verifiably-correct function of the thing in question. We don't trust "Trusted Systems", which I've developed, because we put "trust" in front of "system". We state that those things we "trust" =must= be verified and be verifiable. So, how do you know you have the correct "trusted" certificate? – Julie in Austin Jun 01 '20 at 23:36
  • @JulieinAustin: This is how PKI works. We don't consider certificates as valid just because they are signed by **some** 3rd party CA. We consider certificates valid if they are signed by a CA whose certificate **is contained in our trust store**. Installation of OS installs also a trust store. Some applications use the OS trust store (normally web servers do that), other applications (some browsers, all JREs) use their own trust store that they bring with their installation... – mentallurg Jun 02 '20 at 02:48
  • @JulieinAustin: ... Making sure that unauthorized persons don't have access to your OS is one of the primary security goals, not because of the OP, but always. In particular, compromising trust store would mean possibility of man-in-the-middle attacks. In *this* thread it makes no sense to discuss what would be if smb. has got access to the server, has got root permissions and modified the trust store. – mentallurg Jun 02 '20 at 02:54
  • @mentallurg - You realize that most security violations result from either insiders or configuration errors? In trusted systems, we analyze =trust= in a way which seems utterly unfamiliar to you. You've yet to argue how your solution is any better than just copying things as originally proposed. – Julie in Austin Jun 02 '20 at 15:20
  • @JulieinAustin: Let's continue in the chat: https://chat.stackexchange.com/rooms/108792/room-for-mentallurg-and-julie-in-austin. – mentallurg Jun 02 '20 at 16:29
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).

mentallurg
  • 10,256
  • 5
  • 28
  • 44
tim
  • 29,122
  • 7
  • 96
  • 120
  • 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? – Woodrow Barlow May 26 '20 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 '20 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! – Woodrow Barlow May 26 '20 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.

  • *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 '20 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. – Hubert Jasieniecki May 25 '20 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. – Matthew Read May 25 '20 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 '20 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. – Hubert Jasieniecki May 28 '20 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.

ThoriumBR
  • 51,983
  • 13
  • 131
  • 149
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.

  • 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 '20 at 15:57
  • Thanks, @tim, I have updated my answer. – Sergei Krivonos May 26 '20 at 01: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.

fraxinus
  • 3,458
  • 6
  • 20
  • 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.) – Peter Cordes May 27 '20 at 08: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. – Peter Cordes May 27 '20 at 08: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 '20 at 09: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.) – Peter Cordes May 27 '20 at 09: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.

TheHans255
  • 1,268
  • 2
  • 6
  • 13