Coverage Report

Created: 2026-08-13 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open62541/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
0
    for(size_t i = 0; i < subjectSize; i++) {
167
0
        if(subject[i].length > 0 && !subject[i].data)
168
0
            return UA_STATUSCODE_BADINVALIDARGUMENT;
169
0
    }
170
0
    for(size_t i = 0; i < subjectAltNameSize; i++) {
171
0
        if(subjectAltName[i].length > 0 && !subjectAltName[i].data)
172
0
            return UA_STATUSCODE_BADINVALIDARGUMENT;
173
0
    }
174
175
    /* Use the maximum size */
176
0
    UA_UInt16 keySizeBits = 4096;
177
    /* Default to 1 year */
178
0
    UA_UInt16 expiresInDays = 365;
179
    /* Key type: 0 = RSA (default), 1 = EC */
180
0
    int keyTypeEC = 0;
181
0
    UA_String eccCurve = UA_STRING_STATIC("prime256v1");
182
183
0
    if(params) {
184
0
        const UA_UInt16 *keySizeBitsValue = (const UA_UInt16 *)UA_KeyValueMap_getScalar(
185
0
            params, UA_QUALIFIEDNAME(0, "key-size-bits"), &UA_TYPES[UA_TYPES_UINT16]);
186
0
        if(keySizeBitsValue)
187
0
            keySizeBits = *keySizeBitsValue;
188
189
0
        const UA_UInt16 *expiresInDaysValue = (const UA_UInt16 *)UA_KeyValueMap_getScalar(
190
0
            params, UA_QUALIFIEDNAME(0, "expires-in-days"), &UA_TYPES[UA_TYPES_UINT16]);
191
0
        if(expiresInDaysValue)
192
0
            expiresInDays = *expiresInDaysValue;
193
194
0
        const UA_String *keyTypeValue = (const UA_String *)UA_KeyValueMap_getScalar(
195
0
            params, UA_QUALIFIEDNAME(0, "key-type"), &UA_TYPES[UA_TYPES_STRING]);
196
0
        if(keyTypeValue && uaStringEqualsCI(keyTypeValue, "ec"))
197
0
            keyTypeEC = 1;
198
199
0
        const UA_String *eccCurveValue = (const UA_String *)UA_KeyValueMap_getScalar(
200
0
            params, UA_QUALIFIEDNAME(0, "ecc-curve"), &UA_TYPES[UA_TYPES_STRING]);
201
0
        if(eccCurveValue && eccCurveValue->length > 0)
202
0
            eccCurve = *eccCurveValue;
203
0
    }
204
205
0
    UA_ByteString_init(outPrivateKey);
206
0
    UA_ByteString_init(outCertificate);
207
208
0
    UA_String fullAltSubj = UA_STRING_NULL;
209
0
    UA_Int32 serial = 1;
210
211
    /** \TODO: Seed Random generator
212
    * See: (https://www.openssl.org/docs/man1.1.0/man3/RAND_add.html) */
213
0
    BIO *memCert = NULL;
214
0
    BIO *memPKey = NULL;
215
216
0
    UA_StatusCode errRet = UA_STATUSCODE_GOOD;
217
218
0
    X509 *x509 = X509_new();
219
220
0
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
221
0
    EVP_PKEY *pkey = NULL;
222
0
    if(keyTypeEC) {
223
0
        pkey = UA_ECC_Generate_Key(logger, &eccCurve);
224
0
        if(!pkey) {
225
0
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
226
0
                         "Create Certificate: ECC key generation failed.");
227
0
            errRet = UA_STATUSCODE_BADINTERNALERROR;
228
0
            X509_free(x509);
229
0
            return errRet;
230
0
        }
231
0
    } else {
232
0
        pkey = UA_RSA_Generate_Key(keySizeBits);
233
0
    }
234
0
    if((pkey == NULL) || (x509 == NULL)) {
235
0
        errRet = UA_STATUSCODE_BADOUTOFMEMORY;
236
0
        goto cleanup;
237
0
    }    
238
#else
239
    if(keyTypeEC) {
240
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
241
                     "Create Certificate: ECC key generation requires OpenSSL >= 3.0");
242
        X509_free(x509);
243
        return UA_STATUSCODE_BADNOTIMPLEMENTED;
