// SPDX-License-Identifier: BSD-2-Clause /* * Copyright (c) 2017-2020, Linaro Limited */ #include #include #include #include #include #include #include "attributes.h" #include "object.h" #include "pkcs11_token.h" #include "processing.h" /* * DER encoded EC parameters generated with script: * ta/pkcs11/scripts/dump_ec_curve_params.sh */ static const uint8_t prime192v1_name_der[] = { 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x01, }; static const uint8_t secp224r1_name_der[] = { 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x21, }; static const uint8_t prime256v1_name_der[] = { 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, }; static const uint8_t secp384r1_name_der[] = { 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, }; static const uint8_t secp521r1_name_der[] = { 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23, }; static const uint8_t prime192v1_oid_der[] = { 0x30, 0x81, 0xc7, 0x02, 0x01, 0x01, 0x30, 0x24, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x01, 0x01, 0x02, 0x19, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x30, 0x4b, 0x04, 0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x04, 0x18, 0x64, 0x21, 0x05, 0x19, 0xe5, 0x9c, 0x80, 0xe7, 0x0f, 0xa7, 0xe9, 0xab, 0x72, 0x24, 0x30, 0x49, 0xfe, 0xb8, 0xde, 0xec, 0xc1, 0x46, 0xb9, 0xb1, 0x03, 0x15, 0x00, 0x30, 0x45, 0xae, 0x6f, 0xc8, 0x42, 0x2f, 0x64, 0xed, 0x57, 0x95, 0x28, 0xd3, 0x81, 0x20, 0xea, 0xe1, 0x21, 0x96, 0xd5, 0x04, 0x31, 0x04, 0x18, 0x8d, 0xa8, 0x0e, 0xb0, 0x30, 0x90, 0xf6, 0x7c, 0xbf, 0x20, 0xeb, 0x43, 0xa1, 0x88, 0x00, 0xf4, 0xff, 0x0a, 0xfd, 0x82, 0xff, 0x10, 0x12, 0x07, 0x19, 0x2b, 0x95, 0xff, 0xc8, 0xda, 0x78, 0x63, 0x10, 0x11, 0xed, 0x6b, 0x24, 0xcd, 0xd5, 0x73, 0xf9, 0x77, 0xa1, 0x1e, 0x79, 0x48, 0x11, 0x02, 0x19, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x99, 0xde, 0xf8, 0x36, 0x14, 0x6b, 0xc9, 0xb1, 0xb4, 0xd2, 0x28, 0x31, 0x02, 0x01, 0x01, }; static const uint8_t secp224r1_oid_der[] = { 0x30, 0x81, 0xdf, 0x02, 0x01, 0x01, 0x30, 0x28, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x01, 0x01, 0x02, 0x1d, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x30, 0x53, 0x04, 0x1c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x04, 0x1c, 0xb4, 0x05, 0x0a, 0x85, 0x0c, 0x04, 0xb3, 0xab, 0xf5, 0x41, 0x32, 0x56, 0x50, 0x44, 0xb0, 0xb7, 0xd7, 0xbf, 0xd8, 0xba, 0x27, 0x0b, 0x39, 0x43, 0x23, 0x55, 0xff, 0xb4, 0x03, 0x15, 0x00, 0xbd, 0x71, 0x34, 0x47, 0x99, 0xd5, 0xc7, 0xfc, 0xdc, 0x45, 0xb5, 0x9f, 0xa3, 0xb9, 0xab, 0x8f, 0x6a, 0x94, 0x8b, 0xc5, 0x04, 0x39, 0x04, 0xb7, 0x0e, 0x0c, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f, 0x32, 0x13, 0x90, 0xb9, 0x4a, 0x03, 0xc1, 0xd3, 0x56, 0xc2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xd6, 0x11, 0x5c, 0x1d, 0x21, 0xbd, 0x37, 0x63, 0x88, 0xb5, 0xf7, 0x23, 0xfb, 0x4c, 0x22, 0xdf, 0xe6, 0xcd, 0x43, 0x75, 0xa0, 0x5a, 0x07, 0x47, 0x64, 0x44, 0xd5, 0x81, 0x99, 0x85, 0x00, 0x7e, 0x34, 0x02, 0x1d, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, 0x5c, 0x5c, 0x2a, 0x3d, 0x02, 0x01, 0x01, }; static const uint8_t prime256v1_oid_der[] = { 0x30, 0x81, 0xf7, 0x02, 0x01, 0x01, 0x30, 0x2c, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x01, 0x01, 0x02, 0x21, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x30, 0x5b, 0x04, 0x20, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x04, 0x20, 0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7, 0xb3, 0xeb, 0xbd, 0x55, 0x76, 0x98, 0x86, 0xbc, 0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53, 0xb0, 0xf6, 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b, 0x03, 0x15, 0x00, 0xc4, 0x9d, 0x36, 0x08, 0x86, 0xe7, 0x04, 0x93, 0x6a, 0x66, 0x78, 0xe1, 0x13, 0x9d, 0x26, 0xb7, 0x81, 0x9f, 0x7e, 0x90, 0x04, 0x41, 0x04, 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0, 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5, 0x02, 0x21, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51, 0x02, 0x01, 0x01, }; static const uint8_t secp384r1_oid_der[] = { 0x30, 0x82, 0x01, 0x57, 0x02, 0x01, 0x01, 0x30, 0x3c, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x01, 0x01, 0x02, 0x31, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x30, 0x7b, 0x04, 0x30, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfc, 0x04, 0x30, 0xb3, 0x31, 0x2f, 0xa7, 0xe2, 0x3e, 0xe7, 0xe4, 0x98, 0x8e, 0x05, 0x6b, 0xe3, 0xf8, 0x2d, 0x19, 0x18, 0x1d, 0x9c, 0x6e, 0xfe, 0x81, 0x41, 0x12, 0x03, 0x14, 0x08, 0x8f, 0x50, 0x13, 0x87, 0x5a, 0xc6, 0x56, 0x39, 0x8d, 0x8a, 0x2e, 0xd1, 0x9d, 0x2a, 0x85, 0xc8, 0xed, 0xd3, 0xec, 0x2a, 0xef, 0x03, 0x15, 0x00, 0xa3, 0x35, 0x92, 0x6a, 0xa3, 0x19, 0xa2, 0x7a, 0x1d, 0x00, 0x89, 0x6a, 0x67, 0x73, 0xa4, 0x82, 0x7a, 0xcd, 0xac, 0x73, 0x04, 0x61, 0x04, 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37, 0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20, 0xad, 0x74, 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98, 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38, 0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c, 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0x0a, 0xb7, 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f, 0x5d, 0x9e, 0x98, 0xbf, 0x92, 0x92, 0xdc, 0x29, 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c, 0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0, 0x0a, 0x60, 0xb1, 0xce, 0x1d, 0x7e, 0x81, 0x9d, 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5f, 0x02, 0x31, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0x63, 0x4d, 0x81, 0xf4, 0x37, 0x2d, 0xdf, 0x58, 0x1a, 0x0d, 0xb2, 0x48, 0xb0, 0xa7, 0x7a, 0xec, 0xec, 0x19, 0x6a, 0xcc, 0xc5, 0x29, 0x73, 0x02, 0x01, 0x01, }; static const uint8_t secp521r1_oid_der[] = { 0x30, 0x82, 0x01, 0xc3, 0x02, 0x01, 0x01, 0x30, 0x4d, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x01, 0x01, 0x02, 0x42, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x30, 0x81, 0x9f, 0x04, 0x42, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x04, 0x42, 0x00, 0x51, 0x95, 0x3e, 0xb9, 0x61, 0x8e, 0x1c, 0x9a, 0x1f, 0x92, 0x9a, 0x21, 0xa0, 0xb6, 0x85, 0x40, 0xee, 0xa2, 0xda, 0x72, 0x5b, 0x99, 0xb3, 0x15, 0xf3, 0xb8, 0xb4, 0x89, 0x91, 0x8e, 0xf1, 0x09, 0xe1, 0x56, 0x19, 0x39, 0x51, 0xec, 0x7e, 0x93, 0x7b, 0x16, 0x52, 0xc0, 0xbd, 0x3b, 0xb1, 0xbf, 0x07, 0x35, 0x73, 0xdf, 0x88, 0x3d, 0x2c, 0x34, 0xf1, 0xef, 0x45, 0x1f, 0xd4, 0x6b, 0x50, 0x3f, 0x00, 0x03, 0x15, 0x00, 0xd0, 0x9e, 0x88, 0x00, 0x29, 0x1c, 0xb8, 0x53, 0x96, 0xcc, 0x67, 0x17, 0x39, 0x32, 0x84, 0xaa, 0xa0, 0xda, 0x64, 0xba, 0x04, 0x81, 0x85, 0x04, 0x00, 0xc6, 0x85, 0x8e, 0x06, 0xb7, 0x04, 0x04, 0xe9, 0xcd, 0x9e, 0x3e, 0xcb, 0x66, 0x23, 0x95, 0xb4, 0x42, 0x9c, 0x64, 0x81, 0x39, 0x05, 0x3f, 0xb5, 0x21, 0xf8, 0x28, 0xaf, 0x60, 0x6b, 0x4d, 0x3d, 0xba, 0xa1, 0x4b, 0x5e, 0x77, 0xef, 0xe7, 0x59, 0x28, 0xfe, 0x1d, 0xc1, 0x27, 0xa2, 0xff, 0xa8, 0xde, 0x33, 0x48, 0xb3, 0xc1, 0x85, 0x6a, 0x42, 0x9b, 0xf9, 0x7e, 0x7e, 0x31, 0xc2, 0xe5, 0xbd, 0x66, 0x01, 0x18, 0x39, 0x29, 0x6a, 0x78, 0x9a, 0x3b, 0xc0, 0x04, 0x5c, 0x8a, 0x5f, 0xb4, 0x2c, 0x7d, 0x1b, 0xd9, 0x98, 0xf5, 0x44, 0x49, 0x57, 0x9b, 0x44, 0x68, 0x17, 0xaf, 0xbd, 0x17, 0x27, 0x3e, 0x66, 0x2c, 0x97, 0xee, 0x72, 0x99, 0x5e, 0xf4, 0x26, 0x40, 0xc5, 0x50, 0xb9, 0x01, 0x3f, 0xad, 0x07, 0x61, 0x35, 0x3c, 0x70, 0x86, 0xa2, 0x72, 0xc2, 0x40, 0x88, 0xbe, 0x94, 0x76, 0x9f, 0xd1, 0x66, 0x50, 0x02, 0x42, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfa, 0x51, 0x86, 0x87, 0x83, 0xbf, 0x2f, 0x96, 0x6b, 0x7f, 0xcc, 0x01, 0x48, 0xf7, 0x09, 0xa5, 0xd0, 0x3b, 0xb5, 0xc9, 0xb8, 0x89, 0x9c, 0x47, 0xae, 0xbb, 0x6f, 0xb7, 0x1e, 0x91, 0x38, 0x64, 0x09, 0x02, 0x01, 0x01, }; /* * Edwards curves may be specified in two flavours: * - as a PrintableString 'edwards25519' or 'edwards448' * - as an OID, DER encoded ASN.1 Object */ static const uint8_t ed25519_name_der[] = { 0x13, 0x0c, 'e', 'd', 'w', 'a', 'r', 'd', 's', '2', '5', '5', '1', '9', }; static const uint8_t ed25519_oid_der[] = { 0x06, 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01, }; struct supported_ecc_curve { const uint8_t *oid_der; size_t oid_size; const uint8_t *name_der; size_t name_size; size_t key_size; uint32_t tee_id; const char *label; size_t label_size; }; #define ECC_CURVE(_tee_id, _key_size, _label) \ { \ .tee_id = (_tee_id), \ .key_size = (_key_size), \ .oid_der = _label ## _oid_der, \ .oid_size = sizeof(_label ## _oid_der), \ .name_der = _label ## _name_der, \ .name_size = sizeof(_label ## _name_der), \ .label = #_label, \ .label_size = sizeof(#_label) - 1, \ } static const struct supported_ecc_curve ec_curve_param[] = { ECC_CURVE(TEE_ECC_CURVE_NIST_P192, 192, prime192v1), ECC_CURVE(TEE_ECC_CURVE_NIST_P224, 224, secp224r1), ECC_CURVE(TEE_ECC_CURVE_NIST_P256, 256, prime256v1), ECC_CURVE(TEE_ECC_CURVE_NIST_P384, 384, secp384r1), ECC_CURVE(TEE_ECC_CURVE_NIST_P521, 521, secp521r1), ECC_CURVE(TEE_ECC_CURVE_25519, 256, ed25519), }; static const struct supported_ecc_curve *get_curve(void *attr, size_t size) { size_t idx = 0; /* Weak: not a real DER parser: try by params then by named curve */ for (idx = 0; idx < ARRAY_SIZE(ec_curve_param); idx++) { const struct supported_ecc_curve *curve = ec_curve_param + idx; if (size == curve->oid_size && !TEE_MemCompare(attr, curve->oid_der, curve->oid_size)) return curve; if (size == curve->name_size && !TEE_MemCompare(attr, curve->name_der, curve->name_size)) return curve; } return NULL; } size_t ec_params2tee_keysize(void *ec_params, size_t size) { const struct supported_ecc_curve *curve = get_curve(ec_params, size); if (!curve) return 0; return curve->key_size; } /* * This function intentionally panics if the curve is not found. * Use ec_params2tee_keysize() to check the curve is supported by * the internal core API. */ uint32_t ec_params2tee_curve(void *ec_params, size_t size) { const struct supported_ecc_curve *curve = get_curve(ec_params, size); assert(curve); return curve->tee_id; } enum pkcs11_rc load_tee_ec_key_attrs(TEE_Attribute **tee_attrs, size_t *tee_count, struct pkcs11_object *obj) { TEE_Attribute *attrs = NULL; size_t count = 0; enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR; assert(get_key_type(obj->attributes) == PKCS11_CKK_EC); switch (get_class(obj->attributes)) { case PKCS11_CKO_PUBLIC_KEY: attrs = TEE_Malloc(3 * sizeof(TEE_Attribute), TEE_USER_MEM_HINT_NO_FILL_ZERO); if (!attrs) return PKCS11_CKR_DEVICE_MEMORY; if (pkcs2tee_load_attr(&attrs[count], TEE_ATTR_ECC_CURVE, obj, PKCS11_CKA_EC_PARAMS)) count++; if (pkcs2tee_load_attr(&attrs[count], TEE_ATTR_ECC_PUBLIC_VALUE_X, obj, PKCS11_CKA_EC_POINT)) count++; if (pkcs2tee_load_attr(&attrs[count], TEE_ATTR_ECC_PUBLIC_VALUE_Y, obj, PKCS11_CKA_EC_POINT)) count++; if (count == 3) rc = PKCS11_CKR_OK; break; case PKCS11_CKO_PRIVATE_KEY: attrs = TEE_Malloc(4 * sizeof(TEE_Attribute), TEE_USER_MEM_HINT_NO_FILL_ZERO); if (!attrs) return PKCS11_CKR_DEVICE_MEMORY; if (pkcs2tee_load_attr(&attrs[count], TEE_ATTR_ECC_CURVE, obj, PKCS11_CKA_EC_PARAMS)) count++; if (pkcs2tee_load_attr(&attrs[count], TEE_ATTR_ECC_PRIVATE_VALUE, obj, PKCS11_CKA_VALUE)) count++; if (pkcs2tee_load_attr(&attrs[count], TEE_ATTR_ECC_PUBLIC_VALUE_X, obj, PKCS11_CKA_EC_POINT)) count++; if (pkcs2tee_load_attr(&attrs[count], TEE_ATTR_ECC_PUBLIC_VALUE_Y, obj, PKCS11_CKA_EC_POINT)) count++; if (count == 4) rc = PKCS11_CKR_OK; break; default: assert(0); break; } if (rc == PKCS11_CKR_OK) { *tee_attrs = attrs; *tee_count = count; } else { TEE_Free(attrs); } return rc; } enum pkcs11_rc pkcs2tee_algo_ecdsa(uint32_t *tee_id, struct pkcs11_attribute_head *proc_params, struct pkcs11_object *obj) { switch (proc_params->id) { case PKCS11_CKM_ECDSA: case PKCS11_CKM_ECDSA_SHA1: case PKCS11_CKM_ECDSA_SHA224: case PKCS11_CKM_ECDSA_SHA256: case PKCS11_CKM_ECDSA_SHA384: case PKCS11_CKM_ECDSA_SHA512: break; default: return PKCS11_CKR_GENERAL_ERROR; } /* * TODO: Fixing this in a way to support also other EC curves would * require OP-TEE to be updated for newer version of GlobalPlatform API */ switch (get_object_key_bit_size(obj)) { case 192: *tee_id = TEE_ALG_ECDSA_P192; break; case 224: *tee_id = TEE_ALG_ECDSA_P224; break; case 256: *tee_id = TEE_ALG_ECDSA_P256; break; case 384: *tee_id = TEE_ALG_ECDSA_P384; break; case 521: *tee_id = TEE_ALG_ECDSA_P521; break; default: TEE_Panic(0); break; } return PKCS11_CKR_OK; } static enum pkcs11_rc tee2pkcs_ec_attributes(struct obj_attrs **pub_head, struct obj_attrs **priv_head, TEE_ObjectHandle tee_obj, size_t tee_size) { void *x_ptr = NULL; void *y_ptr = NULL; uint8_t *ecpoint = NULL; size_t x_size = 0; size_t y_size = 0; size_t psize = 0; size_t qsize = 0; size_t dersize = 0; size_t poffset = 0; size_t hsize = 0; enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR; rc = tee2pkcs_add_attribute(priv_head, PKCS11_CKA_VALUE, tee_obj, TEE_ATTR_ECC_PRIVATE_VALUE); if (rc) goto out; rc = alloc_get_tee_attribute_data(tee_obj, TEE_ATTR_ECC_PUBLIC_VALUE_X, &x_ptr, &x_size); if (rc) goto out; rc = alloc_get_tee_attribute_data(tee_obj, TEE_ATTR_ECC_PUBLIC_VALUE_Y, &y_ptr, &y_size); if (rc) goto x_cleanup; psize = (tee_size + 7) / 8; if (x_size > psize || y_size > psize) { rc = PKCS11_CKR_ARGUMENTS_BAD; goto y_cleanup; } qsize = 1 + 2 * psize; if (qsize < 0x80) { /* DER short definitive form up to 127 bytes */ dersize = qsize + 2; hsize = 2 /* der */ + 1 /* point compression */; } else if (qsize < 0x100) { /* DER long definitive form up to 255 bytes */ dersize = qsize + 3; hsize = 3 /* der */ + 1 /* point compression */; } else { EMSG("Too long DER value"); rc = PKCS11_CKR_MECHANISM_PARAM_INVALID; goto y_cleanup; } ecpoint = TEE_Malloc(dersize, TEE_MALLOC_FILL_ZERO); if (!ecpoint) { rc = PKCS11_CKR_DEVICE_MEMORY; goto y_cleanup; } if (qsize < 0x80) { /* DER encoding */ ecpoint[0] = 0x04; ecpoint[1] = qsize & 0x7f; /* Only UNCOMPRESSED ECPOINT is currently supported */ ecpoint[2] = 0x04; } else if (qsize < 0x100) { /* DER encoding */ ecpoint[0] = 0x04; ecpoint[1] = 0x80 | 0x01; /* long form, one size octet */ ecpoint[2] = qsize & 0xFF; /* Only UNCOMPRESSED ECPOINT is currently supported */ ecpoint[3] = 0x04; } poffset = 0; if (x_size < psize) poffset = psize - x_size; TEE_MemMove(ecpoint + hsize + poffset, x_ptr, x_size); poffset = 0; if (y_size < psize) poffset = psize - y_size; TEE_MemMove(ecpoint + hsize + psize + poffset, y_ptr, y_size); /* * Add EC_POINT on both private and public key objects as * TEE_PopulateTransientObject requires public x/y values * for TEE_TYPE_ECDSA_KEYPAIR. */ rc = add_attribute(priv_head, PKCS11_CKA_EC_POINT, ecpoint, dersize); if (rc) goto ecpoint_cleanup; rc = add_attribute(pub_head, PKCS11_CKA_EC_POINT, ecpoint, dersize); ecpoint_cleanup: TEE_Free(ecpoint); y_cleanup: TEE_Free(y_ptr); x_cleanup: TEE_Free(x_ptr); out: return rc; } enum pkcs11_rc generate_ec_keys(struct pkcs11_attribute_head *proc_params, struct obj_attrs **pub_head, struct obj_attrs **priv_head) { enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR; void *a_ptr = NULL; uint32_t a_size = 0; uint32_t tee_size = 0; uint32_t tee_curve = 0; TEE_ObjectHandle tee_obj = TEE_HANDLE_NULL; TEE_Attribute tee_key_attr[1] = { }; TEE_Result res = TEE_ERROR_GENERIC; if (!proc_params || !*pub_head || !*priv_head) return PKCS11_CKR_TEMPLATE_INCONSISTENT; if (remove_empty_attribute(pub_head, PKCS11_CKA_EC_POINT) || remove_empty_attribute(priv_head, PKCS11_CKA_VALUE) || remove_empty_attribute(priv_head, PKCS11_CKA_EC_PARAMS)) { EMSG("Unexpected attribute(s) found"); trace_attributes("public-key", *pub_head); trace_attributes("private-key", *priv_head); return PKCS11_CKR_TEMPLATE_INCONSISTENT; } if (get_attribute_ptr(*pub_head, PKCS11_CKA_EC_PARAMS, &a_ptr, &a_size) || !a_ptr) { EMSG("No EC_PARAMS attribute found in public key"); return PKCS11_CKR_ATTRIBUTE_TYPE_INVALID; } tee_size = ec_params2tee_keysize(a_ptr, a_size); if (!tee_size) return PKCS11_CKR_ATTRIBUTE_TYPE_INVALID; tee_curve = ec_params2tee_curve(a_ptr, a_size); TEE_InitValueAttribute(tee_key_attr, TEE_ATTR_ECC_CURVE, tee_curve, 0); /* Create an ECDSA TEE key: will match PKCS11 ECDSA and ECDH */ res = TEE_AllocateTransientObject(TEE_TYPE_ECDSA_KEYPAIR, tee_size, &tee_obj); if (res) { EMSG("Transient alloc failed with %#"PRIx32, res); return tee2pkcs_error(res); } res = TEE_RestrictObjectUsage1(tee_obj, TEE_USAGE_EXTRACTABLE); if (res) { rc = tee2pkcs_error(res); goto out; } res = TEE_GenerateKey(tee_obj, tee_size, tee_key_attr, 1); if (res) { rc = tee2pkcs_error(res); goto out; } /* Private key needs the same EC_PARAMS as used by the public key */ rc = add_attribute(priv_head, PKCS11_CKA_EC_PARAMS, a_ptr, a_size); if (rc) goto out; rc = tee2pkcs_ec_attributes(pub_head, priv_head, tee_obj, tee_size); out: if (tee_obj != TEE_HANDLE_NULL) TEE_CloseObject(tee_obj); return rc; } enum pkcs11_rc load_tee_eddsa_key_attrs(TEE_Attribute **tee_attrs, size_t *tee_count, struct pkcs11_object *obj) { TEE_Attribute *attrs = NULL; size_t count = 0; enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR; assert(get_key_type(obj->attributes) == PKCS11_CKK_EC_EDWARDS); switch (get_class(obj->attributes)) { case PKCS11_CKO_PUBLIC_KEY: attrs = TEE_Malloc(sizeof(TEE_Attribute), TEE_USER_MEM_HINT_NO_FILL_ZERO); if (!attrs) return PKCS11_CKR_DEVICE_MEMORY; if (pkcs2tee_load_attr(&attrs[count], TEE_ATTR_ED25519_PUBLIC_VALUE, obj, PKCS11_CKA_EC_POINT)) count++; if (count == 1) rc = PKCS11_CKR_OK; break; case PKCS11_CKO_PRIVATE_KEY: attrs = TEE_Malloc(2 * sizeof(TEE_Attribute), TEE_USER_MEM_HINT_NO_FILL_ZERO); if (!attrs) return PKCS11_CKR_DEVICE_MEMORY; if (pkcs2tee_load_attr(&attrs[count], TEE_ATTR_ED25519_PRIVATE_VALUE, obj, PKCS11_CKA_VALUE)) count++; if (pkcs2tee_load_attr(&attrs[count], TEE_ATTR_ED25519_PUBLIC_VALUE, obj, PKCS11_CKA_EC_POINT)) count++; if (count == 2) rc = PKCS11_CKR_OK; break; default: assert(0); break; } if (rc == PKCS11_CKR_OK) { *tee_attrs = attrs; *tee_count = count; } else { TEE_Free(attrs); } return rc; } enum pkcs11_rc generate_eddsa_keys(struct pkcs11_attribute_head *proc_params, struct obj_attrs **pub_head, struct obj_attrs **priv_head) { enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR; void *a_ptr = NULL; uint32_t a_size = 0; uint32_t tee_size = 0; TEE_ObjectHandle tee_obj = TEE_HANDLE_NULL; TEE_Result res = TEE_ERROR_GENERIC; if (!proc_params || !*pub_head || !*priv_head) return PKCS11_CKR_TEMPLATE_INCONSISTENT; if (remove_empty_attribute(pub_head, PKCS11_CKA_EC_POINT) || remove_empty_attribute(priv_head, PKCS11_CKA_VALUE) || remove_empty_attribute(priv_head, PKCS11_CKA_EC_POINT) || remove_empty_attribute(priv_head, PKCS11_CKA_EC_PARAMS)) { EMSG("Unexpected attribute(s) found"); trace_attributes("public-key", *pub_head); trace_attributes("private-key", *priv_head); return PKCS11_CKR_TEMPLATE_INCONSISTENT; } if (get_attribute_ptr(*pub_head, PKCS11_CKA_EC_PARAMS, &a_ptr, &a_size) || !a_ptr) { EMSG("No EC_PARAMS attribute found in public key"); return PKCS11_CKR_ATTRIBUTE_TYPE_INVALID; } tee_size = ec_params2tee_keysize(a_ptr, a_size); if (!tee_size) return PKCS11_CKR_ATTRIBUTE_TYPE_INVALID; res = TEE_AllocateTransientObject(TEE_TYPE_ED25519_KEYPAIR, tee_size, &tee_obj); if (res) { EMSG("Transient alloc failed with %#"PRIx32, res); return tee2pkcs_error(res); } res = TEE_RestrictObjectUsage1(tee_obj, TEE_USAGE_EXTRACTABLE); if (res) { rc = tee2pkcs_error(res); goto out; } res = TEE_GenerateKey(tee_obj, tee_size, NULL, 0); if (res) { rc = tee2pkcs_error(res); goto out; } /* Private key needs the same EC_PARAMS as used by the public key */ rc = add_attribute(priv_head, PKCS11_CKA_EC_PARAMS, a_ptr, a_size); if (rc) goto out; rc = tee2pkcs_add_attribute(priv_head, PKCS11_CKA_VALUE, tee_obj, TEE_ATTR_ED25519_PRIVATE_VALUE); if (rc) goto out; rc = tee2pkcs_add_attribute(priv_head, PKCS11_CKA_EC_POINT, tee_obj, TEE_ATTR_ED25519_PUBLIC_VALUE); if (rc) goto out; rc = tee2pkcs_add_attribute(pub_head, PKCS11_CKA_EC_POINT, tee_obj, TEE_ATTR_ED25519_PUBLIC_VALUE); out: if (tee_obj != TEE_HANDLE_NULL) TEE_CloseObject(tee_obj); return rc; } enum pkcs11_rc pkcs2tee_proc_params_eddsa(struct active_processing *proc, struct pkcs11_attribute_head *proc_params) { enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR; uint32_t ctx_len = 0; uint32_t flag = 0; void *ctx_data = NULL; struct serialargs args = { }; struct eddsa_processing_ctx *ctx = NULL; serialargs_init(&args, proc_params->data, proc_params->size); rc = serialargs_get_u32(&args, &flag); if (rc) return rc; rc = serialargs_get_u32(&args, &ctx_len); if (rc) return rc; rc = serialargs_get_ptr(&args, &ctx_data, ctx_len); if (rc) return rc; if (serialargs_remaining_bytes(&args)) return PKCS11_CKR_ARGUMENTS_BAD; proc->extra_ctx = TEE_Malloc(sizeof(*ctx) + ctx_len, TEE_USER_MEM_HINT_NO_FILL_ZERO); if (!proc->extra_ctx) return PKCS11_CKR_DEVICE_MEMORY; ctx = proc->extra_ctx; ctx->ctx_len = ctx_len; ctx->flag = flag; TEE_MemMove(ctx->ctx, ctx_data, ctx_len); return PKCS11_CKR_OK; } size_t ecdsa_get_input_max_byte_size(TEE_OperationHandle op) { TEE_OperationInfo info = { }; TEE_GetOperationInfo(op, &info); switch (info.algorithm) { case TEE_ALG_ECDSA_P192: return 24; case TEE_ALG_ECDSA_P224: return 28; case TEE_ALG_ECDSA_P256: return 32; case TEE_ALG_ECDSA_P384: return 48; case TEE_ALG_ECDSA_P521: return 66; default: DMSG("Unexpected ECDSA algorithm %#"PRIx32, info.algorithm); return 0; } } enum pkcs11_rc pkcs2tee_param_ecdh(struct pkcs11_attribute_head *proc_params, void **pub_data, size_t *pub_size) { enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR; struct serialargs args = { }; uint32_t word = 0; uint8_t byte = 0; serialargs_init(&args, proc_params->data, proc_params->size); /* Skip KDF */ rc = serialargs_get_u32(&args, &word); if (rc) return rc; /* Shared data size, shall be 0 */ rc = serialargs_get_u32(&args, &word); if (rc || word) return rc; /* Public data size and content */ rc = serialargs_get_u32(&args, &word); if (rc || !word) return rc; *pub_size = word; rc = serialargs_get(&args, &byte, sizeof(uint8_t)); if (rc) return rc; if (byte != 0x02 && byte != 0x03 && byte != 0x04) return PKCS11_CKR_ARGUMENTS_BAD; if (byte != 0x04) { EMSG("DER compressed public key format not yet supported"); return PKCS11_CKR_ARGUMENTS_BAD; } *pub_size -= sizeof(uint8_t); if (*pub_size >= 0x80) { EMSG("DER long definitive form not yet supported"); return PKCS11_CKR_ARGUMENTS_BAD; } rc = serialargs_get_ptr(&args, pub_data, *pub_size); if (rc) return rc; if (serialargs_remaining_bytes(&args)) return PKCS11_CKR_ARGUMENTS_BAD; return PKCS11_CKR_OK; } enum pkcs11_rc pkcs2tee_algo_ecdh(uint32_t *tee_id, struct pkcs11_attribute_head *proc_params, struct pkcs11_object *obj) { enum pkcs11_rc rc = PKCS11_CKR_GENERAL_ERROR; struct serialargs args = { }; uint32_t kdf = 0; serialargs_init(&args, proc_params->data, proc_params->size); rc = serialargs_get_u32(&args, &kdf); if (rc) return rc; /* Remaining arguments are extracted by pkcs2tee_param_ecdh */ if (kdf != PKCS11_CKD_NULL) { DMSG("Only support CKD_NULL key derivation for ECDH"); return PKCS11_CKR_MECHANISM_PARAM_INVALID; } switch (get_object_key_bit_size(obj)) { case 192: *tee_id = TEE_ALG_ECDH_P192; break; case 224: *tee_id = TEE_ALG_ECDH_P224; break; case 256: *tee_id = TEE_ALG_ECDH_P256; break; case 384: *tee_id = TEE_ALG_ECDH_P384; break; case 521: *tee_id = TEE_ALG_ECDH_P521; break; default: TEE_Panic(0); break; } return PKCS11_CKR_OK; }