blob: 75b20dfc3afe959c255a95391e78ea3f93f3f8c0 [file] [log] [blame]
/**
* @file hcAsn.c
* @author NXP Semiconductors
* @version 1.0
* @par License
*
* Copyright 2016 NXP
* SPDX-License-Identifier: Apache-2.0
*
* @par Description
*
* @par History
*
*/
#include "sm_types.h"
// #include "tst_sm_util.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "ax_util.h"
#include "nxLog_hostLib.h"
#include "nxEnsure.h"
/// @cond
#define ASN_TAG_SEQUENCE 0x30
#define ASN_TAG_INTEGER 0x02
#define ASN_P192_BYTE_COUNT 0x18
#define ASN_P224_BYTE_COUNT 0x1C
#define ASN_P256_BYTE_COUNT 0x20
/// @endcond
// Control LOG info created
// #define AX_HC_ASN_LOG_VERBOSE
/*
Example Asn Signature (LEN=71):
30 45
02 21
00 AD D2 2C E9 5B 05 F8 A0 8D 33 33 0F FF 24 7A 55 F4 60 F1 DF 55 27 55 C4 C8 63 53 6A 65 D4 41 74
02 20
21 E5 FF FF 6B 6C B3 0D B9 D6 F2 AB 67 5B 4C 8A E5 7C 58 44 F9 55 8D 54 F1 3E F8 FE C5 00 C0 EF
Corresponding Plain Signature
AD D2 2C E9 5B 05 F8 A0 8D 33 33 0F FF 24 7A 55 F4 60 F1 DF 55 27 55 C4 C8 63 53 6A 65 D4 41 74
21 E5 FF FF 6B 6C B3 0D B9 D6 F2 AB 67 5B 4C 8A E5 7C 58 44 F9 55 8D 54 F1 3E F8 FE C5 00 C0 EF
*/
U16 hcAsnToPlainEcc256(U8 *signature, U16 *pSignatureLen, U8 *asnSignature, U16 asnSignatureLen)
{
U16 rv = ERR_GENERAL_ERROR;
int i = 0;
int component = 0;
ENSURE_OR_GO_EXIT(pSignatureLen != NULL);
ENSURE_OR_GO_EXIT(asnSignature != NULL);
ENSURE_OR_GO_EXIT(signature != NULL);
if (*pSignatureLen < 64)
{
return ERR_API_ERROR;
}
if (asnSignature[0] == ASN_TAG_SEQUENCE)
{
if ( (asnSignature[1]+2) == asnSignatureLen)
{
i = 2;
for (component=0; component<2; component++)
{
if (asnSignature[i] == ASN_TAG_INTEGER)
{
if ((asnSignature[i+1] == 0x20) || (asnSignature[i+1] == 0x21))
{
// Conditionally skip leading 0 when copying to plain format
memcpy(signature+(component*0x20), &asnSignature[i+2+(asnSignature[i+1]-0x20)], 0x20);
i += 2 + asnSignature[i+1];
}
else
{
*pSignatureLen = 0;
return ERR_WRONG_RESPONSE;
}
}
else
{
*pSignatureLen = 0;
return ERR_WRONG_RESPONSE;
}
}
}
else
{
printf("asnSignature[1] + 2: 0x%02X, asnSignatureLen: 0x%02X", asnSignature[1] + 2, asnSignatureLen); // DEBUG
*pSignatureLen = 0;
return ERR_WRONG_RESPONSE;
}
}
else
{
*pSignatureLen = 0;
return ERR_WRONG_RESPONSE;
}
*pSignatureLen = 0x40;
// printBytestring("asnSignature", asnSignature, asnSignatureLen); // DEBUG
// printBytestring("signature", signature, *pSignatureLen); // DEBUG
rv = SW_OK;
exit:
return rv;
}
U16 hcPlainToAsnEcc256(U8 *asnSignature, U16 *asnSignatureLen, U8 *signature, U16 signatureLen)
{
U16 rv = ERR_GENERAL_ERROR;
int i = 0;
int component = 0;
ENSURE_OR_GO_EXIT(asnSignatureLen != NULL);
ENSURE_OR_GO_EXIT(asnSignature != NULL);
ENSURE_OR_GO_EXIT(signature != NULL);
if (*asnSignatureLen < (64+2+4+2))
{
return ERR_API_ERROR;
}
if (signatureLen != 64)
{
return ERR_API_ERROR;
}
asnSignature[0] = ASN_TAG_SEQUENCE;
asnSignature[1] = 0;
i = 2;
for (component = 0; component < 2; component++)
{
asnSignature[i] = ASN_TAG_INTEGER;
if (signature[0 + component*0x20] > 0x7F)
{
asnSignature[i+1] = 0x21;
asnSignature[i+2] = 0x00;
memcpy(&asnSignature[i+3], signature+component*0x20, 0x20);
asnSignature[1] += (0x20 + 3);
i += 0x23;
}
else
{
asnSignature[i+1] = 0x20;
memcpy(&asnSignature[i+2], signature+component*0x20, 0x20);
asnSignature[1] += (0x20 + 2);
i += 0x22;
}
}
*asnSignatureLen = asnSignature[1] + 2;
// printBytestring("asnSignature", asnSignature, *asnSignatureLen); // DEBUG
rv = SW_OK;
exit:
return rv;
}
/**
The purpose of this function is to turn the proprietary ECDSA signature format - that
may be returned by the A7x - into a normalized ASN.1 format.
The A7x will package the 'r' and 's' integer components of an ECDSA signature either as octet arrays of
ASN_Pxxx_BYTE_COUNT or (ASN_Pxxx_BYTE_COUNT + 1) with the additional octet added to ensure the
integer value is a positive number.
ASN.1 requires an integer value is always encoded in the smallest possible number of octets, a requirement
not fulfilled by the A7x.
Note: The implementation of this function only deals with signatures associated with key lengths of 192, 224 and 256 bits
\verbatim
Example of ECDSA-P256 - TLV format - signature that must be normalized
30 45
02
20
00 33 30 6B 74 4E 8B FE 3C 22 6F A2 E4 76 F6 62 CE 09 5B DD 5E 54 A3 DD D0 B5 E7 1B 28 4D F1 63
^^ ^^
02
21
00 9F 9E 24 81 7F FD CF 37 7E 35 DA 05 D7 17 60 2D C1 05 E7 24 22 EE F5 59 AC 25 9F 40 AB FE EC 56
\endverbatim
@param[in,out] asnSignature IN: buffer containing the ECDSA signature in the A7x specific format; OUT: Signature compliant to ASN.1
@param[in,out] asnSignatureLen IN: length of ECDSA signature in A7x specific format;
OUT: Length of signature in ASN.1 format (always less than or equal to length of A7x specific format)
@returns ::SW_OK upon successfull execution
*/
U16 hcNormalizeAsnSignatureEcc(U8 *asnSignature, U16 *asnSignatureLen)
{
U16 rv = ERR_GENERAL_ERROR;
int i = 0;
int component = 0;
U8 asnByteCount = ASN_P256_BYTE_COUNT;
ENSURE_OR_GO_EXIT(asnSignature != NULL);
ENSURE_OR_GO_EXIT(asnSignatureLen != NULL);
#ifdef AX_HC_ASN_LOG_VERBOSE
axPrintByteArray("Before normalization", asnSignature, *asnSignatureLen, AX_COLON_32);
#endif
// Check whether the signature length matches one of the supported keylengths and set
// the matching asnByteCount.
// The case where both r and s are extended with a zero byte in position ASN_P256_BYTE_COUNT + 1 must not be handled.
// Other cases are flagged as an error
switch (*asnSignatureLen)
{
case (2 * (ASN_P192_BYTE_COUNT+2) + 2):
case (2 * (ASN_P192_BYTE_COUNT+2) + 3):
asnByteCount = ASN_P192_BYTE_COUNT;
break;
case (2 * (ASN_P224_BYTE_COUNT+2) + 2):
case (2 * (ASN_P224_BYTE_COUNT+2) + 3):
asnByteCount = ASN_P224_BYTE_COUNT;
break;
case (2 * (ASN_P256_BYTE_COUNT+2) + 2):
case (2 * (ASN_P256_BYTE_COUNT+2) + 3):
asnByteCount = ASN_P256_BYTE_COUNT;
break;
case (2 * (ASN_P192_BYTE_COUNT+2) + 4):
case (2 * (ASN_P224_BYTE_COUNT+2) + 4):
case (2 * (ASN_P256_BYTE_COUNT+2) + 4):
return rv;
default:
// printf("Skip normalization because of unexpected SignatureLen.\r\n");
return ERR_API_ERROR;
}
if (asnSignature[0] == ASN_TAG_SEQUENCE)
{
if ( (asnSignature[1]+2) == *asnSignatureLen)
{
i = 2;
for (component=0; component<2; component++)
{
// printf("Debug (%s - line:%d): component = %d\r\n", __FILE__, __LINE__, component);
if (asnSignature[i] == ASN_TAG_INTEGER)
{
if (asnSignature[i+1] == asnByteCount)
{
// Check whether Zero extension byte must be removed
if ( (asnSignature[i+2] == 0x00) && (asnSignature[i+3] <= 0x7F) )
{
U8 j;
// Check whether there are more 0x00 bytes to strip (start again from initial position)
// 'j' will match the amount of leading 0x00 byte to strip when leaving the loop
for (j=0; j<(asnByteCount-1); j++)
{
if ( (asnSignature[i+2+j] == 0x00) && (asnSignature[i+3+j] <= 0x7F) )
{
continue;
}
break;
}
// Check on possible buffer overflow
if (*asnSignatureLen <= (i + 2 + j))
{
return ERR_WRONG_RESPONSE;
}
memmove( &asnSignature[i+2], &asnSignature[i+2+j], *asnSignatureLen - (i + 2 + j) );
asnSignature[1] -= j;
asnSignature[i+1] -= j;
*asnSignatureLen -= j;
i += 2 + asnSignature[i+1];
}
else
{
i += 2 + asnSignature[i+1];
// printf("asnSignature[i+2] = 0x%02X\r\n", asnSignature[i+2]);
// printf("asnSignature[i+3] = 0x%02X\r\n", asnSignature[i+3]);
}
}
else
{
i += 2 + asnSignature[i+1];
// printf("asnSignature[i+1] = 0x%02X\r\n", asnSignature[i+1]);
}
}
else
{
#ifdef AX_HC_ASN_LOG_VERBOSE
printf("Debug (%s - line:%d): Failed to parse ASN_ECDSA_SIGNATURE.\r\n", __FILE__, __LINE__);
#endif
*asnSignatureLen = 0;
return ERR_WRONG_RESPONSE;
}
}
}
else
{
#ifdef AX_HC_ASN_LOG_VERBOSE
printf("Debug (%s - line:%d): Failed to parse ASN_ECDSA_SIGNATURE.\r\n", __FILE__, __LINE__); // DEBUG
#endif
*asnSignatureLen = 0;
return ERR_WRONG_RESPONSE;
}
}
else
{
#ifdef AX_HC_ASN_LOG_VERBOSE
printf("Debug (%s - line:%d): Failed to parse ASN_ECDSA_SIGNATURE.\r\n", __FILE__, __LINE__); // DEBUG
#endif
*asnSignatureLen = 0;
return ERR_WRONG_RESPONSE;
}
rv = SW_OK;
exit:
return rv;
}