Coverage Report

Created: 2025-11-24 06:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open62541/plugins/crypto/mbedtls/create_certificate.c
Line
Count
Source
1
/* This Source Code Form is subject to the terms of the Mozilla Public
2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
3
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
 *
5
 *    Copyright (c) 2023 Fraunhofer IOSB (Author: Noel Graf)
6
 *
7
 */
8
9
#include <open62541/plugin/create_certificate.h>
10
11
#if defined(UA_ENABLE_ENCRYPTION_MBEDTLS)
12
13
#include "securitypolicy_common.h"
14
#include "../deps/musl_inet_pton.h"
15
16
#include <time.h>
17
18
#include <mbedtls/x509_crt.h>
19
#include <mbedtls/oid.h>
20
#include <mbedtls/asn1write.h>
21
#include <mbedtls/entropy.h>
22
#include <mbedtls/ctr_drbg.h>
23
#include <mbedtls/platform.h>
24
#include <mbedtls/version.h>
25
26
#define SET_OID(x, oid) \
27
0
    do { x.len = MBEDTLS_OID_SIZE(oid); x.p = (unsigned char *) oid; } while (0)
28
29
typedef struct mbedtls_write_san_node{
30
    int type;
31
    char* host;
32
    size_t hostlen;
33
} mbedtls_write_san_node;
34
35
typedef struct mbedtls_write_san_list{
36
    mbedtls_write_san_node node;
37
    struct mbedtls_write_san_list* next;
38
} mbedtls_write_san_list;
39
40
static size_t mbedtls_get_san_list_deep(const mbedtls_write_san_list* sanlist);
41
42
int mbedtls_x509write_crt_set_subject_alt_name(mbedtls_x509write_cert *ctx, const mbedtls_write_san_list* sanlist);
43
44
#if MBEDTLS_VERSION_NUMBER < 0x03030000
45
int mbedtls_x509write_crt_set_ext_key_usage(mbedtls_x509write_cert *ctx,
46
                                            const mbedtls_asn1_sequence *exts);
47
#endif
48
49
static int write_certificate(mbedtls_x509write_cert *crt, UA_CertificateFormat certFormat,
50
                             UA_ByteString *outCertificate, int (*f_rng)(void *, unsigned char *, size_t),
51
                             void *p_rng);
52
53
static int write_private_key(mbedtls_pk_context *key, UA_CertificateFormat keyFormat, UA_ByteString *outPrivateKey);
54
55
UA_StatusCode
56
UA_CreateCertificate(const UA_Logger *logger, const UA_String *subject,
57
                     size_t subjectSize, const UA_String *subjectAltName,
58
                     size_t subjectAltNameSize, UA_CertificateFormat certFormat,
59
                     UA_KeyValueMap *params, UA_ByteString *outPrivateKey,
60
0
                     UA_ByteString *outCertificate) {
61
0
    if(!outPrivateKey || !outCertificate || !logger || !subjectAltName || !subject ||
62
0
       subjectAltNameSize == 0 || subjectSize == 0 ||
63
0
       (certFormat != UA_CERTIFICATEFORMAT_DER && certFormat != UA_CERTIFICATEFORMAT_PEM))
64
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
65
66
    /* Use the maximum size */
67
0
    UA_UInt16 keySizeBits = 4096;
68
    /* Default to 1 year */
69
0
    UA_UInt16 expiresInDays = 365;
70
71
0
    if(params) {
72
0
        const UA_UInt16 *keySizeBitsValue = (const UA_UInt16 *)UA_KeyValueMap_getScalar(
73
0
            params, UA_QUALIFIEDNAME(0, "key-size-bits"), &UA_TYPES[UA_TYPES_UINT16]);
74
0
        if(keySizeBitsValue)
75
0
            keySizeBits = *keySizeBitsValue;
76
77
0
        const UA_UInt16 *expiresInDaysValue = (const UA_UInt16 *)UA_KeyValueMap_getScalar(
78
0
            params, UA_QUALIFIEDNAME(0, "expires-in-days"), &UA_TYPES[UA_TYPES_UINT16]);
79
0
        if(expiresInDaysValue)
80
0
            expiresInDays = *expiresInDaysValue;
81
0
    }
82
83
0
    UA_ByteString_init(outPrivateKey);
84
0
    UA_ByteString_init(outCertificate);
85
86
0
    mbedtls_pk_context key;
87
0
    mbedtls_ctr_drbg_context ctr_drbg;
88
0
    mbedtls_entropy_context entropy;
89
0
    const char *pers = "gen_key";
90
0
    mbedtls_x509write_cert crt;
91
92
0
    UA_StatusCode errRet = UA_STATUSCODE_GOOD;
93
94
    /* Set to sane values */
95
0
    mbedtls_pk_init(&key);
96
0
    mbedtls_ctr_drbg_init(&ctr_drbg);
97
0
    mbedtls_entropy_init(&entropy);
98
0
    mbedtls_x509write_crt_init(&crt);
99
100
    /* Seed the random number generator */
101
0
    if (mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)pers, strlen(pers)) != 0) {
102
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
103
0
                     "Failed to initialize the random number generator.");
