x509write_crt.c 15.3 KB
Newer Older
1 2 3
/*
 *  X.509 certificate writing
 *
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 23 24 25 26 27 28
 *
 *  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.
 */
/*
 * References:
 * - certificates: RFC 5280, updated by RFC 6818
 * - CSRs: PKCS#10 v1.7 aka RFC 2986
 * - attributes: PKCS#9 v2.0 aka RFC 2985
 */

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
29
#if !defined(MBEDTLS_CONFIG_FILE)
30
#include "mbedtls/config.h"
31
#else
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
32
#include MBEDTLS_CONFIG_FILE
33
#endif
34

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
35
#if defined(MBEDTLS_X509_CRT_WRITE_C)
36

37 38 39 40
#include "mbedtls/x509_crt.h"
#include "mbedtls/oid.h"
#include "mbedtls/asn1write.h"
#include "mbedtls/sha1.h"
41

42 43
#include <string.h>

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
44
#if defined(MBEDTLS_PEM_WRITE_C)
45
#include "mbedtls/pem.h"
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
46
#endif /* MBEDTLS_PEM_WRITE_C */
47

48
/* Implementation that should never be optimized out by the compiler */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
49
static void mbedtls_zeroize( void *v, size_t n ) {
50 51 52
    volatile unsigned char *p = v; while( n-- ) *p++ = 0;
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
53
void mbedtls_x509write_crt_init( mbedtls_x509write_cert *ctx )
54
{
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
55
    memset( ctx, 0, sizeof(mbedtls_x509write_cert) );
56

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
57 58
    mbedtls_mpi_init( &ctx->serial );
    ctx->version = MBEDTLS_X509_CRT_VERSION_3;
59 60
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
61
void mbedtls_x509write_crt_free( mbedtls_x509write_cert *ctx )
62
{
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
63
    mbedtls_mpi_free( &ctx->serial );
64

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
65 66 67
    mbedtls_asn1_free_named_data_list( &ctx->subject );
    mbedtls_asn1_free_named_data_list( &ctx->issuer );
    mbedtls_asn1_free_named_data_list( &ctx->extensions );
68

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
69
    mbedtls_zeroize( ctx, sizeof(mbedtls_x509write_cert) );
70 71
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
72
void mbedtls_x509write_crt_set_version( mbedtls_x509write_cert *ctx, int version )
73 74 75 76
{
    ctx->version = version;
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
77
void mbedtls_x509write_crt_set_md_alg( mbedtls_x509write_cert *ctx, mbedtls_md_type_t md_alg )
78 79 80 81
{
    ctx->md_alg = md_alg;
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
82
void mbedtls_x509write_crt_set_subject_key( mbedtls_x509write_cert *ctx, mbedtls_pk_context *key )
83 84 85 86
{
    ctx->subject_key = key;
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
87
void mbedtls_x509write_crt_set_issuer_key( mbedtls_x509write_cert *ctx, mbedtls_pk_context *key )
88 89 90 91
{
    ctx->issuer_key = key;
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
92
int mbedtls_x509write_crt_set_subject_name( mbedtls_x509write_cert *ctx,
Paul Bakker's avatar
Paul Bakker committed
93
                                    const char *subject_name )
94
{
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
95
    return mbedtls_x509_string_to_names( &ctx->subject, subject_name );
96 97
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
98
int mbedtls_x509write_crt_set_issuer_name( mbedtls_x509write_cert *ctx,
Paul Bakker's avatar
Paul Bakker committed
99
                                   const char *issuer_name )
100
{
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
101
    return mbedtls_x509_string_to_names( &ctx->issuer, issuer_name );
102 103
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
104
int mbedtls_x509write_crt_set_serial( mbedtls_x509write_cert *ctx, const mbedtls_mpi *serial )
105 106 107
{
    int ret;

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
108
    if( ( ret = mbedtls_mpi_copy( &ctx->serial, serial ) ) != 0 )
109 110 111 112 113
        return( ret );

    return( 0 );
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
114
int mbedtls_x509write_crt_set_validity( mbedtls_x509write_cert *ctx, const char *not_before,
Paul Bakker's avatar
Paul Bakker committed
115
                                const char *not_after )
116
{
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
117 118
    if( strlen( not_before ) != MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1 ||
        strlen( not_after )  != MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1 )
119
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
120
        return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
121
    }
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
122 123 124 125
    strncpy( ctx->not_before, not_before, MBEDTLS_X509_RFC5280_UTC_TIME_LEN );
    strncpy( ctx->not_after , not_after , MBEDTLS_X509_RFC5280_UTC_TIME_LEN );
    ctx->not_before[MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1] = 'Z';
    ctx->not_after[MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1] = 'Z';
126 127 128 129

    return( 0 );
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
130
int mbedtls_x509write_crt_set_extension( mbedtls_x509write_cert *ctx,
131 132 133 134
                                 const char *oid, size_t oid_len,
                                 int critical,
                                 const unsigned char *val, size_t val_len )
{
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
135
    return mbedtls_x509_set_extension( &ctx->extensions, oid, oid_len,
136 137 138
                               critical, val, val_len );
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
139
int mbedtls_x509write_crt_set_basic_constraints( mbedtls_x509write_cert *ctx,
140 141 142 143 144 145 146 147 148 149
                                         int is_ca, int max_pathlen )
{
    int ret;
    unsigned char buf[9];
    unsigned char *c = buf + sizeof(buf);
    size_t len = 0;

    memset( buf, 0, sizeof(buf) );

    if( is_ca && max_pathlen > 127 )
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
150
        return( MBEDTLS_ERR_X509_BAD_INPUT_DATA );
151 152 153 154 155

    if( is_ca )
    {
        if( max_pathlen >= 0 )
        {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
156
            MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf, max_pathlen ) );
157
        }
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
158
        MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_bool( &c, buf, 1 ) );
159 160
    }

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
161 162 163
    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 ) );
164

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
165 166
    return mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_BASIC_CONSTRAINTS,
                                        MBEDTLS_OID_SIZE( MBEDTLS_OID_BASIC_CONSTRAINTS ),
167 168 169
                                        0, buf + sizeof(buf) - len, len );
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
170 171
#if defined(MBEDTLS_SHA1_C)
int mbedtls_x509write_crt_set_subject_key_identifier( mbedtls_x509write_cert *ctx )
172 173
{
    int ret;
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
174
    unsigned char buf[MBEDTLS_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */
175 176 177
    unsigned char *c = buf + sizeof(buf);
    size_t len = 0;

178
    memset( buf, 0, sizeof(buf) );
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
179
    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_pk_write_pubkey( &c, buf, ctx->subject_key ) );
180

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
181
    mbedtls_sha1( buf + sizeof(buf) - len, len, buf + sizeof(buf) - 20 );
182 183 184
    c = buf + sizeof(buf) - 20;
    len = 20;

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
185 186
    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_OCTET_STRING ) );
187

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
188 189
    return mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER,
                                        MBEDTLS_OID_SIZE( MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER ),
190 191 192
                                        0, buf + sizeof(buf) - len, len );
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
193
int mbedtls_x509write_crt_set_authority_key_identifier( mbedtls_x509write_cert *ctx )
194 195
{
    int ret;
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
196
    unsigned char buf[MBEDTLS_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */
197 198 199
    unsigned char *c = buf + sizeof(buf);
    size_t len = 0;

200
    memset( buf, 0, sizeof(buf) );
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
201
    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_pk_write_pubkey( &c, buf, ctx->issuer_key ) );
202

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
203
    mbedtls_sha1( buf + sizeof(buf) - len, len, buf + sizeof(buf) - 20 );
204 205 206
    c = buf + sizeof(buf) - 20;
    len = 20;

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
207 208
    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 | 0 ) );
209

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
210 211 212
    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 ) );
213

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
214 215
    return mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER,
                                   MBEDTLS_OID_SIZE( MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER ),
216 217
                                   0, buf + sizeof(buf) - len, len );
}
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
218
#endif /* MBEDTLS_SHA1_C */
219

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
220
int mbedtls_x509write_crt_set_key_usage( mbedtls_x509write_cert *ctx, unsigned char key_usage )
221 222 223 224 225 226 227
{
    unsigned char buf[4];
    unsigned char *c;
    int ret;

    c = buf + 4;

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
228
    if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &key_usage, 7 ) ) != 4 )
