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