104
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
105
0
        goto cleanup;
106
0
    }
107
108
    /* Generate an RSA key pair */
109
0
    if (mbedtls_pk_setup(&key, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)) != 0 ||
110
0
        mbedtls_rsa_gen_key(mbedtls_pk_rsa(key), mbedtls_ctr_drbg_random, &ctr_drbg, keySizeBits, 65537) != 0) {
111
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
112
0
                     "Failed to generate RSA key pair.");
113
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
114
0
        goto cleanup;
115
0
    }
116
117
    /* Setting certificate values */
118
0
    mbedtls_x509write_crt_set_version(&crt, MBEDTLS_X509_CRT_VERSION_3);
119
0
    mbedtls_x509write_crt_set_md_alg(&crt, MBEDTLS_MD_SHA256);
120
121
0
    size_t subject_char_len = 0;
122
0
    for(size_t i = 0; i < subjectSize; i++) {
123
0
        subject_char_len += subject[i].length;
124
0
    }
125
0
    char *subject_char = (char*)UA_malloc(subject_char_len + subjectSize);
126
0
    if(!subject_char) {
127
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
128
0
                     "Cannot allocate memory for subject. Out of memory.");
129
0
        errRet = UA_STATUSCODE_BADOUTOFMEMORY;
130
0
        goto cleanup;
131
0
    }
132
133
0
    size_t pos = 0;
134
0
    for(size_t i = 0; i < subjectSize; i++) {
135
0
        subject_char_len += subject[i].length;
136
0
        memcpy(subject_char + pos, subject[i].data, subject[i].length);
137
0
        pos += subject[i].length;
138
0
        if(i < subjectSize - 1)
139
0
            subject_char[pos++] = ',';
140
0
        else
141
0
            subject_char[pos++] = '\0';
142
0
    }
143
144
0
    if((mbedtls_x509write_crt_set_subject_name(&crt, subject_char)) != 0) {
145
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
146
0
                     "Setting subject failed.");
147
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
148
0
        UA_free(subject_char);
149
0
        goto cleanup;
150
0
    }
151
152
0
    if((mbedtls_x509write_crt_set_issuer_name(&crt, subject_char)) != 0) {
153
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
154
0
                     "Setting issuer failed.");
155
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
156
0
        UA_free(subject_char);
157
0
        goto cleanup;
158
0
    }
159
160
0
    UA_free(subject_char);
161
162
0
    mbedtls_write_san_list *cur = NULL;
163
0
    mbedtls_write_san_list *cur_tmp = NULL;
164
0
    mbedtls_write_san_list *head = NULL;
