-
Notifications
You must be signed in to change notification settings - Fork 5
/
main.go
225 lines (194 loc) · 5.97 KB
/
main.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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
package main
import (
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"log"
"math/rand"
"net/http"
"os"
"strconv"
"time"
"github.com/google/uuid"
"github.com/ubirch/ubirch-protocol-sim/go/ubirch"
"go.bug.st/serial"
)
func main() {
log.Println("SIM Interface Example")
if len(os.Args) < 3 {
log.Println("usage: main <port> <baudrate>")
os.Exit(0)
}
port := os.Args[1]
baud, err := strconv.Atoi(os.Args[2])
if err != nil {
log.Printf("baud rate must be integer: %s\n", os.Args[2])
os.Exit(1)
}
// load configuration from file
conf := Config{}
err = conf.Load("config.json")
if err != nil {
log.Fatalf("loading configuration failed: %v", err)
}
mode := &serial.Mode{
BaudRate: baud,
Parity: serial.NoParity,
DataBits: 8,
StopBits: serial.OneStopBit,
}
s, err := serial.Open(port, mode)
if err != nil {
log.Printf("serial port open failed: %v\n", err)
os.Exit(1)
}
serialPort := ubirch.SimSerialPort{Port: s, Debug: conf.Debug}
//noinspection GoUnhandledErrorResult
defer serialPort.Close()
serialPort.Init()
// get SIM IMSI
imsi, err := serialPort.GetIMSI()
if err != nil {
log.Fatalf("getting IMSI failed: %v", err)
}
log.Printf("IMSI: %s", imsi)
// check if PIN is set in config and bootstrap if unset
PIN := conf.Pin
if PIN == "" {
PIN, err = getPIN(imsi, conf)
if err != nil {
log.Fatalf("bootstrapping failed: %v", err)
}
}
sim := ubirch.Protocol{SimInterface: &serialPort, Debug: conf.Debug}
//noinspection GoUnhandledErrorResult
defer sim.Deinit()
// initialize the ubirch protocol sim interface
err = sim.Init(PIN)
if err != nil {
log.Fatalf("initialization failed: %v", err)
}
key_name := "ukey"
cert_name := "ucrt"
//// generate a key pair !!overwrites existing keys!!
//uuidBytes, err := hex.DecodeString(conf.Uuid)
//if err != nil {
// log.Fatalf("failed to decode hex string: %v", err)
//}
//uid, err := uuid.FromBytes(uuidBytes)
//if err != nil {
// log.Fatalf("failed to parse UUID: %v", err)
//}
//err = sim.GenerateKey(key_name, uid)
//if err != nil {
// log.Printf("generating key \"%s\" failed: %v", key_name, err)
//}
// get the UUID associated with the key entry ID
uid, err := sim.GetUUID(key_name)
if err != nil {
log.Fatalf("getting UUID from entry \"%s\" failed: %s", key_name, err)
}
log.Printf("UUID: %s", uid.String())
// get the public key from SIM card
key, err := sim.GetKey(key_name)
if err != nil {
log.Fatalf("getting key %s failed: %v", key_name, err)
}
log.Printf("public key [base64]: %s", base64.StdEncoding.EncodeToString(key))
// create a X.509 certificate signing request (CSR)
csr, err := sim.GenerateCSR(key_name)
if err != nil {
log.Fatalf("unable to create CSR: %v", err)
}
log.Printf("X.509 CSR: " + hex.EncodeToString(csr))
// get X.509 certificate from SIM card
cert, err := sim.GetCertificate(cert_name)
if err != nil {
log.Fatalf("retrieving certificate from SIM failed. %s", err)
}
log.Printf("X.509 certificate: %x", cert)
// send a signed message
type Payload struct {
Timestamp int
ID string
Value int
}
p := Payload{int(time.Now().Unix()), uid.String(), int(rand.Uint32())}
pRendered, err := json.Marshal(p)
if err != nil {
log.Fatalf("can't render payload as json: %v", err)
}
log.Print(string(pRendered))
// create a hash from the payload
digest := sha256.Sum256(pRendered)
log.Printf("hash [base64]: %s", base64.StdEncoding.EncodeToString(digest[:]))
// create a signed UPP message
//upp, err := sim.Sign(name, digest[:], ubirch.Signed, false) // insert hash into the UPP
upp, err := sim.Sign(key_name, pRendered, ubirch.Signed, true) // use automatic hashing
if err != nil {
log.Fatalf("ERROR signing failed: %v", err)
}
log.Printf("UPP [hex]: %s", hex.EncodeToString(upp))
// try to verify the UPP locally
ok, err := sim.Verify(key_name, upp, ubirch.Signed)
if err != nil || !ok {
log.Fatalf("ERROR local verification failed: %v", err)
}
log.Printf("verified: %v", ok)
// send UPP to the UBIRCH backend
send(upp, uid, conf)
for i := 0; i < 3; i++ {
log.Printf(" - - - - - - - - %d. chained UPP: - - - - - - - - ", i+1)
p := Payload{int(time.Now().Unix()), uid.String(), int(rand.Uint32())}
pRendered, err := json.Marshal(p)
if err != nil {
log.Fatalf("can't render payload as json: %v", err)
}
log.Print(string(pRendered))
// create a hash from the payload
digest := sha256.Sum256(pRendered)
log.Printf("hash [base64]: %s", base64.StdEncoding.EncodeToString(digest[:]))
// create a signed UPP message
//upp, err := sim.Sign(name, digest[:], ubirch.Chained, false)
upp, err := sim.Sign(key_name, pRendered, ubirch.Chained, true) // use automatic hashing
if err != nil {
log.Fatalf("ERROR signing failed: %v", err)
}
log.Printf("UPP [hex]: %s", hex.EncodeToString(upp))
// try to verify the UPP locally
ok, err := sim.Verify(key_name, upp, ubirch.Chained)
if err != nil || !ok {
log.Fatalf("ERROR local verification failed: %v", err)
}
log.Printf("verified: %v", ok)
// send UPP to the UBIRCH backend
send(upp, uid, conf)
}
}
func getPIN(imsi string, conf Config) (string, error) {
if conf.Password == "" {
return "", fmt.Errorf("no auth token for backend set in config")
}
// bootstrap SIM identity and retrieve PIN
return bootstrap(imsi, conf.BootstrapService, conf.Password)
}
// send UPP to the UBIRCH backend
func send(upp []byte, uid uuid.UUID, conf Config) {
if conf.Password == "" {
return
}
statusCode, respBody, err := post(upp, conf.Niomon, map[string]string{
"X-Ubirch-Hardware-Id": uid.String(),
"X-Ubirch-Auth-Type": "ubirch",
"X-Ubirch-Credential": base64.StdEncoding.EncodeToString([]byte(conf.Password)),
})
if err != nil {
log.Printf("ERROR: sending UPP failed: %v", err)
} else if statusCode != http.StatusOK {
log.Printf("ERROR: request to %s failed with status code %d: %s", conf.Niomon, statusCode, hex.EncodeToString(respBody))
} else {
log.Printf("UPP successfully sent. response: %s", hex.EncodeToString(respBody))
}
}