1 /* Copyright (C) 2019 Jeremy Thien <jeremy.thien@gmail.com>
2 This file is part of the JWT C Library
3
4 This Source Code Form is subject to the terms of the Mozilla Public
5 License, v. 2.0. If a copy of the MPL was not distributed with this
6 file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <jwt.h>
11 #include <getopt.h>
12 #include <string.h>
13 #include <errno.h>
14 #include <time.h>
15 #include <libgen.h>
16
usage(const char * name)17 void usage(const char *name)
18 {
19 /* TODO Might want to support JWT input via stdin */
20 printf("%s --key some-pub.pem --alg RS256 some-file.jwt\n", name);
21 printf("Options:\n"
22 " -k --key KEY The key to use for verification\n"
23 " -a --alg ALG The algorithm to use for verification\n"
24 " -c --claim KEY=VALUE Verify JWT has claim KEY with VALUE\n");
25 exit(0);
26 }
27
main(int argc,char * argv[])28 int main(int argc, char *argv[])
29 {
30 int exit_status = 0;
31 char opt_key_name[200] = "test-rsa256-pub.pem";
32 jwt_alg_t opt_alg = JWT_ALG_RS256;
33 char opt_jwt_name[200] = "test-rsa256.jwt";
34 int claims_count = 0;
35 int i = 0;
36 unsigned char key[10240];
37 size_t key_len;
38 FILE *fp_pub_key;
39 char jwt_str[2048];
40 size_t jwt_len;
41 FILE *fp_jwt;
42 int ret = 0;
43 jwt_valid_t *jwt_valid;
44 jwt_t *jwt = NULL;
45 int oc = 0;
46 char *optstr = "hk:a:c:";
47 struct option opttbl[] = {
48 { "help", no_argument, NULL, 'h' },
49 { "key", required_argument, NULL, 'k' },
50 { "alg", required_argument, NULL, 'a' },
51 { "claim", required_argument, NULL, 'c' },
52 { NULL, 0, 0, 0 },
53 };
54 char *k = NULL, *v = NULL;
55 struct kv {
56 char *key;
57 char *val;
58 } opt_claims[100];
59 memset(opt_claims, 0, sizeof(opt_claims));
60
61
62 while ((oc = getopt_long(argc, argv, optstr, opttbl, NULL)) != -1) {
63 switch (oc) {
64 case 'k':
65 strncpy(opt_key_name, optarg, sizeof(opt_key_name));
66 opt_key_name[sizeof(opt_key_name) - 1] = '\0';
67 break;
68
69 case 'a':
70 opt_alg = jwt_str_alg(optarg);
71 if (opt_alg == JWT_ALG_INVAL) {
72 fprintf(stderr, "%s is not supported algorithm, using RS256\n", optarg);
73 opt_alg = JWT_ALG_RS256;
74 }
75 break;
76
77 case 'c':
78 k = strtok(optarg, "=");
79 if (k) {
80 v = strtok(NULL, "=");
81 if (v) {
82 opt_claims[claims_count].key = strdup(k);
83 opt_claims[claims_count].val = strdup(v);
84 claims_count++;
85 }
86 }
87 break;
88
89 case 'h':
90 usage(basename(argv[0]));
91 return 0;
92
93 default: /* '?' */
94 usage(basename(argv[0]));
95 exit(EXIT_FAILURE);
96 }
97 }
98
99
100 if (optind == argc) {
101 fprintf(stderr, "Please provide name of jwt file\n");
102 exit(EXIT_FAILURE);
103 }
104 strncpy(opt_jwt_name, argv[optind], sizeof(opt_jwt_name) - 1);
105 opt_jwt_name[sizeof(opt_jwt_name) - 1] = '\0';
106
107 fprintf(stderr, "jwt verification: jwt %s pubkey %s algorithm %s\n",
108 opt_jwt_name, opt_key_name, jwt_alg_str(opt_alg));
109
110 /* Load pub key */
111 fp_pub_key = fopen(opt_key_name, "r");
112 key_len = fread(key, 1, sizeof(key), fp_pub_key);
113 fclose(fp_pub_key);
114 key[key_len] = '\0';
115 fprintf(stderr, "pub key loaded %s (%zu)!\n", opt_key_name, key_len);
116
117 /* Load jwt */
118 fp_jwt = fopen(opt_jwt_name, "r");
119 jwt_len = fread(jwt_str, 1, sizeof(jwt_str), fp_jwt);
120 fclose(fp_jwt);
121 jwt_str[jwt_len] = '\0';
122 fprintf(stderr, "jwt loaded %s (%zu)!\n", opt_jwt_name, jwt_len);
123
124 /* Setup validation */
125 ret = jwt_valid_new(&jwt_valid, opt_alg);
126 if (ret != 0 || jwt_valid == NULL) {
127 fprintf(stderr, "failed to allocate jwt_valid\n");
128 goto finish_valid;
129 }
130
131 jwt_valid_set_headers(jwt_valid, 1);
132 jwt_valid_set_now(jwt_valid, time(NULL));
133 for (i = 0; i < claims_count; i++) {
134 jwt_valid_add_grant(jwt_valid, opt_claims[i].key, opt_claims[i].val);
135 }
136
137 /* Decode jwt */
138 ret = jwt_decode(&jwt, jwt_str, key, key_len);
139 if (ret != 0 || jwt == NULL) {
140 fprintf(stderr, "invalid jwt\n");
141 exit_status = 1;
142 goto finish;
143 }
144
145 fprintf(stderr, "jwt decoded successfully!\n");
146
147 /* Validate jwt */
148 if (jwt_validate(jwt, jwt_valid) != 0) {
149 fprintf(stderr, "jwt failed to validate: %08x\n", jwt_valid_get_status(jwt_valid));
150 jwt_dump_fp(jwt, stderr, 1);
151 exit_status = 1;
152 goto finish;
153 }
154
155 fprintf(stderr, "JWT is authentic! sub: %s\n", jwt_get_grant(jwt, "sub"));
156
157 jwt_dump_fp(jwt, stdout, 1);
158
159 finish:
160 jwt_free(jwt);
161 finish_valid:
162 jwt_valid_free(jwt_valid);
163
164 return exit_status;
165 }
166
167