Using PGP with an unknown entity - security

I'm currently researching on PGP and authentication schemes.
Let's say i'm communicating with someone who claims to be an admin of a ftp site. (say, his email address is admin#genuine-website.com)
Assume both of us have one another's PGP public keys.
Say first, we exchange fingerprints and verify them (by directly transmitting them and not using out of band authentication like phone/sms). In the second step, we exchange a signed message and then verify the signature.
Are these two steps good enough to establish authenticity?
By means of this fictitious example, the basic question i'm trying to ask is whether these steps are "enough" or should i opt for another mutual authentication scheme on top of this?

That's enough, however the most tricky is to verify fingerprints.
For PGP this is done via cross-signing keys with other keys. While in X.509 it is hierarchical structure (top CAs and signed by them certificates), in PGP it is done as 'web of trust'.

No, that's not good enough. A man-in-the-middle can substitute his public keys for yours and your partner's, and then do the same thing with the fingerprints so that everything appears to check out okay.
You'll need to use PGP's web of trust, or exchange fingerprints in another medium that you trust, to verify the public key you received is authentic.

Related

JWT RS256: Is it safe to fetch public key over https?

I'm signing JWT's using the RS256 algorithm. To verify those tokens on the client, I somehow need to access the public key.
Are there security concerns (spoofing, ...) when I set up an unprotected API route ('/api/certificate') that returns the certificate containing the public key. And do I need to take any extra security measurements?
Several concepts are often mixed up, maybe not for you, but let me try to explain a few things in this answer.
Assymetric cryptography obviously needs a public and a private key, both are basically just numbers. The private key is kept secret, the public is, well, public, anybody can have it. When signing stuff, you use the private key to sign and then anybody can verify using the public key that the signature was made by somebody that had the corresponding private key (ie. you).
But the question is then how you distribute your public key, or in your jwt example, how clients get it. As you correctly pointed out in the question, simply downloading the public key over an insecure channel is not good enough as an attacker could replace it with his own, resulting in the attacker being able to sign tokens.
One solution to this could be getting it over https as you proposed, which practically means using a second set of public-private keypair (keys of the webserver) to secure sending the first one. The theoretical question is still the same btw, it's just inherently solved in the background for you: how does the browser know that the public key it receives from the server upon connection actually belongs to the server. There is no secure channel yet between them.
Enter certificates.
A certificate is a document that essentially ties a public key to its owner, and that is excactly what you want. When a browser connects to a website, the server sends its public key along with its certificate, so that the browser can verify that the public key actually belongs to the server (the domain name in this case) that sent it. How that verifies it is beyond the scope of this post, the point is that the certificate is signed by another public key, the certificate to which may be signed by another public key, etc., and the chain is terminated by a list of so called trusted root certificates already set up for your computer and/or browser by your OS/browser vendor.
And you too should verify the public key with the certificate the same way. You don't even need the burden of SSL (https) transport for this, verifying that a public key belongs to a particular subject is the main purpose of certificates.
So all you have to do is not just get the public key from the API, but get it along with its certificate. You are probably already doing this, bare public keys are very rarely used. You are most probably already receiving a pfx or cer or crt or whatever from the server. Depending on the technology stack that you are developing on, you can for sure use built in mechanisms to fully verify a certificate and make sure it's valid. Please don't implement your own validation though, as that's tricky business and quite hard to get right. If the certificate passes validation, you can trust that the public key you received from the API is authentic and belongs to whatever it claims to belong to. There may be caveats though (like for example make sure that beyond basic validation, you check a combination of fields from the certificate that others can't have).
As an additional security measure, you can also implement certificate pinning to make it even more secure against certain types of attacks by having a list of fingerprints for valid certificates in the client (less so in a browser client, but still the concept is the same).
Edit (what fields to check in the certificate after it passed general validation of expiry, etc):
In the general case it depends on who signed the certificate and what kind of certificate it is.
A server certificate signed by a real certificate authority (CA) can only have the server domain as its common name (CN) field, a real CA won't normally sign anything else, and they also won't sign a certificate for yourdomain.com unless you can prove you control yourdomain.com. So in this case it may be enough to check CN after the cert passed validation. You do need to check CN though, as anybody can have a valid certificate from say GlobalSign or Thawte or other trusted CAs, it just costs money. What they can't have is a certificate for yourdomain.com.
If you sign your own certificates, you also won't sign anything for anyone, so in that case it could be enough to check the issuer (that you signed it) and the CN (for whom). If the certificate otherwise passed validation (meaning a trusted root certificate signed it) it should be ok, as an attacker won't normally be able to have his CA certificate as trusted on your computer.
The point in general is that you want to check something that others can't have. It's easier, if you are relying on real CAs, and it's usually best to check the fingerprint.

