Skip to content

Commit 66169d2

Browse files
committed
add es256k
1 parent 019e847 commit 66169d2

File tree

5 files changed

+137
-6
lines changed

5 files changed

+137
-6
lines changed

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ pub fn main() !void {
110110
var validator = try jwt.Validator.init(token);
111111
defer validator.deinit();
112112
113+
// validator.withLeeway(3);
114+
113115
// output:
114116
// hasBeenIssuedBy: true
115117
std.debug.print("hasBeenIssuedBy: {} \n", .{validator.hasBeenIssuedBy("iss")});
@@ -140,6 +142,8 @@ The JWT library have signing methods:
140142

141143
- `ES256`: jwt.SigningMethodES256
142144
- `ES384`: jwt.SigningMethodES384
145+
146+
- `ES256K`: jwt.SigningMethodES256K
143147

144148
- `EdDSA`: jwt.SigningMethodEdDSA
145149
- `ED25519`: jwt.SigningMethodED25519
@@ -171,11 +175,17 @@ const p256_public_key = ecdsa.EcdsaP256Sha256.PublicKey;
171175
const p384_secret_key = ecdsa.EcdsaP384Sha384.SecretKey;
172176
const p384_public_key = ecdsa.EcdsaP384Sha384.PublicKey;
173177
178+
const p256k_secret_key = ecdsa.EcdsaSecp256k1Sha256.SecretKey;
179+
const p256k_public_key = ecdsa.EcdsaSecp256k1Sha256.PublicKey;
180+
174181
// generate p256 public key
175182
const p256_kp = ecdsa.EcdsaP256Sha256.KeyPair.generate();
176183
177184
// generate p384 public key
178185
const p384_kp = ecdsa.EcdsaP384Sha384.KeyPair.generate();
186+
187+
// generate p256k public key
188+
const p256k_kp = ecdsa.EcdsaSecp256k1Sha256.KeyPair.generate();
179189
~~~
180190

181191
EdDSA PublicKey:

build.zig.zon

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
.{
22
.name = "zig-jwt",
33
.description = "A JWT (JSON Web Token) library for zig.",
4-
.version = "1.0.9",
4+
.version = "1.0.11",
55
.paths = .{
66
"build.zig",
77
"build.zig.zon",

src/ecdsa.zig

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ pub const SigningES256 = SignECDSA(ecdsa.EcdsaP256Sha256, "ES256");
99
pub const SigningES384 = SignECDSA(ecdsa.EcdsaP384Sha384, "ES384");
1010
// pub const SigningES512 = SignECDSA(ecdsa.EcdsaP512Sha512, "ES512");
1111

12+
pub const SigningES256K = SignECDSA(ecdsa.EcdsaSecp256k1Sha256, "ES256K");
13+
1214
pub fn SignECDSA(comptime EC: type, comptime name: []const u8) type {
1315
return struct {
1416
alloc: Allocator,
@@ -110,4 +112,28 @@ test "SigningES384" {
110112

111113
try testing.expectEqual(true, veri);
112114

113-
}
115+
}
116+
117+
test "SigningES256K" {
118+
const alloc = std.heap.page_allocator;
119+
120+
const h = SigningES256K.init(alloc);
121+
122+
const alg = h.alg();
123+
const signLength = h.signLength();
124+
try testing.expectEqual(64, signLength);
125+
try testing.expectEqualStrings("ES256K", alg);
126+
127+
const kp = ecdsa.EcdsaSecp256k1Sha256.KeyPair.generate();
128+
129+
const msg = "test-data";
130+
131+
const signed = try h.sign(msg, kp.secret_key);
132+
133+
try testing.expectEqual(64, signed.len);
134+
135+
const veri = h.verify(msg, signed, kp.public_key);
136+
137+
try testing.expectEqual(true, veri);
138+
139+
}

src/jwt.zig

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ pub const SigningMethodPS512 = JWT(rsa_pss.SigningPS512, crypto_rsa.SecretKey, c
2727

2828
pub const SigningMethodES256 = JWT(ecdsa.SigningES256, ecdsa.ecdsa.EcdsaP256Sha256.SecretKey, ecdsa.ecdsa.EcdsaP256Sha256.PublicKey);
2929
pub const SigningMethodES384 = JWT(ecdsa.SigningES384, ecdsa.ecdsa.EcdsaP384Sha384.SecretKey, ecdsa.ecdsa.EcdsaP384Sha384.PublicKey);
30-
// pub const SigningMethodES512 = JWT(ecdsa.SigningES512, ecdsa.ecdsa.SecretKey, ecdsa.ecdsa.PublicKey);
30+
// pub const SigningMethodES512 = JWT(ecdsa.SigningES512, ecdsa.ecdsa.EcdsaP521Sha512.SecretKey, ecdsa.ecdsa.EcdsaP521Sha512.PublicKey);
31+
32+
pub const SigningMethodES256K = JWT(ecdsa.SigningES256K, ecdsa.ecdsa.EcdsaSecp256k1Sha256.SecretKey, ecdsa.ecdsa.EcdsaSecp256k1Sha256.PublicKey);
3133

3234
pub const SigningMethodEdDSA = JWT(eddsa.SigningEdDSA, eddsa.Ed25519.SecretKey, eddsa.Ed25519.PublicKey);
3335
pub const SigningMethodED25519 = JWT(eddsa.SigningED25519, eddsa.Ed25519.SecretKey, eddsa.Ed25519.PublicKey);
@@ -406,6 +408,31 @@ test "SigningMethodES384" {
406408

407409
}
408410

411+
test "SigningMethodES256K" {
412+
const alloc = std.heap.page_allocator;
413+
414+
const kp = ecdsa.ecdsa.EcdsaSecp256k1Sha256.KeyPair.generate();
415+
416+
const claims = .{
417+
.aud = "example.com",
418+
.sub = "foo",
419+
};
420+
421+
const s = SigningMethodES256K.init(alloc);
422+
const token_string = try s.sign(claims, kp.secret_key);
423+
try testing.expectEqual(true, token_string.len > 0);
424+
425+
// ==========
426+
427+
const p = SigningMethodES256K.init(alloc);
428+
var parsed = try p.parse(token_string, kp.public_key);
429+
430+
const claims2 = try parsed.getClaims();
431+
try testing.expectEqualStrings(claims.aud, claims2.object.get("aud").?.string);
432+
try testing.expectEqualStrings(claims.sub, claims2.object.get("sub").?.string);
433+
434+
}
435+
409436
test "SigningMethodHS256" {
410437
const alloc = std.heap.page_allocator;
411438

@@ -608,6 +635,42 @@ test "SigningMethodES256 Check fail" {
608635

609636
}
610637

638+
test "SigningMethodES256K Check" {
639+
const alloc = std.heap.page_allocator;
640+
641+
const pub_key = "04cbcc2ebfaf9f5e874b3cb7e1c66d77db2d51f26e1d92783bb477bb37eb142d5d84b61e80c445d07ddf84e27b9c791db550d0af40aab1898c02cd5c0829c1defc";
642+
const pri_key = "c4e29dedecf2d4fef1bb300cce3fcfca3ec086066fd3d03ebc3cc7a36ee900dd";
643+
const token_str = "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJmb28iOiJiYXIifQ.Xe92dmU8MrI1d4edE2LEKqSmObZJpkIuz0fERihfn65ikTeeX5zjpyAdlHy9ZSBX8N8sqmJy5fxBTBzV26WvIQ";
644+
645+
const encoded_length = ecdsa.ecdsa.EcdsaSecp256k1Sha256.SecretKey.encoded_length;
646+
647+
var pri_key_buf: [encoded_length]u8 = undefined;
648+
_ = try fmt.hexToBytes(&pri_key_buf, pri_key);
649+
650+
var pub_key_buf: [pub_key.len / 2]u8 = undefined;
651+
const pub_key_bytes = try fmt.hexToBytes(&pub_key_buf, pub_key);
652+
653+
const secret_key = try ecdsa.ecdsa.EcdsaSecp256k1Sha256.SecretKey.fromBytes(pri_key_buf);
654+
const public_key = try ecdsa.ecdsa.EcdsaSecp256k1Sha256.PublicKey.fromSec1(pub_key_bytes);
655+
656+
const claims = .{
657+
.foo = "bar",
658+
};
659+
660+
const s = SigningMethodES256K.init(alloc);
661+
const token_string = try s.sign(claims, secret_key);
662+
try testing.expectEqual(true, token_string.len > 0);
663+
664+
// ==========
665+
666+
const p = SigningMethodES256K.init(alloc);
667+
var parsed = try p.parse(token_str, public_key);
668+
669+
const claims2 = try parsed.getClaims();
670+
try testing.expectEqualStrings(claims.foo, claims2.object.get("foo").?.string);
671+
672+
}
673+
611674
test "SigningMethodEdDSA Check" {
612675
const alloc = std.heap.page_allocator;
613676

src/validator.zig

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const Token = @import("token.zig").Token;
99
pub const Validator = struct {
1010
token: Token,
1111
claims: json.Value,
12+
leeway: i64 = 0,
1213

1314
const Self = @This();
1415

@@ -19,13 +20,18 @@ pub const Validator = struct {
1920
return .{
2021
.token = token,
2122
.claims = claims,
23+
.leeway = 0,
2224
};
2325
}
2426

2527
pub fn deinit(self: *Self) void {
2628
self.token.deinit();
2729
}
2830

31+
pub fn withLeeway(self: *Self, leeway: i64) void {
32+
self.leeway = leeway;
33+
}
34+
2935
pub fn isPermittedFor(self: *Self, audience: []const u8) bool {
3036
const claims = self.claims;
3137

@@ -95,7 +101,7 @@ pub const Validator = struct {
95101

96102
if (claims.object.get("iat")) |val| {
97103
if (val == .integer) {
98-
if (now > val.integer) {
104+
if (now + self.leeway >= val.integer) {
99105
return true;
100106
}
101107
}
@@ -111,7 +117,7 @@ pub const Validator = struct {
111117

112118
if (claims.object.get("nbf")) |val| {
113119
if (val == .integer) {
114-
if (now > val.integer) {
120+
if (now + self.leeway >= val.integer) {
115121
return true;
116122
}
117123
}
@@ -127,7 +133,7 @@ pub const Validator = struct {
127133

128134
if (claims.object.get("exp")) |val| {
129135
if (val == .integer) {
130-
if (now <= val.integer) {
136+
if (now - self.leeway < val.integer) {
131137
return false;
132138
}
133139
}
@@ -199,8 +205,34 @@ test "Validator" {
199205
try testing.expectEqual(true, validator.isIdentifiedBy("jti rrr"));
200206
try testing.expectEqual(true, validator.isPermittedFor("example.com"));
201207
try testing.expectEqual(true, validator.hasBeenIssuedBefore(now));
208+
try testing.expectEqual(false, validator.isExpired(now));
202209

203210
const claims = try token.getClaims();
204211
try testing.expectEqual(true, claims.object.get("nbf").?.integer > 0);
212+
213+
try testing.expectEqual(1567842388, claims.object.get("iat").?.integer);
214+
try testing.expectEqual(1767842388, claims.object.get("exp").?.integer);
215+
try testing.expectEqual(1567842388, claims.object.get("nbf").?.integer);
205216

217+
try testing.expectEqual(true, validator.hasBeenIssuedBefore(1567842389));
218+
try testing.expectEqual(true, validator.isMinimumTimeBefore(1567842389));
219+
try testing.expectEqual(true, validator.isExpired(1767842389));
220+
221+
// ======
222+
223+
var token2 = Token.init(alloc);
224+
try token2.parse(check1);
225+
226+
var validator2 = try Validator.init(token2);
227+
defer validator2.deinit();
228+
229+
validator2.withLeeway(3);
230+
231+
try testing.expectEqual(true, validator2.hasBeenIssuedBefore(1567842391));
232+
try testing.expectEqual(false, validator2.hasBeenIssuedBefore(1567842384));
233+
try testing.expectEqual(true, validator2.isMinimumTimeBefore(1567842391));
234+
try testing.expectEqual(false, validator2.isMinimumTimeBefore(1567842384));
235+
try testing.expectEqual(true, validator2.isExpired(1767842392));
236+
try testing.expectEqual(false, validator2.isExpired(1767842389));
237+
206238
}

0 commit comments

Comments
 (0)