commit 69d6496
V. Luna
·
2026-10-08 06:04:41 +0000 UTC
parent eed9cd3
get 'er done
14 files changed,
+147,
-272
M
Makefile
+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"
M
httpd.c
+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+}
M
utils.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_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 */