How to securely transfer from an old private key, to a new one?

I can sign the new (public) key with the old (private) key to securely transfer from one to the other. But far as I can tell, there's nothing stopping anyone who gets the old key from signing a different new key as official, even much later after I've given the old one up.
If I revoke the old private key, nobody can make that bogus signature, which is good. But doesn't revoking a key mean its signature of the new one would be invalidated? (As well as every single signature it's made?)
So someone who knows me as "Alice" would be able to tell I'm the same, even if I'm "Bob." But then they see "Alice"'s revocation, in which case they have to throw all of their knowledge about me away, whether Alice or Bob?
The usual way to deal with this is to use a different key for signing keys and for signing “useful” data.
The data signing key lives on an online server where it's invoked automatically, and thus is at risk of misuse. This key is rotated regularly. In principle, it wouldn't need to be rotated: just revoke it if something bad happens. But in practice revocation is hard: it's often difficult to ensure that every party that relies on the signatures will see the revocation message in a timely way. Expiration ensures that even if a party doesn't see the revocation message, it won't keep accepting compromised signatures for long.
The key signing key lives on an offline server with stringent access control, and since it's a lot better protected, it has a very low risk of being compromised.
A system with keys that sign other keys is called a public key infrastructure. Many systems have multiple levels of signing keys. The best known PKI ecosystem is the one used for HTTPS, with servers having a certificate signed by an intermediate certificate authority, which in turn has a certificate signed by another CA until you reach a root CA. Intermediate CAs are online, but run specialized systems which do nothing but sign certificates. The keys to root CA certificates are split among multiple employees who all get together into a vault with no Internet connection once every few years to generate a new intermediate key.
Running your own CA with OpenSSL is not trivial, but it's doable, and you'll find many tutorials on the web.

How the public key can be ensured being from sender in the digital signature security model?

I read an article about digital signature (link) and have question as follows.
Let's say Alice wants to send a message to Bob. She need to let Bob know the message is from her. So she encrypted the hashed message with her private key into a certificate. Then Bob can decrypted the message with public key when receiving it. Bob can know it is from Alice if the hash code of the message matches the hash code which is decrypted from certificate. Here we have the assumption that Bob already knows the public key. What if the transmission of public key is already attacked? Bob might use the wrong public key to decrypt the wrong message and get that the message if from Alice. Is there any protocal or policy to avoid the attack against public key? And shall we?
Yes, the authenticity of public keys is a key component of applied cryptography. I can issue a public key that says "I am the website of your bank, trust me", but you shouldn't really trust it. Different schemes have been developed to establish authentication of public keys. One approach is the web of trust model in PGP and GnuPG, others are PKI and Kerberos. One of the main difference between these approaches is where you place your trust. I provide a simplified description only, you have to read about them to learn about the exact details (you wouldn't base your security on an extremely short summary, would you?).
In the web of trust there are some people who you trust, and you (ideally) verified their public keys personally. You can trust other public keys if they have been signed by several people bearing your initial trust. Using these trusted individuals you can check more and more keys.
In PKI (Personal Key Infrastructure) you trust several Certificate Authorities (CAs) and accept their public keys. You trust them that they thoroughly check the identity of key holders before signing their public keys. The combination of public key + signature from a CA (and some other data) forms a certificate. The PKI is used in SSL/TLS, it is the underlying infrastructure of the secure web. You use it when you read your mail on a web interface, when you do online banking, etc. If a CA is compromised, then every certificate signed by the CA will be come insecure.
In Kerberos is designed for computer networks and the key server is the single point of trust. It provides mutual authentication and a unique symmetric encryption key for clients and servers. The key server checks the identity of clients by a secret shared only between the key server and the client. Kereberos is used, for example, in Windows, AFS, Grid computing.
your answer gave me much of insight into the question. And also, I would like to put the wikipedia link http://en.wikipedia.org/wiki/X.509#Security here. Coz there is one stentence in the article solve my question "who certificate the Certificate Authority"
This is an example of a self-signed certificate, as the issuer and subject are the same. There's no way to verify this certificate except by checking it against itself; instead, these top-level certificates are manually stored by web browsers. Thawte is one of the root certificate authorities recognized by both Microsoft and Netscape. This certificate comes with the web browser and is trusted by default.
Just in case some one has the same question.

