core/rma/rma_unlock_token.c (99 lines of code) (raw):

// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. #include <stddef.h> #include <stdlib.h> #include <string.h> #include "rma_unlock_token.h" #include "asn1/asn1_util.h" #include "common/buffer_util.h" #include "common/unused.h" /** * Version number for the RMA token format. */ #define RMA_UNLOCK_TOKEN_FORMAT 1 /** * Magic number identifier for an RMA token structure. */ #define RMA_UNLOCK_TOKEN_MAGIC_NUMBER 0x52545354 /** * Length of the UUID field in the unlock token. */ #define RMA_UNLOCK_TOKEN_UUID_LENGTH 16 int rma_unlock_token_authenticate (const struct rma_unlock_token *handler, const uint8_t *data, size_t length) { uint8_t uuid[RMA_UNLOCK_TOKEN_UUID_LENGTH] = {0}; const uint8_t *oid; size_t oid_length; size_t offset; int status; if ((handler == NULL) || (data == NULL)) { return RMA_UNLOCK_TOKEN_INVALID_ARGUMENT; } status = handler->uuid->get_uuid (handler->uuid, uuid, sizeof (uuid)); if (ROT_IS_ERROR (status)) { return status; } /* Parse and validate the RMA token fields against the device context. * - <var>: OID * - uint16_t: format version * - uint32_t: magic number * - uint8_t[16]: UUID * - <var>: digest of DICE Device ID public key * - <var>: token signature */ /* OID */ status = asn1_decode_base128_oid (data, length, &oid, &oid_length); if (status != 0) { return RMA_UNLOCK_TOKEN_BAD_TOKEN_DATA; } if (handler->oid_length != oid_length) { return RMA_UNLOCK_TOKEN_DEVICE_MISMATCH; } status = buffer_compare (handler->oid, oid, oid_length); if (status != 0) { return RMA_UNLOCK_TOKEN_DEVICE_MISMATCH; } offset = &oid[oid_length] - data; /* format version */ if (length < (offset + sizeof (uint16_t))) { return RMA_UNLOCK_TOKEN_BAD_TOKEN_DATA; } if (buffer_unaligned_read16 ((uint16_t*) &data[offset]) != RMA_UNLOCK_TOKEN_FORMAT) { return RMA_UNLOCK_TOKEN_BAD_TOKEN_DATA; } offset += sizeof (uint16_t); /* magic number */ if (length < (offset + sizeof (uint32_t))) { return RMA_UNLOCK_TOKEN_BAD_TOKEN_DATA; } if (buffer_unaligned_read32 ((uint32_t*) &data[offset]) != RMA_UNLOCK_TOKEN_MAGIC_NUMBER) { return RMA_UNLOCK_TOKEN_BAD_TOKEN_DATA; } offset += sizeof (uint32_t); /* UUID */ if (length < (offset + RMA_UNLOCK_TOKEN_UUID_LENGTH)) { return RMA_UNLOCK_TOKEN_BAD_TOKEN_DATA; } status = buffer_compare (uuid, &data[offset], RMA_UNLOCK_TOKEN_UUID_LENGTH); if (status != 0) { return RMA_UNLOCK_TOKEN_DEVICE_MISMATCH; } offset += RMA_UNLOCK_TOKEN_UUID_LENGTH; /* Device ID hash */ if (length < (offset + handler->dice_length)) { return RMA_UNLOCK_TOKEN_BAD_TOKEN_DATA; } status = buffer_compare (handler->dice_hash, &data[offset], handler->dice_length); if (status != 0) { return RMA_UNLOCK_TOKEN_DEVICE_MISMATCH; } offset += handler->dice_length; /* token signature */ return signature_verification_verify_message (handler->authority, handler->hash, handler->auth_hash, data, offset, handler->authority_key, handler->auth_key_length, &data[offset], length - offset); } /** * Initialize a handler for authorizing RMA unlock tokens. * * @param handler The RMA token handler to initialize. * @param authority_key The public key for entity that will be generating RMA tokens. * @param key_length Length of the authority public key. * @param authority Verification handler for the authority public key. This does not need to be * pre-loaded with the authority key since the verification flow will reload the key each time. * @param hash The hash engine to use for token digests. * @param auth_hash Hash algorithm to use for signature verification of the token. * @param uuid Interface for retrieving the device UUID. * @param oid The OID indicating the type of device generating the tokens. This must be a base128 * encoded value. * @param oid_length Length of the device type OID. * @param dice_hash Digest of the DICE Device ID public key. This would typically be available * through the DME structure. * @param hash_length Length of the Device ID digest. * * @return 0 if the RMA token handler was initialized successfully or an error code. */ int rma_unlock_token_init (struct rma_unlock_token *handler, const uint8_t *authority_key, size_t key_length, const struct signature_verification *authority, const struct hash_engine *hash, enum hash_type auth_hash, const struct cmd_device *uuid, const uint8_t *oid, size_t oid_length, const uint8_t *dice_hash, size_t hash_length) { if ((handler == NULL) || (authority_key == NULL) || (key_length == 0) || (authority == NULL) || (hash == NULL) || (uuid == NULL) || (oid == NULL) || (oid_length == 0) || (dice_hash == NULL) || (hash_length == 0)) { return RMA_UNLOCK_TOKEN_INVALID_ARGUMENT; } memset (handler, 0, sizeof (struct rma_unlock_token)); handler->authenticate = rma_unlock_token_authenticate; handler->hash = hash; handler->authority = authority; handler->authority_key = authority_key; handler->auth_key_length = key_length; handler->auth_hash = auth_hash; handler->uuid = uuid; handler->oid = oid; handler->oid_length = oid_length; handler->dice_hash = dice_hash; handler->dice_length = hash_length; return 0; } /** * Release the resources used for RMA token authentication. * * @param handler The RMA token handler to release. */ void rma_unlock_token_release (const struct rma_unlock_token *handler) { UNUSED (handler); }