165
0
    for(size_t i = 0; i < subjectAltNameSize; i++) {
166
0
        char *sanType;
167
0
        char *sanValue;
168
0
        size_t sanValueLength;
169
0
        char *subAlt = (char *)UA_malloc(subjectAltName[i].length + 1);
170
0
        memcpy(subAlt, subjectAltName[i].data, subjectAltName[i].length);
171
172
        /* null-terminate the copied string */
173
0
        subAlt[subjectAltName[i].length] = 0;
174
        /* split into SAN type and value */
175
0
        sanType = strtok(subAlt, ":");
176
0
        sanValue = (char *)subjectAltName[i].data + strlen(sanType) + 1;
177
0
        sanValueLength = subjectAltName[i].length - strlen(sanType) - 1;
178
179
0
        if(sanType) {
180
0
            cur_tmp = (mbedtls_write_san_list*)mbedtls_calloc(1, sizeof(mbedtls_write_san_list));
181
0
            cur_tmp->next = NULL;
182
0
            cur_tmp->node.host = sanValue;
183
0
            cur_tmp->node.hostlen = sanValueLength;
184
185
0
            if(strcmp(sanType, "DNS") == 0) {
186
0
                cur_tmp->node.type = MBEDTLS_X509_SAN_DNS_NAME;
187
0
            } else if(strcmp(sanType, "URI") == 0) {
188
0
                cur_tmp->node.type = MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER;
189
0
            } else if(strcmp(sanType, "IP") == 0) {
190
0
                uint8_t ip[4] = {0};
191
0
                if(musl_inet_pton(AF_INET, sanValue, ip) <= 0) {
192
0
                    UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURECHANNEL, "IP SAN preparation failed");
193
0
                    mbedtls_free(cur_tmp);
194
0
                    UA_free(subAlt);
195
0
                    continue;
196
0
                }
197
0
                cur_tmp->node.type = MBEDTLS_X509_SAN_IP_ADDRESS;
198
0
                cur_tmp->node.host = (char *)ip;
199
0
                cur_tmp->node.hostlen = sizeof(ip);
200
0
            } else if(strcmp(sanType, "RFC822") == 0) {
201
0
                cur_tmp->node.type = MBEDTLS_X509_SAN_RFC822_NAME;
202
0
            } else {
203
0
                UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURECHANNEL, "Given an unsupported SAN");
204
0
                mbedtls_free(cur_tmp);
205
0
                UA_free(subAlt);
206
0
                continue;
207
0
            }
208
0
        } else {
209
0
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURECHANNEL, "Invalid Input format");
210
0
            UA_free(subAlt);
211
0
            continue;
212
0
        }
213
214
0
        if(!cur) {
215
0
            cur = cur_tmp;
216
0
            head = cur_tmp;
217
0
        } else {
218
0
            cur->next = cur_tmp;
219
0
            cur = cur->next;
220
0
        }
221
222
0
        UA_free(subAlt);
223
0
    }
224
225
0
    if((mbedtls_x509write_crt_set_subject_alt_name(&crt, head)) != 0) {
226
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
227
0
                     "Setting subject alternative name failed.");
228
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
229
0
        while(head != NULL) {
230
0
            cur_tmp = head->next;
231
0
            mbedtls_free(head);
232
0
            head = cur_tmp;
233
0
        }
234
0
        goto cleanup;
235
0
    }
236
237
0
    while(head != NULL) {
238
0
        cur_tmp = head->next;
239
0
        mbedtls_free(head);
240
0
        head = cur_tmp;
241
0
    }
242
243
#if MBEDTLS_VERSION_NUMBER >= 0x03040000
244
    unsigned char *serial = (unsigned char *)"1";
245
    size_t serial_len = 1;
246
    mbedtls_x509write_crt_set_serial_raw(&crt, serial, serial_len);
247
#else
248
0
    mbedtls_mpi serial_mpi;
249
0
    mbedtls_mpi_init(&serial_mpi);
250
0
    mbedtls_mpi_lset(&serial_mpi, 1);
251
0
    mbedtls_x509write_crt_set_serial(&crt, &serial_mpi);
252
0
    mbedtls_mpi_free(&serial_mpi);
253
0
#endif
254
255
    /* Get the current time */
256
0
    time_t rawTime;
257
0
    struct tm *timeInfo;
258
0
    time(&rawTime);
259
0
    timeInfo = gmtime(&rawTime);
260
261
    /* Format the current timestamp */
