Coverage Report

Created: 2026-08-14 07:31

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open62541_15/plugins/crypto/openssl/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 2021 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati)
6
 *    Copyright 2022 (c) Wind River Systems, Inc.
7
 *    Copyright 2026 (c) o6 Automation GmbH (Author: Andreas Ebner)
8
 *
9
 */
10
11
#include <open62541/plugin/create_certificate.h>
12
13
#include "securitypolicy_common.h"
14
15
#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)
16
17
#include <openssl/pem.h>
18
#include <openssl/x509v3.h>
19
#include <openssl/err.h>
20
21
/**
22
 * Join an array of UA_String to a single NULL-Terminated UA_String
23
 * separated by character sep
24
 */
25
static UA_StatusCode
26
join_string_with_sep(const UA_String *strings, size_t stringsSize,
27
0
                     char sep, UA_String *out) {
28
0
    if(!out)
29
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
30
31
0
    UA_String_clear(out);
32
0
    size_t totalSize = stringsSize;
33
0
    for(size_t iStr = 0; iStr < stringsSize; ++iStr) {
34
0
        totalSize += strings[iStr].length;
35
0
    }
36
37
0
    UA_ByteString_allocBuffer(out, totalSize);
38
0
    if(!out->data) {
39
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
40
0
    }
41
42
0
    size_t pos = 0;
43
0
    for(size_t iStr = 0; iStr < stringsSize; ++iStr) {
44
0
        memcpy(&out->data[pos], strings[iStr].data, strings[iStr].length);
45
0
        pos += strings[iStr].length;
46
0
        out->data[pos] = (UA_Byte) sep;
47
0
        ++pos;
48
0
    }
49
0
    out->data[out->length-1] = 0;
50
51
0
    return UA_STATUSCODE_GOOD;
52
0
}
53
54
/**
55
 * Search for a character in a string (like strchr).
56
 * \todo Handle UTF-8
57
 *
58
 * \return index of the character or -1 on case of an error.
59
 */
60
61
static UA_Int32
62
0
UA_String_chr(const UA_String *pUaStr, char needl) {
63
0
    UA_Byte byteNeedl = (UA_Byte)needl;
64
0
    for(size_t i = 0; (size_t)i < pUaStr->length; ++i) {
65
0
        if(pUaStr->data[i] == byteNeedl) {
66
0
            return (UA_Int32) i;
67
0
        }
68
0
    }
69
0
    return -1;
70
0
}
71
72
/* char *value cannot be const due to openssl 1.0 compatibility */
73
static UA_StatusCode
74
0
add_x509V3ext(const UA_Logger *logger, X509 *x509, int nid, char *value) {
75
0
    X509_EXTENSION *ex;
76
0
    X509V3_CTX ctx;
77
0
    X509V3_set_ctx_nodb(&ctx);
78
0
    X509V3_set_ctx(&ctx, x509, x509, NULL, NULL, 0);
79
0
    ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
80
0
    if(!ex)
81
0
    {
82
#if UA_LOGLEVEL <= 300
83
        const char * file =  NULL;
84
        int line =  0;
85
        const char * data =  NULL;
86
        int flags =  0;
87
        get_error_line_data(&file, &line, &data, &flags);
88
        UA_LOG_INFO(logger, UA_LOGCATEGORY_SECURECHANNEL,
89
                     "Internal SSL error file: %s:%d data: %s", file, line, data);
90
#endif
91
0
        return UA_STATUSCODE_BADINTERNALERROR;
92
0
    }
93
0
    X509_add_ext(x509, ex, -1);
94
0
    X509_EXTENSION_free(ex);
95
0
    return UA_STATUSCODE_GOOD;
96
0
}
97
98
/* Check if a UA_String equals a C string literal (case-insensitive) */
99
static UA_Boolean
100
0
uaStringEqualsCI(const UA_String *uaStr, const char *cStr) {
101
0
    size_t cLen = strlen(cStr);
102
0
    if(uaStr->length != cLen)
103
0
        return false;
104
0
    for(size_t i = 0; i < cLen; i++) {
105
0
        char a = (char)uaStr->data[i];
106
0
        char b = cStr[i];
107
0
        if(a >= 'A' && a <= 'Z') a = (char)(a + 32);
108
0
        if(b >= 'A' && b <= 'Z') b = (char)(b + 32);
109
0
        if(a != b) return false;
110
0
    }
111
0
    return true;
112
0
}
113
114
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
115
116
/* generate the RSA key */
117
118
0
static EVP_PKEY * UA_RSA_Generate_Key (size_t keySizeBits){
119
0
    return EVP_RSA_gen(keySizeBits);
120
0
}
121
122
/* Generate an ECC key for the given curve name.
123
 * Returns NULL on failure. */
