Add double hash checking support for code signing (#1005)

Add double hash checking support for code signing for both android and ios SDK
This commit is contained in:
Ruslan Bikkinin
2017-09-18 13:37:44 +03:00
committed by GitHub
parent 32f82e6050
commit e1cdd90e4e
5 changed files with 43 additions and 20 deletions

View File

@@ -257,7 +257,8 @@ public class CodePushUpdateManager {
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. " +

View File

@@ -176,6 +176,8 @@ public class CodePushUpdateUtils {
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) {
@@ -184,7 +186,7 @@ public class CodePushUpdateUtils {
JWSVerifier verifier = new RSASSAVerifier((RSAPublicKey)publicKey);
if (signedJWT.verify(verifier)) {
Map<String, Object> claims = signedJWT.getJWTClaimsSet().getClaims();
CodePushUtils.log("JWT verification succeeded:\n" + claims.toString());
CodePushUtils.log("JWT verification succeeded, payload content: " + claims.toString());
return claims;
}
return null;
@@ -233,7 +235,7 @@ public class CodePushUpdateUtils {
}
}
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);
@@ -256,6 +258,10 @@ public class CodePushUpdateUtils {
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.");
}
}

View File

@@ -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

View File

@@ -241,18 +241,32 @@ static NSString *const UnzippedFolderName = @"unzipped";
if (isSignatureVerificationEnabled) {
if (isSignatureAppearedInBundle) {
BOOL isSignatureValid = [CodePushUpdateUtils verifySignatureFor:newUpdateFolderPath
withPublicKey:publicKey
error:&error];
if (!isSignatureValid) {
CPLog(@"Code signing integrity check error.");
if (![CodePushUpdateUtils verifyFolderHash:newUpdateFolderPath
expectedHash:newUpdateHash
error:&error]) {
CPLog(@"The update contents failed the data integrity check.");
if (!error) {
error = [CodePushErrorUtils errorWithMessage:@"Code signing integrity check 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(@"The update contents failed code signing check.");
if (!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:

View File

@@ -335,9 +335,10 @@ NSString * const IgnoreCodePushMetadata = @".codepushrelease";
}
}
+ (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);
@@ -360,6 +361,8 @@ NSString * const IgnoreCodePushMetadata = @".codepushrelease";
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;
@@ -367,9 +370,7 @@ NSString * const IgnoreCodePushMetadata = @".codepushrelease";
NSString *contentHash = envelopedPayload[@"contentHash"];
return [self verifyFolderHash:folderPath
expectedHash:contentHash
error:error];
return [contentHash isEqualToString:newUpdateHash];
}
@end