262
0
    char current_timestamp[15];  // YYYYMMDDhhmmss + '\0'
263
0
    strftime(current_timestamp, sizeof(current_timestamp), "%Y%m%d%H%M%S", timeInfo);
264
265
    /* Calculate the future timestamp */
266
0
    timeInfo->tm_mday += expiresInDays;
267
0
    time_t future_time = mktime(timeInfo);
268
269
    /* Format the future timestamp */
270
0
    char future_timestamp[15];  // YYYYMMDDhhmmss + '\0'
271
0
    strftime(future_timestamp, sizeof(future_timestamp), "%Y%m%d%H%M%S", gmtime(&future_time));
272
273
0
    if(mbedtls_x509write_crt_set_validity(&crt, current_timestamp, future_timestamp) != 0) {
274
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
275
0
                     "Setting 'not before' and 'not after' failed.");
276
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
277
0
        goto cleanup;
278
0
    }
279
280
0
    if(mbedtls_x509write_crt_set_basic_constraints(&crt, 0, -1) != 0) {
281
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
282
0
                     "Setting basic constraints failed.");
283
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
284
0
        goto cleanup;
285
0
    }
286
287
0
    if(mbedtls_x509write_crt_set_key_usage(&crt, MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION
288
0
                                            | MBEDTLS_X509_KU_KEY_ENCIPHERMENT | MBEDTLS_X509_KU_DATA_ENCIPHERMENT
289
0
                                            | MBEDTLS_X509_KU_KEY_CERT_SIGN | MBEDTLS_X509_KU_CRL_SIGN) != 0) {
290
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
291
0
                     "Setting key usage failed.");
292
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
293
0
        goto cleanup;
294
0
    }
295
296
0
    mbedtls_asn1_sequence *ext_key_usage;
297
0
    ext_key_usage = (mbedtls_asn1_sequence *)mbedtls_calloc(1, sizeof(mbedtls_asn1_sequence));
298
0
    ext_key_usage->buf.tag = MBEDTLS_ASN1_OID;
299
0
    SET_OID(ext_key_usage->buf, MBEDTLS_OID_SERVER_AUTH);
300
0
    ext_key_usage->next = (mbedtls_asn1_sequence *)mbedtls_calloc(1, sizeof(mbedtls_asn1_sequence));
301
0
    ext_key_usage->next->buf.tag = MBEDTLS_ASN1_OID;
302
0
    SET_OID(ext_key_usage->next->buf, MBEDTLS_OID_CLIENT_AUTH);
303
304
0
    if(mbedtls_x509write_crt_set_ext_key_usage(&crt, ext_key_usage) != 0) {
305
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
306
0
                     "Setting extended key usage failed.");
307
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
308
0
        mbedtls_free(ext_key_usage->next);
309
0
        mbedtls_free(ext_key_usage);
310
0
        goto cleanup;
311
0
    }
312
313
0
    mbedtls_free(ext_key_usage->next);
314
0
    mbedtls_free(ext_key_usage);
315
316
0
    mbedtls_x509write_crt_set_subject_key(&crt, &key);
317
0
    mbedtls_x509write_crt_set_issuer_key(&crt, &key);
318
319
320
    /* Write private key */
321
0
    if ((write_private_key(&key, certFormat, outPrivateKey)) != 0) {
322
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
323
0
                     "Create Certificate: Writing private key failed.");
324
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
325
0
        goto cleanup;
326
0
    }
327
328
    /* Write Certificate */
329
0
    if ((write_certificate(&crt, certFormat, outCertificate,
330
0
                                 mbedtls_ctr_drbg_random, &ctr_drbg)) != 0) {
331
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
332
0
                     "Create Certificate: Writing certificate failed.");
333
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
334
0
        goto cleanup;
335
0
    }
336
337
0
    mbedtls_ctr_drbg_free(&ctr_drbg);
338
0
    mbedtls_entropy_free(&entropy);
339
0
    mbedtls_x509write_crt_free(&crt);
340
0
    mbedtls_pk_free(&key);
