This repository has been archived by the owner on Dec 8, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
Copy pathmbedtls_utils.c
254 lines (218 loc) · 7.58 KB
/
mbedtls_utils.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
/*
* 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 );
}