-
-
Notifications
You must be signed in to change notification settings - Fork 161
/
pair.go
132 lines (118 loc) · 3.4 KB
/
pair.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package ios
import (
"bytes"
"errors"
"fmt"
"strings"
"github.com/google/uuid"
plist "howett.net/plist"
)
//Pair tries to pair with a device. The first time usually
//fails because the user has to accept a trust pop up on the iOS device.
// What you have to do to pair is:
// 1. run the Pair() function
// 2. accept the trust pop up on the device
// 3. run the Pair() function a second time
func Pair(device DeviceEntry) error {
usbmuxConn, err := NewUsbMuxConnectionSimple()
if err != nil {
return err
}
defer usbmuxConn.Close()
buid, err := usbmuxConn.ReadBuid()
if err != nil {
return err
}
lockdown, err := usbmuxConn.ConnectLockdown(device.DeviceID)
if err != nil {
return err
}
publicKey, err := lockdown.GetValue("DevicePublicKey")
if err != nil {
return err
}
wifiMac, err := lockdown.GetValue("WiFiAddress")
if err != nil {
return err
}
rootCert, hostCert, deviceCert, rootPrivateKey, hostPrivateKey, err := createRootCertificate(publicKey.([]byte))
if err != nil {
return fmt.Errorf("Failed creating pair record with error: %v", err)
}
pairRecordData := newFullPairRecordData(buid, hostCert, rootCert, deviceCert)
request := newLockDownPairRequest(pairRecordData)
err = lockdown.Send(request)
if err != nil {
return err
}
resp, err := lockdown.ReadMessage()
if err != nil {
return err
}
response := getLockdownPairResponsefromBytes(resp)
if isPairingDialogOpen(response) {
return fmt.Errorf("Please accept the PairingDialog on the device and run pairing again!")
}
if response.Error != "" {
return fmt.Errorf("Lockdown error: %s", response.Error)
}
usbmuxConn, err = NewUsbMuxConnectionSimple()
defer usbmuxConn.Close()
if err != nil {
return err
}
success, err := usbmuxConn.savePair(device.Properties.SerialNumber, deviceCert, hostPrivateKey, hostCert, rootPrivateKey, rootCert, response.EscrowBag, wifiMac.(string), pairRecordData.HostID, buid)
if !success || err != nil {
return errors.New("Saving the PairRecord to usbmux failed")
}
return nil
}
type FullPairRecordData struct {
DeviceCertificate []byte
HostCertificate []byte
RootCertificate []byte
SystemBUID string
HostID string
}
type PairingOptions struct {
ExtendedPairingErrors bool
}
type LockDownPairRequest struct {
Label string
PairRecord FullPairRecordData
Request string
ProtocolVersion string
PairingOptions PairingOptions
}
type LockdownPairResponse struct {
Error string
Request string
EscrowBag []byte
}
func getLockdownPairResponsefromBytes(plistBytes []byte) *LockdownPairResponse {
decoder := plist.NewDecoder(bytes.NewReader(plistBytes))
var data LockdownPairResponse
_ = decoder.Decode(&data)
return &data
}
func isPairingDialogOpen(resp *LockdownPairResponse) bool {
return resp.Error == "PairingDialogResponsePending"
}
func newLockDownPairRequest(pairRecord FullPairRecordData) LockDownPairRequest {
var req LockDownPairRequest
req.Label = "go-ios"
req.PairingOptions = PairingOptions{true}
req.Request = "Pair"
req.ProtocolVersion = "2"
req.PairRecord = (pairRecord)
return req
}
func newFullPairRecordData(systemBuid string, hostCert []byte, rootCert []byte, deviceCert []byte) FullPairRecordData {
var data FullPairRecordData
data.SystemBUID = systemBuid
data.HostID = strings.ToUpper(uuid.New().String())
data.RootCertificate = rootCert
data.HostCertificate = hostCert
data.DeviceCertificate = deviceCert
return data
}