124
static EVP_PKEY *
125
0
UA_ECC_Generate_Key(const UA_Logger *logger, const UA_String *curveName) {
126
    /* EdDSA curves use a different keygen path */
127
0
    if(uaStringEqualsCI(curveName, "ed25519"))
128
0
        return EVP_PKEY_Q_keygen(NULL, NULL, "ED25519");
129
0
    if(uaStringEqualsCI(curveName, "ed448"))
130
0
        return EVP_PKEY_Q_keygen(NULL, NULL, "ED448");
131
132
    /* ECDSA curves: map name to OpenSSL curve name */
133
0
    const char *osslCurve = NULL;
134
0
    if(uaStringEqualsCI(curveName, "prime256v1") ||
135
0
       uaStringEqualsCI(curveName, "nistp256"))
136
0
        osslCurve = "prime256v1";
137
0
    else if(uaStringEqualsCI(curveName, "secp384r1") ||
138
0
            uaStringEqualsCI(curveName, "nistp384"))
139
0
        osslCurve = "secp384r1";
140
0
    else if(uaStringEqualsCI(curveName, "brainpoolp256r1"))
141
0
        osslCurve = "brainpoolP256r1";
142
0
    else if(uaStringEqualsCI(curveName, "brainpoolp384r1"))
143
0
        osslCurve = "brainpoolP384r1";
144
145
0
    if(!osslCurve) {
146
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
147
0
                     "Create Certificate: Unsupported ECC curve.");
148
0
        return NULL;
149
0
    }
150
151
0
    return EVP_EC_gen(osslCurve);
