Coverage Report

Created: 2026-07-16 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open62541_15/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
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner)
7
 *
8
 */
9
10
#include <open62541/plugin/create_certificate.h>
11
12
#if defined(UA_ENABLE_ENCRYPTION_MBEDTLS)
13
14
#include "securitypolicy_common.h"
15
#include "../deps/musl_inet_pton.h"
16
17
#include <time.h>
18
19
#include <mbedtls/x509_crt.h>
20
#include <mbedtls/oid.h>
21
#include <mbedtls/asn1write.h>
22
#include <mbedtls/entropy.h>
23
#include <mbedtls/ctr_drbg.h>
24
#include <mbedtls/platform.h>
25
#include <mbedtls/version.h>
26
27
#define SET_OID(x, oid) \
28
0
    do { x.len = MBEDTLS_OID_SIZE(oid); x.p = (unsigned char *) oid; } while (0)
29
30
typedef struct mbedtls_write_san_node{
31
    int type;
32
    char* host;
33
    size_t hostlen;
34
} mbedtls_write_san_node;
35
36
typedef struct mbedtls_write_san_list{
37
    mbedtls_write_san_node node;
38
    struct mbedtls_write_san_list* next;
39
} mbedtls_write_san_list;
40
41
static size_t mbedtls_get_san_list_deep(const mbedtls_write_san_list* sanlist);
42
43
int mbedtls_x509write_crt_set_subject_alt_name(mbedtls_x509write_cert *ctx, const mbedtls_write_san_list* sanlist);
44
45
#if MBEDTLS_VERSION_NUMBER < 0x03030000
46
int mbedtls_x509write_crt_set_ext_key_usage(mbedtls_x509write_cert *ctx,
47
                                            const mbedtls_asn1_sequence *exts);
48
#endif
49
50
static int write_certificate(mbedtls_x509write_cert *crt, UA_CertificateFormat certFormat,
51
                             UA_ByteString *outCertificate, int (*f_rng)(void *, unsigned char *, size_t),
52
                             void *p_rng);
