Skip to content
This repository was archived by the owner on May 20, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,8 @@ public void downloadPackage(JSONObject updatePackage, String expectedBundleFileN

if (isSignatureVerificationEnabled) {
if (isSignatureAppearedInBundle) {
CodePushUpdateUtils.verifySignature(newUpdateFolderPath, stringPublicKey);
CodePushUpdateUtils.verifyFolderHash(newUpdateFolderPath, newUpdateHash);
CodePushUpdateUtils.verifyUpdateSignature(newUpdateFolderPath, newUpdateHash, stringPublicKey);
} else {
throw new CodePushInvalidUpdateException(
"Error! Public key was provided but there is no JWT signature within app bundle to verify. " +
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,13 +172,15 @@ public static void verifyFolderHash(String folderPath, String expectedHash) {
if (!expectedHash.equals(updateContentsManifestHash)) {
throw new CodePushInvalidUpdateException("The update contents failed the data integrity check.");
}

CodePushUtils.log("The update contents succeeded the data integrity check.");
}

public static Map<String, Object> verifyAndDecodeJWT(String jwt, PublicKey publicKey) {
try {
final JWTVerifier verifier = new JWTVerifier(publicKey);
final Map<String, Object> claims = verifier.verify(jwt);
CodePushUtils.log("JWT verification succeeded:\n" + claims.toString());
CodePushUtils.log("JWT signature verification succeeded, payload content: " + claims.toString());
return claims;
} catch (Exception e) {
return null;
Expand Down Expand Up @@ -223,7 +225,7 @@ public static String getSignature(String folderPath) {
}
}

public static void verifySignature(String folderPath, String stringPublicKey) throws CodePushInvalidUpdateException {
public static void verifyUpdateSignature(String folderPath, String packageHash, String stringPublicKey) throws CodePushInvalidUpdateException {
CodePushUtils.log("Verifying signature for folder path: " + folderPath);

final PublicKey publicKey = parsePublicKey(stringPublicKey);
Expand All @@ -246,7 +248,11 @@ public static void verifySignature(String folderPath, String stringPublicKey) th
throw new CodePushInvalidUpdateException("The update could not be verified because the signature did not specify a content hash.");
}

CodePushUpdateUtils.verifyFolderHash(folderPath, contentHash);
if (!contentHash.equals(packageHash)) {
throw new CodePushInvalidUpdateException("The update contents failed the code signing check.");
}

CodePushUtils.log("The update contents succeeded the code signing check.");
}

}
7 changes: 4 additions & 3 deletions ios/CodePush/CodePush.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,10 @@ failCallback:(void (^)(NSError *err))failCallback;
withPublicKey:(NSString *)publicKey
error:(NSError **)error;

+ (BOOL)verifySignatureFor:(NSString *)updateFolderPath
withPublicKey:(NSString *)publicKey
error:(NSError **)error;
+ (BOOL)verifyUpdateSignatureFor:(NSString *)updateFolderPath
expectedHash:(NSString *)newUpdateHash
withPublicKey:(NSString *)publicKeyString
error:(NSError **)error;

@end

Expand Down
26 changes: 20 additions & 6 deletions ios/CodePush/CodePushPackage.m
Original file line number Diff line number Diff line change
Expand Up @@ -241,18 +241,32 @@ + (void)downloadPackage:(NSDictionary *)updatePackage

if (isSignatureVerificationEnabled) {
if (isSignatureAppearedInBundle) {
BOOL isSignatureValid = [CodePushUpdateUtils verifySignatureFor:newUpdateFolderPath
withPublicKey:publicKey
error:&error];
if (![CodePushUpdateUtils verifyFolderHash:newUpdateFolderPath
expectedHash:newUpdateHash
error:&error]) {
CPLog(@"The update contents failed the data integrity check.");
if (!error) {
error = [CodePushErrorUtils errorWithMessage:@"The update contents failed the data integrity check."];
}

failCallback(error);
return;
} else {
CPLog(@"The update contents succeeded the data integrity check.");
}
BOOL isSignatureValid = [CodePushUpdateUtils verifyUpdateSignatureFor:newUpdateFolderPath
expectedHash:newUpdateHash
withPublicKey:publicKey
error:&error];
if (!isSignatureValid) {
CPLog(@"Code signing integrity check error.");
CPLog(@"The update contents failed code signing check.");
if (!error) {
error = [CodePushErrorUtils errorWithMessage:@"Code signing integrity check error."];
error = [CodePushErrorUtils errorWithMessage:@"The update contents failed code signing check."];
}
failCallback(error);
return;
} else {
CPLog(@"The update contents succeeded the code signing integrity check.");
CPLog(@"The update contents succeeded the code signing check.");
}
} else {
error = [CodePushErrorUtils errorWithMessage:
Expand Down
13 changes: 7 additions & 6 deletions ios/CodePush/CodePushUpdateUtils.m
Original file line number Diff line number Diff line change
Expand Up @@ -335,9 +335,10 @@ + (NSDictionary *) verifyAndDecodeJWT:(NSString *)jwt
}
}

+ (BOOL)verifySignatureFor:(NSString *)folderPath
withPublicKey:(NSString *)publicKeyString
error:(NSError **)error
+ (BOOL)verifyUpdateSignatureFor:(NSString *)folderPath
expectedHash:(NSString *)newUpdateHash
withPublicKey:(NSString *)publicKeyString
error:(NSError **)error
{
NSLog(@"Verifying signature for folder path: %@", folderPath);

Expand All @@ -360,16 +361,16 @@ + (BOOL)verifySignatureFor:(NSString *)folderPath
return false;
}

CPLog(@"JWT signature verification succeeded, payload content: %@", envelopedPayload);

if(![envelopedPayload objectForKey:@"contentHash"]){
CPLog(@"The update could not be verified because the signature did not specify a content hash.");
return false;
}

NSString *contentHash = envelopedPayload[@"contentHash"];

return [self verifyFolderHash:folderPath
expectedHash:contentHash
error:error];
return [contentHash isEqualToString:newUpdateHash];
}

@end