commit 69d6496

V. Luna  ·  2026-10-08 06:04:41 +0000 UTC
parent eed9cd3
get 'er done
14 files changed,  +147, -272
M data.c
M html.c
M http.c
M main.c
M rss.c
M snac.c
+18, -15
 1@@ -6,18 +6,21 @@ all: snac
 2 
 3 snac: snac.o main.o sandbox.o data.o http.o httpd.o webfinger.o \
 4     activitypub.o html.o utils.o format.o upgrade.o mastoapi.o rss.o
 5-	$(CC) $(CFLAGS) -L$(PREFIX)/lib *.o -lcurl -lcrypto $(LDFLAGS) -pthread -o $@
 6+	$(CC) $(CFLAGS) -L$(PREFIX)/lib *.o -lcurl -lbearssl $(LDFLAGS) -pthread -o $@
 7 
 8-test: tests/b64_vectors
 9+test: tests/smtp tests/b64_vectors
10+
11+tests/smtp: tests/smtp.o
12+	$(CC) $(CFLAGS) -L$(PREFIX)/lib $< -lcurl -lbearssl $(LDFLAGS) -o $@
13 
14 tests/b64_vectors: tests/b64_vectors.o
15-	$(CC) $(CFLAGS) -L$(PREFIX)/lib -L/home/v/opt/bearssl/lib tests/b64_vectors.o -lbearssl $(LDFLAGS) -o $@
16+	$(CC) $(CFLAGS) -L$(PREFIX)/lib $< -lbearssl $(LDFLAGS) -o $@
17 
18 .c.o:
19-	$(CC) $(CFLAGS) $(CPPFLAGS) -I$(PREFIX)/include -I/home/v/opt/bearssl/include -c $< -o $@
20+	$(CC) $(CFLAGS) $(CPPFLAGS) -I$(PREFIX)/include -c $< -o $@
21 
22 clean:
23-	rm -rf *.o tests/*.o tests/b64_vectors *.core snac makefile.depend
24+	rm -rf *.o tests/*.o tests/smtp tests/b64_vectors *.core snac makefile.depend
25 
26 dep:
27 	$(CC) -I$(PREFIX)/include -MM *.c > makefile.depend
28@@ -57,36 +60,36 @@ update-po:
29 	done
30 
31 activitypub.o: activitypub.c xs.h xs_json.h xs_curl.h xs_url.h xs_mime.h \
32- xs_openssl.h xs_regex.h xs_time.h xs_set.h xs_match.h xs_unicode.h \
33+ xs_bearssl.h xs_regex.h xs_time.h xs_set.h xs_match.h xs_unicode.h \
34  xs_webmention.h xs_http.h xs_http_codes.h snac.h
35-data.o: data.c xs.h xs_hex.h xs_io.h xs_json.h xs_openssl.h xs_glob.h \
36+data.o: data.c xs.h xs_hex.h xs_io.h xs_json.h xs_bearssl.h xs_glob.h \
37  xs_set.h xs_time.h xs_regex.h xs_match.h xs_unicode.h xs_random.h \
38  xs_po.h xs_http.h xs_http_codes.h xs_list_tools.h xs_curl.h snac.h
39 format.o: format.c xs.h xs_regex.h xs_mime.h xs_html.h xs_json.h \
40  xs_time.h xs_match.h xs_unicode.h snac.h
41-html.o: html.c xs.h xs_io.h xs_json.h xs_regex.h xs_set.h xs_openssl.h \
42+html.o: html.c xs.h xs_io.h xs_json.h xs_regex.h xs_set.h xs_bearssl.h \
43  xs_time.h xs_mime.h xs_match.h xs_html.h xs_curl.h xs_unicode.h xs_url.h \
44  xs_random.h xs_http.h xs_http_codes.h xs_list_tools.h snac.h
45-http.o: http.c xs.h xs_io.h xs_openssl.h xs_curl.h xs_time.h xs_json.h \
46+http.o: http.c xs.h xs_io.h xs_bearssl.h xs_curl.h xs_time.h xs_json.h \
47  xs_http.h xs_http_codes.h snac.h
48 httpd.o: httpd.c xs.h xs_io.h xs_json.h xs_socket.h xs_unix_socket.h \
49- xs_http.h xs_http_codes.h xs_httpd.h xs_mime.h xs_time.h xs_openssl.h \
50+ xs_http.h xs_http_codes.h xs_httpd.h xs_mime.h xs_time.h xs_bearssl.h \
51  xs_fcgi.h xs_html.h xs_webmention.h snac.h
52-main.o: main.c xs.h xs_io.h xs_json.h xs_time.h xs_openssl.h xs_match.h \
53+main.o: main.c xs.h xs_io.h xs_json.h xs_time.h xs_bearssl.h xs_match.h \
54  xs_random.h xs_http.h xs_http_codes.h snac.h
55-mastoapi.o: mastoapi.c xs.h xs_hex.h xs_openssl.h xs_json.h xs_io.h \
56+mastoapi.o: mastoapi.c xs.h xs_hex.h xs_bearssl.h xs_json.h xs_io.h \
57  xs_time.h xs_glob.h xs_set.h xs_random.h xs_url.h xs_mime.h xs_match.h \
58  xs_unicode.h xs_http.h xs_http_codes.h snac.h
59 rss.o: rss.c xs.h xs_html.h xs_regex.h xs_time.h xs_match.h xs_curl.h \
60- xs_openssl.h xs_json.h xs_http.h xs_http_codes.h xs_unicode.h snac.h
61+ xs_bearssl.h xs_json.h xs_http.h xs_http_codes.h xs_unicode.h snac.h
62 sandbox.o: sandbox.c xs.h snac.h
63 snac.o: snac.c xs.h xs_hex.h xs_io.h xs_unicode_tbl.h xs_unicode.h \
64- xs_json.h xs_curl.h xs_openssl.h xs_socket.h xs_unix_socket.h xs_url.h \
65+ xs_json.h xs_curl.h xs_bearssl.h xs_socket.h xs_unix_socket.h xs_url.h \
66  xs_http.h xs_http_codes.h xs_httpd.h xs_mime.h xs_regex.h xs_set.h \
67  xs_time.h xs_glob.h xs_random.h xs_match.h xs_fcgi.h xs_html.h xs_po.h \
68  xs_webmention.h xs_list_tools.h snac.h
69 upgrade.o: upgrade.c xs.h xs_io.h xs_json.h xs_glob.h snac.h
70-utils.o: utils.c xs.h xs_io.h xs_json.h xs_time.h xs_openssl.h \
71+utils.o: utils.c xs.h xs_io.h xs_json.h xs_time.h xs_bearssl.h \
72  xs_random.h xs_glob.h xs_curl.h xs_regex.h xs_http.h xs_http_codes.h \
73  xs_list_tools.h xs_set.h snac.h
74 webfinger.o: webfinger.c xs.h xs_json.h xs_curl.h xs_mime.h xs_http.h \
+1, -1
1@@ -6,7 +6,7 @@
2 #include "xs_curl.h"
3 #include "xs_url.h"
4 #include "xs_mime.h"
5-#include "xs_openssl.h"
6+#include "xs_bearssl.h"
7 #include "xs_regex.h"
8 #include "xs_time.h"
9 #include "xs_set.h"
M data.c
+1, -1
1@@ -5,7 +5,7 @@
2 #include "xs_hex.h"
3 #include "xs_io.h"
4 #include "xs_json.h"
5-#include "xs_openssl.h"
6+#include "xs_bearssl.h"
7 #include "xs_glob.h"
8 #include "xs_set.h"
9 #include "xs_time.h"
M html.c
+1, -1
1@@ -6,7 +6,7 @@
2 #include "xs_json.h"
3 #include "xs_regex.h"
4 #include "xs_set.h"
5-#include "xs_openssl.h"
6+#include "xs_bearssl.h"
7 #include "xs_time.h"
8 #include "xs_mime.h"
9 #include "xs_match.h"
M http.c
+1, -1
1@@ -3,7 +3,7 @@
2 
3 #include "xs.h"
4 #include "xs_io.h"
5-#include "xs_openssl.h"
6+#include "xs_bearssl.h"
7 #include "xs_curl.h"
8 #include "xs_time.h"
9 #include "xs_json.h"
+1, -1
1@@ -10,7 +10,7 @@
2 #include "xs_httpd.h"
3 #include "xs_mime.h"
4 #include "xs_time.h"
5-#include "xs_openssl.h"
6+#include "xs_bearssl.h"
7 #include "xs_fcgi.h"
8 #include "xs_html.h"
9 #include "xs_webmention.h"
M main.c
+1, -1
1@@ -5,7 +5,7 @@
2 #include "xs_io.h"
3 #include "xs_json.h"
4 #include "xs_time.h"
5-#include "xs_openssl.h"
6+#include "xs_bearssl.h"
7 #include "xs_match.h"
8 #include "xs_random.h"
9 #include "xs_http.h"
+1, -1
1@@ -5,7 +5,7 @@
2 
3 #include "xs.h"
4 #include "xs_hex.h"
5-#include "xs_openssl.h"
6+#include "xs_bearssl.h"
7 #include "xs_json.h"
8 #include "xs_io.h"
9 #include "xs_time.h"
M rss.c
+1, -1
1@@ -7,7 +7,7 @@
2 #include "xs_time.h"
3 #include "xs_match.h"
4 #include "xs_curl.h"
5-#include "xs_openssl.h"
6+#include "xs_bearssl.h"
7 #include "xs_json.h"
8 #include "xs_http.h"
9 #include "xs_unicode.h"
M snac.c
+1, -1
1@@ -12,7 +12,7 @@
2 #include "xs_unicode.h"
3 #include "xs_json.h"
4 #include "xs_curl.h"
5-#include "xs_openssl.h"
6+#include "xs_bearssl.h"
7 #include "xs_socket.h"
8 #include "xs_unix_socket.h"
9 #include "xs_url.h"
+24, -0
 1@@ -0,0 +1,24 @@
 2+/* snac - A simple, minimalistic ActivityPub instance */
 3+/* copyright (c) 2022 - 2025 grunfink et al. / MIT license */
 4+
 5+#define XS_IMPLEMENTATION
 6+#include "../xs.h"
 7+#include "../xs_curl.h"
 8+
 9+#define FROM "<snac-smtp-test@locahost>"
