Coverage Report

Created: 2026-09-28 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open62541_15/plugins/crypto/openssl/certificategroup.c
Line
Count
Source
1
/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
2
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
3
 *
4
 *    Copyright 2020 (c) Wind River Systems, Inc.
5
 *    Copyright 2020 (c) basysKom GmbH
6
 *    Copyright 2024 (c) Fraunhofer IOSB (Author: Noel Graf)
7
 *    Copyright 2024 (c) Siemens AG (Authors: Tin Raic, Thomas Zeschg)
8
 */
9
10
#include <open62541/util.h>
11
#include <open62541/plugin/certificategroup_default.h>
12
13
#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)
14
#include <openssl/x509.h>
15
#include <openssl/x509_vfy.h>
16
#include <openssl/x509v3.h>
17
#include <openssl/pem.h>
18
19
#include "libc_time.h"
20
#include "securitypolicy_common.h"
21
22
7
#define SHA1_DIGEST_LENGTH 20
23
24
/* Configuration parameters */
25
26
#define MEMORYCERTSTORE_PARAMETERSSIZE 2
27
7.09k
#define MEMORYCERTSTORE_PARAMINDEX_MAXTRUSTLISTSIZE 0
28
7.09k
#define MEMORYCERTSTORE_PARAMINDEX_MAXREJECTEDLISTSIZE 1
29
30
static const struct {
31
    UA_QualifiedName name;
32
    const UA_DataType *type;
33
    UA_Boolean required;
34
} MemoryCertStoreParameters[MEMORYCERTSTORE_PARAMETERSSIZE] = {
35
    {{0, UA_STRING_STATIC("maxTrustListSize")}, &UA_TYPES[UA_TYPES_UINT16], false},
36
    {{0, UA_STRING_STATIC("maxRejectedListSize")}, &UA_TYPES[UA_TYPES_STRING], false}
37
};
38
39
struct MemoryCertStore;
40
typedef struct MemoryCertStore MemoryCertStore;
41
42
struct MemoryCertStore {
43
    UA_TrustListDataType trustList;
44
    size_t rejectedCertificatesSize;
45
    UA_ByteString *rejectedCertificates;
46
47
    UA_UInt32 maxTrustListSize;
48
    UA_UInt32 maxRejectedListSize;
49
50
    UA_Boolean reloadRequired;
51
52
    STACK_OF(X509) *trustedCertificates;
53
    STACK_OF(X509) *issuerCertificates;
54
    STACK_OF(X509_CRL) *crls;
55
};
56
57
static UA_Boolean
58
openSSLCheckCA(X509 *cert);
59
60
static UA_StatusCode
61
0
MemoryCertStore_removeFromTrustList(UA_CertificateGroup *certGroup, const UA_TrustListDataType *trustList) {
62
    /* Check parameter */
63
0
    if(certGroup == NULL || trustList == NULL) {
64
0
        return UA_STATUSCODE_BADINTERNALERROR;
65
0
    }
66
67
0
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
68
0
    context->reloadRequired = true;
69
0
    return UA_TrustListDataType_remove(trustList, &context->trustList);
70
0
}
71
72
static UA_StatusCode
73
0
MemoryCertStore_getTrustList(UA_CertificateGroup *certGroup, UA_TrustListDataType *trustList) {
74
    /* Check parameter */
75
0
    if(certGroup == NULL || trustList == NULL) {
76
0
        return UA_STATUSCODE_BADINTERNALERROR;
77
0
    }
78
79
0
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
80
0
    return UA_TrustListDataType_copy(&context->trustList, trustList);
81
0
}
82
83
static UA_StatusCode
84
7.09k
MemoryCertStore_setTrustList(UA_CertificateGroup *certGroup, const UA_TrustListDataType *trustList) {
85
    /* Check parameter */
86
7.09k
    if(certGroup == NULL || trustList == NULL) {
87
0
        return UA_STATUSCODE_BADINTERNALERROR;
88
0
    }
89
90
7.09k
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
91
7.09k
    if(context->maxTrustListSize != 0 && UA_TrustListDataType_getSize(trustList) > context->maxTrustListSize) {
92
0
        return UA_STATUSCODE_BADINTERNALERROR;
93
0
    }
94
7.09k
    context->reloadRequired = true;
95
    /* Remove the section of the trust list that needs to be reset, while keeping the remaining parts intact */
96
7.09k
    return UA_TrustListDataType_set(trustList, &context->trustList);
97
7.09k
}
98
99
static UA_StatusCode
100
0
MemoryCertStore_addToTrustList(UA_CertificateGroup *certGroup, const UA_TrustListDataType *trustList) {
101
    /* Check parameter */
102
0
    if(certGroup == NULL || trustList == NULL) {
103
0
        return UA_STATUSCODE_BADINTERNALERROR;
104
0
    }
105
106
0
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
107
0
    if(context->maxTrustListSize != 0 && UA_TrustListDataType_getSize(&context->trustList) + UA_TrustListDataType_getSize(trustList) > context->maxTrustListSize) {
108
0
        return UA_STATUSCODE_BADINTERNALERROR;
109
0
    }
110
0
    context->reloadRequired = true;
111
0
    return UA_TrustListDataType_add(trustList, &context->trustList);
112
0
}
113
114
static UA_StatusCode
115
0
MemoryCertStore_getRejectedList(UA_CertificateGroup *certGroup, UA_ByteString **rejectedList, size_t *rejectedListSize) {
116
    /* Check parameter */
117
0
    if(certGroup == NULL || rejectedList == NULL || rejectedListSize == NULL) {
118
0
        return UA_STATUSCODE_BADINTERNALERROR;
119
0
    }
120
121
0
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
122
0
    UA_StatusCode retval = UA_Array_copy(context->rejectedCertificates, context->rejectedCertificatesSize,
123
0
                                         (void**)rejectedList, &UA_TYPES[UA_TYPES_BYTESTRING]);
124
125
0
    if(retval == UA_STATUSCODE_GOOD)
126
0
        *rejectedListSize = context->rejectedCertificatesSize;
127
128
0
    return retval;
129
0
}
130
131
static UA_StatusCode
132
0
openSSLCheckCrlMatch(X509 *cert, X509_CRL *crl) {
133
0
    X509_NAME *certSubject = X509_get_subject_name(cert);
134
0
    if(!certSubject)
135
0
        return UA_STATUSCODE_BADINTERNALERROR;
136
137
0
    X509_NAME *crlIssuer = X509_CRL_get_issuer(crl);
138
0
    if(!crlIssuer) {
139
0
        return UA_STATUSCODE_BADINTERNALERROR;
140
0
    }
141
142
0
    if(X509_NAME_cmp(certSubject, crlIssuer) == 0)
143
0
        return UA_STATUSCODE_GOOD;
144
145
0
    return UA_STATUSCODE_BADNOMATCH;
146
0
}
147
148
static UA_StatusCode
149
openSSLFindCrls(UA_CertificateGroup *certGroup, const UA_ByteString *certificate,
150
                const UA_ByteString *crlList, const size_t crlListSize,
151
0
                UA_ByteString **crls, size_t *crlsSize) {
152
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
153
154
0
    X509 *cert = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
155
0
    if(!cert)
156
0
        return UA_STATUSCODE_BADINTERNALERROR;
157
158
    /* Check if the certificate is a CA certificate.
159
     * Only a CA certificate can have a CRL. */
160
0
    if(!openSSLCheckCA(cert)) {
161
0
        UA_LOG_WARNING(certGroup->logging, UA_LOGCATEGORY_SECURITYPOLICY,
162
0
                       "The certificate is not a CA certificate and therefore does not have a CRL.");
163
0
        X509_free(cert);
164
0
        return UA_STATUSCODE_GOOD;
165
0
    }
166
167
0
    UA_Boolean foundMatch = false;
168
0
    for(size_t i = 0; i < crlListSize; i++) {
169
0
        X509_CRL *crl = UA_OpenSSL_LoadCrl(&crlList[i]);
170
0
        if(!crl) {
171
0
            X509_free(cert);
172
0
            return UA_STATUSCODE_BADINTERNALERROR;
173
0
        }
174
175
0
        retval = openSSLCheckCrlMatch(cert, crl);
176
0
        X509_CRL_free(crl);
177
0
        if(retval != UA_STATUSCODE_GOOD) {
178
0
            continue;
179
0
        }
180
181
        /* Continue the search, as a certificate may be associated with multiple CRLs. */
182
0
        foundMatch = true;
183
0
        retval = UA_Array_appendCopy((void **)crls, crlsSize, &crlList[i],
184
0
                                 &UA_TYPES[UA_TYPES_BYTESTRING]);
185
0
        if(retval != UA_STATUSCODE_GOOD) {
186
0
            X509_free(cert);
187
0
            return retval;
188
0
        }
189
0
    }
190
0
    X509_free(cert);
191
0
    if(!foundMatch)
192
0
        return UA_STATUSCODE_BADNOMATCH;
193
194
0
    return UA_STATUSCODE_GOOD;
195
0
}
196
197
static UA_StatusCode
198
MemoryCertStore_getCertificateCrls(UA_CertificateGroup *certGroup, const UA_ByteString *certificate,
199
                                   const UA_Boolean isTrusted, UA_ByteString **crls,
200
0
                                   size_t *crlsSize) {
201
    /* Check parameter */
202
0
    if(certGroup == NULL || certificate == NULL || crls == NULL) {
203
0
        return UA_STATUSCODE_BADINTERNALERROR;
204
0
    }
205
206
0
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
207
208
0
    if(isTrusted) {
209
0
        return openSSLFindCrls(certGroup, certificate,
210
0
                               context->trustList.trustedCrls,
211
0
                               context->trustList.trustedCrlsSize, crls,
212
0
                               crlsSize);
213
0
    }
214
0
    return openSSLFindCrls(certGroup, certificate,
215
0
                           context->trustList.issuerCrls,
216
0
                           context->trustList.issuerCrlsSize, crls,
217
0
                           crlsSize);
218
0
}
219
220
static UA_StatusCode
221
0
MemoryCertStore_addToRejectedList(UA_CertificateGroup *certGroup, const UA_ByteString *certificate) {
222
    /* Check parameter */
223
0
    if(certGroup == NULL || certificate == NULL) {
224
0
        return UA_STATUSCODE_BADINTERNALERROR;
225
0
    }
226
227
0
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
228
229
    /* check duplicate certificate */
230
0
    for(size_t i = 0; i < context->rejectedCertificatesSize; i++) {
231
0
        if(UA_ByteString_equal(certificate, &context->rejectedCertificates[i]))
232
0
            return UA_STATUSCODE_GOOD; /* certificate already exist */
233
0
    }
234
235
    /* Store rejected certificate */
236
0
    if(context->maxRejectedListSize == 0 || context->rejectedCertificatesSize < context->maxRejectedListSize) {
237
0
        return UA_Array_appendCopy((void**)&context->rejectedCertificates, &context->rejectedCertificatesSize,
238
0
                                   certificate, &UA_TYPES[UA_TYPES_BYTESTRING]);
239
0
    }
240
0
    UA_Array_delete(context->rejectedCertificates, context->rejectedCertificatesSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
241
0
    context->rejectedCertificates = NULL;
242
0
    context->rejectedCertificatesSize = 0;
243
0
    return UA_Array_appendCopy((void**)&context->rejectedCertificates, &context->rejectedCertificatesSize,
244
0
                               certificate, &UA_TYPES[UA_TYPES_BYTESTRING]);
245
0
}
246
247
static void
248
7.09k
MemoryCertStore_clear(UA_CertificateGroup *certGroup) {
249
    /* check parameter */
250
7.09k
    if(certGroup == NULL) {
251
0
        return;
252
0
    }
253
254
7.09k
    UA_NodeId_clear(&certGroup->certificateGroupId);
255
256
7.09k
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
257
7.09k
    if(context) {
258
7.09k
        UA_TrustListDataType_clear(&context->trustList);
259
260
7.09k
        UA_Array_delete(context->rejectedCertificates, context->rejectedCertificatesSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
261
7.09k
        context->rejectedCertificates = NULL;
262
7.09k
        context->rejectedCertificatesSize = 0;
263
264
7.09k
        sk_X509_pop_free(context->trustedCertificates, X509_free);
265
7.09k
        sk_X509_pop_free(context->issuerCertificates, X509_free);
266
7.09k
        sk_X509_CRL_pop_free(context->crls, X509_CRL_free);
267
268
7.09k
        UA_free(context);
269
7.09k
        certGroup->context = NULL;
270
7.09k
    }
271
7.09k
}
272
273
static UA_StatusCode
274
7.09k
reloadCertificates(UA_CertificateGroup *certGroup) {
275
    /* Check parameter */
276
7.09k
    if(certGroup == NULL) {
277
0
        return UA_STATUSCODE_BADINTERNALERROR;
278
0
    }
279
280
7.09k
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
281
282
7.09k
    sk_X509_pop_free(context->trustedCertificates, X509_free);
283
7.09k
    context->trustedCertificates = sk_X509_new_null();
284
7.09k
    if(context->trustedCertificates == NULL) {
285
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
286
0
    }
287
7.09k
    for(size_t i = 0; i < context->trustList.trustedCertificatesSize; i++) {
288
0
        X509 *cert = UA_OpenSSL_LoadCertificate(&context->trustList.trustedCertificates[i], EVP_PKEY_NONE);
289
0
        if(cert == NULL)
290
0
            return UA_STATUSCODE_BADINTERNALERROR;
291
0
        sk_X509_push(context->trustedCertificates, cert);
292
0
    }
293
294
7.09k
    sk_X509_pop_free(context->issuerCertificates, X509_free);
295
7.09k
    context->issuerCertificates = sk_X509_new_null();
296
7.09k
    if(context->issuerCertificates == NULL) {
297
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
298
0
    }
299
7.09k
    for(size_t i = 0; i < context->trustList.issuerCertificatesSize; i++) {
300
0
        X509 *cert = UA_OpenSSL_LoadCertificate(&context->trustList.issuerCertificates[i], EVP_PKEY_NONE);
301
0
        if(cert == NULL)
302
0
            return UA_STATUSCODE_BADINTERNALERROR;
303
0
        sk_X509_push(context->issuerCertificates, cert);
304
0
    }
305
306
7.09k
    sk_X509_CRL_pop_free(context->crls, X509_CRL_free);
307
7.09k
    context->crls = sk_X509_CRL_new_null();
308
7.09k
    if(context->crls == NULL) {
309
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
310
0
    }
311
7.09k
    for(size_t i = 0; i < context->trustList.trustedCrlsSize; i++) {
312
0
        X509_CRL * crl = NULL;
313
0
        BIO * bio = NULL;
314
315
0
        bio = BIO_new_mem_buf((void *)context->trustList.trustedCrls[i].data,
316
0
                              (int)context->trustList.trustedCrls[i].length);
317
        /* Try to load DER encoded CRL */
318
0
        crl = d2i_X509_CRL_bio(bio, NULL);
319
0
        if(crl == NULL) {
320
            /* Try to load PEM encoded CRL */
321
0
            (void)BIO_reset(bio);
322
0
            crl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL);
323
0
        }
324
0
        BIO_free(bio);
325
326
0
        if(crl == NULL)
327
0
            return UA_STATUSCODE_BADINTERNALERROR;
328
0
        sk_X509_CRL_push(context->crls, crl);
329
0
    }
330
7.09k
    for(size_t i = 0; i < context->trustList.issuerCrlsSize; i++) {
331
0
        X509_CRL * crl = NULL;
332
0
        BIO * bio = NULL;
333
334
0
        bio = BIO_new_mem_buf((void *)context->trustList.issuerCrls[i].data,
335
0
                              (int)context->trustList.issuerCrls[i].length);
336
        /* Try to load DER encoded Issuer CRL */
337
0
        crl = d2i_X509_CRL_bio(bio, NULL);
338
0
        if(crl == NULL) {
339
            /* Try to load PEM encoded Issuer CRL */
340
0
            (void)BIO_reset(bio);
341
0
            crl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL);
342
0
        }
343
0
        BIO_free(bio);
344
345
0
        if(crl == NULL)
346
0
            return UA_STATUSCODE_BADINTERNALERROR;
347
0
        sk_X509_CRL_push(context->crls, crl);
348
0
    }
349
350
7.09k
    return UA_STATUSCODE_GOOD;
351
7.09k
}
352
353
/* Find binary substring. Taken and adjusted from
354
 * http://tungchingkai.blogspot.com/2011/07/binary-strstr.html */
