ADD_DEFINITIONS("-D${CMAKE_BUILD_TYPE}")
+IF(FORMAT_RAW_ENABLED)
+ADD_DEFINITIONS("-DFORMAT_RAW_ENABLED")
+ENDIF(FORMAT_RAW_ENABLED)
+
ADD_SUBDIRECTORY(ta)
ADD_SUBDIRECTORY(serialization)
-DINCLUDE_DIR=%{include_dir} \
-DLIB_DIR=%{lib_dir} \
-DTA_NAME=%{ta_name} \
- -DSECRET_KEY_ENABLE=%{secret_ta_key_enable}
+ -DSECRET_KEY_ENABLE=%{secret_ta_key_enable} \
+ -DFORMAT_RAW_ENABLED=%{?format_raw:%format_raw}%{!?format_raw:OFF}
make %{?jobs:-j%jobs}
%install
${KEY_MANAGER_TA_PATH}/src/internal.c
${KEY_MANAGER_TA_PATH}/src/km_ta.c
${KEY_MANAGER_TA_PATH}/src/base64.c
+ ${KEY_MANAGER_TA_PATH}/src/asn1.c
${KEY_MANAGER_TA_COMMON_PATH}/src/log.c
${KEY_MANAGER_TA_SERIALIZATION_PATH}/src/km_serialization.c
)
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd. All rights reserved
+ *
+ * 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 <tee_internal_api.h>
+
+#pragma once
+
+TEE_Result ecdsa_asn1_to_raw(void *sig, uint32_t sig_len, void **out, uint32_t *out_len);
+TEE_Result ecdsa_raw_to_asn1(void *sig, uint32_t sig_len, void **out, uint32_t *out_len);
void *output, uint32_t *output_size);
TEE_Result KM_AsymmetricSign(TEE_OperationHandle hndl, void *digest, uint32_t digest_size,
- void *signature, uint32_t *sig_size);
+ void *signature, uint32_t *sig_size, bool raw);
TEE_Result KM_AsymmetricVerify(TEE_OperationHandle hndl, void *digest, uint32_t digest_size,
- void *signature, uint32_t sig_size);
+ void *signature, uint32_t sig_size, bool raw);
#endif // __CRYPTO_ASYMMETRIC_H__
--- /dev/null
+/*
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd. All rights reserved
+ *
+ * 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 <string.h> //memcpy
+
+#include "asn1.h"
+
+/*
+ * Compute ASN.1 encoded length for the provided integer. The ASN.1
+ * encoding is signed, so its leading bit must have value 0; it must
+ * also be of minimal length (so leading bytes of value 0 must be
+ * removed, except if that would contradict the rule about the sign
+ * bit).
+ */
+
+static size_t asn1_int_length(const unsigned char *x, size_t xlen)
+{
+ while (xlen > 0 && *x == 0) {
+ x ++;
+ xlen --;
+ }
+ if (xlen == 0 || *x >= 0x80) {
+ xlen ++;
+ }
+ return xlen;
+}
+
+TEE_Result ecdsa_raw_to_asn1(void *sig, uint32_t sig_len, void **out, uint32_t *out_len)
+{
+ TEE_Result ret = TEE_SUCCESS;
+ unsigned char *buf;
+ uint32_t hlen, rlen, slen, zlen, off;
+
+ /*
+ * Internal buffer is large enough to accommodate a signature
+ * such that r and s fit on 125 bytes each (signed encoding),
+ * meaning a curve order of up to 999 bits. This is the limit
+ * that ensures "simple" length encodings.
+ */
+ uint8_t *tmp = NULL;
+ tmp = (uint8_t *) TEE_Malloc(257, 0);
+ if (tmp == NULL) {
+ ret = TEE_ERROR_OUT_OF_MEMORY;
+ goto clean;
+ }
+
+ buf = sig;
+ if ((sig_len & 1) != 0) {
+ ret = TEE_ERROR_GENERIC;
+ goto clean;
+ }
+
+ /*
+ * Compute lengths for the two integers.
+ */
+ hlen = sig_len >> 1;
+ rlen = asn1_int_length(buf, hlen);
+ slen = asn1_int_length(buf + hlen, hlen);
+ if (rlen > 125 || slen > 125) {
+ ret = TEE_ERROR_GENERIC;
+ goto clean;
+ }
+
+ /*
+ * SEQUENCE header.
+ */
+ tmp[0] = 0x30;
+ zlen = rlen + slen + 4;
+ if (zlen >= 0x80) {
+ tmp[1] = 0x81;
+ tmp[2] = zlen;
+ off = 3;
+ } else {
+ tmp[1] = zlen;
+ off = 2;
+ }
+
+ /*
+ * First INTEGER (r).
+ */
+ tmp[off ++] = 0x02;
+ tmp[off ++] = rlen;
+ if (rlen > hlen) {
+ tmp[off] = 0x00;
+ memcpy(tmp + off + 1, buf, hlen);
+ } else {
+ memcpy(tmp + off, buf + hlen - rlen, rlen);
+ }
+ off += rlen;
+
+ /*
+ * Second INTEGER (s).
+ */
+ tmp[off ++] = 0x02;
+ tmp[off ++] = slen;
+ if (slen > hlen) {
+ tmp[off] = 0x00;
+ memcpy(tmp + off + 1, buf + hlen, hlen);
+ } else {
+ memcpy(tmp + off, buf + sig_len - slen, slen);
+ }
+ off += slen;
+
+ /*
+ * Return ASN.1 signature.
+ */
+ *out = TEE_Realloc(tmp, off);
+ *out_len = off;
+
+clean:
+ if (ret != TEE_SUCCESS)
+ TEE_Free(tmp);
+
+ return ret;
+}
+
+TEE_Result ecdsa_asn1_to_raw(void *sig, uint32_t sig_len, void **out, uint32_t *out_len)
+{
+ TEE_Result ret = TEE_SUCCESS;
+ unsigned char *buf, *r, *s;
+ uint32_t zlen, rlen, slen, off;
+
+ /*
+ * Signature format is a SEQUENCE of two INTEGER values. We
+ * support only integers of less than 127 bytes each (signed
+ * encoding) so the resulting raw signature will have length
+ * at most 254 bytes.
+ */
+
+ uint8_t *tmp = NULL;
+ tmp = (uint8_t *) TEE_Malloc(254, 0);
+ if (tmp == NULL) {
+ ret = TEE_ERROR_OUT_OF_MEMORY;
+ goto clean;
+ }
+
+ buf = sig;
+ if (sig_len < 8) {
+ ret = TEE_ERROR_GENERIC;
+ goto clean;
+ }
+
+ /*
+ * First byte is SEQUENCE tag.
+ */
+ if (buf[0] != 0x30) {
+ ret = TEE_ERROR_GENERIC;
+ goto clean;
+ }
+
+ /*
+ * The SEQUENCE length will be encoded over one or two bytes. We
+ * limit the total SEQUENCE contents to 255 bytes, because it
+ * makes things simpler; this is enough for subgroup orders up
+ * to 999 bits.
+ */
+ zlen = buf[1];
+ if (zlen > 0x80) {
+ if (zlen != 0x81) {
+ ret = TEE_ERROR_GENERIC;
+ goto clean;
+ }
+ zlen = buf[2];
+ if (zlen != sig_len - 3) {
+ ret = TEE_ERROR_GENERIC;
+ goto clean;
+ }
+ off = 3;
+ } else {
+ if (zlen != sig_len - 2) {
+ ret = TEE_ERROR_GENERIC;
+ goto clean;
+ }
+ off = 2;
+ }
+
+ /*
+ * First INTEGER (r).
+ */
+ if (buf[off ++] != 0x02) {
+ ret = TEE_ERROR_GENERIC;
+ goto clean;
+ }
+ rlen = buf[off ++];
+ if (rlen >= 0x80) {
+ ret = TEE_ERROR_GENERIC;
+ goto clean;
+ }
+ r = buf + off;
+ off += rlen;
+
+ /*
+ * Second INTEGER (s).
+ */
+ if (off + 2 > sig_len) {
+ ret = TEE_ERROR_GENERIC;
+ goto clean;
+ }
+ if (buf[off ++] != 0x02) {
+ ret = TEE_ERROR_GENERIC;
+ goto clean;
+ }
+ slen = buf[off ++];
+ if (slen >= 0x80 || slen != sig_len - off) {
+ ret = TEE_ERROR_GENERIC;
+ goto clean;
+ }
+ s = buf + off;
+
+ /*
+ * Removing leading zeros from r and s.
+ */
+ while (rlen > 0 && *r == 0) {
+ rlen --;
+ r ++;
+ }
+ while (slen > 0 && *s == 0) {
+ slen --;
+ s ++;
+ }
+
+ /*
+ * Compute common length for the two integers, then copy integers
+ * into the temporary buffer, and finally copy it back over the
+ * signature buffer.
+ */
+ zlen = rlen > slen ? rlen : slen;
+ sig_len = zlen << 1;
+
+ memset(tmp, 0, sig_len);
+ memcpy(tmp + zlen - rlen, r, rlen);
+ memcpy(tmp + sig_len - slen, s, slen);
+ *out = TEE_Realloc(tmp, sig_len);
+ *out_len = sig_len;
+
+clean:
+ if (ret != TEE_SUCCESS)
+ TEE_Free(tmp);
+
+ return ret;
+}
\ No newline at end of file
uint32_t digestSize = 0;
uint32_t algo = 0;
uint32_t key_size_in_bits = 0;
+ bool raw = false;
void *in_buffer = param[1].memref.buffer;
void *out_buffer = param[2].memref.buffer;
}
outSize = KM_MaxObjectSizeBytes(&info);
- if (param[0].value.a == ALGO_ECDSA_SV)
- outSize *= 2;
+ if (param[0].value.a == ALGO_ECDSA_SV) {
+ // ECDSA-Sig-Value ::= SEQUENCE {
+ // r INTEGER,
+ // s INTEGER
+ // }
+ outSize = 8 + outSize *2;
+ #ifdef FORMAT_RAW_ENABLED
+ raw = true;
+ #endif
+ }
out = TEE_Malloc(outSize, 0);
if (out == NULL) {
}
// create signature
- ret = KM_AsymmetricSign(operation, digest, digestSize, out, &outSize);
+ ret = KM_AsymmetricSign(operation, digest, digestSize, out, &outSize, raw);
if (TEE_SUCCESS != ret) {
LOG("Failed to sign digested message");
goto clean;
uint32_t digestSize = 0;
uint32_t algo = 0;
uint32_t key_size_in_bits = 0;
+ bool raw = false;
void *in_buffer = param[1].memref.buffer;
uint32_t in_size_guard = param[1].memref.size;
goto clean;
}
+ if (param[0].value.a == ALGO_ECDSA_SV) {
+ #ifdef FORMAT_RAW_ENABLED
+ raw = true;
+ #endif
+ }
+
// no check over here - return anything that TEE_AsymmetricVerifyDigest gives us
// return code will contain information whether the signature was correct or not
- ret = KM_AsymmetricVerify(operation, digest, digestSize, signature.data, signature.data_size);
+ ret = KM_AsymmetricVerify(operation, digest, digestSize, signature.data, signature.data_size, raw);
clean:
TEE_CloseObject(key);
* @brief Implementation of Global Platform Internal API usage (asymmetric operations)
*/
+#include "asn1.h"
#include "crypto_asymmetric.h"
#include "log.h"
}
TEE_Result KM_AsymmetricSign(TEE_OperationHandle hndl, void *digest, uint32_t digest_size,
- void *signature, uint32_t *sig_size)
+ void *signature, uint32_t *sig_size, bool raw)
{
TEE_Result ret = TEE_SUCCESS;
+ void *out;
+ uint32_t out_len;
ret = TEE_AsymmetricSignDigest(hndl, NULL, 0, digest, digest_size, signature, sig_size);
if (TEE_SUCCESS != ret) {
return ret;
}
+#if 0
+ if (raw) {
+ void *in;
+ uint32_t in_len;
+ ret = ecdsa_asn1_to_raw(signature, *sig_size, &in, &in_len);
+ if (TEE_SUCCESS != ret) {
+ LOG("ecdsa_asn1_to_raw has failed with=%x.", ret);
+ return ret;
+ }
+ signature = in;
+ *sig_size = in_len;
+ }
+#endif
+
+ if (raw) {
+ ret = ecdsa_raw_to_asn1(signature, *sig_size, &out, &out_len);
+ if (TEE_SUCCESS != ret) {
+ LOG("ecdsa_raw_to_asn1 has failed with=%x.", ret);
+ return ret;
+ }
+ memcpy(signature, out, out_len);
+ TEE_Free(out);
+ *sig_size = out_len;
+ }
+
return ret;
}
TEE_Result KM_AsymmetricVerify(TEE_OperationHandle hndl, void *digest, uint32_t digest_size,
- void *signature, uint32_t sig_size)
+ void *signature, uint32_t sig_size, bool raw)
{
TEE_Result ret = TEE_SUCCESS;
+ void *out;
+ uint32_t out_len;
+
+ if (raw) {
+ ret = ecdsa_asn1_to_raw(signature, sig_size, &out, &out_len);
+ if (TEE_SUCCESS != ret) {
+ LOG("ecdsa_asn1_to_raw has failed with=%x.", ret);
+ return ret;
+ }
+ }
+
+#if 0
+ if (raw) {
+ void *in;
+ uint32_t in_len;
+ ret = ecdsa_raw_to_asn1(out, out_len, &in, &in_len);
+ if (TEE_SUCCESS != ret) {
+ LOG("ecdsa_raw_to_asn1 has failed with=%x.", ret);
+ return ret;
+ }
+ out = in;
+ out_len = in_len;
+ }
+#endif
+
+ if (raw) {
+ ret = TEE_AsymmetricVerifyDigest(hndl, NULL, 0, digest, digest_size, out, out_len);
+ TEE_Free(out);
+ } else {
+ ret = TEE_AsymmetricVerifyDigest(hndl, NULL, 0, digest, digest_size, signature, sig_size);
+ }
- ret = TEE_AsymmetricVerifyDigest(hndl, NULL, 0, digest, digest_size, signature, sig_size);
if (TEE_SUCCESS != ret && TEE_ERROR_SIGNATURE_INVALID != ret) {
LOG("TEE_AsymmetricVerifyDigest has failed with=%x.", ret);
return ret;