danielpaulus / go-ios

This is an operating system independent implementation of iOS device features. You can run UI tests, launch or kill apps, install apps etc. with it.
MIT License
976 stars 184 forks source link

Adding http proxy doesn't work #423

Open dokisha opened 4 months ago

dokisha commented 4 months ago

Short story: Created certificate.p12 file that go-ios suggests doesn't work for adding http proxy.

Tried different ways of creating .p12 file and got different errors

Can anyone check what I'm doing wrong? What is the correct way of creating certificate.p12 file? There is one more opened bug, but i decided to give more info in this one.

Long story: Steps to reproduce the behavior:

  1. run the command
    
    go-ios prepare create-cert
    # output:
    {"level":"info","msg":"supervision-cert.der"}
    {"level":"info","msg":"supervision-cert.pem"}
    {"level":"info","msg":"supervision-private-key.key"}
    {"level":"info","msg":"supervision-private-key.pem"}
    {"level":"info","msg":"supervision-csr.csr","time"}
    {"level":"info","msg":"Golang does not have good PKCS12 format sadly. If you need a p12 file run this: 'openssl pkcs12 -export -inkey supervision-private-key.pem -in supervision-cert.pem -out certificate.p12 -password pass:a'"}
2. run the command 

openssl pkcs12 -export -inkey supervision-private-key.pem -in supervision-cert.pem -out certificate.p12 -password pass:a

this creates certificate.p12

3. run the command 

go-ios erase --udid

press y when asked and wait for device to be factory reseted

when device is rebooted, don't touch it, don't unlock it

4. run the command

go-ios activate --udid

output:

{"level":"info","msg":"device successfully activated"}


5. run the command 

go-ios prepare --skip-all --udid --certfile=/certificate.p12 --orgname=Test

output:

{"level":"info","msg":"device is activated:true"} {"level":"info","msg":"send flush request"} {"level":"info","msg":"get cloud config"} {"level":"info","msg":"supervising device"} "ok"%

6. Take the device into hand, connect to wifi when prompted, press "Agree" on terms => You are now on home screen

7. Open settings, you will see message "This iPhone is supervised and managed by Test"

8. run the command

go-ios httpproxy --udid 123.123.123.123 1234 usr123 pass123 --p12file=/certificate.p12 --password=a output: {"err":"pkcs12: unknown digest algorithm: 2.16.840.1.101.3.4.2.1","level":"fatal","msg":"failed"}


**Expected behavior**
httpproxy is added

**Desktop:**
 - OS: macOS, M1, Sonoma 14.3.1
 - OpenSSL 3.3.0 9 Apr 2024 (Library: OpenSSL 3.3.0 9 Apr 2024)

**Smartphone:**
 - Device: iphone 8, iOS Version 16.7.8
 - Device: iphone SE, iOS Version 17.3

**Additional context**
It seems like something is wrong with certificate.p12 file, so I repeated steps 2-8 with different openssl command in step 2:

### Try 1: create .p12 with SHA1 algorithm, different error

step 2: create .p12 openssl pkcs12 -export -inkey supervision-private-key.pem -in supervision-cert.pem -out certificate.p12 -password pass:a -macalg sha1

step 8: add http proxy, gives error: {"err":"pkcs12: algorithm 1.2.840.113549.1.5.13 is not supported","level":"fatal","msg":"failed"}


### Try 2: create .p12 with DES algorithm, better error

step 2: create .p12 openssl pkcs12 -export -inkey supervision-private-key.pem -in supervision-cert.pem -out certificate.p12 -password pass:a -certpbe PBE-SHA1-3DES -keypbe PBE-SHA1-3DES -macalg sha1

step 8: add http proxy {"err":"escalate response had error map[Status:CertificateRejected]","level":"fatal","msg":"failed"}

This seems like certificate.p12 is valid, but is not trusted by device? so I ran the command:

go-ios profile add /certificate.p12

open Settings, there is "Profile Downloaded", press on it (says its not signed), then "Install"

after installing it, it show under General => VPN & Device Management

This didn't help. Adding http proxy still gets Status:CertificateRejected
This gave me an idea that certificate.p12 file must also have Root cert trusted by iphone

Try 3: Signing the certificate.p12

openssl genrsa -out rootCA.key 2048

this creates: rootCA.key

openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 364 -out rootCA.pem -subj "/CN=Test/O=TestOrg/OU=TestUnit"

this creates: rootCA.pem

openssl genrsa -out server.key 2048

this creates: server.key

openssl req -new -key server.key -out server.csr -subj "/CN=Test/O=TestOrg/OU=TestUnit"

creates: server.csr

openssl x509 -req -in server.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out server.crt -days 365 -sha256

creates: server.crt

openssl pkcs12 -export -inkey server.key -in server.crt -certfile rootCA.pem -out certificate.p12 -password pass:a -certpbe PBE-SHA1-3DES -keypbe PBE-SHA1-3DES -macalg sha1

this creates: certificate.p12

Now I installed Root cert on iphone with 

go-ios profile add ./rootCA.pem

