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