1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <inttypes.h>
18 #include <stdint.h>
19 #include <stdio.h>
20 #include <string.h>
21
22 #include <nanohub/aes.h>
23 #include <nanohub/rsa.h>
24 #include <nanohub/sha2.h>
25
26 #include <appSec.h>
27 #include <bl.h>
28 #include <heap.h>
29 #include <seos.h>
30
31 #define APP_HDR_SIZE (sizeof(struct ImageHeader))
32 #define APP_HDR_MAX_SIZE (sizeof(struct ImageHeader) + sizeof(struct AppSecSignHdr) + sizeof(struct AppSecEncrHdr))
33 #define APP_DATA_CHUNK_SIZE (AES_BLOCK_WORDS * sizeof(uint32_t)) //data blocks are this size
34 #define APP_SIG_SIZE RSA_BYTES
35
36 // verify block is SHA placed in integral number of encryption blocks (for SHA256 and AES256 happens to be exactly 2 AES blocks)
37 #define APP_VERIFY_BLOCK_SIZE ((SHA2_HASH_SIZE + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE
38
39 #define APP_SEC_SIG_ALIGN APP_DATA_CHUNK_SIZE
40 #define APP_SEC_ENCR_ALIGN APP_DATA_CHUNK_SIZE
41
42 #define STATE_INIT 0 // nothing gotten yet
43 #define STATE_RXING_HEADERS 1 // variable size headers (min APP_HDR_SIZE, max APP_HDR_MAX_SIZE)
44 #define STATE_RXING_DATA 2 // each data block is AES_BLOCK_WORDS 32-bit words (for AES reasons)
45 #define STATE_RXING_SIG_HASH 3 // each is RSA_BYTES bytes
46 #define STATE_RXING_SIG_PUBKEY 4 // each is RSA_BYTES bytes
47 #define STATE_VERIFY 5 // decryption of ciphertext done; now decrypting and verifying the encrypted plaintext SHA2
48 #define STATE_DONE 6 // all is finished and well
49 #define STATE_BAD 7 // unrecoverable badness has happened. this will *NOT* fix itself. It is now ok to give up, start over, cry, or pray to your favourite deity for help
50 #define STATE_MAX 8 // total number of states
51
52 //#define DEBUG_FSM
53
54 struct AppSecState {
55 union { //we save some memory by reusing this space.
56 struct {
57 struct AesCbcContext cbc;
58 struct Sha2state sha;
59 struct Sha2state cbcSha;
60 };
61 struct {
62 struct RsaState rsa;
63 uint32_t rsaState1, rsaState2, rsaStep;
64 };
65 };
66 uint32_t rsaTmp[RSA_WORDS];
67 uint32_t lastHash[SHA2_HASH_WORDS];
68
69 AppSecWriteCbk writeCbk;
70 AppSecPubKeyFindCbk pubKeyFindCbk;
71 AppSecGetAesKeyCbk aesKeyAccessCbk;
72
73 union {
74 union { //make the compiler work to make sure we have enough space
75 uint8_t placeholderAppHdr[APP_HDR_MAX_SIZE];
76 uint8_t placeholderDataChunk[APP_DATA_CHUNK_SIZE];
77 uint8_t placeholderSigChunk[APP_SIG_SIZE];
78 uint8_t placeholderAesKey[AES_KEY_WORDS * sizeof(uint32_t)];
79 };
80 uint8_t dataBytes[0]; //we actually use these two for access
81 uint32_t dataWords[0];
82 };
83
84 uint32_t signedBytesIn;
85 uint32_t encryptedBytesIn;
86 uint32_t signedBytesOut;
87 uint32_t encryptedBytesOut;
88
89 uint16_t haveBytes; //in dataBytes...
90 uint16_t chunkSize;
91 uint8_t curState;
92 uint8_t needSig :1;
93 uint8_t haveSig :1;
94 uint8_t haveEncr :1;
95 uint8_t haveTrustedKey :1;
96 uint8_t doingRsa :1;
97 };
98
limitChunkSize(struct AppSecState * state)99 static void limitChunkSize(struct AppSecState *state)
100 {
101 if (state->haveSig && state->chunkSize > state->signedBytesIn)
102 state->chunkSize = state->signedBytesIn;
103 if (state->haveEncr && state->chunkSize > state->encryptedBytesIn)
104 state->chunkSize = state->signedBytesIn;
105 }
106
appSecSetCurState(struct AppSecState * state,uint32_t curState)107 static void appSecSetCurState(struct AppSecState *state, uint32_t curState)
108 {
109 const static uint16_t chunkSize[STATE_MAX] = {
110 [STATE_RXING_HEADERS] = APP_HDR_SIZE,
111 [STATE_RXING_DATA] = APP_DATA_CHUNK_SIZE,
112 [STATE_VERIFY] = APP_VERIFY_BLOCK_SIZE,
113 [STATE_RXING_SIG_HASH] = APP_SIG_SIZE,
114 [STATE_RXING_SIG_PUBKEY] = APP_SIG_SIZE,
115 };
116 if (curState >= STATE_MAX)
117 curState = STATE_BAD;
118 if (curState != state->curState || curState == STATE_INIT) {
119 #ifdef DEBUG_FSM
120 osLog(LOG_INFO, "%s: oldState=%" PRIu8
121 "; new state=%" PRIu32
122 "; old chunk size=%" PRIu16
123 "; new chunk size=%" PRIu16
124 "; have bytes=%" PRIu16
125 "\n",
126 __func__, state->curState, curState,
127 state->chunkSize, chunkSize[curState],
128 state->haveBytes);
129 #endif
130 state->curState = curState;
131 state->chunkSize = chunkSize[curState];
132 }
133 }
134
appSecGetCurState(const struct AppSecState * state)135 static inline uint32_t appSecGetCurState(const struct AppSecState *state)
136 {
137 return state->curState;
138 }
139
140 //init/deinit
appSecInit(AppSecWriteCbk writeCbk,AppSecPubKeyFindCbk pubKeyFindCbk,AppSecGetAesKeyCbk aesKeyAccessCbk,bool mandateSigning)141 struct AppSecState *appSecInit(AppSecWriteCbk writeCbk, AppSecPubKeyFindCbk pubKeyFindCbk, AppSecGetAesKeyCbk aesKeyAccessCbk, bool mandateSigning)
142 {
143 struct AppSecState *state = heapAlloc(sizeof(struct AppSecState));
144
145 if (!state)
146 return NULL;
147
148 memset(state, 0, sizeof(struct AppSecState));
149
150 state->writeCbk = writeCbk;
151 state->pubKeyFindCbk = pubKeyFindCbk;
152 state->aesKeyAccessCbk = aesKeyAccessCbk;
153 appSecSetCurState(state, STATE_INIT);
154 if (mandateSigning)
155 state->needSig = 1;
156
157 return state;
158 }
159
appSecDeinit(struct AppSecState * state)160 void appSecDeinit(struct AppSecState *state)
161 {
162 heapFree(state);
163 }
164
165 //if needed, decrypt and hash incoming data
appSecBlockRx(struct AppSecState * state)166 static AppSecErr appSecBlockRx(struct AppSecState *state)
167 {
168 //if signatures are on, hash it
169 if (state->haveSig) {
170
171 //make sure we do not get too much data & account for the data we got
172 if (state->haveBytes > state->signedBytesIn)
173 return APP_SEC_TOO_MUCH_DATA;
174 state->signedBytesIn -= state->haveBytes;
175
176 //make sure we do not produce too much data (discard padding) & make sure we account for it
177 if (state->signedBytesOut < state->haveBytes)
178 state->haveBytes = state->signedBytesOut;
179 state->signedBytesOut -= state->haveBytes;
180
181 //hash the data
182 BL.blSha2processBytes(&state->sha, state->dataBytes, state->haveBytes);
183 }
184
185 // decrypt if encryption is on
186 if (state->haveEncr) {
187
188 uint32_t *dataP = state->dataWords;
189 uint32_t i, numBlocks = state->haveBytes / APP_DATA_CHUNK_SIZE;
190
191 //we should not be called with partial encr blocks
192 if (state->haveBytes % APP_DATA_CHUNK_SIZE)
193 return APP_SEC_TOO_LITTLE_DATA;
194
195 // make sure we do not get too much data & account for the data we got
196 if (state->haveBytes > state->encryptedBytesIn)
197 return APP_SEC_TOO_MUCH_DATA;
198 state->encryptedBytesIn -= state->haveBytes;
199
200 // decrypt
201 for (i = 0; i < numBlocks; i++, dataP += AES_BLOCK_WORDS)
202 BL.blAesCbcDecr(&state->cbc, dataP, dataP);
203
204 // make sure we do not produce too much data (discard padding) & make sure we account for it
205 if (state->encryptedBytesOut < state->haveBytes)
206 state->haveBytes = state->encryptedBytesOut;
207 state->encryptedBytesOut -= state->haveBytes;
208
209 if (state->haveBytes)
210 BL.blSha2processBytes(&state->cbcSha, state->dataBytes, state->haveBytes);
211 }
212
213 limitChunkSize(state);
214
215 return APP_SEC_NO_ERROR;
216 }
217
appSecProcessIncomingHdr(struct AppSecState * state,uint32_t * needBytesOut)218 static AppSecErr appSecProcessIncomingHdr(struct AppSecState *state, uint32_t *needBytesOut)
219 {
220 struct ImageHeader *image;
221 struct nano_app_binary_t *aosp;
222 uint32_t flags;
223 uint32_t needBytes;
224 struct AppSecSignHdr *signHdr = NULL;
225 struct AppSecEncrHdr *encrHdr = NULL;
226 uint8_t *hdr = state->dataBytes;
227 AppSecErr ret;
228
229 image = (struct ImageHeader *)hdr; hdr += sizeof(*image);
230 aosp = &image->aosp;
231 flags = aosp->flags;
232 if (aosp->header_version != 1 ||
233 aosp->magic != NANOAPP_AOSP_MAGIC ||
234 image->layout.version != 1 ||
235 image->layout.magic != GOOGLE_LAYOUT_MAGIC)
236 return APP_SEC_HEADER_ERROR;
237
238 needBytes = sizeof(*image);
239 if ((flags & NANOAPP_SIGNED_FLAG) != 0)
240 needBytes += sizeof(*signHdr);
241 if ((flags & NANOAPP_ENCRYPTED_FLAG) != 0)
242 needBytes += sizeof(*encrHdr);
243
244 *needBytesOut = needBytes;
245
246 if (needBytes > state->haveBytes)
247 return APP_SEC_NO_ERROR;
248
249 *needBytesOut = 0;
250
251 if ((flags & NANOAPP_SIGNED_FLAG) != 0) {
252 signHdr = (struct AppSecSignHdr *)hdr; hdr += sizeof(*signHdr);
253 osLog(LOG_INFO, "%s: signed size=%" PRIu32 "\n",
254 __func__, signHdr->appDataLen);
255 if (!signHdr->appDataLen) {
256 //no data bytes
257 return APP_SEC_INVALID_DATA;
258 }
259 state->signedBytesIn = state->signedBytesOut = signHdr->appDataLen;
260 state->haveSig = 1;
261 BL.blSha2init(&state->sha);
262 BL.blSha2processBytes(&state->sha, state->dataBytes, needBytes);
263 }
264
265 if ((flags & NANOAPP_ENCRYPTED_FLAG) != 0) {
266 uint32_t k[AES_KEY_WORDS];
267
268 encrHdr = (struct AppSecEncrHdr *)hdr; hdr += sizeof(*encrHdr);
269 osLog(LOG_INFO, "%s: encrypted data size=%" PRIu32
270 "; key ID=%016" PRIX64 "\n",
271 __func__, encrHdr->dataLen, encrHdr->keyID);
272
273 if (!encrHdr->dataLen || !encrHdr->keyID)
274 return APP_SEC_INVALID_DATA;
275 ret = state->aesKeyAccessCbk(encrHdr->keyID, k);
276 if (ret != APP_SEC_NO_ERROR) {
277 osLog(LOG_ERROR, "%s: Secret key not found\n", __func__);
278 return ret;
279 }
280
281 BL.blAesCbcInitForDecr(&state->cbc, k, encrHdr->IV);
282 BL.blSha2init(&state->cbcSha);
283 state->encryptedBytesOut = encrHdr->dataLen;
284 state->encryptedBytesIn = ((state->encryptedBytesOut + APP_SEC_ENCR_ALIGN - 1) / APP_SEC_ENCR_ALIGN) * APP_SEC_ENCR_ALIGN;
285 state->haveEncr = 1;
286 osLog(LOG_INFO, "%s: encrypted aligned data size=%" PRIu32 "\n",
287 __func__, state->encryptedBytesIn);
288
289 if (state->haveSig) {
290 state->signedBytesIn = state->signedBytesOut = signHdr->appDataLen - sizeof(*encrHdr);
291 // at this point, signedBytesOut must equal encryptedBytesIn
292 if (state->signedBytesOut != (state->encryptedBytesIn + SHA2_HASH_SIZE)) {
293 osLog(LOG_ERROR, "%s: sig data size does not match encrypted data\n", __func__);
294 return APP_SEC_INVALID_DATA;
295 }
296 }
297 }
298
299 //if we are in must-sign mode and no signature was provided, fail
300 if (!state->haveSig && state->needSig) {
301 osLog(LOG_ERROR, "%s: only signed images can be uploaded\n", __func__);
302 return APP_SEC_SIG_VERIFY_FAIL;
303 }
304
305 // now, transform AOSP header to FW common header
306 struct FwCommonHdr common = {
307 .magic = APP_HDR_MAGIC,
308 .appId = aosp->app_id,
309 .fwVer = APP_HDR_VER_CUR,
310 .fwFlags = image->layout.flags,
311 .appVer = aosp->app_version,
312 .payInfoType = image->layout.payload,
313 .chreApiMajor = 0xFF,
314 .chreApiMinor = 0xFF,
315 };
316
317 if (image->layout.flags & FL_APP_HDR_CHRE) {
318 if (aosp->chre_api_major || aosp->chre_api_minor) {
319 common.chreApiMajor = aosp->chre_api_major;
320 common.chreApiMinor = aosp->chre_api_minor;
321 } else {
322 // fields not defined prior to CHRE 1.1
323 common.chreApiMajor = 0x01;
324 common.chreApiMinor = 0x00;
325 }
326 }
327
328 // check to see if this is special system types of payload
329 switch(image->layout.payload) {
330 case LAYOUT_APP:
331 common.fwFlags = (common.fwFlags | FL_APP_HDR_APPLICATION) & ~FL_APP_HDR_INTERNAL;
332 common.payInfoSize = sizeof(struct AppInfo);
333 osLog(LOG_INFO, "App container found\n");
334 break;
335 case LAYOUT_KEY:
336 common.fwFlags |= FL_APP_HDR_SECURE;
337 common.payInfoSize = sizeof(struct KeyInfo);
338 osLog(LOG_INFO, "Key container found\n");
339 break;
340 case LAYOUT_OS:
341 common.payInfoSize = sizeof(struct OsUpdateHdr);
342 osLog(LOG_INFO, "OS update container found\n");
343 break;
344 default:
345 break;
346 }
347
348 memcpy(state->dataBytes, &common, sizeof(common));
349 state->haveBytes = sizeof(common);
350
351 //we're now in data-accepting state
352 appSecSetCurState(state, STATE_RXING_DATA);
353
354 return APP_SEC_NO_ERROR;
355 }
356
appSecProcessIncomingData(struct AppSecState * state)357 static AppSecErr appSecProcessIncomingData(struct AppSecState *state)
358 {
359 //check for data-ending conditions
360 if (state->haveSig && !state->signedBytesIn) {
361 // we're all done with the signed portion of the data, now come the signatures
362 appSecSetCurState(state, STATE_RXING_SIG_HASH);
363
364 //collect the hash
365 memcpy(state->lastHash, BL.blSha2finish(&state->sha), SHA2_HASH_SIZE);
366 } else if (state->haveEncr && !state->encryptedBytesIn) {
367 if (appSecGetCurState(state) == STATE_RXING_DATA) {
368 //we're all done with encrypted plaintext
369 state->encryptedBytesIn = sizeof(state->cbcSha);
370 appSecSetCurState(state, STATE_VERIFY);
371 }
372 }
373
374 //pass to caller
375 return state->haveBytes ? state->writeCbk(state->dataBytes, state->haveBytes) : APP_SEC_NO_ERROR;
376 }
377
appSecDoSomeProcessing(struct AppSecState * state)378 AppSecErr appSecDoSomeProcessing(struct AppSecState *state)
379 {
380 const uint32_t *result;
381
382 if (!state->doingRsa) {
383 //shouldn't be calling us then...
384 return APP_SEC_BAD;
385 }
386
387 result = BL.blRsaPubOpIterative(&state->rsa, state->rsaTmp, state->dataWords, &state->rsaState1, &state->rsaState2, &state->rsaStep);
388 if (state->rsaStep)
389 return APP_SEC_NEED_MORE_TIME;
390
391 //we just finished the RSA-ing
392 state->doingRsa = 0;
393
394 //verify signature padding (and thus likely: correct decryption)
395 result = BL.blSigPaddingVerify(result);
396 if (!result)
397 return APP_SEC_SIG_DECODE_FAIL;
398
399 //check if hashes match
400 if (memcmp(state->lastHash, result, SHA2_HASH_SIZE))
401 return APP_SEC_SIG_VERIFY_FAIL;
402
403 //hash the provided pubkey
404 BL.blSha2init(&state->sha);
405 BL.blSha2processBytes(&state->sha, state->dataBytes, APP_SIG_SIZE);
406 memcpy(state->lastHash, BL.blSha2finish(&state->sha), SHA2_HASH_SIZE);
407 appSecSetCurState(state, STATE_RXING_SIG_HASH);
408
409 return APP_SEC_NO_ERROR;
410 }
411
appSecProcessIncomingSigData(struct AppSecState * state)412 static AppSecErr appSecProcessIncomingSigData(struct AppSecState *state)
413 {
414 bool keyFound = false;
415
416 //if we're RXing the hash, just stash it away and move on
417 if (appSecGetCurState(state) == STATE_RXING_SIG_HASH) {
418 state->haveTrustedKey = 0;
419 memcpy(state->rsaTmp, state->dataWords, APP_SIG_SIZE);
420 appSecSetCurState(state, STATE_RXING_SIG_PUBKEY);
421 return APP_SEC_NO_ERROR;
422 }
423
424 // verify it is a known root
425 state->pubKeyFindCbk(state->dataWords, &keyFound);
426 state->haveTrustedKey = keyFound;
427
428 //we now have the pubKey. decrypt over time
429 state->doingRsa = 1;
430 state->rsaStep = 0;
431 return APP_SEC_NEED_MORE_TIME;
432 }
433
appSecVerifyEncryptedData(struct AppSecState * state)434 static AppSecErr appSecVerifyEncryptedData(struct AppSecState *state)
435 {
436 const uint32_t *hash = BL.blSha2finish(&state->cbcSha);
437 bool verified = memcmp(hash, state->dataBytes, SHA2_BLOCK_SIZE) == 0;
438
439 osLog(LOG_INFO, "%s: decryption verification: %s\n", __func__, verified ? "passed" : "failed");
440
441 // TODO: fix verify logic
442 // return verified ? APP_SEC_NO_ERROR : APP_SEC_VERIFY_FAILED;
443 return APP_SEC_NO_ERROR;
444 }
445
appSecRxData(struct AppSecState * state,const void * dataP,uint32_t len,uint32_t * lenUnusedP)446 AppSecErr appSecRxData(struct AppSecState *state, const void *dataP, uint32_t len, uint32_t *lenUnusedP)
447 {
448 const uint8_t *data = (const uint8_t*)dataP;
449 AppSecErr ret = APP_SEC_NO_ERROR;
450 uint32_t needBytes;
451
452 if (appSecGetCurState(state) == STATE_INIT)
453 appSecSetCurState(state, STATE_RXING_HEADERS);
454
455 while (len) {
456 len--;
457 state->dataBytes[state->haveBytes++] = *data++;
458 if (state->haveBytes < state->chunkSize)
459 continue;
460 switch (appSecGetCurState(state)) {
461 case STATE_RXING_HEADERS:
462 // AOSP header is never encrypted; if it is signed, it will hash itself
463 needBytes = 0;
464 ret = appSecProcessIncomingHdr(state, &needBytes);
465 if (ret != APP_SEC_NO_ERROR)
466 goto out;
467 if (needBytes > state->chunkSize) {
468 state->chunkSize = needBytes;
469 // get more data and try again
470 continue;
471 }
472 // done with parsing header(s); we might have something to write to flash
473 if (state->haveBytes) {
474 osLog(LOG_INFO, "%s: save converted header [%" PRIu16 " bytes] to flash\n", __func__, state->haveBytes);
475 ret = appSecProcessIncomingData(state);
476 state->haveBytes = 0;
477 }
478 limitChunkSize(state);
479 goto out;
480
481 case STATE_RXING_DATA:
482 ret = appSecBlockRx(state);
483 if (ret != APP_SEC_NO_ERROR)
484 goto out;
485
486 ret = appSecProcessIncomingData(state);
487 state->haveBytes = 0;
488 if (ret != APP_SEC_NO_ERROR)
489 goto out;
490 break;
491
492 case STATE_VERIFY:
493 ret = appSecBlockRx(state);
494 if (ret == APP_SEC_NO_ERROR)
495 ret = appSecProcessIncomingData(state);
496 if (ret == APP_SEC_NO_ERROR)
497 ret = appSecVerifyEncryptedData(state);
498 goto out;
499
500 case STATE_RXING_SIG_HASH:
501 case STATE_RXING_SIG_PUBKEY:
502 //no need for calling appSecBlockRx() as sigs are not signed, and encryption cannot be done after signing
503 ret = appSecProcessIncomingSigData(state);
504 state->haveBytes = 0;
505 goto out;
506
507 default:
508 appSecSetCurState(state, STATE_BAD);
509 state->haveBytes = 0;
510 len = 0;
511 ret = APP_SEC_BAD;
512 break;
513 }
514 }
515
516 out:
517 *lenUnusedP = len;
518
519 if (ret != APP_SEC_NO_ERROR && ret != APP_SEC_NEED_MORE_TIME) {
520 osLog(LOG_ERROR, "%s: failed: state=%" PRIu32 "; err=%" PRIu32 "\n",
521 __func__, appSecGetCurState(state), ret);
522 appSecSetCurState(state, STATE_BAD);
523 }
524
525 return ret;
526 }
527
appSecRxDataOver(struct AppSecState * state)528 AppSecErr appSecRxDataOver(struct AppSecState *state)
529 {
530 AppSecErr ret;
531
532 // Feed remaining data to data processor, if any
533 if (state->haveBytes) {
534 // if we are using encryption and/or signing, we are supposed to consume all data at this point.
535 if (state->haveSig || state->haveEncr) {
536 appSecSetCurState(state, STATE_BAD);
537 return APP_SEC_TOO_LITTLE_DATA;
538 }
539 // Not in data rx stage when the incoming data ends? This is not good (if we had encr or sign we'd not be here)
540 if (appSecGetCurState(state) != STATE_RXING_DATA) {
541 appSecSetCurState(state, STATE_BAD);
542 return APP_SEC_TOO_LITTLE_DATA;
543 }
544 // Feed the remaining data to the data processor
545 ret = appSecProcessIncomingData(state);
546 if (ret != APP_SEC_NO_ERROR) {
547 appSecSetCurState(state, STATE_BAD);
548 return ret;
549 }
550 } else {
551 // we don't know in advance how many signature packs we shall receive,
552 // so we evaluate every signature pack as if it is the last, but do not
553 // return error if public key is not trusted; only here we make the final
554 // determination
555 if (state->haveSig) {
556 // check the most recent key status
557 if (!state->haveTrustedKey) {
558 appSecSetCurState(state, STATE_BAD);
559 return APP_SEC_SIG_ROOT_UNKNOWN;
560 } else {
561 appSecSetCurState(state, STATE_DONE);
562 }
563 }
564 }
565
566 //for unsigned/unencrypted case we have no way to judge length, so we assume it is over when we're told it is
567 //this is potentially dangerous, but then again so is allowing unsigned uploads in general.
568 if (!state->haveSig && !state->haveEncr && appSecGetCurState(state) == STATE_RXING_DATA)
569 appSecSetCurState(state, STATE_DONE);
570
571 //Check the state and return our verdict
572 if(appSecGetCurState(state) == STATE_DONE)
573 return APP_SEC_NO_ERROR;
574
575 appSecSetCurState(state, STATE_BAD);
576 return APP_SEC_TOO_LITTLE_DATA;
577 }
578