152
0
}
153
154
#endif
155
156
UA_StatusCode
157
UA_CreateCertificate(const UA_Logger *logger, const UA_String *subject,
158
                     size_t subjectSize, const UA_String *subjectAltName,
159
                     size_t subjectAltNameSize, UA_CertificateFormat certFormat,
160
                     UA_KeyValueMap *params, UA_ByteString *outPrivateKey,
161
0
                     UA_ByteString *outCertificate) {
162
0
    if(!outPrivateKey || !outCertificate || !logger || !subjectAltName || !subject ||
163
0
       subjectAltNameSize == 0 || subjectSize == 0 ||
164
0
       (certFormat != UA_CERTIFICATEFORMAT_DER && certFormat != UA_CERTIFICATEFORMAT_PEM))
165
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
166
167
    /* Use the maximum size */
168
0
    UA_UInt16 keySizeBits = 4096;
169
    /* Default to 1 year */
170
0
    UA_UInt16 expiresInDays = 365;
171
    /* Key type: 0 = RSA (default), 1 = EC */
172
0
    int keyTypeEC = 0;
173
0
    UA_String eccCurve = UA_STRING_STATIC("prime256v1");
174
175
0
    if(params) {
176
0
        const UA_UInt16 *keySizeBitsValue = (const UA_UInt16 *)UA_KeyValueMap_getScalar(
177
0
            params, UA_QUALIFIEDNAME(0, "key-size-bits"), &UA_TYPES[UA_TYPES_UINT16]);
178
0
        if(keySizeBitsValue)
179
0
            keySizeBits = *keySizeBitsValue;
180
181
0
        const UA_UInt16 *expiresInDaysValue = (const UA_UInt16 *)UA_KeyValueMap_getScalar(
182
0
            params, UA_QUALIFIEDNAME(0, "expires-in-days"), &UA_TYPES[UA_TYPES_UINT16]);
183
0
        if(expiresInDaysValue)
184
0
            expiresInDays = *expiresInDaysValue;
185
186
0
        const UA_String *keyTypeValue = (const UA_String *)UA_KeyValueMap_getScalar(
187
0
            params, UA_QUALIFIEDNAME(0, "key-type"), &UA_TYPES[UA_TYPES_STRING]);
188
0
        if(keyTypeValue && uaStringEqualsCI(keyTypeValue, "ec"))
189
0
            keyTypeEC = 1;
190
191
0
        const UA_String *eccCurveValue = (const UA_String *)UA_KeyValueMap_getScalar(
192
0
            params, UA_QUALIFIEDNAME(0, "ecc-curve"), &UA_TYPES[UA_TYPES_STRING]);
193
0
        if(eccCurveValue && eccCurveValue->length > 0)
194
0
            eccCurve = *eccCurveValue;
195
0
    }
196
197
0
    UA_ByteString_init(outPrivateKey);
198
0
    UA_ByteString_init(outCertificate);
199
200
0
    UA_String fullAltSubj = UA_STRING_NULL;
201
0
    UA_Int32 serial = 1;
202
203
    /** \TODO: Seed Random generator
204
    * See: (https://www.openssl.org/docs/man1.1.0/man3/RAND_add.html) */
205
0
    BIO *memCert = NULL;
206
0
    BIO *memPKey = NULL;
207
208
0
    UA_StatusCode errRet = UA_STATUSCODE_GOOD;
209
210
0
    X509 *x509 = X509_new();
211
212
0
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
213
0
    EVP_PKEY *pkey = NULL;
214
0
    if(keyTypeEC) {
215
0
        pkey = UA_ECC_Generate_Key(logger, &eccCurve);
216
0
        if(!pkey) {
217
0
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
218
0
                         "Create Certificate: ECC key generation failed.");
219
0
            errRet = UA_STATUSCODE_BADINTERNALERROR;
220
0
            X509_free(x509);
221
0
            return errRet;
222
0
        }
223
0
    } else {
224
0
        pkey = UA_RSA_Generate_Key(keySizeBits);
225
0
    }
226
0
    if((pkey == NULL) || (x509 == NULL)) {
227
0
        errRet = UA_STATUSCODE_BADOUTOFMEMORY;
228
0
        goto cleanup;
229
0
    }    
230
#else
231
    if(keyTypeEC) {
232
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
233
                     "Create Certificate: ECC key generation requires OpenSSL >= 3.0");
234
        X509_free(x509);
235
        return UA_STATUSCODE_BADNOTIMPLEMENTED;
236
    }
237
    BIGNUM *exponent = BN_new();
238
    EVP_PKEY *pkey = EVP_PKEY_new();
239
    RSA *rsa = RSA_new();
240
    if(!pkey || !x509 || !exponent || !rsa) {
241
        errRet = UA_STATUSCODE_BADOUTOFMEMORY;
242
        goto cleanup;
243
    }
244
245
    UA_LOG_INFO(logger, UA_LOGCATEGORY_SECURECHANNEL,
246
                "Create Certificate: Generating RSA key. This may take a while.");
247
248
    if(BN_set_word(exponent, RSA_F4) != 1) {
249
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
250
                     "Create Certificate: Setting RSA exponent failed.");
251
        errRet = UA_STATUSCODE_BADINTERNALERROR;
252
        goto cleanup;
253
    }
254
255
    if(RSA_generate_key_ex(rsa, (int) keySizeBits, exponent, NULL) != 1) {
256
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
257
                     "Create Certificate: Generating RSA key failed.");