355
356
static const unsigned char *
357
0
UA_Bstrstr(const unsigned char *s1, size_t l1, const unsigned char *s2, size_t l2) {
358
0
    if(l2 == 0)
359
0
        return s1;
360
0
    if(l2 > l1)
361
0
        return NULL;
362
0
    size_t limit = l1 - l2 + 1;
363
0
    for(size_t i = 0; i < limit; i++) {
364
0
        if(s1[i] == s2[0] && memcmp(&s1[i], s2, l2) == 0)
365
0
            return &s1[i];
366
0
    }
367
0
    return NULL;
368
0
}
369
370
static const unsigned char openssl_PEM_PRE[28] = "-----BEGIN CERTIFICATE-----";
371
372
/* Extract the leaf certificate from a bytestring that may contain an entire chain */
373
static X509 *
374
0
openSSLLoadLeafCertificate(UA_ByteString cert, size_t *offset) {
375
0
    if(cert.length <= *offset)
376
0
        return NULL;
377
0
    cert.length -= *offset;
378
0
    cert.data += *offset;
379
380
    /* Detect DER encoding. Extract the encoding length and cut. */
381
0
    if(cert.length >= 4 && cert.data[0] == 0x30 && cert.data[1] == 0x82) {
382
        /* The certificate length is encoded after the magic bytes */
383
0
        size_t certLen = 4; /* Magic numbers + length bytes */
384
0
        certLen += (size_t)(((uint16_t)cert.data[2]) << 8);
385
0
        certLen += cert.data[3];
386
0
        if(certLen > cert.length)
387
0
            return NULL;
388
0
        cert.length = certLen;
389
0
        *offset += certLen;
390
0
        const UA_Byte *dataPtr = cert.data;
391
0
        return d2i_X509(NULL, &dataPtr, (long)cert.length);
392
0
    }
393
394
    /* Assume PEM encoding. Detect multiple certificates and cut. */
395
0
    if(cert.length > 27 * 4) {
396
0
        const unsigned char *match =
397
0
            UA_Bstrstr(&cert.data[27*2], cert.length - (27*2),
398
0
                       openssl_PEM_PRE, 27);
399
0
        if(match)
400
0
            cert.length = (uintptr_t)(match - cert.data);
401
0
    }
402
0
    *offset += cert.length;
403
404
0
    BIO *bio = BIO_new_mem_buf((void *) cert.data, (int)cert.length);
405
0
    X509 *result = PEM_read_bio_X509(bio, NULL, NULL, NULL);
406
0
    BIO_free(bio);
407
0
    return result;
408
0
}
409
410
/* The bytestring might contain an entire certificate chain. The first
411
 * stack-element is the leaf certificate itself. The remaining ones are
412
 * potential issuer certificates. */
