Skip to content

ECDSA signing & public key exporting #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
May 30, 2019
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added ATCRYPTOAUTH-XPRO-B-K64F2.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added ATCRYPTOAUTH-XPRO-B-Shield.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
63 changes: 63 additions & 0 deletions atecc608a_utils.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* \file atecc608a_utils.c
* \brief ATECC508A and ATECC509A utility functions.
*/

/*
* Copyright (C) 2019, ARM Limited, 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 "atecc608a_utils.h"

#include "atca_basic.h"

psa_status_t atecc608a_get_serial_number(uint8_t* buffer,
size_t buffer_size,
size_t *buffer_length)
{
psa_status_t status = PSA_ERROR_GENERIC_ERROR;

if (buffer_size < ATCA_SERIAL_NUM_SIZE)
{
return PSA_ERROR_BUFFER_TOO_SMALL;
}

ASSERT_SUCCESS_PSA(atecc608a_init());

ASSERT_SUCCESS(atcab_read_serial_number(buffer));
*buffer_length = ATCA_SERIAL_NUM_SIZE;

exit:
atecc608a_deinit();
return status;
}

psa_status_t atecc608a_check_config_locked()
{
bool config_locked;
psa_status_t status = PSA_ERROR_GENERIC_ERROR;

ASSERT_SUCCESS_PSA(atecc608a_init());

ASSERT_SUCCESS(atcab_is_locked(LOCK_ZONE_CONFIG, &config_locked));

exit:
atecc608a_deinit();
if (status == PSA_SUCCESS)
{
status = config_locked? PSA_SUCCESS : PSA_ERROR_HARDWARE_FAILURE;
}
return status;
}
64 changes: 64 additions & 0 deletions atecc608a_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* \file atecc608a_utils.h
* \brief ATECC508A and ATECC509A utility functions.
*/

/*
* Copyright (C) 2019, ARM Limited, 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.
*/

#ifndef ATECC608A_UTILS_H
#define ATECC608A_UTILS_H

#include "psa/crypto.h"
#include "atecc608a_se.h"

/** This macro checks if the result of an `expression` is equal to an
* `expected` value and sets a `status` variable of type `psa_status_t` to
* `PSA_SUCCESS`. If they are not equal, the `status` is set to
* `psa_error instead`, the error details are printed, and the code jumps
* to the `exit` label. */
#define ASSERT_STATUS(expression, expected, psa_error) \
do \
{ \
ATCA_STATUS ASSERT_result = (expression); \
ATCA_STATUS ASSERT_expected = (expected); \
if ((ASSERT_result) != (ASSERT_expected)) \
{ \
printf("assertion failed at %s:%d " \
"(actual=%d expected=%d)\n", __FILE__, __LINE__, \
ASSERT_result, ASSERT_expected); \
status = (psa_error); \
goto exit; \
} \
status = PSA_SUCCESS; \
} while(0)

/** Check if an ATCA operation is successful, translate the error otherwise. */
#define ASSERT_SUCCESS(expression) ASSERT_STATUS(expression, ATCA_SUCCESS, \
atecc608a_to_psa_error(ASSERT_result))

/** Does the same as the macro above, but without the error translation and for
* the PSA return code - PSA_SUCCESS.*/
#define ASSERT_SUCCESS_PSA(expression) ASSERT_STATUS(expression, PSA_SUCCESS, \
ASSERT_result)

psa_status_t atecc608a_get_serial_number(uint8_t* buffer, size_t buffer_size,
size_t *buffer_length);

psa_status_t atecc608a_check_config_locked();

#endif /* ATECC608A_SE_H */
188 changes: 188 additions & 0 deletions main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
/*
* Copyright (c) 2019, Arm Limited and affiliates
* 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 <stdio.h>
#include <inttypes.h>
#include <string.h>

#if defined(ATCA_HAL_I2C)
#include "psa/crypto.h"
#include "atecc608a_se.h"
#include "atecc608a_utils.h"
#include "atca_helpers.h"

static const uint8_t hash_input1[] = "abc";
/* SHA-256 hash of ['a','b','c'] */
static const uint8_t sha256_expected_hash1[] = {
0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA,
0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23,
0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C,
0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD
};

static const uint8_t hash_input2[] = "";
/* SHA-256 hash of an empty string */
static const uint8_t sha256_expected_hash2[] = {
0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55
};


psa_status_t atecc608a_hash_sha256(const uint8_t *input, size_t input_size,
const uint8_t *expected_hash,
size_t expected_hash_size)
{
psa_status_t status = PSA_ERROR_GENERIC_ERROR;
uint8_t actual_hash[ATCA_SHA_DIGEST_SIZE] = {0};

printf("SHA-256:\n\n");
atcab_printbin_label("Input: ", (uint8_t *)input, input_size);
atcab_printbin_label("Expected Hash: ", (uint8_t *)expected_hash,
expected_hash_size);
ASSERT_SUCCESS_PSA(atecc608a_init());
ASSERT_SUCCESS(atcab_hw_sha2_256(input, input_size, actual_hash));
atcab_printbin_label("Actual Hash: ", actual_hash, ATCA_SHA_DIGEST_SIZE);
ASSERT_STATUS(memcmp(actual_hash, expected_hash, sizeof(actual_hash)), 0,
PSA_ERROR_HARDWARE_FAILURE);
printf("Success!\n\n");

exit:
atecc608a_deinit();
return status;
}