53
54
static int write_private_key(mbedtls_pk_context *key, UA_CertificateFormat keyFormat, UA_ByteString *outPrivateKey);
55
56
/* Case-insensitive comparison of a UA_String with a C string literal */
57
static UA_Boolean
58
0
uaStringEqualsCI_mbedtls(const UA_String *uaStr, const char *cStr) {
59
0
    size_t cLen = strlen(cStr);
60
0
    if(uaStr->length != cLen)
61
0
        return false;
62
0
    for(size_t i = 0; i < cLen; i++) {
63
0
        char a = (char)uaStr->data[i];
64
0
        char b = cStr[i];
65
0
        if(a >= 'A' && a <= 'Z') a = (char)(a + 32);
66
0
        if(b >= 'A' && b <= 'Z') b = (char)(b + 32);
67
0
        if(a != b) return false;
68
0
    }
69
0
    return true;
70
0
}
71
72
UA_StatusCode
73
UA_CreateCertificate(const UA_Logger *logger, const UA_String *subject,
74
                     size_t subjectSize, const UA_String *subjectAltName,
75
                     size_t subjectAltNameSize, UA_CertificateFormat certFormat,
76
                     UA_KeyValueMap *params, UA_ByteString *outPrivateKey,
77
0
                     UA_ByteString *outCertificate) {
78
0
    if(!outPrivateKey || !outCertificate || !logger || !subjectAltName || !subject ||
79
0
       subjectAltNameSize == 0 || subjectSize == 0 ||
80
0
       (certFormat != UA_CERTIFICATEFORMAT_DER && certFormat != UA_CERTIFICATEFORMAT_PEM))
81
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
82
83
    /* Use the maximum size */
84
0
    UA_UInt16 keySizeBits = 4096;
85
    /* Default to 1 year */
86
0
    UA_UInt16 expiresInDays = 365;
87
    /* Key type: 0 = RSA (default), 1 = EC */
88
0
    int keyTypeEC = 0;
89
0
    UA_String eccCurve = UA_STRING_STATIC("prime256v1");
90
91
0
    if(params) {
92
0
        const UA_UInt16 *keySizeBitsValue = (const UA_UInt16 *)UA_KeyValueMap_getScalar(
93
0
            params, UA_QUALIFIEDNAME(0, "key-size-bits"), &UA_TYPES[UA_TYPES_UINT16]);
94
0
        if(keySizeBitsValue)
95
0
            keySizeBits = *keySizeBitsValue;
96
97
0
        const UA_UInt16 *expiresInDaysValue = (const UA_UInt16 *)UA_KeyValueMap_getScalar(
98
0
            params, UA_QUALIFIEDNAME(0, "expires-in-days"), &UA_TYPES[UA_TYPES_UINT16]);
99
0
        if(expiresInDaysValue)
100
0
            expiresInDays = *expiresInDaysValue;
101
102
0
        const UA_String *keyTypeValue = (const UA_String *)UA_KeyValueMap_getScalar(
103
0
            params, UA_QUALIFIEDNAME(0, "key-type"), &UA_TYPES[UA_TYPES_STRING]);
104
0
        if(keyTypeValue && uaStringEqualsCI_mbedtls(keyTypeValue, "ec"))
105
0
            keyTypeEC = 1;
106
107
0
        const UA_String *eccCurveValue = (const UA_String *)UA_KeyValueMap_getScalar(
108
0
            params, UA_QUALIFIEDNAME(0, "ecc-curve"), &UA_TYPES[UA_TYPES_STRING]);
109
0
        if(eccCurveValue && eccCurveValue->length > 0)
110
0
            eccCurve = *eccCurveValue;
111
0
    }
112
113
0
    UA_ByteString_init(outPrivateKey);
114
0
    UA_ByteString_init(outCertificate);
115
116
0
    mbedtls_pk_context key;
117
0
    mbedtls_ctr_drbg_context ctr_drbg;
118
0
    mbedtls_entropy_context entropy;
119
0
    const char *pers = "gen_key";
120
0
    mbedtls_x509write_cert crt;
121
122
0
    UA_StatusCode errRet = UA_STATUSCODE_GOOD;
123
124
    /* Set to sane values */
125
0
    mbedtls_pk_init(&key);
126
0
    mbedtls_ctr_drbg_init(&ctr_drbg);
127
0
    mbedtls_entropy_init(&entropy);
128
0
    mbedtls_x509write_crt_init(&crt);
129
130
    /* Seed the random number generator */
131
0
    if (mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)pers, strlen(pers)) != 0) {
132
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
133
0
                     "Failed to initialize the random number generator.");
134
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
135
0
        goto cleanup;
136
0
    }
137
138
    /* Generate a key pair */
139
0
    if(keyTypeEC) {
140
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
141
        /* Map curve name to mbedTLS group ID */
142
        mbedtls_ecp_group_id grp_id = MBEDTLS_ECP_DP_SECP256R1; /* default: P-256 */
143
        if(uaStringEqualsCI_mbedtls(&eccCurve, "prime256v1") ||
144
           uaStringEqualsCI_mbedtls(&eccCurve, "nistp256"))
145
            grp_id = MBEDTLS_ECP_DP_SECP256R1;
146
        else if(uaStringEqualsCI_mbedtls(&eccCurve, "secp384r1") ||
147
                uaStringEqualsCI_mbedtls(&eccCurve, "nistp384"))
148
            grp_id = MBEDTLS_ECP_DP_SECP384R1;
149
        else if(uaStringEqualsCI_mbedtls(&eccCurve, "brainpoolp256r1"))
150
            grp_id = MBEDTLS_ECP_DP_BP256R1;
151
        else if(uaStringEqualsCI_mbedtls(&eccCurve, "brainpoolp384r1"))
152
            grp_id = MBEDTLS_ECP_DP_BP384R1;
153
        else if(uaStringEqualsCI_mbedtls(&eccCurve, "ed25519") ||
154
                uaStringEqualsCI_mbedtls(&eccCurve, "ed448")) {
155
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
156
                         "EdDSA (Curve25519/Curve448) certificate generation "
157
                         "is not supported with mbedTLS. Use OpenSSL.");
158
            errRet = UA_STATUSCODE_BADNOTIMPLEMENTED;
159
            goto cleanup;
160
        } else {
161
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
162
                         "Create Certificate: Unsupported ECC curve for mbedTLS.");
163
            errRet = UA_STATUSCODE_BADINVALIDARGUMENT;
164
            goto cleanup;
165
        }
166
167
        if(mbedtls_pk_setup(&key, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)) != 0 ||