413
static STACK_OF(X509) *
414
0
openSSLLoadCertificateStack(const UA_ByteString cert) {
415
0
    size_t offset = 0;
416
0
    X509 *x509 = NULL;
417
0
    STACK_OF(X509) *result = sk_X509_new_null();
418
0
    if(!result)
419
0
        return NULL;
420
0
    while((x509 = openSSLLoadLeafCertificate(cert, &offset))) {
421
0
        sk_X509_push(result, x509);
422
0
    }
423
0
    return result;
424
0
}
425
426
/* Return the first matching issuer candidate AFTER prev */
427
static X509 *
428
0
openSSLFindNextIssuer(MemoryCertStore *ctx, STACK_OF(X509) *stack, X509 *x509, X509 *prev) {
429
    /* First check issuers from the stack - provided in the same bytestring as
430
     * the certificate. This can also return x509 itself. */
431
0
    X509_NAME *in = X509_get_issuer_name(x509);
432
0
    do {
433
0
        int size = sk_X509_num(stack);
434
0
        for(int i = 0; i < size; i++) {
435
0
            X509 *candidate = sk_X509_value(stack, i);
436
0
            if(prev) {
437
0
                if(prev == candidate)
438
0
                    prev = NULL; /* This was the last issuer we tried to verify */
439
0
                continue;
440
0
            }
441
            /* This checks subject/issuer name and the key usage of the issuer.
442
             * It does not verify the validity period and if the issuer key was
443
             * used for the signature. We check that afterwards. */
444
0
            if(X509_NAME_cmp(in, X509_get_subject_name(candidate)) == 0)
445
0
                return candidate;
446
0
        }
447
        /* Switch from the stack that came with the cert to the issuer list and
448
         * then to the trust list. */
449
0
        if(stack == ctx->trustedCertificates)
450
0
            stack = NULL;
451
0
        else if(stack == ctx->issuerCertificates)
452
0
            stack = ctx->trustedCertificates;
453
0
        else
454
0
            stack = ctx->issuerCertificates;
455
0
    } while(stack);
456
0
    return NULL;
457
0
}
458
459
/* Is the certificate a CA? */
460
static UA_Boolean
461
114
openSSLCheckCA(X509 *cert) {
462
114
    uint32_t flags = X509_get_extension_flags(cert);
463
    /* The basic constraints must be set with the CA flag true */
464
114
    if(!(flags & EXFLAG_CA))
465
34
        return false;
466
467
    /* The Key Usage extension must be set */
468
80
    if(!(flags & EXFLAG_KUSAGE))
469
66
        return false;
470
471
    /* The Key Usage must include cert signing and CRL issuing */
472
14
    uint32_t usage = X509_get_key_usage(cert);
473
14
    if(!(usage & KU_KEY_CERT_SIGN) || !(usage & KU_CRL_SIGN))
474
9
        return false;
475
476
5
    return true;
477
14
}
478
479
static UA_StatusCode
480
0
openSSLCheckRevoked(UA_CertificateGroup *cg, MemoryCertStore *ctx, X509 *cert) {
481
0
    const ASN1_INTEGER *sn = X509_get0_serialNumber(cert);
482
0
    const X509_NAME *in = X509_get_issuer_name(cert);
483
0
    int size = sk_X509_CRL_num(ctx->crls);
484
485
0
    if(size == 0) {
486
0
        UA_LOG_WARNING(cg->logging, UA_LOGCATEGORY_SECURITYPOLICY,
487
0
                       "Zero revocation lists have been loaded. "
488
0
                       "This seems intentional - omitting the check.");
489
0
        return UA_STATUSCODE_GOOD;
490
0
    }
491
492
    /* Loop over the crl and match the Issuer Name */
493
0
    UA_StatusCode res = UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN;
494
0
    for(int i = 0; i < size; i++) {
495
        /* The crl contains a list of serial numbers from the same issuer */
496
0
        X509_CRL *crl = sk_X509_CRL_value(ctx->crls, i);
497
0
        if(X509_NAME_cmp(in, X509_CRL_get_issuer(crl)) != 0)
498
0
            continue;
499
0
        STACK_OF(X509_REVOKED) *rs = X509_CRL_get_REVOKED(crl);
500
0
        int rsize = sk_X509_REVOKED_num(rs);
501
0
        for(int j = 0; j < rsize; j++) {
502
0
            X509_REVOKED *r = sk_X509_REVOKED_value(rs, j);
503
0
            if(ASN1_INTEGER_cmp(sn, X509_REVOKED_get0_serialNumber(r)) == 0)
504
0
                return UA_STATUSCODE_BADCERTIFICATEREVOKED;
505
0
        }
506
0
        res = UA_STATUSCODE_GOOD; /* There was at least one crl that did not revoke (so far) */
507
0
    }
508
0
    return res;
509
0
}
510
511
0
#define UA_OPENSSL_MAX_CHAIN_LENGTH 10
512
513
static UA_StatusCode
514
openSSL_verifyChain(UA_CertificateGroup *cg, MemoryCertStore *ctx, STACK_OF(X509) *stack,
515
0
                    X509 **old_issuers, X509 *cert, int depth) {
516
    /* Maxiumum chain length */
517
0
    if(depth == UA_OPENSSL_MAX_CHAIN_LENGTH)
518
0
        return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
519
520
    /* Return the most specific error code. BADCERTIFICATECHAININCOMPLETE is
521
     * returned only if all possible chains are incomplete. */
522
0
    X509 *issuer = NULL;
523
0
    UA_StatusCode ret = UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
524
0
    while(ret != UA_STATUSCODE_GOOD) {
525
        /* Find the issuer. We jump back here to find a different path if a
526
         * subsequent check fails. */
527
0
        issuer = openSSLFindNextIssuer(ctx, stack, cert, issuer);
528
0
        if(!issuer)
529
0
            break;
530
531
        /* Verification Step: Certificate Usage
532
         * Can the issuer act as CA? Omit for self-signed leaf certificates. */
533
0
        if((depth > 0 || issuer != cert) && !openSSLCheckCA(issuer)) {
534
0
            ret = UA_STATUSCODE_BADCERTIFICATEISSUERUSENOTALLOWED;
535
0
            continue;
536
0
        }
537
538
        /* Verification Step: Signature */
539
0
        int opensslRet = X509_verify(cert, X509_get0_pubkey(issuer));
540
0
        if(opensslRet == -1) {
541
0
            return UA_STATUSCODE_BADCERTIFICATEINVALID; /* Ill-formed signature */
542
0
        } else if(opensslRet == 0) {
543
0
            ret = UA_STATUSCODE_BADCERTIFICATEINVALID;  /* Wrong issuer, try again */
544
0
            continue;
545
0
        }
546
547
        /* The certificate is self-signed. We have arrived at the top of the
548
         * chain. We check whether the certificate is trusted below. This is the
549
         * only place where we return UA_STATUSCODE_BADCERTIFICATEUNTRUSTED.
550
         * This signals that the chain is complete (but can be still
551
         * untrusted).
552
         *
553
         * Break here as we have reached the end of the chain. Omit the
554
         * Revocation Check for self-signed certificates. */
555
0
        if(cert == issuer || X509_cmp(cert, issuer) == 0) {
556
0
            ret = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED;
557
0
            break;
558
0
        }
559
560
        /* Verification Step: Revocation Check */
561
0
        ret = openSSLCheckRevoked(cg, ctx, cert);
562
0
        if(depth > 0) {
563
0
            if(ret == UA_STATUSCODE_BADCERTIFICATEREVOKED)
564
0
                ret = UA_STATUSCODE_BADCERTIFICATEISSUERREVOKED;
565
0
            if(ret == UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN)
566
0
                ret = UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN;
567
0
        }
568
0
        if(ret != UA_STATUSCODE_GOOD)
569
0
            continue;
570
571
        /* Detect (endless) loops of issuers. The last one can be skipped by the
572
         * check for self-signed just before. */
573
0
        for(int i = 0; i < depth; i++) {
574
0
            if(old_issuers[i] == issuer)
575
0
                return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
576
0
        }
577
0
        old_issuers[depth] = issuer;
578
579
        /* We have found the issuer certificate used for the signature. Recurse
580
         * to the next certificate in the chain (verify the current issuer). */
581
0
        ret = openSSL_verifyChain(cg, ctx, stack, old_issuers, issuer, depth + 1);
582
0
    }
583
584
    /* Is the certificate in the trust list? If yes, then we are done. */
585
0
    if(ret == UA_STATUSCODE_BADCERTIFICATEUNTRUSTED) {
586
0
        for(int i = 0; i < sk_X509_num(ctx->trustedCertificates); i++) {
587
0
            if(X509_cmp(cert, sk_X509_value(ctx->trustedCertificates, i)) == 0) {
588
0
                ret = UA_STATUSCODE_GOOD;
589
0
                break;
590
0
            }
591
0
        }
592
0
    }
593
594
0
    if (ret == UA_STATUSCODE_GOOD) {
595
        /* Verification Step: Validity Period */
596
0
        ASN1_TIME *notBefore = X509_get_notBefore(cert);
597
0
        ASN1_TIME *notAfter = X509_get_notAfter(cert);
598
0
        if(X509_cmp_current_time(notBefore) != -1 || X509_cmp_current_time(notAfter) != 1)
599
0
            return (depth == 0) ? UA_STATUSCODE_BADCERTIFICATETIMEINVALID :
600
0
                UA_STATUSCODE_BADCERTIFICATEISSUERTIMEINVALID;
601
0
    }
602
603
0
    return ret;
604
0
}
605
606
/* This follows Part 6, 6.1.3 Determining if a Certificate is trusted.
607
 * It defines a sequence of steps for certificate verification. */