229 230
        return( ret );

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
231 232
    ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_KEY_USAGE,
                                       MBEDTLS_OID_SIZE( MBEDTLS_OID_KEY_USAGE ),
233 234 235 236 237 238 239
                                       1, buf, 4 );
    if( ret != 0 )
        return( ret );

    return( 0 );
}

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
240
int mbedtls_x509write_crt_set_ns_cert_type( mbedtls_x509write_cert *ctx,
241 242 243 244 245 246 247 248
                                    unsigned char ns_cert_type )
{
    unsigned char buf[4];
    unsigned char *c;
    int ret;

    c = buf + 4;

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
249
    if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &ns_cert_type, 8 ) ) != 4 )
250 251
        return( ret );

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
252 253
    ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_NS_CERT_TYPE,
                                       MBEDTLS_OID_SIZE( MBEDTLS_OID_NS_CERT_TYPE ),
254 255 256 257 258 259 260 261 262 263 264 265 266 267
                                       0, buf, 4 );
    if( ret != 0 )
        return( ret );

    return( 0 );
}

static int x509_write_time( unsigned char **p, unsigned char *start,
                            const char *time, size_t size )
{
    int ret;
    size_t len = 0;

    /*
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
268
     * write MBEDTLS_ASN1_UTC_TIME if year < 2050 (2 bytes shorter)
269 270 271
     */
    if( time[0] == '2' && time[1] == '0' && time [2] < '5' )
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
272
        MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start,
273 274
                                             (const unsigned char *) time + 2,
                                             size - 2 ) );
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
275 276
        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 ) );
