💾 Archived View for gemini.rmf-dev.com › repo › Vaati › Vgmi › files › 54c74ef79e5821ec45aee69ae78f0… captured on 2023-12-28 at 15:45:15. Gemini links have been rewritten to link to archived content
-=-=-=-=-=-=-
0 /*
1 * ISC License
2 * Copyright (c) 2023 RMF <rawmonk@firemail.cc>
3 */
4 /* socket */
5 #include <arpa/inet.h>
6 #include <netdb.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/socket.h>
11 #ifdef __FreeBSD__
12 #include <netinet/in.h>
13 #include "sandbox.h"
14 #define connect sandbox_connect
15 #endif
16 /* tls */
17 #include <tls.h>
18
19 #include <errno.h>
20 #include <unistd.h>
21
22 #include "macro.h"
23 #include "strlcpy.h"
24 #include "error.h"
25 #include "client.h"
26 #include "page.h"
27 #include "request.h"
28 #include "known_hosts.h"
29 #include "secure.h"
30 #include "certificate.h"
31 #include "storage.h"
32 #include "memory.h"
33 #include "config.h"
34
35 struct secure {
36 struct tls *ctx;
37 struct tls_config *config;
38 };
39
40 int secure_initialized = 0;
41
42 static const char *_tls_error(struct tls *ctx) {
43 const char *str = tls_error(ctx);
44 return str ? str : "Success";
45 }
46
47 static const char *_tls_config_error(struct tls_config *config) {
48 const char *str = tls_config_error(config);
49 return str ? str : "Success";
50 }
51
52 int secure_init(struct secure *secure, const char *hostname) {
53
54 if (!secure_initialized) {
55 if (tls_init()) {
56 STRLCPY(error_tls, strerror(errno));
57 return ERROR_TLS_FAILURE;
58 }
59 secure_initialized = 1;
60 }
61
62 if (!secure->ctx) {
63 secure->ctx = tls_client();
64 if (!secure->ctx) {
65 return ERROR_MEMORY_FAILURE;
66 }
67 }
68
69 if (!secure->config) {
70 secure->config = tls_config_new();
71 if (!secure->config) {
72 return ERROR_MEMORY_FAILURE;
73 }
74
75 tls_config_insecure_noverifycert(secure->config);
76 if (tls_configure(secure->ctx, secure->config)) {
77 STRLCPY(error_tls, _tls_config_error(secure->config));
78 return ERROR_TLS_FAILURE;
79 }
80
81 if (hostname) {
82 char cert_path[1024], key_path[1024];
83 char cert[4096], key[4096];
84 size_t cert_len, key_len;
85
86 int ret = certificate_getpath(hostname,
87 V(cert_path), V(key_path));
88 /* TODO: handle errors properly */
89 if (ret < 0) return 0;
90 if (storage_read(cert_path, V(cert), &cert_len))
91 return 0;
92 if (storage_read(key_path, V(key), &key_len))
93 return 0;
94 tls_config_set_keypair_mem(secure->config,
95 (unsigned char*)cert, cert_len,
96 (unsigned char*)key, key_len);
97 }
98 }
99
100 return 0;
101 }
102
103 struct secure *secure_new() {
104 struct secure *secure = calloc(1, sizeof(struct secure));
105 return secure;
106 }
107
108 int secure_connect(struct secure *secure, struct request request) {
109
110 int ret, sockfd;
111 struct sockaddr *addr;
112
113 if ((ret = secure_init(secure, request.name))) return ret;
114
115 sockfd = socket(AF_INET, SOCK_STREAM, 0);
116 if (sockfd == -1) return ERROR_SOCKET_CREATION;
117
118 addr = request.addr;
119 ret = -1;
120 switch (addr->sa_family) {
121 case AF_INET:
122 ((struct sockaddr_in*)addr)->sin_port = htons(request.port);
123 ret = connect(sockfd, addr, sizeof(struct sockaddr_in));
124 break;
125 case AF_INET6:
126 ((struct sockaddr_in6*)addr)->sin6_port = request.port;
127 ret = connect(sockfd, addr, sizeof(struct sockaddr_in6));
128 break;
129 }
130 if (ret) {
131 ret = ERROR_SOCKET_CONNECTION;
132 goto error;
133 }
134
135 if (tls_connect_socket(secure->ctx, sockfd, request.name)) {
136 ret = ERROR_TLS_FAILURE;
137 STRLCPY(error_tls, _tls_error(secure->ctx));
138 goto error;
139 }
140
141 if (tls_handshake(secure->ctx)) {
142 ret = ERROR_TLS_FAILURE;
143 STRLCPY(error_tls, _tls_error(secure->ctx));
144 goto error;
145 }
146
147 {
148 const char *hash = tls_peer_cert_hash(secure->ctx);
149 time_t start = tls_peer_cert_notbefore(secure->ctx);
150 time_t end = tls_peer_cert_notafter(secure->ctx);
151 ret = known_hosts_verify(request.name, hash, start, end);
152 if (ret) goto error;
153 }
154
155 return 0;
156 error:
157 close(sockfd);
158 return ret;
159 }
160
161 int secure_send(struct secure *secure, const char *data, size_t len) {
162 if (tls_write(secure->ctx, data, len) == (ssize_t)len) return 0;
163 STRLCPY(error_tls, _tls_error(secure->ctx));
164 return ERROR_TLS_FAILURE;
165 }
166
167 int secure_read(struct secure *secure, char **data, size_t *length) {
168
169 const size_t pad = 16; /* pad the end with null-bytes in case the data
170 ends with an incomplete unicode character */
171 char buf[1024], *ptr;
172 size_t len, allocated;
173 int i;
174
175 ptr = NULL;
176 i = len = allocated = 0;
177 while (len < config.maximumBodyLength) {
178 if (len + sizeof(buf) > allocated) {
179 char *tmp;
180 allocated += sizeof(buf);
181 tmp = realloc(ptr, allocated + pad);
182 if (!tmp) {
183 free(ptr);
184 return ERROR_MEMORY_FAILURE;
185 }
186 ptr = tmp;
187 }
188 i = tls_read(secure->ctx, buf, sizeof(buf));
189 if (i == TLS_WANT_POLLIN) continue;
190 if (i < 1) break;
191 memcpy(&ptr[len], buf, i);
192 len += i;
193 }
194 if (len >= config.maximumBodyLength) {
195 free(ptr);
196 return ERROR_RESPONSE_TOO_LARGE;
197 }
198 if (i < 0) {
199 free(ptr);
200 STRLCPY(error_tls, _tls_error(secure->ctx));
201 return ERROR_TLS_FAILURE;
202 }
203 memset(&ptr[len], 0, pad);
204 *length = len;
205 if (readonly(ptr, *length, data)) return ERROR_ERRNO;
206 free(ptr);
207 return 0;
208 }
209
210 int secure_free(struct secure *secure) {
211 tls_config_free(secure->config);
212 tls_free(secure->ctx);
213 free(secure);
214 return 0;
215 }
216