after installing it, enable it via General => About => Certificate Trust settings

But it didn't even get to trusting part, trying to add http proxy with newly created certificate.p12 gives error

go-ios httpproxy --udid 123.123.123.123 1234 usr123 pass123 --p12file=/certificate.p12 --password=a {"err":"pkcs12: expected exactly two safe bags in the PFX PDU","level":"fatal","msg":"failed"}



some people [commented out bag checking ](https://github.com/RobotsAndPencils/buford/issues/8)in pkcs12.go on [line 228 ](https://gitee.com/zhouhuodev/gmsm/blob/71cb6201d680/pkcs12/pkcs12.go) but i'm not even sure if that's the problem.

Looking at this [pkcs12.go source code](https://github.com/SSLMate/go-pkcs12/blob/master/pkcs12.go), it suggests using DecodeChain instead Decode on line 398, not sure what go-ios is using, and again if that's the problem.
dokisha commented 4 months ago

I have downgraded OpenSSL from 3.3.0 to 1.1.1 and now suggested openssl command produces .p12 that gets [Status:CertificateRejected] which seems like a progress

Steps:

go-ios prepare create-cert
openssl pkcs12 -export -inkey supervision-private-key.pem -in supervision-cert.pem -out certificate.p12 -password pass:a
go-ios erase
go-ios activate
go-ios prepare --skip-all --certfile=./certificate.p12 --orgname=Test -v
go-ios devmode enable
go-ios httpproxy 123.123.123.123 1234 usr123 pass123 --p12file=./certificate.p12 --password=a -v

{"err":"escalate response had error map[Status:CertificateRejected]","level":"fatal","msg":"failed"}

Am I missing a step? Now I'm just guessing, but why doesn't prepare need a .p12 password?

Here are debug logs for prepare step, it also logs CertificateRejected but finishes without error:

{"level":"info","msg":"Set Debug mode"}
{"level":"debug","msg":"map[--address:\u003cnil\u003e --all:false --apps:false --arg:[] --basedir:\u003cnil\u003e --binary:false --bundle-id:\u003cnil\u003e --bundleid:\u003cnil\u003e --certfile:./certificate.p12 --details:false --dstPath:\u003cnil\u003e --enable-post-restart:false --env:[] --filesharing:false --force:false --gpxfilepath:\u003cnil\u003e --help:false --iface:\u003cnil\u003e --lang:false --lat:\u003cnil\u003e --list:false --locale:false --log-output:\u003cnil\u003e --lon:\u003cnil\u003e --mode:\u003cnil\u003e --nojson:false --orgname:Test --output:\u003cnil\u003e --p12file:\u003cnil\u003e --pair-record-path:\u003cnil\u003e --password:\u003cnil\u003e --path:\u003cnil\u003e --pid:\u003cnil\u003e --plist:false --port:\u003cnil\u003e --pretty:false --process:\u003cnil\u003e --r:false --rsd-port:\u003cnil\u003e --setlang:\u003cnil\u003e --setlocale:\u003cnil\u003e --skip:[] --skip-all:true --srcPath:\u003cnil\u003e --stop-at-entry:false --stream:false --system:false --test-runner-bundle-id:\u003cnil\u003e --test-to-run:[] --test-to-skip:[] --testrunnerbundleid:\u003cnil\u003e --trace:false --tunnel-info-port:\u003cnil\u003e --udid:\u003cnil\u003e --verbose:true --version:false --wait:false --xctest-config:\u003cnil\u003e --xctestconfig:\u003cnil\u003e 12h:false 24h:false \u003capp_path\u003e:\u003cnil\u003e \u003cbundleID\u003e:\u003cnil\u003e \u003ccwd\u003e:\u003cnil\u003e \u003chost\u003e:\u003cnil\u003e \u003chostPort\u003e:\u003cnil\u003e \u003ckey\u003e:[] \u003cpass\u003e:\u003cnil\u003e \u003cpattern\u003e:\u003cnil\u003e \u003cport\u003e:\u003cnil\u003e \u003cprofileFile\u003e:\u003cnil\u003e \u003cprofileId\u003e:\u003cnil\u003e \u003cprofileName\u003e:\u003cnil\u003e \u003cprofileTypeId\u003e:\u003cnil\u003e \u003csrcpattern\u003e:\u003cnil\u003e \u003ctarget\u003e:\u003cnil\u003e \u003ctargetPort\u003e:\u003cnil\u003e \u003cuser\u003e:\u003cnil\u003e activate:false add:false apps:false assistivetouch:false auto:false ax:false batterycheck:false cp:false crash:false create-cert:false date:false debug:false devicename:false devicestate:false devmode:false diagnostics:false disable:false diskspace:false display:false dproxy:false enable:false erase:false forward:false fsync:false get:false httpproxy:false image:false info:false install:false instruments:false ip:false kill:false lang:false launch:false list:false listen:false lockdown:false ls:false mkdir:false mobilegestalt:false mount:false notifications:false pair:false pcap:false prepare:true printskip:false profile:false ps:false pull:false push:false readpair:false reboot:false remove:false resetlocation:false rm:false runtest:false runwda:false screenshot:false setlocation:false setlocationgpx:false start:false syslog:false timeformat:false toggle:false tree:false tunnel:false uninstall:false version:false voiceover:false zoomtouch:false]"}
{"level":"info","msg":"device is activated:true"}
{"EnableServiceSSL":true,"Port":50897,"Request":"StartService","Service":"com.apple.mobile.MCInstall","level":"debug","msg":"Service started on device"}
{"level":"info","msg":"send flush request"}
{"level":"debug","msg":"flush: map[Status:Acknowledged]"}
{"level":"info","msg":"get cloud config"}
{"level":"debug","msg":"get first cloudconfig: map[Status:Acknowledged]"}
{"level":"debug","msg":"hello response: map[Status:Acknowledged]"}
{"level":"info","msg":"supervising device"}
{"level":"debug","msg":"set cloud config: map[CloudConfiguration:map[AllowPairing:1 IsSupervised:true OrganizationName:Test SkipSetup:[Accessibility Android Appearance AppleID AppStore Biometric DeviceToDeviceMigration Diagnostics EnableLockdownMode FileVault iCloudDiagnostics iCloudStorage iMessageAndFaceTime Location MessagingActivationUsingPhoneNumber Passcode Payment Privacy Restore RestoreCompleted Safety ScreenSaver ScreenTime SIMSetup Siri SoftwareUpdate TapToSetup TermsOfAddress TVHomeScreenSync TVProviderSignIn TVRoom UpdateCompleted WatchMigration Welcome DisplayTone HomeButtonSensitivity OnBoarding Zoom] SupervisorHostCertificates:[..] RequestType:SetCloudConfiguration]"}
{"level":"debug","msg":"set response: map[Status:Acknowledged]"}
{"level":"debug","msg":"get cloud config"}
{"level":"debug","msg":"cloud config config: map[CloudConfiguration:map[AllowPairing:1 CloudConfigurationUIComplete:true ConfigurationSource:2 ConfigurationWasApplied:true IsMDMUnremovable:false IsMandatory:true IsSupervised:true OrganizationName:Test SkipSetup:[Accessibility Android Appearance AppleID AppStore Biometric DeviceToDeviceMigration Diagnostics EnableLockdownMode FileVault iCloudDiagnostics iCloudStorage iMessageAndFaceTime Location MessagingActivationUsingPhoneNumber Passcode Payment Privacy Restore RestoreCompleted Safety ScreenSaver ScreenTime SIMSetup Siri SoftwareUpdate TapToSetup TermsOfAddress TVHomeScreenSync TVProviderSignIn TVRoom UpdateCompleted WatchMigration Welcome DisplayTone HomeButtonSensitivity OnBoarding Zoom] SupervisorHostCertificates:[..] Status:Acknowledged]"}
{"level":"debug","msg":"escalate response had error map[Status:CertificateRejected]"}
{"level":"debug","msg":"Setting locale: en_US"}
{"level":"debug","msg":"Setting language: en"}
{"EnableServiceSSL":false,"Port":50906,"Request":"StartService","Service":"com.apple.afc","level":"debug","msg":"Service started on device"}
{"level":"debug","msg":"skip setup: nothing to remove"}
{"level":"debug","msg":"list of files [. .. SkipSetup MediaLibrary.sqlitedb MediaLibrary.sqlitedb-wal MediaLibrary.sqlitedb-shm IC-Info.sidv]"}

Here are debug logs for httpproxy step:

{"EnableServiceSSL":true,"Port":49326,"Request":"StartService","Service":"com.apple.mobile.MCInstall","level":"debug","msg":"Service started on device"}
{"err":"escalate response had error map[Status:CertificateRejected]","level":"fatal","msg":"failed"}
dokisha commented 3 months ago

No matter how I create .p12, best I can get is CertificateRejected Even If i include CA in p12, comment out bag checking in pkcs12.go, it ends up with CertificateRejected

I've also generated iOS Development cert by apple developer portal, converted it to .p12 and did steps 3-8 again with it, and it also gets CertificateRejected

Also tried to prepare device with Apple Development and Apple Push Services certificates generated by portal, they also get rejected when executing go-ios httpproxy

Tried on mac, linux and 5 different iphone devices (ios15/16/17)

dokisha commented 3 months ago

I've tried to debug setproxy.go file and these are rough steps through functions where it goes wrong:

SetHttpProxy 
=> setUpProfile 
=> InstallProfileSilent 
=> profileService.AddProfileSupervised 
=> mcInstallConn.Escalate 
=> pkcs12.Decode 
=> mcInstallConn.EscalateWithCertAndKey 
=> mcInstallConn.sendAndReceive 
=> checkStatus => this function returns `dict` with value "CertificateRejected"

So function AddProfileSupervised fails and doesn't proceed to addProfile because Escalate failed, as if device was prepared with completely different cert.

I'm basically out of my depth here, not sure if prepare is wrong or escalate or something else.

Can anyone help?