277 278 279
    }
    else
    {
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
280
        MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start,
281 282
                                                  (const unsigned char *) time,
                                                  size ) );
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
283 284
        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 ) );
285 286
    }

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

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
290
int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf, size_t size,
291 292 293 294 295 296 297 298
                       int (*f_rng)(void *, unsigned char *, size_t),
                       void *p_rng )
{
    int ret;
    const char *sig_oid;
    size_t sig_oid_len = 0;
    unsigned char *c, *c2;
    unsigned char hash[64];
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
299
    unsigned char sig[MBEDTLS_MPI_MAX_SIZE];
300 301 302
    unsigned char tmp_buf[2048];
    size_t sub_len = 0, pub_len = 0, sig_and_oid_len = 0, sig_len;
    size_t len = 0;
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
303
    mbedtls_pk_type_t pk_alg;
304 305 306 307 308 309 310

    /*
     * Prepare data to be signed in tmp_buf
     */
    c = tmp_buf + sizeof( tmp_buf );

    /* Signature algorithm needed in TBS, and later for actual signature */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
311 312 313
    pk_alg = mbedtls_pk_get_type( ctx->issuer_key );
    if( pk_alg == MBEDTLS_PK_ECKEY )
        pk_alg = MBEDTLS_PK_ECDSA;
314

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
315
    if( ( ret = mbedtls_oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg,
316 317 318 319 320 321 322 323
                                        &sig_oid, &sig_oid_len ) ) != 0 )
    {
        return( ret );
    }

    /*
     *  Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
     */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
324 325 326 327 328 329 330
    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_extensions( &c, tmp_buf, ctx->extensions ) );
    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) );
    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED |
                                                    MBEDTLS_ASN1_SEQUENCE ) );
    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) );
    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC |
                                                    MBEDTLS_ASN1_CONSTRUCTED | 3 ) );
331 332 333 334

    /*
     *  SubjectPublicKeyInfo
     */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
335
    MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_pk_write_pubkey_der( ctx->subject_key,
336 337 338 339 340 341 342
                                                tmp_buf, c - tmp_buf ) );
    c -= pub_len;
    len += pub_len;

    /*
     *  Subject  ::=  Name
     */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
343
    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_names( &c, tmp_buf, ctx->subject ) );
