💾 Archived View for gemini.rmf-dev.com › repo › Vaati › Vgmi › files › a03ad9a68a5e10b0d67164cac7c25… captured on 2024-02-05 at 09:55:22. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-12-28)
-=-=-=-=-=-=-
0 /*
1 * ISC License
2 * Copyright (c) 2023 RMF <rawmonk@firemail.cc>
3 */
4 #include <stdlib.h>
5 #include <string.h>
6 #include <openssl/pem.h>
7 #include <openssl/err.h>
8 #include <fcntl.h>
9 #ifdef __linux__
10 #include <sys/random.h>
11 #endif
12 #include "storage.h"
13 #include "strlcpy.h"
14 #include "config.h"
15
16 int certificate_getpath(const char *host, char *crt, size_t crt_len,
17 char *key, size_t key_len) {
18 int len = strnlen(host, 1024);
19 if (strlcpy(crt, host, crt_len) >= crt_len - 4) return -1;
20 if (strlcpy(key, host, key_len) >= key_len - 4) return -1;
21 if (strlcpy(&crt[len], ".crt", crt_len - len) + len >= crt_len)
22 return -1;
23 if (strlcpy(&key[len], ".key", key_len - len) + len >= key_len)
24 return -1;
25 return len + 4;
26 }
27
28 int certificate_create(char *host, char *error, int errlen) {
29
30 char key[1024];
31 char crt[1024];
32 FILE* f = NULL;
33 int fd, id, ret = 1;
34
35 X509_NAME *name;
36 #ifdef USE_OPENSSL
37 EVP_PKEY *pkey = EVP_RSA_gen(CERTIFICATE_BITS);
38 X509 *x509 = X509_new();
39 #else /* LibreSSL */
40 EVP_PKEY *pkey = EVP_PKEY_new();
41 RSA *rsa = RSA_new();
42 BIGNUM *bne = BN_new();
43 X509 *x509 = X509_new();
44 if (BN_set_word(bne, 65537) != 1) goto failed;
45 if (RSA_generate_key_ex(rsa, config.certificateBits, bne, NULL) != 1)
46 goto failed;
47
48 EVP_PKEY_assign_RSA(pkey, rsa);
49 #endif
50
51 #ifdef __linux__
52 getrandom(&id, sizeof(id), GRND_RANDOM);
53 #else
54 arc4random_buf(&id, sizeof(id));
55 #endif
56 if (ASN1_INTEGER_set(X509_get_serialNumber(x509), id) != 1)
57 goto failed;
58
59 X509_gmtime_adj(X509_getm_notBefore(x509), 0);
60 X509_gmtime_adj(X509_getm_notAfter(x509), config.certificateLifespan);
61
62 if (X509_set_pubkey(x509, pkey) != 1) goto failed;
63
64 name = X509_get_subject_name(x509);
65 if (X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC,
66 (unsigned char*)host, -1, -1, 0) != 1)
67 goto failed;
68
69 if (X509_set_issuer_name(x509, name) != 1) goto failed;
70 if (X509_sign(x509, pkey, EVP_sha1()) == 0) goto failed;
71
72 if (certificate_getpath(host, crt, sizeof(crt),
73 key, sizeof(key)) == -1)
74 goto failed;
75
76 /* Key */
77 fd = storage_open(key, O_CREAT|O_WRONLY|O_TRUNC, 0600);
78 if (fd < 0) {
79 snprintf(error, errlen, "Failed to open %s : %s",
80 key, strerror(errno));
81 goto skip_error;
82 }
83 f = fdopen(fd, "wb");
84
85 if (!f) {
86 snprintf(error, errlen, "Failed to write to %s : %s",
87 key, strerror(errno));
88 goto skip_error;
89 }
90 if (PEM_write_PrivateKey(f, pkey, NULL, NULL, 0, NULL, NULL) != 1)
91 goto failed;
92 fclose(f);
93
94 /* Certificate */
95 fd = storage_open(crt, O_CREAT|O_WRONLY|O_TRUNC, 0600);
96 if (fd < 0) {
97 snprintf(error, errlen, "Failed to open %s", crt);
98 goto skip_error;
99 }
100 f = fdopen(fd, "wb");
101
102 if (!f) {
103 snprintf(error, errlen, "Failed to write to %s", crt);
104 goto skip_error;
105 }
106 if (PEM_write_X509(f, x509) != 1)
107 goto failed;
108 fclose(f);
109
110 f = NULL;
111 ret = 0;
112 goto skip_error;
113 failed:
114 snprintf(error, errlen, "Failed to generate certificate");
115 skip_error:
116 if (f) fclose(f);
117 EVP_PKEY_free(pkey);
118 X509_free(x509);
119 #ifndef USE_OPENSSL
120 BN_free(bne);
121 #endif
122 return ret;
123 }
124