main
xs_bearssl.h
1#ifndef _XS_BEARSSL_H
2#define _XS_BEARSSL_H
3
4#include "xs.h"
5#include "xs_hex.h"
6
7xs_str* _xs_digest(const xs_val* input, int size, const char* digest, int as_hex);
8
9#ifndef _XS_MD5_H
10#define xs_md5_hex(input, size) _xs_digest(input, size, "md5", 1)
11#endif // _XS_MD5_H
12
13#ifndef _XS_BASE64_H
14xs_str* xs_base64_enc(const xs_val* data, int size);
15xs_val* xs_base64_dec(const xs_str* data, int* size);
16#endif // _XS_BASE64_H
17
18#define xs_sha1_hex(input, size) _xs_digest(input, size, "sha1", 1)
19#define xs_sha256_hex(input, size) _xs_digest(input, size, "sha256", 1)
20#define xs_sha256_base64(input, size) _xs_digest(input, size, "sha256", 0)
21
22xs_dict* xs_evp_genkey(int bits);
23xs_str* xs_evp_sign(const char* secret, const char* mem, int size);
24int xs_evp_verify(const char* pubkey, const char* mem, int size, const char* b64_sig);
25
26#ifdef XS_IMPLEMENTATION
27
28#include "bearssl_x509.h"
29#include "bearssl_hash.h"
30#include "bearssl_pem.h"
31#include "bearssl_rand.h"
32#include "bearssl_rsa.h"
33
34#ifndef _XS_BASE64_H
35/* *
36 * Ok after reading the bearSSL code for a while I found they expose nothing for base64
37 * encoding, they do mention it in the header files but they only use it internally for
38 * their pem encoding and I can't even really copy the code because it's written in some
39 * weird uxn like language that only Thomas Pornin (that is actually his last name lol)
40 * knows.
41 *
42 * So that just leaves me to handroll the base64 encoding! Shrub I don't know why you
43 * meatride this lib so much but I hope this gets you to join minx cafe.
44 * */
45
46static const char _b64_tab[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
47
48static int _b64_val(int c) {
49 if (c >= 'A' && c <= 'Z') return c - 'A';
50 if (c >= 'a' && c <= 'z') return c - 'a' + 26;
51 if (c >= '0' && c <= '9') return c - '0' + 52;
52 if (c == '+') return 62;
53 if (c == '/') return 63;
54 return -1;
55}
56
57xs_str* xs_base64_enc(const xs_val* data, int size) { // NOLINT
58 const int b64_bytes = 3;
59 const int b64_chars = 4;
60
61 const unsigned char *d = (const unsigned char *)data;
62
63 int output_len = ((size + b64_bytes - 1) / b64_bytes) * b64_chars;
64 xs_str* s = xs_realloc(NULL, _xs_blk_size(output_len + 1));
65
66 int i = 0, j = 0;
67 while (i + b64_bytes - 1 < size) {
68 unsigned int v = (d[i] << 16) | (d[i + 1] << 8) | d[i + 2];
69
70 s[j++] = _b64_tab[(v >> 18) & 0x3f];
71 s[j++] = _b64_tab[(v >> 12) & 0x3f];
72 s[j++] = _b64_tab[(v >> 6) & 0x3f];
73 s[j++] = _b64_tab[v & 0x3f];
74 i += b64_bytes;
75 }
76
77 if (i < size) {
78 unsigned int v = d[i] << 16;
79 int rem = size - i;
80
81 if (rem == 2) { v |= d[i + 1] << 8; }
82
83 s[j++] = _b64_tab[(v >> 18) & 0x3f];
84 s[j++] = _b64_tab[(v >> 12) & 0x3f];
85 s[j++] = (rem == 2) ? _b64_tab[(v >> 6) & 0x3f] : '=';
86 s[j++] = '=';
87 }
88
89 s[j] = '\0';
90
91 return s;
92}
93
94xs_val* xs_base64_dec(const xs_str* data, int* size) {
95 int input_len = strlen(data);
96 unsigned char* out = xs_realloc(NULL, _xs_blk_size(input_len + 1));
97
98 int o = 0, acc = 0, bits = 0, pad = 0, i;
99
100 for (i = 0; i < input_len; i++) {
101 int c = (unsigned char)data[i];
102 int v;
103
104 if (c == '\n' || c == '\r' || c == ' ' || c == '\t') {
105 continue;
106 }
107
108 if (c == '=') {
109 pad++;
110 if (pad > 2) { xs_free(out); return NULL; }
111 continue;
112 }
113
114 if (pad > 0) { xs_free(out); return NULL; }
115
116 v = _b64_val(c);
117 if (v < 0) { xs_free(out); return NULL; }
118
119 acc = (acc << 6) | v;
120 bits += 6;
121
122 if (bits >= 8) {
123 bits -= 8;
124 out[o++] = (acc >> bits) & 0xff;
125 }
126 }
127
128 if (bits != pad * 2) { xs_free(out); return NULL; }
129
130 out = xs_realloc(out, _xs_blk_size(o + 1));
131 out[o] = '\0';
132 *size = o;
133
134 return (xs_val*)out;
135}
136#endif // _XS_BASE64_H
137
138/* im hungy */
139static int _digest_raw(const char* name, const void* data, size_t len, unsigned char* out) {
140 if (strcmp(name, "md5") == 0) {
141 br_md5_context ctx;
142 br_md5_init(&ctx);
143 br_md5_update(&ctx, data, len);
144 br_md5_out(&ctx, out);
145 return 16;
146 }
147
148 if (strcmp(name, "sha1") == 0) {
149 br_sha1_context ctx;
150 br_sha1_init(&ctx);
151 br_sha1_update(&ctx, data, len);
152 br_sha1_out(&ctx, out);
153 return 20;
154 }
155
156 if (strcmp(name, "sha256") == 0) {
157 br_sha256_context ctx;
158 br_sha256_init(&ctx);
159 br_sha256_update(&ctx, data, len);
160 br_sha256_out(&ctx, out);
161 return 32;
162 }
163
164 return 0;
165}
166
167xs_str* _xs_digest(const xs_val* input, int size, const char* digest, int as_hex) {
168 unsigned char out[64];
169 int n = _digest_raw(digest, input, size, out);
170
171 if (n == 0) { return NULL; }
172
173 return as_hex ? xs_hex_enc((char*)out, n) : xs_base64_enc((char*)out, n);
174}
175
176struct _pembuf {
177 unsigned char* ptr;
178 size_t len;
179 size_t cap;
180};
181
182static void _pem_sink(void* vctx, const void* data, size_t len) {
183 struct _pembuf* buf = vctx;
184
185 if (buf->len + len > buf->cap) {
186 buf->cap = (buf->len + len) * 2 + 64;
187 buf->ptr = xs_realloc(buf->ptr, (int)buf->cap);
188 }
189
190 memcpy(buf->ptr + buf->len, data, len);
191 buf->len += len;
192}
193
194static unsigned char* _pem_to_der(const char* pem, size_t* out_len) {
195 br_pem_decoder_context pctx;
196 struct _pembuf buf = {0};
197
198 const char* src = pem;
199
200 br_pem_decoder_init(&pctx);
201 br_pem_decoder_setdest(&pctx, _pem_sink, &buf);
202
203 size_t pem_len = strlen(pem);
204 int done = 0;
205 while (pem_len > 0 && !done) {
206 size_t n = br_pem_decoder_push(&pctx, src, pem_len);
207 int ev;
208
209 src += n;
210 pem_len -= n;
211 ev = br_pem_decoder_event(&pctx);
212
213 if (ev == BR_PEM_END_OBJ) {
214 done = 1;
215 }
216
217 if (ev == BR_PEM_ERROR) {
218 xs_free(buf.ptr);
219 return NULL;
220 }
221
222 if (n == 0 && ev == 0) { break; }
223 }
224
225 if (!done || buf.ptr == NULL) {
226 xs_free(buf.ptr);
227 return NULL;
228 }
229
230 *out_len = buf.len;
231 return buf.ptr;
232}
233
234static int _der_tlv(const unsigned char** cur, const unsigned char* end, unsigned char* tag, size_t* len, const unsigned char** val) {
235 const unsigned char* p = *cur;
236 size_t vlen;
237
238 if (p >= end) { return 0; }
239
240 *tag = *p++;
241
242 if (p >= end) { return 0; }
243
244 vlen = *p++;
245
246 if (vlen & 0x80) {
247 int nbytes = vlen & 0x7f;
248
249 if (nbytes == 0 || nbytes > 4) { return 0; }
250
251 vlen = 0;
252 while (nbytes--) {
253 if (p >= end) { return 0; }
254
255 vlen = (vlen << 8) | *p++;
256 }
257 }
258
259 if ((size_t)(end - p) < vlen) { return 0; }
260
261 *len = vlen;
262 *val = p;
263 *cur = p + vlen;
264
265 return 1;
266}
267
268static size_t _der_put(unsigned char* dst, unsigned char tag, const unsigned char* content, size_t c_len) {
269 size_t hl;
270
271 if (c_len < 128) {
272 dst[0] = tag;
273 dst[1] = (unsigned char)c_len;
274 hl = 2;
275 } else if (c_len < 256) {
276 dst[0] = tag;
277 dst[1] = 0x81;
278 dst[2] = (unsigned char)c_len;
279 hl = 3;
280 } else {
281 dst[0] = tag;
282 dst[1] = 0x82;
283 dst[2] = (unsigned char)(c_len >> 8);
284 dst[3] = (unsigned char)c_len;
285 hl = 4;
286 }
287
288 if (content) { memmove(dst + hl, content, c_len); }
289
290 return hl + c_len;
291}
292
293static size_t _der_uint(unsigned char *dst, const unsigned char *v, size_t len) {
294 unsigned char tmp[600];
295 int pad;
296 size_t clen;
297
298 while (len > 1 && v[0] == 0) {
299 v++;
300 len--;
301 }
302
303 pad = (len > 0 && (v[0] & 0x80)) ? 1 : 0;
304 clen = len + pad;
305
306 if (pad) { tmp[0] = 0; }
307
308 memcpy(tmp + pad, v, len);
309
310 return _der_put(dst, 0x02, tmp, clen);
311}
312
313static size_t _build_spki(unsigned char* dst, const unsigned char* n, size_t n_len, const unsigned char* e, size_t e_len) {
314 static const unsigned char alg_id[] = {
315 0x30, 0x0d,
316 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
317 0x05, 0x00
318 };
319 unsigned char rsa_pub[1024], rsa_seq[1100], bit_content[1200], bit_str[1300], content[1400];
320 size_t rsa_len = 0, seq_len, bit_len;
321
322 rsa_len += _der_uint(rsa_pub + rsa_len, n, n_len);
323 rsa_len += _der_uint(rsa_pub + rsa_len, e, e_len);
324 seq_len = _der_put(rsa_seq, 0x30, rsa_pub, rsa_len);
325
326 bit_content[0] = 0x00;
327 memcpy(bit_content + 1, rsa_seq, seq_len);
328 bit_len = _der_put(bit_str, 0x03, bit_content, seq_len + 1);
329
330 memcpy(content, alg_id, sizeof(alg_id));
331 memcpy(content + sizeof(alg_id), bit_str, bit_len);
332
333 return _der_put(dst, 0x30, content, sizeof(alg_id) + bit_len);
334}
335
336static int _parse_spki(const unsigned char* der, size_t len, br_rsa_public_key* pk) {
337 const unsigned char* cur = der, *end = der + len;
338 const unsigned char* val;
339 unsigned char tag;
340 size_t vlen;
341
342 // outer SEQUENCE
343 if (!_der_tlv(&cur, end, &tag, &vlen, &val) || tag != 0x30) { return 0; }
344
345 const unsigned char* algo = val, *algo_end = val + vlen;
346
347 // AlgorithmIdentifier SEQUENCE
348 if (!_der_tlv(&algo, algo_end, &tag, &vlen, &val) || tag != 0x30) { return 0; }
349
350 // OID (rsaEncryption)
351 const unsigned char* oid = val, *oid_end = val + vlen;
352 if (!_der_tlv(&oid, oid_end, &tag, &vlen, &val) || tag != 0x06) { return 0; }
353
354 // BIT STRING
355 if (!_der_tlv(&algo, algo_end, &tag, &vlen, &val) || tag != 0x03) { return 0; }
356 if (vlen < 1 || val[0] != 0) { return 0; }
357
358 const unsigned char* rsa = val + 1, *rsa_end = val + vlen;
359
360 // RSAPublicKey SEQUENCE
361 if (!_der_tlv(&rsa, rsa_end, &tag, &vlen, &val) || tag != 0x30) { return 0; }
362
363 const unsigned char* key = val, *key_end = val + vlen;
364 const unsigned char* n_ptr, *e_ptr;
365 size_t n_len, e_len;
366
367 if (!_der_tlv(&key, key_end, &tag, &n_len, &n_ptr) || tag != 0x02) { return 0; }
368 if (!_der_tlv(&key, key_end, &tag, &e_len, &e_ptr) || tag != 0x02) { return 0; }
369
370 pk->n = (unsigned char*)n_ptr; pk->nlen = n_len;
371 pk->e = (unsigned char*)e_ptr; pk->elen = e_len;
372
373 return 1;
374}
375
376/* RSA sign / verify / keygen */
377xs_str* xs_evp_sign(const char* secret, const char* mem, int size) {
378 xs_str* signature = NULL;
379 unsigned char* der;
380 size_t der_len;
381
382 der = _pem_to_der(secret, &der_len);
383
384 if (der != NULL) {
385 br_skey_decoder_context skey_ctx;
386 const br_rsa_private_key* skey;
387
388 br_skey_decoder_init(&skey_ctx);
389 br_skey_decoder_push(&skey_ctx, der, der_len);
390 skey = br_skey_decoder_get_rsa(&skey_ctx);
391
392 if (skey != NULL) {
393 unsigned char hash[32];
394 br_sha256_context sha_ctx;
395 size_t sig_len = (skey->n_bitlen + 7) / 8;
396 unsigned char* sig = xs_realloc(NULL, (int)sig_len);
397
398 br_sha256_init(&sha_ctx);
399 br_sha256_update(&sha_ctx, mem, size);
400 br_sha256_out(&sha_ctx, hash);
401
402 if (br_rsa_i31_pkcs1_sign(BR_HASH_OID_SHA256, hash, 32, skey, sig)) {
403 signature = xs_base64_enc((char*)sig, (int)sig_len);
404 }
405
406 xs_free(sig);
407 }
408
409 xs_free(der);
410 }
411
412 return signature;
413}
414
415int xs_evp_verify(const char* pubkey, const char* mem, int size, const char* b64_sig) {
416 unsigned char* der;
417 size_t der_len;
418
419 der = _pem_to_der(pubkey, &der_len);
420
421 int r = 0;
422 if (der != NULL) {
423 br_rsa_public_key pkey;
424
425 if (_parse_spki(der, der_len, &pkey)) {
426 int sig_len;
427 xs_val* sig = xs_base64_dec(b64_sig, &sig_len);
428
429 if (sig != NULL && sig_len > 0) {
430 unsigned char hash[32], hout[64];
431 br_sha256_context sha_ctx;
432
433 br_sha256_init(&sha_ctx);
434 br_sha256_update(&sha_ctx, mem, size);
435 br_sha256_out(&sha_ctx, hash);
436
437 if (br_rsa_i31_pkcs1_vrfy((const unsigned char*)sig, sig_len,
438 BR_HASH_OID_SHA256, 32, &pkey, hout)) {
439 r = (memcmp(hash, hout, 32) == 0);
440 }
441
442 xs_free(sig);
443 }
444 }
445
446 xs_free(der);
447 }
448
449 return r;
450}
451
452xs_dict* xs_evp_genkey(int bits) {
453 br_hmac_drbg_context drbg;
454 br_prng_seeder seeder;
455 unsigned char kbuf_priv[BR_RSA_KBUF_PRIV_SIZE(4096)];
456 unsigned char kbuf_pub[BR_RSA_KBUF_PUB_SIZE(4096)];
457 unsigned char dbuf[600];
458 br_rsa_private_key skey;
459 br_rsa_public_key pkey;
460 size_t d_len, der_len, pem_len;
461
462 br_hmac_drbg_init(&drbg, &br_sha256_vtable, NULL, 0);
463 seeder = br_prng_seeder_system(NULL);
464
465 if (seeder == NULL || !seeder((const br_prng_class**)&drbg)) { return NULL; }
466
467 if (!br_rsa_i31_keygen((const br_prng_class**)&drbg, &skey, kbuf_priv,
468 &pkey, kbuf_pub, (unsigned)bits, 65537)) { return NULL; }
469
470 d_len = br_rsa_i31_compute_privexp(dbuf, &skey, 65537);
471 if (d_len == 0) { return NULL; }
472
473 // private key
474 der_len = br_encode_rsa_pkcs8_der(NULL, &skey, &pkey, dbuf, d_len);
475 unsigned char* der = xs_realloc(NULL, (int)der_len);
476 br_encode_rsa_pkcs8_der(der, &skey, &pkey, dbuf, d_len);
477
478 pem_len = br_pem_encode(NULL, der, der_len, "PRIVATE KEY", 0);
479 xs* secret = xs_realloc(NULL, _xs_blk_size((int)pem_len + 1));
480 br_pem_encode(secret, der, der_len, "PRIVATE KEY", 0);
481 xs_free(der);
482
483 // public key
484 unsigned char* spki = xs_realloc(NULL, 2048);
485 der_len = _build_spki(spki, pkey.n, pkey.nlen, pkey.e, pkey.elen);
486
487 pem_len = br_pem_encode(NULL, spki, der_len, "PUBLIC KEY", 0);
488 xs* public = xs_realloc(NULL, _xs_blk_size((int)pem_len + 1));
489 br_pem_encode(public, spki, der_len, "PUBLIC KEY", 0);
490 xs_free(spki);
491
492 xs_dict* keypair = xs_dict_new();
493 keypair = xs_dict_append(keypair, "secret", secret);
494 keypair = xs_dict_append(keypair, "public", public);
495
496 return keypair;
497}
498
499#endif // XS_IMPLEMENTATION
500
501#endif // _XS_BEARSSL_H