1 /*
2  * attest_token_decode_common.c
3  *
4  * Copyright (c) 2019, Laurence Lundblade.
5  * Copyright (c) 2020-2022, Arm Limited. All rights reserved.
6  *
7  * SPDX-License-Identifier: BSD-3-Clause
8  *
9  * See BSD-3-Clause license in README.md
10  */
11 
12 #include "attest_token_decode.h"
13 #include "attest.h"
14 #include "q_useful_buf.h"
15 #include "qcbor_util.h"
16 #include "config_attest.h"
17 
18 /**
19  * \file attest_token_decode_common.c
20  *
21  * \brief Common functions in attestation token decoder.
22  *
23  * This decodes and verifies an attestation token giving access to the
24  * data items in the token. The data items are also known as claims.
25  *
26  * This is written primarily as tests for the token encoder, though it
27  * close to a full commercial token decoder. The main thing missing is
28  * a thorough test suite for it. Test before commercial use is
29  * important as this is a parser / decoder and thus subject to attack
30  * by malicious input. It does however, use QCBOR for most base
31  * parsing, and QCBOR is thoroughly tested and commercial.
32  *
33  * This is oriented around the Arm-defined initial attestation token.
34  *
35  * \c uint_fast8_t is used for type and nest levels. They are
36  * 8-bit quantities, but making using uint8_t variables
37  * and parameters can result in bigger, slower code.
38  * \c uint_fast8_t is part of \c <stdint.h>. It is not
39  * used in structures where it is more important to keep
40  * the size smaller.
41  */
42 
43 
44 /**
45  * Compute the bit indicating a claim is present
46  */
47 #define CLAIM_PRESENT_BIT(item_index) (0x01U << (item_index))
48 
49 
50 /*
51  * Public function. See attest_token_decode.h
52  */
attest_token_decode_init(struct attest_token_decode_context * me,uint32_t options)53 void attest_token_decode_init(struct attest_token_decode_context *me,
54                               uint32_t options)
55 {
56     memset(me, 0, sizeof(struct attest_token_decode_context));
57     me->options = options;
58     me->last_error = ATTEST_TOKEN_ERR_NO_VALID_TOKEN;
59 }
60 
61 /*
62  * Public function. See attest_token_decode.h
63  */
64 enum attest_token_err_t
attest_token_decode_get_bstr(struct attest_token_decode_context * me,int32_t label,struct q_useful_buf_c * claim)65 attest_token_decode_get_bstr(struct attest_token_decode_context *me,
66                              int32_t label,
67                              struct q_useful_buf_c *claim)
68 {
69     enum attest_token_err_t return_value;
70     QCBORItem               item;
71 
72     if(me->last_error != ATTEST_TOKEN_ERR_SUCCESS) {
73         return_value = me->last_error;
74         *claim = NULL_Q_USEFUL_BUF_C;
75         goto Done;
76     }
77 
78     return_value = qcbor_util_get_top_level_item_in_map(me->payload,
79                                                        label,
80                                                        QCBOR_TYPE_BYTE_STRING,
81                                                        &item);
82     if(return_value != ATTEST_TOKEN_ERR_SUCCESS) {
83         goto Done;
84     }
85 
86     *claim = item.val.string;
87 
88 Done:
89     return return_value;
90 }
91 
92 
93 /*
94  * Public function. See attest_token_decode.h
95  */
96 enum attest_token_err_t
attest_token_decode_get_tstr(struct attest_token_decode_context * me,int32_t label,struct q_useful_buf_c * claim)97 attest_token_decode_get_tstr(struct attest_token_decode_context *me,
98                              int32_t label,
99                              struct q_useful_buf_c *claim)
100 {
101     enum attest_token_err_t return_value;
102     QCBORItem               item;
103 
104     if(me->last_error != ATTEST_TOKEN_ERR_SUCCESS) {
105         return_value = me->last_error;
106         *claim = NULL_Q_USEFUL_BUF_C;
107         goto Done;
108     }
109 
110     return_value = qcbor_util_get_top_level_item_in_map(me->payload,
111                                                        label,
112                                                        QCBOR_TYPE_TEXT_STRING,
113                                                        &item);
114     if(return_value != ATTEST_TOKEN_ERR_SUCCESS) {
115         goto Done;
116     }
117 
118     *claim = item.val.string;
119 
120 Done:
121     return return_value;
122 }
123 
124 
125 /*
126  * Public function. See attest_token_decode.h
127  */
128 enum attest_token_err_t
attest_token_decode_get_int(struct attest_token_decode_context * me,int32_t label,int64_t * integer)129 attest_token_decode_get_int(struct attest_token_decode_context *me,
130                             int32_t label,
131                             int64_t *integer)
132 {
133     enum attest_token_err_t return_value;
134     QCBORItem               item;
135     QCBORDecodeContext      decode_context;
136 
137     if(me->last_error != ATTEST_TOKEN_ERR_SUCCESS) {
138         return_value = me->last_error;
139         *integer = 0;
140         goto Done;
141     }
142 
143     QCBORDecode_Init(&decode_context, me->payload, QCBOR_DECODE_MODE_NORMAL);
144 
145     return_value = qcbor_util_get_item_in_map(&decode_context,
146                                              label,
147                                              &item);
148     if(return_value != ATTEST_TOKEN_ERR_SUCCESS) {
149         goto Done;
150     }
151 
152     if(QCBORDecode_Finish(&decode_context)) {
153         return_value = ATTEST_TOKEN_ERR_CBOR_STRUCTURE;
154     }
155 
156     if(item.uDataType == QCBOR_TYPE_INT64) {
157         *integer = item.val.int64;
158     } else if(item.uDataType == QCBOR_TYPE_UINT64) {
159         if(item.val.uint64 < INT64_MAX) {
160             *integer = (int64_t)item.val.uint64;
161         } else {
162             return_value = ATTEST_TOKEN_ERR_INTEGER_VALUE;
163         }
164     } else {
165         return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
166     }
167 
168 Done:
169     return return_value;
170 }
171 
172 
173 /*
174  * Public function. See attest_token_decode.h
175  */
176 enum attest_token_err_t
attest_token_decode_get_uint(struct attest_token_decode_context * me,int32_t label,uint64_t * integer)177 attest_token_decode_get_uint(struct attest_token_decode_context *me,
178                              int32_t label,
179                              uint64_t *integer)
180 {
181     enum attest_token_err_t return_value;
182     QCBORItem               item;
183     QCBORDecodeContext      decode_context;
184 
185     if(me->last_error != ATTEST_TOKEN_ERR_SUCCESS) {
186         return_value = me->last_error;
187         *integer = 0;
188         goto Done;
189     }
190 
191     QCBORDecode_Init(&decode_context, me->payload, QCBOR_DECODE_MODE_NORMAL);
192 
193     return_value = qcbor_util_get_item_in_map(&decode_context,
194                                              label,
195                                              &item);
196     if(return_value != 0) {
197         goto Done;
198     }
199 
200     if(QCBORDecode_Finish(&decode_context)) {
201         return_value = ATTEST_TOKEN_ERR_CBOR_STRUCTURE;
202     }
203 
204     if(item.uDataType == QCBOR_TYPE_UINT64) {
205         *integer = item.val.uint64;
206     } else if(item.uDataType == QCBOR_TYPE_INT64) {
207         if(item.val.int64 >= 0) {
208             *integer = (uint64_t)item.val.int64;
209         } else {
210             return_value = ATTEST_TOKEN_ERR_INTEGER_VALUE;
211         }
212     } else {
213         return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
214     }
215 
216 Done:
217     return return_value;
218 }
219 
220 
221 /*
222  * Public function. See attest_token_decode.h
223  */
224 enum attest_token_err_t
attest_token_decode_get_payload(struct attest_token_decode_context * me,struct q_useful_buf_c * payload)225 attest_token_decode_get_payload(struct attest_token_decode_context *me,
226                                 struct q_useful_buf_c *payload)
227 {
228     enum attest_token_err_t return_value;
229 
230     if(me->last_error != ATTEST_TOKEN_ERR_SUCCESS) {
231         return_value = me->last_error;
232         *payload = NULL_Q_USEFUL_BUF_C;
233         goto Done;
234     }
235 
236     if(q_useful_buf_c_is_null_or_empty(me->payload)) {
237         return_value = ATTEST_TOKEN_ERR_NO_VALID_TOKEN;
238         goto Done;
239     }
240 
241     *payload = me->payload;
242     return_value = ATTEST_TOKEN_ERR_SUCCESS;
243 
244 Done:
245     return return_value;
246 }
247 
248 
249 /*
250  * Public function. See attest_token_decode.h
251  */
252 enum attest_token_err_t
attest_token_decode_get_iat_simple(struct attest_token_decode_context * me,struct attest_token_iat_simple_t * items)253 attest_token_decode_get_iat_simple(struct attest_token_decode_context *me,
254                                    struct attest_token_iat_simple_t *items)
255 {
256     struct qcbor_util_items_to_get_t  list[NUMBER_OF_ITEMS+1];
257     QCBORDecodeContext                decode_context;
258     int64_t                           client_id_64;
259     enum attest_token_err_t           return_value;
260 
261     /* Set all q_useful_bufs to NULL and flags to 0 */
262     memset(items, 0, sizeof(struct attest_token_iat_simple_t));
263 
264     /* Re use flags as array indexes because it works nicely */
265     list[NONCE_FLAG].label                = IAT_NONCE;
266     list[INSTANCE_ID_FLAG].label          = IAT_INSTANCE_ID;
267     list[BOOT_SEED_FLAG].label            = IAT_BOOT_SEED;
268     list[CERT_REF_FLAG].label             = IAT_CERTIFICATION_REFERENCE;
269     list[IMPLEMENTATION_ID_FLAG].label    = IAT_IMPLEMENTATION_ID;
270     list[CLIENT_ID_FLAG].label            = IAT_CLIENT_ID;
271     list[SECURITY_LIFECYCLE_FLAG].label   = IAT_SECURITY_LIFECYCLE;
272     list[PROFILE_DEFINITION_FLAG].label   = IAT_PROFILE_DEFINITION;
273     list[VERIFICATION_SERVICE_FLAG].label = IAT_VERIFICATION_SERVICE;
274 #if ATTEST_TOKEN_PROFILE_ARM_CCA
275     list[PLAT_HASH_ALGO_ID].label         = IAT_PLATFORM_HASH_ALGO_ID;
276     list[PLAT_CONFIG].label               = IAT_PLATFORM_CONFIG;
277 #endif
278     list[NUMBER_OF_ITEMS].label           = 0; /* terminate the list. */
279 
280     if(me->last_error != ATTEST_TOKEN_ERR_SUCCESS) {
281         return_value = me->last_error;
282         goto Done;
283     }
284 
285     QCBORDecode_Init(&decode_context, me->payload, QCBOR_DECODE_MODE_NORMAL);
286 
287     return_value = qcbor_util_get_items_in_map(&decode_context,
288                                               list);
289     if(return_value != ATTEST_TOKEN_ERR_SUCCESS) {
290         goto Done;
291     }
292 
293     /* ---- NONCE ---- */
294     if(list[NONCE_FLAG].item.uDataType == QCBOR_TYPE_BYTE_STRING) {
295         items->nonce = list[NONCE_FLAG].item.val.string;
296         items->item_flags |= CLAIM_PRESENT_BIT(NONCE_FLAG);
297     }
298 
299     /* ---- Instance ID -------*/
300     if(list[INSTANCE_ID_FLAG].item.uDataType == QCBOR_TYPE_BYTE_STRING) {
301         items->instance_id = list[INSTANCE_ID_FLAG].item.val.string;
302         items->item_flags |= CLAIM_PRESENT_BIT(INSTANCE_ID_FLAG);
303     }
304 
305     /* ---- BOOT SEED -------*/
306     if(list[BOOT_SEED_FLAG].item.uDataType ==  QCBOR_TYPE_BYTE_STRING) {
307         items->boot_seed = list[BOOT_SEED_FLAG].item.val.string;
308         items->item_flags |= CLAIM_PRESENT_BIT(BOOT_SEED_FLAG);\
309     }
310 
311     /* ---- CERTIFICATION REFERENCE -------*/
312     if(list[CERT_REF_FLAG].item.uDataType == QCBOR_TYPE_TEXT_STRING) {
313         items->cert_ref = list[CERT_REF_FLAG].item.val.string;
314         items->item_flags |= CLAIM_PRESENT_BIT(CERT_REF_FLAG);
315 
316     }
317 
318     /* ----IMPLEMENTATION ID -------*/
319     if(list[IMPLEMENTATION_ID_FLAG].item.uDataType == QCBOR_TYPE_BYTE_STRING) {
320         items->implementation_id = list[IMPLEMENTATION_ID_FLAG].item.val.string;
321         items->item_flags |= CLAIM_PRESENT_BIT(IMPLEMENTATION_ID_FLAG);
322     }
323 
324     /* ----CLIENT ID -------*/
325     if(list[CLIENT_ID_FLAG].item.uDataType == QCBOR_TYPE_INT64) {
326         client_id_64 = list[CLIENT_ID_FLAG].item.val.int64;
327         if(client_id_64 < INT32_MAX || client_id_64 > INT32_MIN) {
328             items->client_id = (int32_t)client_id_64;
329             items->item_flags |= CLAIM_PRESENT_BIT(CLIENT_ID_FLAG);
330         }
331     }
332 
333     /* ----SECURITY LIFECYCLE -------*/
334     if(list[SECURITY_LIFECYCLE_FLAG].item.uDataType == QCBOR_TYPE_INT64) {
335         if(list[SECURITY_LIFECYCLE_FLAG].item.val.int64 < UINT32_MAX) {
336             items->security_lifecycle =
337                 (uint32_t)list[SECURITY_LIFECYCLE_FLAG].item.val.int64;
338             items->item_flags |=CLAIM_PRESENT_BIT(SECURITY_LIFECYCLE_FLAG);
339         }
340     }
341 
342     /* ---- PROFILE_DEFINITION -------*/
343     if(list[PROFILE_DEFINITION_FLAG].item.uDataType == QCBOR_TYPE_TEXT_STRING) {
344         items->profile_definition=list[PROFILE_DEFINITION_FLAG].item.val.string;
345         items->item_flags |= CLAIM_PRESENT_BIT(PROFILE_DEFINITION_FLAG);
346     }
347 
348     /* ---- VERIFICATION_SERVICE -------*/
349     if(list[VERIFICATION_SERVICE_FLAG].item.uDataType == QCBOR_TYPE_TEXT_STRING) {
350         items->verif_serv =
351             list[VERIFICATION_SERVICE_FLAG].item.val.string;
352         items->item_flags |= CLAIM_PRESENT_BIT(VERIFICATION_SERVICE_FLAG);
353     }
354 
355 Done:
356     return return_value;
357 }
358 
359 
360 /*
361  * Public function. See attest_token_decode.h
362  */
363 enum attest_token_err_t
attest_token_get_num_sw_components(struct attest_token_decode_context * me,uint32_t * num_sw_components)364 attest_token_get_num_sw_components(struct attest_token_decode_context *me,
365                                    uint32_t *num_sw_components)
366 {
367     enum attest_token_err_t return_value;
368     QCBORItem               item;
369 
370     if(me->last_error != ATTEST_TOKEN_ERR_SUCCESS) {
371         return_value = me->last_error;
372         goto Done;
373     }
374 
375     return_value = qcbor_util_get_top_level_item_in_map(me->payload,
376                                         IAT_SW_COMPONENTS,
377                                         QCBOR_TYPE_ARRAY,
378                                         &item);
379     if(return_value != ATTEST_TOKEN_ERR_SUCCESS) {
380 #if ATTEST_TOKEN_PROFILE_PSA_IOT_1 /* Other profiles mandates the SW comp*/
381         if(return_value == ATTEST_TOKEN_ERR_NOT_FOUND) {
382             /* Now decide if it was intentionally left out. */
383             return_value = qcbor_util_get_top_level_item_in_map(me->payload,
384                                           IAT_NO_SW_COMPONENTS,
385                                           QCBOR_TYPE_INT64,
386                                           &item);
387             if(return_value == ATTEST_TOKEN_ERR_SUCCESS) {
388                 if(item.val.int64 == NO_SW_COMPONENT_FIXED_VALUE) {
389                     /* Successful omission of SW components. Pass on the
390                      * success return_value */
391                     *num_sw_components = 0;
392                 } else {
393                     /* Indicator for no SW components malformed */
394                     return_value = ATTEST_TOKEN_ERR_SW_COMPONENTS_MISSING;
395                 }
396             } else if(return_value == ATTEST_TOKEN_ERR_NOT_FOUND) {
397                 /* Should have been an indicator for no SW components */
398                 return_value = ATTEST_TOKEN_ERR_SW_COMPONENTS_MISSING;
399             }
400         }
401 #endif /* ATTEST_TOKEN_PROFILE_PSA_IOT_1 */
402         goto Done;
403     } else {
404         /* The SW components claim exists */
405         if(item.val.uCount == 0) {
406             /* Empty SW component not allowed */
407             return_value = ATTEST_TOKEN_ERR_SW_COMPONENTS_MISSING;
408         } else {
409             /* SUCCESS! Pass on the success return_value */
410             /* Note that this assumes the array is definite length */
411             *num_sw_components = item.val.uCount;
412         }
413     }
414 
415 Done:
416     return return_value;
417 }
418 
419 
420 /**
421  * \brief Decode a single SW component
422  *
423  * \param[in] decode_context    The CBOR decoder context to decode from
424  * \param[in] sw_component_item The top-level map item for this SW
425  *                              component.
426  * \param[out] sw_component     The structure to fill in with decoded data.
427  *
428  * \return An error from \ref attest_token_err_t.
429  *
430  */
431 static inline enum attest_token_err_t
decode_sw_component(QCBORDecodeContext * decode_context,const QCBORItem * sw_component_item,struct attest_token_sw_component_t * sw_component)432 decode_sw_component(QCBORDecodeContext               *decode_context,
433                     const QCBORItem                  *sw_component_item,
434                     struct attest_token_sw_component_t *sw_component)
435 {
436     enum attest_token_err_t return_value;
437     QCBORItem claim_item;
438     QCBORError cbor_error;
439     uint_fast8_t next_nest_level; /* nest levels are 8-bit, but a uint8_t
440                                      var is often slower and more code */
441 
442     if(sw_component_item->uDataType != QCBOR_TYPE_MAP) {
443         return_value = ATTEST_TOKEN_ERR_CBOR_STRUCTURE;
444         goto Done;
445     }
446 
447     /* Zero it, setting booleans to false, pointers to NULL and
448        lengths to 0 */
449     memset(sw_component, 0, sizeof(struct attest_token_sw_component_t));
450 
451     return_value = ATTEST_TOKEN_ERR_SUCCESS;
452 
453     while(1) {
454         cbor_error = QCBORDecode_GetNext(decode_context, &claim_item);
455         if(cbor_error != QCBOR_SUCCESS) {
456             /* no tolerance for any errors here */
457             return_value = ATTEST_TOKEN_ERR_CBOR_NOT_WELL_FORMED;
458             goto Done;
459         }
460 
461         if(claim_item.uLabelType == QCBOR_TYPE_INT64) {
462             switch(claim_item.label.int64) {
463             case IAT_SW_COMPONENT_MEASUREMENT_TYPE:
464                 if(claim_item.uDataType != QCBOR_TYPE_TEXT_STRING) {
465                     return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
466                     goto Done;
467                 }
468                 sw_component->measurement_type = claim_item.val.string;
469                 sw_component->item_flags |=
470                     CLAIM_PRESENT_BIT(SW_MEASUREMENT_TYPE_FLAG);
471 
472                 break;
473 
474             case IAT_SW_COMPONENT_MEASUREMENT_VALUE:
475                 if(claim_item.uDataType != QCBOR_TYPE_BYTE_STRING) {
476                     return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
477                     goto Done;
478                 }
479                 sw_component->measurement_val = claim_item.val.string;
480                 sw_component->item_flags |=
481                     CLAIM_PRESENT_BIT(SW_MEASURMENT_VAL_FLAG);
482                 break;
483 
484             case IAT_SW_COMPONENT_VERSION:
485                 if(claim_item.uDataType != QCBOR_TYPE_TEXT_STRING) {
486                     return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
487                     goto Done;
488                 }
489                 sw_component->version = claim_item.val.string;
490                 sw_component->item_flags |=
491                     CLAIM_PRESENT_BIT(SW_VERSION_FLAG);
492                 break;
493 
494             case IAT_SW_COMPONENT_SIGNER_ID:
495                 if(claim_item.uDataType != QCBOR_TYPE_BYTE_STRING) {
496                     return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
497                     goto Done;
498                 }
499                 sw_component->signer_id = claim_item.val.string;
500                 sw_component->item_flags |=
501                     CLAIM_PRESENT_BIT(SW_SIGNER_ID_FLAG);
502                 break;
503 
504             case IAT_SW_COMPONENT_MEASUREMENT_DESC:
505                 if(claim_item.uDataType != QCBOR_TYPE_TEXT_STRING) {
506                     return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
507                     goto Done;
508                 }
509                 sw_component->measurement_desc = claim_item.val.string;
510                 sw_component->item_flags |=
511                     CLAIM_PRESENT_BIT(SW_MEASUREMENT_DESC_FLAG);
512                 break;
513             }
514         }
515 
516         if(qcbor_util_consume_item(decode_context,
517                                   &claim_item,
518                                   &next_nest_level)) {
519             return_value = ATTEST_TOKEN_ERR_CBOR_NOT_WELL_FORMED;
520             goto Done;
521         }
522         if(next_nest_level < sw_component_item->uNextNestLevel) {
523             /* Got all the items in the map */
524             break;
525         }
526     }
527 
528 Done:
529     return return_value;
530 }
531 
532 
533 /*
534  * Public function. See attest_token_decode.h
535  */
536 enum attest_token_err_t
attest_token_get_sw_component(struct attest_token_decode_context * me,uint32_t requested_index,struct attest_token_sw_component_t * sw_components)537 attest_token_get_sw_component(struct attest_token_decode_context *me,
538                               uint32_t requested_index,
539                               struct attest_token_sw_component_t *sw_components)
540 {
541     enum attest_token_err_t return_value;
542     QCBORItem               sw_components_array_item;
543     QCBORDecodeContext      decode_context;
544     QCBORItem               sw_component_item;
545     QCBORError              qcbor_error;
546     uint_fast8_t            exit_array_level;
547 
548     if(me->last_error != ATTEST_TOKEN_ERR_SUCCESS) {
549         return_value = me->last_error;
550         goto Done;
551     }
552 
553     QCBORDecode_Init(&decode_context, me->payload, QCBOR_DECODE_MODE_NORMAL);
554 
555     /* Find the map containing all the SW Components */
556     return_value = qcbor_util_decode_to_labeled_item(&decode_context,
557                                               IAT_SW_COMPONENTS,
558                                               &sw_components_array_item);
559     if(return_value != ATTEST_TOKEN_ERR_SUCCESS) {
560         goto Done;
561     }
562 
563     if(sw_components_array_item.uDataType != QCBOR_TYPE_ARRAY) {
564         return_value = ATTEST_TOKEN_ERR_CBOR_TYPE;
565         goto Done;
566     }
567 
568     exit_array_level = sw_components_array_item.uNextNestLevel;
569 
570     /* Loop over contents of SW Components array */
571     while(1) {
572         qcbor_error = QCBORDecode_GetNext(&decode_context, &sw_component_item);
573         if(qcbor_error) {
574             /* no tolerance for any errors here */
575             return_value = ATTEST_TOKEN_ERR_CBOR_NOT_WELL_FORMED;
576             goto Done;
577         }
578 
579         if(sw_component_item.uNextNestLevel <= exit_array_level) {
580             /* Next item will be outside the array */
581             return_value = ATTEST_TOKEN_ERR_NOT_FOUND;
582             /* The end of the array containing SW components
583                and didn't get to the requested_index. */
584             goto Done;
585         }
586 
587         if(requested_index == 0) {
588             /* Found the one of interest. Decode it and break out */
589             return_value = decode_sw_component(&decode_context,
590                                                &sw_component_item,
591                                                sw_components);
592             break; /* The normal, non-error exit from this loop */
593         }
594 
595         /* Every member in the array counts even if they are not
596          * what is expected */
597         requested_index--;
598 
599         if(qcbor_util_consume_item(&decode_context, &sw_component_item, NULL)) {
600             return_value = ATTEST_TOKEN_ERR_CBOR_NOT_WELL_FORMED;
601             goto Done;
602         }
603     }
604 
605 Done:
606     return return_value;
607 }
608