// Execute the mutulChallengeResponse server: in this example the ocra suite is predefined both for the client and the server // 1. Wait for the client's randomly generated question // 2. Send to the client both the calculated ocra value (based on the ocra suite and client's + server's questions) and the server's question // 3. Get from the client the calculated ocra value based on the client's and server's questions // 4. Calculate the expected ocra value based on both the client's and the server's questions // 5. Comapre the calculated ocra value with the one recived from the client // 6. If the values are equal: the client is authenticated // 6.1. Send an OK message to the client // 6.2. Increase the 'ocra used' counter (to prevent replay attacks) // 7. Else (the values are not equal) send a NOK message to the client func mutualChallengeResponseServer(key string, counter string) { QS := "Server 9879" QC := <-channel RS, err := ocra.GenerateOCRAAdvance(mutualOcraSuite, key, counter, QC+QS, mutualPassword, "", "") if err != nil { doneChannel <- fmt.Sprintf(failFmt, err) } channel <- RS channel <- QS RC := <-channel cOtp, err := ocra.GenerateOCRAAdvance(mutualOcraSuite, key, counter, QS+QC, mutualPassword, "", "") if err != nil { doneChannel <- fmt.Sprintf(failFmt, err) } if RC == cOtp { channel <- OKStr val, _ := strconv.Atoi(counter) counter = fmt.Sprintf("%06d", val+1) } else { channel <- NOKStr } }
func mutualChallengeResponseClient(key string, counter string) { QC := "Client 1234" channel <- QC RS := <-channel QS := <-channel sOtp, err := ocra.GenerateOCRAAdvance(mutualOcraSuite, key, counter, QC+QS, mutualPassword, "", "") if err != nil { doneChannel <- fmt.Sprintf(failFmt, err) } RC, err := ocra.GenerateOCRAAdvance(mutualOcraSuite, key, counter, QS+QC, mutualPassword, "", "") if err != nil { doneChannel <- fmt.Sprintf(failFmt, err) } if RS == sOtp { channel <- RC } else { channel <- "0" } fmt.Printf("Client/Server otp: (%v,%v), Ocra suite: %v, Client/Server questions: ('%v','%v'), counter: %v, password: %v\n", RC, RS, mutualOcraSuite, QC, QS, counter, mutualPassword) ok := <-channel if ok == OKStr { val, _ := strconv.Atoi(counter) counter = fmt.Sprintf("%06d", val+1) } doneChannel <- ok }
func TestOneWayChallengeResponse(t *testing.T) { userName := usersName[0] initAListOfUsers(t, usersName) url := listener + servicePath + fmt.Sprintf(cr.ConvertCommandToRequest(urlCommands[verifyUserIdentityCommand]), usersPath, userName, verifyUserIdentityChallengeToken) res := exeCommandCheckRes(t, cr.HTTPGetStr, url, http.StatusOK, "", cr.StringMessage{Str: cr.GetMessageStr}) var OcraData ocraData err := json.Unmarshal([]byte(res), &OcraData) if err != nil { t.Errorf("Test fail: execute GET to '%v' expected to get ocra data but received: %v, error: %v", url, res, err) } //Calculate the cleint OTP otp, err := ocra.GenerateOCRAAdvance(ocraUserDataInfo.OcraSuite, secretCode, OcraData.Counter, OcraData.ServerQuestion, OcraData.Password, OcraData.SessionID, OcraData.TimeStamp) logger.Info.Println("The calculated OTP for ocra data:", res, "is:", otp) if err != nil { t.Errorf("Test fail: Try to generate OCRA with the following parameters: %v, error: %v", res, err) } OcraData.Otp = otp data, _ := json.Marshal(OcraData) url = listener + servicePath + fmt.Sprintf(cr.ConvertCommandToRequest(urlCommands[verifyUserIdentityCommand]), usersPath, userName, verifyUserIdentityOtpToken) exeCommandCheckRes(t, cr.HTTPPutStr, url, http.StatusOK, string(data), cr.Match{Match: true, Message: ""}) }
// Execute the oneWayChallengeResponse client: // 1. Wait for the ocra suite defined by the server (in this example) // and the server's randomly generated question // 2. Send to the server the calculated ocra value (using the ocra suite and the server's question) // 3. Send the server's approval to the "done channel" func oneWayChallengeResponseClient(key string) { oneWayOcraSuite := <-channel question := <-channel otp, err := ocra.GenerateOCRAAdvance(oneWayOcraSuite, key, "", question, "", "", "") if err != nil { doneChannel <- fmt.Sprintf(failFmt, err) } fmt.Printf("Client otp: %v, Ocra suite: %v, Question: '%v'\n", otp, oneWayOcraSuite, question) channel <- otp ok := <-channel doneChannel <- ok }
func TestMutualChallengeResponse(t *testing.T) { var OcraData ocraData userName := usersName[0] initAListOfUsers(t, usersName) OcraData.ClientQuestion = "The client 1" url := listener + servicePath + fmt.Sprintf(cr.ConvertCommandToRequest(urlCommands[verifyUserIdentityCommand]), usersPath, userName, verifyUserIdentityMutualChallengeStep1Token) data, _ := json.Marshal(cr.StringMessage{Str: OcraData.ClientQuestion}) res := exeCommandCheckRes(t, cr.HTTPPutStr, url, http.StatusOK, string(data), cr.StringMessage{Str: cr.GetMessageStr}) err := json.Unmarshal([]byte(res), &OcraData) if err != nil { t.Errorf("Test fail: execute GET to '%v' expected to get ocra data but received: %v, error: %v", url, res, err) t.FailNow() } clientOtp, err := ocra.GenerateOCRAAdvance(ocraUserDataInfo.OcraSuite, secretCode, OcraData.Counter, OcraData.ServerQuestion+OcraData.ClientQuestion, OcraData.Password, OcraData.SessionID, OcraData.TimeStamp) serverOtp, _ := ocra.GenerateOCRAAdvance(ocraUserDataInfo.OcraSuite, secretCode, OcraData.Counter, OcraData.ClientQuestion+OcraData.ServerQuestion, OcraData.Password, OcraData.SessionID, OcraData.TimeStamp) logger.Info.Println("The calculated client OTP for ocra data:", res, "and client question:", OcraData.ClientQuestion, "is:", clientOtp, "the server otp:", serverOtp) if err != nil { t.Errorf("Test fail: Try to generate OCRA with the following parameters: %v, error: %v", res, err) t.FailNow() } if OcraData.Otp != serverOtp { t.Errorf("Test fail: The calculated server OTP: %v is not as the received OTP: %v", serverOtp, OcraData.Otp) t.FailNow() } url = listener + servicePath + fmt.Sprintf(cr.ConvertCommandToRequest(urlCommands[verifyUserIdentityCommand]), usersPath, userName, verifyUserIdentityMutualChallengeStep2Token) OcraData.Otp = clientOtp data, _ = json.Marshal(OcraData) exeCommandCheckRes(t, cr.HTTPPutStr, url, http.StatusOK, string(data), cr.Match{Match: true, Message: ""}) }
// In this example, The oneWayOcraSuite is defined by the server and sent to the client // 1. Send the ocra suite and the "random" question to the client // 2. Comapre the expected calculated ocra value with the one recived from the client // 3. Based on the result of the comparison, send either an 'OK' or a 'NOK' message to the client func oneWayChallengeResponseServer(key string) { oneWayOcraSuite := "OCRA-1:HOTP-SHA1-6:QA08" question := "abcd1234" channel <- oneWayOcraSuite channel <- question refOtp, err := ocra.GenerateOCRAAdvance(oneWayOcraSuite, key, "", question, "", "", "") if err != nil { doneChannel <- fmt.Sprintf(failFmt, err) } otp := <-channel if otp == refOtp { channel <- OKStr } else { channel <- NOKStr } }
func (o OcraRestful) restVerifyOcraUserIdentityMutualChallengeStep2(request *restful.Request, response *restful.Response) { data := o.getOcra(request, response) if data == nil { return } var ocraData ocraData err := request.ReadEntity(&ocraData) clientOtp, err := ocra.GenerateOCRAAdvance(data.OcraSuite, string(data.Key), ocraData.Counter, ocraData.ServerQuestion+ocraData.ClientQuestion, ocraData.Password, ocraData.SessionID, ocraData.TimeStamp) logger.Trace.Println("ocraData:", ocraData, "client otp:", ocraData.Otp, "calculated client otp:", clientOtp) if ocraData.Otp == clientOtp && err == nil { response.WriteHeaderAndEntity(http.StatusOK, cr.Match{Match: true, Message: "OTP match"}) logger.Trace.Println("Server verify the OTP successfully") } else { logger.Trace.Println("Server calculated OTP:", clientOtp, "is different from the one sent from the client", ocraData.Otp) response.WriteHeaderAndEntity(http.StatusOK, cr.Match{Match: false, Message: "Client OTP doesn't match"}) } }
func (o OcraRestful) restVerifyOcraUserIdentityMutualChallengeStep1(request *restful.Request, response *restful.Response) { data := o.getOcra(request, response) if data == nil { return } var ocraData ocraData err := request.ReadEntity(&ocraData) logger.Trace.Println("Server received data:", ocraData, "Error:", err) ocraData.ServerQuestion = o.getRandString(ocraQuestionLen) serverOtp, err := ocra.GenerateOCRAAdvance(data.OcraSuite, string(data.Key), ocraData.Counter, ocraData.ClientQuestion+ocraData.ServerQuestion, ocraData.Password, ocraData.SessionID, ocraData.TimeStamp) if err != nil { o.setError(response, http.StatusNotFound, err) return } logger.Trace.Println("ocraData:", ocraData, "server otp:", serverOtp) ocraData.Otp = serverOtp response.WriteHeaderAndEntity(http.StatusOK, ocraData) }
func (o OcraRestful) restVerifyOcraUserIdentityCheckOtp(request *restful.Request, response *restful.Response) { data := o.getOcra(request, response) if data == nil { return } var ocraData ocraData err := request.ReadEntity(&ocraData) if err != nil { str := fmt.Sprintf("Error while reading data '%v', error: %v", ocraData, err) o.setError(response, http.StatusNotFound, fmt.Errorf(str)) return } // verify client OTP otp, err := ocra.GenerateOCRAAdvance(data.OcraSuite, string(data.Key), ocraData.Counter, ocraData.ServerQuestion, ocraData.Password, ocraData.SessionID, ocraData.TimeStamp) logger.Trace.Println("ocraData:", ocraData, "otp:", otp, "client otp:", ocraData.Otp) if ocraData.Otp == otp && err == nil { response.WriteHeaderAndEntity(http.StatusOK, cr.Match{Match: true, Message: "OTP match"}) logger.Trace.Println("Server verify the OTP successfully") } else { logger.Trace.Println("Server calculated OTP:", otp, "is different from the one sent from the client", ocraData.Otp) response.WriteHeaderAndEntity(http.StatusOK, cr.Match{Match: false, Message: "OTP doesn't match"}) } }