244
    }
245
    BIGNUM *exponent = BN_new();
246
    EVP_PKEY *pkey = EVP_PKEY_new();
247
    RSA *rsa = RSA_new();
248
    if(!pkey || !x509 || !exponent || !rsa) {
249
        errRet = UA_STATUSCODE_BADOUTOFMEMORY;
250
        goto cleanup;
251
    }
252
253
    UA_LOG_INFO(logger, UA_LOGCATEGORY_SECURECHANNEL,
254
                "Create Certificate: Generating RSA key. This may take a while.");
255
256
    if(BN_set_word(exponent, RSA_F4) != 1) {
257
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
258
                     "Create Certificate: Setting RSA exponent failed.");
259
        errRet = UA_STATUSCODE_BADINTERNALERROR;
260
        goto cleanup;
261
    }
262
263
    if(RSA_generate_key_ex(rsa, (int) keySizeBits, exponent, NULL) != 1) {
264
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
265
                     "Create Certificate: Generating RSA key failed.");
266
        errRet = UA_STATUSCODE_BADINTERNALERROR;
267
        goto cleanup;
268
    }
269
270
    if(EVP_PKEY_assign_RSA(pkey, rsa) != 1) {
271
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
272
                     "Create Certificate: Assign RSA key failed.");
273
        errRet = UA_STATUSCODE_BADINTERNALERROR;
274
        goto cleanup;
275
    }
276
    /* rsa will be freed by pkey */
277
    rsa = NULL;
278
279
#endif  /* end of OPENSSL_VERSION_NUMBER >= 0x30000000L */
280
281
    /* x509v3 has version 2
282
     * (https://www.openssl.org/docs/man1.1.0/man3/X509_set_version.html) */
283
0
    if(X509_set_version(x509, 2) != 1) {
284
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
285
0
                     "Create Certificate: Setting version failed.");
286
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
287
0
        goto cleanup;
288
0
    }
289
290
0
    if(ASN1_INTEGER_set(X509_get_serialNumber(x509), serial) != 1) {
291
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
292
0
                     "Create Certificate: Setting serial number failed.");
293
        /* Only memory errors are possible */
294
0
        errRet = UA_STATUSCODE_BADOUTOFMEMORY;
295
0
        goto cleanup;
296
0
    }
297
298
0
    if(X509_gmtime_adj(X509_get_notBefore(x509), 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_time_adj_ex(X509_get_notAfter(x509), (int)expiresInDays, 0, NULL) ==
306
0
       NULL) {
307
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
308
0
                     "Create Certificate: Setting 'not before' failed.");
309
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
310
0
        goto cleanup;
311
0
    }
312
313
0
    if(X509_set_pubkey(x509, pkey) != 1) {
314
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
315
0
                     "Create Certificate: Setting publik key failed.");
316
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
317
0
        goto cleanup;
318
0
    }
319
320
0
    X509_NAME *name = X509_get_subject_name(x509);
321
0
    if(name == NULL) {
322
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
323
0
                     "Create Certificate: Getting name failed.");
324
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
325
0
        goto cleanup;
326
0
    }
327
328
0
    for(UA_UInt32 iSubject = 0; iSubject < subjectSize; ++iSubject) {
329
0
        UA_Int32 sep = UA_String_chr(&subject[iSubject], '=');
330
0
        char field[16];
331
0
        if(sep == -1 || sep == 0 ||
332
0
            ((size_t) sep == (subject[iSubject].length - 1)) || sep >= 15) {
333
0
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
334
0
                         "Create Certificate: Subject must contain one '=' with "
335
0
                         "content before and after.");
336
0
            errRet = UA_STATUSCODE_BADINTERNALERROR;
337
0
            goto cleanup;
338
0
        }
339
0
        memcpy(field, subject[iSubject].data, (size_t) sep);
340
0
        field[sep] = 0;
341
0
        UA_Byte* pData = &subject[iSubject].data[sep + 1];
342
0
        if(X509_NAME_add_entry_by_txt(
343
0
               name, field, MBSTRING_ASC,
344
0
               (const unsigned char *)pData,
345
0
               (int) subject[iSubject].length - (int) sep - 1, -1, 0) != 1) {
346
0
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
347
0
                         "Create Certificate: Setting subject failed.");