258
        errRet = UA_STATUSCODE_BADINTERNALERROR;
259
        goto cleanup;
260
    }
261
262
    if(EVP_PKEY_assign_RSA(pkey, rsa) != 1) {
263
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
264
                     "Create Certificate: Assign RSA key failed.");
265
        errRet = UA_STATUSCODE_BADINTERNALERROR;
266
        goto cleanup;
267
    }
268
    /* rsa will be freed by pkey */
269
    rsa = NULL;
270
271
#endif  /* end of OPENSSL_VERSION_NUMBER >= 0x30000000L */
272
273
    /* x509v3 has version 2
274
     * (https://www.openssl.org/docs/man1.1.0/man3/X509_set_version.html) */
275
0
    if(X509_set_version(x509, 2) != 1) {
276
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
277
0
                     "Create Certificate: Setting version failed.");
278
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
279
0
        goto cleanup;
280
0
    }
281
282
0
    if(ASN1_INTEGER_set(X509_get_serialNumber(x509), serial) != 1) {
283
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
284
0
                     "Create Certificate: Setting serial number failed.");
285
        /* Only memory errors are possible */
286
0
        errRet = UA_STATUSCODE_BADOUTOFMEMORY;
287
0
        goto cleanup;
288
0
    }
289
290
0
    if(X509_gmtime_adj(X509_get_notBefore(x509), 0) == NULL) {
291
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
292
0
                     "Create Certificate: Setting 'not before' failed.");
293
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
294
0
        goto cleanup;
295
0
    }
296
297
0
    if(X509_time_adj_ex(X509_get_notAfter(x509), (int)expiresInDays, 0, NULL) ==
298
0
       NULL) {
299
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
300
0
                     "Create Certificate: Setting 'not before' failed.");
301
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
302
0
        goto cleanup;
303
0
    }
304
305
0
    if(X509_set_pubkey(x509, pkey) != 1) {
306
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
307
0
                     "Create Certificate: Setting publik key failed.");
308
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
309
0
        goto cleanup;
310
0
    }
311
312
0
    X509_NAME *name = X509_get_subject_name(x509);
313
0
    if(name == NULL) {
314
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
315
0
                     "Create Certificate: Getting name failed.");
316
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
317
0
        goto cleanup;
318
0
    }
319
320
0
    for(UA_UInt32 iSubject = 0; iSubject < subjectSize; ++iSubject) {
321
0
        UA_Int32 sep = UA_String_chr(&subject[iSubject], '=');
322
0
        char field[16];
323
0
        if(sep == -1 || sep == 0 ||
324
0
            ((size_t) sep == (subject[iSubject].length - 1)) || sep >= 15) {
325
0
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
326
0
                         "Create Certificate: Subject must contain one '=' with "
327
0
                         "content before and after.");
328
0
            errRet = UA_STATUSCODE_BADINTERNALERROR;
329
0
            goto cleanup;
330
0
        }
331
0
        memcpy(field, subject[iSubject].data, (size_t) sep);
332
0
        field[sep] = 0;
333
0
        UA_Byte* pData = &subject[iSubject].data[sep + 1];
334
0
        if(X509_NAME_add_entry_by_txt(
335
0
               name, field, MBSTRING_ASC,
336
0
               (const unsigned char *)pData,
337
0
               (int) subject[iSubject].length - (int) sep - 1, -1, 0) != 1) {
338
0
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
339
0
                         "Create Certificate: Setting subject failed.");
340
0
            errRet = UA_STATUSCODE_BADINTERNALERROR;
341
0
            goto cleanup;
342
0
        }
343
0
    }
344
    /* Self signed, so issuer == subject */
345
0
    if(X509_set_issuer_name(x509, name) != 1) {
346
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
347
0
                     "Create Certificate: Setting name failed.");
348
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
349
0
        goto cleanup;
350
0
    }
351
352
0
    errRet = add_x509V3ext(logger, x509, NID_basic_constraints, "CA:FALSE");