344 345 346 347 348 349 350 351

    /*
     *  Validity ::= SEQUENCE {
     *       notBefore      Time,
     *       notAfter       Time }
     */
    sub_len = 0;

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
352 353
    MBEDTLS_ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_after,
                                            MBEDTLS_X509_RFC5280_UTC_TIME_LEN ) );
354

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
355 356
    MBEDTLS_ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_before,
                                            MBEDTLS_X509_RFC5280_UTC_TIME_LEN ) );
357 358

    len += sub_len;
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
359 360 361
    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, sub_len ) );
    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED |
                                                    MBEDTLS_ASN1_SEQUENCE ) );
362 363 364 365

    /*
     *  Issuer  ::=  Name
     */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
366
    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_names( &c, tmp_buf, ctx->issuer ) );
367 368 369 370

    /*
     *  Signature   ::=  AlgorithmIdentifier
     */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
371
    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_algorithm_identifier( &c, tmp_buf,
372 373 374 375 376
                       sig_oid, strlen( sig_oid ), 0 ) );

    /*
     *  Serial   ::=  INTEGER
     */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
377
    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, tmp_buf, &ctx->serial ) );
378 379 380 381 382

    /*
     *  Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
     */
    sub_len = 0;
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
383
    MBEDTLS_ASN1_CHK_ADD( sub_len, mbedtls_asn1_write_int( &c, tmp_buf, ctx->version ) );
384
    len += sub_len;
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
385 386 387
    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, sub_len ) );
    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC |
                                                    MBEDTLS_ASN1_CONSTRUCTED | 0 ) );
388

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
389 390 391
    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) );
    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED |
                                                    MBEDTLS_ASN1_SEQUENCE ) );
392 393 394 395

    /*
     * Make signature
     */
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
396
    mbedtls_md( mbedtls_md_info_from_type( ctx->md_alg ), c, len, hash );
397

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
398
    if( ( ret = mbedtls_pk_sign( ctx->issuer_key, ctx->md_alg, hash, 0, sig, &sig_len,
399 400 401 402 403 404 405 406 407
                         f_rng, p_rng ) ) != 0 )
    {
        return( ret );
    }

    /*
     * Write data to output buffer
     */
    c2 = buf + size;
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
408
    MBEDTLS_ASN1_CHK_ADD( sig_and_oid_len, mbedtls_x509_write_sig( &c2, buf,
409 410 411 412 413 414
                                        sig_oid, sig_oid_len, sig, sig_len ) );

    c2 -= len;
    memcpy( c2, c, len );

    len += sig_and_oid_len;
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
415 416 417
    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c2, buf, len ) );
    MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c2, buf, MBEDTLS_ASN1_CONSTRUCTED |
                                                 MBEDTLS_ASN1_SEQUENCE ) );
418

419
    return( (int) len );
420 421 422 423 424
}

#define PEM_BEGIN_CRT           "-----BEGIN CERTIFICATE-----\n"
#define PEM_END_CRT             "-----END CERTIFICATE-----\n"

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
425 426
#if defined(MBEDTLS_PEM_WRITE_C)
int mbedtls_x509write_crt_pem( mbedtls_x509write_cert *crt, unsigned char *buf, size_t size,
427 428 429 430 431 432 433
                       int (*f_rng)(void *, unsigned char *, size_t),
                       void *p_rng )
{
    int ret;
    unsigned char output_buf[4096];
    size_t olen = 0;

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
434
    if( ( ret = mbedtls_x509write_crt_der( crt, output_buf, sizeof(output_buf),
435 436 437 438 439
                                   f_rng, p_rng ) ) < 0 )
    {
        return( ret );
    }

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
440
    if( ( ret = mbedtls_pem_write_buffer( PEM_BEGIN_CRT, PEM_END_CRT,
441 442 443 444 445 446 447 448
                                  output_buf + sizeof(output_buf) - ret,
                                  ret, buf, size, &olen ) ) != 0 )
    {
        return( ret );
    }

    return( 0 );
}
Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
449
#endif /* MBEDTLS_PEM_WRITE_C */
450

Manuel Pégourié-Gonnard's avatar
Manuel Pégourié-Gonnard committed
451
#endif /* MBEDTLS_X509_CRT_WRITE_C */