348
0
            errRet = UA_STATUSCODE_BADINTERNALERROR;
349
0
            goto cleanup;
350
0
        }
351
0
    }
352
    /* Self signed, so issuer == subject */
353
0
    if(X509_set_issuer_name(x509, name) != 1) {
354
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
355
0
                     "Create Certificate: Setting name failed.");
356
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
357
0
        goto cleanup;
358
0
    }
359
360
0
    errRet = add_x509V3ext(logger, x509, NID_basic_constraints, "CA:FALSE");
361
0
    if(errRet != UA_STATUSCODE_GOOD) {
362
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
363
0
                     "Create Certificate: Setting 'Basic Constraints' failed.");
364
0
        goto cleanup;
365
0
    }
366
367
    /* See https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.3 for
368
     * possible values. ECC certificates need keyAgreement for ECDH. */
369
0
    const char *keyUsageStr = keyTypeEC
370
0
        ? "digitalSignature,nonRepudiation,keyAgreement,keyCertSign"
371
0
        : "digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyCertSign";
372
0
    errRet = add_x509V3ext(logger, x509, NID_key_usage, (char*)(uintptr_t)keyUsageStr);
373
0
    if(errRet != UA_STATUSCODE_GOOD) {
374
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
375
0
                     "Create Certificate: Setting 'Key Usage' failed.");
376
0
        goto cleanup;
377
0
    }
378
379
0
    errRet = add_x509V3ext(logger, x509, NID_ext_key_usage, "serverAuth,clientAuth");
380
0
    if(errRet != UA_STATUSCODE_GOOD) {
381
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
382
0
                     "Create Certificate: Setting 'Extended Key Usage' failed.");
383
0
        goto cleanup;
384
0
    }
385
386
0
    errRet = add_x509V3ext(logger, x509, NID_subject_key_identifier, "hash");
387
0
    if(errRet != UA_STATUSCODE_GOOD) {
388
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
389
0
                     "Create Certificate: Setting 'Subject Key Identifier' failed.");
390
0
        goto cleanup;
391
0
    }
392
393
0
    errRet = join_string_with_sep(subjectAltName, subjectAltNameSize, ',', &fullAltSubj);
394
0
    if(errRet != UA_STATUSCODE_GOOD) {
395
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
396
0
                     "Create Certificate: Joining altSubject failed.");
397
0
        goto cleanup;
398
0
    }
399
400
0
    errRet = add_x509V3ext(logger, x509, NID_subject_alt_name, (char*) fullAltSubj.data);
401
0
    if(errRet != UA_STATUSCODE_GOOD) {
402
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
403
0
                     "Create Certificate: Setting 'Subject Alternative Name' failed.");
404
0
        goto cleanup;
405
0
    }
406
407
    /* Select the digest for signing.
408
     * EdDSA (Ed25519/Ed448): pass NULL (intrinsic hash).
409
     * ECDSA P-384 / brainpoolP384r1: SHA-384.
410
     * Everything else (RSA, P-256, brainpoolP256r1): SHA-256. */
411
0
    const EVP_MD *signMd = EVP_sha256();
412
0
    if(keyTypeEC) {
413
0
        if(uaStringEqualsCI(&eccCurve, "ed25519") ||
414
0
           uaStringEqualsCI(&eccCurve, "ed448"))
415
0
            signMd = NULL; /* EdDSA uses intrinsic hash */
416
0
        else if(uaStringEqualsCI(&eccCurve, "secp384r1") ||
417
0
                uaStringEqualsCI(&eccCurve, "nistp384") ||
418
0
                uaStringEqualsCI(&eccCurve, "brainpoolp384r1"))
419
0
            signMd = EVP_sha384();
420
0
    }
421
422
0
    if(X509_sign(x509, pkey, signMd) == 0) {
423
0
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
424
0
                     "Create Certificate: Signing failed.");
425
0
        errRet = UA_STATUSCODE_BADINTERNALERROR;
426
0
        goto cleanup;
427
0
    }