psa_status_t atecc608a_print_locked_zones()
{
psa_status_t status = PSA_ERROR_GENERIC_ERROR;
bool locked;
printf("--- Device locks information ---\n");
ASSERT_SUCCESS_PSA(atecc608a_init());
ASSERT_SUCCESS(atcab_is_locked(LOCK_ZONE_CONFIG, &locked));
printf(" - Config locked: %d\n", locked);
ASSERT_SUCCESS(atcab_is_locked(LOCK_ZONE_DATA, &locked));
printf(" - Data locked: %d\n", locked);
for(uint8_t i=0; i < 16; i++)
{
ASSERT_SUCCESS(atcab_is_slot_locked(i, &locked));
printf(" - Slot %d locked: %d\n", i, locked);
}
printf("--------------------------------\n");

exit:
atecc608a_deinit();
return status;
}

psa_status_t atecc608a_print_serial_number()
{
psa_status_t status = PSA_ERROR_GENERIC_ERROR;
uint8_t serial[ATCA_SERIAL_NUM_SIZE];
size_t buffer_length;

ASSERT_SUCCESS_PSA(atecc608a_get_serial_number(serial,
ATCA_SERIAL_NUM_SIZE,
&buffer_length));
printf("Serial Number:\n");
atcab_printbin_sp(serial, buffer_length);
printf("\n");
exit:
return status;
}

int main(void)
{
enum {
key_type = PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_CURVE_SECP256R1),
keypair_type = PSA_KEY_TYPE_ECC_KEYPAIR(PSA_ECC_CURVE_SECP256R1),
key_bits = 256,
hash_alg = PSA_ALG_SHA_256,
alg = PSA_ALG_ECDSA(hash_alg),
sig_size = PSA_ASYMMETRIC_SIGN_OUTPUT_SIZE(key_type, key_bits, alg),
pubkey_size = PSA_KEY_EXPORT_ECC_PUBLIC_KEY_MAX_SIZE(key_bits),
hash_size = PSA_HASH_SIZE(hash_alg),
};
psa_status_t status;
psa_key_handle_t verify_handle;
uint8_t signature[sig_size];
size_t signature_length = 0;
const uint8_t hash[hash_size] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider re-using sha256_expected_hash1 for this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather go for clarity, since this is just an example.

psa_key_policy_t policy = PSA_KEY_POLICY_INIT;
static uint8_t pubkey[pubkey_size];
size_t pubkey_len = 0;
psa_key_slot_number_t atecc608a_key_slot_device = 0;

atecc608a_print_serial_number();

ASSERT_SUCCESS_PSA(atecc608a_hash_sha256(hash_input1,
sizeof(hash_input1) - 1,
sha256_expected_hash1,
sizeof(sha256_expected_hash1)));

ASSERT_SUCCESS_PSA(atecc608a_hash_sha256(hash_input2,
sizeof(hash_input2) - 1,
sha256_expected_hash2,
sizeof(sha256_expected_hash2)));

ASSERT_SUCCESS_PSA(psa_crypto_init());

atecc608a_print_locked_zones();
/* Verify that the device has a locked config before doing anything */
ASSERT_SUCCESS_PSA(atecc608a_check_config_locked());

ASSERT_SUCCESS_PSA(atecc608a_drv_info.p_key_management->p_export(
atecc608a_key_slot_device, pubkey, sizeof(pubkey),
&pubkey_len));

ASSERT_SUCCESS_PSA(atecc608a_drv_info.p_asym->p_sign(
atecc608a_key_slot_device, alg, hash, sizeof(hash),
signature, sizeof(signature), &signature_length));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your function pointer syntax doesn't look how I'd expect. Does this work?

    ASSERT_SUCCESS_PSA(atecc608a_drv_info.p_asym->p_sign(
                         atecc608a_key_slot_device, alg, hash, sizeof(hash),
                         signature, sizeof(signature), &signature_length));

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, it works too. I just prefer the first syntax. Would you like me to change it?

Copy link
Contributor

@Patater Patater May 28, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the explicit parenthesis wrapping and dereferencing makes it less clear, as it implies there is a reason to do those things, which implies something tricky is going on. I'd prefer, and many readers of our code would probably expect, my syntax.


/*
* Import the secure element's public key into a volatile key slot.
*/
ASSERT_SUCCESS_PSA(psa_allocate_key(&verify_handle));

psa_key_policy_set_usage(&policy, PSA_KEY_USAGE_VERIFY, alg);
ASSERT_SUCCESS_PSA(psa_set_key_policy(verify_handle, &policy));

ASSERT_SUCCESS_PSA(psa_import_key(verify_handle, key_type, pubkey,
pubkey_len));

/* Verify that the signature produced by the secure element is valid. */
ASSERT_SUCCESS_PSA(psa_asymmetric_verify(verify_handle, alg, hash,
sizeof(hash), signature,
signature_length));

printf("Verification successful!\n");
exit:
return status;
}
#else
int main(void)
{
printf("Not all of the required options are defined:\n"
" - ATCA_HAL_I2C\n");
return 0;
}
#endif
Loading