//------------------------------------------------------------------------- // Installs new service data on a user token. // // 'copr' - Structure for holding coprocessor information. // 'user' - Structure for holding user token information. // 'secret' - the authentication secret to install on user token. // // Return: If TRUE, new service installation succeeded. // If FALSE, an error occurred. // SMALLINT InstallServiceData(SHACopr* copr, SHAUser* user, uchar* secret, int secret_length, int initialBalance) { short handle; int maxwrite; FileEntry fe; uchar fullBindCode[15]; //make sure user has a file directory structure memcpy(fe.Name, copr->serviceFilename, 4); fe.Ext = copr->serviceFilename[4]; // install master authentication secret if(user->devAN[0]==0x18) { //need to format the device if(!owFormat(user->portnum, user->devAN)) return FALSE; //and create an empty stub for his account information if(!owCreateFile(user->portnum, user->devAN, &maxwrite, &handle, &fe)) return FALSE; //need to know what page the stub is on user->accountPageNumber = fe.Spage; // set the serial number to that of the user owSerialNum(user->portnum, user->devAN, FALSE); OWASSERT( InstallSystemSecret18(user->portnum, user->accountPageNumber, user->accountPageNumber&7, secret, secret_length, FALSE), OWERROR_INSTALL_SECRET_FAILED, FALSE ); } else if((user->devAN[0]&0x7F)==0x33) { // set the serial number to that of the user owSerialNum(user->portnum, user->devAN, FALSE); //because of copy-authorization, we need to install the //secret first on the DS1961S and _then_ format the system OWASSERT( InstallSystemSecret33(user->portnum, 0, 0, secret, secret_length, FALSE), OWERROR_INSTALL_SECRET_FAILED, FALSE ); //need to format the device if(!owFormat(user->portnum, user->devAN)) return FALSE; //and create an empty stub for his account information if(!owCreateFile(user->portnum, user->devAN, &maxwrite, &handle, &fe)) return FALSE; //need to know what page the stub is on user->accountPageNumber = fe.Spage; } else { return FALSE; } // format the bind code properly // first four bytes of bind code memcpy(fullBindCode, copr->bindCode, 4); // followed by the pagenumber fullBindCode[4] = (uchar)user->accountPageNumber; // and 7 bytes of the address of current device memcpy(&fullBindCode[5], user->devAN, 7); // followed by the last 3 bytes of bind code memcpy(&fullBindCode[12], &(copr->bindCode[4]), 3); // create a unique secret for iButton if(user->devAN[0]==0x18) { DebitFile* accountFile = (DebitFile*)user->accountFile; OWASSERT( BindSecretToiButton18(user->portnum, user->accountPageNumber, user->accountPageNumber&7, copr->bindData, fullBindCode, TRUE), OWERROR_BIND_SECRET_FAILED, FALSE ); // do a read just to get value of writecycle counter user->writeCycleCounter = ReadAuthPageSHA18(user->portnum, user->accountPageNumber, user->accountFile, NULL, TRUE); //setup user account file with initial balance IntToBytes(accountFile->balanceBytes,3,initialBalance); // set transaction ID accountFile->transID[0] = 0; accountFile->transID[0] = 0; } else if((user->devAN[0]&0x7F)==0x33) { DebitFile33* accountFile33 = (DebitFile33*)user->accountFile; OWASSERT( BindSecretToiButton33(user->portnum, user->accountPageNumber, 0, copr->bindData, fullBindCode, TRUE), OWERROR_BIND_SECRET_FAILED, FALSE ); // Call VerifyUser just to get the user's secret in wspc if(!VerifyUser(copr, user, TRUE)) return FALSE; //Record A //setup user account file with initial balance IntToBytes(accountFile33->balanceBytes_A,3,initialBalance); // set transaction ID accountFile33->transID_A[0] = 0; accountFile33->transID_A[0] = 0; //Record B //setup user account file with initial balance IntToBytes(accountFile33->balanceBytes_B,3,initialBalance); // set transaction ID accountFile33->transID_B[0] = 0; accountFile33->transID_B[0] = 0; } //sign the data with coprocessor and write it out return UpdateServiceData(copr, user); }
//------------------------------------------------------------------------- // Verifies the authentication response of a user token. // // 'copr' - Structure for holding coprocessor information. // 'user' - Structure for holding user token information. // 'chlg' - 3-byte buffer of challenge data. // 'doBind' - if true, the user's unique secret is recreated on the // coprocessor. If this function is called multiple times, // it is acceptable to skip the bind for all calls after // the first on the same user token. // // Return: If TRUE, the user's authentication response matched exactly the // signature generated by the coprocessor. // If FALSE, an error occurred or the signature did not match. // SMALLINT VerifyAuthResponse(SHACopr* copr, SHAUser* user, uchar* chlg, SMALLINT doBind) { int addr = copr->wspcPageNumber << 5; int wcc = user->writeCycleCounter; uchar sign_cmd; uchar scratchpad[32]; uchar fullBindCode[15]; memset(scratchpad, 0x00, 32); memset(fullBindCode, 0x0FF, 15); // format the bind code properly if(user->devAN[0]==0x18) { // Format for DS1963S memcpy(fullBindCode, copr->bindCode, 4); memcpy(&fullBindCode[12], &(copr->bindCode[4]), 3); // use ValidateDataPage command sign_cmd = SHA_VALIDATE_DATA_PAGE; // copy wcc LSB first if(!IntToBytes(&scratchpad[8], 4, wcc)) OWERROR(OWERROR_NO_ERROR_SET); } else if(user->devAN[0]==0x33||user->devAN[0]==0xB3) { // Leave bindCode FF for DS1961S // Use AuthenticateHost command sign_cmd = SHA_AUTHENTICATE_HOST; // the user doesn't have a write cycle counter memset(&scratchpad[8], 0x0FF, 4); } else { OWERROR(OWERROR_WRONG_TYPE); return FALSE; } // the pagenumber fullBindCode[4] = (uchar)user->accountPageNumber; // and 7 bytes of the address of current device memcpy(&fullBindCode[5], user->devAN, 7); // get the user address and page num from fullBindCode memcpy(&scratchpad[12], &fullBindCode[4], 8); // set the same challenge bytes memcpy(&scratchpad[20], chlg, 3); // set the serial number to that of the coprocessor owSerialNum(copr->portnum, copr->devAN, FALSE); // install user's unique secret on the wspc secret if(doBind) { OWASSERT( BindSecretToiButton18(copr->portnum, copr->authPageNumber, copr->wspcPageNumber&7, copr->bindData, fullBindCode, FALSE), OWERROR_BIND_SECRET_FAILED, FALSE ); if(user->devAN[0]==0x33||user->devAN[0]==0xB3) { // also copy the resulting secret into secret location 0, to // replace the signing secret. Necessary for producing the // DS1961S's write-authorization MAC. OWASSERT( CopySecretSHA18(copr->portnum, 0), OWERROR_COPY_SECRET_FAILED, FALSE); } } // recreate the signature and verify OWASSERT( WriteDataPageSHA18(copr->portnum, copr->wspcPageNumber, user->accountFile, doBind), OWERROR_WRITE_DATA_PAGE_FAILED, FALSE ); OWASSERT( WriteScratchpadSHA18(copr->portnum, addr, scratchpad, 32, TRUE), OWERROR_WRITE_SCRATCHPAD_FAILED, FALSE ); OWASSERT( SHAFunction18(copr->portnum, sign_cmd, addr, TRUE), OWERROR_SHA_FUNCTION_FAILED, FALSE ); OWASSERT( MatchScratchpadSHA18(copr->portnum, user->responseMAC, TRUE), OWERROR_MATCH_SCRATCHPAD_FAILED, FALSE ); return TRUE; }
//------------------------------------------------------------------------- // Updates service data on a user token. This includes signing the // data if the part is a DS1963S. // // 'copr' - Structure for holding coprocessor information. // 'user' - Structure for holding user token information. // // Return: If TRUE, update succeeded. // If FALSE, an error occurred. // SMALLINT UpdateServiceData(SHACopr* copr, SHAUser* user) { ushort crc16, i; uchar scratchpad[32]; if(user->devAN[0] == 0x18) { DebitFile* accountFile = (DebitFile*)user->accountFile; // make sure length is right. accountFile->fileLength = 29; // update transaction ID // doesn't matter what it is, just needs to change accountFile->transID[0] += 1; if(accountFile->transID[0]==0) accountFile->transID[1] += 1; // conversion factor - 2 data bytes accountFile->convFactor[0] = (uchar)0x8B; accountFile->convFactor[1] = (uchar)0x48; // clear out the old signature and CRC memcpy(accountFile->signature, copr->initSignature, 20); memset(accountFile->crc16, 0x00, 2); // reset data type code accountFile->dataTypeCode = 1; //file doesn't continue on another page accountFile->contPtr = 0; // --- Set up the scratchpad for signing memset(scratchpad, 0x00, 32); // the write cycle counter +1 (since we are about to write this to it) if(user->writeCycleCounter>0) IntToBytes(&scratchpad[8], 4, user->writeCycleCounter+1); else // user doesn't have write cycle counter (DS1961S) memset(&scratchpad[8], 0x0FF, 4); // the pagenumber scratchpad[12] = (uchar)user->accountPageNumber; // and 7 bytes of the address of current device memcpy(&scratchpad[13], user->devAN, 7); // the coprocessor's signing challenge memcpy(&scratchpad[20], copr->signChlg, 3); OWASSERT( CreateDataSignatureVM(copr, sign_secret, user->accountFile, scratchpad, accountFile->signature, TRUE), OWERROR_SIGN_SERVICE_DATA_FAILED, FALSE ); //add the crc at the end of the data. setcrc16(user->portnum, user->accountPageNumber); for (i = 0; i < 30; i++) crc16 = docrc16(user->portnum,user->accountFile[i]); crc16 = ~crc16; accountFile->crc16[0] = (uchar)crc16; accountFile->crc16[1] = (uchar)(crc16>>8); }