428
429
0
    switch(certFormat) {
430
0
        case UA_CERTIFICATEFORMAT_DER: {
431
0
            unsigned char *p;
432
            /* Private Key */
433
            /* get length */
434
0
            outPrivateKey->length = (size_t)i2d_PrivateKey(pkey, NULL);
435
0
            if((int)outPrivateKey->length <= 0) {
436
0
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
437
0
                            "Create Certificate: Create private DER key failed.");
438
0
                errRet = UA_STATUSCODE_BADINTERNALERROR;
439
0
                goto cleanup;
440
0
            }
441
            /* allocate buffer */
442
0
            UA_ByteString_allocBuffer(outPrivateKey, outPrivateKey->length);
443
0
            memset(outPrivateKey->data, 0, outPrivateKey->length);
444
0
            p = outPrivateKey->data;
445
0
            i2d_PrivateKey(pkey, &p);
446
447
            /* Certificate */
448
            /* get length */
449
0
            outCertificate->length = (size_t)i2d_X509(x509, NULL);
450
0
            if((int)outCertificate->length <= 0) {
451
0
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
452
0
                            "Create Certificate: Create DER-certificate failed.");
453
0
                errRet = UA_STATUSCODE_BADINTERNALERROR;
454
0
                goto cleanup;
455
0
            }
456
            /* allocate buffer */
457
0
            UA_ByteString_allocBuffer(outCertificate, outCertificate->length);
458
0
            memset(outCertificate->data, 0, outCertificate->length);
459
0
            p = outCertificate->data;
460
0
            i2d_X509(x509, &p);
461
0
            break;
462
0
        }
463
0
        case UA_CERTIFICATEFORMAT_PEM: {
464
            /* Private Key */
465
0
            memPKey = BIO_new(BIO_s_mem());
466
0
            if(!memPKey) {
467
0
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
468
0
                            "Create Certificate: Allocate Membuffer for PKey failed.");
469
0
                errRet = UA_STATUSCODE_BADOUTOFMEMORY;
470
0
                goto cleanup;
471
0
            }
472
473
0
            if(PEM_write_bio_PrivateKey(memPKey, pkey, NULL, NULL, 0, 0, NULL) != 1) {
474
0
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
475
0
                            "Create Certificate: Generate PEM-PrivateKey failed.");
476
0
                errRet = UA_STATUSCODE_BADINTERNALERROR;
477
0
                goto cleanup;
478
0
            }
479
480
0
            UA_ByteString tmpPem = UA_BYTESTRING_NULL;
481
0
            tmpPem.length = (size_t) BIO_get_mem_data(memPKey, &tmpPem.data);
482
0
            errRet = UA_ByteString_copy(&tmpPem, outPrivateKey);
483
0
            if(errRet != UA_STATUSCODE_GOOD) {
484
0
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
485
0
                            "Create Certificate: Copy PEM PKey failed.");
486
0
                goto cleanup;
487
0
            }
488
489
            /* Certificate */
490
0
            memCert = BIO_new(BIO_s_mem());
491
0
            if(!memCert) {
492
0
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
493
0
                            "Create Certificate: Allocate Membuffer for Cert failed.");
494
0
                errRet = UA_STATUSCODE_BADOUTOFMEMORY;
495
0
                goto cleanup;
496
0
            }
497
498
0
            if(PEM_write_bio_X509(memCert, x509) != 1) {
499
0
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
500
0
                            "Create Certificate: Generate PEM-Certifcate failed.");
501
0
                errRet = UA_STATUSCODE_BADINTERNALERROR;
502
0
                goto cleanup;
503
0
            }
504
505
0
            tmpPem.length = (size_t) BIO_get_mem_data(memCert, &tmpPem.data);
506
0
            errRet = UA_ByteString_copy(&tmpPem, outCertificate);
507
0
            if(errRet != UA_STATUSCODE_GOOD) {
508
0
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
509
0
                            "Create Certificate: Copy PEM Certificate failed.");
510
0
                goto cleanup;
511
0
            }
512
0
            break;
513
0
        }
514
0
    }
515
516
0
cleanup:
517
0
    UA_String_clear(&fullAltSubj);
518
#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
519
    RSA_free(rsa);
520
    BN_free(exponent);    
521
#endif
522
0
    X509_free(x509);
523
0
    EVP_PKEY_free(pkey);
524
0
    BIO_free(memCert);
525
0
    BIO_free(memPKey);
526
0
    return errRet;
527
0
}
528
529
#endif