Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

extract the plist via ASN1 parser #4

Merged
merged 6 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
59 changes: 50 additions & 9 deletions EmbeddedProvision.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,26 @@

/* Begin PBXBuildFile section */
59799E312746587000BFB375 /* EmbeddedProvision.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59799E302746587000BFB375 /* EmbeddedProvision.swift */; };
59EF99BC27446D6900FB2378 /* EmbeddedProvision.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 59EF99B127446D6900FB2378 /* EmbeddedProvision.framework */; };
59EF99C127446D6900FB2378 /* EmbeddedProvisionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59EF99C027446D6900FB2378 /* EmbeddedProvisionTests.swift */; };
9400259F2CC12857000C9264 /* Entitlements.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9400259E2CC12857000C9264 /* Entitlements.swift */; };
940025A02CC12857000C9264 /* Entitlements.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9400259E2CC12857000C9264 /* Entitlements.swift */; };
94691DA22CBFDE900046785A /* APSEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94691DA12CBFDE900046785A /* APSEnvironment.swift */; };
94691DA32CBFDE900046785A /* APSEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94691DA12CBFDE900046785A /* APSEnvironment.swift */; };
94691DAC2CBFFAC80046785A /* embedded.mobileprovision in Resources */ = {isa = PBXBuildFile; fileRef = 94691DA42CBFE83D0046785A /* embedded.mobileprovision */; };
94691DAF2CC001190046785A /* Bundle+Testing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94691DAE2CC001190046785A /* Bundle+Testing.swift */; };
9D71CE412CC1C3E800970263 /* ASN1Decoder in Frameworks */ = {isa = PBXBuildFile; productRef = 9D71CE402CC1C3E800970263 /* ASN1Decoder */; };
9D71CE432CC1C7E700970263 /* ASN1Decoder in Frameworks */ = {isa = PBXBuildFile; productRef = 9D71CE422CC1C7E700970263 /* ASN1Decoder */; };
9D71CE462CC1C81000970263 /* EmbeddedProvision.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2D2163227AC276700A104B8 /* EmbeddedProvision.framework */; };
D2D2161227AC276700A104B8 /* EmbeddedProvision.swift in Sources */ = {isa = PBXBuildFile; fileRef = 59799E302746587000BFB375 /* EmbeddedProvision.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
59EF99BD27446D6900FB2378 /* PBXContainerItemProxy */ = {
9D71CE482CC1C81000970263 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 59EF99A827446D6900FB2378 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 59EF99B027446D6900FB2378;
remoteInfo = MagicBell;
remoteGlobalIDString = D2D215DA27AC276700A104B8;
remoteInfo = "EmbeddedProvision-macOS";
};
/* End PBXContainerItemProxy section */

Expand Down Expand Up @@ -72,21 +74,23 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
9D71CE432CC1C7E700970263 /* ASN1Decoder in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
59EF99B827446D6900FB2378 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
59EF99BC27446D6900FB2378 /* EmbeddedProvision.framework in Frameworks */,
9D71CE462CC1C81000970263 /* EmbeddedProvision.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
D2D2162427AC276700A104B8 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
9D71CE412CC1C3E800970263 /* ASN1Decoder in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -101,6 +105,7 @@
D280727827A2E40C00FD941A /* EmbeddedProvision.podspec */,
59EF9AC6274471A500FB2378 /* Source */,
59EF99BF27446D6900FB2378 /* Tests */,
9D71CE3F2CC1C3E800970263 /* Frameworks */,
59EF99B227446D6900FB2378 /* Products */,
);
sourceTree = "<group>";
Expand Down Expand Up @@ -135,6 +140,13 @@
path = Source;
sourceTree = "<group>";
};
9D71CE3F2CC1C3E800970263 /* Frameworks */ = {
isa = PBXGroup;
children = (
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXHeadersBuildPhase section */
Expand Down Expand Up @@ -185,7 +197,7 @@
buildRules = (
);
dependencies = (
59EF99BE27446D6900FB2378 /* PBXTargetDependency */,
9D71CE492CC1C81000970263 /* PBXTargetDependency */,
);
name = EmbeddedProvisionTests;
productName = MagicBellTests;
Expand Down Expand Up @@ -238,6 +250,9 @@
Base,
);
mainGroup = 59EF99A727446D6900FB2378;
packageReferences = (
9D71CE3C2CC1C37700970263 /* XCRemoteSwiftPackageReference "ASN1Decoder" */,
);
productRefGroup = 59EF99B227446D6900FB2378 /* Products */;
projectDirPath = "";
projectRoot = "";
Expand Down Expand Up @@ -307,10 +322,10 @@
/* End PBXSourcesBuildPhase section */

/* Begin PBXTargetDependency section */
59EF99BE27446D6900FB2378 /* PBXTargetDependency */ = {
9D71CE492CC1C81000970263 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 59EF99B027446D6900FB2378 /* EmbeddedProvision-iOS */;
targetProxy = 59EF99BD27446D6900FB2378 /* PBXContainerItemProxy */;
target = D2D215DA27AC276700A104B8 /* EmbeddedProvision-macOS */;
targetProxy = 9D71CE482CC1C81000970263 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */

Expand Down Expand Up @@ -500,6 +515,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
Expand All @@ -522,6 +538,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
Expand Down Expand Up @@ -639,6 +656,30 @@
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */

/* Begin XCRemoteSwiftPackageReference section */
9D71CE3C2CC1C37700970263 /* XCRemoteSwiftPackageReference "ASN1Decoder" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/filom/ASN1Decoder";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 1.10.0;
};
};
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
9D71CE402CC1C3E800970263 /* ASN1Decoder */ = {
isa = XCSwiftPackageProductDependency;
package = 9D71CE3C2CC1C37700970263 /* XCRemoteSwiftPackageReference "ASN1Decoder" */;
productName = ASN1Decoder;
};
9D71CE422CC1C7E700970263 /* ASN1Decoder */ = {
isa = XCSwiftPackageProductDependency;
package = 9D71CE3C2CC1C37700970263 /* XCRemoteSwiftPackageReference "ASN1Decoder" */;
productName = ASN1Decoder;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 59EF99A827446D6900FB2378 /* Project object */;
}
20 changes: 14 additions & 6 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,30 @@ let package = Package(
name: "EmbeddedProvision",
platforms: [
.iOS(.v12),
.macOS(.v10_15)
.macOS(.v10_15),
],
products: [
.library(
name: "EmbeddedProvision",
targets: ["EmbeddedProvision"]
),
)
stigi marked this conversation as resolved.
Show resolved Hide resolved
],
dependencies: [
.package(url: "https://github.com/filom/ASN1Decoder", from: "1.10.0")
],
targets: [
.target(
name: "EmbeddedProvision",
dependencies: ["ASN1Decoder"],
path: "Source"
),
.testTarget(name: "EmbeddedProvisionTests",
dependencies: [ "EmbeddedProvision" ],
path: "Tests",
resources: [ .copy("embedded.mobileprovision") ])
.testTarget(
name: "EmbeddedProvisionTests",
dependencies: [
"EmbeddedProvision",
"ASN1Decoder",
],
path: "Tests",
resources: [.copy("embedded.mobileprovision")]),
]
)
43 changes: 34 additions & 9 deletions Source/EmbeddedProvision.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import ASN1Decoder
import Foundation

// import Security

Comment on lines +4 to +5
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like some leftover

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I have some code to check the code signing certificate to see if it's a testflight build - but I left that out for now.

// Inspired by Expo
// https://github.com/expo/expo/blob/c158ef23812c2995f326c51565b189e234948885/packages/expo-application/ios/EXApplication/EXProvisioningProfile.m#L28 (MIT License)
// and https://github.com/doneservices/ApsEnvironment/blob/221afddd19be77f9a5a943be637a8cc7e9dfeb94/Sources/ApsEnvironment/ApsEnvironment.swift#L4 (MIT License)
Expand All @@ -17,7 +20,7 @@ public struct EmbeddedProvision: Decodable {
public let expirationDate: Date
public let entitlements: Entitlements

private enum CodingKeys : String, CodingKey {
private enum CodingKeys: String, CodingKey {
case name = "Name"
case appIDName = "AppIDName"
case platform = "Platform"
Expand All @@ -32,7 +35,8 @@ extension EmbeddedProvision {
public static func guessEmbeddedProvisionProfileURL() -> URL? {
// [TN3125 - Profile Location](https://developer.apple.com/documentation/technotes/tn3125-inside-code-signing-provisioning-profiles#Profile-location)
let iOSURL = Bundle.main.url(forResource: "embedded", withExtension: "mobileprovision")
let macOSURL = Bundle.main.url(forResource: "embedded", withExtension:"provisionprofile", subdirectory: "Contents")
let macOSURL = Bundle.main.url(
forResource: "embedded", withExtension: "provisionprofile", subdirectory: "Contents")
return iOSURL ?? macOSURL
}

Expand All @@ -42,15 +46,36 @@ extension EmbeddedProvision {
}

public static func load(from profileURL: URL) throws -> EmbeddedProvision {
// The provisioning profile is contained as plain text in a signed plist.
// We're not (yet?) validating the signature, but are simply extracting the plist XML data.
guard
let data = try? Data(contentsOf: profileURL),
let open = data.range(of: "<plist".data(using: .ascii)!),
let close = data.range(of: "</plist>".data(using: .ascii)!, options: [], in: open.lowerBound..<data.endIndex),
let mobileProvision = try? PropertyListDecoder().decode(EmbeddedProvision.self, from: data[open.lowerBound..<close.upperBound]) else {

guard let data = try? Data(contentsOf: profileURL) else {
throw EmbeddedProvisionError.decodingError
}

guard let pkcs7 = try? PKCS7(data: data) else {
throw EmbeddedProvisionError.decodingError
}

let mainBlock = pkcs7.mainBlock

guard let block = mainBlock.findOid(.pkcs7data) else {
throw EmbeddedProvisionError.decodingError
}

guard let octetStringBlock = block.parent?.sub(1)?.sub(0) else {
throw EmbeddedProvisionError.decodingError
}

guard let xmlString = octetStringBlock.value as? String else {
throw EmbeddedProvisionError.decodingError
}

guard let plistData = xmlString.data(using: .utf8) else {
throw EmbeddedProvisionError.decodingError
}

let mobileProvision = try PropertyListDecoder().decode(
EmbeddedProvision.self, from: plistData)

return mobileProvision
}
}
7 changes: 4 additions & 3 deletions Tests/EmbeddedProvisionTests.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Testing
import Foundation
import Testing

@testable import EmbeddedProvision

let existingProvisionURL: URL = {
Expand Down Expand Up @@ -60,12 +61,12 @@ struct EmbeddedProvisionProperties {

@Test("parses creationDate")
func creationDate() throws {
#expect(provision.creationDate.timeIntervalSince1970 == 1729244250)
#expect(provision.creationDate.timeIntervalSince1970 == 1_729_244_250)
}

@Test("parses expirationDate")
func expirationDate() throws {
#expect(provision.expirationDate.timeIntervalSince1970 == 1760780250)
#expect(provision.expirationDate.timeIntervalSince1970 == 1_760_780_250)
}
}

Expand Down
6 changes: 4 additions & 2 deletions example/EmbeddedProvisionExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 18.1;
IPHONEOS_DEPLOYMENT_TARGET = 18.0;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
Expand Down Expand Up @@ -243,7 +243,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 18.1;
IPHONEOS_DEPLOYMENT_TARGET = 18.0;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
Expand All @@ -269,6 +269,7 @@
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 18.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down Expand Up @@ -298,6 +299,7 @@
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 18.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down
Loading