353
0
    if(errRet != UA_STATUSCODE_GOOD) {
354
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
355
0
                     "Create Certificate: Setting 'Basic Constraints' failed.");
356
0
        goto cleanup;
357
0
    }
358
359
    /* See https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.3 for
360
     * possible values. ECC certificates need keyAgreement for ECDH. */
361
0
    const char *keyUsageStr = keyTypeEC
362
0
        ? "digitalSignature,nonRepudiation,keyAgreement,keyCertSign"
363
0
        : "digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyCertSign";
364
0
    errRet = add_x509V3ext(logger, x509, NID_key_usage, (char*)(uintptr_t)keyUsageStr);
365
0
    if(errRet != UA_STATUSCODE_GOOD) {
366
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
367
0
                     "Create Certificate: Setting 'Key Usage' failed.");
368
0
        goto cleanup;
369
0
    }
370
371
0
    errRet = add_x509V3ext(logger, x509, NID_ext_key_usage, "serverAuth,clientAuth");
372
0
    if(errRet != UA_STATUSCODE_GOOD) {
373
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
374
0
                     "Create Certificate: Setting 'Extended Key Usage' failed.");
375
0
        goto cleanup;
376
0
    }
377
378
0
    errRet = add_x509V3ext(logger, x509, NID_subject_key_identifier, "hash");
379
0
    if(errRet != UA_STATUSCODE_GOOD) {
380
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
381
0
                     "Create Certificate: Setting 'Subject Key Identifier' failed.");
382
0
        goto cleanup;
383
0
    }
384
385
0
    errRet = join_string_with_sep(subjectAltName, subjectAltNameSize, ',', &fullAltSubj);
386
0
    if(errRet != UA_STATUSCODE_GOOD) {
387
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
388
0
                     "Create Certificate: Joining altSubject failed.");
389
0
        goto cleanup;
390
0
    }
391
392
0
    errRet = add_x509V3ext(logger, x509, NID_subject_alt_name, (char*) fullAltSubj.data);
393
0
    if(errRet != UA_STATUSCODE_GOOD) {
394
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
395
0
                     "Create Certificate: Setting 'Subject Alternative Name' failed.");
396
0
        goto cleanup;
397
0
    }
398
399
    /* Select the digest for signing.
400
     * EdDSA (Ed25519/Ed448): pass NULL (intrinsic hash).
401
     * ECDSA P-384 / brainpoolP384r1: SHA-384.
402
     * Everything else (RSA, P-256, brainpoolP256r1): SHA-256. */
403
0
    const EVP_MD *signMd = EVP_sha256();
404
0
    if(keyTypeEC) {
405
0
        if(uaStringEqualsCI(&eccCurve, "ed25519") ||
406
0
           uaStringEqualsCI(&eccCurve, "ed448"))
407
0
            signMd = NULL; /* EdDSA uses intrinsic hash */
408
0
        else if(uaStringEqualsCI(&eccCurve, "secp384r1") ||
409
0
                uaStringEqualsCI(&eccCurve, "nistp384") ||
410
0
                uaStringEqualsCI(&eccCurve, "brainpoolp384r1"))
411
0
            signMd = EVP_sha384();
412
0
    }
413
414
0
    if(X509_sign(x509, pkey, signMd) == 0) {
415
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
416
0
                     "Create Certificate: Signing failed.");
417
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
418
0
        goto cleanup;
419
0
    }
