Skip to content

Commit fa04f35

Browse files
committed
Implement signature verification
1 parent 3800149 commit fa04f35

File tree

7 files changed

+239
-27
lines changed

7 files changed

+239
-27
lines changed

JWT.podspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ Pod::Spec.new do |spec|
1111
spec.ios.deployment_target = '8.0'
1212
spec.osx.deployment_target = '10.9'
1313
spec.requires_arc = true
14+
spec.dependency 'CryptoSwift', '~> 0.0.8'
1415
end
1516

JWT.xcodeproj/project.pbxproj

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
279D63A81AD07FFF0024E2BC /* JWT.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 279D639C1AD07FFF0024E2BC /* JWT.framework */; };
1212
279D63AF1AD07FFF0024E2BC /* JWTTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279D63AE1AD07FFF0024E2BC /* JWTTests.swift */; };
1313
279D63B91AD0803F0024E2BC /* JWT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279D63B81AD0803F0024E2BC /* JWT.swift */; };
14+
885619E9E1C342A9D8BD77B7 /* Pods_JWT.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 540942F3614C41E3827F2013 /* Pods_JWT.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
15+
EBEC5851F5183DF2D7BFE1AF /* Pods_JWTTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE8198B6E30BA6B8F8125FA7 /* Pods_JWTTests.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
1416
/* End PBXBuildFile section */
1517

1618
/* Begin PBXContainerItemProxy section */
@@ -31,13 +33,20 @@
3133
279D63AD1AD07FFF0024E2BC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
3234
279D63AE1AD07FFF0024E2BC /* JWTTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JWTTests.swift; sourceTree = "<group>"; };
3335
279D63B81AD0803F0024E2BC /* JWT.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JWT.swift; sourceTree = "<group>"; };
36+
3BD8D638895FE8AF4FDDA8A9 /* Pods-JWTTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JWTTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-JWTTests/Pods-JWTTests.debug.xcconfig"; sourceTree = "<group>"; };
37+
540942F3614C41E3827F2013 /* Pods_JWT.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_JWT.framework; sourceTree = BUILT_PRODUCTS_DIR; };
38+
56671E3EAC540766DE31974E /* Pods-JWT.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JWT.release.xcconfig"; path = "Pods/Target Support Files/Pods-JWT/Pods-JWT.release.xcconfig"; sourceTree = "<group>"; };
39+
85B0E9B465B3B29391C19D14 /* Pods-JWTTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JWTTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-JWTTests/Pods-JWTTests.release.xcconfig"; sourceTree = "<group>"; };
40+
8CDC721EB1EAFD72E8CCF46E /* Pods-JWT.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JWT.debug.xcconfig"; path = "Pods/Target Support Files/Pods-JWT/Pods-JWT.debug.xcconfig"; sourceTree = "<group>"; };
41+
CE8198B6E30BA6B8F8125FA7 /* Pods_JWTTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_JWTTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3442
/* End PBXFileReference section */
3543

