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/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
4
#define SHA1_DIGEST_LENGTH 20
23
24
/* Configuration parameters */
25
26
#define MEMORYCERTSTORE_PARAMETERSSIZE 2
27
9.01k
#define MEMORYCERTSTORE_PARAMINDEX_MAXTRUSTLISTSIZE 0
28
9.01k
#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
9.01k
MemoryCertStore_setTrustList(UA_CertificateGroup *certGroup, const UA_TrustListDataType *trustList) {
85
    /* Check parameter */
86
9.01k
    if(certGroup == NULL || trustList == NULL) {
87
0
        return UA_STATUSCODE_BADINTERNALERROR;
88
0
    }
89
90
9.01k
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
91
9.01k
    if(context->maxTrustListSize != 0 && UA_TrustListDataType_getSize(trustList) > context->maxTrustListSize) {
92
0
        return UA_STATUSCODE_BADINTERNALERROR;
93
0
    }
94
9.01k
    context->reloadRequired = true;
95
    /* Remove the section of the trust list that needs to be reset, while keeping the remaining parts intact */
96
9.01k
    return UA_TrustListDataType_set(trustList, &context->trustList);
97
9.01k
}
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
9.01k
MemoryCertStore_clear(UA_CertificateGroup *certGroup) {
249
    /* check parameter */
250
9.01k
    if(certGroup == NULL) {
251
0
        return;
252
0
    }
253
254
9.01k
    UA_NodeId_clear(&certGroup->certificateGroupId);
255
256
9.01k
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
257
9.01k
    if(context) {
258
9.01k
        UA_TrustListDataType_clear(&context->trustList);
259
260
9.01k
        UA_Array_delete(context->rejectedCertificates, context->rejectedCertificatesSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
261
9.01k
        context->rejectedCertificates = NULL;
262
9.01k
        context->rejectedCertificatesSize = 0;
263
264
9.01k
        sk_X509_pop_free(context->trustedCertificates, X509_free);
265
9.01k
        sk_X509_pop_free(context->issuerCertificates, X509_free);
266
9.01k
        sk_X509_CRL_pop_free(context->crls, X509_CRL_free);
267
268
9.01k
        UA_free(context);
269
9.01k
        certGroup->context = NULL;
270
9.01k
    }
271
9.01k
}
272
273
static UA_StatusCode
274
9.01k
reloadCertificates(UA_CertificateGroup *certGroup) {
275
    /* Check parameter */
276
9.01k
    if(certGroup == NULL) {
277
0
        return UA_STATUSCODE_BADINTERNALERROR;
278
0
    }
279
280
9.01k
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
281
282
9.01k
    sk_X509_pop_free(context->trustedCertificates, X509_free);
283
9.01k
    context->trustedCertificates = sk_X509_new_null();
284
9.01k
    if(context->trustedCertificates == NULL) {
285
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
286
0
    }
287
9.01k
    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
9.01k
    sk_X509_pop_free(context->issuerCertificates, X509_free);
295
9.01k
    context->issuerCertificates = sk_X509_new_null();
296
9.01k
    if(context->issuerCertificates == NULL) {
297
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
298
0
    }
299
9.01k
    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
9.01k
    sk_X509_CRL_pop_free(context->crls, X509_CRL_free);
307
9.01k
    context->crls = sk_X509_CRL_new_null();
308
9.01k
    if(context->crls == NULL) {
309
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
310
0
    }
311
9.01k
    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
9.01k
    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
9.01k
    return UA_STATUSCODE_GOOD;
351
9.01k
}
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
bstrchr(const unsigned char *s, const unsigned char ch, size_t l) {
358
    /* find first occurrence of c in char s[] for length l*/
359
0
    for(; l > 0; ++s, --l) {
360
0
        if(*s == ch)
361
0
            return s;
362
0
    }
363
0
    return NULL;
364
0
}
365
366
static const unsigned char *
367
0
UA_Bstrstr(const unsigned char *s1, size_t l1, const unsigned char *s2, size_t l2) {
368
    /* find first occurrence of s2[] in s1[] for length l1*/
369
0
    const unsigned char *ss1 = s1;
370
0
    const unsigned char *ss2 = s2;
371
    /* handle special case */
372
0
    if(l1 == 0)
373
0
        return NULL;
374
0
    if(l2 == 0)
375
0
        return s1;
376
377
    /* match prefix */
378
0
    for(; (s1 = bstrchr(s1, *s2, (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1)) != NULL &&
379
0
            (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1 != 0; ++s1) {
380
381
        /* match rest of prefix */
382
0
        const unsigned char *sc1, *sc2;
383
0
        for(sc1 = s1, sc2 = s2; ;)
384
0
            if(++sc2 >= ss2+l2)
385
0
                return s1;
386
0
            else if (*++sc1 != *sc2)
387
0
                break;
388
0
    }
389
0
    return NULL;
390
0
}
391
392
static const unsigned char openssl_PEM_PRE[28] = "-----BEGIN CERTIFICATE-----";
393
394
/* Extract the leaf certificate from a bytestring that may contain an entire chain */
395
static X509 *
396
0
openSSLLoadLeafCertificate(UA_ByteString cert, size_t *offset) {
397
0
    if(cert.length <= *offset)
398
0
        return NULL;
399
0
    cert.length -= *offset;
400
0
    cert.data += *offset;
401
402
    /* Detect DER encoding. Extract the encoding length and cut. */
403
0
    if(cert.length >= 4 && cert.data[0] == 0x30 && cert.data[1] == 0x82) {
404
        /* The certificate length is encoded after the magic bytes */
405
0
        size_t certLen = 4; /* Magic numbers + length bytes */
406
0
        certLen += (size_t)(((uint16_t)cert.data[2]) << 8);
407
0
        certLen += cert.data[3];
408
0
        if(certLen > cert.length)
409
0
            return NULL;
410
0
        cert.length = certLen;
411
0
        *offset += certLen;
412
0
        const UA_Byte *dataPtr = cert.data;
413
0
        return d2i_X509(NULL, &dataPtr, (long)cert.length);
414
0
    }
415
416
    /* Assume PEM encoding. Detect multiple certificates and cut. */
417
0
    if(cert.length > 27 * 4) {
418
0
        const unsigned char *match =
419
0
            UA_Bstrstr(openssl_PEM_PRE, 27, &cert.data[27*2], cert.length - (27*2));
420
0
        if(match)
421
0
            cert.length = (uintptr_t)(match - cert.data);
422
0
    }
423
0
    *offset += cert.length;
424
425
0
    BIO *bio = BIO_new_mem_buf((void *) cert.data, (int)cert.length);
426
0
    X509 *result = PEM_read_bio_X509(bio, NULL, NULL, NULL);
427
0
    BIO_free(bio);
428
0
    return result;
429
0
}
430
431
/* The bytestring might contain an entire certificate chain. The first
432
 * stack-element is the leaf certificate itself. The remaining ones are
433
 * potential issuer certificates. */
434
static STACK_OF(X509) *
435
0
openSSLLoadCertificateStack(const UA_ByteString cert) {
436
0
    size_t offset = 0;
437
0
    X509 *x509 = NULL;
438
0
    STACK_OF(X509) *result = sk_X509_new_null();
439
0
    if(!result)
440
0
        return NULL;
441
0
    while((x509 = openSSLLoadLeafCertificate(cert, &offset))) {
442
0
        sk_X509_push(result, x509);
443
0
    }
444
0
    return result;
445
0
}
446
447
/* Return the first matching issuer candidate AFTER prev */
448
static X509 *
449
0
openSSLFindNextIssuer(MemoryCertStore *ctx, STACK_OF(X509) *stack, X509 *x509, X509 *prev) {
450
    /* First check issuers from the stack - provided in the same bytestring as
451
     * the certificate. This can also return x509 itself. */
452
0
    X509_NAME *in = X509_get_issuer_name(x509);
453
0
    do {
454
0
        int size = sk_X509_num(stack);
455
0
        for(int i = 0; i < size; i++) {
456
0
            X509 *candidate = sk_X509_value(stack, i);
457
0
            if(prev) {
458
0
                if(prev == candidate)
459
0
                    prev = NULL; /* This was the last issuer we tried to verify */
460
0
                continue;
461
0
            }
462
            /* This checks subject/issuer name and the key usage of the issuer.
463
             * It does not verify the validity period and if the issuer key was
464
             * used for the signature. We check that afterwards. */
465
0
            if(X509_NAME_cmp(in, X509_get_subject_name(candidate)) == 0)
466
0
                return candidate;
467
0
        }
468
        /* Switch from the stack that came with the cert to the issuer list and
469
         * then to the trust list. */
470
0
        if(stack == ctx->trustedCertificates)
471
0
            stack = NULL;
472
0
        else if(stack == ctx->issuerCertificates)
473
0
            stack = ctx->trustedCertificates;
474
0
        else
475
0
            stack = ctx->issuerCertificates;
476
0
    } while(stack);
477
0
    return NULL;
478
0
}
479
480
/* Is the certificate a CA? */
481
static UA_Boolean
482
0
openSSLCheckCA(X509 *cert) {
483
0
    uint32_t flags = X509_get_extension_flags(cert);
484
    /* The basic constraints must be set with the CA flag true */
485
0
    if(!(flags & EXFLAG_CA))
486
0
        return false;
487
488
    /* The Key Usage extension must be set */
489
0
    if(!(flags & EXFLAG_KUSAGE))
490
0
        return false;
491
492
    /* The Key Usage must include cert signing and CRL issuing */
493
0
    uint32_t usage = X509_get_key_usage(cert);
494
0
    if(!(usage & KU_KEY_CERT_SIGN) || !(usage & KU_CRL_SIGN))
495
0
        return false;
496
497
0
    return true;
498
0
}
499
500
static UA_StatusCode
501
0
openSSLCheckRevoked(UA_CertificateGroup *cg, MemoryCertStore *ctx, X509 *cert) {
502
0
    const ASN1_INTEGER *sn = X509_get0_serialNumber(cert);
503
0
    const X509_NAME *in = X509_get_issuer_name(cert);
504
0
    int size = sk_X509_CRL_num(ctx->crls);
505
506
0
    if(size == 0) {
507
0
        UA_LOG_WARNING(cg->logging, UA_LOGCATEGORY_SECURITYPOLICY,
508
0
                       "Zero revocation lists have been loaded. "
509
0
                       "This seems intentional - omitting the check.");
510
0
        return UA_STATUSCODE_GOOD;
511
0
    }
512
513
    /* Loop over the crl and match the Issuer Name */
514
0
    UA_StatusCode res = UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN;
515
0
    for(int i = 0; i < size; i++) {
516
        /* The crl contains a list of serial numbers from the same issuer */
517
0
        X509_CRL *crl = sk_X509_CRL_value(ctx->crls, i);
518
0
        if(X509_NAME_cmp(in, X509_CRL_get_issuer(crl)) != 0)
519
0
            continue;
520
0
        STACK_OF(X509_REVOKED) *rs = X509_CRL_get_REVOKED(crl);
521
0
        int rsize = sk_X509_REVOKED_num(rs);
522
0
        for(int j = 0; j < rsize; j++) {
523
0
            X509_REVOKED *r = sk_X509_REVOKED_value(rs, j);
524
0
            if(ASN1_INTEGER_cmp(sn, X509_REVOKED_get0_serialNumber(r)) == 0)
525
0
                return UA_STATUSCODE_BADCERTIFICATEREVOKED;
526
0
        }
527
0
        res = UA_STATUSCODE_GOOD; /* There was at least one crl that did not revoke (so far) */
528
0
    }
529
0
    return res;
530
0
}
531
532
0
#define UA_OPENSSL_MAX_CHAIN_LENGTH 10
533
534
static UA_StatusCode
535
openSSL_verifyChain(UA_CertificateGroup *cg, MemoryCertStore *ctx, STACK_OF(X509) *stack,
536
0
                    X509 **old_issuers, X509 *cert, int depth) {
537
    /* Maxiumum chain length */
538
0
    if(depth == UA_OPENSSL_MAX_CHAIN_LENGTH)
539
0
        return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
540
541
    /* Return the most specific error code. BADCERTIFICATECHAININCOMPLETE is
542
     * returned only if all possible chains are incomplete. */
543
0
    X509 *issuer = NULL;
544
0
    UA_StatusCode ret = UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
545
0
    while(ret != UA_STATUSCODE_GOOD) {
546
        /* Find the issuer. We jump back here to find a different path if a
547
         * subsequent check fails. */
548
0
        issuer = openSSLFindNextIssuer(ctx, stack, cert, issuer);
549
0
        if(!issuer)
550
0
            break;
551
552
        /* Verification Step: Certificate Usage
553
         * Can the issuer act as CA? Omit for self-signed leaf certificates. */
554
0
        if((depth > 0 || issuer != cert) && !openSSLCheckCA(issuer)) {
555
0
            ret = UA_STATUSCODE_BADCERTIFICATEISSUERUSENOTALLOWED;
556
0
            continue;
557
0
        }
558
559
        /* Verification Step: Signature */
560
0
        int opensslRet = X509_verify(cert, X509_get0_pubkey(issuer));
561
0
        if(opensslRet == -1) {
562
0
            return UA_STATUSCODE_BADCERTIFICATEINVALID; /* Ill-formed signature */
563
0
        } else if(opensslRet == 0) {
564
0
            ret = UA_STATUSCODE_BADCERTIFICATEINVALID;  /* Wrong issuer, try again */
565
0
            continue;
566
0
        }
567
568
        /* The certificate is self-signed. We have arrived at the top of the
569
         * chain. We check whether the certificate is trusted below. This is the
570
         * only place where we return UA_STATUSCODE_BADCERTIFICATEUNTRUSTED.
571
         * This signals that the chain is complete (but can be still
572
         * untrusted).
573
         *
574
         * Break here as we have reached the end of the chain. Omit the
575
         * Revocation Check for self-signed certificates. */
576
0
        if(cert == issuer || X509_cmp(cert, issuer) == 0) {
577
0
            ret = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED;
578
0
            break;
579
0
        }
580
581
        /* Verification Step: Revocation Check */
582
0
        ret = openSSLCheckRevoked(cg, ctx, cert);
583
0
        if(depth > 0) {
584
0
            if(ret == UA_STATUSCODE_BADCERTIFICATEREVOKED)
585
0
                ret = UA_STATUSCODE_BADCERTIFICATEISSUERREVOKED;
586
0
            if(ret == UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN)
587
0
                ret = UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN;
588
0
        }
589
0
        if(ret != UA_STATUSCODE_GOOD)
590
0
            continue;
591
592
        /* Detect (endless) loops of issuers. The last one can be skipped by the
593
         * check for self-signed just before. */
594
0
        for(int i = 0; i < depth; i++) {
595
0
            if(old_issuers[i] == issuer)
596
0
                return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
597
0
        }
598
0
        old_issuers[depth] = issuer;
599
600
        /* We have found the issuer certificate used for the signature. Recurse
601
         * to the next certificate in the chain (verify the current issuer). */
602
0
        ret = openSSL_verifyChain(cg, ctx, stack, old_issuers, issuer, depth + 1);
603
0
    }
604
605
    /* Is the certificate in the trust list? If yes, then we are done. */
606
0
    if(ret == UA_STATUSCODE_BADCERTIFICATEUNTRUSTED) {
607
0
        for(int i = 0; i < sk_X509_num(ctx->trustedCertificates); i++) {
608
0
            if(X509_cmp(cert, sk_X509_value(ctx->trustedCertificates, i)) == 0) {
609
0
                ret = UA_STATUSCODE_GOOD;
610
0
                break;
611
0
            }
612
0
        }
613
0
    }
614
615
0
    if (ret == UA_STATUSCODE_GOOD) {
616
        /* Verification Step: Validity Period */
617
0
        ASN1_TIME *notBefore = X509_get_notBefore(cert);
618
0
        ASN1_TIME *notAfter = X509_get_notAfter(cert);
619
0
        if(X509_cmp_current_time(notBefore) != -1 || X509_cmp_current_time(notAfter) != 1)
620
0
            return (depth == 0) ? UA_STATUSCODE_BADCERTIFICATETIMEINVALID :
621
0
                UA_STATUSCODE_BADCERTIFICATEISSUERTIMEINVALID;
622
0
    }
623
624
0
    return ret;
625
0
}
626
627
/* This follows Part 6, 6.1.3 Determining if a Certificate is trusted.
628
 * It defines a sequence of steps for certificate verification. */
629
static UA_StatusCode
630
0
verifyCertificate(UA_CertificateGroup *certGroup, const UA_ByteString *certificate) {
631
    /* Check parameter */
632
0
    if(certGroup == NULL || certGroup->context == NULL)
633
0
        return UA_STATUSCODE_BADINTERNALERROR;
634
635
0
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
636
0
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
637
0
    if(context->reloadRequired) {
638
0
        ret = reloadCertificates(certGroup);
639
0
        if(ret != UA_STATUSCODE_GOOD)
640
0
            return ret;
641
0
        context->reloadRequired = false;
642
0
    }
643
644
    /* Verification Step: Certificate Structure */
645
0
    STACK_OF(X509) *stack = openSSLLoadCertificateStack(*certificate);
646
0
    if(!stack || sk_X509_num(stack) < 1) {
647
0
        sk_X509_pop_free(stack, X509_free);
648
0
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
649
0
    }
650
651
    /* Verification Step: Certificate Usage
652
     * Check whether the certificate is a User certificate or a CA certificate.
653
     * Refer the test case CTT/Security/Security Certificate Validation/029.js
654
     * for more details. */
655
0
    X509 *leaf = sk_X509_value(stack, 0);
656
0
    if(openSSLCheckCA(leaf)) {
657
0
        sk_X509_pop_free(stack, X509_free);
658
0
        return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
659
0
    }
660
661
    /* These steps are performed outside of this method.
662
     * Because we need the server or client context.
663
     * - Security Policy
664
     * - Host Name
665
     * - URI */
666
667
    /* Verification Step: Build Certificate Chain
668
     * We perform the checks for each certificate inside. */
669
0
    X509 *old_issuers[UA_OPENSSL_MAX_CHAIN_LENGTH];
670
0
    ret = openSSL_verifyChain(certGroup, context, stack, old_issuers, leaf, 0);
671
0
    sk_X509_pop_free(stack, X509_free);
672
0
    return ret;
673
0
}
674
675
static UA_StatusCode
676
MemoryCertStore_verifyCertificate(UA_CertificateGroup *certGroup,
677
0
                                  const UA_ByteString *certificate) {
678
    /* Check parameter */
679
0
    if(certGroup == NULL || certificate == NULL) {
680
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
681
0
    }
682
683
0
    UA_StatusCode retval = verifyCertificate(certGroup, certificate);
684
0
    if(retval != UA_STATUSCODE_GOOD) {
685
0
        if(MemoryCertStore_addToRejectedList(certGroup, certificate) != UA_STATUSCODE_GOOD) {
686
0
            UA_LOG_WARNING(certGroup->logging, UA_LOGCATEGORY_SECURITYPOLICY,
687
0
                           "Could not append certificate to rejected list");
688
0
        }
689
0
    }
690
0
    return retval;
691
0
}
692
693
UA_StatusCode
694
UA_CertificateGroup_Memorystore(UA_CertificateGroup *certGroup,
695
                                UA_NodeId *certificateGroupId,
696
                                const UA_TrustListDataType *trustList,
697
                                const UA_Logger *logger,
698
9.01k
                                const UA_KeyValueMap *params) {
699
700
9.01k
    if(certGroup == NULL || certificateGroupId == NULL) {
701
0
        return UA_STATUSCODE_BADINTERNALERROR;
702
0
    }
703
704
9.01k
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
705
706
    /* Clear if the plugin is already initialized */
707
9.01k
    if(certGroup->clear)
708
0
        certGroup->clear(certGroup);
709
710
9.01k
    UA_NodeId_copy(certificateGroupId, &certGroup->certificateGroupId);
711
9.01k
    certGroup->logging = logger;
712
713
9.01k
    certGroup->getTrustList = MemoryCertStore_getTrustList;
714
9.01k
    certGroup->setTrustList = MemoryCertStore_setTrustList;
715
9.01k
    certGroup->addToTrustList = MemoryCertStore_addToTrustList;
716
9.01k
    certGroup->removeFromTrustList = MemoryCertStore_removeFromTrustList;
717
9.01k
    certGroup->getRejectedList = MemoryCertStore_getRejectedList;
718
9.01k
    certGroup->getCertificateCrls = MemoryCertStore_getCertificateCrls;
719
9.01k
    certGroup->verifyCertificate = MemoryCertStore_verifyCertificate;
720
9.01k
    certGroup->clear = MemoryCertStore_clear;
721
722
    /* Set PKI Store context data */
723
9.01k
    MemoryCertStore *context = (MemoryCertStore *)UA_calloc(1, sizeof(MemoryCertStore));
724
9.01k
    if(!context) {
725
0
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
726
0
        goto cleanup;
727
0
    }
728
9.01k
    certGroup->context = context;
729
    /* Default values */
730
9.01k
    context->maxTrustListSize = 65535;
731
9.01k
    context->maxRejectedListSize = 100;
732
733
9.01k
    if(params) {
734
9.01k
        const UA_UInt32 *maxTrustListSize = (const UA_UInt32*)
735
9.01k
        UA_KeyValueMap_getScalar(params, MemoryCertStoreParameters[MEMORYCERTSTORE_PARAMINDEX_MAXTRUSTLISTSIZE].name,
736
9.01k
                                 &UA_TYPES[UA_TYPES_UINT32]);
737
738
9.01k
        const UA_UInt32 *maxRejectedListSize = (const UA_UInt32*)
739
9.01k
        UA_KeyValueMap_getScalar(params, MemoryCertStoreParameters[MEMORYCERTSTORE_PARAMINDEX_MAXREJECTEDLISTSIZE].name,
740
9.01k
                                 &UA_TYPES[UA_TYPES_UINT32]);
741
742
9.01k
        if(maxTrustListSize) {
743
0
            context->maxTrustListSize = *maxTrustListSize;
744
0
        }
745
746
9.01k
        if(maxRejectedListSize) {
747
0
            context->maxRejectedListSize = *maxRejectedListSize;
748
0
        }
749
9.01k
    }
750
751
9.01k
    UA_TrustListDataType_add(trustList, &context->trustList);
752
9.01k
    reloadCertificates(certGroup);
753
754
9.01k
    return UA_STATUSCODE_GOOD;
755
756
0
cleanup:
757
0
    certGroup->clear(certGroup);
758
0
    return retval;
759
9.01k
}
760
761
UA_StatusCode
762
UA_CertificateUtils_verifyApplicationUri(const UA_ByteString *certificate,
763
59
                                         const UA_String *applicationURI) {
764
59
    const unsigned char *pData = certificate->data;
765
59
    if(!pData)
766
0
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
767
768
59
    X509 *certificateX509 = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
769
59
    if(!certificateX509)
770
59
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
771
772
0
    GENERAL_NAMES *pNames = (GENERAL_NAMES *)
773
0
        X509_get_ext_d2i(certificateX509, NID_subject_alt_name, NULL, NULL);
774
0
    if(!pNames) {
775
0
        X509_free(certificateX509);
776
0
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
777
0
    }
778
779
0
    UA_String subjectURI = UA_STRING_NULL;
780
0
    for(int i = 0; i < sk_GENERAL_NAME_num(pNames); i++) {
781
0
        GENERAL_NAME *value = sk_GENERAL_NAME_value(pNames, i);
782
0
        if(value->type == GEN_URI) {
783
0
            subjectURI.length = (size_t) (value->d.ia5->length);
784
0
            subjectURI.data = (UA_Byte*)UA_malloc(subjectURI.length);
785
0
            if(!subjectURI.data) {
786
0
                X509_free(certificateX509);
787
0
                sk_GENERAL_NAME_pop_free(pNames, GENERAL_NAME_free);
788
0
                return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
789
0
            }
790
0
            (void)memcpy(subjectURI.data, value->d.ia5->data, subjectURI.length);
791
0
            break;
792
0
        }
793
0
    }
794
795
0
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
796
0
    if(UA_Bstrstr(subjectURI.data, subjectURI.length,
797
0
                  applicationURI->data, applicationURI->length) == NULL)
798
0
        ret = UA_STATUSCODE_BADCERTIFICATEURIINVALID;
799
800
0
    X509_free(certificateX509);
801
0
    sk_GENERAL_NAME_pop_free(pNames, GENERAL_NAME_free);
802
0
    UA_String_clear(&subjectURI);
803
0
    return ret;
804
0
}
805
806
UA_StatusCode
807
UA_CertificateUtils_getExpirationDate(UA_ByteString *certificate,
808
85
                                      UA_DateTime *expiryDateTime) {
809
85
    X509 *x509 = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
810
85
    if(!x509)
811
85
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
812
813
    /* Get the certificate Expiry date */
814
0
    ASN1_TIME *not_after = X509_get_notAfter(x509);
815
816
0
    struct tm dtTime;
817
0
    ASN1_TIME_to_tm(not_after, &dtTime);
818
0
    X509_free(x509);
819
820
0
    struct musl_tm dateTime;
821
0
    memset(&dateTime, 0, sizeof(struct musl_tm));
822
0
    dateTime.tm_year = dtTime.tm_year;
823
0
    dateTime.tm_mon = dtTime.tm_mon;
824
0
    dateTime.tm_mday = dtTime.tm_mday;
825
0
    dateTime.tm_hour = dtTime.tm_hour;
826
0
    dateTime.tm_min = dtTime.tm_min;
827
0
    dateTime.tm_sec = dtTime.tm_sec;
828
829
0
    long long sec_epoch = musl_tm_to_secs(&dateTime);
830
0
    *expiryDateTime = UA_DATETIME_UNIX_EPOCH;
831
0
    *expiryDateTime += sec_epoch * UA_DATETIME_SEC;
832
0
    return UA_STATUSCODE_GOOD;
833
85
}
834
835
UA_StatusCode
836
UA_CertificateUtils_getSubjectName(UA_ByteString *certificate,
837
196
                                   UA_String *subjectName) {
838
196
    X509_NAME *sn = NULL;
839
196
    X509 *x509 = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
840
196
    X509_CRL *x509_crl = NULL;
841
842
196
    if(x509) {
843
0
        sn = X509_get_subject_name(x509);
844
196
    } else {
845
196
        x509_crl = UA_OpenSSL_LoadCrl(certificate);
846
196
        if(!x509_crl)
847
196
            return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
848
0
        sn = X509_CRL_get_issuer(x509_crl);
849
0
    }
850
851
0
    char buf[1024];
852
0
    *subjectName = UA_STRING_ALLOC(X509_NAME_oneline(sn, buf, 1024));
853
854
0
    if(x509)
855
0
        X509_free(x509);
856
0
    if(x509_crl)
857
0
        X509_CRL_free(x509_crl);
858
0
    return UA_STATUSCODE_GOOD;
859
196
}
860
861
UA_StatusCode
862
UA_CertificateUtils_getThumbprint(UA_ByteString *certificate,
863
4
                                  UA_String *thumbprint) {
864
4
    if(certificate == NULL || thumbprint->length != (SHA1_DIGEST_LENGTH * 2))
865
4
        return UA_STATUSCODE_BADINTERNALERROR;
866
867
0
    unsigned char digest[SHA1_DIGEST_LENGTH];
868
0
    unsigned int digestLen;
869
870
0
    X509 *cert = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
871
0
    if(cert) {
872
0
        if(X509_digest(cert, EVP_sha1(), digest, &digestLen) != 1) {
873
0
            X509_free(cert);
874
0
            return UA_STATUSCODE_BADINTERNALERROR;
875
0
        }
876
0
        X509_free(cert);
877
0
    } else {
878
0
        X509_CRL *crl = UA_OpenSSL_LoadCrl(certificate);
879
0
        if(!crl)
880
0
            return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
881
0
        if(X509_CRL_digest(crl, EVP_sha1(), digest, &digestLen) != 1) {
882
0
            X509_CRL_free(crl);
883
0
            return UA_STATUSCODE_BADINTERNALERROR;
884
0
        }
885
0
        X509_CRL_free(crl);
886
0
    }
887
888
0
    UA_String thumb = UA_STRING_NULL;
889
0
    thumb.length = (SHA1_DIGEST_LENGTH * 2) + 1;
890
0
    thumb.data = (UA_Byte*)malloc(sizeof(UA_Byte) * thumb.length);
891
892
    /* Create a string containing a hex representation */
893
0
    char *p = (char*)thumb.data;
894
0
    for(size_t i = 0; i < digestLen; i++) {
895
0
        p += sprintf(p, "%.2X", digest[i]);
896
0
    }
897
898
0
    memcpy(thumbprint->data, thumb.data, thumbprint->length);
899
0
    free(thumb.data);
900
901
0
    return UA_STATUSCODE_GOOD;
902
0
}
903
904
UA_StatusCode
905
UA_CertificateUtils_getKeySize(UA_ByteString *certificate,
906
123
                               size_t *keySize){
907
123
    if(certificate == NULL)
908
0
        return UA_STATUSCODE_BADINTERNALERROR;
909
910
123
    X509 *cert = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
911
123
    if(!cert)
912
123
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
913
914
0
    EVP_PKEY *pkey = X509_get_pubkey(cert);
915
0
    if(!pkey) {
916
0
        X509_free(cert);
917
0
        return UA_STATUSCODE_BADINTERNALERROR;
918
0
    }
919
920
0
    if(EVP_PKEY_base_id(pkey) == EVP_PKEY_RSA) {
921
0
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
922
0
        *keySize = EVP_PKEY_get_size(pkey) * 8;
923
#else
924
        *keySize =  RSA_size(get_pkey_rsa(pkey)) * 8;
925
#endif
926
0
    } else if(EVP_PKEY_base_id(pkey) == EVP_PKEY_EC) {
927
0
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
928
0
        *keySize = EVP_PKEY_get_size(pkey) * 8;
929
#else
930
        *keySize =  ECDSA_size(EVP_PKEY_get0_EC_KEY(pkey)) * 8;
931
#endif
932
0
    } else {
933
0
        EVP_PKEY_free(pkey);
934
0
        X509_free(cert);
935
0
        return UA_STATUSCODE_BADINTERNALERROR; /* Unsupported key type */
936
0
    }
937
938
0
    EVP_PKEY_free(pkey);
939
0
    X509_free(cert);
940
941
0
    return UA_STATUSCODE_GOOD;
942
0
}
943
944
UA_StatusCode
945
UA_CertificateUtils_comparePublicKeys(const UA_ByteString *certificate1,
946
0
                                      const UA_ByteString *certificate2) {
947
0
    if(certificate1 == NULL || certificate2 == NULL)
948
0
        return UA_STATUSCODE_BADINTERNALERROR;
949
950
0
    BIO *dataBio1 = BIO_new_mem_buf(certificate1->data, certificate1->length);
951
0
    if(!dataBio1)
952
0
        return UA_STATUSCODE_BADINTERNALERROR;
953
954
0
    BIO *dataBio2 = BIO_new_mem_buf(certificate2->data, certificate2->length);
955
0
    if(!dataBio2) {
956
0
        BIO_free(dataBio1);
957
0
        return UA_STATUSCODE_BADINTERNALERROR;
958
0
    }
959
960
0
    X509 *cert1 = NULL;
961
0
    X509 *cert2 = NULL;
962
0
    X509_REQ *csr1 = NULL;
963
0
    X509_REQ *csr2 = NULL;
964
    /* Try to read the certificate as PEM first */
965
0
    cert1 = PEM_read_bio_X509(dataBio1, NULL, 0, NULL);
966
0
    if(!cert1) {
967
        /* If PEM read fails, reset BIO and try reading as DER */
968
0
        (void)BIO_reset(dataBio1);
969
0
        cert1 = d2i_X509_bio(dataBio1, NULL);
970
0
    }
971
    /* Try to read as a csr */
972
0
    if(!cert1) {
973
0
        (void)BIO_reset(dataBio1);
974
0
        csr1 = PEM_read_bio_X509_REQ(dataBio1, NULL, 0, NULL);
975
0
        if(!csr1) {
976
0
            (void)BIO_reset(dataBio1);
977
0
            csr1 = d2i_X509_REQ_bio(dataBio1, NULL);
978
0
        }
979
0
    }
980
0
    if(!cert1 && !csr1) {
981
0
        BIO_free(dataBio1);
982
0
        BIO_free(dataBio2);
983
0
        return UA_STATUSCODE_BADINTERNALERROR;
984
0
    }
985
986
0
    cert2 = PEM_read_bio_X509(dataBio2, NULL, 0, NULL);
987
0
    if(!cert2) {
988
        /* If PEM read fails, reset BIO and try reading as DER */
989
0
        (void)BIO_reset(dataBio2);
990
0
        cert2 = d2i_X509_bio(dataBio2, NULL);
991
0
    }
992
    /* Try to load as a csr */
993
0
    if(!cert2) {
994
0
        (void)BIO_reset(dataBio2);
995
0
        csr2 = PEM_read_bio_X509_REQ(dataBio2, NULL, 0, NULL);
996
0
        if(!csr2) {
997
0
            (void)BIO_reset(dataBio2);
998
0
            csr2 = d2i_X509_REQ_bio(dataBio2, NULL);
999
0
        }
1000
0
    }
1001
0
    if(!cert2 && !csr2) {
1002
0
        X509_free(cert1);
1003
0
        X509_REQ_free(csr1);
1004
0
        BIO_free(dataBio1);
1005
0
        BIO_free(dataBio2);
1006
0
        return UA_STATUSCODE_BADINTERNALERROR;
1007
0
    }
1008
1009
0
    BIO_free(dataBio1);
1010
0
    BIO_free(dataBio2);
1011
1012
0
    EVP_PKEY *pkey1 = cert1 ? X509_get_pubkey(cert1) : X509_REQ_get_pubkey(csr1);
1013
0
    EVP_PKEY *pkey2 = cert2 ? X509_get_pubkey(cert2) : X509_REQ_get_pubkey(csr2);
1014
1015
0
    X509_free(cert1);
1016
0
    X509_free(cert2);
1017
0
    X509_REQ_free(csr1);
1018
0
    X509_REQ_free(csr2);
1019
1020
0
    if(!pkey1 || !pkey2) {
1021
0
        EVP_PKEY_free(pkey1);
1022
0
        EVP_PKEY_free(pkey2);
1023
0
        return UA_STATUSCODE_BADINTERNALERROR;
1024
0
    }
1025
1026
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
1027
0
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
1028
0
    int isEqual = EVP_PKEY_eq(pkey1, pkey2);
1029
0
    if(isEqual == 0)
1030
0
        retval = UA_STATUSCODE_BADNOMATCH;
1031
0
    if(isEqual < 0)
1032
0
        retval = UA_STATUSCODE_BADINTERNALERROR;
1033
#else
1034
    int isEqual = EVP_PKEY_cmp(pkey1, pkey2);
1035
    if(isEqual == 0)
1036
        retval = UA_STATUSCODE_BADNOMATCH;
1037
    if(isEqual < 0)
1038
        retval = UA_STATUSCODE_BADINTERNALERROR;
1039
#endif
1040
1041
0
    EVP_PKEY_free(pkey1);
1042
0
    EVP_PKEY_free(pkey2);
1043
1044
0
    return retval;
1045
0
}
1046
1047
UA_StatusCode
1048
UA_CertificateUtils_checkKeyPair(const UA_ByteString *certificate,
1049
0
                                 const UA_ByteString *privateKey) {
1050
0
    if(certificate == NULL || privateKey == NULL)
1051
0
        return UA_STATUSCODE_BADINTERNALERROR;
1052
1053
0
    X509 *cert = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
1054
0
    if(!cert)
1055
0
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
1056
1057
0
    EVP_PKEY *pkey = UA_OpenSSL_LoadPrivateKey(privateKey);
1058
0
    if(!pkey) {
1059
0
        X509_free(cert);
1060
0
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
1061
0
    }
1062
1063
    /* Verify if the private key matches the public key in the certificate */
1064
0
    if(X509_check_private_key(cert, pkey) != 1) {
1065
0
        X509_free(cert);
1066
0
        EVP_PKEY_free(pkey);
1067
0
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
1068
0
    }
1069
1070
0
    X509_free(cert);
1071
0
    EVP_PKEY_free(pkey);
1072
1073
0
    return UA_STATUSCODE_GOOD;
1074
0
}
1075
1076
UA_StatusCode
1077
546
UA_CertificateUtils_checkCA(const UA_ByteString *certificate) {
1078
546
    if(certificate == NULL)
1079
0
        return UA_STATUSCODE_BADINTERNALERROR;
1080
1081
546
    X509 *certificateX509 = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
1082
546
    if(!certificateX509)
1083
546
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
1084
1085
0
    UA_StatusCode retval = openSSLCheckCA(certificateX509) ?
1086
0
        UA_STATUSCODE_GOOD : UA_STATUSCODE_BADNOMATCH;
1087
0
    X509_free(certificateX509);
1088
0
    return retval;
1089
546
}
1090
1091
static int
1092
0
privateKeyPasswordCallback(char *buf, int size, int rwflag, void *userdata) {
1093
0
    (void) rwflag;
1094
0
    UA_ByteString *pw = (UA_ByteString*)userdata;
1095
0
    if(pw->length <= (size_t)size)
1096
0
        memcpy(buf, pw->data, pw->length);
1097
0
    return (int)pw->length;
1098
0
}
1099
1100
UA_StatusCode
1101
UA_CertificateUtils_decryptPrivateKey(const UA_ByteString privateKey,
1102
                                      const UA_ByteString password,
1103
0
                                      UA_ByteString *outDerKey) {
1104
0
    if(!outDerKey)
1105
0
        return UA_STATUSCODE_BADINTERNALERROR;
1106
1107
0
    if(privateKey.length == 0) {
1108
0
        *outDerKey = UA_BYTESTRING_NULL;
1109
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
1110
0
    }
1111
1112
0
    EVP_PKEY *pkey = NULL;
1113
0
    const unsigned char * in = privateKey.data;
1114
1115
    /* Check if input is already in DER format */
1116
0
    pkey = d2i_AutoPrivateKey(NULL, &in, privateKey.length);
1117
0
    if(pkey != NULL) {
1118
0
        EVP_PKEY_free(pkey);
1119
0
        return UA_ByteString_copy(&privateKey, outDerKey);
1120
0
    }
1121
1122
    /* Decrypt */
1123
0
    BIO *bio = BIO_new_mem_buf((void*)privateKey.data, (int)privateKey.length);
1124
0
    pkey = PEM_read_bio_PrivateKey(bio, NULL,
1125
0
                                             privateKeyPasswordCallback,
1126
0
                                             (void*)(uintptr_t)&password);
1127
0
    BIO_free(bio);
1128
0
    if(!pkey)
1129
0
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
1130
1131
    /* Write DER encoded, allocates the new memory */
1132
0
    unsigned char *data = NULL;
1133
0
    const int numBytes = i2d_PrivateKey(pkey, &data);
1134
0
    EVP_PKEY_free(pkey);
1135
0
    if(!data)
1136
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
1137
1138
    /* Copy to the data to outDerKey
1139
     * Passing the data pointer directly causes a heap corruption on Windows
1140
     * when outDerKey is cleared.
1141
     */
1142
0
    UA_ByteString temp = UA_BYTESTRING_NULL;
1143
0
    temp.data = data;
1144
0
    temp.length = (size_t)numBytes;
1145
0
    const UA_StatusCode success = UA_ByteString_copy(&temp, outDerKey);
1146
    /* OPENSSL_clear_free() is not supported by the LibreSSL version in the CI */
1147
0
    OPENSSL_cleanse(data, numBytes);
1148
    OPENSSL_free(data);
1149
0
    return success;
1150
0
}
1151
1152
#endif