608
static UA_StatusCode
609
0
verifyCertificate(UA_CertificateGroup *certGroup, const UA_ByteString *certificate) {
610
    /* Check parameter */
611
0
    if(certGroup == NULL || certGroup->context == NULL)
612
0
        return UA_STATUSCODE_BADINTERNALERROR;
613
614
0
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
615
0
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
616
0
    if(context->reloadRequired) {
617
0
        ret = reloadCertificates(certGroup);
618
0
        if(ret != UA_STATUSCODE_GOOD)
619
0
            return ret;
620
0
        context->reloadRequired = false;
621
0
    }
622
623
    /* Verification Step: Certificate Structure */
624
0
    STACK_OF(X509) *stack = openSSLLoadCertificateStack(*certificate);
625
0
    if(!stack || sk_X509_num(stack) < 1) {
626
0
        sk_X509_pop_free(stack, X509_free);
627
0
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
628
0
    }
629
630
    /* Verification Step: Certificate Usage
631
     * Check whether the certificate is a User certificate or a CA certificate.
632
     * Refer the test case CTT/Security/Security Certificate Validation/029.js
633
     * for more details. */
634
0
    X509 *leaf = sk_X509_value(stack, 0);
635
0
    if(openSSLCheckCA(leaf)) {
636
0
        sk_X509_pop_free(stack, X509_free);
637
0
        return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
638
0
    }
639
640
    /* These steps are performed outside of this method.
641
     * Because we need the server or client context.
642
     * - Security Policy
643
     * - Host Name
644
     * - URI */
645
646
    /* Verification Step: Build Certificate Chain
647
     * We perform the checks for each certificate inside. */
648
0
    X509 *old_issuers[UA_OPENSSL_MAX_CHAIN_LENGTH];
649
0
    ret = openSSL_verifyChain(certGroup, context, stack, old_issuers, leaf, 0);
650
0
    sk_X509_pop_free(stack, X509_free);
651
0
    return ret;
652
0
}
653
654
static UA_StatusCode
655
MemoryCertStore_verifyCertificate(UA_CertificateGroup *certGroup,
656
0
                                  const UA_ByteString *certificate) {
657
    /* Check parameter */
658
0
    if(certGroup == NULL || certificate == NULL) {
659
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
660
0
    }
661
662
0
    UA_StatusCode retval = verifyCertificate(certGroup, certificate);
663
0
    if(retval != UA_STATUSCODE_GOOD) {
664
0
        if(MemoryCertStore_addToRejectedList(certGroup, certificate) != UA_STATUSCODE_GOOD) {
665
0
            UA_LOG_WARNING(certGroup->logging, UA_LOGCATEGORY_SECURITYPOLICY,
666
0
                           "Could not append certificate to rejected list");
667
0
        }
668
0
    }
669
0
    return retval;
670
0
}
671
672
UA_StatusCode
673
UA_CertificateGroup_Memorystore(UA_CertificateGroup *certGroup,
674
                                UA_NodeId *certificateGroupId,
675
                                const UA_TrustListDataType *trustList,
676
                                const UA_Logger *logger,
677
7.09k
                                const UA_KeyValueMap *params) {
678
679
7.09k
    if(certGroup == NULL || certificateGroupId == NULL) {
680
0
        return UA_STATUSCODE_BADINTERNALERROR;
681
0
    }
682
683
7.09k
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
684
685
    /* Clear if the plugin is already initialized */
686
7.09k
    if(certGroup->clear)
687
0
        certGroup->clear(certGroup);
688
689
7.09k
    UA_NodeId_copy(certificateGroupId, &certGroup->certificateGroupId);
690
7.09k
    certGroup->logging = logger;
691
692
7.09k
    certGroup->getTrustList = MemoryCertStore_getTrustList;
693
7.09k
    certGroup->setTrustList = MemoryCertStore_setTrustList;
694
7.09k
    certGroup->addToTrustList = MemoryCertStore_addToTrustList;
695
7.09k
    certGroup->removeFromTrustList = MemoryCertStore_removeFromTrustList;
696
7.09k
    certGroup->getRejectedList = MemoryCertStore_getRejectedList;
697
7.09k
    certGroup->getCertificateCrls = MemoryCertStore_getCertificateCrls;
698
7.09k
    certGroup->verifyCertificate = MemoryCertStore_verifyCertificate;
699
7.09k
    certGroup->clear = MemoryCertStore_clear;
700
701
    /* Set PKI Store context data */
702
7.09k
    MemoryCertStore *context = (MemoryCertStore *)UA_calloc(1, sizeof(MemoryCertStore));
703
7.09k
    if(!context) {
704
0
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
705
0
        goto cleanup;
706
0
    }
707
7.09k
    certGroup->context = context;
708
    /* Default values */
709
7.09k
    context->maxTrustListSize = 65535;
710
7.09k
    context->maxRejectedListSize = 100;
711
712
7.09k
    if(params) {
713
7.09k
        const UA_UInt32 *maxTrustListSize = (const UA_UInt32*)
714
7.09k
        UA_KeyValueMap_getScalar(params, MemoryCertStoreParameters[MEMORYCERTSTORE_PARAMINDEX_MAXTRUSTLISTSIZE].name,
715
7.09k
                                 &UA_TYPES[UA_TYPES_UINT32]);
716
717
7.09k
        const UA_UInt32 *maxRejectedListSize = (const UA_UInt32*)
718
7.09k
        UA_KeyValueMap_getScalar(params, MemoryCertStoreParameters[MEMORYCERTSTORE_PARAMINDEX_MAXREJECTEDLISTSIZE].name,
719
7.09k
                                 &UA_TYPES[UA_TYPES_UINT32]);
720
721
7.09k
        if(maxTrustListSize) {
722
0
            context->maxTrustListSize = *maxTrustListSize;
723
0
        }
724
725
7.09k
        if(maxRejectedListSize) {
726
0
            context->maxRejectedListSize = *maxRejectedListSize;
727
0
        }
728
7.09k
    }
729
730
7.09k
    UA_TrustListDataType_add(trustList, &context->trustList);
731
7.09k
    reloadCertificates(certGroup);
732
733
7.09k
    return UA_STATUSCODE_GOOD;
734
735
0
cleanup:
736
0
    certGroup->clear(certGroup);
737
0
    return retval;
738
7.09k
}
739
740
UA_StatusCode
741
UA_CertificateUtils_verifyApplicationUri(const UA_ByteString *certificate,
742
108
                                         const UA_String *applicationURI) {
743
108
    const unsigned char *pData = certificate->data;
744
108
    if(!pData)
745
0
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
746
747
108
    X509 *certificateX509 = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
748
108
    if(!certificateX509)
749
104
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
750
751
4
    GENERAL_NAMES *pNames = (GENERAL_NAMES *)
752
4
        X509_get_ext_d2i(certificateX509, NID_subject_alt_name, NULL, NULL);
753
4
    if(!pNames) {
754
4
        X509_free(certificateX509);
755
4
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
756
4
    }
757
758
0
    UA_String subjectURI = UA_STRING_NULL;
759
0
    for(int i = 0; i < sk_GENERAL_NAME_num(pNames); i++) {
760
0
        GENERAL_NAME *value = sk_GENERAL_NAME_value(pNames, i);
761
0
        if(value->type == GEN_URI) {
762
0
            subjectURI.length = (size_t) (value->d.ia5->length);
763
0
            subjectURI.data = (UA_Byte*)UA_malloc(subjectURI.length);
764
0
            if(!subjectURI.data) {
765
0
                X509_free(certificateX509);
766
0
                sk_GENERAL_NAME_pop_free(pNames, GENERAL_NAME_free);
767
0
                return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
768
0
            }
769
0
            (void)memcpy(subjectURI.data, value->d.ia5->data, subjectURI.length);
770
0
            break;
771
0
        }
772
0
    }
773
774
0
    UA_StatusCode ret = UA_STATUSCODE_BADCERTIFICATEURIINVALID;
775
0
    if(subjectURI.length > 0 &&
776
0
       subjectURI.length == applicationURI->length &&
777
0
       memcmp(subjectURI.data, applicationURI->data, subjectURI.length) == 0)
778
0
        ret = UA_STATUSCODE_GOOD;
779
780
0
    X509_free(certificateX509);
781
0
    sk_GENERAL_NAME_pop_free(pNames, GENERAL_NAME_free);
782
0
    UA_String_clear(&subjectURI);
783
0
    return ret;
784
0
}
785
786
UA_StatusCode
787
UA_CertificateUtils_getExpirationDate(UA_ByteString *certificate,
788
252
                                      UA_DateTime *expiryDateTime) {
789
252
    X509 *x509 = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
790
252
    if(!x509)
791
138
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
792
793
    /* Get the certificate Expiry date */
794
114
    ASN1_TIME *not_after = X509_get_notAfter(x509);
795
796
114
    struct tm dtTime;
797
114
    ASN1_TIME_to_tm(not_after, &dtTime);
798
114
    X509_free(x509);
799
800
114
    struct musl_tm dateTime;
801
114
    memset(&dateTime, 0, sizeof(struct musl_tm));
802
114
    dateTime.tm_year = dtTime.tm_year;
803
114
    dateTime.tm_mon = dtTime.tm_mon;
804
114
    dateTime.tm_mday = dtTime.tm_mday;
805
114
    dateTime.tm_hour = dtTime.tm_hour;
806
114
    dateTime.tm_min = dtTime.tm_min;
807
114
    dateTime.tm_sec = dtTime.tm_sec;
808
809
114
    long long sec_epoch = musl_tm_to_secs(&dateTime);
810
114
    *expiryDateTime = UA_DATETIME_UNIX_EPOCH;
811
114
    *expiryDateTime += sec_epoch * UA_DATETIME_SEC;
812
114
    return UA_STATUSCODE_GOOD;
813
252
}
814
815
UA_StatusCode
816
UA_CertificateUtils_getSubjectName(UA_ByteString *certificate,
817
843
                                   UA_String *subjectName) {
818
843
    X509_NAME *sn = NULL;
819
843
    X509 *x509 = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
820
843
    X509_CRL *x509_crl = NULL;
821
822
843
    if(x509) {
823
36
        sn = X509_get_subject_name(x509);
824
807
    } else {
825
807
        x509_crl = UA_OpenSSL_LoadCrl(certificate);
826
807
        if(!x509_crl)
827
807
            return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
828
0
        sn = X509_CRL_get_issuer(x509_crl);
829
0
    }
830
831
36
    char buf[1024];
832
36
    *subjectName = UA_STRING_ALLOC(X509_NAME_oneline(sn, buf, 1024));
833
834
36
    if(x509)
835
36
        X509_free(x509);
836
36
    if(x509_crl)
837
0
        X509_CRL_free(x509_crl);
838
36
    return UA_STATUSCODE_GOOD;
839
843
}
840
841
UA_StatusCode
842
UA_CertificateUtils_getThumbprint(UA_ByteString *certificate,
843
7
                                  UA_String *thumbprint) {
844
7
    if(certificate == NULL || thumbprint->length != (SHA1_DIGEST_LENGTH * 2))
845
7
        return UA_STATUSCODE_BADINTERNALERROR;
846
847
0
    unsigned char digest[SHA1_DIGEST_LENGTH];
848
0
    unsigned int digestLen;
849
850
0
    X509 *cert = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
851
0
    if(cert) {
852
0
        if(X509_digest(cert, EVP_sha1(), digest, &digestLen) != 1) {
853
0
            X509_free(cert);
854
0
            return UA_STATUSCODE_BADINTERNALERROR;
855
0
        }
856
0
        X509_free(cert);
857
0
    } else {
858
0
        X509_CRL *crl = UA_OpenSSL_LoadCrl(certificate);
859
0
        if(!crl)
860
0
            return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
861
0
        if(X509_CRL_digest(crl, EVP_sha1(), digest, &digestLen) != 1) {
862
0
            X509_CRL_free(crl);
863
0
            return UA_STATUSCODE_BADINTERNALERROR;
864
0
        }
865
0
        X509_CRL_free(crl);
866
0
    }
867
868
0
    UA_String thumb = UA_STRING_NULL;
869
0
    thumb.length = (SHA1_DIGEST_LENGTH * 2) + 1;
870
0
    thumb.data = (UA_Byte*)malloc(sizeof(UA_Byte) * thumb.length);
871
872
    /* Create a string containing a hex representation */
873
0
    char *p = (char*)thumb.data;
874
0
    for(size_t i = 0; i < digestLen; i++) {
875
0
        p += sprintf(p, "%.2X", digest[i]);
876
0
    }
877
878
0
    memcpy(thumbprint->data, thumb.data, thumbprint->length);
879
0
    free(thumb.data);
880
881
0
    return UA_STATUSCODE_GOOD;
882
0
}
883
884
UA_StatusCode
885
UA_CertificateUtils_getKeySize(UA_ByteString *certificate,
886
153
                               size_t *keySize){
887
153
    if(certificate == NULL)
888
0
        return UA_STATUSCODE_BADINTERNALERROR;
889
890
153
    X509 *cert = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
891
153
    if(!cert)
892
148
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
893
894
5
    EVP_PKEY *pkey = X509_get_pubkey(cert);
895
5
    if(!pkey) {
896
2
        X509_free(cert);
897
2
        return UA_STATUSCODE_BADINTERNALERROR;
898
2
    }
899
900
3
    if(EVP_PKEY_base_id(pkey) == EVP_PKEY_RSA) {
901
1
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
902
1
        *keySize = EVP_PKEY_get_size(pkey) * 8;
903
#else
904
        *keySize =  RSA_size(get_pkey_rsa(pkey)) * 8;
905
#endif
906
2
    } else if(EVP_PKEY_base_id(pkey) == EVP_PKEY_EC) {
907
2
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
908
2
        *keySize = EVP_PKEY_get_size(pkey) * 8;
909
#else
910
        *keySize =  ECDSA_size(EVP_PKEY_get0_EC_KEY(pkey)) * 8;
911
#endif
912
2
    } else {
913
0
        EVP_PKEY_free(pkey);
914
0
        X509_free(cert);
915
0
        return UA_STATUSCODE_BADINTERNALERROR; /* Unsupported key type */
916
0
    }
917
918
3
    EVP_PKEY_free(pkey);
919
3
    X509_free(cert);
920
921
3
    return UA_STATUSCODE_GOOD;
922
3
}
923
924
UA_StatusCode
925
UA_CertificateUtils_comparePublicKeys(const UA_ByteString *certificate1,
926
0
                                      const UA_ByteString *certificate2) {
927
0
    if(certificate1 == NULL || certificate2 == NULL)
928
0
        return UA_STATUSCODE_BADINTERNALERROR;
929
930
0
    BIO *dataBio1 = BIO_new_mem_buf(certificate1->data, certificate1->length);
931
0
    if(!dataBio1)
932
0
        return UA_STATUSCODE_BADINTERNALERROR;
933
934
0
    BIO *dataBio2 = BIO_new_mem_buf(certificate2->data, certificate2->length);
935
0
    if(!dataBio2) {
936
0
        BIO_free(dataBio1);
937
0
        return UA_STATUSCODE_BADINTERNALERROR;
938
0
    }
939
940
0
    X509 *cert1 = NULL;
941
0
    X509 *cert2 = NULL;
942
0
    X509_REQ *csr1 = NULL;
943
0
    X509_REQ *csr2 = NULL;
944
    /* Try to read the certificate as PEM first */
945
0
    cert1 = PEM_read_bio_X509(dataBio1, NULL, 0, NULL);
946
0
    if(!cert1) {
947
        /* If PEM read fails, reset BIO and try reading as DER */
948
0
        (void)BIO_reset(dataBio1);
949
0
        cert1 = d2i_X509_bio(dataBio1, NULL);
950
0
    }
951
    /* Try to read as a csr */
952
0
    if(!cert1) {
953
0
        (void)BIO_reset(dataBio1);
954
0
        csr1 = PEM_read_bio_X509_REQ(dataBio1, NULL, 0, NULL);
955
0
        if(!csr1) {
956
0
            (void)BIO_reset(dataBio1);
957
0
            csr1 = d2i_X509_REQ_bio(dataBio1, NULL);
958
0
        }
959
0
    }
960
0
    if(!cert1 && !csr1) {
961
0
        BIO_free(dataBio1);
962
0
        BIO_free(dataBio2);
963
0
        return UA_STATUSCODE_BADINTERNALERROR;
964
0
    }
965
966
0
    cert2 = PEM_read_bio_X509(dataBio2, NULL, 0, NULL);
967
0
    if(!cert2) {
968
        /* If PEM read fails, reset BIO and try reading as DER */
969
0
        (void)BIO_reset(dataBio2);
970
0
        cert2 = d2i_X509_bio(dataBio2, NULL);
971
0
    }
972
    /* Try to load as a csr */
973
0
    if(!cert2) {
974
0
        (void)BIO_reset(dataBio2);
975
0
        csr2 = PEM_read_bio_X509_REQ(dataBio2, NULL, 0, NULL);
976
0
        if(!csr2) {
977
0
            (void)BIO_reset(dataBio2);
978
0
            csr2 = d2i_X509_REQ_bio(dataBio2, NULL);
979
0
        }
980
0
    }
981
0
    if(!cert2 && !csr2) {
982
0
        X509_free(cert1);
983
0
        X509_REQ_free(csr1);
984
0
        BIO_free(dataBio1);
985
0
        BIO_free(dataBio2);
986
0
        return UA_STATUSCODE_BADINTERNALERROR;
987
0
    }
988
989
0
    BIO_free(dataBio1);
990
0
    BIO_free(dataBio2);
991
992
0
    EVP_PKEY *pkey1 = cert1 ? X509_get_pubkey(cert1) : X509_REQ_get_pubkey(csr1);
993
0
    EVP_PKEY *pkey2 = cert2 ? X509_get_pubkey(cert2) : X509_REQ_get_pubkey(csr2);
994
995
0
    X509_free(cert1);
996
0
    X509_free(cert2);
997
0
    X509_REQ_free(csr1);
998
0
    X509_REQ_free(csr2);
999
1000
0
    if(!pkey1 || !pkey2) {
1001
0
        EVP_PKEY_free(pkey1);
1002
0
        EVP_PKEY_free(pkey2);
1003
0
        return UA_STATUSCODE_BADINTERNALERROR;
1004
0
    }
1005
1006
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
1007
0
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
1008
0
    int isEqual = EVP_PKEY_eq(pkey1, pkey2);
1009
0
    if(isEqual == 0)
1010
0
        retval = UA_STATUSCODE_BADNOMATCH;
1011
0
    if(isEqual < 0)
1012
0
        retval = UA_STATUSCODE_BADINTERNALERROR;
1013
#else
1014
    int isEqual = EVP_PKEY_cmp(pkey1, pkey2);
1015
    if(isEqual == 0)
1016
        retval = UA_STATUSCODE_BADNOMATCH;
1017
    if(isEqual < 0)
1018
        retval = UA_STATUSCODE_BADINTERNALERROR;
1019
#endif
1020
1021
0
    EVP_PKEY_free(pkey1);
1022
0
    EVP_PKEY_free(pkey2);
1023
1024
0
    return retval;
1025
0
}
1026
1027
UA_StatusCode
1028
UA_CertificateUtils_checkKeyPair(const UA_ByteString *certificate,
1029
0
                                 const UA_ByteString *privateKey) {
1030
0
    if(certificate == NULL || privateKey == NULL)
1031
0
        return UA_STATUSCODE_BADINTERNALERROR;
1032
1033
0
    X509 *cert = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
1034
0
    if(!cert)
1035
0
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
1036
1037
0
    EVP_PKEY *pkey = UA_OpenSSL_LoadPrivateKey(privateKey);
1038
0
    if(!pkey) {
1039
0
        X509_free(cert);
1040
0
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
1041
0
    }
1042
1043
    /* Verify if the private key matches the public key in the certificate */
1044
0
    if(X509_check_private_key(cert, pkey) != 1) {
1045
0
        X509_free(cert);
1046
0
        EVP_PKEY_free(pkey);
1047
0
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
1048
0
    }
1049
1050
0
    X509_free(cert);
1051
0
    EVP_PKEY_free(pkey);
1052
1053
0
    return UA_STATUSCODE_GOOD;
1054
0
}
1055
1056
UA_StatusCode
1057
1.02k
UA_CertificateUtils_checkCA(const UA_ByteString *certificate) {
1058
1.02k
    if(certificate == NULL)
1059
0
        return UA_STATUSCODE_BADINTERNALERROR;
1060
1061
1.02k
    X509 *certificateX509 = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
1062
1.02k
    if(!certificateX509)
1063
915
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
1064
1065
114
    UA_StatusCode retval = openSSLCheckCA(certificateX509) ?
1066
109
        UA_STATUSCODE_GOOD : UA_STATUSCODE_BADNOMATCH;
1067
114
    X509_free(certificateX509);
1068
114
    return retval;
1069
1.02k
}
1070
1071
static int
1072
0
privateKeyPasswordCallback(char *buf, int size, int rwflag, void *userdata) {
1073
0
    (void) rwflag;
1074
0
    UA_ByteString *pw = (UA_ByteString*)userdata;
1075
0
    if(pw->length <= (size_t)size)
1076
0
        memcpy(buf, pw->data, pw->length);
1077
0
    return (int)pw->length;
1078
0
}
1079
1080
UA_StatusCode
1081
UA_CertificateUtils_decryptPrivateKey(const UA_ByteString privateKey,
1082
                                      const UA_ByteString password,
1083
0
                                      UA_ByteString *outDerKey) {
1084
0
    if(!outDerKey)
1085
0
        return UA_STATUSCODE_BADINTERNALERROR;
1086
1087
0
    if(privateKey.length == 0) {
1088
0
        *outDerKey = UA_BYTESTRING_NULL;
1089
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
1090
0
    }
1091
1092
0
    EVP_PKEY *pkey = NULL;
1093
0
    const unsigned char * in = privateKey.data;
1094
1095
    /* Check if input is already in DER format */
1096
0
    pkey = d2i_AutoPrivateKey(NULL, &in, privateKey.length);
1097
0
    if(pkey != NULL) {
1098
0
        EVP_PKEY_free(pkey);
1099
0
        return UA_ByteString_copy(&privateKey, outDerKey);
1100
0
    }
1101
1102
    /* Decrypt */
1103
0
    BIO *bio = BIO_new_mem_buf((void*)privateKey.data, (int)privateKey.length);
1104
0
    pkey = PEM_read_bio_PrivateKey(bio, NULL,
1105
0
                                             privateKeyPasswordCallback,
1106
0
                                             (void*)(uintptr_t)&password);
1107
0
    BIO_free(bio);
1108
0
    if(!pkey)
1109
0
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
1110
1111
    /* Write DER encoded, allocates the new memory */
1112
0
    unsigned char *data = NULL;
1113
0
    const int numBytes = i2d_PrivateKey(pkey, &data);
1114
0
    EVP_PKEY_free(pkey);
1115
0
    if(!data)
1116
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
1117
1118
    /* Copy to the data to outDerKey
1119
     * Passing the data pointer directly causes a heap corruption on Windows
1120
     * when outDerKey is cleared.
1121
     */
1122
0
    UA_ByteString temp = UA_BYTESTRING_NULL;
1123
0
    temp.data = data;
1124
0
    temp.length = (size_t)numBytes;
1125
0
    const UA_StatusCode success = UA_ByteString_copy(&temp, outDerKey);
1126
    /* OPENSSL_clear_free() is not supported by the LibreSSL version in the CI */
1127
0
    OPENSSL_cleanse(data, numBytes);
1128
    OPENSSL_free(data);
1129
0
    return success;
1130
0
}
1131
1132
#endif