341
342
0
cleanup:
343
0
    mbedtls_ctr_drbg_free(&ctr_drbg);
344
0
    mbedtls_entropy_free(&entropy);
345
0
    mbedtls_x509write_crt_free(&crt);
346
0
    mbedtls_pk_free(&key);
347
0
    return errRet;
348
0
}
349
350
0
static int write_private_key(mbedtls_pk_context *key, UA_CertificateFormat keyFormat, UA_ByteString *outPrivateKey) {
351
0
    int ret;
352
0
    unsigned char output_buf[16000];
353
0
    unsigned char *c = output_buf;
354
0
    size_t len = 0;
355
356
0
    memset(output_buf, 0, sizeof(output_buf));
357
0
    switch(keyFormat) {
358
0
    case UA_CERTIFICATEFORMAT_DER: {
359
0
        if((ret = mbedtls_pk_write_key_der(key, output_buf, sizeof(output_buf))) < 0) {
360
0
            return ret;
361
0
        }
362
363
0
        len = ret;
364
0
        c = output_buf + sizeof(output_buf) - len;
365
0
        break;
366
0
    }
367
0
    case UA_CERTIFICATEFORMAT_PEM: {
368
0
        if((ret = mbedtls_pk_write_key_pem(key, output_buf, sizeof(output_buf))) != 0) {
369
0
            return ret;
370
0
        }
371
372
0
        len = strlen((char *)output_buf);
373
0
        break;
374
0
    }
375
0
    }
376
377
0
    outPrivateKey->length = len;
378
0
    UA_ByteString_allocBuffer(outPrivateKey, outPrivateKey->length);
379
0
    memcpy(outPrivateKey->data, c, outPrivateKey->length);
380
381
0
    return 0;
382
0
}
383
384
static int write_certificate(mbedtls_x509write_cert *crt, UA_CertificateFormat certFormat,
385
                      UA_ByteString *outCertificate, int (*f_rng)(void *, unsigned char *, size_t),
386
0
                      void *p_rng) {
387
0
    int ret;
388
0
    unsigned char output_buf[4096];
389
0
    unsigned char *c = output_buf;
390
0
    size_t len = 0;
391
392
0
    memset(output_buf, 0, sizeof(output_buf));
393
0
    switch(certFormat) {
394
0
    case UA_CERTIFICATEFORMAT_DER: {
395
0
        if((ret = mbedtls_x509write_crt_der(crt, output_buf, sizeof(output_buf), f_rng, p_rng)) < 0) {
396
0
            return ret;
397
0
        }
398
399
0
        len = ret;
400
0
        c = output_buf + sizeof(output_buf) - len;
401
0
        break;
402
0
    }
403
0
    case UA_CERTIFICATEFORMAT_PEM: {
404
0
        if((ret = mbedtls_x509write_crt_pem(crt, output_buf, sizeof(output_buf), f_rng, p_rng)) < 0) {
405
0
            return ret;
406
0
        }
407
408
0
        len = strlen((char *)output_buf);
409
0
        break;
410
0
    }
411
0
    }
412
413
0
    outCertificate->length = len;
414
0
    UA_ByteString_allocBuffer(outCertificate, outCertificate->length);
415
0
    memcpy(outCertificate->data, c, outCertificate->length);
416
417
0
    return 0;
418
0
}
419
420
#if MBEDTLS_VERSION_NUMBER < 0x03030000
421
int mbedtls_x509write_crt_set_ext_key_usage(mbedtls_x509write_cert *ctx,
422
0
                                            const mbedtls_asn1_sequence *exts) {
423
0
    unsigned char buf[256];
424
0
    unsigned char *c = buf + sizeof(buf);
425
0
    int ret;
426
0
    size_t len = 0;
427
0
    const mbedtls_asn1_sequence *last_ext = NULL;
428
0
    const mbedtls_asn1_sequence *ext;
429
430
0
    memset(buf, 0, sizeof(buf));
431
432
    /* We need at least one extension: SEQUENCE SIZE (1..MAX) OF KeyPurposeId */
433
0
    if(!exts) {
434
0
        return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
435
0
    }
436
437
    /* Iterate over exts backwards, so we write them out in the requested order */
438
0
    while(last_ext != exts) {
439
0
        for(ext = exts; ext->next != last_ext; ext = ext->next) {
440
0
        }
441
0
        if(ext->buf.tag != MBEDTLS_ASN1_OID) {
442
0
            return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
443
0
        }
444
0
        MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_raw_buffer(&c, buf, ext->buf.p, ext->buf.len));
445
0
        MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, ext->buf.len));