168
           mbedtls_ecp_gen_key(grp_id, mbedtls_pk_ec(key),
169
                               mbedtls_ctr_drbg_random, &ctr_drbg) != 0) {
170
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
171
                         "Failed to generate ECC key pair.");
172
            errRet = UA_STATUSCODE_BADINTERNALERROR;
173
            goto cleanup;
174
        }
175
#else
176
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
177
0
                     "ECC certificate generation requires mbedTLS >= 3.0.");
178
0
        errRet = UA_STATUSCODE_BADNOTIMPLEMENTED;
179
0
        goto cleanup;
180
0
#endif
181
0
    } else {
182
        /* Generate an RSA key pair */
183
0
        if(mbedtls_pk_setup(&key, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)) != 0 ||
184
0
           mbedtls_rsa_gen_key(mbedtls_pk_rsa(key), mbedtls_ctr_drbg_random,
185
0
                               &ctr_drbg, keySizeBits, 65537) != 0) {
186
0
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
187
0
                         "Failed to generate RSA key pair.");
188
0
            errRet = UA_STATUSCODE_BADINTERNALERROR;
189
0
            goto cleanup;
190
0
        }
191
0
    }
192
193
    /* Setting certificate values */
194
0
    mbedtls_x509write_crt_set_version(&crt, MBEDTLS_X509_CRT_VERSION_3);
195
    /* P-384 / brainpoolP384r1 use SHA-384; everything else uses SHA-256 */
196
0
    if(keyTypeEC &&
197
0
       (uaStringEqualsCI_mbedtls(&eccCurve, "secp384r1") ||
198
0
        uaStringEqualsCI_mbedtls(&eccCurve, "nistp384") ||
199
0
        uaStringEqualsCI_mbedtls(&eccCurve, "brainpoolp384r1")))
200
0
        mbedtls_x509write_crt_set_md_alg(&crt, MBEDTLS_MD_SHA384);
201
0
    else
202
0
        mbedtls_x509write_crt_set_md_alg(&crt, MBEDTLS_MD_SHA256);
203
204
0
    size_t subject_char_len = 0;
205
0
    for(size_t i = 0; i < subjectSize; i++) {
206
0
        subject_char_len += subject[i].length;
207
0
    }
208
0
    char *subject_char = (char*)UA_malloc(subject_char_len + subjectSize);
209
0
    if(!subject_char) {
210
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
211
0
                     "Cannot allocate memory for subject. Out of memory.");
212
0
        errRet = UA_STATUSCODE_BADOUTOFMEMORY;
213
0
        goto cleanup;
214
0
    }
215
216
0
    size_t pos = 0;
217
0
    for(size_t i = 0; i < subjectSize; i++) {
218
0
        subject_char_len += subject[i].length;
219
0
        memcpy(subject_char + pos, subject[i].data, subject[i].length);
220
0
        pos += subject[i].length;
221
0
        if(i < subjectSize - 1)
222
0
            subject_char[pos++] = ',';
223
0
        else
224
0
            subject_char[pos++] = '\0';
225
0
    }
226
227
0
    if((mbedtls_x509write_crt_set_subject_name(&crt, subject_char)) != 0) {
228
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
229
0
                     "Setting subject failed.");
230
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
231
0
        UA_free(subject_char);
232
0
        goto cleanup;
233
0
    }
234
235
0
    if((mbedtls_x509write_crt_set_issuer_name(&crt, subject_char)) != 0) {
236
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
237
0
                     "Setting issuer failed.");
238
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
239
0
        UA_free(subject_char);
240
0
        goto cleanup;
241
0
    }
242
243
0
    UA_free(subject_char);
244
245
0
    mbedtls_write_san_list *cur = NULL;
246
0
    mbedtls_write_san_list *cur_tmp = NULL;
247
0
    mbedtls_write_san_list *head = NULL;
248
0
    for(size_t i = 0; i < subjectAltNameSize; i++) {
249
        /* Copy and null-terminate */
250
0
        char *subAlt = (char *)UA_malloc(subjectAltName[i].length + 1);
251
0
        memcpy(subAlt, subjectAltName[i].data, subjectAltName[i].length);
252
0
        subAlt[subjectAltName[i].length] = 0;
253
254
        /* split into SAN type and value */
255
0
        char *sanType = NULL;
256
0
        for(char *char_pos = subAlt; *char_pos != 0; char_pos++) {
257
0
            if(*char_pos == ':') {
258
0
                *char_pos = '\0';
259
0
                sanType = subAlt;
260
0
                break;
261
0
            }
262
0
        }
263
264
0
        if(!sanType) {
265
0
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURECHANNEL, "Invalid Input format");
266
0
            UA_free(subAlt);
267
0
            continue;
268
0
        }