3644
/* Begin PBXFrameworksBuildPhase section */
3745
279D63981AD07FFF0024E2BC /* Frameworks */ = {
3846
isa = PBXFrameworksBuildPhase;
3947
buildActionMask = 2147483647;
4048
files = (
49+
885619E9E1C342A9D8BD77B7 /* Pods_JWT.framework in Frameworks */,
4150
);
4251
runOnlyForDeploymentPostprocessing = 0;
4352
};
@@ -46,6 +55,7 @@
4655
buildActionMask = 2147483647;
4756
files = (
4857
279D63A81AD07FFF0024E2BC /* JWT.framework in Frameworks */,
58+
EBEC5851F5183DF2D7BFE1AF /* Pods_JWTTests.framework in Frameworks */,
4959
);
5060
runOnlyForDeploymentPostprocessing = 0;
5161
};
@@ -58,6 +68,8 @@
5868
279D639E1AD07FFF0024E2BC /* JWT */,
5969
279D63AB1AD07FFF0024E2BC /* JWTTests */,
6070
279D639D1AD07FFF0024E2BC /* Products */,
71+
378492BA2DE66F2F8E379F49 /* Pods */,
72+
AC8AE547FDAF3DD80EB4DB2F /* Frameworks */,
6173
);
6274
indentWidth = 2;
6375
sourceTree = "<group>";
@@ -107,6 +119,26 @@
107119
name = "Supporting Files";
108120
sourceTree = "<group>";
109121
};
122+
378492BA2DE66F2F8E379F49 /* Pods */ = {
123+
isa = PBXGroup;
124+
children = (
125+
8CDC721EB1EAFD72E8CCF46E /* Pods-JWT.debug.xcconfig */,
126+
56671E3EAC540766DE31974E /* Pods-JWT.release.xcconfig */,
127+
3BD8D638895FE8AF4FDDA8A9 /* Pods-JWTTests.debug.xcconfig */,
128+
85B0E9B465B3B29391C19D14 /* Pods-JWTTests.release.xcconfig */,
129+
);
130+
name = Pods;
131+
sourceTree = "<group>";
132+
};
133+
AC8AE547FDAF3DD80EB4DB2F /* Frameworks */ = {
134+
isa = PBXGroup;
135+
children = (
136+
540942F3614C41E3827F2013 /* Pods_JWT.framework */,
137+
CE8198B6E30BA6B8F8125FA7 /* Pods_JWTTests.framework */,
138+
);
139+
name = Frameworks;
140+
sourceTree = "<group>";
141+
};
110142
/* End PBXGroup section */
111143

112144
/* Begin PBXHeadersBuildPhase section */
@@ -125,10 +157,13 @@
125157
isa = PBXNativeTarget;
126158
buildConfigurationList = 279D63B21AD07FFF0024E2BC /* Build configuration list for PBXNativeTarget "JWT" */;
127159
buildPhases = (
160+
4B9936F743EA727EA58353BD /* Check Pods Manifest.lock */,
128161
279D63971AD07FFF0024E2BC /* Sources */,
129162
279D63981AD07FFF0024E2BC /* Frameworks */,
130163
279D63991AD07FFF0024E2BC /* Headers */,
131164
279D639A1AD07FFF0024E2BC /* Resources */,
165+
842FB8EA008161B653B5AD81 /* Embed Pods Frameworks */,
166+
6D3D4069FD3A7DC06168A6A2 /* Copy Pods Resources */,
132167
);
133168
buildRules = (
134169
);
@@ -143,9 +178,12 @@
143178
isa = PBXNativeTarget;
144179
buildConfigurationList = 279D63B51AD07FFF0024E2BC /* Build configuration list for PBXNativeTarget "JWTTests" */;
145180
buildPhases = (
181+
7DCEFCF83F6CF372A33D5219 /* Check Pods Manifest.lock */,
146182
279D63A31AD07FFF0024E2BC /* Sources */,
147183
279D63A41AD07FFF0024E2BC /* Frameworks */,
148184
279D63A51AD07FFF0024E2BC /* Resources */,
185+
E68E26141F4DF11E3638A2F0 /* Embed Pods Frameworks */,
186+
F7C4974401B24623F6907649 /* Copy Pods Resources */,
149187
);
150188
buildRules = (
151189
);
@@ -209,6 +247,99 @@
209247
};
210248
/* End PBXResourcesBuildPhase section */
211249

