diff --git a/go/main/client.go b/go/main/client.go index 2ab4c3a..c6635fe 100644 --- a/go/main/client.go +++ b/go/main/client.go @@ -8,8 +8,9 @@ import ( "errors" "fmt" "io/ioutil" - "log" "net/http" + + log "github.com/sirupsen/logrus" ) // post A http request to the backend service and return response code and body diff --git a/go/main/config.go b/go/main/config.go index 6e6eb58..c49daf7 100644 --- a/go/main/config.go +++ b/go/main/config.go @@ -3,48 +3,100 @@ package main import ( "encoding/json" "fmt" - "io/ioutil" - "log" + "os" "strings" + + log "github.com/sirupsen/logrus" +) + +const ( + DEV_STAGE = "dev" + DEV_UUID = "9d3c78ff-22f3-4441-a5d1-85c636d486ff" + DEV_PUBKEY_ECDSA = "LnU8BkvGcZQPy5gWVUL+PHA0DP9dU61H8DBO8hZvTyI7lXIlG1/oruVMT7gS2nlZDK9QG+ugkRt/zTrdLrAYDA==" + DEV_PUBKEY_EdDSA = "okA7krya3TZbPNEv8SDQIGR/hOppg/mLxMh+D0vozWY=" + + DEMO_STAGE = "demo" + DEMO_UUID = "07104235-1892-4020-9042-00003c94b60b" + DEMO_PUBKEY_ECDSA = "xm+iIomBRjR3QdvLJrGE1OBs3bAf8EI49FfgBriRk36n4RUYX+0smrYK8tZkl6Lhrt9lzjiUGrXGijRoVE+UjA==" + DEMO_PUBKEY_EdDSA = "Of93YysDTQ66bSGcL/GS6fJJFsmgJnKstJ/QURiq0lE=" + + PROD_STAGE = "prod" + PROD_UUID = "10b2e1a4-56b3-4fff-9ada-cc8c20f93016" + PROD_PUBKEY_ECDSA = "pJdYoJN0N3QTFMBVjZVQie1hhgumQVTy2kX9I7kXjSyoIl40EOa9MX24SBAABBV7xV2IFi1KWMnC1aLOIvOQjQ==" + PROD_PUBKEY_EdDSA = "74BIrQbAKFrwF3AJOBgwxGzsAl0B2GCF51pPAEHC5pA=" + + defaultKeyURL = "https://key.%s.ubirch.com/api/keyService/v1/pubkey" + defaultDataURL = "https://data.%s.ubirch.com/v1" + defaultNiomonURL = "https://niomon.%s.ubirch.com/" + defaultVerifyURL = "https://verify.%s.ubirch.com/api/upp" + defaultBootstrapURL = "https://api.console.%s.ubirch.com/ubirch-web-ui/api/v1/devices/bootstrap" ) // configuration file structure type Config struct { - Password string `json:"password"` // password for the ubirch backend (mandatory) - Env string `json:"env"` // ubirch environment (optional) - KeyService string `json:"keyService"` // key service URL (optional) - Niomon string `json:"niomon"` // authentication service URL (optional) - DataService string `json:"data"` // data service URL (optional) - VerifyService string `json:"verify"` // verification service URL (optional) - BootstrapService string `json:"boot"` // bootstrap service URL (optional) - Debug bool `json:"debug"` // enable extended debug output (optional) - Uuid string `json:"uuid"` // the device uuid (set UUID here if you want to generate a new key pair on the SIM card) - Pin string `json:"pin"` // the SIM pin (set PIN here if bootstrapping is not possible) + Password string `json:"password"` // password for the ubirch backend (mandatory) + Env string `json:"env"` // ubirch environment (optional) + ServerIdentity identity `json:"serverIdentity"` // backend UUID and public keys (optional) + KeyService string `json:"keyService"` // key service URL (optional) + Niomon string `json:"niomon"` // authentication service URL (optional) + DataService string `json:"data"` // data service URL (optional) + VerifyService string `json:"verify"` // verification service URL (optional) + BootstrapService string `json:"boot"` // bootstrap service URL (optional) + Debug bool `json:"debug"` // enable extended debug output (optional) + Uuid string `json:"uuid"` // the device uuid (set UUID here if you want to generate a new key pair on the SIM card) + Pin string `json:"pin"` // the SIM pin (set PIN here if bootstrapping is not possible) +} + +type identity struct { + UUID string + PubKey pubkey +} + +type pubkey struct { + ECDSA string + EdDSA string +} + +var defaultServerIdentities = map[string]identity{ + DEV_STAGE: {UUID: DEV_UUID, PubKey: pubkey{ECDSA: DEV_PUBKEY_ECDSA, EdDSA: DEV_PUBKEY_EdDSA}}, + DEMO_STAGE: {UUID: DEMO_UUID, PubKey: pubkey{ECDSA: DEMO_PUBKEY_ECDSA, EdDSA: DEMO_PUBKEY_EdDSA}}, + PROD_STAGE: {UUID: PROD_UUID, PubKey: pubkey{ECDSA: PROD_PUBKEY_ECDSA, EdDSA: PROD_PUBKEY_EdDSA}}, } // Load the config file func (c *Config) Load(fn string) error { - contextBytes, err := ioutil.ReadFile(fn) + fileHandle, err := os.Open(fn) if err != nil { return err } + defer fileHandle.Close() - err = json.Unmarshal(contextBytes, c) + err = json.NewDecoder(fileHandle).Decode(c) if err != nil { - log.Fatalf("unable to read configuration %v", err) return err } + if c.Debug { + log.SetLevel(log.DebugLevel) + } + if c.Password == "" { log.Printf("password not set in config. will skip backend communication.") } if c.Env == "" { - c.Env = "prod" + c.Env = PROD_STAGE + } + + // assert Env variable value is a valid UBIRCH backend environment + if !(c.Env == DEV_STAGE || c.Env == DEMO_STAGE || c.Env == PROD_STAGE) { + return fmt.Errorf("invalid UBIRCH backend environment: \"%s\"", c.Env) } + log.Debugf("UBIRCH backend \"%s\" environment", c.Env) + if c.KeyService == "" { - c.KeyService = fmt.Sprintf("https://key.%s.ubirch.com/api/keyService/v1/pubkey", c.Env) + c.KeyService = fmt.Sprintf(defaultKeyURL, c.Env) } else { c.KeyService = strings.TrimSuffix(c.KeyService, "/mpack") } @@ -53,18 +105,28 @@ func (c *Config) Load(fn string) error { c.Env = strings.Split(c.KeyService, ".")[1] if c.Niomon == "" { - c.Niomon = fmt.Sprintf("https://niomon.%s.ubirch.com/", c.Env) + c.Niomon = fmt.Sprintf(defaultNiomonURL, c.Env) } if c.DataService == "" { - c.DataService = fmt.Sprintf("https://data.%s.ubirch.com/v1", c.Env) + c.DataService = fmt.Sprintf(defaultDataURL, c.Env) } else { c.DataService = strings.TrimSuffix(c.DataService, "/msgPack") } if c.VerifyService == "" { - c.VerifyService = fmt.Sprintf("https://verify.%s.ubirch.com/api/upp", c.Env) + c.VerifyService = fmt.Sprintf(defaultVerifyURL, c.Env) } if c.BootstrapService == "" { - c.BootstrapService = fmt.Sprintf("https://api.console.%s.ubirch.com/ubirch-web-ui/api/v1/devices/bootstrap", c.Env) + c.BootstrapService = fmt.Sprintf(defaultBootstrapURL, c.Env) + } + + log.Debugf(" - Key Service: %s", c.KeyService) + log.Debugf(" - Authentication Service: %s", c.Niomon) + log.Debugf(" - Data Service: %s", c.DataService) + log.Debugf(" - Verification Service: %s", c.VerifyService) + log.Debugf(" - Bootstrapping Service: %s", c.BootstrapService) + + if c.ServerIdentity == (identity{}) { + c.ServerIdentity = defaultServerIdentities[c.Env] } return nil diff --git a/go/main/go.mod b/go/main/go.mod index 89afaea..ba51700 100644 --- a/go/main/go.mod +++ b/go/main/go.mod @@ -4,7 +4,7 @@ go 1.12 require ( github.com/google/uuid v1.1.1 - github.com/ubirch/ubirch-protocol-go/ubirch/v2 v2.1.3 + github.com/sirupsen/logrus v1.7.0 github.com/ubirch/ubirch-protocol-sim/go/ubirch v0.0.0 go.bug.st/serial v1.1.0 golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 // indirect diff --git a/go/main/go.sum b/go/main/go.sum index a3046af..07a23f7 100644 --- a/go/main/go.sum +++ b/go/main/go.sum @@ -2,12 +2,17 @@ github.com/creack/goselect v0.1.1 h1:tiSSgKE1eJtxs1h/VgGQWuXUP0YS4CDIFMp6vaI1ls0 github.com/creack/goselect v0.1.1/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/paypal/go.crypto v0.1.0/go.mod h1:SkWGgUAivahcWkhrh1+u2TdpofifG/A2vNpmnhT4oHY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= @@ -15,8 +20,6 @@ github.com/ubirch/go.crypto v0.1.2 h1:IYMOx19UgWt4+k7PydcOVtEWFiU10O8dHoof00j8IK github.com/ubirch/go.crypto v0.1.2/go.mod h1:aiZQ37CxSBS7cBLsFbTnDxGeg5RkH7Z5LKBYeNasIrw= github.com/ubirch/ubirch-protocol-go/ubirch v1.0.1 h1:N5pGaZ/sW4bK2m4CUraVyrzfuQpnacXoQTmh7f6sRzQ= github.com/ubirch/ubirch-protocol-go/ubirch v1.0.1/go.mod h1:FNnB4hBmDXOLmdf4ytPSab+9HUdtgK10AY/0eg1RSOs= -github.com/ubirch/ubirch-protocol-go/ubirch/v2 v2.1.2 h1:oyvbyF4XfKa8tAwveNXxnaliFUbocELEFsXfyp4atag= -github.com/ubirch/ubirch-protocol-go/ubirch/v2 v2.1.2/go.mod h1:nTqN+niHQNN5XLxMgd5MOD+yW9vBi9trYIj4vBuVi2Y= github.com/ubirch/ubirch-protocol-go/ubirch/v2 v2.1.3 h1:jz8Fu27w2VtwPTfooQ0k5evfkaRe4EboZxK6c1tkg0c= github.com/ubirch/ubirch-protocol-go/ubirch/v2 v2.1.3/go.mod h1:nTqN+niHQNN5XLxMgd5MOD+yW9vBi9trYIj4vBuVi2Y= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= @@ -25,6 +28,7 @@ github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= go.bug.st/serial v1.1.0 h1:O0EHZw8ZdhmTAikak5ZY/8vyKCpFxZYgqZw1bGegxU8= go.bug.st/serial v1.1.0/go.mod h1:rpXPISGjuNjPTRTcMlxi9lN6LoIPxd1ixVjBd8aSk/Q= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/go/main/main.go b/go/main/main.go index 22c8401..729bb71 100644 --- a/go/main/main.go +++ b/go/main/main.go @@ -6,7 +6,7 @@ import ( "encoding/hex" "encoding/json" "fmt" - "log" + "go.bug.st/serial" "math/rand" "net/http" "os" @@ -14,11 +14,13 @@ import ( "time" "github.com/google/uuid" + log "github.com/sirupsen/logrus" "github.com/ubirch/ubirch-protocol-sim/go/ubirch" - "go.bug.st/serial" ) func main() { + log.SetFormatter(&log.TextFormatter{FullTimestamp: true, TimestampFormat: "2006-01-02 15:04:05.000 -0700"}) + log.Println("SIM Interface Example") if len(os.Args) < 3 { log.Println("usage: main ") @@ -70,6 +72,7 @@ func main() { if err != nil { log.Fatalf("bootstrapping failed: %v", err) } + log.Infof("PIN: %s", PIN) } sim := ubirch.Protocol{SimInterface: &serialPort, Debug: conf.Debug} @@ -85,33 +88,37 @@ func main() { 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) - //} + // generate a new ECDSA key pair for the device, if there is none stored on the SIM yet + entryExists, err := sim.EntryExists(key_name) + if err != nil { + log.Fatalf("checking for entry \"%s\" on SIM failed: %v", key_name, err) + } + if !entryExists && conf.Uuid != "" { + uid, err := uuid.Parse(conf.Uuid) + if err != nil { + log.Fatalf("failed to parse UUID: %v", err) + } + + // generate a key pair !!! overwrites existing keys with that entry ID !!! + 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 + // get the device 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()) + log.Printf("device UUID: %s", uid.String()) - // get the public key from SIM card + // get the device 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)) + log.Printf("device public key [base64]: %s", base64.StdEncoding.EncodeToString(key)) // create a X.509 certificate signing request (CSR) csr, err := sim.GenerateCSR(key_name) @@ -127,6 +134,41 @@ func main() { } log.Printf("X.509 certificate: %x", cert) + //// delete currently stored backend public key + //err = sim.DeleteSSEntry(conf.Env) + //if err != nil { + // log.Fatalf("deleting backend public key failed: %v", err) + //} + + // store backend public key on the SIM for verification, if the entry does not exist yet + entryExists, err = sim.EntryExists(conf.Env) + if err != nil { + log.Fatalf("checking for entry \"%s\" on SIM failed: %v", conf.Env, err) + } + if !entryExists { + uid, err := uuid.Parse(conf.ServerIdentity.UUID) + if err != nil { + log.Fatalf("failed to parse UUID: %v", err) + } + + pubKey, err := base64.StdEncoding.DecodeString(conf.ServerIdentity.PubKey.ECDSA) + if err != nil { + log.Fatalf("decoding base64 encoded public key failed: %v", err) + } + + err = sim.PutPubKey(conf.Env, uid, pubKey) + if err != nil { + log.Fatalf("storing backend public key failed: %v", err) + } + } + + // get the backend public key from SIM card + pubKey, err := sim.GetKey(conf.Env) + if err != nil { + log.Fatalf("getting key %s failed: %v", conf.Env, err) + } + log.Printf("backend public key [base64]: %s", base64.StdEncoding.EncodeToString(pubKey)) + // send a signed message type Payload struct { Timestamp int @@ -153,16 +195,26 @@ func main() { } log.Printf("UPP [hex]: %s", hex.EncodeToString(upp)) - // try to verify the UPP locally + // 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) + log.Printf("UPP locally verified: %v", ok) // send UPP to the UBIRCH backend - send(upp, uid, conf) + resp := send(upp, uid, conf) + + if resp != nil { + // verify response signature + ok, err = sim.Verify(conf.Env, resp, ubirch.ProtocolType(resp[1])) + if err != nil || !ok { + log.Fatalf("ERROR backend response signature verification failed: %v", err) + } + log.Printf("backend response verified: %v", ok) + } + // send chained messages for i := 0; i < 3; i++ { log.Printf(" - - - - - - - - %d. chained UPP: - - - - - - - - ", i+1) p := Payload{int(time.Now().Unix()), uid.String(), int(rand.Uint32())} @@ -184,15 +236,24 @@ func main() { } log.Printf("UPP [hex]: %s", hex.EncodeToString(upp)) - // try to verify the UPP locally + // 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) + log.Printf("UPP locally verified: %v", ok) // send UPP to the UBIRCH backend - send(upp, uid, conf) + resp := send(upp, uid, conf) + + if resp != nil { + // verify response signature + ok, err = sim.Verify(conf.Env, resp, ubirch.ProtocolType(resp[1])) + if err != nil || !ok { + log.Fatalf("ERROR backend response signature verification failed: %v", err) + } + log.Printf("backend response verified: %v", ok) + } } } @@ -205,9 +266,10 @@ func getPIN(imsi string, conf Config) (string, error) { } // send UPP to the UBIRCH backend -func send(upp []byte, uid uuid.UUID, conf Config) { +func send(upp []byte, uid uuid.UUID, conf Config) []byte { if conf.Password == "" { - return + log.Warn("backend auth (\"password\") not set in config - request not sent") + return nil } statusCode, respBody, err := post(upp, conf.Niomon, map[string]string{ @@ -216,10 +278,15 @@ func send(upp []byte, uid uuid.UUID, conf Config) { "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)) + log.Errorf("sending UPP failed: %v", err) + return nil } + + if statusCode != http.StatusOK { + log.Errorf("request to %s failed with status code %d: %s", conf.Niomon, statusCode, hex.EncodeToString(respBody)) + return nil + } + + log.Printf("UPP successfully sent. response: %s", hex.EncodeToString(respBody)) + return respBody } diff --git a/go/ubirch/modem.go b/go/ubirch/modem.go index 2dafedf..a835632 100644 --- a/go/ubirch/modem.go +++ b/go/ubirch/modem.go @@ -114,8 +114,8 @@ func (sp *SimSerialPort) GetIMSI() (string, error) { if err != nil { return "", err } - if len(response[0]) != IMSI_LEN || response[1] != "OK" { - return "", fmt.Errorf(response[0]) + if response[len(response)-1] != "OK" || len(response[len(response)-2]) != IMSI_LEN { + return "", fmt.Errorf(response[len(response)-1]) } return response[0], err } diff --git a/go/ubirch/ubirch_sim.go b/go/ubirch/ubirch_sim.go index 0f25648..ef20676 100644 --- a/go/ubirch/ubirch_sim.go +++ b/go/ubirch/ubirch_sim.go @@ -282,6 +282,10 @@ func (p *Protocol) openChannel() error { return nil } + if p.Debug { + log.Printf(">> opening new channel to SIM") + } + // open a new channel via channel 0 (basic channel) data, code, err := p.execute(stkOpenChannel) if err != nil { @@ -300,6 +304,10 @@ func (p *Protocol) openChannel() error { // set the channel p.channel = channel + if p.Debug { + log.Printf(">> using channel %d", p.channel) + } + return nil } @@ -312,6 +320,10 @@ func (p *Protocol) closeChannel() error { return nil } + if p.Debug { + log.Printf(">> closing channel %d", p.channel) + } + // close the channel via channel 0 (basic channel) channel := p.channel p.channel = 0 @@ -366,10 +378,10 @@ func (p *Protocol) Deinit() error { return p.closeChannel() } -// selectSSEntryID selects an entry in the secure storage using the entry ID, see [1] 2.1.4 +// selectSSEntry selects an entry in the secure storage using the entry ID, see [1] 2.1.4 // returns the entry title (usually UUID) sent by the SIM as response to the command as well as the APDU code and error condition //also checks if selected entry ID is the same as in the request -func (p *Protocol) selectSSEntryID(entryID string) ([]byte, uint16, error) { +func (p *Protocol) selectSSEntry(entryID string) ([]byte, uint16, error) { if p.Debug { log.Printf(">> selecting SS entry \"%s\"", entryID) } @@ -410,6 +422,24 @@ func (p *Protocol) selectSSEntryID(entryID string) ([]byte, uint16, error) { return entryTitle, code, nil } +// EntryExists checks if an entry with a given entry ID exists in the SIM secure storage +func (p *Protocol) EntryExists(entryID string) (bool, error) { + if p.Debug { + log.Printf(">> checking for SS entry \"%s\"", entryID) + } + _, code, err := p.execute(stkAppSsEntrySelect, len(entryID), hex.EncodeToString([]byte(entryID))) + if err != nil { + return false, err + } + if code == ApduNotFound { + return false, nil + } + if code>>8 == 0x61 { + return true, nil + } + return false, fmt.Errorf("received unexpected code: 0x%x", code) +} + //GetLastSignature reads the SS entry 'LastSign SSEntry' which contains the signature of the //last UPP created on the SIM. This entry is sued both for chained and signed packets see manual TLSAuthApp 3.4.1 func (p *Protocol) GetLastSignature() ([]byte, error) { @@ -417,7 +447,7 @@ func (p *Protocol) GetLastSignature() ([]byte, error) { log.Printf(">> get last signature") } //Select the entry - _, _, err := p.selectSSEntryID("LastSign SSEntry") + _, _, err := p.selectSSEntry("LastSign SSEntry") if err != nil { return nil, err } @@ -507,28 +537,28 @@ func (p *Protocol) GetAllSSEntries() ([]map[string]string, error) { return entryMap, nil } -//DeleteSSEntryID deletes an entry in the secure storage (SS) of the SIM using it's entry ID +//DeleteSSEntry deletes an entry in the secure storage (SS) of the SIM using it's entry ID //It returns the response code and the error condition. The code can be used to unambigously check //the cause of the error in the caller. -func (p *Protocol) DeleteSSEntryID(entryID string) (uint16, error) { +func (p *Protocol) DeleteSSEntry(entryID string) error { if p.Debug { log.Printf(">> deleting SS entry \"%s\"", entryID) } // delete SS entry command _, code, err := p.execute(stkAppSsDeleteEntryID, len(entryID), hex.EncodeToString([]byte(entryID))) if err != nil { - return code, err + return err } switch code { case ApduOk: - return code, nil + return nil case ApduNotFound: - return code, fmt.Errorf("entry \"%s\" not found", entryID) + return fmt.Errorf("entry \"%s\" not found", entryID) case ApduWrongData: - return code, fmt.Errorf("invalid entry ID length") + return fmt.Errorf("invalid entry ID length") default: - return code, fmt.Errorf("unexpected return code received") + return fmt.Errorf("unexpected return code received: %s", code) } } diff --git a/go/ubirch/ubirch_sim_test.go b/go/ubirch/ubirch_sim_test.go index bbce3a0..c9a8265 100644 --- a/go/ubirch/ubirch_sim_test.go +++ b/go/ubirch/ubirch_sim_test.go @@ -501,8 +501,8 @@ func TestSim_GenerateKeyPair(t *testing.T) { asserter.NoErrorf(sim.GenerateKey(testName, uuid.Nil), "failed to generate Key Pair") // TODO, do we need to check for nil UUIDs? //delete generated keypair when we're done - sim.DeleteSSEntryID(testName) - sim.DeleteSSEntryID("_" + testName) + sim.DeleteSSEntry(testName) + sim.DeleteSSEntry("_" + testName) } // *WARNING* careful with this function, it can block the SIM card, @@ -711,9 +711,9 @@ func TestSim_StoreCertificate(t *testing.T) { asserter.NoErrorf(certReadX509.CheckSignatureFrom(ca), "Failed to verify Signature from root") // remove the test entries - sim.DeleteSSEntryID(certName) - sim.DeleteSSEntryID(defaultName) - sim.DeleteSSEntryID("_" + defaultName) + sim.DeleteSSEntry(certName) + sim.DeleteSSEntry(defaultName) + sim.DeleteSSEntry("_" + defaultName) } // TestSim_UpdateCertificate tests updating a Certificate in the SIM @@ -794,9 +794,9 @@ func TestSim_UpdateCertificate(t *testing.T) { asserter.NoErrorf(certReadX509Upd.CheckSignatureFrom(ca), "Failed to verify Signature from root") // remove the test entries - sim.DeleteSSEntryID(certName) - sim.DeleteSSEntryID(defaultName) - sim.DeleteSSEntryID("_" + defaultName) + sim.DeleteSSEntry(certName) + sim.DeleteSSEntry(defaultName) + sim.DeleteSSEntry("_" + defaultName) } // TestSim_GenerateCSR tests getting a CSR (Certificate Signing Request) from the SIM @@ -849,8 +849,8 @@ func TestSim_GenerateCSR(t *testing.T) { // test checking if the Public Key Algorithm is correct asserter.Equalf(csrX509.PublicKeyAlgorithm, csrPubKeyAlgorithm, "the public key algorithm is not correct") - sim.DeleteSSEntryID(defaultName) - sim.DeleteSSEntryID("_" + defaultName) + sim.DeleteSSEntry(defaultName) + sim.DeleteSSEntry("_" + defaultName) } // todo WIP @@ -1052,7 +1052,7 @@ func TestSIM_PutPubKey(t *testing.T) { setErr := sim.PutPubKey(currTest.pubkeyName, currTest.UUID, currPubkey) //if creation was succesfull, make sure we clean up the key later if setErr == nil { - defer sim.DeleteSSEntryID(currTest.pubkeyName) + defer sim.DeleteSSEntry(currTest.pubkeyName) } // check test outcome vs expectation @@ -1550,7 +1550,7 @@ func TestSim_Verify(t *testing.T) { // Put the pubkey for the test on the SIM (and make sure we clean it up when we're done using 'defer') err = sim.PutPubKey(currTest.nameForPutPubKey, currUUID, currPubkey) - defer sim.DeleteSSEntryID(currTest.nameForPutPubKey) + defer sim.DeleteSSEntry(currTest.nameForPutPubKey) requirer.NoError(err, "putting pubkey on SIM failed") // convert test input string to bytes