What makes SSL secure?

I've been reading a few sites on the internet on how SSL works, but I don't understand how exactly it makes things secure. Probably because I don't understand completely how it works.
Let me begin with the core idea of SSL. It is used to encrypt HTTP connections, but for the client and the server to communicate with encrypted data, surely an encryption key needs to be shared. If someone is eavesdropping on your connection, wouldn't they just be able to grab this key and continue listening while decrypting the data? I can image this technique would work if we're talking about a long term connection, but HTTP requests are often completed within half a second.
Let's assume this is somehow taken care of. The other utilisation of SSL is to verify if a server is exactly who it says it is. What prevents a rogue server from faking a certificate signed by a root certificate provider? In none of the descriptions I've read, the browser actually contacted one of these authorities to verify the certificate with them. Let's assume the certificate is encrypted with a private key by the root certificate authority, how is the browser able to verify the data in this certificate without knowing the decryption key? Or is the decryption key different from the encryption key?
One solution to these problems I can imagine is if the certificate and key are only sent once and are stored along with the domain and IP address in your browser.
Thanks for explaining in advance.
First, some basic concepts about public key cryptography:
This relies on a pair of keys. One is the public key (which can be distributed); the other one is the private key, intended to be kept private.
You can encrypt data using the public key, which the private key can decrypt/decipher.
You can sign data using the private key, and this signature can be verified using the public key.
To make sure you're communicating with the right entity, you need to bind an identity to a key-pair. This is where certificates come in. A public key certificate is a signed document containing both the subject's identity (name) and the subject's public key.
For example, the certificate for www.google.com contains its public key and the name www.google.com. It has been signed using the private key of a Certification Authority (in this case, Thawte). In the X.509 terminology (the common standard for certificates used for HTTPS), the CA is the issuer of the certificate, and it puts its name in the certificate too, alongside the subject's name, the subject's public key (and other attributes). The issuers are meant to verify the identity of who they issue a certificate for.
The reason you don't necessarily see your browser fetching information from the CAs is that a number of commercial (or governmental) CA certificates are bundled with your browser or your OS. You trust them by default. This can be considered as a "leap of faith", but any trust mechanism needs this sort of starting point.
You may want to read more about the TLS handshake, but in short:
The client gets the server's public key by looking into its certificate.
The client encrypts a secret using this public key and sends it to the server. The details of this depend on the cipher suite (could be Diffie-Hellman based), but the result of this should be a list of shared encryption keys (using symmetric cryptography, not public key cryptography).
These shared keys are only known to the client and the server, and they're used for encryption/decryption.
For SSL/TLS to be secure, you need at least 3 points:
A suitable cipher suite, and a successful handshake.
Verifying that the client trust the server certificate (typically, via a known CA in the PKI model).
Verifying that the certificate belongs to the server the client intended to contact (hostname verification).
(This is the case for the vast majority of usages of SSL/TLS (in particular HTTPS), but it's also possible to use other mechanisms than X.509 certificates with TLS, for example OpenPGP certificate or Kerberos cipher suites. This is less common as far as I know.)
In order to encrypt a connection you have to agree to some shared secret. This can be done with diffie-hellman. To prevent man in the middle attacks, so you also need a certificate mechanism.
For encrypting or signing (certificates) you can use asynchronous keys. This means you have two different keys (public and private key) to encrypt/decrypt. Usually you encrypt your data with a public key, and someone can decrypt it with his private key. Signing is done with your private key, and someone else can check it with a public key.
So you see, faking a certificate is not that easy, since you don't have the private key from a root certificate provider.
surely an encryption key needs to be shared. If someone is eavesdropping on your connection, wouldn't they just be able to grab this key
No. The key is never transmitted. It is computed at both ends independently via a key-agreement algorithm.
What prevents a rogue server from faking a certificate signed by a root certificate provider?
The certificate is sent along with its digital signature which is made with the private key, and verified by the peer via the certificate's own public key. The server would need the private key of the server it is spoofing.
When using protocols such as Diffie-Hellman key exchange, the two parties to a communication each generate a random number, transform it in some way, and send the transformed version to the other party. The transformation is such that combining the first number with the transformed version of the second will yield the same result as combining the second number with the transformed version of the first. An adversary who only had the transformed numbers, however, would have no way of finding the un-transformed version of either, nor a way of computing what the result would be if the (unavailable) untransformed version of one number were combined with the (available) transformed version of the other.
Diffie-Hellman key exchange by itself would be sufficient to protect against all forms of passive attack or historical attacks (meaning if an attacker hadn't taken steps to intercept a communication before it took place, it cannot later be compromised except by performing some calculations which could not, with anything resembling today's technology, be computed in any remotely feasible time). The problem with it is that it cannot very well protect against the situation where an attacker (e.g. Z) can intercept all communications between the participants (e.g. X and Y) and substitute his own. In that scenario, X would establish a connection with Z--thinking him to by Y--which nobody but he and Z could decode. Z would then--pretending to be X--establish a connection with Y.
If X and Y have any pre-existing means of sharing information with each other in such a way that they can decode it much faster than Z, even if it's not terribly secure, this may suffice to prevent the above-described man-in-the-middle attack. All that needs to happen is for X and Y to ask each other something about the key they're using. If Z can recognize that question and substitute its own answer, it would be able to continue the ruse. On the other hand, if the question were asked in such a way that a legitimate party would be able to respond much more quickly than an imposter, Z might be stumped. As an example, if a voice-phone application displayed for each participant information about the negotiated key, and one party asked the other "read off digits 12 to 18 of your key, doing your best impression of Elmer Fudd" (selecting, on the spot, the digits to read and the voice to use) a legitimate participant would be able to respond immediately, but an attacker would need time to produce a phony recording of the person speaking as indicated).

