1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
#include "jwt.h"
#include "base64.h"
#include <dynstr.h>
#include <cjson/cJSON.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include <openssl/sha.h>
#include <errno.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
static const char jwt_header[] = "{\"alg\": \"HS256\", \"typ\": \"JWT\"}";
static char *get_payload(const char *const name)
{
char *ret = NULL;
struct dynstr d;
dynstr_init(&d);
if (dynstr_append(&d, "{\"name\": \"%s\"}", name))
{
fprintf(stderr, "%s: dynstr_append name failed\n", __func__);
goto end;
}
else if (!(ret = base64_encode(d.str, d.len)))
{
fprintf(stderr, "%s: base64 failed\n", __func__);
goto end;
}
end:
dynstr_free(&d);
return ret;
}
static char *get_hmac(const void *const buf, const size_t n,
const void *const key, const size_t keyn)
{
unsigned char hmac[SHA256_DIGEST_LENGTH];
const EVP_MD *const md = EVP_sha256();
char *ret = NULL;
if (!md)
{
fprintf(stderr, "%s: EVP_sha256 failed\n", __func__);
return NULL;
}
else if (!HMAC(md, key, keyn, buf, n, hmac, NULL))
{
fprintf(stderr, "%s: HMAC failed\n", __func__);
return NULL;
}
else if (!(ret = base64_encode(hmac, sizeof hmac)))
{
fprintf(stderr, "%s: base64 failed\n", __func__);
return NULL;
}
return ret;
}
char *jwt_encode(const char *const name, const void *const key, const size_t n)
{
char *ret = NULL;
char *const header = base64_encode(jwt_header, strlen(jwt_header)),
*const payload = get_payload(name),
*hmac = NULL;
struct dynstr jwt;
dynstr_init(&jwt);
if (!header)
{
fprintf(stderr, "%s: base64_encode header failed\n", __func__);
goto end;
}
else if (!payload)
{
fprintf(stderr, "%s: get_payload failed\n", __func__);
goto end;
}
else if (dynstr_append(&jwt, "%s.%s", header, payload))
{
fprintf(stderr, "%s: dynstr_append header+payload failed", __func__);
goto end;
}
else if (!(hmac = get_hmac(jwt.str, jwt.len, key, n)))
{
fprintf(stderr, "%s: get_hmac failed\n", __func__);
goto end;
}
else if (dynstr_append(&jwt, ".%s", hmac))
{
fprintf(stderr, "%s: dynstr_append hmac failed\n", __func__);
goto end;
}
ret = jwt.str;
end:
free(header);
free(payload);
free(hmac);
if (!ret)
dynstr_free(&jwt);
return ret;
}
int jwt_check(const char *const jwt, const void *const key, const size_t n)
{
const char *const p = strrchr(jwt, '.');
const EVP_MD *const md = EVP_sha256();
unsigned char hmac[SHA256_DIGEST_LENGTH];
char *dhmac = NULL;
size_t hmaclen;
if (!md)
{
fprintf(stderr, "%s: EVP_sha256 failed\n", __func__);
return -1;
}
else if (!p)
{
fprintf(stderr, "%s: expected '.'\n", __func__);
return 1;
}
else if (!HMAC(md, key, n, (const unsigned char *)jwt, p - jwt, hmac, NULL))
{
fprintf(stderr, "%s: HMAC failed\n", __func__);
return -1;
}
else if (!(dhmac = base64_decode(p + 1, &hmaclen)))
{
fprintf(stderr, "%s: base64_decode failed\n", __func__);
return -1;
}
const int r = memcmp(dhmac, hmac, hmaclen);
free(dhmac);
return !!r;
}
|