269
270
0
        char *sanValue = (char *)subjectAltName[i].data + strlen(sanType) + 1;
271
0
        size_t sanValueLength = subjectAltName[i].length - strlen(sanType) - 1;
272
273
0
        cur_tmp = (mbedtls_write_san_list*)mbedtls_calloc(1, sizeof(mbedtls_write_san_list));
274
0
        cur_tmp->next = NULL;
275
0
        cur_tmp->node.host = sanValue;
276
0
        cur_tmp->node.hostlen = sanValueLength;
277
278
0
        if(strcmp(sanType, "DNS") == 0) {
279
0
            cur_tmp->node.type = MBEDTLS_X509_SAN_DNS_NAME;
280
0
        } else if(strcmp(sanType, "URI") == 0) {
281
0
            cur_tmp->node.type = MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER;
282
0
        } else if(strcmp(sanType, "IP") == 0) {
283
0
            uint8_t *ip = (uint8_t *)mbedtls_calloc(1, 4);
284
0
            if(!ip) {
285
0
                mbedtls_free(cur_tmp);
286
0
                UA_free(subAlt);
287
0
                continue;
288
0
            }
289
0
            if(musl_inet_pton(AF_INET, sanValue, ip) <= 0) {
290
0
                UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURECHANNEL, "IP SAN preparation failed");
291
0
                mbedtls_free(ip);
292
0
                mbedtls_free(cur_tmp);
293
0
                UA_free(subAlt);
294
0
                continue;
295
0
            }
296
0
            cur_tmp->node.type = MBEDTLS_X509_SAN_IP_ADDRESS;
297
0
            cur_tmp->node.host = (char *)ip;
298
0
            cur_tmp->node.hostlen = 4;
299
0
        } else if(strcmp(sanType, "RFC822") == 0) {
300
0
            cur_tmp->node.type = MBEDTLS_X509_SAN_RFC822_NAME;
301
0
        } else {
302
0
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURECHANNEL, "Given an unsupported SAN");
303
0
            mbedtls_free(cur_tmp);
304
0
            UA_free(subAlt);
305
0
            continue;
306
0
        }
307
308
0
        if(!cur) {
309
0
            cur = cur_tmp;
310
0
            head = cur_tmp;
311
0
        } else {
312
0
            cur->next = cur_tmp;
313
0
            cur = cur->next;
314
0
        }
315
316
0
        UA_free(subAlt);
317
0
    }
318
319
0
    if((mbedtls_x509write_crt_set_subject_alt_name(&crt, head)) != 0) {
320
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
321
0
                     "Setting subject alternative name failed.");
322
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
323
0
        while(head != NULL) {
324
0
            cur_tmp = head->next;
325
0
            if(head->node.type == MBEDTLS_X509_SAN_IP_ADDRESS)
326
0
                mbedtls_free(head->node.host);
327
0
            mbedtls_free(head);
328
0
            head = cur_tmp;
329
0
        }
330
0
        goto cleanup;
331
0
    }
332
333
0
    while(head != NULL) {
334
0
        cur_tmp = head->next;
335
0
        if(head->node.type == MBEDTLS_X509_SAN_IP_ADDRESS)
336
0
            mbedtls_free(head->node.host);
337
0
        mbedtls_free(head);
338
0
        head = cur_tmp;
339
0
    }
340
341
#if MBEDTLS_VERSION_NUMBER >= 0x03040000
342
    unsigned char *serial = (unsigned char *)"1";
343
    size_t serial_len = 1;
344
    mbedtls_x509write_crt_set_serial_raw(&crt, serial, serial_len);
345
#else
346
0
    mbedtls_mpi serial_mpi;
347
0
    mbedtls_mpi_init(&serial_mpi);
348
0
    mbedtls_mpi_lset(&serial_mpi, 1);
349
0
    mbedtls_x509write_crt_set_serial(&crt, &serial_mpi);
