nuttx-apps/crypto/controlse/mbedtls_extension.c

311 lines
9.7 KiB
C
Raw Normal View History

/****************************************************************************
* apps/crypto/controlse/mbedtls_extension.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you 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.
*
****************************************************************************/
/* Copyright The Mbed TLS Contributors
* SPDX-License-Identifier: Apache-2.0
*
* The source code in this file is based on
* mbedtls_x509write_crt_der() method from x509write_crt.c in Mbed TLS
*/
/* Copyright 2023 NXP */
/****************************************************************************
* Included Files
****************************************************************************/
#define MBEDTLS_ALLOW_PRIVATE_ACCESS
#include <mbedtls/asn1write.h>
#include <mbedtls/error.h>
#include <mbedtls/oid.h>
#include <mbedtls/x509_crt.h>
#include <nuttx/crypto/se05x.h>
#include <sys/ioctl.h>
#include <string.h>
/****************************************************************************
* Private Functions
****************************************************************************/
static int x509_write_time(FAR unsigned char **p, FAR unsigned char *start,
FAR const char *t, size_t size)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t len = 0;
/* write MBEDTLS_ASN1_UTC_TIME if year < 2050 (2 bytes shorter) */
if (t[0] == '2' && t[1] == '0' && t[2] < '5')
{
MBEDTLS_ASN1_CHK_ADD(
len, mbedtls_asn1_write_raw_buffer(
p, start, (FAR const unsigned char *)t + 2, size - 2));
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
MBEDTLS_ASN1_CHK_ADD(
len, mbedtls_asn1_write_tag(p, start, MBEDTLS_ASN1_UTC_TIME));
}
else
{
MBEDTLS_ASN1_CHK_ADD(len,
mbedtls_asn1_write_raw_buffer(
p, start, (FAR const unsigned char *)t, size));
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(p, start, len));
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(
p, start, MBEDTLS_ASN1_GENERALIZED_TIME));
}
return ((int)len);
}
/****************************************************************************
* Public Functions
****************************************************************************/
int mbedtls_x509write_crt_der_se05x(FAR mbedtls_x509write_cert *ctx,
FAR unsigned char *buf, size_t size,
int se05x_fd, uint32_t private_key_id)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
FAR const char *sig_oid;
size_t sig_oid_len = 0;
FAR unsigned char *c;
FAR unsigned char *c2;
unsigned char hash[64];
unsigned char sig[MBEDTLS_PK_SIGNATURE_MAX_SIZE];
size_t sub_len = 0;
size_t pub_len = 0;
size_t sig_and_oid_len = 0;
size_t sig_len;
size_t len = 0;
mbedtls_pk_type_t pk_alg;
/* Prepare data to be signed at the end of the target buffer */
c = buf + size;
/* Signature algorithm needed in TBS, and later for actual signature */
/* There's no direct way of extracting a signature algorithm
* (represented as an element of mbedtls_pk_type_t) from a PK instance.
*/
if (mbedtls_pk_can_do(ctx->issuer_key, MBEDTLS_PK_RSA))
{
pk_alg = MBEDTLS_PK_RSA;
}
else if (mbedtls_pk_can_do(ctx->issuer_key, MBEDTLS_PK_ECDSA))
{
pk_alg = MBEDTLS_PK_ECDSA;
}
else
{
return (MBEDTLS_ERR_X509_INVALID_ALG);
}
if ((ret = mbedtls_oid_get_oid_by_sig_alg(pk_alg, ctx->md_alg, &sig_oid,
&sig_oid_len)) != 0)
{
return (ret);
}
/* Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension */
/* Only for v3 */
if (ctx->version == MBEDTLS_X509_CRT_VERSION_3)
{
MBEDTLS_ASN1_CHK_ADD(
len, mbedtls_x509_write_extensions(&c, buf, ctx->extensions));
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
MBEDTLS_ASN1_CHK_ADD(len,
mbedtls_asn1_write_tag(&c, buf,
MBEDTLS_ASN1_CONSTRUCTED |
MBEDTLS_ASN1_SEQUENCE));
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
MBEDTLS_ASN1_CHK_ADD(
len, mbedtls_asn1_write_tag(&c, buf,
MBEDTLS_ASN1_CONTEXT_SPECIFIC |
MBEDTLS_ASN1_CONSTRUCTED | 3));
}
/* SubjectPublicKeyInfo */
MBEDTLS_ASN1_CHK_ADD(
pub_len, mbedtls_pk_write_pubkey_der(ctx->subject_key, buf, c - buf));
c -= pub_len;
len += pub_len;
/* Subject ::= Name */
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_x509_write_names(&c, buf, ctx->subject));
/* Validity ::= SEQUENCE {
* notBefore Time,
* notAfter Time }
*/
sub_len = 0;
MBEDTLS_ASN1_CHK_ADD(sub_len,
x509_write_time(&c, buf, ctx->not_after,
MBEDTLS_X509_RFC5280_UTC_TIME_LEN));
MBEDTLS_ASN1_CHK_ADD(sub_len,
x509_write_time(&c, buf, ctx->not_before,
MBEDTLS_X509_RFC5280_UTC_TIME_LEN));
len += sub_len;
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, sub_len));
MBEDTLS_ASN1_CHK_ADD(
len, mbedtls_asn1_write_tag(
&c, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
/* Issuer ::= Name */
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_x509_write_names(&c, buf, ctx->issuer));
/* Signature ::= AlgorithmIdentifier */
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_algorithm_identifier(
&c, buf, sig_oid, strlen(sig_oid), 0));
/* Serial ::= INTEGER
*
* Written data is:
* - "ctx->serial_len" bytes for the raw serial buffer
* - if MSb of "serial" is 1, then prepend an extra 0x00 byte
* - 1 byte for the length
* - 1 byte for the TAG
*/
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_raw_buffer(&c, buf,
ctx->serial, ctx->serial_len));
if (*c & 0x80)
{
if (c - buf < 1)
{
return MBEDTLS_ERR_X509_BUFFER_TOO_SMALL;
}
*(--c) = 0x0;
len++;
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf,
ctx->serial_len + 1));
}
else
{
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf,
ctx->serial_len));
}
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&c, buf,
MBEDTLS_ASN1_INTEGER));
/* Version ::= INTEGER { v1(0), v2(1), v3(2) } */
/* Can be omitted for v1 */
if (ctx->version != MBEDTLS_X509_CRT_VERSION_1)
{
sub_len = 0;
MBEDTLS_ASN1_CHK_ADD(sub_len,
mbedtls_asn1_write_int(&c, buf, ctx->version));
len += sub_len;
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, sub_len));
MBEDTLS_ASN1_CHK_ADD(
len, mbedtls_asn1_write_tag(&c, buf,
MBEDTLS_ASN1_CONTEXT_SPECIFIC |
MBEDTLS_ASN1_CONSTRUCTED | 0));
}
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
MBEDTLS_ASN1_CHK_ADD(
len, mbedtls_asn1_write_tag(
&c, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
/* Make signature
*/
/* Compute hash of CRT. */
if ((ret = mbedtls_md(mbedtls_md_info_from_type(ctx->md_alg), c, len,
hash)) != 0)
{
return (ret);
}
{
struct se05x_signature_s args = {
.key_id = private_key_id,
.algorithm = SE05X_ALGORITHM_SHA256,
.tbs = {
.buffer = hash,
.buffer_size = 32,
.buffer_content_size = 32
},
.signature = {.buffer = sig, .buffer_size = sizeof(sig)},
};
ret = ioctl(se05x_fd, SEIOC_CREATE_SIGNATURE, &args);
if (ret != 0)
{
return ret;
}
sig_len = args.signature.buffer_content_size;
}
/* Move CRT to the front of the buffer to have space
* for the signature.
*/
memmove(buf, c, len);
c = buf + len;
/* Add signature at the end of the buffer,
* making sure that it doesn't underflow
* into the CRT buffer.
*/
c2 = buf + size;
MBEDTLS_ASN1_CHK_ADD(
sig_and_oid_len,
mbedtls_x509_write_sig(&c2, c, sig_oid, sig_oid_len, sig, sig_len));
/* Memory layout after this step:
*
* buf c=buf+len c2 buf+size
* [CRT0,...,CRTn, UNUSED, ..., UNUSED, SIG0, ..., SIGm]
*/
/* Move raw CRT to just before the signature. */
c = c2 - len;
memmove(c, buf, len);
len += sig_and_oid_len;
MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
MBEDTLS_ASN1_CHK_ADD(
len, mbedtls_asn1_write_tag(
&c, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
return ((int)len);
}