asn1write.c 9.87 KB
Newer Older
1 2 3
/*
 * ASN.1 buffer writing functionality
 *
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
4
 *  Copyright (C) 2006-2014, ARM Limited, All Rights Reserved
5
 *
6
 *  This file is part of mbed TLS (https://tls.mbed.org)
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
23
#if !defined(MBEDTLS_CONFIG_FILE)
24
#include "mbedtls/config.h"
25
#else
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
26
#include MBEDTLS_CONFIG_FILE
27
#endif
28

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
29
#if defined(MBEDTLS_ASN1_WRITE_C)
30

31
#include "mbedtls/asn1write.h"
32

33 34
#include <string.h>

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
35
#if defined(MBEDTLS_PLATFORM_C)
36
#include "mbedtls/platform.h"
37 38
#else
#include <stdlib.h>
39
#define mbedtls_calloc    calloc
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
40
#define mbedtls_free       free
41 42
#endif

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
43
int mbedtls_asn1_write_len( unsigned char **p, unsigned char *start, size_t len )
44 45 46 47
{
    if( len < 0x80 )
    {
        if( *p - start < 1 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
48
            return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
49

50
        *--(*p) = (unsigned char) len;
51 52 53 54 55 56
        return( 1 );
    }

    if( len <= 0xFF )
    {
        if( *p - start < 2 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
57
            return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
58

59
        *--(*p) = (unsigned char) len;
60 61 62 63 64
        *--(*p) = 0x81;
        return( 2 );
    }

    if( *p - start < 3 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
65
        return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
66 67 68 69 70 71 72 73 74 75

    // We assume we never have lengths larger than 65535 bytes
    //
    *--(*p) = len % 256;
    *--(*p) = ( len / 256 ) % 256;
    *--(*p) = 0x82;

    return( 3 );
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
76
int mbedtls_asn1_write_tag( unsigned char **p, unsigned char *start, unsigned char tag )
77 78
{
    if( *p - start < 1 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
79
        return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
80 81 82 83 84 85

    *--(*p) = tag;

    return( 1 );
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
86
int mbedtls_asn1_write_raw_buffer( unsigned char **p, unsigned char *start,
87 88 89 90 91
                           const unsigned char *buf, size_t size )
{
    size_t len = 0;

    if( *p - start < (int) size )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
92
        return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
93 94 95 96 97

    len = size;
    (*p) -= len;
    memcpy( *p, buf, len );

98
    return( (int) len );
99 100
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
101 102
#if defined(MBEDTLS_BIGNUM_C)
int mbedtls_asn1_write_mpi( unsigned char **p, unsigned char *start, const mbedtls_mpi *X )
103 104 105 106 107 108
{
    int ret;
    size_t len = 0;

    // Write the MPI
    //
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
109
    len = mbedtls_mpi_size( X );
110 111

    if( *p - start < (int) len )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
112
        return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
113 114

    (*p) -= len;
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
115
    MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( X, *p, len ) );
116 117 118 119

    // DER format assumes 2s complement for numbers, so the leftmost bit
    // should be 0 for positive numbers and 1 for negative numbers.
    //
120
    if( X->s ==1 && **p & 0x80 )
121 122
    {
        if( *p - start < 1 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
123
            return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
124 125 126 127 128

        *--(*p) = 0x00;
        len += 1;
    }

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
129 130
    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_INTEGER ) );
131

132 133 134 135
    ret = (int) len;

cleanup:
    return( ret );
136
}
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
137
#endif /* MBEDTLS_BIGNUM_C */
138

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
139
int mbedtls_asn1_write_null( unsigned char **p, unsigned char *start )
140 141 142 143 144 145
{
    int ret;
    size_t len = 0;

    // Write NULL
    //
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
146 147
    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, 0) );
    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_NULL ) );
148

149
    return( (int) len );
150 151
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
152
int mbedtls_asn1_write_oid( unsigned char **p, unsigned char *start,
153
                    const char *oid, size_t oid_len )
154 155 156 157
{
    int ret;
    size_t len = 0;

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
158
    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start,
159
                                  (const unsigned char *) oid, oid_len ) );
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
160 161
    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_OID ) );
162

163
    return( (int) len );
164 165
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
166
int mbedtls_asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start,
167 168
                                     const char *oid, size_t oid_len,
                                     size_t par_len )
169 170 171 172
{
    int ret;
    size_t len = 0;

173
    if( par_len == 0 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
174
        MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_null( p, start ) );
175 176
    else
        len += par_len;
177

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
178
    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( p, start, oid, oid_len ) );
179

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
180 181 182
    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_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) );
183

184
    return( (int) len );
185 186
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
187
int mbedtls_asn1_write_bool( unsigned char **p, unsigned char *start, int boolean )
Paul Bakker's avatar
Paul Bakker committed
188 189 190 191 192
{
    int ret;
    size_t len = 0;

    if( *p - start < 1 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
193
        return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
Paul Bakker's avatar
Paul Bakker committed
194 195 196 197

    *--(*p) = (boolean) ? 1 : 0;
    len++;

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
198 199
    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_BOOLEAN ) );
