mirror of
https://github.com/FreeRTOS/FreeRTOS.git
synced 2026-08-05 04:34:50 +00:00
268 lines
7.7 KiB
C
268 lines
7.7 KiB
C
/*
|
|
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* 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.
|
|
*
|
|
* This file is part of mbed TLS (https://tls.mbed.org)
|
|
*/
|
|
|
|
/**
|
|
* @file mbedtls_utils.c
|
|
* @brief Helper functions originating from mbedTLS.
|
|
*/
|
|
|
|
/* Standard includes. */
|
|
#include <string.h>
|
|
|
|
/* mbedTLS includes. */
|
|
#include "mbedtls/base64.h"
|
|
#include "mbedtls/rsa.h"
|
|
#include "mbedtls/asn1.h"
|
|
#include "mbedtls/platform_util.h"
|
|
#include "mbedtls/oid.h"
|
|
/*-----------------------------------------------------------*/
|
|
|
|
/* @brief Converts PEM documents into DER formatted byte arrays.
|
|
* This is a helper function from mbedTLS util pem2der.c
|
|
* (https://github.com/ARMmbed/mbedtls/blob/development/programs/util/pem2der.c#L75)
|
|
*
|
|
* \param pucInput[in] Pointer to PEM object
|
|
* \param xLen[in] Length of PEM object
|
|
* \param pucOutput[out] Pointer to buffer where DER oboject will be placed
|
|
* \param pxOlen[in/out] Pointer to length of DER buffer. This value is updated
|
|
* to contain the actual length of the converted DER object.
|
|
*
|
|
* \return 0 if successful. Negative if conversion failed. If buffer is not
|
|
* large enough to hold converted object, pxOlen is still updated but -1 is returned.
|
|
*
|
|
*/
|
|
int convert_pem_to_der( const unsigned char * pucInput,
|
|
size_t xLen,
|
|
unsigned char * pucOutput,
|
|
size_t * pxOlen )
|
|
{
|
|
int lRet;
|
|
const unsigned char * pucS1;
|
|
const unsigned char * pucS2;
|
|
const unsigned char * pucEnd = pucInput + xLen;
|
|
size_t xOtherLen = 0;
|
|
|
|
pucS1 = ( unsigned char * ) strstr( ( const char * ) pucInput, "-----BEGIN" );
|
|
|
|
if( pucS1 == NULL )
|
|
{
|
|
return( -1 );
|
|
}
|
|
|
|
pucS2 = ( unsigned char * ) strstr( ( const char * ) pucInput, "-----END" );
|
|
|
|
if( pucS2 == NULL )
|
|
{
|
|
return( -1 );
|
|
}
|
|
|
|
pucS1 += 10;
|
|
|
|
while( pucS1 < pucEnd && *pucS1 != '-' )
|
|
{
|
|
pucS1++;
|
|
}
|
|
|
|
while( pucS1 < pucEnd && *pucS1 == '-' )
|
|
{
|
|
pucS1++;
|
|
}
|
|
|
|
if( *pucS1 == '\r' )
|
|
{
|
|
pucS1++;
|
|
}
|
|
|
|
if( *pucS1 == '\n' )
|
|
{
|
|
pucS1++;
|
|
}
|
|
|
|
if( ( pucS2 <= pucS1 ) || ( pucS2 > pucEnd ) )
|
|
{
|
|
return( -1 );
|
|
}
|
|
|
|
lRet = mbedtls_base64_decode( NULL, 0, &xOtherLen, ( const unsigned char * ) pucS1, pucS2 - pucS1 );
|
|
|
|
if( lRet == MBEDTLS_ERR_BASE64_INVALID_CHARACTER )
|
|
{
|
|
return( lRet );
|
|
}
|
|
|
|
if( xOtherLen > *pxOlen )
|
|
{
|
|
return( -1 );
|
|
}
|
|
|
|
if( ( lRet = mbedtls_base64_decode( pucOutput, xOtherLen, &xOtherLen, ( const unsigned char * ) pucS1,
|
|
pucS2 - pucS1 ) ) != 0 )
|
|
{
|
|
return( lRet );
|
|
}
|
|
|
|
*pxOlen = xOtherLen;
|
|
|
|
return( 0 );
|
|
}
|
|
/*-----------------------------------------------------------*/
|
|
|
|
|
|
/* This function is a modified version of the static function
|
|
rsa_rsassa_pkcs1_v15_encode() inside of rsa.c in mbedTLS. It has been extracted
|
|
so that FreeRTOS PKCS #11 libraries and testing may use it. */
|
|
|
|
/* Construct a PKCS v1.5 encoding of a hashed message
|
|
*
|
|
* This is used both for signature generation and verification.
|
|
*
|
|
* Parameters:
|
|
* - md_alg: Identifies the hash algorithm used to generate the given hash;
|
|
* MBEDTLS_MD_NONE if raw data is signed.
|
|
* - hashlen: Length of hash in case hashlen is MBEDTLS_MD_NONE.
|
|
* - hash: Buffer containing the hashed message or the raw data.
|
|
* - dst_len: Length of the encoded message.
|
|
* - dst: Buffer to hold the encoded message.
|
|
*
|
|
* Assumptions:
|
|
* - hash has size hashlen if md_alg == MBEDTLS_MD_NONE.
|
|
* - hash has size corresponding to md_alg if md_alg != MBEDTLS_MD_NONE.
|
|
* - dst points to a buffer of size at least dst_len.
|
|
*
|
|
*/
|
|
|
|
/* \brief Formats cryptographically hashed data for RSA signing in accordance
|
|
* with PKCS #1 version 1.5.
|
|
*
|
|
* Currently assumes SHA-256.
|
|
*/
|
|
int PKI_RSA_RSASSA_PKCS1_v15_Encode( const unsigned char * hash,
|
|
size_t dst_len,
|
|
unsigned char * dst )
|
|
{
|
|
size_t oid_size = 0;
|
|
size_t nb_pad = dst_len;
|
|
unsigned char * p = dst;
|
|
const char * oid = NULL;
|
|
mbedtls_md_type_t md_alg = MBEDTLS_MD_SHA256;
|
|
unsigned int hashlen = 0;
|
|
|
|
const mbedtls_md_info_t * md_info = mbedtls_md_info_from_type( md_alg );
|
|
|
|
if( md_info == NULL )
|
|
{
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
}
|
|
|
|
if( mbedtls_oid_get_oid_by_md( md_alg, &oid, &oid_size ) != 0 )
|
|
{
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
}
|
|
|
|
hashlen = mbedtls_md_get_size( md_info );
|
|
|
|
/* Double-check that 8 + hashlen + oid_size can be used as a
|
|
* 1-byte ASN.1 length encoding and that there's no overflow. */
|
|
if( ( 8 + hashlen + oid_size >= 0x80 ) ||
|
|
( 10 + hashlen < hashlen ) ||
|
|
( 10 + hashlen + oid_size < 10 + hashlen ) )
|
|
{
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
}
|
|
|
|
/*
|
|
* Static bounds check:
|
|
* - Need 10 bytes for five tag-length pairs.
|
|
* (Insist on 1-byte length encodings to protect against variants of
|
|
* Bleichenbacher's forgery attack against lax PKCS#1v1.5 verification)
|
|
* - Need hashlen bytes for hash
|
|
* - Need oid_size bytes for hash alg OID.
|
|
*/
|
|
if( nb_pad < 10 + hashlen + oid_size )
|
|
{
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
}
|
|
|
|
nb_pad -= 10 + hashlen + oid_size;
|
|
|
|
/* Need space for signature header and padding delimiter (3 bytes),
|
|
* and 8 bytes for the minimal padding */
|
|
if( nb_pad < 3 + 8 )
|
|
{
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
}
|
|
|
|
nb_pad -= 3;
|
|
|
|
/* Now nb_pad is the amount of memory to be filled
|
|
* with padding, and at least 8 bytes long. */
|
|
|
|
/* Write signature header and padding */
|
|
*p++ = 0;
|
|
*p++ = MBEDTLS_RSA_SIGN;
|
|
memset( p, 0xFF, nb_pad );
|
|
p += nb_pad;
|
|
*p++ = 0;
|
|
|
|
/* Are we signing raw data? */
|
|
if( md_alg == MBEDTLS_MD_NONE )
|
|
{
|
|
memcpy( p, hash, hashlen );
|
|
return( 0 );
|
|
}
|
|
|
|
/* Signing hashed data, add corresponding ASN.1 structure
|
|
*
|
|
* DigestInfo ::= SEQUENCE {
|
|
* digestAlgorithm DigestAlgorithmIdentifier,
|
|
* digest Digest }
|
|
* DigestAlgorithmIdentifier ::= AlgorithmIdentifier
|
|
* Digest ::= OCTET STRING
|
|
*
|
|
* Schematic:
|
|
* TAG-SEQ + LEN [ TAG-SEQ + LEN [ TAG-OID + LEN [ OID ]
|
|
* TAG-NULL + LEN [ NULL ] ]
|
|
* TAG-OCTET + LEN [ HASH ] ]
|
|
*/
|
|
*p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED;
|
|
*p++ = ( unsigned char ) ( 0x08 + oid_size + hashlen );
|
|
*p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED;
|
|
*p++ = ( unsigned char ) ( 0x04 + oid_size );
|
|
*p++ = MBEDTLS_ASN1_OID;
|
|
*p++ = ( unsigned char ) oid_size;
|
|
memcpy( p, oid, oid_size );
|
|
p += oid_size;
|
|
*p++ = MBEDTLS_ASN1_NULL;
|
|
*p++ = 0x00;
|
|
*p++ = MBEDTLS_ASN1_OCTET_STRING;
|
|
*p++ = ( unsigned char ) hashlen;
|
|
memcpy( p, hash, hashlen );
|
|
p += hashlen;
|
|
|
|
/* Just a sanity-check, should be automatic
|
|
* after the initial bounds check. */
|
|
if( p != dst + dst_len )
|
|
{
|
|
mbedtls_platform_zeroize( dst, dst_len );
|
|
return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA );
|
|
}
|
|
|
|
return( 0 );
|
|
}
|