public static void ResignExecutable(MachObjectFile file, string bundleIdentifier, List <X509Certificate> certificateChain, AsymmetricKeyEntry privateKey, byte[] infoFileBytes, byte[] codeResourcesBytes, EntitlementsFile entitlements) { X509Certificate signingCertificate = certificateChain[certificateChain.Count - 1]; string certificateCN = CertificateHelper.GetCertificateCommonName(signingCertificate); string teamID = CertificateHelper.GetCertificateOrganizationalUnit(signingCertificate); SegmentCommand linkEditSegment = SegmentCommandHelper.FindLinkEditSegment(file.LoadCommands); if (linkEditSegment == null) { throw new InvalidDataException("LinkEdit segment was not found"); } if (file.LoadCommands[file.LoadCommands.Count - 1].CommandType != LoadCommandType.CodeSignature) { throw new NotImplementedException("The last LoadCommand entry is not CodeSignature"); } CodeSignatureCommand command = (CodeSignatureCommand)file.LoadCommands[file.LoadCommands.Count - 1]; int codeLength = (int)command.DataOffset; CodeDirectoryBlob codeDirectory = CreateCodeDirectoryBlob(codeLength, bundleIdentifier, teamID, HashType.SHA1); AttributeTable signedAttributesTable = null; #if ALT_CODE_DIRECTORY_SHA256 CodeDirectoryBlob alternativeCodeDirectory1 = CreateCodeDirectoryBlob(codeLength, bundleIdentifier, teamID, HashType.SHA256); signedAttributesTable = GenerateSignedAttributesTable(codeDirectory.GetBytes(), alternativeCodeDirectory1.GetBytes()); #endif CodeRequirementsBlob codeRequirements = CreateCodeRequirementsBlob(bundleIdentifier, certificateCN); EntitlementsBlob entitlementsBlob = CreateEntitlementsBlob(entitlements); CmsSignatureBlob cmsSignature = new CmsSignatureBlob(); // We create a dummy signature to determine the length required cmsSignature.Data = CMSHelper.GenerateSignature(certificateChain, privateKey, codeDirectory.GetBytes(), signedAttributesTable); CodeSignatureSuperBlob codeSignature = new CodeSignatureSuperBlob(); codeSignature.Entries.Add(CodeSignatureEntryType.CodeDirectory, codeDirectory); codeSignature.Entries.Add(CodeSignatureEntryType.Requirements, codeRequirements); codeSignature.Entries.Add(CodeSignatureEntryType.Entitlements, entitlementsBlob); #if ALT_CODE_DIRECTORY_SHA256 codeSignature.Entries.Add(CodeSignatureEntryType.AlternateCodeDirectory1, alternativeCodeDirectory1); #endif codeSignature.Entries.Add(CodeSignatureEntryType.CmsSignature, cmsSignature); command.DataSize = (uint)codeSignature.Length; uint finalFileSize = command.DataOffset + command.DataSize; SegmentCommandHelper.SetEndOffset(linkEditSegment, finalFileSize); byte[] codeToHash = ByteReader.ReadBytes(file.GetBytes(), 0, codeLength); UpdateSpecialHashes(codeDirectory, codeToHash, infoFileBytes, codeRequirements, codeResourcesBytes, entitlementsBlob); #if ALT_CODE_DIRECTORY_SHA256 UpdateSpecialHashes(alternativeCodeDirectory1, codeToHash, infoFileBytes, codeRequirements, codeResourcesBytes, entitlementsBlob); signedAttributesTable = GenerateSignedAttributesTable(codeDirectory.GetBytes(), alternativeCodeDirectory1.GetBytes()); #endif cmsSignature.Data = CMSHelper.GenerateSignature(certificateChain, privateKey, codeDirectory.GetBytes(), signedAttributesTable); // Store updated code signature: byte[] codeSignatureBytes = codeSignature.GetBytes(); Array.Resize <byte>(ref file.Data, (codeLength - file.DataOffset) + (int)command.DataSize); ByteWriter.WriteBytes(file.Data, (int)command.DataOffset - file.DataOffset, codeSignatureBytes); }
public static bool ValidateSpecialHashes(MachObjectFile file, byte[] infoFileBytes, byte[] codeResourcesBytes) { byte[] codeSignatureBytes = file.GetCodeSignatureBytes(); if (CodeSignatureSuperBlob.IsCodeSignatureSuperBlob(codeSignatureBytes, 0)) { CodeSignatureSuperBlob codeSignature = new CodeSignatureSuperBlob(codeSignatureBytes, 0); CodeDirectoryBlob codeDirectory = codeSignature.GetEntry(CodeSignatureEntryType.CodeDirectory) as CodeDirectoryBlob; byte[] infoFileHash = HashAlgorithmHelper.ComputeHash(codeDirectory.HashType, infoFileBytes); if (!ByteUtils.AreByteArraysEqual(infoFileHash, codeDirectory.SpecialHashes[codeDirectory.SpecialHashes.Count - CodeDirectoryBlob.InfoFileHashOffset])) { return(false); } byte[] codeResourcesHash = HashAlgorithmHelper.ComputeHash(codeDirectory.HashType, codeResourcesBytes); if (!ByteUtils.AreByteArraysEqual(codeResourcesHash, codeDirectory.SpecialHashes[codeDirectory.SpecialHashes.Count - CodeDirectoryBlob.CodeResourcesFileHashOffset])) { return(false); } CodeRequirementsBlob codeRequirements = codeSignature.GetEntry(CodeSignatureEntryType.Requirements) as CodeRequirementsBlob; byte[] codeRequirementsBytes = codeRequirements.GetBytes(); byte[] codeRequirementsHash = HashAlgorithmHelper.ComputeHash(codeDirectory.HashType, codeRequirementsBytes); if (!ByteUtils.AreByteArraysEqual(codeRequirementsHash, codeDirectory.SpecialHashes[codeDirectory.SpecialHashes.Count - CodeDirectoryBlob.RequirementsHashOffset])) { return(false); } if (codeDirectory.SpecialHashes.Count >= CodeDirectoryBlob.EntitlementsHashOffset) { CodeSignatureGenericBlob entitlements = codeSignature.GetEntry(CodeSignatureEntryType.Entitlements) as CodeSignatureGenericBlob; byte[] entitlementsBytes = entitlements.GetBytes(); byte[] entitlementsHash = HashAlgorithmHelper.ComputeHash(codeDirectory.HashType, entitlementsBytes); if (!ByteUtils.AreByteArraysEqual(entitlementsHash, codeDirectory.SpecialHashes[codeDirectory.SpecialHashes.Count - CodeDirectoryBlob.EntitlementsHashOffset])) { return(false); } } return(true); } return(false); }
public static CodeRequirementsBlob CreateCodeRequirementsBlob(string ident, string certificateCN) { CodeRequirementsBlob codeRequirements = new CodeRequirementsBlob(); CodeRequirementBlob codeRequirement = new CodeRequirementBlob(); codeRequirements.Entries.Add(SecurityRequirementType.DesignatedRequirementType, codeRequirement); IdentValue identValue = new IdentValue(ident); AppleGenericAnchor appleGenericAnchor = new AppleGenericAnchor(); CertificateField certificateField = new CertificateField(); certificateField.CertificateIndex = 0; certificateField.FieldName = "subject.CN"; certificateField.Match = new MatchSuffix(MatchOperationName.Equal, certificateCN); CertificateGeneric certificateGeneric = new CertificateGeneric(); certificateGeneric.CertificateIndex = 1; certificateGeneric.OID = APPLE_IOS_OID; certificateGeneric.Match = new MatchSuffix(MatchOperationName.Exists); codeRequirement.Expression = new AndExpression(identValue, new AndExpression(appleGenericAnchor, new AndExpression(certificateField, certificateGeneric))); return(codeRequirements); }
public static void UpdateHashes(CodeDirectoryBlob codeDirectory, byte[] codeToHash, byte[] infoFileBytes, CodeRequirementsBlob codeRequirements, byte[] codeResourcesBytes, EntitlementsBlob entitlements) { codeDirectory.CodeHashes = HashAlgorithmHelper.ComputeHashes(codeDirectory.HashType, codeDirectory.PageSize, codeToHash); codeDirectory.SpecialHashes = new List <byte[]>(); codeDirectory.SpecialHashes.Insert(0, (HashAlgorithmHelper.ComputeHash(codeDirectory.HashType, infoFileBytes))); codeDirectory.SpecialHashes.Insert(0, (HashAlgorithmHelper.ComputeHash(codeDirectory.HashType, codeRequirements.GetBytes()))); codeDirectory.SpecialHashes.Insert(0, (HashAlgorithmHelper.ComputeHash(codeDirectory.HashType, codeResourcesBytes))); if (SpecialHashCount >= CodeDirectoryBlob.ApplicationSpecificHashOffset) { codeDirectory.SpecialHashes.Insert(0, new byte[HashAlgorithmHelper.GetHashLength(codeDirectory.HashType)]); if (SpecialHashCount >= CodeDirectoryBlob.EntitlementsHashOffset) { codeDirectory.SpecialHashes.Insert(0, (HashAlgorithmHelper.ComputeHash(codeDirectory.HashType, entitlements.GetBytes()))); } } }