Paul Bakker's avatar
Paul Bakker committed
200

201
    return( (int) len );
Paul Bakker's avatar
Paul Bakker committed
202 203
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
204
int mbedtls_asn1_write_int( unsigned char **p, unsigned char *start, int val )
205 206 207 208 209 210 211 212 213
{
    int ret;
    size_t len = 0;

    // TODO negative values and values larger than 128
    // DER format assumes 2s complement for numbers, so the leftmost bit
    // should be 0 for positive numbers and 1 for negative numbers.
    //
    if( *p - start < 1 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
214
        return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
215 216 217 218

    len += 1;
    *--(*p) = val;

219
    if( val > 0 && **p & 0x80 )
220 221
    {
        if( *p - start < 1 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
222
            return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
223 224 225 226 227

        *--(*p) = 0x00;
        len += 1;
    }

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
228 229
    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_INTEGER ) );
230

231
    return( (int) len );
232 233
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
234
int mbedtls_asn1_write_printable_string( unsigned char **p, unsigned char *start,
235
                                 const char *text, size_t text_len )
236 237 238 239
{
    int ret;
    size_t len = 0;

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
240
    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start,
241
                  (const unsigned char *) text, text_len ) );
242

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
243 244
    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_PRINTABLE_STRING ) );
245

246
    return( (int) len );
247
}
248

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
249
int mbedtls_asn1_write_ia5_string( unsigned char **p, unsigned char *start,
250
                           const char *text, size_t text_len )
251 252 253 254
{
    int ret;
    size_t len = 0;

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
255
    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start,
256
                  (const unsigned char *) text, text_len ) );
257

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
258 259
    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_IA5_STRING ) );
260

261
    return( (int) len );
262
}
263

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
264
int mbedtls_asn1_write_bitstring( unsigned char **p, unsigned char *start,
265 266 267 268 269 270 271 272 273 274
                          const unsigned char *buf, size_t bits )
{
    int ret;
    size_t len = 0, size;

    size = ( bits / 8 ) + ( ( bits % 8 ) ? 1 : 0 );

    // Calculate byte length
    //
    if( *p - start < (int) size + 1 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
275
        return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
276 277 278 279 280 281 282

    len = size + 1;
    (*p) -= size;
    memcpy( *p, buf, size );

    // Write unused bits
    //
283
    *--(*p) = (unsigned char) (size * 8 - bits);
284

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
285 286
    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_BIT_STRING ) );
287

288
    return( (int) len );
289 290
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
291
int mbedtls_asn1_write_octet_string( unsigned char **p, unsigned char *start,
292 293 294 295 296
                             const unsigned char *buf, size_t size )
{
    int ret;
    size_t len = 0;

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
297
    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, buf, size ) );
298

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
299 300
    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_OCTET_STRING ) );
301

302
    return( (int) len );
303
}
304

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
305
mbedtls_asn1_named_data *mbedtls_asn1_store_named_data( mbedtls_asn1_named_data **head,
306 307 308 309
                                        const char *oid, size_t oid_len,
                                        const unsigned char *val,
                                        size_t val_len )
{
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
310
    mbedtls_asn1_named_data *cur;
311

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
312
    if( ( cur = mbedtls_asn1_find_named_data( *head, oid, oid_len ) ) == NULL )
313 314 315
    {
        // Add new entry if not present yet based on OID
        //
316
        if( ( cur = mbedtls_calloc( 1, sizeof(mbedtls_asn1_named_data) ) ) == NULL )
317 318 319
            return( NULL );

        cur->oid.len = oid_len;
320
        cur->oid.p = mbedtls_calloc( 1, oid_len );
321 322
        if( cur->oid.p == NULL )
        {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
323
            mbedtls_free( cur );
324 325 326
            return( NULL );
        }

327 328
        memcpy( cur->oid.p, oid, oid_len );

329
        cur->val.len = val_len;
330
        cur->val.p = mbedtls_calloc( 1, val_len );
331 332
        if( cur->val.p == NULL )
        {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
333 334
            mbedtls_free( cur->oid.p );
            mbedtls_free( cur );
335 336 337 338 339 340 341 342 343 344
            return( NULL );
        }

        cur->next = *head;
        *head = cur;
    }
    else if( cur->val.len < val_len )
    {
        // Enlarge existing value buffer if needed
        //
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
345
        mbedtls_free( cur->val.p );
346 347 348
        cur->val.p = NULL;

        cur->val.len = val_len;
349
        cur->val.p = mbedtls_calloc( 1, val_len );
350 351
        if( cur->val.p == NULL )
        {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
352 353
            mbedtls_free( cur->oid.p );
            mbedtls_free( cur );
354 355 356 357 358 359 360 361 362
            return( NULL );
        }
    }

    if( val != NULL )
        memcpy( cur->val.p, val, val_len );

    return( cur );
}
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
363
#endif /* MBEDTLS_ASN1_WRITE_C */