350
0
    mbedtls_mpi_free(&serial_mpi);
351
0
#endif
352
353
    /* Get the current time */
354
0
    time_t rawTime;
355
0
    struct tm *timeInfo;
356
0
    time(&rawTime);
357
0
    timeInfo = gmtime(&rawTime);
358
359
    /* Format the current timestamp */
360
0
    char current_timestamp[15];  // YYYYMMDDhhmmss + '\0'
361
0
    strftime(current_timestamp, sizeof(current_timestamp), "%Y%m%d%H%M%S", timeInfo);
362
363
    /* Calculate the future timestamp */
364
0
    timeInfo->tm_mday += expiresInDays;
365
0
    time_t future_time = mktime(timeInfo);
366
367
    /* Format the future timestamp */
368
0
    char future_timestamp[15];  // YYYYMMDDhhmmss + '\0'
369
0
    strftime(future_timestamp, sizeof(future_timestamp), "%Y%m%d%H%M%S", gmtime(&future_time));
370
371
0
    if(mbedtls_x509write_crt_set_validity(&crt, current_timestamp, future_timestamp) != 0) {
372
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
373
0
                     "Setting 'not before' and 'not after' failed.");
374
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
375
0
        goto cleanup;
376
0
    }
377
378
0
    if(mbedtls_x509write_crt_set_basic_constraints(&crt, 0, -1) != 0) {
379
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
380
0
                     "Setting basic constraints failed.");
381
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
382
0
        goto cleanup;
383
0
    }
384
385
    /* ECC certificates need keyAgreement for ECDH instead of keyEncipherment */
386
0
    unsigned int keyUsageFlags = keyTypeEC
387
0
        ? (MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION
388
0
           | MBEDTLS_X509_KU_KEY_AGREEMENT | MBEDTLS_X509_KU_KEY_CERT_SIGN)
389
0
        : (MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION
390
0
           | MBEDTLS_X509_KU_KEY_ENCIPHERMENT | MBEDTLS_X509_KU_DATA_ENCIPHERMENT
391
0
           | MBEDTLS_X509_KU_KEY_CERT_SIGN | MBEDTLS_X509_KU_CRL_SIGN);
392
0
    if(mbedtls_x509write_crt_set_key_usage(&crt, keyUsageFlags) != 0) {
393
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
394
0
                     "Setting key usage failed.");
395
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
396
0
        goto cleanup;
397
0
    }
398
399
0
    mbedtls_asn1_sequence *ext_key_usage;
400
0
    ext_key_usage = (mbedtls_asn1_sequence *)mbedtls_calloc(1, sizeof(mbedtls_asn1_sequence));
401
0
    ext_key_usage->buf.tag = MBEDTLS_ASN1_OID;
402
0
    SET_OID(ext_key_usage->buf, MBEDTLS_OID_SERVER_AUTH);
403
0
    ext_key_usage->next = (mbedtls_asn1_sequence *)mbedtls_calloc(1, sizeof(mbedtls_asn1_sequence));
404
0
    ext_key_usage->next->buf.tag = MBEDTLS_ASN1_OID;
405
0
    SET_OID(ext_key_usage->next->buf, MBEDTLS_OID_CLIENT_AUTH);
406
407
0
    if(mbedtls_x509write_crt_set_ext_key_usage(&crt, ext_key_usage) != 0) {
408
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
409
0
                     "Setting extended key usage failed.");
410
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
411
0
        mbedtls_free(ext_key_usage->next);
412
0
        mbedtls_free(ext_key_usage);
413
0
        goto cleanup;
414
0
    }
415
416
0
    mbedtls_free(ext_key_usage->next);
417
0
    mbedtls_free(ext_key_usage);
418
419
0
    mbedtls_x509write_crt_set_subject_key(&crt, &key);
420
0
    mbedtls_x509write_crt_set_issuer_key(&crt, &key);
421
422
423
    /* Write private key */
424
0
    if ((write_private_key(&key, certFormat, outPrivateKey)) != 0) {
425
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
426
0
                     "Create Certificate: Writing private key failed.");
427
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
428
0
        goto cleanup;
429
0
    }
430
431
    /* Write Certificate */
432
0
    if ((write_certificate(&crt, certFormat, outCertificate,
433
0
                                 mbedtls_ctr_drbg_random, &ctr_drbg)) != 0) {
434
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
435
0
                     "Create Certificate: Writing certificate failed.");
