Make encode and validate take similar options
parent
c3d434f588
commit
b8267a940b
28
jwt.zig
28
jwt.zig
|
@ -21,13 +21,13 @@ const JWTType = enum {
|
||||||
JWE,
|
JWE,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const HeaderOptions = struct {
|
pub const SignatureOptions = struct {
|
||||||
alg: Algorithm,
|
alg: Algorithm,
|
||||||
key: []const u8,
|
key: []const u8,
|
||||||
kid: ?[]const u8 = null,
|
kid: ?[]const u8 = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn encode(allocator: *std.mem.Allocator, payload: anytype, headerOptions: HeaderOptions) ![]const u8 {
|
pub fn encode(allocator: *std.mem.Allocator, payload: anytype, signatureOptions: SignatureOptions) ![]const u8 {
|
||||||
var payload_json = std.ArrayList(u8).init(allocator);
|
var payload_json = std.ArrayList(u8).init(allocator);
|
||||||
defer payload_json.deinit();
|
defer payload_json.deinit();
|
||||||
|
|
||||||
|
@ -35,9 +35,9 @@ pub fn encode(allocator: *std.mem.Allocator, payload: anytype, headerOptions: He
|
||||||
|
|
||||||
var protected_header = std.json.ObjectMap.init(allocator);
|
var protected_header = std.json.ObjectMap.init(allocator);
|
||||||
defer protected_header.deinit();
|
defer protected_header.deinit();
|
||||||
try protected_header.put("alg", .{ .String = std.meta.tagName(headerOptions.alg) });
|
try protected_header.put("alg", .{ .String = std.meta.tagName(signatureOptions.alg) });
|
||||||
try protected_header.put("typ", .{ .String = "JWT" });
|
try protected_header.put("typ", .{ .String = "JWT" });
|
||||||
if (headerOptions.kid) |kid| {
|
if (signatureOptions.kid) |kid| {
|
||||||
try protected_header.put("kid", .{ .String = kid });
|
try protected_header.put("kid", .{ .String = kid });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,9 +60,9 @@ pub fn encode(allocator: *std.mem.Allocator, payload: anytype, headerOptions: He
|
||||||
jwt_text.items[protected_header_base64_len] = '.';
|
jwt_text.items[protected_header_base64_len] = '.';
|
||||||
_ = base64url.Encoder.encode(payload_base64, payload_json.items);
|
_ = base64url.Encoder.encode(payload_base64, payload_json.items);
|
||||||
|
|
||||||
switch (headerOptions.alg) {
|
switch (signatureOptions.alg) {
|
||||||
.HS256 => {
|
.HS256 => {
|
||||||
const signature = generate_signature_hmac_sha256(headerOptions.key, protected_header_base64, payload_base64);
|
const signature = generate_signature_hmac_sha256(signatureOptions.key, protected_header_base64, payload_base64);
|
||||||
const signature_base64_len = base64url.Encoder.calcSize(signature.len);
|
const signature_base64_len = base64url.Encoder.calcSize(signature.len);
|
||||||
|
|
||||||
try jwt_text.resize(payload_base64_len + 1 + protected_header_base64_len + 1 + signature_base64_len);
|
try jwt_text.resize(payload_base64_len + 1 + protected_header_base64_len + 1 + signature_base64_len);
|
||||||
|
@ -76,7 +76,7 @@ pub fn encode(allocator: *std.mem.Allocator, payload: anytype, headerOptions: He
|
||||||
return jwt_text.toOwnedSlice();
|
return jwt_text.toOwnedSlice();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validate(allocator: *std.mem.Allocator, algorithm: Algorithm, key: []const u8, tokenText: []const u8) !ValueTree {
|
pub fn validate(allocator: *std.mem.Allocator, tokenText: []const u8, signatureOptions: SignatureOptions) !ValueTree {
|
||||||
// 1. Verify that the JWT contains at least one period ('.')
|
// 1. Verify that the JWT contains at least one period ('.')
|
||||||
// character.
|
// character.
|
||||||
// 2. Let the Encoded JOSE Header be the portion of the JWT before the
|
// 2. Let the Encoded JOSE Header be the portion of the JWT before the
|
||||||
|
@ -120,7 +120,7 @@ pub fn validate(allocator: *std.mem.Allocator, algorithm: Algorithm, key: []cons
|
||||||
const alg = std.meta.stringToEnum(Algorithm, alg_val.String) orelse return error.InvalidAlgorithm;
|
const alg = std.meta.stringToEnum(Algorithm, alg_val.String) orelse return error.InvalidAlgorithm;
|
||||||
|
|
||||||
// Make sure that the algorithm matches: https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
|
// Make sure that the algorithm matches: https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
|
||||||
if (alg != algorithm) return error.InvalidAlgorithm;
|
if (alg != signatureOptions.alg) return error.InvalidAlgorithm;
|
||||||
|
|
||||||
// TODO: Determine if "jku"/"jwk" need to be parsed and validated
|
// TODO: Determine if "jku"/"jwk" need to be parsed and validated
|
||||||
|
|
||||||
|
@ -168,9 +168,9 @@ pub fn validate(allocator: *std.mem.Allocator, algorithm: Algorithm, key: []cons
|
||||||
defer allocator.free(signature);
|
defer allocator.free(signature);
|
||||||
try base64url.Decoder.decode(signature, signature_base64);
|
try base64url.Decoder.decode(signature, signature_base64);
|
||||||
|
|
||||||
switch (algorithm) {
|
switch (signatureOptions.alg) {
|
||||||
.HS256 => {
|
.HS256 => {
|
||||||
const gen_sig = generate_signature_hmac_sha256(key, jose_base64, payload_base64);
|
const gen_sig = generate_signature_hmac_sha256(signatureOptions.key, jose_base64, payload_base64);
|
||||||
if (!std.mem.eql(u8, signature, &gen_sig)) {
|
if (!std.mem.eql(u8, signature, &gen_sig)) {
|
||||||
return error.InvalidSignature;
|
return error.InvalidSignature;
|
||||||
}
|
}
|
||||||
|
@ -257,7 +257,7 @@ test "validate jws hmac sha-256" {
|
||||||
defer std.testing.allocator.free(key);
|
defer std.testing.allocator.free(key);
|
||||||
try base64url.Decoder.decode(key, key_base64);
|
try base64url.Decoder.decode(key, key_base64);
|
||||||
|
|
||||||
var claims_tree = try validate(std.testing.allocator, .HS256, key, token);
|
var claims_tree = try validate(std.testing.allocator, token, .{ .alg = .HS256, .key = key });
|
||||||
defer claims_tree.deinit();
|
defer claims_tree.deinit();
|
||||||
|
|
||||||
var claims = claims_tree.root;
|
var claims = claims_tree.root;
|
||||||
|
@ -276,10 +276,12 @@ test "generate and then validate jws hmac sha-256" {
|
||||||
.iat = @as(i64, 1516239022),
|
.iat = @as(i64, 1516239022),
|
||||||
};
|
};
|
||||||
|
|
||||||
const token = try encode(std.testing.allocator, payload, .{ .alg = .HS256, .key = key });
|
const signatureOptions = SignatureOptions{ .alg = .HS256, .key = key };
|
||||||
|
|
||||||
|
const token = try encode(std.testing.allocator, payload, signatureOptions);
|
||||||
defer std.testing.allocator.free(token);
|
defer std.testing.allocator.free(token);
|
||||||
|
|
||||||
var claims_tree = try validate(std.testing.allocator, .HS256, key, token);
|
var claims_tree = try validate(std.testing.allocator, token, signatureOptions);
|
||||||
defer claims_tree.deinit();
|
defer claims_tree.deinit();
|
||||||
|
|
||||||
var claims = claims_tree.root;
|
var claims = claims_tree.root;
|
||||||
|
|
Loading…
Reference in New Issue