# OCSP server
![GitHub License](https://img.shields.io/github/license/DorianCoding/OCSP_server)
[![Github stars](https://img.shields.io/github/stars/DorianCoding/OCSP_server.svg)](https://github.com/DorianCoding/OCSP_server/stargazers)
*OCSP Server is a **OCSP responder**, the Rust implementation of the [python version](https://github.com/DorianCoding/OCSP_MySql).*
----
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 :
```toml
#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
1) Clone the repo `git clone https://github.com/DorianCoding/OCSP_MySql.git`
2) 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
1) Clone the repo `git clone https://github.com/DorianCoding/OCSP_MySql.git`
2) Type `cargo run` or `cargo 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 :
```bash
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](#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 .