Skip to content

Commit 733fffc

Browse files
committed
add rsa pkcs8 parse
1 parent 458d606 commit 733fffc

File tree

5 files changed

+234
-32
lines changed

5 files changed

+234
-32
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,13 @@ const public_key = jwt.crypto_rsa.PublicKey;
166166
167167
// rsa no generate
168168
169-
// from plain bytes
169+
// from pkcs1 der bytes
170170
const secret_key = try jwt.crypto_rsa.SecretKey.fromDer(prikey_bytes);
171171
const public_key = try jwt.crypto_rsa.PublicKey.fromDer(pubkey_bytes);
172+
173+
// from pkcs8 der bytes
174+
const secret_key = try jwt.crypto_rsa.SecretKey.fromPKCS8Der(prikey_bytes);
175+
const public_key = try jwt.crypto_rsa.PublicKey.fromPKCS8Der(pubkey_bytes);
172176
~~~
173177

174178
ECDSA 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.17",
4+
.version = "1.0.18",
55
.fingerprint = 0x30a5aec248bd7ac3,
66
.minimum_zig_version = "0.14.0-dev.3451+d8d2aa9af",
77
.dependencies = .{},

src/jwt.zig

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1419,3 +1419,101 @@ test "SigningMethodPS256 Check fail" {
14191419
try testing.expectEqual(true, need_true);
14201420

14211421
}
1422+
1423+
test "SigningMethodRS256 with pkcs8 key" {
1424+
const alloc = std.heap.page_allocator;
1425+
1426+
const prikey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDh/nCDmXaEqxN416b9XjV8acmbqA52uPzKbesWQRT/BPxEO2dKAURk5CkcSBDskvfzFR9TRjeDppjD1BPSEnuYKnP0SvmotoxcnBnHMfMBqGV8DSJyppu8k4y9C3MPq5C/rA8TJm0NNaJCL0BfAGkeyw+elgYifbRlm42VfYGsKVyIeEI9Qghk5Cf8yapMPfWNLKOhChXsyGExMBMonHZeseFH7UNwonNAFJMAaelhVqqmwBFqn6fBGKmvedRO7HIaiEFNKaMna6xJ5Bccjds4MhF7UC5PIdx4Bt7CfxvjrbIRYoBF2l30CNBblIhU992zPkHoaVhDkt1gq3OdO7LvAgMBAAECggEBALCJrWTv7ahnZ3efpqAIBuogTVBd8KaHjVmokds5jehFAbdfXClwYfgaT477MNVNXYmzN1w63sTl0DIxqiYRMCFHEHuGUg6cQ3tYqb50Y2spG9XTANTlF4UxEeDfX8ue7xz7kG8aNlf6TL084iEUVgmrAJGWikZJQjGZWPmtKC3OTeJY5Bev5qHVuMRe+XEM5aQc3ph+lXlOF0Qp0Eg8YRWprrev2faH6prMqu2JGomoac6sfM4QJhtEViF7Gw0XPthPTbF19IefuAwi9psMM/9CnQ+MTWN2i6IxoUdicsFuC+Wdlb3K5V/+uldNSr+ePEhcya+YTLK9IOcVwWKQHykCgYEA8XvuEribf+t0ZPtfxr+DC9nZHXbVoFx0/ARpSG+P/fp3Hn3rO9iYQ6OtZ9mEXTzf+dhYTaRWq6PbCOz6i0It+J8QSBdxU9OcQ4871mDe41IvSc1CCGMW4PeIYtNQEK0zrqhN7SMtKyUd7yAsYRCrIzMc7NjE2qJvFw5kh7xC3Q0CgYEA75Qjn5daNYSAOa/ILdOs5J/8oIaO27RNK/fSKm/btsMsyum8+YP/mWmm1MXBzG9WEKzZv5yEKOWCEVJYVsFQsGt9yLYW2WIKU5UxiuU0F1RImF/dphIbYOh7oGC3WfYKk2f+K7ftjc196ZkEkDuE2Xh1h75/67Mzztx1DbXj6OsCgYBcDRfFfyWXb5Og4smxo1M680H2H1RzmorlfnD7sbs733wE3Y8L8xanwf7Z9WqleA0Q2k1e22RGbWGTV3JyHzoS6d90+6qxf5qzjigLIkYUdUGdambfd5ZDD1ioA1Ej6kInM/TwjlYreiyc+LCyF36FHnjKOB9iEEU0jsH3k+YRCQKBgHMVLPuHX6zfhhyvxK/Gw4FbHKYbnNoKxRs+wvThoKAtJwIdv0n4TzppVttUV2CVhrkh3sM9MvrWLGGXtZmO6Oyl5dkZJuarQpydyRuYOCqQsQKI4lbY0c/+PQxwCQMsvi3KwXxMsM7yC+6/M0L5ZDp2s7ZOGvKktVlD6vJ4Eg+bAoGARnGGprSBW8dAb/s53r0paPh4k/bySrXdGEprLwk6g3S8+aylcmjUdjcIq4dEb4A/nv12dx1Sc4y99c62R0zi+TT6FYBIFDMz3HNVzO0Jr6SgC6CNVotL0D725CioR5U1NyTHHRLZth69HLuEZCZQlPJCbePXMRRHmOl1svzcVuo=";
1427+
const pubkey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4f5wg5l2hKsTeNem/V41fGnJm6gOdrj8ym3rFkEU/wT8RDtnSgFEZOQpHEgQ7JL38xUfU0Y3g6aYw9QT0hJ7mCpz9Er5qLaMXJwZxzHzAahlfA0icqabvJOMvQtzD6uQv6wPEyZtDTWiQi9AXwBpHssPnpYGIn20ZZuNlX2BrClciHhCPUIIZOQn/MmqTD31jSyjoQoV7MhhMTATKJx2XrHhR+1DcKJzQBSTAGnpYVaqpsARap+nwRipr3nUTuxyGohBTSmjJ2usSeQXHI3bODIRe1AuTyHceAbewn8b462yEWKARdpd9AjQW5SIVPfdsz5B6GlYQ5LdYKtznTuy7wIDAQAB";
1428+
1429+
const prikey_bytes = try utils.base64Decode(alloc, prikey);
1430+
const pubkey_bytes = try utils.base64Decode(alloc, pubkey);
1431+
1432+
const secret_key = try crypto_rsa.SecretKey.fromPKCS8Der(prikey_bytes);
1433+
const public_key = try crypto_rsa.PublicKey.fromPKCS8Der(pubkey_bytes);
1434+
1435+
const claims = .{
1436+
.aud = "example.com",
1437+
.sub = "foo",
1438+
};
1439+
1440+
const s = SigningMethodRS256.init(alloc);
1441+
const token_string = try s.sign(claims, secret_key);
1442+
try testing.expectEqual(true, token_string.len > 0);
1443+
1444+
// ==========
1445+
1446+
const p = SigningMethodRS256.init(alloc);
1447+
var parsed = try p.parse(token_string, public_key);
1448+
1449+
const claims2 = try parsed.getClaims();
1450+
try testing.expectEqualStrings(claims.aud, claims2.object.get("aud").?.string);
1451+
try testing.expectEqualStrings(claims.sub, claims2.object.get("sub").?.string);
1452+
1453+
}
1454+
1455+
test "SigningMethodPS256 with pkcs8 key" {
1456+
const alloc = std.heap.page_allocator;
1457+
1458+
const prikey = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDh/nCDmXaEqxN416b9XjV8acmbqA52uPzKbesWQRT/BPxEO2dKAURk5CkcSBDskvfzFR9TRjeDppjD1BPSEnuYKnP0SvmotoxcnBnHMfMBqGV8DSJyppu8k4y9C3MPq5C/rA8TJm0NNaJCL0BfAGkeyw+elgYifbRlm42VfYGsKVyIeEI9Qghk5Cf8yapMPfWNLKOhChXsyGExMBMonHZeseFH7UNwonNAFJMAaelhVqqmwBFqn6fBGKmvedRO7HIaiEFNKaMna6xJ5Bccjds4MhF7UC5PIdx4Bt7CfxvjrbIRYoBF2l30CNBblIhU992zPkHoaVhDkt1gq3OdO7LvAgMBAAECggEBALCJrWTv7ahnZ3efpqAIBuogTVBd8KaHjVmokds5jehFAbdfXClwYfgaT477MNVNXYmzN1w63sTl0DIxqiYRMCFHEHuGUg6cQ3tYqb50Y2spG9XTANTlF4UxEeDfX8ue7xz7kG8aNlf6TL084iEUVgmrAJGWikZJQjGZWPmtKC3OTeJY5Bev5qHVuMRe+XEM5aQc3ph+lXlOF0Qp0Eg8YRWprrev2faH6prMqu2JGomoac6sfM4QJhtEViF7Gw0XPthPTbF19IefuAwi9psMM/9CnQ+MTWN2i6IxoUdicsFuC+Wdlb3K5V/+uldNSr+ePEhcya+YTLK9IOcVwWKQHykCgYEA8XvuEribf+t0ZPtfxr+DC9nZHXbVoFx0/ARpSG+P/fp3Hn3rO9iYQ6OtZ9mEXTzf+dhYTaRWq6PbCOz6i0It+J8QSBdxU9OcQ4871mDe41IvSc1CCGMW4PeIYtNQEK0zrqhN7SMtKyUd7yAsYRCrIzMc7NjE2qJvFw5kh7xC3Q0CgYEA75Qjn5daNYSAOa/ILdOs5J/8oIaO27RNK/fSKm/btsMsyum8+YP/mWmm1MXBzG9WEKzZv5yEKOWCEVJYVsFQsGt9yLYW2WIKU5UxiuU0F1RImF/dphIbYOh7oGC3WfYKk2f+K7ftjc196ZkEkDuE2Xh1h75/67Mzztx1DbXj6OsCgYBcDRfFfyWXb5Og4smxo1M680H2H1RzmorlfnD7sbs733wE3Y8L8xanwf7Z9WqleA0Q2k1e22RGbWGTV3JyHzoS6d90+6qxf5qzjigLIkYUdUGdambfd5ZDD1ioA1Ej6kInM/TwjlYreiyc+LCyF36FHnjKOB9iEEU0jsH3k+YRCQKBgHMVLPuHX6zfhhyvxK/Gw4FbHKYbnNoKxRs+wvThoKAtJwIdv0n4TzppVttUV2CVhrkh3sM9MvrWLGGXtZmO6Oyl5dkZJuarQpydyRuYOCqQsQKI4lbY0c/+PQxwCQMsvi3KwXxMsM7yC+6/M0L5ZDp2s7ZOGvKktVlD6vJ4Eg+bAoGARnGGprSBW8dAb/s53r0paPh4k/bySrXdGEprLwk6g3S8+aylcmjUdjcIq4dEb4A/nv12dx1Sc4y99c62R0zi+TT6FYBIFDMz3HNVzO0Jr6SgC6CNVotL0D725CioR5U1NyTHHRLZth69HLuEZCZQlPJCbePXMRRHmOl1svzcVuo=";
1459+
const pubkey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4f5wg5l2hKsTeNem/V41fGnJm6gOdrj8ym3rFkEU/wT8RDtnSgFEZOQpHEgQ7JL38xUfU0Y3g6aYw9QT0hJ7mCpz9Er5qLaMXJwZxzHzAahlfA0icqabvJOMvQtzD6uQv6wPEyZtDTWiQi9AXwBpHssPnpYGIn20ZZuNlX2BrClciHhCPUIIZOQn/MmqTD31jSyjoQoV7MhhMTATKJx2XrHhR+1DcKJzQBSTAGnpYVaqpsARap+nwRipr3nUTuxyGohBTSmjJ2usSeQXHI3bODIRe1AuTyHceAbewn8b462yEWKARdpd9AjQW5SIVPfdsz5B6GlYQ5LdYKtznTuy7wIDAQAB";
1460+
1461+
const prikey_bytes = try utils.base64Decode(alloc, prikey);
1462+
const pubkey_bytes = try utils.base64Decode(alloc, pubkey);
1463+
1464+
const secret_key = try crypto_rsa.SecretKey.fromPKCS8Der(prikey_bytes);
1465+
const public_key = try crypto_rsa.PublicKey.fromPKCS8Der(pubkey_bytes);
1466+
1467+
const claims = .{
1468+
.aud = "example.com",
1469+
.sub = "foo",
1470+
};
1471+
1472+
const s = SigningMethodPS256.init(alloc);
1473+
const token_string = try s.sign(claims, secret_key);
1474+
try testing.expectEqual(true, token_string.len > 0);
1475+
1476+
// ==========
1477+
1478+
const p = SigningMethodPS256.init(alloc);
1479+
var parsed = try p.parse(token_string, public_key);
1480+
1481+
const claims2 = try parsed.getClaims();
1482+
try testing.expectEqualStrings(claims.aud, claims2.object.get("aud").?.string);
1483+
try testing.expectEqualStrings(claims.sub, claims2.object.get("sub").?.string);
1484+
1485+
}
1486+
1487+
test "SigningMethodRS256 Check with pkcs8 key" {
1488+
const alloc = std.heap.page_allocator;
1489+
1490+
const pubkey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4f5wg5l2hKsTeNem/V41fGnJm6gOdrj8ym3rFkEU/wT8RDtnSgFEZOQpHEgQ7JL38xUfU0Y3g6aYw9QT0hJ7mCpz9Er5qLaMXJwZxzHzAahlfA0icqabvJOMvQtzD6uQv6wPEyZtDTWiQi9AXwBpHssPnpYGIn20ZZuNlX2BrClciHhCPUIIZOQn/MmqTD31jSyjoQoV7MhhMTATKJx2XrHhR+1DcKJzQBSTAGnpYVaqpsARap+nwRipr3nUTuxyGohBTSmjJ2usSeQXHI3bODIRe1AuTyHceAbewn8b462yEWKARdpd9AjQW5SIVPfdsz5B6GlYQ5LdYKtznTuy7wIDAQAB";
1491+
const token_str = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg";
1492+
1493+
const pubkey_bytes = try utils.base64Decode(alloc, pubkey);
1494+
const public_key = try crypto_rsa.PublicKey.fromPKCS8Der(pubkey_bytes);
1495+
1496+
const p = SigningMethodRS256.init(alloc);
1497+
var parsed = try p.parse(token_str, public_key);
1498+
1499+
const claims2 = try parsed.getClaims();
1500+
try testing.expectEqualStrings("bar", claims2.object.get("foo").?.string);
1501+
1502+
}
1503+
1504+
test "SigningMethodPS256 Check with pkcs8 key" {
1505+
const alloc = std.heap.page_allocator;
1506+
1507+
const pubkey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4f5wg5l2hKsTeNem/V41fGnJm6gOdrj8ym3rFkEU/wT8RDtnSgFEZOQpHEgQ7JL38xUfU0Y3g6aYw9QT0hJ7mCpz9Er5qLaMXJwZxzHzAahlfA0icqabvJOMvQtzD6uQv6wPEyZtDTWiQi9AXwBpHssPnpYGIn20ZZuNlX2BrClciHhCPUIIZOQn/MmqTD31jSyjoQoV7MhhMTATKJx2XrHhR+1DcKJzQBSTAGnpYVaqpsARap+nwRipr3nUTuxyGohBTSmjJ2usSeQXHI3bODIRe1AuTyHceAbewn8b462yEWKARdpd9AjQW5SIVPfdsz5B6GlYQ5LdYKtznTuy7wIDAQAB";
1508+
const token_str = "eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.PPG4xyDVY8ffp4CcxofNmsTDXsrVG2npdQuibLhJbv4ClyPTUtR5giNSvuxo03kB6I8VXVr0Y9X7UxhJVEoJOmULAwRWaUsDnIewQa101cVhMa6iR8X37kfFoiZ6NkS-c7henVkkQWu2HtotkEtQvN5hFlk8IevXXPmvZlhQhwzB1sGzGYnoi1zOfuL98d3BIjUjtlwii5w6gYG2AEEzp7HnHCsb3jIwUPdq86Oe6hIFjtBwduIK90ca4UqzARpcfwxHwVLMpatKask00AgGVI0ysdk0BLMjmLutquD03XbThHScC2C2_Pp4cHWgMzvbgLU2RYYZcZRKr46QeNgz9w";
1509+
1510+
const pubkey_bytes = try utils.base64Decode(alloc, pubkey);
1511+
const public_key = try crypto_rsa.PublicKey.fromPKCS8Der(pubkey_bytes);
1512+
1513+
const p = SigningMethodPS256.init(alloc);
1514+
var parsed = try p.parse(token_str, public_key);
1515+
1516+
const claims2 = try parsed.getClaims();
1517+
try testing.expectEqualStrings("bar", claims2.object.get("foo").?.string);
1518+
1519+
}

