XRootD
Loading...
Searching...
No Matches
XrdSecztn.cc
Go to the documentation of this file.
1// Copyright (c) 2015 Erwin Jansen
2//
3// MIT License
4//
5// Permission is hereby granted, free of charge, to any person obtaining
6// a copy of this software and associated documentation files (the
7// "Software"), to deal in the Software without restriction, including
8// without limitation the rights to use, copy, modify, merge, publish,
9// distribute, sublicense, and/or sell copies of the Software, and to
10// permit persons to whom the Software is furnished to do so, subject to
11// the following conditions:
12//
13// The above copyright notice and this permission notice shall be
14// included in all copies or substantial portions of the Software.
15//
16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24// Note: the code in the anonymous namespace came from Erwin Jansen but was
25// heavily edited to solve this particular problem. For more info see:
26// https://github.com/pokowaka/jwt-cpp
27
28#include <cstdint>
29#include <cstdlib>
30#include <cstring>
31#include <limits>
32
33#ifndef __FreeBSD__
34#include <alloca.h>
35#endif
36
37#define WHITESPACE 64
38#define EQUALS 65
39#define INVALID 66
40
41/******************************************************************************/
42/* L o c a l F u n c t i o n s */
43/******************************************************************************/
44
45namespace
46{
47 const char b64Table[] = {
48 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
49 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
50 66, 66, 66, 66, 66, 66, 66, 62, 66, 62, 66, 63, 52, 53, 54, 55, 56, 57,
51 58, 59, 60, 61, 66, 66, 66, 66, 66, 66, 66, 0, 1, 2, 3, 4, 5, 6,
52 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
53 25, 66, 66, 66, 66, 63, 66, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
54 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 66, 66, 66,
55 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
56 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
57 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
58 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
59 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
60 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
61 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66,
62 66, 66, 66, 66};
63
64/******************************************************************************/
65/* D e c o d e B y t e s N e e d e d */
66/******************************************************************************/
67
74 size_t DecodeBytesNeeded(size_t num_decode) {
75 return 3 + (num_decode / 4) * 3;
76 }
77
78/******************************************************************************/
79/* D e c o d e U r l */
80/******************************************************************************/
81
82int DecodeUrl(const char *decode, size_t num_decode, char *out, size_t &num_out)
83{
84 // No integer overflows please.
85 if (num_decode > std::numeric_limits<size_t>::max() - (size_t)decode)
86 return 1;
87
88 if (num_out > std::numeric_limits<size_t>::max() - (size_t)out)
89 return 1;
90
91 if (num_out < DecodeBytesNeeded(num_decode))
92 return 1;
93
94 const char *end = decode + num_decode;
95 const char *out_start = out;
96 char iter = 0;
97 uint32_t buf = 0;
98 uint8_t ch;
99 char c;
100
101 while (decode < end) {
102 ch = *decode++;
103 c = b64Table[ch];
104
105 switch (c) {
106 case INVALID:
107 return 1; // invalid input, return error
108 default:
109 buf = buf << 6 | c;
110 iter++; // increment the number of iteration
111 // If the buffer is full, split it into bytes
112 if (iter == 4) {
113 *(out++) = (buf >> 16) & 0xff;
114 *(out++) = (buf >> 8) & 0xff;
115 *(out++) = buf & 0xff;
116 buf = 0;
117 iter = 0;
118 }
119 }
120 }
121
122 if (iter == 3) {
123 *(out++) = (buf >> 10) & 0xff;
124 *(out++) = (buf >> 2) & 0xff;
125 } else {
126 if (iter == 2) {
127 *(out++) = (buf >> 4) & 0xff;
128 }
129 }
130
131 num_out = (out - out_start); // modify to reflect the actual output size
132 return 0;
133}
134}
135
136/******************************************************************************/
137/* X r d S e c z t n : : i s J W T */
138/******************************************************************************/
139
140namespace XrdSecztn
141{
142bool isJWT(const char *b64data)
143{
144 size_t inBytes, outBytes;
145 const char *dot;
146 char *key, *outData, inData[1024];
147
148// Skip over the header should it exist (sommetime it does sometimes not)
149//
150 if (!strncmp(b64data, "Bearer%20", 9)) b64data += 9;
151
152// We are only interested in the header which must appear first and be
153// separated by a dot from subsequent tokens. If it does not have the
154// dot then we assume it's not returnable. Otherwise truncate it at the dot.
155//
156 if (!(dot = index(b64data, '.'))) return false;
157
158// Copy out the token segment we wish to check. The JWT header can never be
159// more than 1K long and that's being way generous.
160//
161 inBytes = dot - b64data;
162 if (inBytes >= (int)sizeof(inData)) return false;
163 memcpy(inData, b64data, inBytes);
164 inData[inBytes] = 0;
165
166// Allocate a buffer large enough to hold the result. Get it from the stack.
167//
168 outBytes = DecodeBytesNeeded(inBytes);
169 outData = (char *)alloca(outBytes);
170
171// If we can't decode what we have then indicate this is not returnable
172//
173 if (DecodeUrl(inData, inBytes, outData, outBytes)) return false;
174
175// The json object must start/end with a brace and must contain the key:value
176// of '"typ":"JWT"', other elements may change but not this one.
177//
178 if (outBytes <= 0 || *outData != '{' || outData[outBytes-1] != '}')
179 return false;
180
181// Search for the key
182//
183 if (!(key = strstr(outData, "\"typ\""))) return false;
184
185// Subsequently there should be a colon or spaces but nothing more
186//
187 key += 5;
188 while(*key == ' ') key++;
189 if (*key != ':') return false;
190
191// There may be more spaces but anything else must be the expected value
192//
193 key++;
194 while(*key == ' ') key++;
195 return strncmp(key, "\"JWT\"", 5) == 0;
196}
197}
#define INVALID
Definition XrdSecztn.cc:39
bool isJWT(const char *)
Definition XrdSecztn.cc:142