436
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
437
0
        goto cleanup;
438
0
    }
439
440
0
    mbedtls_ctr_drbg_free(&ctr_drbg);
441
0
    mbedtls_entropy_free(&entropy);
442
0
    mbedtls_x509write_crt_free(&crt);
443
0
    mbedtls_pk_free(&key);
444
445
0
cleanup:
446
0
    mbedtls_ctr_drbg_free(&ctr_drbg);
447
0
    mbedtls_entropy_free(&entropy);
448
0
    mbedtls_x509write_crt_free(&crt);
449
0
    mbedtls_pk_free(&key);
450
0
    return errRet;
451
0
}
452
453
0
static int write_private_key(mbedtls_pk_context *key, UA_CertificateFormat keyFormat, UA_ByteString *outPrivateKey) {
454
0
    int ret;
455
0
    unsigned char output_buf[16000];
456
0
    unsigned char *c = output_buf;
457
0
    size_t len = 0;
458
459
0
    memset(output_buf, 0, sizeof(output_buf));
460
0
    switch(keyFormat) {
461
0
    case UA_CERTIFICATEFORMAT_DER: {
462
0
        if((ret = mbedtls_pk_write_key_der(key, output_buf, sizeof(output_buf))) < 0) {
463
0
            return ret;
464
0
        }
465
466
0
        len = (size_t)ret;
467
0
        c = output_buf + sizeof(output_buf) - len;
468
0
        break;
469
0
    }
470
0
    case UA_CERTIFICATEFORMAT_PEM: {
471
0
        if((ret = mbedtls_pk_write_key_pem(key, output_buf, sizeof(output_buf))) != 0) {
472
0
            return ret;
473
0
        }
474
475
0
        len = strlen((char *)output_buf);
476
0
        break;
477
0
    }
478
0
    }
479
480
0
    outPrivateKey->length = len;
481
0
    UA_ByteString_allocBuffer(outPrivateKey, outPrivateKey->length);
482
0
    memcpy(outPrivateKey->data, c, outPrivateKey->length);
483
484
0
    return 0;
485
0
}
486
487
static int write_certificate(mbedtls_x509write_cert *crt, UA_CertificateFormat certFormat,
488
                      UA_ByteString *outCertificate, int (*f_rng)(void *, unsigned char *, size_t),
489
0
                      void *p_rng) {
490
0
    int ret;
491
0
    unsigned char output_buf[4096];
492
0
    unsigned char *c = output_buf;
493
0
    size_t len = 0;
494
495
0
    memset(output_buf, 0, sizeof(output_buf));
496
0
    switch(certFormat) {
497
0
    case UA_CERTIFICATEFORMAT_DER: {
498
0
        if((ret = mbedtls_x509write_crt_der(crt, output_buf, sizeof(output_buf), f_rng, p_rng)) < 0) {
499
0
            return ret;
500
0
        }
501
502
0
        len = (size_t)ret;
503
0
        c = output_buf + sizeof(output_buf) - len;
504
0
        break;
505
0
    }
506
0
    case UA_CERTIFICATEFORMAT_PEM: {
507
0
        if((ret = mbedtls_x509write_crt_pem(crt, output_buf, sizeof(output_buf), f_rng, p_rng)) < 0) {
508
0
            return ret;
509
0
        }
510
511
0
        len = strlen((char *)output_buf);
512
0
        break;
513
0
    }
514
0
    }
515
516
0
    outCertificate->length = len;
517
0
    UA_ByteString_allocBuffer(outCertificate, outCertificate->length);
518
0
    memcpy(outCertificate->data, c, outCertificate->length);
519
520
0
    return 0;
521
0
}
522
523
#if MBEDTLS_VERSION_NUMBER < 0x03030000
524
int mbedtls_x509write_crt_set_ext_key_usage(mbedtls_x509write_cert *ctx,
525
0
                                            const mbedtls_asn1_sequence *exts) {
526
0
    unsigned char buf[256];
527
0
    unsigned char *c = buf + sizeof(buf);
528
0
    int ret;
529
0
    size_t len = 0;
530
0
    const mbedtls_asn1_sequence *last_ext = NULL;
531
0
    const mbedtls_asn1_sequence *ext;
532
533
0
    memset(buf, 0, sizeof(buf));
534
535
    /* We need at least one extension: SEQUENCE SIZE (1..MAX) OF KeyPurposeId */
536
0
    if(!exts) {
537
0
        return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
538
0
    }
539
540
    /* Iterate over exts backwards, so we write them out in the requested order */
541
0
    while(last_ext != exts) {
542
0
        for(ext = exts; ext->next != last_ext; ext = ext->next) {
543
0
        }
544
0
        if(ext->buf.tag != MBEDTLS_ASN1_OID) {
545
0
            return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
546
0
        }
547
0
        MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_raw_buffer(&c, buf, ext->buf.p, ext->buf.len));
548
0
        MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, ext->buf.len));
