mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			
		
			
				
	
	
		
			386 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
			
		
		
	
	
			386 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
/** @file
 | 
						|
 * Copyright (c) 2019, Arm Limited or its affiliates. All rights reserved.
 | 
						|
 * SPDX-License-Identifier : Apache-2.0
 | 
						|
 *
 | 
						|
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
 * you may not use this file except in compliance with the License.
 | 
						|
 * You may obtain a copy of the License at
 | 
						|
 *
 | 
						|
 *  http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 *
 | 
						|
 * Unless required by applicable law or agreed to in writing, software
 | 
						|
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
 * See the License for the specific language governing permissions and
 | 
						|
 * limitations under the License.
 | 
						|
**/
 | 
						|
 | 
						|
#include "pal_attestation_eat.h"
 | 
						|
 | 
						|
uint32_t  mandatory_claims = 0, mandaroty_sw_components = 0;
 | 
						|
bool_t    sw_component_present = 0;
 | 
						|
 | 
						|
static int get_items_in_map(QCBORDecodeContext *decode_context,
 | 
						|
                            struct items_to_get_t *item_list)
 | 
						|
{
 | 
						|
    int                     item_index;
 | 
						|
    QCBORItem               item;
 | 
						|
    struct items_to_get_t  *item_ptr = item_list;
 | 
						|
 | 
						|
    /* initialize the data type of all items in the list */
 | 
						|
    while (item_ptr->label != 0)
 | 
						|
    {
 | 
						|
        item_ptr->item.uDataType = QCBOR_TYPE_NONE;
 | 
						|
        item_ptr++;
 | 
						|
    }
 | 
						|
 | 
						|
    QCBORDecode_GetNext(decode_context, &item);
 | 
						|
    if (item.uDataType != QCBOR_TYPE_MAP)
 | 
						|
    {
 | 
						|
        return PAL_ATTEST_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    for (item_index = item.val.uCount; item_index != 0; item_index--)
 | 
						|
    {
 | 
						|
        if (QCBORDecode_GetNext(decode_context, &item) != QCBOR_SUCCESS)
 | 
						|
        {
 | 
						|
            return PAL_ATTEST_TOKEN_ERR_CBOR_FORMATTING;
 | 
						|
        }
 | 
						|
        if (item.uLabelType != QCBOR_TYPE_INT64)
 | 
						|
        {
 | 
						|
            continue;
 | 
						|
        }
 | 
						|
 | 
						|
        item_ptr = item_list;
 | 
						|
        while (item_ptr->label != 0)
 | 
						|
        {
 | 
						|
            if (item.label.int64 == item_ptr->label)
 | 
						|
            {
 | 
						|
                item_ptr->item = item;
 | 
						|
            }
 | 
						|
            item_ptr++;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return PAL_ATTEST_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
static int get_item_in_map(QCBORDecodeContext *decode_context,
 | 
						|
                           int32_t label,
 | 
						|
                           QCBORItem *item)
 | 
						|
{
 | 
						|
    struct items_to_get_t   item_list[2];
 | 
						|
 | 
						|
    item_list[0].label = label;
 | 
						|
    item_list[1].label = 0;
 | 
						|
 | 
						|
    if (get_items_in_map(decode_context, item_list))
 | 
						|
    {
 | 
						|
        return PAL_ATTEST_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    if (item_list[0].item.uDataType == QCBOR_TYPE_NONE)
 | 
						|
    {
 | 
						|
        return PAL_ATTEST_TOKEN_ERR_CBOR_FORMATTING;
 | 
						|
    }
 | 
						|
 | 
						|
    *item = item_list[0].item;
 | 
						|
 | 
						|
    return PAL_ATTEST_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
static int parse_unprotected_headers(QCBORDecodeContext *decode_context,
 | 
						|
                                     struct useful_buf_c *child,
 | 
						|
                                     bool *loop_back)
 | 
						|
{
 | 
						|
    struct items_to_get_t   item_list[3];
 | 
						|
 | 
						|
    item_list[0].label = COSE_HEADER_PARAM_KID;
 | 
						|
    item_list[1].label = T_COSE_SHORT_CIRCUIT_LABEL;
 | 
						|
    item_list[2].label = 0;
 | 
						|
    *loop_back = false;
 | 
						|
 | 
						|
    if (get_items_in_map(decode_context, item_list))
 | 
						|
    {
 | 
						|
        return PAL_ATTEST_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    if (item_list[1].item.uDataType == QCBOR_TYPE_TRUE)
 | 
						|
    {
 | 
						|
        *loop_back = true;
 | 
						|
    }
 | 
						|
 | 
						|
    if (item_list[0].item.uDataType != QCBOR_TYPE_BYTE_STRING)
 | 
						|
    {
 | 
						|
        return PAL_ATTEST_TOKEN_ERR_CBOR_FORMATTING;
 | 
						|
    }
 | 
						|
 | 
						|
    *child = item_list[0].item.val.string;
 | 
						|
 | 
						|
    return PAL_ATTEST_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
static int parse_protected_headers(struct useful_buf_c protected_headers,
 | 
						|
                                   int32_t *alg_id)
 | 
						|
{
 | 
						|
    QCBORDecodeContext  decode_context;
 | 
						|
    QCBORItem           item;
 | 
						|
 | 
						|
    QCBORDecode_Init(&decode_context, protected_headers, 0);
 | 
						|
 | 
						|
    if (get_item_in_map(&decode_context, COSE_HEADER_PARAM_ALG, &item))
 | 
						|
    {
 | 
						|
        return PAL_ATTEST_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    if (QCBORDecode_Finish(&decode_context))
 | 
						|
    {
 | 
						|
        return PAL_ATTEST_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    if ((item.uDataType != QCBOR_TYPE_INT64) || (item.val.int64 > INT32_MAX))
 | 
						|
    {
 | 
						|
        return PAL_ATTEST_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    *alg_id = (int32_t)item.val.int64;
 | 
						|
 | 
						|
    return PAL_ATTEST_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
    @brief    - This API will verify the claims
 | 
						|
    @param    - decode_context      : The buffer containing the challenge
 | 
						|
                item                : context for decoding the data items
 | 
						|
                completed_challenge : Buffer containing the challenge
 | 
						|
    @return   - error status
 | 
						|
**/
 | 
						|
static int parse_claims(QCBORDecodeContext *decode_context, QCBORItem item,
 | 
						|
                                   struct useful_buf_c completed_challenge)
 | 
						|
{
 | 
						|
    int i, count = 0;
 | 
						|
    int status = PAL_ATTEST_SUCCESS;
 | 
						|
 | 
						|
    /* Parse each claim and validate their data type */
 | 
						|
    while (status == PAL_ATTEST_SUCCESS)
 | 
						|
    {
 | 
						|
        status = QCBORDecode_GetNext(decode_context, &item);
 | 
						|
        if (status != PAL_ATTEST_SUCCESS)
 | 
						|
            break;
 | 
						|
 | 
						|
        mandatory_claims |= 1 << (EAT_CBOR_ARM_RANGE_BASE - item.label.int64);
 | 
						|
        if (item.uLabelType == QCBOR_TYPE_INT64)
 | 
						|
        {
 | 
						|
            if (item.label.int64 == EAT_CBOR_ARM_LABEL_NONCE)
 | 
						|
            {
 | 
						|
                if (item.uDataType == QCBOR_TYPE_BYTE_STRING)
 | 
						|
                {
 | 
						|
                    /* Given challenge vs challenge in token */
 | 
						|
                    if (UsefulBuf_Compare(item.val.string, completed_challenge))
 | 
						|
                        return PAL_ATTEST_TOKEN_CHALLENGE_MISMATCH;
 | 
						|
                }
 | 
						|
                else
 | 
						|
                    return PAL_ATTEST_TOKEN_NOT_SUPPORTED;
 | 
						|
            }
 | 
						|
            else if (item.label.int64 == EAT_CBOR_ARM_LABEL_BOOT_SEED ||
 | 
						|
                     item.label.int64 == EAT_CBOR_ARM_LABEL_IMPLEMENTATION_ID ||
 | 
						|
                     item.label.int64 == EAT_CBOR_ARM_LABEL_UEID)
 | 
						|
            {
 | 
						|
                if (item.uDataType != QCBOR_TYPE_BYTE_STRING)
 | 
						|
                    return PAL_ATTEST_TOKEN_ERR_CBOR_FORMATTING;
 | 
						|
            }
 | 
						|
            else if (item.label.int64 == EAT_CBOR_ARM_LABEL_ORIGINATION ||
 | 
						|
                     item.label.int64 == EAT_CBOR_ARM_LABEL_PROFILE_DEFINITION ||
 | 
						|
                     item.label.int64 == EAT_CBOR_ARM_LABEL_HW_VERSION)
 | 
						|
            {
 | 
						|
                if (item.uDataType != QCBOR_TYPE_TEXT_STRING)
 | 
						|
                    return PAL_ATTEST_TOKEN_ERR_CBOR_FORMATTING;
 | 
						|
            }
 | 
						|
            else if (item.label.int64 == EAT_CBOR_ARM_LABEL_CLIENT_ID ||
 | 
						|
                     item.label.int64 == EAT_CBOR_ARM_LABEL_SECURITY_LIFECYCLE)
 | 
						|
            {
 | 
						|
                if (item.uDataType != QCBOR_TYPE_INT64)
 | 
						|
                    return PAL_ATTEST_TOKEN_ERR_CBOR_FORMATTING;
 | 
						|
            }
 | 
						|
            else if (item.label.int64 == EAT_CBOR_ARM_LABEL_SW_COMPONENTS)
 | 
						|
            {
 | 
						|
                if (item.uDataType != QCBOR_TYPE_ARRAY)
 | 
						|
                    return PAL_ATTEST_TOKEN_ERR_CBOR_FORMATTING;
 | 
						|
 | 
						|
                sw_component_present = 1;
 | 
						|
                status = QCBORDecode_GetNext(decode_context, &item);
 | 
						|
                if (status != PAL_ATTEST_SUCCESS)
 | 
						|
                    continue;
 | 
						|
 | 
						|
                count = item.val.uCount;
 | 
						|
                for (i = 0; i <= count; i++)
 | 
						|
                {
 | 
						|
                    mandaroty_sw_components |= 1 << item.label.int64;
 | 
						|
 | 
						|
                    if (item.label.int64 == EAT_CBOR_SW_COMPONENT_MEASUREMENT)
 | 
						|
                    {
 | 
						|
                         if (item.uDataType != QCBOR_TYPE_BYTE_STRING)
 | 
						|
                            return PAL_ATTEST_TOKEN_ERR_CBOR_FORMATTING;
 | 
						|
                    }
 | 
						|
                    else if (item.label.int64 == EAT_CBOR_SW_COMPONENT_MEASUREMENT_DESC)
 | 
						|
                    {
 | 
						|
                        if (item.uDataType != QCBOR_TYPE_TEXT_STRING)
 | 
						|
                            return PAL_ATTEST_TOKEN_ERR_CBOR_FORMATTING;
 | 
						|
                    }
 | 
						|
                    else if (item.label.int64 == EAT_CBOR_SW_COMPONENT_VERSION)
 | 
						|
                    {
 | 
						|
                        if (item.uDataType != QCBOR_TYPE_TEXT_STRING)
 | 
						|
                            return PAL_ATTEST_TOKEN_ERR_CBOR_FORMATTING;
 | 
						|
                    }
 | 
						|
                    else if (item.label.int64 == EAT_CBOR_SW_COMPONENT_SIGNER_ID)
 | 
						|
                    {
 | 
						|
                        if (item.uDataType != QCBOR_TYPE_BYTE_STRING)
 | 
						|
                            return PAL_ATTEST_TOKEN_ERR_CBOR_FORMATTING;
 | 
						|
                    }
 | 
						|
                    else if (item.label.int64 == EAT_CBOR_SW_COMPONENT_EPOCH)
 | 
						|
                    {
 | 
						|
                        if (item.uDataType != QCBOR_TYPE_INT64)
 | 
						|
                            return PAL_ATTEST_TOKEN_ERR_CBOR_FORMATTING;
 | 
						|
                    }
 | 
						|
                    else if (item.label.int64 == EAT_CBOR_SW_COMPONENT_TYPE)
 | 
						|
                    {
 | 
						|
                        if (item.uDataType != QCBOR_TYPE_TEXT_STRING)
 | 
						|
                            return PAL_ATTEST_TOKEN_ERR_CBOR_FORMATTING;
 | 
						|
                    }
 | 
						|
 | 
						|
                    if (i < count)
 | 
						|
                    {
 | 
						|
                        status = QCBORDecode_GetNext(decode_context, &item);
 | 
						|
                        if (status != PAL_ATTEST_SUCCESS)
 | 
						|
                            return PAL_ATTEST_TOKEN_ERR_CBOR_FORMATTING;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            /* ToDo: Add other claim types */
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (status == QCBOR_ERR_HIT_END)
 | 
						|
        return PAL_ATTEST_SUCCESS;
 | 
						|
    else
 | 
						|
        return PAL_ATTEST_TOKEN_ERR_CBOR_FORMATTING;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
    @brief    - This API will verify the attestation token
 | 
						|
    @param    - challenge       : The buffer containing the challenge
 | 
						|
                challenge_size  : Size of the challenge buffer
 | 
						|
                token           : The buffer containing the attestation token
 | 
						|
                token_size      : Size of the token buffer
 | 
						|
    @return   - error status
 | 
						|
**/
 | 
						|
int32_t pal_initial_attest_verify_token(uint8_t *challenge, uint32_t challenge_size,
 | 
						|
                                        uint8_t *token, uint32_t token_size)
 | 
						|
{
 | 
						|
    int                 status = PAL_ATTEST_SUCCESS;
 | 
						|
    bool                short_circuit;
 | 
						|
    int32_t             cose_algorithm_id;
 | 
						|
    QCBORItem           item;
 | 
						|
    QCBORDecodeContext  decode_context;
 | 
						|
    struct useful_buf_c completed_challenge;
 | 
						|
    struct useful_buf_c completed_token;
 | 
						|
    struct useful_buf_c payload;
 | 
						|
    struct useful_buf_c protected_headers;
 | 
						|
    struct useful_buf_c kid;
 | 
						|
 | 
						|
    /* Construct the token buffer for validation */
 | 
						|
    completed_token.ptr = token;
 | 
						|
    completed_token.len = token_size;
 | 
						|
 | 
						|
    /* Construct the challenge buffer for validation */
 | 
						|
    completed_challenge.ptr = challenge;
 | 
						|
    completed_challenge.len = challenge_size;
 | 
						|
 | 
						|
/*
 | 
						|
    -------------------------
 | 
						|
    |  CBOR Array Type      |
 | 
						|
    -------------------------
 | 
						|
    |  Protected Headers    |
 | 
						|
    -------------------------
 | 
						|
    |  Unprotected Headers  |
 | 
						|
    -------------------------
 | 
						|
    |  Payload              |
 | 
						|
    -------------------------
 | 
						|
    |  Signature            |
 | 
						|
    -------------------------
 | 
						|
*/
 | 
						|
 | 
						|
    /* Initialize the decorder */
 | 
						|
    QCBORDecode_Init(&decode_context, completed_token, QCBOR_DECODE_MODE_NORMAL);
 | 
						|
 | 
						|
    /* Get the Header */
 | 
						|
    QCBORDecode_GetNext(&decode_context, &item);
 | 
						|
 | 
						|
    /* Check the CBOR Array type. Check if the count is 4.
 | 
						|
     * Only COSE_SIGN1 is supported now.
 | 
						|
     */
 | 
						|
    if (item.uDataType != QCBOR_TYPE_ARRAY || item.val.uCount != 4 ||
 | 
						|
       !QCBORDecode_IsTagged(&decode_context, &item, CBOR_TAG_COSE_SIGN1))
 | 
						|
        return PAL_ATTEST_TOKEN_ERR_CBOR_FORMATTING;
 | 
						|
 | 
						|
    /* Get the next headers */
 | 
						|
    QCBORDecode_GetNext(&decode_context, &item);
 | 
						|
    if (item.uDataType != QCBOR_TYPE_BYTE_STRING)
 | 
						|
        return PAL_ATTEST_TOKEN_ERR_CBOR_FORMATTING;
 | 
						|
 | 
						|
    protected_headers = item.val.string;
 | 
						|
 | 
						|
    /* Parse the protected headers and check the data type and value*/
 | 
						|
    status = parse_protected_headers(protected_headers, &cose_algorithm_id);
 | 
						|
    if (status != PAL_ATTEST_SUCCESS)
 | 
						|
        return status;
 | 
						|
 | 
						|
    /* Parse the unprotected headers and check the data type and value */
 | 
						|
    short_circuit = false;
 | 
						|
    status = parse_unprotected_headers(&decode_context, &kid, &short_circuit);
 | 
						|
    if (status != PAL_ATTEST_SUCCESS)
 | 
						|
        return status;
 | 
						|
 | 
						|
    /* Get the payload */
 | 
						|
    QCBORDecode_GetNext(&decode_context, &item);
 | 
						|
    if (item.uDataType != QCBOR_TYPE_BYTE_STRING)
 | 
						|
        return PAL_ATTEST_TOKEN_ERR_CBOR_FORMATTING;
 | 
						|
 | 
						|
    payload = item.val.string;
 | 
						|
 | 
						|
    /* Get the digital signature */
 | 
						|
    QCBORDecode_GetNext(&decode_context, &item);
 | 
						|
    if (item.uDataType != QCBOR_TYPE_BYTE_STRING)
 | 
						|
        return PAL_ATTEST_TOKEN_ERR_CBOR_FORMATTING;
 | 
						|
 | 
						|
    /* Initialize the Decoder and validate the payload format */
 | 
						|
    QCBORDecode_Init(&decode_context, payload, QCBOR_DECODE_MODE_NORMAL);
 | 
						|
    status = QCBORDecode_GetNext(&decode_context, &item);
 | 
						|
    if (status != PAL_ATTEST_SUCCESS)
 | 
						|
        return status;
 | 
						|
 | 
						|
    if (item.uDataType != QCBOR_TYPE_MAP)
 | 
						|
        return PAL_ATTEST_TOKEN_ERR_CBOR_FORMATTING;
 | 
						|
 | 
						|
    /* Parse the payload and check the data type of each claim */
 | 
						|
    status = parse_claims(&decode_context, item, completed_challenge);
 | 
						|
    if (status != PAL_ATTEST_SUCCESS)
 | 
						|
        return status;
 | 
						|
 | 
						|
    if ((mandatory_claims & MANDATORY_CLAIM_WITH_SW_COMP) == MANDATORY_CLAIM_WITH_SW_COMP)
 | 
						|
    {
 | 
						|
        if ((mandaroty_sw_components & MANDATORY_SW_COMP) != MANDATORY_SW_COMP)
 | 
						|
            return PAL_ATTEST_TOKEN_NOT_ALL_MANDATORY_CLAIMS;
 | 
						|
    }
 | 
						|
    else if ((mandatory_claims & MANDATORY_CLAIM_NO_SW_COMP) != MANDATORY_CLAIM_NO_SW_COMP)
 | 
						|
    {
 | 
						|
        return PAL_ATTEST_TOKEN_NOT_ALL_MANDATORY_CLAIMS;
 | 
						|
    }
 | 
						|
 | 
						|
    return PAL_ATTEST_SUCCESS;
 | 
						|
}
 |