src/rsa/der.zig

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,7 @@ pub const Parser = struct {
2424
bytes: []const u8,
2525
index: Index = 0,
2626

27-
pub const Error = Element.Error || error{
28-
UnexpectedElement,
29-
InvalidIntegerEncoding,
30-
Overflow,
31-
NonCanonical,
32-
};
33-
34-
pub fn expectBool(self: *Parser) Error!bool {
27+
pub fn expectBool(self: *Parser) !bool {
3528
const ele = try self.expect(.universal, false, .boolean);
3629
if (ele.slice.len() != 1) return error.InvalidBool;
3730

@@ -42,7 +35,7 @@ pub const Parser = struct {
4235
};
4336
}
4437

45-
pub fn expectBitstring(self: *Parser) Error!BitString {
38+
pub fn expectBitstring(self: *Parser) !BitString {
4639
const ele = try self.expect(.universal, false, .bitstring);
4740
const bytes = self.view(ele);
4841
const right_padding = bytes[0];
@@ -54,7 +47,7 @@ pub const Parser = struct {
5447
}
5548

5649
// TODO: return high resolution date time type instead of epoch seconds
57-
pub fn expectDateTime(self: *Parser) Error!i64 {
50+
pub fn expectDateTime(self: *Parser) !i64 {
5851
const ele = try self.expect(.universal, false, null);
5952
const bytes = self.view(ele);
6053
switch (ele.identifier.tag) {
@@ -93,12 +86,12 @@ pub const Parser = struct {
9386
}
9487
}
9588

96-
pub fn expectOid(self: *Parser) Error![]const u8 {
89+
pub fn expectOid(self: *Parser) ![]const u8 {
9790
const oid = try self.expect(.universal, false, .object_identifier);
9891
return self.view(oid);
9992
}
10093

101-
pub fn expectEnum(self: *Parser, comptime Enum: type) Error!Enum {
94+
pub fn expectEnum(self: *Parser, comptime Enum: type) !Enum {
10295
const oid = try self.expectOid();
10396
return Enum.oids.get(oid) orelse {
10497
if (builtin.mode == .Debug) {
@@ -111,7 +104,7 @@ pub const Parser = struct {
111104
};
112105
}
113106

114-
pub fn expectInt(self: *Parser, comptime T: type) Error!T {
107+
pub fn expectInt(self: *Parser, comptime T: type) !T {
115108
const ele = try self.expectPrimitive(.integer);
116109
const bytes = self.view(ele);
117110

@@ -130,7 +123,7 @@ pub const Parser = struct {
130123
return @bitCast(result);
131124
}
132125

133-
pub fn expectString(self: *Parser, allowed: std.EnumSet(String.Tag)) Error!String {
126+
pub fn expectString(self: *Parser, allowed: std.EnumSet(String.Tag)) !String {
134127
const ele = try self.expect(.universal, false, null);
135128
switch (ele.identifier.tag) {
136129
inline .string_utf8,
@@ -154,7 +147,7 @@ pub const Parser = struct {
154147
return error.UnexpectedElement;
155148
}
156149

157-
pub fn expectPrimitive(self: *Parser, tag: ?Identifier.Tag) Error!Element {
150+
pub fn expectPrimitive(self: *Parser, tag: ?Identifier.Tag) !Element {
158151
var elem = try self.expect(.universal, false, tag);
159152
if (tag == .integer and elem.slice.len() > 0) {
160153
if (self.view(elem)[0] == 0) elem.slice.start += 1;
@@ -164,16 +157,16 @@ pub const Parser = struct {
164157
}
165158

166159
/// Remember to call `expectEnd`
167-
pub fn expectSequence(self: *Parser) Error!Element {
160+
pub fn expectSequence(self: *Parser) !Element {
168161
return try self.expect(.universal, true, .sequence);
169162
}
170163

171164
/// Remember to call `expectEnd`
172-
pub fn expectSequenceOf(self: *Parser) Error!Element {
165+
pub fn expectSequenceOf(self: *Parser) !Element {
173166
return try self.expect(.universal, true, .sequence_of);
174167
}
175168

176-
pub fn expectEnd(self: *Parser, val: usize) Error!void {
169+
pub fn expectEnd(self: *Parser, val: usize) !void {
177170
if (self.index != val) return error.NonCanonical; // either forgot to parse end OR an attacker
178171
}
179172

@@ -182,7 +175,7 @@ pub const Parser = struct {
182175
class: ?Identifier.Class,
183176
constructed: ?bool,
184177
tag: ?Identifier.Tag,
185-
) Error!Element {
178+
) !Element {
186179
if (self.index >= self.bytes.len) return error.EndOfStream;
187180

188181
const res = try Element.init(self.bytes, self.index);
@@ -229,9 +222,7 @@ pub const Element = struct {
229222
}
230223
};
231224

232-
pub const Error = error{ InvalidLength, EndOfStream };
233-
234-
pub fn init(bytes: []const u8, index: Index) Error!Element {
225+
pub fn init(bytes: []const u8, index: Index) !Element {
235226
var stream = std.io.fixedBufferStream(bytes[index..]);
236227
var reader = stream.reader();
237228

0 commit comments

Comments
 (0)