Protecting ECDH against MITM attacks

I am working on a project that requires an ECDH key exchange. I am trying to understand how to protect against MITM attacks. I can sign the public key and send a signature along with the public key transfer to ensure that the key has not been tampered with but that doesn't stop a MITM attack from just doing the same thing. I understand that the key exchange must be verified somehow by a third party but I'm having a hard time understanding how it is that a third party can be the solution assuming that someone can do an MITM attack. Why couldn't they just do an MITM on the third party verification too? Is there really a fail proof way of completely eliminating all possible MITM attacks without some kind of pre-known by both parties?
You need a¹ trusted third party to sign both keys.
Without any knowledge or assertions about the identity of the intended partner, there's simply no way to distinguish him² from anyone else.
¹ one or multiple
² Bob
In a PKI system, "certifying authorities" are an important part of the infrastructure. Certifying authorities sign the public key and the identifying information, so that you know the corresponding private really belongs to the purported identity. This is true for EC keys just as it is for RSA.
By the way, I've looked for CAs that issue EC certificates, and apparently they aren't in practical use.
Most people obtain certificates for their certifying authorities as part of their operating system or security application. They trust these certificates implicitly. There are several dangers here, though.
First, most users don't have an effective way to verify the integrity of these certificates. This is a pretty hard problem, because, at the root of it, you have to have a 100% trustworthy channel for the verification—channel between the authority and the user with which an attacker cannot tamper. When a user downloads a new browser with an collection of root certificates, he can't know that the software wasn't tampered with in transit, or even built with a bogus CA certificate in the collection.
Even if the certificate collection is received intact as the provider intended, there have been questions raised about the integrity of many certifying authorities included by default in popular software. For example, some have pointed out that telecommunications companies in states that have been linked to terror sponsorship have their certificates included in popular browsers. Any trusted authority can issue a certificate for any domain name, and a browser will accept it without question.
In short, no, there is no way to establish a secure channel without first sharing some information on a secure channel. The benefit of PKI and asymmetric cryptography is that one exchange on a secure channel (the receipt of a trusted authority's certificate) permits the establishment of secure channels with many parties. But you have to bootstrap the system somehow.
It sounds like you are heading down a path of rolling your own crypto protocol. Don't do that. It's a bad idea. It leads to insecure systems.
Instead, use SSL or TLS. That is designed to take care of the subtle issues in designing this kind of crypto protocol -- and it has been well-vetted. You'll need a way to verify the other endpoint's certificate. You could use a certification authority, or in some cases it might be feasible to hardcode the public key of the entity you expect to talk to.
You may get better answers if you ask on the Crypto stack exchange.

Resources