I want to create a self signed PKI for a couple servers I am running. I am finding tutorials with copy paste commands from openssl, and hand waving explanations that describe the general purpose of signing certificates, or 20 page papers on the algorithms used. However, I am really trying to understand the way certificates are added on from the basic public and private key.

I would really like to understand how this works, on a level in between the mathematics and the general "it's used for validation" explanations - ideally - precisely defined inputs and outputs but I don't care how the algorithm works to produce the output. Here is what I understand:

  1. I create a root private key (random base 64 number) (rootkey.key)
  2. I create a root public certificate with that rootkey (rootcert.crt), this contains the inverse of the rootkey, i.e. public key (q1)
  3. I create a server private key (random base 64 number) (serverkey.key)
  4. I sign the server private key with the rootkey to create (servercert.crt). (q2)

Now when I establish TLS connection with the server

  1. I send my tls request with version number.
  2. Server sends servercert.crt
  3. I check servercert.crt against rootcert.crt (which I have on client side) (q3)
  4. If it's trusted then we can continue with exchanging symmetric encryption keys

(q1) A certificate is a string of pseudorandom digits. What is the mapping between the public key + some strings of domain name, email etc. and these digits? My first thought is this is encrypted with the private key, but then, how could you decrypt since the public key is inside?

(q2) what is happening here? Is this the same process, using rootkey, as step 2?

(q3) What am I doing here? decrypting the server.crt with the public key from the rootcert.crt makes sense as server.crt would be encrypted with the rootkey, but how do I get that root public key?

I think fundamentally it boils down to what is the structure of the certificate. Not just what it contains written in ASN.1 as I read on wikipedia, but mapping this to the pseudorandom digits in the file itself. While writing this I narrowed my question a lot, very useful process, but I still cannot figure this out exactly.


3 Answers 3

  1. No, a certificate is not a string of pseudorandom digits. It's an ASN.1 DER structure, with contents defined in RFC 5280 and its errata. The public key isn't necessarily an "inverse" of the private key, that would only be even vaguely correct for RSA keys. Just say the public key is "mathematically related to" the private key.

  2. No, signing is an entirely unrelated process from generating a public key. That process is quite complicated, but is described in section 8 of RFC 3447 .

  3. Certificates aren't encrypted. They contain a public key, some identity information (a Common Name, possibly other fields), some validity information (a date range when it's valid, possibly extensions defining what it can be used for), information to identify the signer, and a signature over all that information.

In your creation steps you missed the step of making a Certificate Signing Request (CSR) after making a public key. That CSR's TBS section is what gets signed, not just the public key.

The ASN.1 JavaScript Decoder can provide a very nice visual breakdown of the ASN.1 structure of a certificate, CSR, public key, or private key. Obviously don't enter a real private key you'd use there, just generate one to see how the encoding works.

  • $\begingroup$ FWIW: CSRs don't get signed by CAs... they have a completely orthogonal structure and the CA has to copy out the pieces of data they care about when making a (Tbs)Certificate. They're not essential to the flow, but, admittedly, they /are/ generally used in practice. $\endgroup$
    – bartonjs
    Commented Jan 25, 2023 at 23:55
  • $\begingroup$ Yeah, only the TBS portion of the CSR gets signed. The original signature used to prove possession of the private key is stripped off, and the metadata for that sequence removed. In practice, OpenSSL takes a CSR as an input when creating a certificate, so for the usual use of OpenSSL command-line tools a CSR is a necessary step. And signing just the TBS portion without validating the self-signature of a CSR would be a violation of the CA/Browser forum rules, so no public CA would accept such a thing. $\endgroup$ Commented Jan 26, 2023 at 2:23
  • $\begingroup$ "CSR is what gets signed" is only a rough approximation. Actually some part of the CSR is stripped (some ASN.1 decoration, the signature, often some info that the Certification Authority is not willing to sign), and things get added (such as the certificate serial number). $\endgroup$
    – fgrieu
    Commented Jan 26, 2023 at 9:41

A TLS handshake concludes with unilateral authentication of the server. For (EC)DHE-only key exchange, the server sends a Certificate message followed by a CertificateVerify message, the former contains a certificate (along with its certificate chain) for authentication, and the latter contains a signature (constructed with the private key corresponding to the public key in the certificate) over a hash of the handshake's transcript, thereby, proving possession of the private key used for signing, hence, identifying the server.

The certificate chain comprises DER-encoded X.509v3 certificates (unless an alternative was negotiated). The server's certificate must appear first and every subsequent certificate should certify the previous one (i.e., every subsequent certificate should contain a signature - using the private key corresponding to the certificate's public key - over the previous certificate's public key), hence, the list is a certificate chain.

Regarding your questions, you're creating (q2) and verifying (q3) the certificate.

Further details: https://arxiv.org/abs/1904.02148 (Section 2.5).


The answers were all helpful. With them I worked on my understanding to come up with this conceptual understanding expressed in pseudocode:

1. signing certificate

signature = encrypt(hash(server_info), rootkey)

certificate = start_cert + server_info + algorithm_used + signature + end_cert

2. validating certificate

if hash(server_info) == decrypt(signature, rootcert):

    return valid

The only way part 2 is true if the info was indeed signed by the private of the CA.

I know this leaves out some details of implementation and extra security stuff but I finally understand the basic premise of how this is even possible.

Also, Q: why can you not read the server_info in the file? A: It is not actually hashed or encrypted, it is just encoded to a binary format, and then stored in base64 making it look like a string that has been encrypted.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.