blob: 9d76b1755c05422fee2cd06eb813c9e85542d6cb [file] [log] [blame]
/*
*
* Copyright 2018-2020 NXP
* SPDX-License-Identifier: Apache-2.0
*/
#include <fsl_sss_util_asn1_der.h>
#include <nxEnsure.h>
#include <nxLog_sss.h>
#include <stdlib.h>
#include <string.h>
#if SSS_HAVE_APPLET_SE05X_IOT
#include <fsl_sss_se05x_apis.h>
#endif
#if SSS_HAVE_MBEDTLS
#include <fsl_sss_mbedtls_apis.h>
#endif
#if SSS_HAVE_OPENSSL
#include <fsl_sss_openssl_apis.h>
#include <openssl/pem.h>
#include <openssl/pkcs12.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#endif
#define IS_VALID_TAG(x) \
(x == ASN_TAG_SEQUENCE || x == ASN_TAG_OBJ_IDF || x == ASN_TAG_BITSTRING || x == ASN_TAG_INT || \
x == ASN_TAG_OCTETSTRING || x == ASN_TAG_CNT_SPECIFIC || x == ASN_TAG_CRL_EXTENSIONS) ? \
1 : \
0
#define IS_VALID_RFC8410_TAG(x) \
(x == ASN_TAG_SEQUENCE || x == ASN_TAG_OBJ_IDF || x == ASN_TAG_BITSTRING || x == ASN_TAG_INT || \
x == ASN_TAG_OCTETSTRING || x == ASN_TAG_CNT_SPECIFIC || x == ASN_TAG_CRL_EXTENSIONS || \
x == (ASN_TAG_CNT_SPECIFIC_PRIMITIVE | 0x01)) ? \
1 : \
0
/* clang-format off */
/* RSA Header */
const uint8_t grsa512PubHeader[] = {
0x30, 0x5C, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, \
0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, \
0x00, 0x03, 0x4B, 0x00, 0x30, 0x48, 0x02 };
const uint8_t grsa1kPubHeader[] = {
0x30, 0x81, 0x9F, 0x30, 0x0D, 0x06, 0x09, 0x2A, \
0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, \
0x05, 0x00, 0x03, 0x81, 0x8D, 0x00, 0x30, 0x81, \
0x89, 0x02 };
const uint8_t grsa1152PubHeader[] = {
0x30, 0x81, 0xAF, 0x30, 0x0D, 0x06, 0x09, 0x2A, \
0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, \
0x05, 0x00, 0x03, 0x81, 0x9D, 0x00, 0x30, 0x81, \
0x99, 0x02 };
const uint8_t grsa2kPubHeader[] = {
0x30, 0x82, 0x01, 0x22, 0x30, 0x0D, 0x06, 0x09, \
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, \
0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0F, 0x00, \
0x30, 0x82, 0x01, 0x0A, 0x02 };
const uint8_t grsa3kPubHeader[] = {
0x30, 0x82, 0x01, 0xA2, 0x30, 0x0D, 0x06, 0x09, \
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, \
0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x8F, 0x00, \
0x30, 0x82, 0x01, 0x8A, 0x02 };
const uint8_t grsa4kPubHeader[] = {
0x30, 0x82, 0x02, 0x22, 0x30, 0x0D, 0x06, 0x09, \
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, \
0x01, 0x05, 0x00, 0x03, 0x82, 0x02, 0x0F, 0x00, \
0x30, 0x82, 0x02, 0x0A, 0x02 };
/* ECC Header */
const uint8_t gecc_der_header_nist192[] = {
0x30, 0x49, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86,
0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A,
0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x01, 0x03,
0x32, 0x00, };
const uint8_t gecc_der_header_nist224[] = {
0x30, 0x4E, 0x30, 0x10, 0x06, 0x07, 0x2A, 0x86,
0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x05, 0x2B,
0x81, 0x04, 0x00, 0x21, 0x03, 0x3A, 0x00, };
const uint8_t gecc_der_header_nist256[] = {
0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86,
0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A,
0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03,
0x42, 0x00 };
const uint8_t gecc_der_header_nist384[] = {
0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2A, 0x86,
0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x05, 0x2B,
0x81, 0x04, 0x00, 0x22, 0x03, 0x62, 0x00, };
const uint8_t gecc_der_header_nist521[] = {
0x30, 0x81, 0x9B, 0x30, 0x10, 0x06, 0x07, 0x2A,
0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x05,
0x2B, 0x81, 0x04, 0x00, 0x23, 0x03, 0x81, 0x86,
0x00, };
const uint8_t gecc_der_header_160k[] = {
0x30, 0x3e, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86,
0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b,
0x81, 0x04, 0x00, 0x09, 0x03, 0x2a, 0x00, };
const uint8_t gecc_der_header_192k[] = {
0x30, 0x46, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86,
0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b,
0x81, 0x04, 0x00, 0x1f, 0x03, 0x32, 0x00, };
const uint8_t gecc_der_header_224k[] = {
0x30, 0x4e, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86,
0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b,
0x81, 0x04, 0x00, 0x20, 0x03, 0x3a, 0x00, };
const uint8_t gecc_der_header_256k[] = {
0x30, 0x56, 0x30, 0x10, 0x06, 0x07, 0x2A, 0x86,
0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x05, 0x2B,
0x81, 0x04, 0x00, 0x0A, 0x03, 0x42, 0x00 };
const uint8_t gecc_der_header_bp160[] = {
0x30, 0x42, 0x30, 0x14, 0x06, 0x07, 0x2a, 0x86,
0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x09, 0x2b,
0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x01,
0x03, 0x2a, 0x00, };
const uint8_t gecc_der_header_bp192[] = {
0x30, 0x4a, 0x30, 0x14, 0x06, 0x07, 0x2a, 0x86,
0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x09, 0x2b,
0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x03,
0x03, 0x32, 0x00, };
const uint8_t gecc_der_header_bp224[] = {
0x30, 0x52, 0x30, 0x14, 0x06, 0x07, 0x2a, 0x86,
0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x09, 0x2b,
0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x05,
0x03, 0x3a, 0x00, };
const uint8_t gecc_der_header_bp256[] = {
0x30, 0x5a, 0x30, 0x14, 0x06, 0x07, 0x2a, 0x86,
0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x09, 0x2b,
0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07,
0x03, 0x42, 0x00, };
const uint8_t gecc_der_header_bp320[] = {
0x30, 0x6a, 0x30, 0x14, 0x06, 0x07, 0x2a, 0x86,
0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x09, 0x2b,
0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x09,
0x03, 0x52, 0x00,
};
const uint8_t gecc_der_header_bp384[] = {
0x30, 0x7A, 0x30, 0x14, 0x06, 0x07, 0x2A, 0x86, \
0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x09, 0x2B, \
0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0B, \
0x03, 0x62, 0x00, };
const uint8_t gecc_der_header_bp512[] = {
0x30, 0x81, 0x9B, 0x30, 0x14, 0x06, 0x07, 0x2A,
0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x09,
0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01,
0x0D, 0x03, 0x81, 0x82, 0x00, };
const uint8_t gecc_der_header_mont_dh_448[] = {
0x30, 0x42, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65,
0x6f, 0x03, 0x39, 0x00, };
const uint8_t gecc_der_header_mont_dh_25519[] = {
0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65,
0x6e, 0x03, 0x21, 0x00, };
const uint8_t gecc_der_header_twisted_ed_25519[] = {
0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65,
0x70, 0x03, 0x21, 0x00, };
/* clang-format on */
size_t const der_ecc_nistp192_header_len = sizeof(gecc_der_header_nist192);
size_t const der_ecc_nistp224_header_len = sizeof(gecc_der_header_nist224);
size_t const der_ecc_nistp256_header_len = sizeof(gecc_der_header_nist256);
size_t const der_ecc_nistp384_header_len = sizeof(gecc_der_header_nist384);
size_t const der_ecc_nistp521_header_len = sizeof(gecc_der_header_nist521);
size_t const der_ecc_160k_header_len = sizeof(gecc_der_header_160k);
size_t const der_ecc_192k_header_len = sizeof(gecc_der_header_192k);
size_t const der_ecc_224k_header_len = sizeof(gecc_der_header_224k);
size_t const der_ecc_256k_header_len = sizeof(gecc_der_header_256k);
size_t const der_ecc_bp160_header_len = sizeof(gecc_der_header_bp160);
size_t const der_ecc_bp192_header_len = sizeof(gecc_der_header_bp192);
size_t const der_ecc_bp224_header_len = sizeof(gecc_der_header_bp224);
size_t const der_ecc_bp256_header_len = sizeof(gecc_der_header_bp256);
size_t const der_ecc_bp320_header_len = sizeof(gecc_der_header_bp320);
size_t const der_ecc_bp384_header_len = sizeof(gecc_der_header_bp384);
size_t const der_ecc_bp512_header_len = sizeof(gecc_der_header_bp512);
size_t const der_ecc_mont_dh_448_header_len = sizeof(gecc_der_header_mont_dh_448);
size_t const der_ecc_mont_dh_25519_header_len = sizeof(gecc_der_header_mont_dh_25519);
size_t const der_ecc_twisted_ed_25519_header_len = sizeof(gecc_der_header_twisted_ed_25519);
static int check_tag(int tag);
/* ************************************************************************** */
/* Functions : ASN.1 Functions */
/* ************************************************************************** */
sss_status_t sss_util_asn1_rsa_parse_private(const uint8_t *key,
size_t keylen,
sss_cipher_type_t cipher_type,
uint8_t **modulus,
size_t *modlen,
uint8_t **pubExp,
size_t *pubExplen,
uint8_t **priExp,
size_t *priExplen,
uint8_t **prime1,
size_t *prime1len,
uint8_t **prime2,
size_t *prime2len,
uint8_t **exponent1,
size_t *exponent1len,
uint8_t **exponent2,
size_t *exponent2len,
uint8_t **coefficient,
size_t *coefficientlen)
{
uint8_t *pBuf = (uint8_t *)key;
size_t taglen = 0;
size_t bufIndex = 0;
uint8_t tag;
int ret;
sss_status_t status = kStatus_SSS_Fail;
/* Parse ASN.1 Sequence */
/* Example:
0x30, 0x82, 0x02, 0x77, ;SEQUENCE
0x02, 0x01, ;INTEGER
0x00, ;Algorithm version
0x30, 0x0D, ;Sequence
0x06, 0x09, ;ObjectIdentifier
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01,
0x01,
0x05, 0x00, ;Null
0x04, 0x82, 0x02, 0x61, ;OctetString
0x30, 0x82, 0x02, 0x5D, ;Sequence
0x02, 0x01, 0x00, ;Integer
0x02, 0x81, 0x81, ;Integer - Modulus
*/
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex);
if (ret != 0)
goto exit;
if (taglen != (keylen - bufIndex)) {
LOG_E("Invlaid Key");
goto exit;
}
/* No need of algorithem Version */
ENSURE_OR_GO_EXIT(bufIndex < keylen);
if (pBuf[bufIndex] == ASN_TAG_INT) {
bufIndex += 3;
}
ENSURE_OR_GO_EXIT(bufIndex < keylen);
tag = pBuf[bufIndex];
while (tag != ASN_TAG_INT) {
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex); /* Private Key Header Nested TLV */
if (ret != 0)
goto exit;
if (tag == ASN_TAG_SEQUENCE && pBuf[bufIndex] != ASN_TAG_INT)
bufIndex += taglen;
ENSURE_OR_GO_EXIT(bufIndex < keylen);
tag = pBuf[bufIndex];
}
ENSURE_OR_GO_EXIT(bufIndex < keylen);
if (pBuf[bufIndex] == ASN_TAG_INT && pBuf[bufIndex + 1] == 1) {
bufIndex += 3;
}
/* Get the Modulus*/
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex);
if (ret != 0)
goto exit;
if (modlen != NULL) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
if (pBuf[bufIndex] == 0x00) {
if (taglen) {
*modlen = taglen - 1; /*Exclude Starting Null*/
bufIndex++;
}
else {
goto exit;
}
}
else
*modlen = taglen;
*modulus = SSS_MALLOC(*modlen);
if ((*modulus != NULL) && ((*modlen) > 0)) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
memcpy(*modulus, pBuf + bufIndex, *modlen);
bufIndex += *modlen;
}
else {
LOG_E("Either malloc failed or improper length");
goto exit;
}
}
else
bufIndex += taglen;
/* Get Public Exponent */
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex);
if (ret != 0)
goto exit;
if (pubExplen != NULL) {
*pubExplen = taglen;
*pubExp = SSS_MALLOC(*pubExplen);
if ((*pubExp != NULL) && ((*pubExplen) > 0)) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
memcpy(*pubExp, pBuf + bufIndex, *pubExplen);
bufIndex += *pubExplen;
}
else {
LOG_E("Either malloc failed or improper length");
goto exit;
}
}
else
bufIndex += taglen;
/* Get Private Exponent*/
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex);
if (ret != 0)
goto exit;
if (priExplen != NULL) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
if (pBuf[bufIndex] == 0x00) {
if (taglen) {
*priExplen = taglen - 1; /*Exclude Starting Null*/
bufIndex++;
}
else {
goto exit;
}
}
else
*priExplen = taglen;
*priExp = SSS_MALLOC(*priExplen);
if ((*priExp != NULL) && ((*priExplen) > 0)) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
memcpy(*priExp, pBuf + bufIndex, *priExplen);
bufIndex += *priExplen;
}
else {
LOG_E("Either malloc failed or improper length");
goto exit;
}
}
else
bufIndex += taglen;
/* Get First prime (p)*/
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex);
if (ret != 0)
goto exit;
if (prime1len != NULL) {
if (pBuf[bufIndex] == 0x00) {
if (taglen) {
*prime1len = taglen - 1; /*Exclude Starting Null*/
bufIndex++;
}
else {
goto exit;
}
}
else
*prime1len = taglen;
*prime1 = SSS_MALLOC(*prime1len);
if ((*prime1 != NULL) && ((*prime1len) > 0)) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
memcpy(*prime1, pBuf + bufIndex, *prime1len);
bufIndex += *prime1len;
}
else {
LOG_E("Either malloc failed or improper length");
goto exit;
}
}
else
bufIndex += taglen;
/* Get Second prime (q)*/
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex);
if (ret != 0)
goto exit;
if (prime2len != NULL) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
if (pBuf[bufIndex] == 0x00) {
if (taglen) {
*prime2len = taglen - 1; /*Exclude Starting Null*/
bufIndex++;
}
else {
goto exit;
}
}
else
*prime2len = taglen;
*prime2 = SSS_MALLOC(*prime2len);
if (*prime2 == NULL) {
LOG_E("malloc failed");
goto exit;
}
if (*prime2len > 0) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
memcpy(*prime2, pBuf + bufIndex, *prime2len);
bufIndex += *prime2len;
}
else {
LOG_E("Either malloc failed or improper length");
goto exit;
}
}
else
bufIndex += taglen;
/* Get First exponent (dP)*/
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex);
if (ret != 0)
goto exit;
if (exponent1len != NULL) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
if (pBuf[bufIndex] == 0x00) {
if (taglen) {
*exponent1len = taglen - 1; /*Exclude Starting Null*/
bufIndex++;
}
else {
goto exit;
}
}
else
*exponent1len = taglen;
*exponent1 = SSS_MALLOC(*exponent1len);
if ((*exponent1 != NULL) && ((*exponent1len) > 0)) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
memcpy(*exponent1, pBuf + bufIndex, *exponent1len);
bufIndex += *exponent1len;
}
else {
LOG_E("Either malloc failed or improper length");
goto exit;
}
}
else
bufIndex += taglen;
/* Get Second exponent (dQ)*/
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex);
if (ret != 0)
goto exit;
if (exponent2len != NULL) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
if (pBuf[bufIndex] == 0x00) {
if (taglen) {
*exponent2len = taglen - 1; /*Exclude Starting Null*/
bufIndex++;
}
else {
goto exit;
}
}
else
*exponent2len = taglen;
*exponent2 = SSS_MALLOC(*exponent2len);
if (*exponent2 == NULL) {
LOG_E("malloc failed");
goto exit;
}
if (*exponent2len > 0) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
memcpy(*exponent2, pBuf + bufIndex, *exponent2len);
bufIndex += *exponent2len;
}
else {
LOG_E("exponent2len improper");
goto exit;
}
}
else
bufIndex += taglen;
/* Get Coefficient (qinv)*/
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex);
if (ret != 0)
goto exit;
if (coefficientlen != NULL) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
if (pBuf[bufIndex] == 0x00) {
if (taglen) {
*coefficientlen = taglen - 1; /*Exclude Starting Null*/
bufIndex++;
}
else {
goto exit;
}
}
else
*coefficientlen = taglen;
*coefficient = SSS_MALLOC(*coefficientlen);
if ((*coefficient != NULL) && ((*coefficientlen) > 0)) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
memcpy(*coefficient, pBuf + bufIndex, *coefficientlen);
bufIndex += *coefficientlen;
}
else {
LOG_E("Either malloc failed or improper length");
goto exit;
}
}
else
bufIndex += taglen;
status = kStatus_SSS_Success;
exit:
return status;
}
sss_status_t sss_util_asn1_rsa_parse_private_allow_invalid_key(const uint8_t *key,
size_t keylen,
sss_cipher_type_t cipher_type,
uint8_t **modulus,
size_t *modlen,
uint8_t **pubExp,
size_t *pubExplen,
uint8_t **priExp,
size_t *priExplen,
uint8_t **prime1,
size_t *prime1len,
uint8_t **prime2,
size_t *prime2len,
uint8_t **exponent1,
size_t *exponent1len,
uint8_t **exponent2,
size_t *exponent2len,
uint8_t **coefficient,
size_t *coefficientlen)
{
uint8_t *pBuf = (uint8_t *)key;
size_t taglen = 0;
size_t bufIndex = 0;
uint8_t tag;
int ret;
sss_status_t status = kStatus_SSS_Fail;
/* Parse ASN.1 Sequence */
/* Example:
0x30, 0x82, 0x02, 0x77, ;SEQUENCE
0x02, 0x01, ;INTEGER
0x00, ;Algorithm version
0x30, 0x0D, ;Sequence
0x06, 0x09, ;ObjectIdentifier
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01,
0x01,
0x05, 0x00, ;Null
0x04, 0x82, 0x02, 0x61, ;OctetString
0x30, 0x82, 0x02, 0x5D, ;Sequence
0x02, 0x01, 0x00, ;Integer
0x02, 0x81, 0x81, ;Integer - Modulus
*/
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex);
ENSURE_OR_GO_EXIT(0 == ret);
// if (taglen != (keylen - bufIndex)) {
// LOG_E("Invlaid Key");
// goto exit;
// }
/* No need of algorithem Version */
ENSURE_OR_GO_EXIT(bufIndex < keylen);
if (pBuf[bufIndex] == ASN_TAG_INT) {
bufIndex += 3;
}
ENSURE_OR_GO_EXIT(bufIndex < keylen);
tag = pBuf[bufIndex];
while (tag != ASN_TAG_INT) {
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex); /* Private Key Head*/
ENSURE_OR_GO_EXIT(0 == ret);
if (tag == ASN_TAG_SEQUENCE && pBuf[bufIndex] != ASN_TAG_INT)
bufIndex += taglen;
ENSURE_OR_GO_EXIT(bufIndex < keylen);
tag = pBuf[bufIndex];
}
ENSURE_OR_GO_EXIT(bufIndex < keylen);
if (pBuf[bufIndex] == ASN_TAG_INT && pBuf[bufIndex + 1] == 1) {
bufIndex += 3;
}
/* Get the Modulus*/
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex);
ENSURE_OR_GO_EXIT(0 == ret);
if (modlen != NULL) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
if (pBuf[bufIndex] == 0x00) {
if (taglen) {
*modlen = taglen - 1; /*Exclude Starting Null*/
bufIndex++;
}
else {
goto exit;
}
}
else
*modlen = taglen;
*modulus = SSS_MALLOC(*modlen);
if ((*modulus != NULL) && ((*modlen) > 0)) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
memcpy(*modulus, pBuf + bufIndex, *modlen);
bufIndex += *modlen;
}
else {
LOG_E("Either malloc failed or improper length");
goto exit;
}
}
else
bufIndex += taglen;
/* Get Public Exponent */
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex);
ENSURE_OR_GO_EXIT(0 == ret);
if (pubExplen != NULL) {
*pubExplen = taglen;
*pubExp = SSS_MALLOC(*pubExplen);
ENSURE_OR_GO_EXIT(bufIndex < keylen);
if ((*pubExp != NULL) && ((*pubExplen) > 0)) {
memcpy(*pubExp, pBuf + bufIndex, *pubExplen);
bufIndex += *pubExplen;
}
else {
LOG_E("Either malloc failed or improper length");
goto exit;
}
}
else
bufIndex += taglen;
/* Get Private Exponent*/
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex);
ENSURE_OR_GO_EXIT(0 == ret);
if (priExplen != NULL) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
if (pBuf[bufIndex] == 0x00) {
if (taglen) {
*priExplen = taglen - 1; /*Exclude Starting Null*/
bufIndex++;
}
else {
goto exit;
}
}
else
*priExplen = taglen;
*priExp = SSS_MALLOC(*priExplen);
if ((*priExp != NULL) && ((*priExplen) > 0)) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
memcpy(*priExp, pBuf + bufIndex, *priExplen);
bufIndex += *priExplen;
}
else {
LOG_E("Either malloc failed or improper length");
goto exit;
}
}
else
bufIndex += taglen;
/* Get First prime (p)*/
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex);
ENSURE_OR_GO_EXIT(0 == ret);
if (prime1len != NULL) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
if (pBuf[bufIndex] == 0x00) {
if (taglen) {
*prime1len = taglen - 1; /*Exclude Starting Null*/
bufIndex++;
}
else {
goto exit;
}
}
else
*prime1len = taglen;
*prime1 = SSS_MALLOC(*prime1len);
if ((*prime1 != NULL) && ((*prime1len) > 0)) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
memcpy(*prime1, pBuf + bufIndex, *prime1len);
bufIndex += *prime1len;
}
else {
LOG_E("Either malloc failed or improper length");
goto exit;
}
}
else
bufIndex += taglen;
/* Get Second prime (q)*/
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex);
ENSURE_OR_GO_EXIT(0 == ret);
if (prime2len != NULL) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
if (pBuf[bufIndex] == 0x00) {
if (taglen) {
*prime2len = taglen - 1; /*Exclude Starting Null*/
bufIndex++;
}
else {
goto exit;
}
}
else
*prime2len = taglen;
*prime2 = SSS_MALLOC(*prime2len);
if (*prime2 == NULL) {
LOG_E("malloc failed");
goto exit;
}
if (*prime2len > 0) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
memcpy(*prime2, pBuf + bufIndex, *prime2len);
bufIndex += *prime2len;
}
else {
LOG_E("Either malloc failed or improper length");
goto exit;
}
}
else
bufIndex += taglen;
/* Get First exponent (dP)*/
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex);
ENSURE_OR_GO_EXIT(0 == ret);
if (exponent1len != NULL) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
if (pBuf[bufIndex] == 0x00) {
if (taglen) {
*exponent1len = taglen - 1; /*Exclude Starting Null*/
bufIndex++;
}
else {
goto exit;
}
}
else
*exponent1len = taglen;
*exponent1 = SSS_MALLOC(*exponent1len);
if ((*exponent1 != NULL) && ((*exponent1len) > 0)) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
memcpy(*exponent1, pBuf + bufIndex, *exponent1len);
bufIndex += *exponent1len;
}
else {
LOG_E("Either malloc failed or improper length");
goto exit;
}
}
else
bufIndex += taglen;
/* Get Second exponent (dQ)*/
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex);
ENSURE_OR_GO_EXIT(0 == ret);
if (exponent2len != NULL) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
if (pBuf[bufIndex] == 0x00) {
if (taglen) {
*exponent2len = taglen - 1; /*Exclude Starting Null*/
bufIndex++;
}
else {
goto exit;
}
}
else
*exponent2len = taglen;
*exponent2 = SSS_MALLOC(*exponent2len);
if (*exponent2 == NULL) {
LOG_E("malloc failed");
goto exit;
}
if (*exponent2len > 0) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
memcpy(*exponent2, pBuf + bufIndex, *exponent2len);
bufIndex += *exponent2len;
}
else {
LOG_E("exponent2len improper");
goto exit;
}
}
else
bufIndex += taglen;
/* Get Coefficient (qinv)*/
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex);
ENSURE_OR_GO_EXIT(0 == ret);
if (coefficientlen != NULL) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
if (pBuf[bufIndex] == 0x00) {
if (taglen) {
*coefficientlen = taglen - 1; /*Exclude Starting Null*/
bufIndex++;
}
else {
goto exit;
}
}
else
*coefficientlen = taglen;
*coefficient = SSS_MALLOC(*coefficientlen);
if ((*coefficient != NULL) && ((*coefficientlen) > 0)) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
memcpy(*coefficient, pBuf + bufIndex, *coefficientlen);
bufIndex += *coefficientlen;
}
else {
LOG_E("Either malloc failed or improper length");
goto exit;
}
}
else
bufIndex += taglen;
status = kStatus_SSS_Success;
exit:
return status;
}
sss_status_t sss_util_asn1_rsa_parse_public_nomalloc(
const uint8_t *key, size_t keylen, uint8_t *modulus, size_t *modlen, uint8_t *pubExp, size_t *pubExplen)
{
uint8_t *pBuf = (uint8_t *)key;
size_t taglen = 0;
size_t bufIndex = 0;
int ret;
sss_status_t status = kStatus_SSS_Fail;
size_t temp_modlen = 0, temp_pubExplen = 0;
if ((key == NULL) || (modulus == NULL) || (modlen == NULL) || (pubExp == NULL) || (pubExplen == NULL)) {
goto exit;
}
//int tag = (key[1] == 0x82) ? 4 : 3;
/* Parse Header Information
Public Key contains 3 Sequences as header */
ENSURE_OR_GO_EXIT(bufIndex < keylen);
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex); /* ASN.1 Sequence */
if (ret != 0)
goto exit;
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex); /* Public Header Nested TLV */
if (ret != 0)
goto exit;
bufIndex += taglen;
/* Bit-String + NULL Byte */
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex);
if (ret != 0)
goto exit;
bufIndex++;
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex); /* Sequence of interger*/
if (ret != 0)
goto exit;
/* Get the Modulus*/
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex);
if (ret != 0)
goto exit;
ENSURE_OR_GO_EXIT(bufIndex < keylen);
if (pBuf[bufIndex] == 0x00) {
if (taglen) {
temp_modlen = taglen - 1; /*Exclude Starting Null*/
bufIndex++;
}
else {
goto exit;
}
}
else
temp_modlen = taglen;
if (*modlen < temp_modlen) {
LOG_E("modulus overflow");
goto exit;
}
*modlen = temp_modlen;
if ((*modlen) > 0) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
memcpy(modulus, pBuf + bufIndex, *modlen);
bufIndex += *modlen;
}
else {
LOG_E("Either malloc failed or improper length");
goto exit;
}
/* Get Public Exponent */
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex);
temp_pubExplen = taglen;
if (*pubExplen < temp_pubExplen) {
LOG_E("pubExp overflow");
goto exit;
}
*pubExplen = temp_pubExplen;
if (*pubExplen > 0) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
memcpy(pubExp, pBuf + bufIndex, *pubExplen);
bufIndex += *pubExplen;
status = kStatus_SSS_Success;
}
exit:
return status;
}
sss_status_t sss_util_asn1_rsa_parse_public_nomalloc_complete_modulus(
const uint8_t *key, size_t keylen, uint8_t *modulus, size_t *modlen, uint8_t *pubExp, size_t *pubExplen)
{
uint8_t *pBuf = (uint8_t *)key;
size_t taglen = 0;
size_t bufIndex = 0;
int ret;
sss_status_t status = kStatus_SSS_Fail;
size_t temp_modlen = 0, temp_pubExplen = 0;
if ((key == NULL) || (modulus == NULL) || (modlen == NULL) || (pubExp == NULL) || (pubExplen == NULL)) {
goto exit;
}
//int tag = (key[1] == 0x82) ? 4 : 3;
/* Parse Header Information
Public Key contains 3 Sequences as header */
ENSURE_OR_GO_EXIT(bufIndex < keylen);
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex); /* ASN.1 Sequence */
if (ret != 0)
goto exit;
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex); /* Public Header Nested TLV */
if (ret != 0)
goto exit;
bufIndex += taglen;
/* Bit-String + NULL Byte */
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex);
if (ret != 0)
goto exit;
bufIndex++;
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex); /* Sequence of interger*/
if (ret != 0)
goto exit;
/* Get the Modulus*/
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex);
if (ret != 0)
goto exit;
ENSURE_OR_GO_EXIT(bufIndex < keylen);
temp_modlen = taglen;
if (*modlen < temp_modlen) {
LOG_E("modulus overflow");
goto exit;
}
*modlen = temp_modlen;
if ((*modlen) > 0) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
memcpy(modulus, pBuf + bufIndex, *modlen);
bufIndex += *modlen;
}
else {
LOG_E("Either malloc failed or improper length");
goto exit;
}
/* Get Public Exponent */
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex);
temp_pubExplen = taglen;
if (*pubExplen < temp_pubExplen) {
LOG_E("pubExp overflow");
goto exit;
}
*pubExplen = temp_pubExplen;
if (*pubExplen > 0) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
memcpy(pubExp, pBuf + bufIndex, *pubExplen);
bufIndex += *pubExplen;
status = kStatus_SSS_Success;
}
exit:
return status;
}
sss_status_t sss_util_asn1_rsa_parse_public(
const uint8_t *key, size_t keylen, uint8_t **modulus, size_t *modlen, uint8_t **pubExp, size_t *pubExplen)
{
uint8_t *pBuf = (uint8_t *)key;
size_t taglen = 0;
size_t bufIndex = 0;
int ret;
sss_status_t status = kStatus_SSS_Fail;
//int tag = (key[1] == 0x82) ? 4 : 3;
/* Parse Header Information
Public Key contains 3 Sequences as header */
ENSURE_OR_GO_EXIT(bufIndex < keylen);
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex); /* ASN.1 Sequence */
if (ret != 0)
goto exit;
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex); /* Public Header Nested TLV */
if (ret != 0)
goto exit;
bufIndex += taglen;
/* Bit-String + NULL Byte */
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex);
if (ret != 0)
goto exit;
bufIndex++;
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex); /* Sequence of interger*/
if (ret != 0)
goto exit;
/* Get the Modulus*/
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex);
if (ret != 0)
goto exit;
ENSURE_OR_GO_EXIT(bufIndex < keylen);
if (pBuf[bufIndex] == 0x00) {
if (taglen) {
*modlen = taglen - 1; /*Exclude Starting Null*/
bufIndex++;
}
else {
goto exit;
}
}
else
*modlen = taglen;
*modulus = SSS_MALLOC(*modlen);
if ((*modulus != NULL) && ((*modlen) > 0)) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
memcpy(*modulus, pBuf + bufIndex, *modlen);
bufIndex += *modlen;
}
else {
LOG_E("Either malloc failed or improper length");
goto exit;
}
/* Get Public Exponent */
ret = asn_1_parse_tlv(pBuf, &taglen, &bufIndex);
*pubExplen = taglen;
*pubExp = SSS_MALLOC(*pubExplen);
if (*pubExp == NULL) {
LOG_E("malloc failed");
goto exit;
}
if (*pubExplen > 0) {
ENSURE_OR_GO_EXIT(bufIndex < keylen);
memcpy(*pubExp, pBuf + bufIndex, *pubExplen);
bufIndex += *pubExplen;
status = kStatus_SSS_Success;
}
exit:
return status;
}
sss_status_t sss_util_asn1_rsa_get_public(
uint8_t *key, size_t *keylen, uint8_t *modulus, size_t modlen, uint8_t *pubExp, size_t pubExplen)
{
sss_status_t status = kStatus_SSS_Fail;
size_t pbkeylen = modlen + pubExplen + sizeof(grsa1kPubHeader) + 3 + 3;
size_t index = 0;
size_t intModLEn = modlen + 1; // RSA Key has null byte before moduls start
if (*keylen < pbkeylen) {
LOG_E("Buffer not sufficient");
goto exit;
}
/* Copy the Public Header According to key bit len*/
if (modlen == 0x40) {
memcpy(key, grsa512PubHeader, sizeof(grsa512PubHeader));
index += sizeof(grsa512PubHeader);
}
else if (modlen == 0x80) {
memcpy(key, grsa1kPubHeader, sizeof(grsa1kPubHeader));
index += sizeof(grsa1kPubHeader);
}
else if (modlen == 0x90) {
memcpy(key, grsa1152PubHeader, sizeof(grsa1152PubHeader));
index += sizeof(grsa1152PubHeader);
}
else if (modlen == 0x100) {
memcpy(key, grsa2kPubHeader, sizeof(grsa2kPubHeader));
index += sizeof(grsa2kPubHeader);
}
else if (modlen == 0x180) {
memcpy(key, grsa3kPubHeader, sizeof(grsa3kPubHeader));
index += sizeof(grsa3kPubHeader);
}
else if (modlen == 0x200) {
memcpy(key, grsa4kPubHeader, sizeof(grsa4kPubHeader));
index += sizeof(grsa4kPubHeader);
}
if (intModLEn < 0x7f)
key[index++] = (uint8_t)intModLEn;
else if (intModLEn < 0xFF) {
key[index++] = 0x81;
key[index++] = (uint8_t)intModLEn;
}
else {
key[index++] = 0x82;
key[index++] = (uint8_t)(intModLEn >> 8);
key[index++] = (uint8_t)intModLEn & 0xFF;
}
key[index++] = 0x00; // Null byte
memcpy(key + index, modulus, modlen);
index += modlen;
/*Copy the public Exponent*/
key[index++] = 0x02; // tag
key[index++] = (uint8_t)pubExplen; // length
memcpy(key + index, pubExp, pubExplen); // value
index += pubExplen;
*keylen = index;
status = kStatus_SSS_Success;
exit:
return status;
}
sss_status_t sss_util_asn1_ecdaa_get_signature(
uint8_t *signature, size_t *signatureLen, uint8_t *rawSignature, size_t rawSignatureLen)
{
sss_status_t status = kStatus_SSS_Fail;
size_t signAsn1Len, r_len, s_len;
r_len = rawSignatureLen / 2;
s_len = rawSignatureLen / 2;
// SEQUENCE (2B) + INTEGER(2B) + INTEGER(2B)
signAsn1Len = 6 + rawSignatureLen;
if (*signatureLen < signAsn1Len) {
LOG_E("ECDAA Signature buffer overflow");
goto exit;
}
/*
Example:
30 44 ; SEQUENCE (68 Bytes)
02 20 ; INTEGER (32 Bytes)
| 3d 46 28 7b 8c 6e 8c 8c 26 1c 1b 88 f2 73 b0 9a
| 32 a6 cf 28 09 fd 6e 30 d5 a7 9f 26 37 00 8f 54
02 20 ; INTEGER (32 Bytes)
| 4e 72 23 6e a3 90 a9 a1 7b cf 5f 7a 09 d6 3a b2
| 17 6c 92 bb 8e 36 c0 41 98 a2 7b 90 9b 6e 8f 13
*/
*signatureLen = signAsn1Len;
if (rawSignatureLen == 0x40) { // TPM_ECC_BN_P256
signature[0] = 0x30; //SEQUENCE
signature[1] = (uint8_t)(rawSignatureLen + 4); //INTEGER(2B) + INTEGER(2B)
signature[2] = 0x02; //INTEGER
signature[3] = (uint8_t)r_len; //lenght of r
memcpy(&signature[4], &rawSignature[0], r_len);
signature[3 + r_len + 1] = 0x02; //INTEGER
signature[3 + r_len + 2] = (uint8_t)s_len; //lenght of s
memcpy(&signature[3 + r_len + 3], &rawSignature[r_len], s_len);
}
else {
LOG_E("Invalid ECDAA Signature data");
goto exit;
}
status = kStatus_SSS_Success;
exit:
return status;
}
#if 0
static uint8_t *asn_1_parse_header(uint8_t *key, size_t keylen)
{
uint8_t *pBuf = key;
uint16_t taglen = 0;
sss_status_t status = kStatus_SSS_Fail;
int tag = (key[1] == 0x82) ? 4 : 3;
/* Parse Header Information*/
pBuf = asn_1_parse_tlv(pBuf, &taglen);
if (taglen != (keylen - tag))
{
LOG_E("Invlaid Key");
return status;
}
}
#endif
int asn_1_parse_tlv(uint8_t *pbuf, size_t *taglen, size_t *bufindex)
{
size_t Len;
uint8_t *buf = pbuf + *bufindex;
int tag;
tag = *buf++; /*Exclude The Tag*/
Len = *buf++;
int ret = 0;
if (check_tag(tag)) {
ret = 1;
goto exit;
}
if (Len <= 0x7FU) {
*taglen = Len;
*bufindex += 1 + 1;
goto exit;
}
else if (Len == 0x81) {
*taglen = *buf++;
*bufindex += 1 + 2;
goto exit;
}
else if (Len == 0x82) {
*taglen = *buf++;
*taglen = (*taglen << 8) | (*buf++);
*bufindex += 1 + 3;
goto exit;
}
ret = 1;
exit:
return ret;
}
static int check_tag(int tag)
{
int ret = 0;
switch (tag) {
case ASN_TAG_INT:
case ASN_TAG_SEQUENCE:
case ASN_TAG_BITSTRING:
case ASN_TAG_OBJ_IDF:
case ASN_TAG_OCTETSTRING:
break;
default:
LOG_E("Wrong Tag parsed -- %d \n", tag);
ret = 1;
break;
}
return ret;
}
#ifdef _MSC_VER
#pragma warning(disable : 4127)
#endif
sss_status_t sss_util_asn1_get_oid_from_header(uint8_t *input, size_t inLen, uint32_t *output, uint8_t *outLen)
{
size_t i = 0;
size_t taglen = 0;
int objectIdCnt = 0;
int tag = 0;
uint8_t outBufindex = 0;
sss_status_t status = kStatus_SSS_Fail;
for (;;) {
ENSURE_OR_GO_EXIT(i < inLen);
tag = input[i++];
if (tag == ASN_TAG_SEQUENCE || tag == ASN_TAG_OBJ_IDF) {
ENSURE_OR_GO_EXIT(i < inLen);
taglen = input[i++];
if (taglen == 0x81) {
taglen = input[i];
i = i + 1;
}
else if (taglen == 0x82) {
ENSURE_OR_GO_EXIT(i < (inLen - 1));
taglen = input[i] | input[i + 1] << 8;
i = i + 2;
}
if (taglen > inLen)
goto exit;
if (tag == ASN_TAG_OBJ_IDF)
objectIdCnt++;
if (objectIdCnt == 2) {
if (taglen <= 0)
goto exit;
ENSURE_OR_GO_EXIT(i < inLen);
ENSURE_OR_GO_EXIT(outBufindex < (*outLen));
output[outBufindex++] = input[i] / 40;
output[outBufindex++] = input[i++] % 40;
taglen--;
while (taglen--) {
uint32_t cnt = 0;
uint32_t temp = 0;
do {
ENSURE_OR_GO_EXIT(i < inLen);
temp = temp << (7 * cnt);
temp = temp | (input[i] & 0x7F);
cnt++;
} while (input[i++] > 0x7F);
taglen = taglen - (cnt - 1);
ENSURE_OR_GO_EXIT(outBufindex < (*outLen));
output[outBufindex++] = temp;
}
break;
}
else {
if (tag == 0x06) {
i = i + taglen;
if (i > inLen)
goto exit;
}
}
}
else {
goto exit;
}
}
*outLen = outBufindex;
status = kStatus_SSS_Success;
exit:
return status;
}
sss_status_t sss_util_asn1_get_oid_from_sssObj(sss_object_t *pkeyObject, uint32_t *output, uint8_t *outLen)
{
sss_status_t status = kStatus_SSS_Fail;
uint8_t pbKey[256] = {0};
size_t pbKeyBitLen = 0;
size_t pbKeyBytetLen = sizeof(pbKey);
status = sss_key_store_get_key(pkeyObject->keyStore, pkeyObject, pbKey, &pbKeyBytetLen, &pbKeyBitLen);
if (status != kStatus_SSS_Success) {
goto exit;
}
status = sss_util_asn1_get_oid_from_header(pbKey, pbKeyBytetLen, output, outLen);
if (status != kStatus_SSS_Success) {
goto exit;
}
status = kStatus_SSS_Success;
exit:
return status;
}
sss_status_t sss_util_pkcs8_asn1_get_ec_public_key_index(
const uint8_t *input, size_t inLen, uint16_t *outkeyIndex, size_t *publicKeyLen)
{
size_t i = 0;
size_t taglen = 0;
sss_status_t status = kStatus_SSS_Fail;
uint8_t value_index = 0;
for (;;) {
ENSURE_OR_GO_EXIT(i < inLen);
int tag = input[i++];
if (IS_VALID_TAG(tag)) {
ENSURE_OR_GO_EXIT(i < inLen);
taglen = input[i++];
if (taglen == 0x81) {
ENSURE_OR_GO_EXIT(i < inLen);
taglen = input[i];
i = i + 1;
}
else if (taglen == 0x82) {
ENSURE_OR_GO_EXIT(i < (inLen - 1));
taglen = input[i] | input[i + 1] << 8;
i = i + 2;
}
if (taglen > inLen)
goto exit;
value_index = (uint8_t)i;
if (tag == ASN_TAG_SEQUENCE) {
if (i + taglen != inLen) {
i = i + taglen;
}
continue;
}
if (tag == ASN_TAG_BITSTRING) {
*outkeyIndex = value_index;
*publicKeyLen = taglen;
ENSURE_OR_GO_EXIT(value_index < inLen);
if (input[value_index] == 0x00 || input[value_index] == 0x01) {
*outkeyIndex = *outkeyIndex + 1;
*publicKeyLen = *publicKeyLen - 1;
}
break;
}
}
else {
goto exit;
}
}
ENSURE_OR_GO_EXIT((*outkeyIndex) < inLen);
ENSURE_OR_GO_EXIT(((*outkeyIndex) + (*publicKeyLen)) <= inLen);
status = kStatus_SSS_Success;
exit:
return status;
}
sss_status_t sss_util_pkcs8_asn1_get_ec_pair_key_index(const uint8_t *input,
size_t inLen,
uint16_t *pubkeyIndex,
size_t *publicKeyLen,
uint16_t *prvkeyIndex,
size_t *privateKeyLen)
{
size_t i = 0;
size_t taglen = 0;
sss_status_t status = kStatus_SSS_Fail;
//uint8_t octate_string_start = 0;
for (;;) {
ENSURE_OR_GO_EXIT(i < inLen);
int tag = input[i++];
if (IS_VALID_TAG(tag)) {
ENSURE_OR_GO_EXIT(i < inLen);
taglen = input[i++];
if (taglen == 0x81) {
ENSURE_OR_GO_EXIT(i < inLen);
taglen = input[i];
i = i + 1;
}
else if (taglen == 0x82) {
ENSURE_OR_GO_EXIT(i < (inLen - 1));
taglen = input[i] | input[i + 1] << 8;
i = i + 2;
}
if (taglen > inLen)
goto exit;
if (tag == ASN_TAG_OCTETSTRING) {
if (i + taglen == inLen) {
continue;
}
else {
*prvkeyIndex = (uint16_t)i;
*privateKeyLen = taglen;
}
}
if (tag == ASN_TAG_BITSTRING) {
*pubkeyIndex = (uint16_t)i;
*publicKeyLen = taglen;
ENSURE_OR_GO_EXIT(i < inLen);
if (input[i] == 0x00 || input[i] == 0x01) {
*pubkeyIndex = *pubkeyIndex + 1;
*publicKeyLen = *publicKeyLen - 1;
}
break;
}
if (i + taglen == inLen) {
continue;
}
else {
i = i + taglen;
}
}
else {
goto exit;
}
}
ENSURE_OR_GO_EXIT((*pubkeyIndex) < inLen);
ENSURE_OR_GO_EXIT(((*pubkeyIndex) + (*publicKeyLen)) <= inLen);
ENSURE_OR_GO_EXIT((*prvkeyIndex) < inLen);
ENSURE_OR_GO_EXIT(((*prvkeyIndex) + (*privateKeyLen)) <= inLen);
status = kStatus_SSS_Success;
exit:
return status;
}
sss_status_t sss_util_rfc8410_asn1_get_ec_pair_key_index(const uint8_t *input,
size_t inLen,
uint16_t *pubkeyIndex,
size_t *publicKeyLen,
uint16_t *prvkeyIndex,
size_t *privateKeyLen)
{
size_t i = 0;
size_t taglen = 0;
sss_status_t status = kStatus_SSS_Fail;
//uint8_t octate_string_start = 0;
for (;;) {
ENSURE_OR_GO_EXIT(i < inLen);
int tag = input[i++];
if (IS_VALID_RFC8410_TAG(tag)) {
ENSURE_OR_GO_EXIT(i < inLen);
taglen = input[i++];
if (taglen == 0x81) {
ENSURE_OR_GO_EXIT(i < inLen);
taglen = input[i];
i = i + 1;
}
else if (taglen == 0x82) {
ENSURE_OR_GO_EXIT(i < (inLen - 1));
taglen = input[i] | input[i + 1] << 8;
i = i + 2;
}
if (taglen > inLen)
goto exit;
if (tag == ASN_TAG_OCTETSTRING) {
// With RFC8410, the private key is an Octet String packed inside an Octet String
// Following code will only work for Lengths upto 127 byte
ENSURE_OR_GO_EXIT(taglen >= 2);
ENSURE_OR_GO_EXIT(ASN_TAG_OCTETSTRING == input[i]);
ENSURE_OR_GO_EXIT(taglen - 2 == (size_t)(input[i + 1]));
i += 2;
taglen -= 2;
*prvkeyIndex = (uint16_t)i;
*privateKeyLen = taglen;
}
if (tag == (ASN_TAG_CNT_SPECIFIC_PRIMITIVE | 0x01)) {
*pubkeyIndex = (uint16_t)i;
*publicKeyLen = taglen;
ENSURE_OR_GO_EXIT(i < inLen);
if (input[i] == 0x00 || input[i] == 0x01) {
*pubkeyIndex = *pubkeyIndex + 1;
*publicKeyLen = *publicKeyLen - 1;
}
break;
}
if (i + taglen == inLen) {
continue;
}
else {
i = i + taglen;
}
}
else {
goto exit;
}
}
ENSURE_OR_GO_EXIT((*pubkeyIndex) < inLen);
ENSURE_OR_GO_EXIT(((*pubkeyIndex) + (*publicKeyLen)) <= inLen);
ENSURE_OR_GO_EXIT((*prvkeyIndex) < inLen);
ENSURE_OR_GO_EXIT(((*prvkeyIndex) + (*privateKeyLen)) <= inLen);
status = kStatus_SSS_Success;
exit:
return status;
}
sss_status_t sss_util_openssl_read_pkcs12(
const char *pkcs12_cert, const char *password, uint8_t *private_key, uint8_t *cert)
{
sss_status_t retval = kStatus_SSS_Success;
#if SSS_HAVE_OPENSSL
int status = 0;
FILE *pkcs12_cert_file;
PKCS12 *p12_cert;
X509 *x509_cert;
EVP_PKEY *p_key;
BIO *pem_key_bio = BIO_new(BIO_s_mem());
BIO *cert_bio = BIO_new(BIO_s_mem());
STACK_OF(X509) *additional_certs = NULL;
// Open PKCS12 certificate file
pkcs12_cert_file = fopen(pkcs12_cert, "rb");
if (pkcs12_cert_file == NULL) {
retval = kStatus_SSS_Fail;
goto exit;
}
p12_cert = d2i_PKCS12_fp(pkcs12_cert_file, NULL);
fclose(pkcs12_cert_file);
// Parse PKCS12 key and certificates to seperate pem and certificates
status = PKCS12_parse(p12_cert, password, &p_key, &x509_cert, &additional_certs);
if (!status) {
retval = kStatus_SSS_Fail;
goto exit;
}
PKCS12_free(p12_cert);
// Dump pem key to buffer
PEM_write_bio_PrivateKey(pem_key_bio, p_key, NULL, NULL, 0, NULL, NULL);
BIO_read(pem_key_bio, private_key, 10000);
// Dump certificate to buffer
PEM_write_bio_X509(cert_bio, x509_cert);
BIO_read(cert_bio, cert, 20000);
exit:
#endif
return retval;
}
sss_status_t sss_util_openssl_write_pkcs12(sss_session_t *session,
sss_key_store_t *ks,
sss_object_t *obj,
const char *pkcs12_cert,
const char *password,
const char *ref_key,
long ref_key_length,
const char *cert_bytes,
const char *cert_subject)
{
sss_status_t retval = kStatus_SSS_Success;
#if SSS_HAVE_OPENSSL
FILE *pkcs12_file;
X509 *x509_cert = X509_new();
EVP_PKEY *p_key = 0;
PKCS12 *p12;
BIO *pem_key_bio = BIO_new(BIO_s_mem());
// Parse Private key
BIO_write(pem_key_bio, ref_key, ref_key_length);
PEM_read_bio_PrivateKey(pem_key_bio, &p_key, NULL, NULL);
if (p_key == NULL) {
retval = kStatus_SSS_Fail;
goto exit;
}
//Generate certificate
retval = sss_util_openssl_generate_cert_pkcs12(session, ks, obj, x509_cert, cert_bytes, cert_subject);
if (retval != kStatus_SSS_Success || x509_cert == NULL) {
retval = kStatus_SSS_Fail;
goto exit;
}
// Generate PKCS12 key and certificate
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
p12 = PKCS12_create((char *)password,
#else
p12 = PKCS12_create(password,
#endif
NULL,
p_key,
x509_cert,
NULL,
0,
0,
PKCS12_DEFAULT_ITER,
1,
NID_key_usage);
if (p12 == NULL) {
retval = kStatus_SSS_Fail;
goto exit;
}
//write into file
pkcs12_file = fopen(pkcs12_cert, "wb");
if (i2d_PKCS12_fp(pkcs12_file, p12) != 1) {
retval = kStatus_SSS_Fail;
}
fclose(pkcs12_file);
exit:
#endif
return retval;
}
sss_status_t sss_util_openssl_generate_cert_pkcs12(sss_session_t *session,
sss_key_store_t *ks,
sss_object_t *obj,
void *certificate_in,
const char *cert_bytes,
const char *cert_subject)
{
sss_status_t status = kStatus_SSS_Fail;
#if SSS_HAVE_OPENSSL
X509 *certificate = (X509 *)certificate_in;
if (!X509_set_version(certificate, 2)) {
return status;
}
ASN1_INTEGER *serialNumber = ASN1_INTEGER_new();
if (!ASN1_INTEGER_set(serialNumber, 1) || !X509_set_serialNumber(certificate, serialNumber)) {
return status;
}
X509_NAME *subjectName = X509_NAME_new();
if (!X509_NAME_add_entry_by_txt(subjectName,
"CN",
MBSTRING_ASC,
(const unsigned char *)cert_bytes,
-1 /* len */,
-1 /* loc */,
0 /* set */) ||
!X509_set_subject_name(certificate, subjectName)) {
return status;
}
if (!X509_set_issuer_name(certificate, subjectName)) {
return status;
}
ASN1_TIME *notBefore = ASN1_TIME_new();
time_t activeDateTime = time(NULL);
if (!ASN1_TIME_set(notBefore, activeDateTime) || !X509_set_notBefore(certificate, notBefore)) {
return status;
}
ASN1_TIME *notAfter = ASN1_TIME_new();
time_t notAfterTime = time(NULL);
if (!ASN1_TIME_set(notAfter, notAfterTime * 2) || !X509_set_notAfter(certificate, notAfter)) {
return status;
}
/*Get public key*/
uint8_t key[1024];
size_t keybytelen = sizeof(key);
size_t keybitlen = keybytelen * 8;
status = sss_key_store_get_key(ks, obj, key, &keybytelen, &keybitlen);
LOG_I("sss_key_store_get_key status %x", status);
if (status != kStatus_SSS_Success)
return status;
status = kStatus_SSS_Fail;
BIO *bio = BIO_new_mem_buf(key, (int)sizeof(key));
if (bio == NULL) {
return status;
}
EVP_PKEY *pKey = d2i_PUBKEY_bio(bio, NULL);
if (pKey == NULL) {
return status;
}
/*Add public key*/
if (!X509_set_pubkey(certificate, pKey)) {
return status;
}
X509V3_CTX x509v3_ctx = {0};
char *basicConstraints = "CA:TRUE";
X509_EXTENSION *extension_SAN = X509V3_EXT_nconf_nid(NULL, &x509v3_ctx, NID_subject_alt_name, (char *)cert_subject);
if (!X509_add_ext(certificate, extension_SAN, -1)) {
return status;
}
X509_EXTENSION *extension_BasicConstraints =
X509V3_EXT_nconf_nid(NULL, &x509v3_ctx, NID_basic_constraints, basicConstraints);
if (!X509_add_ext(certificate, extension_BasicConstraints, -1)) {
return status;
}
int type = NID_ecdsa_with_SHA256;
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
X509_ALGOR *tbs_algo = certificate->cert_info->signature;
X509_ALGOR *algo = certificate->sig_alg;
X509_ALGOR_set0(algo, OBJ_nid2obj(type), V_ASN1_NULL, NULL);
#else
X509_ALGOR *tbs_algo = (X509_ALGOR *)X509_get0_tbs_sigalg(certificate);
#endif
X509_ALGOR_set0(tbs_algo, OBJ_nid2obj(type), V_ASN1_NULL, NULL);
/*Convert to DER format to sign*/
int len = 0;
uint8_t tbs_bytes[1024];
uint8_t *p_tbs_bytes = &tbs_bytes[0];
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
X509_CINF *cinf = certificate->cert_info;
len = i2d_X509_CINF(cinf, &p_tbs_bytes);
#else
len = i2d_re_X509_tbs(certificate, &p_tbs_bytes);
LOG_I("len = %d", len);
#endif
/*Calculate digest for signing*/
uint8_t digest[32] = {0};
size_t digestLen = sizeof(digest);
sss_digest_t digestCtx;
status = sss_digest_context_init(&digestCtx, session, kAlgorithm_SSS_SHA256, kMode_SSS_Digest);
status = sss_digest_one_go(&digestCtx, &tbs_bytes[0], len, digest, &digestLen);
sss_digest_context_free(&digestCtx);
if (status != kStatus_SSS_Success)
return status;
status = kStatus_SSS_Fail;
/*Sign digest*/
sss_asymmetric_t asymmCtx;
uint8_t signature[512];
uint8_t *p_signature = &signature[0];
size_t signatureLen = sizeof(signature);
sss_algorithm_t hash_algo = kAlgorithm_SSS_SHA256;
if (obj->cipherType == kSSS_CipherType_RSA || obj->cipherType == kSSS_CipherType_RSA_CRT)
hash_algo = kAlgorithm_SSS_RSASSA_PKCS1_PSS_MGF1_SHA256;
status = sss_asymmetric_context_init(&asymmCtx, session, obj, hash_algo, kMode_SSS_Sign);
status = sss_asymmetric_sign_digest(&asymmCtx, digest, digestLen, signature, &signatureLen);
if (status != kStatus_SSS_Success)
return status;
/*Add signature to certificate structure*/
#if (OPENSSL_VERSION_NUMBER < 0x10100000L)
ASN1_BIT_STRING *sig = certificate->signature;
#else
ASN1_BIT_STRING *sig;
X509_ALGOR *algo;
X509_get0_signature((const ASN1_BIT_STRING **)&sig, (const X509_ALGOR **)&algo, certificate);
X509_ALGOR_set0(algo, OBJ_nid2obj(type), V_ASN1_NULL, NULL);
#endif
len = ASN1_BIT_STRING_set(sig, p_signature, (int)signatureLen);
#endif
return status;
}