Projekt

Obecné

Profil

Knowledge-Base » Historie » Verze 3

Michal Seják, 2021-03-11 12:05
Minor changes (readability+)

1 1 Jan Pašek
h1. Knowledge-Base
2
3 2 Michal Seják
Main source of general X.509 info: https://gist.github.com/Soarez/9688998
4
OCSP and certificate revocation using raw openssl: https://bhashineen.medium.com/create-your-own-ocsp-server-ffb212df8e63
5
6 1 Jan Pašek
h2. X.509 certificates
7
8 2 Michal Seják
h3. What is a certificate (authority)?
9
10
*Certificate* = a structure belonging to a _subject_ containing his ID and public key. It is signed (= encrypted) by an _issuer_. Everyone trusts _issuer_, so by using _issuer's_ public key to decrypt the certificate, one obtains _subject's_ public key without worrying about MITM attacks. Now, whenever Alice sends data to Bob, Alice encrypts data using her private key and sends her certificate, Bob decrypts certificate using CA's public key (obtaining Alice's public key and ensuring himself Alice is actually Alice), and uses Alice's public key to decrypt Alice's data.
11
12
*Certificate authority (=CA)* = an entity capable of generating _certificates_. Must:
13
# be trusted by all communicating parties
14
# be able to fill in certificate fields according to _subject's_ needs
15
# be able to set itself as an _issuer_ of that certificate
16
# be able to encrypt the certificate by its own private key
17 3 Michal Seják
# allow every communicating party to acquire the CA's own public key (for decryption of certificates)
18 2 Michal Seják
19
*Root CA* = A CA which generates its own certificate for signing "from scratch"; that is, it signs its own certificate (= self-signed certificate).
20
21
*Intermediate CA* = A CA which uses another CA to sign its certificate. 
22
23
*End-entity certificate* = A certificate unable to sign other certificates. Cannot be used by CA's (as opposed to the above cases), but can be used for other purposes, such as client validation, document signature, etc.
24
25
h3. Structure (version 3)
26
27
h4. Person structure
28
29
* Country code [C] (2 capital characters, "EN", "CZ", etc.)
30
* Province [ST] (string; province/region, like "Pilsen Region")
31
* Locality [L] (string; city/town/municipality, e.g. "Pilsen")
32
* Organization [O] (string)
33
* Organizational unit [OU] (string; section name, department of org., etc.)
34
* Common name [CN] (string; a person's identifier)
35
* Email address [emailAddress] (string; that person's contact info, ideally -- an email address) 
36
37
h4. Certificate structure
38
39
* Data
40
** Version (1, 2, or 3, corresponding respectively to the RFC over which it is designed: 1422, 2459, or 5280)
41
** Serial number (uniquely identifies certificates issued by a single CA)
42
** Signature algorithm (how was the certificate signed, like "sha256 with RSA")
43
** *Issuer (person)* (certificate authority, equal to subject if self-signed)
44 3 Michal Seják
*** _Person structure_
45 2 Michal Seják
** Validity (time interval)
46
*** Not before (beginning of closed interval of validity)
47
*** Not after (end of closed interval of validity)
48
** *Subject* (who is the certificate issued to)
49 3 Michal Seják
*** _Person structure_
50 2 Michal Seják
** Subject public key info (certificates care only that the cipher is asymmetric)
51
*** Public key algorithm: (what the actual asymmetric implementation is)
52
**** algorithm name
53
**** key definition
54
** *X509v3 extensions*
55
*** constraints (bool whether certificate subject is CA)
56
*** identifiers (alternative to serial numbers) of authority and subject
57
*** *key usage* (how the key will be used)
58
**** for CA -> *signing certificates & CRLs*
59
**** for end certificates -> ...
60
* Signature algorithm (again; identical as above, helps prevent substitution attacks)
61
62
63 1 Jan Pašek
h2. OpenSSL
64 2 Michal Seják
65
* crypto library
66
* Apache (free for commertial purposes)
67
68
* CLI (awkward calls)
69
<pre><code class="python">
70
os.system("openssl ...")
71
subprocess.run("openssl ...", input=bytes(...))
72
</code></pre>
73
74
* *very fast* - proud enough to include benchmarks in command set. Declares certificates and certificate authorities very quickly (basic setup including end certificate takes 100-200 ms)
75
76
Example usage (key generation):
77
<pre><code class="python">
78
def make_private_key(name, passphrase):
79
    subprocess.run(["openssl", "genrsa", "-des3", "-out", name + ".key", "2048"],
80
                   input=bytes(f'{passphrase}\n{passphrase}\n', encoding='utf-8'))
81
</code></pre>
82
83
The code is not very readable, but can be formatted in the following way to add readability:
84
<pre><code class="python">
85
subprocess.run(["openssl",
86
                    "genrsa",               # generate a private key for RSA encryption scheme
87
                    "-des3",                # use DES3 for encryption by passphrase
88
                    "-out", f"{name}.key",  # output specification
89
                    "2048"],                # bits
90
91
                   input=bytes(             # input required to interact with openssl's CLI
92
                       f'{passphrase}\n'    # openssl queries for passphrase, respond and return
93
                       f'{passphrase}\n',   # openssl queries for passphrase verification, respond and return
94
                       encoding='utf-8')    # use standard encoding for input stream
95
                   )
96
</code></pre>
97
98
* vast amount of customization & config files, while pretty straightforward and easy to use if special features and customization deemed unnecessary
99
* contains bugs that users must handle (e.g. entering an incorrect password causes the program to fail checking of future passwords regardless of their correctness)
100
* overall handling of "return values" must be parsed from openssl's stdout, which can be a nuisance
101
* however, we can safely estimate the upper bound for the amount of unique openssl commands we will have to call to be 10 (CA creation, certificate sign/revoke, key creation, crl, ocsp, ...),
102
which have predictable output formats
103
* huge documentation at our disposal
104
* implicitly defaults certain variables to smart values, e.g. allows keys to be generated randomly without explicitly specifying details about exponents in RSA
105
106
h2. cryptography (Python lib)
107
108
* crypto library 
109
* low-level OpenSSL utility
110
* very well documented
111
* tutorials
112
* contains useful pre-implemented classes, like Certificate and CertificateIssuer, but these will have to be extended in order to be linked together in a tree structure
113
* however, it seems to have been designed with ease-of-use and OOP in mind as opposed to performance; overly complex design patterns like Builder, performs a multitude of actions and function calls before actually calling the backend (= openssl); this causes the same result achieved by openssl to arrive about 2x slower 
114
* if raw openssl calls are formatted in the way specified above, it uses cca the same amount of lines of code while being more readable, but larger
115
116
This tutorial code is perhaps slightly more readable than raw openssl calls.
117
<pre><code class="python">
118
key = rsa.generate_private_key(
119
    public_exponent=65537,
120
    key_size=2048,
121
)
122
with open("cert/key.pem", "wb") as f:
123
    f.write(key.private_bytes(
124
        encoding=serialization.Encoding.PEM,
125
        format=serialization.PrivateFormat.TraditionalOpenSSL,
126
        encryption_algorithm=serialization.BestAvailableEncryption(b"passphrase"),
127
    ))
128
</code></pre>
129
130
* depends on *cffi*, which depends on *pycparser* -> three new libraries are required to be installed on the target machine