549
0
        MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_OID));
550
0
        last_ext = ext;
551
0
    }
552
553
0
    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
554
0
    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
555
556
0
    return mbedtls_x509write_crt_set_extension(ctx, MBEDTLS_OID_EXTENDED_KEY_USAGE,
557
0
                                               MBEDTLS_OID_SIZE(MBEDTLS_OID_EXTENDED_KEY_USAGE), 1, c, len);
558
0
}
559
560
#endif
561
562
0
static size_t mbedtls_get_san_list_deep(const mbedtls_write_san_list* sanlist) {
563
0
    size_t ret = 0;
564
0
    const mbedtls_write_san_list* cur = sanlist;
565
0
    while (cur) {
566
0
        ++ret;
567
0
        cur = cur->next;
568
0
    }
569
570
0
    return ret;
571
0
}
572
573
0
int mbedtls_x509write_crt_set_subject_alt_name(mbedtls_x509write_cert *ctx, const mbedtls_write_san_list* sanlist) {
574
0
    int ret = 0;
575
0
    size_t sandeep = 0;
576
0
    const mbedtls_write_san_list* cur = sanlist;
577
0
    unsigned char* buf;
578
0
    unsigned char* pc;
579
0
    size_t len;
580
0
    size_t buflen = 0;
581
582
    /* How many alt names to be written */
583
0
    sandeep = mbedtls_get_san_list_deep(sanlist);
584
0
    if (sandeep == 0)
585
0
        return ret;
586
587
0
    buflen = MBEDTLS_SAN_MAX_LEN * sandeep + sandeep;
588
0
    buf = (unsigned char *)mbedtls_calloc(1, buflen);
589
0
    if(!buf)
590
0
        return MBEDTLS_ERR_ASN1_ALLOC_FAILED;
591
592
0
    memset(buf, 0, buflen);
593
0
    pc = buf + buflen;
594
595
0
    len = 0;
596
0
    while(cur) {
597
0
        switch (cur->node.type) {
598
0
        case MBEDTLS_X509_SAN_DNS_NAME:
599
0
        case MBEDTLS_X509_SAN_RFC822_NAME:
600
0
        case MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER:
601
0
        case MBEDTLS_X509_SAN_IP_ADDRESS:
602
0
            MBEDTLS_ASN1_CHK_CLEANUP_ADD(len,
603
0
                                         mbedtls_asn1_write_raw_buffer(&pc, buf, (const unsigned char *)cur->node.host,
604
0
                                                                       cur->node.hostlen));
605
0
            MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_len(&pc, buf, cur->node.hostlen));
606
0
            MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_tag(&pc, buf,
607
0
                                                                     MBEDTLS_ASN1_CONTEXT_SPECIFIC | cur->node.type));
608
0
            break;
609
0
        default:
610
            /* Error out on an unsupported SAN */
611
0
            ret = MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE;
612
0
            goto cleanup;
613
0
        }
614
615
0
        cur = cur->next;
616
0
    }
617
618
0
    MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_len(&pc, buf, len));
619
0
    MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_tag(&pc, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));
620
621
0
    ret = mbedtls_x509write_crt_set_extension(ctx, MBEDTLS_OID_SUBJECT_ALT_NAME,
622
0
                                              MBEDTLS_OID_SIZE(MBEDTLS_OID_SUBJECT_ALT_NAME), 0, buf + buflen - len, len);
623
624
0
    mbedtls_free(buf);
625
0
    return ret;
626
627
0
cleanup:
628
    mbedtls_free(buf);
629
0
    return ret;
630
0
}
631
632
#endif