1 unstable release
0.2.0 | Sep 23, 2024 |
---|
#112 in Caching
44KB
431 lines
OCSP server
OCSP Server is a OCSP responder, the Rust implementation of the python version.
This software implements a OCSP responder in Rust, fetching certificate status in a Mysql/MariaDB database. Unlike the Python implementation, it does implement its own TCP listener on a user-selected port. It will answer to any GET or POST requests on any URL.
Requirements
- A CA certificate (self-signed allowed) and/or an intermediate CA that will sign leaf certificates.
- A config file (config.toml) in the same directory. As well, files indicated in this file must also be accessible.
- A Mysql database containing all certificates (check below) that could be checked and were signed.
What is done
- Extract OCSP requests, verify it is a signed certificate by the CA, check in the database if it is good or revoked and sign the response. It also caches answers for some days to avoid RSA calculations.
- Create a specific user for this task to ensure protection for intermediate certificate, as the private key is required.
What is not done
- Only leaf certificates will be signed as valid, not the intermediate one.
- No control is performed on the TCP socket and it should not be open to public as it but rather behind a reverse proxy that controls the flow, such as Apache or Nginx. Requests are limited to 3 Mb.
[!TIP] The intermediate certificate should be signed by CA in an OCSP response that is stored separately. The CA certificate and private key should be stored offline.
Config file
The config file should contain the following informations :
#Config file, all fields are compulsory
cachedays = 3 #Number of days a response is valid once created (only for valid certificates)
dbip = "127.0.0.1" #IP to connect to MySql database
dbuser = "cert" #Username to connect to MySql database
port = 9000 #Port to listen to, from 1 to 65535. Cannot use a port already used by another service (privileged ports allowed if used as root or as a service)
dbname = "certs" #Name to connect to MySql data
dbpassword = "certdata" #Password to connect to cert data
cachefolder = "cache/" #Folder to cache data (relative or absolute, will be created if not present)
itcert = "/var/public_files/it_cert.crt" #Path to intermediate certificate
itkey = "/var/private_files/it_privkey.pem" #Path to intermediate private key, keep it secret
[!CAUTION] Config.toml should be read-only for the script and inaccessible for others because it contains dbpassword. Intermediate certificate key should be held secret, must be read-only for the script and inaccessible to anyone else. The intermediate certificate should be world-readonly, including to the script. As a service, the script will use a brand-new user called pycert. This ensures system integrity and protection. All the filesystem is locked by systemd except the cache folder. The responder will reply to any certificate that are present in the database, whatever they are currently expired or not.
How to implement?
As a linux service (Recommended)
Create your config file in the main directory and call service.sh
as root. The service then will be started on bootup and will listen to connections.
Binaries
- Clone the repo
git clone https://github.com/DorianCoding/OCSP_MySql.git
- Extract binaries for your architecture and execute it in the background.
Feel free to share binaries for others architectures in a PR so they can be added. Please post only optimized binaries (release).
Compile from source
- Clone the repo
git clone https://github.com/DorianCoding/OCSP_MySql.git
- Type
cargo run
orcargo run --release
and enjoy 👍
MySql table
This script requires a table with this kind of structure :
CREATE TABLE `list_certs` (
`cert_num` varchar(50) NOT NULL,
`revocation_time` datetime DEFAULT NULL,
`revocation_reason` enum('unspecified','key_compromise','ca_compromise','affiliation_changed','superseded','cessation_of_operation','certificate_hold','privilege_withdrawn','aa_compromise') DEFAULT NULL,
`cert` blob NOT NULL,
`status` enum('Valid','Revoked') NOT NULL DEFAULT 'Valid',
PRIMARY KEY (`cert_num`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
- The certificate number must be unique and start with 0x (like a hex number). Cert must contain the certificate in PEM format. Revocaition_time must be in UTC timezone.
- When the certificate is valid, status must be "Valid" and revocation_time and reason must be NULL. On the opposite, upon revocation, status must be "Revoked" and revocation_time and reason must be set.
Script test and timeline
Test integration
You can test the script using openssl
and replacing issuer and cert by files containing respectively the issuer and the local certificate :
openssl ocsp -issuer myissuer.crt -cert localcert.crt -url http://localhost:9000 -resp_text
You should get a valid OCSP response. If you don't, check integration.
Timeline
The script is fast and can be used in production systems. Here is the time taken using a 2048-bit RSA key as signing key :
Architecture | CPU | RAM | Time to perform test |
---|---|---|---|
armv7l 32-bit | RaspberryTM | 1 Go | 0,4s from scratch and 0,12s from cache |
x86_64 | Intel-i5 6th generation | 16 Go | 0,2s from scratch and 0,04s from cache |
Script input/output
Toggle
Input
This software requires an OCSP request in binary form from the socket client. A request look like this (in base64 format), the binary form (DER format) is not human-readable but is the one needed :
MHoweDBRME8wTTAJBgUrDgMCGgUABBRGf2x685RgF9qF4azpunF6LM75OQQUwX3C7a+au9Af8tx/
tcfCxFkwR68CFAlOMV+mrbm8PqIFZKeyLubrqlXgoiMwITAfBgkrBgEFBQcwAQIEEgQQkcDcDZCP
zGR57CNCnt6eKg==
You can use openssl ocsp -reqin file -req_text
to verify the format, which will give you something like this :
OCSP Request Data:
Version: 1 (0x0)
Requestor List:
Certificate ID:
Hash Algorithm: sha1
Issuer Name Hash: 467F6C7AF3946017DA85E1ACE9BA717A2CCEF939
Issuer Key Hash: C17DC2EDAF9ABBD01FF2DC7FB5C7C2C4593047AF
Serial Number: 094E315FA6ADB9BC3EA20564A7B22EE6EBAA55E0
Request Extensions:
OCSP Nonce:
041091C0DC0D908FCC6479EC23429EDE9E2A
Output
The software will give a binary file which is the OCSP response in DER format, just as before, the base64 form :
MIIB1woBAKCCAdAwggHMBgkrBgEFBQcwAQEEggG9MIIBuTCBoqIWBBTBfcLtr5q70B/y3H+1x8LE
WTBHrxgPMjAyMjEyMjkxMzE5MDlaMHcwdTBNMAkGBSsOAwIaBQAEFEZ/bHrzlGAX2oXhrOm6cXos
zvk5BBTBfcLtr5q70B/y3H+1x8LEWTBHrwIUCU4xX6atubw+ogVkp7Iu5uuqVeCAABgPMjAyMjEy
MjkxMzE5MDlaoBEYDzIwMjIxMjMwMTMxOTA4WjANBgkqhkiG9w0BAQsFAAOCAQEAkIg1jf1Y5gm2
FB0eAdgfP5/h0CddJBYyD0p8SvwXdTTU+Uee+7zUhTwNzq3omosSLMgJ2yEjEv/vai4XgvCeJ+uL
vhMZADzgmifNw/58o94F7RbY9t9XoKhioS9tN0QT/y7Gzyz16vD+vYYqkW8Pvb6ueRL5A3QUARUz
eUZoU24omksxF3smVbCzM8czBAre5ydejKDS6GjnMcTZqg+GggVYJMS7ZocHVbwVRv75xFo+M/7P
cg78TNJ+KtrUOJFWYaJOOZhUleBaSmg8AW9rsZuLl98pexghCwEb9hh1mfkSUWpvRJFyVC7xblQa
JvLu5tc1TJLKtYP5uUrRmDEufA==
You can use openssl ocsp -respin file -resp_text
to verify the format, which will give you something like this :
OCSP Response Data:
OCSP Response Status: successful (0x0)
Response Type: Basic OCSP Response
Version: 1 (0x0)
Responder Id: C17DC2EDAF9ABBD01FF2DC7FB5C7C2C4593047AF
Produced At: Dec 29 13:19:09 2022 GMT
Responses:
Certificate ID:
Hash Algorithm: sha1
Issuer Name Hash: 467F6C7AF3946017DA85E1ACE9BA717A2CCEF939
Issuer Key Hash: C17DC2EDAF9ABBD01FF2DC7FB5C7C2C4593047AF
Serial Number: 094E315FA6ADB9BC3EA20564A7B22EE6EBAA55E0
Cert Status: good
This Update: Dec 29 13:19:09 2022 GMT
Next Update: Dec 30 13:19:08 2022 GMT
Signature Algorithm: sha256WithRSAEncryption
90:88:35:8d:fd:58:e6:09:b6:14:1d:1e:01:d8:1f:3f:9f:e1:
d0:27:5d:24:16:32:0f:4a:7c:4a:fc:17:75:34:d4:f9:47:9e:
fb:bc:d4:85:3c:0d:ce:ad:e8:9a:8b:12:2c:c8:09:db:21:23:
12:ff:ef:6a:2e:17:82:f0:9e:27:eb:8b:be:13:19:00:3c:e0:
9a:27:cd:c3:fe:7c:a3:de:05:ed:16:d8:f6:df:57:a0:a8:62:
a1:2f:6d:37:44:13:ff:2e:c6:cf:2c:f5:ea:f0:fe:bd:86:2a:
91:6f:0f:bd:be:ae:79:12:f9:03:74:14:01:15:33:79:46:68:
53:6e:28:9a:4b:31:17:7b:26:55:b0:b3:33:c7:33:04:0a:de:
e7:27:5e:8c:a0:d2:e8:68:e7:31:c4:d9:aa:0f:86:82:05:58:
24:c4:bb:66:87:07:55:bc:15:46:fe:f9:c4:5a:3e:33:fe:cf:
72:0e:fc:4c:d2:7e:2a:da:d4:38:91:56:61:a2:4e:39:98:54:
95:e0:5a:4a:68:3c:01:6f:6b:b1:9b:8b:97:df:29:7b:18:21:
0b:01:1b:f6:18:75:99:f9:12:51:6a:6f:44:91:72:54:2e:f1:
6e:54:1a:26:f2:ee:e6:d7:35:4c:92:ca:b5:83:f9:b9:4a:d1:
98:31:2e:7c
License
- GPL 3.0
OCSP Server - OCSP responder in Rust Copyright (C) 2023 DorianCoding
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, under version 3 of the License only.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see https://www.gnu.org/licenses/.
Dependencies
~35–69MB
~1.5M SLoC