10+
11+int main(void) {
12+    xs *to   = xs_fmt("<%s@localhost>", getenv("USER")),
13+       *body = xs_fmt(""
14+        "To: %s \r\n"
15+        "From: " FROM "\r\n"
16+        "Subject: snac smtp test\r\n"
17+        "\r\n"
18+        "If you read this as an email, it probably worked!\r\n",
19+        to);
20+
21+    return xs_smtp_request("smtp://localhost", NULL, NULL, 
22+        FROM,
23+        to,
24+        body, 0);
25+}
+1, -1
1@@ -5,7 +5,7 @@
2 #include "xs_io.h"
3 #include "xs_json.h"
4 #include "xs_time.h"
5-#include "xs_openssl.h"
6+#include "xs_bearssl.h"
7 #include "xs_random.h"
8 #include "xs_glob.h"
9 #include "xs_curl.h"
+95, -2
  1@@ -28,6 +28,7 @@ int xs_evp_verify(const char* pubkey, const char* mem, int size, const char* b64
  2 #include "bearssl_x509.h"
  3 #include "bearssl_hash.h"
  4 #include "bearssl_pem.h"
  5+#include "bearssl_rand.h"
  6 #include "bearssl_rsa.h"
  7 
  8 #ifndef _XS_BASE64_H
  9@@ -309,6 +310,29 @@ static size_t _der_uint(unsigned char *dst, const unsigned char *v, size_t len)
 10         return _der_put(dst, 0x02, tmp, clen);
 11 }
 12 
 13+static size_t _build_spki(unsigned char* dst, const unsigned char* n, size_t n_len, const unsigned char* e, size_t e_len) {
 14+        static const unsigned char alg_id[] = {
 15+                0x30, 0x0d,
 16+                0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
 17+                0x05, 0x00
 18+        };
 19+        unsigned char rsa_pub[1024], rsa_seq[1100], bit_content[1200], bit_str[1300], content[1400];
 20+        size_t rsa_len = 0, seq_len, bit_len;
 21+
 22+        rsa_len += _der_uint(rsa_pub + rsa_len, n, n_len);
 23+        rsa_len += _der_uint(rsa_pub + rsa_len, e, e_len);
 24+        seq_len = _der_put(rsa_seq, 0x30, rsa_pub, rsa_len);
 25+
 26+        bit_content[0] = 0x00;
 27+        memcpy(bit_content + 1, rsa_seq, seq_len);
 28+        bit_len = _der_put(bit_str, 0x03, bit_content, seq_len + 1);
 29+
 30+        memcpy(content, alg_id, sizeof(alg_id));
 31+        memcpy(content + sizeof(alg_id), bit_str, bit_len);
 32+
 33+        return _der_put(dst, 0x30, content, sizeof(alg_id) + bit_len);
 34+}
 35+
 36 static int _parse_spki(const unsigned char* der, size_t len, br_rsa_public_key* pk) {
 37         const unsigned char* cur = der, *end = der + len;
 38         const unsigned char* val;
 39@@ -397,10 +421,79 @@ int xs_evp_verify(const char* pubkey, const char* mem, int size, const char* b64
 40         int r = 0;
 41         if (der != NULL) {
 42                 br_rsa_public_key pkey;
 43+
 44+                if (_parse_spki(der, der_len, &pkey)) {
 45+                        int sig_len;
 46+                        xs_val* sig = xs_base64_dec(b64_sig, &sig_len);
 47+
 48+                        if (sig != NULL && sig_len > 0) {
 49+                                unsigned char hash[32], hout[64];
 50+                                br_sha256_context sha_ctx;
 51+
 52+                                br_sha256_init(&sha_ctx);
 53+                                br_sha256_update(&sha_ctx, mem, size);
 54+                                br_sha256_out(&sha_ctx, hash);
 55+
 56+                                if (br_rsa_i31_pkcs1_vrfy((const unsigned char*)sig, sig_len,
 57+                                        BR_HASH_OID_SHA256, 32, &pkey, hout)) {
 58+                                        r = (memcmp(hash, hout, 32) == 0);
 59+                                }
 60+
 61+                                xs_free(sig);
 62+                        }
 63+                }
 64+
 65+                xs_free(der);
 66         }
 67 
 68-        // TODO: 
 69-        return 0;
 70+        return r;
 71+}
 72+
 73+xs_dict* xs_evp_genkey(int bits) {
 74+        br_hmac_drbg_context drbg;
 75+        br_prng_seeder seeder;
 76+        unsigned char kbuf_priv[BR_RSA_KBUF_PRIV_SIZE(4096)];
 77+        unsigned char kbuf_pub[BR_RSA_KBUF_PUB_SIZE(4096)];
 78+        unsigned char dbuf[600];
 79+        br_rsa_private_key skey;
 80+        br_rsa_public_key pkey;
 81+        size_t d_len, der_len, pem_len;
 82+
 83+        br_hmac_drbg_init(&drbg, &br_sha256_vtable, NULL, 0);
 84+        seeder = br_prng_seeder_system(NULL);
 85+
 86+        if (seeder == NULL || !seeder((const br_prng_class**)&drbg)) { return NULL; }
 87+
 88+        if (!br_rsa_i31_keygen((const br_prng_class**)&drbg, &skey, kbuf_priv,
 89+                &pkey, kbuf_pub, (unsigned)bits, 65537)) { return NULL; }
 90+
 91+        d_len = br_rsa_i31_compute_privexp(dbuf, &skey, 65537);
 92+        if (d_len == 0) { return NULL; }
 93+
 94+        // private key
 95+        der_len = br_encode_rsa_pkcs8_der(NULL, &skey, &pkey, dbuf, d_len);
 96+        unsigned char* der = xs_realloc(NULL, (int)der_len);
 97+        br_encode_rsa_pkcs8_der(der, &skey, &pkey, dbuf, d_len);
 98+
 99+        pem_len = br_pem_encode(NULL, der, der_len, "PRIVATE KEY", 0);
100+        xs* secret = xs_realloc(NULL, _xs_blk_size((int)pem_len + 1));
101+        br_pem_encode(secret, der, der_len, "PRIVATE KEY", 0);
102+        xs_free(der);
103+
104+        // public key
105+        unsigned char* spki = xs_realloc(NULL, 2048);
106+        der_len = _build_spki(spki, pkey.n, pkey.nlen, pkey.e, pkey.elen);
107+
108+        pem_len = br_pem_encode(NULL, spki, der_len, "PUBLIC KEY", 0);
109+        xs* public = xs_realloc(NULL, _xs_blk_size((int)pem_len + 1));
110+        br_pem_encode(public, spki, der_len, "PUBLIC KEY", 0);
111+        xs_free(spki);
112+
113+        xs_dict* keypair = xs_dict_new();
114+        keypair = xs_dict_append(keypair, "secret", secret);
115+        keypair = xs_dict_append(keypair, "public", public);
116+
117+        return keypair;
118 }
119 
120 #endif // XS_IMPLEMENTATION
+0, -245
  1@@ -1,245 +0,0 @@
  2-/* copyright (c) 2022 - 2026 grunfink et al. / MIT license */
  3-//
  4-// #ifndef _XS_OPENSSL_H
  5-//
  6-// #define _XS_OPENSSL_H
  7-//
  8-// #include "xs.h"
  9-// #include "xs_hex.h"
 10-//
 11-// xs_str *_xs_digest(const xs_val *input, int size, const char *digest, int as_hex);
 12-//
 13-// #ifndef _XS_MD5_H
 14-// #define xs_md5_hex(input, size)       _xs_digest(input, size, "md5",    1)
 15-// #endif /* XS_MD5_H */
 16-//
 17-// #ifndef _XS_BASE64_H
 18-// xs_str *xs_base64_enc(const xs_val *data, int sz);
 19-// xs_val *xs_base64_dec(const xs_str *data, int *size);
 20-// #endif /* XS_BASE64_H */
 21-//
 22-// #define xs_sha1_hex(input, size)      _xs_digest(input, size, "sha1",   1)
 23-// #define xs_sha256_hex(input, size)    _xs_digest(input, size, "sha256", 1)
 24-// #define xs_sha256_base64(input, size) _xs_digest(input, size, "sha256", 0)
 25-//
 26-// xs_dict *xs_evp_genkey(int bits);
 27-// xs_str *xs_evp_sign(const char *secret, const char *mem, int size);
 28-// int xs_evp_verify(const char *pubkey, const char *mem, int size, const char *b64sig);
 29-//
 30-//
 31-// #ifdef XS_IMPLEMENTATION
 32-//
 33-// #include "openssl/rsa.h"
 34-// #include "openssl/pem.h"
 35-// #include "openssl/evp.h"
 36-//
 37-//
 38-// #ifndef _XS_BASE64_H
 39-//
 40-// xs_str *xs_base64_enc(const xs_val *data, int sz)
 41-// /* encodes data to base64 */
 42-// {
 43-//     BIO *mem, *b64;
 44-//     BUF_MEM *bptr;
 45-//
 46-//     b64 = BIO_new(BIO_f_base64());
 47-//     mem = BIO_new(BIO_s_mem());
 48-//     b64 = BIO_push(b64, mem);
 49-//
 50-//     BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
 51-//
 52-//     BIO_write(b64, data, sz);
 53-//     BIO_flush(b64);
 54-//     BIO_get_mem_ptr(b64, &bptr);
 55-//
 56-//     int n = bptr->length;
 57-//     xs_str *s = xs_realloc(NULL, _xs_blk_size(n + 1));
 58-//
 59-//     memcpy(s, bptr->data, n);
 60-//     s[n] = '\0';
 61-//
 62-//     BIO_free_all(b64);
 63-//
 64-//     return s;
 65-// }
 66-//
 67-//
 68-// xs_val *xs_base64_dec(const xs_str *data, int *size)
 69-// /* decodes data from base64 */
 70-// {
 71-//     BIO *b64, *mem;
 72-//
 73-//     *size = strlen(data);
 74-//
 75-//     b64 = BIO_new(BIO_f_base64());
 76-//     mem = BIO_new_mem_buf(data, *size);
 77-//     b64 = BIO_push(b64, mem);
 78-//
 79-//     BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
 80-//
 81-//     /* alloc a very big buffer */
 82-//     xs_str *s = xs_realloc(NULL, *size);
 83-//
 84-//     *size = BIO_read(b64, s, *size);
 85-//
 86-//     /* adjust to current size */
 87-//     s = xs_realloc(s, _xs_blk_size(*size + 1));
 88-//     s[*size] = '\0';
 89-//
 90-//     BIO_free_all(b64);
 91-//
 92-//     return s;
 93-// }
 94-//
 95-// #endif /* _XS_BASE64_H */
 96-//
 97-//
 98-// xs_str *_xs_digest(const xs_val *input, int size, const char *digest, int as_hex)
 99-// /* generic function for generating and encoding digests */
100-// {
101-//     const EVP_MD *md;
102-//
103-//     if ((md = EVP_get_digestbyname(digest)) == NULL)
104-//         return NULL;
105-//
106-//     unsigned char output[1024];
107-//     unsigned int out_size;
108-//     EVP_MD_CTX *mdctx;
109-//
110-//     mdctx = EVP_MD_CTX_new();
111-//     EVP_DigestInit_ex(mdctx, md, NULL);
112-//     EVP_DigestUpdate(mdctx, input, size);
113-//     EVP_DigestFinal_ex(mdctx, output, &out_size);
114-//     EVP_MD_CTX_free(mdctx);
115-//
116-//     return as_hex ? xs_hex_enc   ((char *)output, out_size) :
117-//                     xs_base64_enc((char *)output, out_size);
118-// }
119-//
120-//
121-// xs_dict *xs_evp_genkey(int bits)
122-// /* generates an RSA keypair using the EVP interface */
123-// {
124-//     xs_dict *keypair = NULL;
125-//     EVP_PKEY_CTX *ctx = NULL;
126-//     EVP_PKEY *pkey = NULL;
127-//
128-//     if ((ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL)) == NULL)
129-//         return NULL;
130-//
131-//     if (EVP_PKEY_keygen_init(ctx) <= 0 ||
132-//         EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, bits) <= 0 ||
133-//         EVP_PKEY_keygen(ctx, &pkey) <= 0)
134-//         return NULL;
135-//
136-//     BIO *bs = BIO_new(BIO_s_mem());
137-//     BIO *bp = BIO_new(BIO_s_mem());
138-//     BUF_MEM *sptr;
139-//     BUF_MEM *pptr;
140-//
141-//     PEM_write_bio_PrivateKey(bs, pkey, NULL, NULL, 0, 0, NULL);
142-//     BIO_get_mem_ptr(bs, &sptr);
143-//
144-//     PEM_write_bio_PUBKEY(bp, pkey);
145-//     BIO_get_mem_ptr(bp, &pptr);
146-//
147-//     keypair = xs_dict_new();
148-//
149-//     xs *secret = xs_str_new_sz(sptr->data, sptr->length);
150-//     xs *public = xs_str_new_sz(pptr->data, pptr->length);
151-//     keypair = xs_dict_append(keypair, "secret", secret);
152-//     keypair = xs_dict_append(keypair, "public", public);
153-//
154-//     BIO_free(bs);
155-//     BIO_free(bp);
156-//
157-//     EVP_PKEY_free(pkey);
158-//     EVP_PKEY_CTX_free(ctx);
159-//
160-//     return keypair;
161-// }
162-//
163-//
164-// xs_str *xs_evp_sign(const char *secret, const char *mem, int size)
165-// /* signs a memory block (secret is in PEM format) */
166-// {
167-//     xs_str *signature = NULL;
168-//     BIO *b;
169-//     unsigned char *sig;
170-//     unsigned int sig_len;
171-//     EVP_PKEY *pkey;
172-//     EVP_MD_CTX *mdctx;
173-//     const EVP_MD *md;
174-//
175-//     /* un-PEM the key */
176-//     b = BIO_new_mem_buf(secret, strlen(secret));
177-//     pkey = PEM_read_bio_PrivateKey(b, NULL, NULL, NULL);
178-//
179-//     /* I've learnt all these magical incantations by watching
180-//        the Python module code and the OpenSSL manual pages */
181-//     /* Well, "learnt" may be an overstatement */
182-//
183-//     md = EVP_get_digestbyname("sha256");
184-//
185-//     mdctx = EVP_MD_CTX_new();
186-//
187-//     sig_len = EVP_PKEY_size(pkey);
188-//     sig = xs_realloc(NULL, sig_len);
189-//
190-//     EVP_SignInit(mdctx, md);
191-//     EVP_SignUpdate(mdctx, mem, size);
192-//
193-//     if (EVP_SignFinal(mdctx, sig, &sig_len, pkey) == 1)
194-//         signature = xs_base64_enc((char *)sig, sig_len);
195-//
196-//     EVP_MD_CTX_free(mdctx);
197-//     EVP_PKEY_free(pkey);
198-//     BIO_free(b);
199-//     xs_free(sig);
200-//
201-//     return signature;
202-// }
203-//
204-//
205-// int xs_evp_verify(const char *pubkey, const char *mem, int size, const char *b64sig)
206-// /* verifies a base64 block, returns non-zero on ok */
207-// {
208-//     int r = 0;
209-//     BIO *b;
210-//     EVP_PKEY *pkey;
211-//     EVP_MD_CTX *mdctx;
212-//     const EVP_MD *md;
213-//
214-//     /* un-PEM the key */
215-//     b = BIO_new_mem_buf(pubkey, strlen(pubkey));
216-//     pkey = PEM_read_bio_PUBKEY(b, NULL, NULL, NULL);
217-//
218-//     md = EVP_get_digestbyname("sha256");
219-//     mdctx = EVP_MD_CTX_new();
220-//
221-//     if (pkey != NULL) {
222-//         xs *sig = NULL;
223-//         int s_size;
224-//
225-//         /* de-base64 */
226-//         sig = xs_base64_dec(b64sig,  &s_size);
227-//
228-//         if (sig != NULL) {
229-//             EVP_VerifyInit(mdctx, md);
230-//             EVP_VerifyUpdate(mdctx, mem, size);
231-//
232-//             r = EVP_VerifyFinal(mdctx, (unsigned char *)sig, s_size, pkey);
233-//         }
234-//     }
235-//
236-//     EVP_MD_CTX_free(mdctx);
237-//     EVP_PKEY_free(pkey);
238-//     BIO_free(b);
239-//
240-//     return r;
241-// }
242-//
243-//
244-// #endif /* XS_IMPLEMENTATION */
245-//
246-// #endif /* _XS_OPENSSL_H */