420
421
0
    switch(certFormat) {
422
0
        case UA_CERTIFICATEFORMAT_DER: {
423
0
            unsigned char *p;
424
            /* Private Key */
425
            /* get length */
426
0
            outPrivateKey->length = (size_t)i2d_PrivateKey(pkey, NULL);
427
0
            if((int)outPrivateKey->length <= 0) {
428
0
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
429
0
                            "Create Certificate: Create private DER key failed.");
430
0
                errRet = UA_STATUSCODE_BADINTERNALERROR;
431
0
                goto cleanup;
432
0
            }
433
            /* allocate buffer */
434
0
            UA_ByteString_allocBuffer(outPrivateKey, outPrivateKey->length);
435
0
            memset(outPrivateKey->data, 0, outPrivateKey->length);
436
0
            p = outPrivateKey->data;
437
0
            i2d_PrivateKey(pkey, &p);
438
439
            /* Certificate */
440
            /* get length */
441
0
            outCertificate->length = (size_t)i2d_X509(x509, NULL);
442
0
            if((int)outCertificate->length <= 0) {
443
0
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
444
0
                            "Create Certificate: Create DER-certificate failed.");
445
0
                errRet = UA_STATUSCODE_BADINTERNALERROR;
446
0
                goto cleanup;
447
0
            }
448
            /* allocate buffer */
449
0
            UA_ByteString_allocBuffer(outCertificate, outCertificate->length);
450
0
            memset(outCertificate->data, 0, outCertificate->length);
451
0
            p = outCertificate->data;
452
0
            i2d_X509(x509, &p);
453
0
            break;
454
0
        }
455
0
        case UA_CERTIFICATEFORMAT_PEM: {
456
            /* Private Key */
457
0
            memPKey = BIO_new(BIO_s_mem());
458
0
            if(!memPKey) {
459
0
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
460
0
                            "Create Certificate: Allocate Membuffer for PKey failed.");
461
0
                errRet = UA_STATUSCODE_BADOUTOFMEMORY;
462
0
                goto cleanup;
463
0
            }
464
465
0
            if(PEM_write_bio_PrivateKey(memPKey, pkey, NULL, NULL, 0, 0, NULL) != 1) {
466
0
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
467
0
                            "Create Certificate: Generate PEM-PrivateKey failed.");
468
0
                errRet = UA_STATUSCODE_BADINTERNALERROR;
469
0
                goto cleanup;
470
0
            }
471
472
0
            UA_ByteString tmpPem = UA_BYTESTRING_NULL;
473
0
            tmpPem.length = (size_t) BIO_get_mem_data(memPKey, &tmpPem.data);
474
0
            errRet = UA_ByteString_copy(&tmpPem, outPrivateKey);
475
0
            if(errRet != UA_STATUSCODE_GOOD) {
476
0
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
477
0
                            "Create Certificate: Copy PEM PKey failed.");
478
0
                goto cleanup;
479
0
            }
480
481
            /* Certificate */
482
0
            memCert = BIO_new(BIO_s_mem());
483
0
            if(!memCert) {
484
0
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
485
0
                            "Create Certificate: Allocate Membuffer for Cert failed.");
486
0
                errRet = UA_STATUSCODE_BADOUTOFMEMORY;
487
0
                goto cleanup;
488
0
            }
489
490
0
            if(PEM_write_bio_X509(memCert, x509) != 1) {
491
0
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
492
0
                            "Create Certificate: Generate PEM-Certifcate failed.");
493
0
                errRet = UA_STATUSCODE_BADINTERNALERROR;
494
0
                goto cleanup;
495
0
            }
496
497
0
            tmpPem.length = (size_t) BIO_get_mem_data(memCert, &tmpPem.data);
498
0
            errRet = UA_ByteString_copy(&tmpPem, outCertificate);
499
0
            if(errRet != UA_STATUSCODE_GOOD) {
500
0
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
501
0
                            "Create Certificate: Copy PEM Certificate failed.");
502
0
                goto cleanup;
503
0
            }
504
0
            break;
505
0
        }
506
0
    }
507
508
0
cleanup:
509
0
    UA_String_clear(&fullAltSubj);
510
#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
511
    RSA_free(rsa);
512
    BN_free(exponent);    
513
#endif
514
0
    X509_free(x509);
515
0
    EVP_PKEY_free(pkey);
516
0
    BIO_free(memCert);
517
0
    BIO_free(memPKey);
518
0
    return errRet;
519
0
}
520
521
#endif