2

I have a naive question about certificates. I know the hash of the public key is signed with the CA's private key. I have an alternative design. Because the public key is being transmitted anyway, so why don't we sign the public key directly and send it? So the browser can decipher it to get the public key? What consideration prevents us from using this design?

auspicious99
  • 493
  • 3
  • 17
user231806
  • 21
  • 1

4 Answers4

3

For any message that is signed with a digital signature, it is standard to take a hash of the message first, then apply the digital signature algorithm to the hash.

Without applying the hash function first, the message would have to be split into blocks small enough for the digital signature algorithm to act on each block separately. This would complicate not only the signing process, but the verification process as well.

mti2935
  • 19,868
  • 2
  • 45
  • 64
  • And the signed 'body' of an X.509-type certificate (the ones used for SSL/TLS, S/MIME, PDF, Microsoft, Apple, Java, and most applications most people know about other than PGP) contains much more than just the publickey. – dave_thompson_085 Apr 10 '20 at 01:49
  • Whether the digital signature algorithm is applied to the whole public key or just a hash of it, it doesn't mean the public key can be recovered from the digital signature alone, as the OP was asking about ("So the browser can decipher it to get the public key"). So it is not just about the needless complexity. – auspicious99 Apr 10 '20 at 03:45
0

So, after doing my last answer, I think I realized that I answered the wrong question. (But that one's still pretty neat if I do say so myself, so I'll leave it.) Now I'll answer a different question:

If signing and encryption are just the same thing but backwards, why bother hashing the certificate and signing the hash? Why not just sign (i.e., encrypt with the CA's private key) the whole certificate, and transmit that -- which the client could decrypt with the CA's public key? Wouldn't that take less bandwidth?

There are three reasons why we don't do this:

RSA encryption (or signing) can indeed be done on payloads of arbitrary length, but it's slooooowwww.

Like really, really slow. That's why nobody actually encrypts messages with RSA -- they generate a (relatively short, like 16 bytes) message key and encrypt that instead. Then you can use the message key to encrypt your message using a much faster symmetric cipher.

Signatures aren't, in general, just encryption but backwards.

RSA is a special case where encryption with a private key gives you a signature scheme, but not only can you usually not swap private and public keys like that, encryption schemes usually can't be used as signature schemes and vice versa.

Take ECC for example: An ECC private key is just an integer, but an ECC public key is a curve point -- generally represented as a pair of integers (X, Y). ECDH, the key-agreement scheme used to power ECC encryption, is as simple as multiplying a private key and public key together -- if you tried to swap one of those for the other type, you'd get a public key times a public key -- which is just a number times a number, and can be broken with division -- or a curve point times a curve point, which isn't a thing you can do with curve points. (You can add them, which means you can multiply by a whole number -- but you can't multiply them by each other.)

Reading a certificate would be too expensive.

The body of the certificate needs to be accessible without doing anything expensive, like using RSA to decrypt it. That's a really expensive operation, and it would have to be done before you could even tell if the certificate even claimed to be for the right thing.

Also, there are ususally multiple trusted CAs, and most certificates aren't issued directly but through a Sub-CA -- which usually aren't stored on the end-user's computer, but are sent down along with the certificate you're actually interested in verifying. Which means that you'd have to read the certificate to figure out which CA or Sub-CA it says it's from before you know which key to use to decrypt it.

There wouldn't be any integrity protection.

This one's a bit more subtle. Let's say I handed you some random-looking data and told you it was a certificate for google.com. If you decrypted it, you'd get something-or-other -- probably random looking gibberish, but maybe not. Somehow, you've got to check to see if that decrypted data is actually a certificate for google or not, and just checking to see if the name "google.com" was in there would be a really bad idea -- because the name is short, it wouldn't be too hard to find a random blob that decrypted to something with that string at a certain position.

To provide integrity protection you need some known data to check for -- maybe a magic header field or something -- but that data would have to be at least as long as a hash would be to be effective. That would mean you'd have to increase the size of your certificate by at least that much.

Reid Rankin
  • 1,062
  • 5
  • 10
0

What do you mean by

why don't we sign the public key directly and send it?

If, by "sign the public key directly", you mean to generate the digital signature of the public key and send ONLY the digital signature and not the public key itself, then the browser cannot "decipher it to get the public key". This is because a digital signature is a cryptographic hash of the message that is signed. It is not an encrypted cipher text version of the message (public key, in this case) that can be deciphered to get back the original message.

So then if you mean send both the public key and its digital signature, that is the same thing that "I know the hash of the public key is signed with the CA's private key" means. The hash of the public key, signed with the CA's private key, is the digital signature.

auspicious99
  • 493
  • 3
  • 17
-1

The signature might be taken over a hash of the public key (plus a bunch of other things), but that hash isn't transmitted to the client. Intead, the client gets the full key and has to perform the hash again themselves when they go to verify the signature

Here's a bit more in-depth example of what the X.509 certificate standard (the one HTTPS and all the browsers use) does.

An X.509 certificate consists of a data structure with three parts: the body, an algorithm identifier, and a signature. Here's a dump of the certificate from security.stackexchange.com at time of writing. There's a lot of stuff in there for sure, but you can see that the top level consists of only three elements. The first SEQUENCE is the body of the certificate, the second SEQUENCE identifies the algorithm of the signature (in this case, sha256WithRSAEncryption), and the final BIT STRING is the signature itself.

Now, take a look at the seventh thing in the body:

SEQUENCE (2 elem)
  SEQUENCE (2 elem)
    OBJECT IDENTIFIER 1.2.840.113549.1.1.1 rsaEncryption (PKCS #1)
    NULL
  BIT STRING (1 elem)
    SEQUENCE (2 elem)
      INTEGER (2048 bit) 194658326354028367422746831133348837415085361304076036342735773779128…
      INTEGER 65537

That's the public key -- the whole public key. There are two essential parts to a RSA public key, the exponent and the modulus. The modulus is the long, 2048-bit integer you see there, while the exponent is 65537. (Exponents need to be prime, but don't have to be secret or even very large. A lot of keys use 2, but 65537 is probably the most popular choice, because it's 2^16 + 1 -- which makes the exponentiation calculation easy to run on typical hardware.)

The key takeaway here is that while hashing is performed as part of the signature process, the signature is made over the whole certificate body, which includes the whole public key -- along with a bunch of other stuff. So, essentially, you're right: we should send down the whole public key as part of the certificate, not just the hash -- which is why that's what we do.

Reid Rankin
  • 1,062
  • 5
  • 10