@@ -4,18 +4,21 @@ import { parseFile } from 'bplist-parser';
4
4
import { createHash } from 'crypto' ;
5
5
import { execa } from 'execa' ;
6
6
import frida from 'frida' ;
7
- import { exists , mkdirp } from 'fs-extra' ;
8
- import { readFile , writeFile } from 'fs/promises' ;
7
+ import { exists , mkdirp } from 'fs-extra' ;
8
+ import { readFile , writeFile } from 'fs/promises' ;
9
9
import globalCacheDir from 'global-cache-dir' ;
10
10
import { NodeSSH } from 'node-ssh' ;
11
11
import { join } from 'path' ;
12
- import type { PlatformApi , PlatformApiOptions , Proxy , SupportedCapability , SupportedRunTarget } from '.' ;
12
+ import type { PlatformApi , PlatformApiOptions , Proxy , SupportedCapability , SupportedRunTarget } from '.' ;
13
13
import { venvOptions } from '../scripts/common/python' ;
14
- import { asyncUnimplemented , getObjFromFridaScript , isRecord , retryCondition } from './utils' ;
14
+ import { asyncUnimplemented , getObjFromFridaScript , isRecord , retryCondition } from './utils' ;
15
15
import {
16
16
arrayBufferToPem ,
17
+ asn1ValueToDer ,
17
18
certificateFingerprint ,
18
19
certificateHasExpired ,
20
+ certSubjectToAsn1 ,
21
+ createPkcs12Container ,
19
22
generateCertificate ,
20
23
parsePemCertificateFromFile ,
21
24
pemToArrayBuffer ,
@@ -170,53 +173,54 @@ export const iosApi = <RunTarget extends SupportedRunTarget<'ios'>>(
170
173
if ( ! plist ) throw new Error ( 'Failed to ensure supervision mode: Invalid CloudConfiguration.' ) ;
171
174
172
175
let hostCert ;
173
- let hostKey ;
174
176
175
177
if (
176
178
( await exists ( join ( cacheDir , 'ios' , 'supervisorCert.pem' ) ) ) &&
177
- ( await exists ( join ( cacheDir , 'ios' , 'supervisorPrivateKey.pem ' ) ) )
179
+ ( await exists ( join ( cacheDir , 'ios' , 'supervisorKeyStore.p12 ' ) ) )
178
180
) {
179
- hostCert = pemToArrayBuffer ( ( await readFile ( join ( cacheDir , 'ios' , 'supervisorCert.pem' ) ) ) . toString ( ) ) ;
180
- hostKey = pemToArrayBuffer (
181
- ( await readFile ( join ( cacheDir , 'ios' , 'supervisorPrivateKey.pem' ) ) ) . toString ( )
182
- ) ;
181
+ hostCert = ( await readFile ( join ( cacheDir , 'ios' , 'supervisorCert.pem' ) ) ) . toString ( ) ;
183
182
184
183
if ( ! ( await certificateHasExpired ( hostCert ) ) ) {
185
184
const hostCertFingerprint = await certificateFingerprint ( hostCert ) ;
186
185
187
- // Test if the current host certificate is already controlling the device.
188
- if (
189
- plist . IsSupervised &&
190
- plist . SupervisorHostCertificates &&
191
- plist . SupervisorHostCertificates . length > 0 &&
192
- plist . SupervisorHostCertificates . some (
193
- async ( cert ) => ( await certificateFingerprint ( cert ) ) === hostCertFingerprint
186
+ try {
187
+ // Test if the current host certificate is already controlling the device.
188
+ if (
189
+ plist . IsSupervised &&
190
+ plist . SupervisorHostCertificates &&
191
+ plist . SupervisorHostCertificates . length > 0 &&
192
+ plist . SupervisorHostCertificates . some (
193
+ ( cert ) =>
194
+ certificateFingerprint ( arrayBufferToPem ( cert , 'CERTIFICATE' ) ) ===
195
+ hostCertFingerprint
196
+ )
194
197
)
195
- )
196
- return ;
198
+ return ;
199
+ } catch ( e ) {
200
+ // The certificate is invalid, so we need to generate a new one.
201
+ hostCert = undefined ;
202
+ }
197
203
} else {
198
204
hostCert = undefined ;
199
- hostKey = undefined ;
200
205
}
201
206
}
202
207
203
- if ( ! hostCert || ! hostKey ) {
208
+ if ( ! hostCert ) {
204
209
// We have no exsiting keys, so let’s generate one.
205
210
const generated = await generateCertificate ( OrganizationName ) ;
206
211
hostCert = generated . certificate ;
207
- hostKey = generated . privateKey ;
212
+ const hostKey = generated . privateKey ;
213
+
214
+ const keyStore = createPkcs12Container ( hostCert , hostKey , 'appstraction' ) ;
208
215
209
216
await mkdirp ( join ( cacheDir , 'ios' ) ) ;
210
- await writeFile ( join ( cacheDir , 'ios' , 'supervisorCert.pem' ) , arrayBufferToPem ( hostCert , 'CERTIFICATE' ) ) ;
211
- await writeFile (
212
- join ( cacheDir , 'ios' , 'supervisorPrivateKey.pem' ) ,
213
- arrayBufferToPem ( hostKey , 'PRIVATE KEY' )
214
- ) ;
217
+ await writeFile ( join ( cacheDir , 'ios' , 'supervisorCert.pem' ) , hostCert ) ;
218
+ await writeFile ( join ( cacheDir , 'ios' , 'supervisorKeyStore.p12' ) , Buffer . from ( keyStore . toHex ( ) , 'hex' ) ) ;
215
219
}
216
220
217
221
const newPlist = {
218
222
...plist ,
219
- SupervisorHostCertificates : [ Buffer . from ( hostCert ) ] ,
223
+ SupervisorHostCertificates : [ Buffer . from ( pemToArrayBuffer ( hostCert ) ) ] ,
220
224
IsSupervised : true ,
221
225
OrganizationName,
222
226
AllowPairing : true ,
@@ -426,7 +430,7 @@ export const iosApi = <RunTarget extends SupportedRunTarget<'ios'>>(
426
430
const { cert, certDer } = await parsePemCertificateFromFile ( path ) ;
427
431
428
432
const sha256 = createHash ( 'sha256' ) . update ( certDer ) . digest ( 'hex' ) ;
429
- const subj = Buffer . from ( cert . subject . toSchema ( ) . valueBlock . toBER ( ) ) . toString ( 'hex' ) ;
433
+ const subj = asn1ValueToDer ( certSubjectToAsn1 ( cert ) ) . toHex ( ) ;
430
434
const tset = Buffer . from (
431
435
`<?xml version="1.0" encoding="UTF-8"?>
432
436
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
@@ -445,6 +449,7 @@ export const iosApi = <RunTarget extends SupportedRunTarget<'ios'>>(
445
449
throw new Error ( 'SSH is required for removing a certificate authority.' ) ;
446
450
447
451
const { certDer } = await parsePemCertificateFromFile ( path ) ;
452
+
448
453
const sha256 = createHash ( 'sha256' ) . update ( certDer ) . digest ( 'hex' ) ;
449
454
450
455
await this . _internal . ssh (
0 commit comments