446
0
        MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_OID));
447
0
        last_ext = ext;
448
0
    }
449
450
0
    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
451
0
    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
452
453
0
    return mbedtls_x509write_crt_set_extension(ctx, MBEDTLS_OID_EXTENDED_KEY_USAGE,
454
0
                                               MBEDTLS_OID_SIZE(MBEDTLS_OID_EXTENDED_KEY_USAGE), 1, c, len);
455
0
}
456
457
#endif
458
459
0
static size_t mbedtls_get_san_list_deep(const mbedtls_write_san_list* sanlist) {
460
0
    size_t ret = 0;
461
0
    const mbedtls_write_san_list* cur = sanlist;
462
0
    while (cur) {
463
0
        ++ret;
464
0
        cur = cur->next;
465
0
    }
466
467
0
    return ret;
468
0
}
469
470
0
int mbedtls_x509write_crt_set_subject_alt_name(mbedtls_x509write_cert *ctx, const mbedtls_write_san_list* sanlist) {
471
0
    int ret = 0;
472
0
    size_t sandeep = 0;
473
0
    const mbedtls_write_san_list* cur = sanlist;
474
0
    unsigned char* buf;
475
0
    unsigned char* pc;
476
0
    size_t len;
477
0
    size_t buflen = 0;
478
479
    /* How many alt names to be written */
480
0
    sandeep = mbedtls_get_san_list_deep(sanlist);
481
0
    if (sandeep == 0)
482
0
        return ret;
483
484
0
    buflen = MBEDTLS_SAN_MAX_LEN * sandeep + sandeep;
485
0
    buf = (unsigned char *)mbedtls_calloc(1, buflen);
486
0
    if(!buf)
487
0
        return MBEDTLS_ERR_ASN1_ALLOC_FAILED;
488
489
0
    memset(buf, 0, buflen);
490
0
    pc = buf + buflen;
491
492
0
    len = 0;
493
0
    while(cur) {
494
0
        switch (cur->node.type) {
495
0
        case MBEDTLS_X509_SAN_DNS_NAME:
496
0
        case MBEDTLS_X509_SAN_RFC822_NAME:
497
0
        case MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER:
498
0
        case MBEDTLS_X509_SAN_IP_ADDRESS:
499
0
            MBEDTLS_ASN1_CHK_CLEANUP_ADD(len,
500
0
                                         mbedtls_asn1_write_raw_buffer(&pc, buf, (const unsigned char *)cur->node.host,
501
0
                                                                       cur->node.hostlen));
502
0
            MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_len(&pc, buf, cur->node.hostlen));
503
0
            MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_tag(&pc, buf,
504
0
                                                                     MBEDTLS_ASN1_CONTEXT_SPECIFIC | cur->node.type));
505
0
            break;
506
0
        default:
507
            /* Error out on an unsupported SAN */
508
0
            ret = MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE;
509
0
            goto cleanup;
510
0
        }
511
512
0
        cur = cur->next;
513
0
    }
514
515
0
    MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_len(&pc, buf, len));
516
0
    MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_tag(&pc, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
517
518
0
    ret = mbedtls_x509write_crt_set_extension(ctx, MBEDTLS_OID_SUBJECT_ALT_NAME,
519
0
                                              MBEDTLS_OID_SIZE(MBEDTLS_OID_SUBJECT_ALT_NAME), 0, buf + buflen - len, len);
520
521
0
    mbedtls_free(buf);
522
0
    return ret;
523
524
0
cleanup:
525
    mbedtls_free(buf);
526
0
    return ret;
527
0
}
528
529
#endif