250+
/* Begin PBXShellScriptBuildPhase section */
251+
4B9936F743EA727EA58353BD /* Check Pods Manifest.lock */ = {
252+
isa = PBXShellScriptBuildPhase;
253+
buildActionMask = 2147483647;
254+
files = (
255+
);
256+
inputPaths = (
257+
);
258+
name = "Check Pods Manifest.lock";
259+
outputPaths = (
260+
);
261+
runOnlyForDeploymentPostprocessing = 0;
262+
shellPath = /bin/sh;
263+
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
264+
showEnvVarsInLog = 0;
265+
};
266+
6D3D4069FD3A7DC06168A6A2 /* Copy Pods Resources */ = {
267+
isa = PBXShellScriptBuildPhase;
268+
buildActionMask = 2147483647;
269+
files = (
270+
);
271+
inputPaths = (
272+
);
273+
name = "Copy Pods Resources";
274+
outputPaths = (
275+
);
276+
runOnlyForDeploymentPostprocessing = 0;
277+
shellPath = /bin/sh;
278+
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-JWT/Pods-JWT-resources.sh\"\n";
279+
showEnvVarsInLog = 0;
280+
};
281+
7DCEFCF83F6CF372A33D5219 /* Check Pods Manifest.lock */ = {
282+
isa = PBXShellScriptBuildPhase;
283+
buildActionMask = 2147483647;
284+
files = (
285+
);
286+
inputPaths = (
287+
);
288+
name = "Check Pods Manifest.lock";
289+
outputPaths = (
290+
);
291+
runOnlyForDeploymentPostprocessing = 0;
292+
shellPath = /bin/sh;
293+
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
294+
showEnvVarsInLog = 0;
295+
};
296+
842FB8EA008161B653B5AD81 /* Embed Pods Frameworks */ = {
297+
isa = PBXShellScriptBuildPhase;
298+
buildActionMask = 2147483647;
299+
files = (
300+
);
301+
inputPaths = (
302+
);
303+
name = "Embed Pods Frameworks";
304+
outputPaths = (
305+
);
306+
runOnlyForDeploymentPostprocessing = 0;
307+
shellPath = /bin/sh;
308+
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-JWT/Pods-JWT-frameworks.sh\"\n";
309+
showEnvVarsInLog = 0;
310+
};
311+
E68E26141F4DF11E3638A2F0 /* Embed Pods Frameworks */ = {
312+
isa = PBXShellScriptBuildPhase;
313+
buildActionMask = 2147483647;
314+
files = (
315+
);
316+
inputPaths = (
317+
);
318+
name = "Embed Pods Frameworks";
319+
outputPaths = (
320+
);
321+
runOnlyForDeploymentPostprocessing = 0;
322+
shellPath = /bin/sh;
323+
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-JWTTests/Pods-JWTTests-frameworks.sh\"\n";
324+
showEnvVarsInLog = 0;
325+
};
326+
F7C4974401B24623F6907649 /* Copy Pods Resources */ = {
327+
isa = PBXShellScriptBuildPhase;
328+
buildActionMask = 2147483647;
329+
files = (
330+
);
331+
inputPaths = (
332+
);
333+
name = "Copy Pods Resources";
334+
outputPaths = (
335+
);
336+
runOnlyForDeploymentPostprocessing = 0;
337+
shellPath = /bin/sh;
338+
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-JWTTests/Pods-JWTTests-resources.sh\"\n";
339+
showEnvVarsInLog = 0;
340+
};
341+
/* End PBXShellScriptBuildPhase section */
342+
212343
/* Begin PBXSourcesBuildPhase section */
213344
279D63971AD07FFF0024E2BC /* Sources */ = {
214345
isa = PBXSourcesBuildPhase;
@@ -320,6 +451,7 @@
320451
};
321452
279D63B31AD07FFF0024E2BC /* Debug */ = {
322453
isa = XCBuildConfiguration;
454+
baseConfigurationReference = 8CDC721EB1EAFD72E8CCF46E /* Pods-JWT.debug.xcconfig */;
323455
buildSettings = {
324456
CLANG_ENABLE_MODULES = YES;
325457
COMBINE_HIDPI_IMAGES = YES;
@@ -339,6 +471,7 @@
339471
};
340472
279D63B41AD07FFF0024E2BC /* Release */ = {
341473
isa = XCBuildConfiguration;
474+
baseConfigurationReference = 56671E3EAC540766DE31974E /* Pods-JWT.release.xcconfig */;
342475
buildSettings = {
343476
CLANG_ENABLE_MODULES = YES;
344477
COMBINE_HIDPI_IMAGES = YES;
@@ -357,6 +490,7 @@
357490
};
358491
279D63B61AD07FFF0024E2BC /* Debug */ = {
359492
isa = XCBuildConfiguration;
493+
baseConfigurationReference = 3BD8D638895FE8AF4FDDA8A9 /* Pods-JWTTests.debug.xcconfig */;
360494
buildSettings = {
361495
COMBINE_HIDPI_IMAGES = YES;
362496
FRAMEWORK_SEARCH_PATHS = (
@@ -375,6 +509,7 @@
375509
};
376510
279D63B71AD07FFF0024E2BC /* Release */ = {
377511
isa = XCBuildConfiguration;
512+
baseConfigurationReference = 85B0E9B465B3B29391C19D14 /* Pods-JWTTests.release.xcconfig */;
378513
buildSettings = {
379514
COMBINE_HIDPI_IMAGES = YES;
380515
FRAMEWORK_SEARCH_PATHS = (

JWT.xcworkspace/contents.xcworkspacedata

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

JWT/JWT.swift

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import Foundation
2+
import CryptoSwift
23

34
public typealias Payload = [String:AnyObject]
45

@@ -10,6 +11,9 @@ public enum InvalidToken : Printable {
1011
case InvalidIssuedAt
1112
case InvalidAudience
1213

14+
case InvalidAlgorithm
15+
case InvalidKey
16+
1317
public var description:String {
1418
switch self {
1519
case .DecodeError(let error):
@@ -24,6 +28,10 @@ public enum InvalidToken : Printable {
2428
return "Issued at claim (iat) is in the future"
2529
case InvalidAudience:
2630
return "Invalid Audience"
31+
case InvalidAlgorithm:
32+
return "Unsupported Algorithm"
33+
case InvalidKey:
34+
return "Invalid Key"
2735
}
2836
}
2937
}
@@ -35,11 +43,11 @@ public enum DecodeResult {
3543

3644

3745
/// Decode a JWT
38-
public func decode(jwt:String, verify:Bool = true, audience:String? = nil, issuer:String? = nil) -> DecodeResult {
46+
public func decode(jwt:String, key:String? = nil, verify:Bool = true, audience:String? = nil, issuer:String? = nil) -> DecodeResult {
3947
switch load(jwt) {
4048
case let .Success(header, payload, signature, signatureInput):
4149
if verify {
42-
if let failure = validateClaims(payload, audience, issuer) {
50+
if let failure = validateClaims(payload, audience, issuer) ?? verifySignature(header, signatureInput, signature, key) {
4351
return .Failure(failure)
4452
}
4553
}
@@ -112,7 +120,35 @@ func load(jwt:String) -> LoadResult {
112120
return .Success(header:header!, payload:payload!, signature:signature!, signatureInput:signatureInput)
113121
}
114122

115-
// MARK: Validation
123+
// MARK: Signature Verification
124+
125+
func verifySignature(header:Payload, signingInput:String, signature:NSData, key:String?) -> InvalidToken? {
126+
if let alg = header["alg"] as? String {
127+
switch alg {
128+
case "none":
129+
return nil
130+
case "HS256":
131+
if let key = key?.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) {
132+
let mac = Authenticator.HMAC(key: key, variant:.sha256)
133+
let result = mac.authenticate(signingInput.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!)
134+
if result! == signature {
135+
return nil
136+
} else {
137+
return .DecodeError("Signature verification failed")
138+
}
139+
}
140+
break
141+
default:
142+
break
143+
}
144+
145+
return .InvalidAlgorithm
146+
}
147+
148+
return .DecodeError("Missing Algorithm")
149+
}
150+
151+
// MARK: Claim Validation
116152

117153
func validateAudience(payload:Payload, audience:String?) -> InvalidToken? {
118154
if let audience = audience {

0 commit comments

Comments
 (0)