-
Notifications
You must be signed in to change notification settings - Fork 19
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
Changes from all commits
91bf729
eeb7c01
5c11b63
5e6070f
62fe4d7
ab7ee36
2d4af00
0450289
19724e9
7b50eb7
703aa54
9ee704d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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; | ||
} |
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 */ |
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, | ||
}; | ||
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)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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)); There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
There was a problem hiding this comment.
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.There was a problem hiding this comment.
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.