Coverage Report

Created: 2026-08-30 06:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open62541/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
6.55k
#define MEMORYCERTSTORE_PARAMINDEX_MAXTRUSTLISTSIZE 0
28
6.55k
#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
6.55k
MemoryCertStore_setTrustList(UA_CertificateGroup *certGroup, const UA_TrustListDataType *trustList) {
85
    /* Check parameter */
86
6.55k
    if(certGroup == NULL || trustList == NULL) {
87
0
        return UA_STATUSCODE_BADINTERNALERROR;
88
0
    }
89
90
6.55k
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
91
6.55k
    if(context->maxTrustListSize != 0 && UA_TrustListDataType_getSize(trustList) > context->maxTrustListSize) {
92
0
        return UA_STATUSCODE_BADINTERNALERROR;
93
0
    }
94
6.55k
    context->reloadRequired = true;
95
    /* Remove the section of the trust list that needs to be reset, while keeping the remaining parts intact */
96
6.55k
    return UA_TrustListDataType_set(trustList, &context->trustList);
97
6.55k
}
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
6.55k
MemoryCertStore_clear(UA_CertificateGroup *certGroup) {
249
    /* check parameter */
250
6.55k
    if(certGroup == NULL) {
251
0
        return;
252
0
    }
253
254
6.55k
    UA_NodeId_clear(&certGroup->certificateGroupId);
255
256
6.55k
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
257
6.55k
    if(context) {
258
6.55k
        UA_TrustListDataType_clear(&context->trustList);
259
260
6.55k
        UA_Array_delete(context->rejectedCertificates, context->rejectedCertificatesSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
261
6.55k
        context->rejectedCertificates = NULL;
262
6.55k
        context->rejectedCertificatesSize = 0;
263
264
6.55k
        sk_X509_pop_free(context->trustedCertificates, X509_free);
265
6.55k
        sk_X509_pop_free(context->issuerCertificates, X509_free);
266
6.55k
        sk_X509_CRL_pop_free(context->crls, X509_CRL_free);
267
268
6.55k
        UA_free(context);
269
6.55k
        certGroup->context = NULL;
270
6.55k
    }
271
6.55k
}
272
273
static UA_StatusCode
274
6.55k
reloadCertificates(UA_CertificateGroup *certGroup) {
275
    /* Check parameter */
276
6.55k
    if(certGroup == NULL) {
277
0
        return UA_STATUSCODE_BADINTERNALERROR;
278
0
    }
279
280
6.55k
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
281
282
6.55k
    sk_X509_pop_free(context->trustedCertificates, X509_free);
283
6.55k
    context->trustedCertificates = sk_X509_new_null();
284
6.55k
    if(context->trustedCertificates == NULL) {
285
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
286
0
    }
287
6.55k
    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
6.55k
    sk_X509_pop_free(context->issuerCertificates, X509_free);
295
6.55k
    context->issuerCertificates = sk_X509_new_null();
296
6.55k
    if(context->issuerCertificates == NULL) {
297
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
298
0
    }
299
6.55k
    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
6.55k
    sk_X509_CRL_pop_free(context->crls, X509_CRL_free);
307
6.55k
    context->crls = sk_X509_CRL_new_null();
308
6.55k
    if(context->crls == NULL) {
309
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
310
0
    }
311
6.55k
    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
6.55k
    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
6.55k
    return UA_STATUSCODE_GOOD;
351
6.55k
}
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
123
openSSLCheckCA(X509 *cert) {
483
123
    uint32_t flags = X509_get_extension_flags(cert);
484
    /* The basic constraints must be set with the CA flag true */
485
123
    if(!(flags & EXFLAG_CA))
486
51
        return false;
487
488
    /* The Key Usage extension must be set */
489
72
    if(!(flags & EXFLAG_KUSAGE))
490
45
        return false;
491
492
    /* The Key Usage must include cert signing and CRL issuing */
493
27
    uint32_t usage = X509_get_key_usage(cert);
494
27
    if(!(usage & KU_KEY_CERT_SIGN) || !(usage & KU_CRL_SIGN))
495
11
        return false;
496
497
16
    return true;
498
27
}
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
6.55k
                                const UA_KeyValueMap *params) {
699
700
6.55k
    if(certGroup == NULL || certificateGroupId == NULL) {
701
0
        return UA_STATUSCODE_BADINTERNALERROR;
702
0
    }
703
704
6.55k
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
705
706
    /* Clear if the plugin is already initialized */
707
6.55k
    if(certGroup->clear)
708
0
        certGroup->clear(certGroup);
709
710
6.55k
    UA_NodeId_copy(certificateGroupId, &certGroup->certificateGroupId);
711
6.55k
    certGroup->logging = logger;
712
713
6.55k
    certGroup->getTrustList = MemoryCertStore_getTrustList;
714
6.55k
    certGroup->setTrustList = MemoryCertStore_setTrustList;
715
6.55k
    certGroup->addToTrustList = MemoryCertStore_addToTrustList;
716
6.55k
    certGroup->removeFromTrustList = MemoryCertStore_removeFromTrustList;
717
6.55k
    certGroup->getRejectedList = MemoryCertStore_getRejectedList;
718
6.55k
    certGroup->getCertificateCrls = MemoryCertStore_getCertificateCrls;
719
6.55k
    certGroup->verifyCertificate = MemoryCertStore_verifyCertificate;
720
6.55k
    certGroup->clear = MemoryCertStore_clear;
721
722
    /* Set PKI Store context data */
723
6.55k
    MemoryCertStore *context = (MemoryCertStore *)UA_calloc(1, sizeof(MemoryCertStore));
724
6.55k
    if(!context) {
725
0
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
726
0
        goto cleanup;
727
0
    }
728
6.55k
    certGroup->context = context;
729
    /* Default values */
730
6.55k
    context->maxTrustListSize = 65535;
731
6.55k
    context->maxRejectedListSize = 100;
732
733
6.55k
    if(params) {
734
6.55k
        const UA_UInt32 *maxTrustListSize = (const UA_UInt32*)
735
6.55k
        UA_KeyValueMap_getScalar(params, MemoryCertStoreParameters[MEMORYCERTSTORE_PARAMINDEX_MAXTRUSTLISTSIZE].name,
736
6.55k
                                 &UA_TYPES[UA_TYPES_UINT32]);
737
738
6.55k
        const UA_UInt32 *maxRejectedListSize = (const UA_UInt32*)
739
6.55k
        UA_KeyValueMap_getScalar(params, MemoryCertStoreParameters[MEMORYCERTSTORE_PARAMINDEX_MAXREJECTEDLISTSIZE].name,
740
6.55k
                                 &UA_TYPES[UA_TYPES_UINT32]);
741
742
6.55k
        if(maxTrustListSize) {
743
0
            context->maxTrustListSize = *maxTrustListSize;
744
0
        }
745
746
6.55k
        if(maxRejectedListSize) {
747
0
            context->maxRejectedListSize = *maxRejectedListSize;
748
0
        }
749
6.55k
    }
750
751
6.55k
    UA_TrustListDataType_add(trustList, &context->trustList);
752
6.55k
    reloadCertificates(certGroup);
753
754
6.55k
    return UA_STATUSCODE_GOOD;
755
756
0
cleanup:
757
0
    certGroup->clear(certGroup);
758
0
    return retval;
759
6.55k
}
760
761
UA_StatusCode
762
UA_CertificateUtils_verifyApplicationUri(const UA_ByteString *certificate,
763
90
                                         const UA_String *applicationURI) {
764
90
    const unsigned char *pData = certificate->data;
765
90
    if(!pData)
766
0
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
767
768
90
    X509 *certificateX509 = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
769
90
    if(!certificateX509)
770
78
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
771
772
12
    GENERAL_NAMES *pNames = (GENERAL_NAMES *)
773
12
        X509_get_ext_d2i(certificateX509, NID_subject_alt_name, NULL, NULL);
774
12
    if(!pNames) {
775
12
        X509_free(certificateX509);
776
12
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
777
12
    }
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(subjectURI.length != applicationURI->length ||
797
0
       memcmp(subjectURI.data, applicationURI->data, applicationURI->length) != 0)
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
221
                                      UA_DateTime *expiryDateTime) {
809
221
    X509 *x509 = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
810
221
    if(!x509)
811
68
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
812
813
    /* Get the certificate Expiry date */
814
153
    ASN1_TIME *not_after = X509_get_notAfter(x509);
815
816
153
    struct tm dtTime;
817
153
    ASN1_TIME_to_tm(not_after, &dtTime);
818
153
    X509_free(x509);
819
820
153
    struct musl_tm dateTime;
821
153
    memset(&dateTime, 0, sizeof(struct musl_tm));
822
153
    dateTime.tm_year = dtTime.tm_year;
823
153
    dateTime.tm_mon = dtTime.tm_mon;
824
153
    dateTime.tm_mday = dtTime.tm_mday;
825
153
    dateTime.tm_hour = dtTime.tm_hour;
826
153
    dateTime.tm_min = dtTime.tm_min;
827
153
    dateTime.tm_sec = dtTime.tm_sec;
828
829
153
    long long sec_epoch = musl_tm_to_secs(&dateTime);
830
153
    *expiryDateTime = UA_DATETIME_UNIX_EPOCH;
831
153
    *expiryDateTime += sec_epoch * UA_DATETIME_SEC;
832
153
    return UA_STATUSCODE_GOOD;
833
221
}
834
835
UA_StatusCode
836
UA_CertificateUtils_getSubjectName(UA_ByteString *certificate,
837
550
                                   UA_String *subjectName) {
838
550
    if(!certificate || (certificate->length > 0 && !certificate->data) ||
839
550
       !subjectName)
840
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
841
550
    X509_NAME *sn = NULL;
842
550
    X509 *x509 = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
843
550
    X509_CRL *x509_crl = NULL;
844
845
550
    if(x509) {
846
7
        sn = X509_get_subject_name(x509);
847
543
    } else {
848
543
        x509_crl = UA_OpenSSL_LoadCrl(certificate);
849
543
        if(!x509_crl)
850
500
            return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
851
43
        sn = X509_CRL_get_issuer(x509_crl);
852
43
    }
853
854
50
    char buf[1024];
855
50
    char *name = X509_NAME_oneline(sn, buf, sizeof(buf));
856
50
    UA_StatusCode retval = UA_STATUSCODE_BADINTERNALERROR;
857
50
    UA_String result = UA_STRING_NULL;
858
50
    if(name) {
859
50
        UA_String tmp = UA_STRING(name);
860
50
        retval = UA_String_copy(&tmp, &result);
861
50
    }
862
863
50
    if(x509)
864
7
        X509_free(x509);
865
50
    if(x509_crl)
866
43
        X509_CRL_free(x509_crl);
867
50
    if(retval == UA_STATUSCODE_GOOD)
868
36
        *subjectName = result;
869
50
    return retval;
870
550
}
871
872
UA_StatusCode
873
UA_CertificateUtils_getThumbprint(UA_ByteString *certificate,
874
4
                                  UA_String *thumbprint) {
875
4
    if(certificate == NULL || thumbprint->length != (SHA1_DIGEST_LENGTH * 2))
876
4
        return UA_STATUSCODE_BADINTERNALERROR;
877
878
0
    unsigned char digest[SHA1_DIGEST_LENGTH];
879
0
    unsigned int digestLen;
880
881
0
    X509 *cert = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
882
0
    if(cert) {
883
0
        if(X509_digest(cert, EVP_sha1(), digest, &digestLen) != 1) {
884
0
            X509_free(cert);
885
0
            return UA_STATUSCODE_BADINTERNALERROR;
886
0
        }
887
0
        X509_free(cert);
888
0
    } else {
889
0
        X509_CRL *crl = UA_OpenSSL_LoadCrl(certificate);
890
0
        if(!crl)
891
0
            return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
892
0
        if(X509_CRL_digest(crl, EVP_sha1(), digest, &digestLen) != 1) {
893
0
            X509_CRL_free(crl);
894
0
            return UA_STATUSCODE_BADINTERNALERROR;
895
0
        }
896
0
        X509_CRL_free(crl);
897
0
    }
898
899
0
    UA_String thumb = UA_STRING_NULL;
900
0
    thumb.length = (SHA1_DIGEST_LENGTH * 2) + 1;
901
0
    thumb.data = (UA_Byte*)malloc(sizeof(UA_Byte) * thumb.length);
902
903
    /* Create a string containing a hex representation */
904
0
    char *p = (char*)thumb.data;
905
0
    for(size_t i = 0; i < digestLen; i++) {
906
0
        p += sprintf(p, "%.2X", digest[i]);
907
0
    }
908
909
0
    memcpy(thumbprint->data, thumb.data, thumbprint->length);
910
0
    free(thumb.data);
911
912
0
    return UA_STATUSCODE_GOOD;
913
0
}
914
915
UA_StatusCode
916
UA_CertificateUtils_getKeySize(UA_ByteString *certificate,
917
183
                               size_t *keySize){
918
183
    if(certificate == NULL)
919
0
        return UA_STATUSCODE_BADINTERNALERROR;
920
921
183
    X509 *cert = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
922
183
    if(!cert)
923
175
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
924
925
8
    EVP_PKEY *pkey = X509_get_pubkey(cert);
926
8
    if(!pkey) {
927
5
        X509_free(cert);
928
5
        return UA_STATUSCODE_BADINTERNALERROR;
929
5
    }
930
931
3
    if(EVP_PKEY_base_id(pkey) == EVP_PKEY_RSA) {
932
1
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
933
1
        *keySize = EVP_PKEY_get_size(pkey) * 8;
934
#else
935
        *keySize =  RSA_size(get_pkey_rsa(pkey)) * 8;
936
#endif
937
2
    } else if(EVP_PKEY_base_id(pkey) == EVP_PKEY_EC) {
938
2
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
939
2
        *keySize = EVP_PKEY_get_size(pkey) * 8;
940
#else
941
        *keySize =  ECDSA_size(EVP_PKEY_get0_EC_KEY(pkey)) * 8;
942
#endif
943
2
    } else {
944
0
        EVP_PKEY_free(pkey);
945
0
        X509_free(cert);
946
0
        return UA_STATUSCODE_BADINTERNALERROR; /* Unsupported key type */
947
0
    }
948
949
3
    EVP_PKEY_free(pkey);
950
3
    X509_free(cert);
951
952
3
    return UA_STATUSCODE_GOOD;
953
3
}
954
955
UA_StatusCode
956
UA_CertificateUtils_getExtendedKeyUsage(const UA_ByteString *certificate,
957
0
                                        UA_CertificateEku *extendedKeyUsage) {
958
0
    if(!certificate || !extendedKeyUsage)
959
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
960
961
0
    *extendedKeyUsage = UA_CERTIFICATEEKU_NONE;
962
0
    X509 *cert = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
963
0
    if(!cert)
964
0
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
965
966
0
    int critical = -1;
967
0
    EXTENDED_KEY_USAGE *eku = (EXTENDED_KEY_USAGE*)
968
0
        X509_get_ext_d2i(cert, NID_ext_key_usage, &critical, NULL);
969
0
    if(!eku) {
970
0
        X509_free(cert);
971
        /* -1 means that the extension is absent. Other values indicate an
972
         * invalid or duplicate extension. */
973
0
        return (critical == -1) ? UA_STATUSCODE_GOOD :
974
0
            UA_STATUSCODE_BADCERTIFICATEINVALID;
975
0
    }
976
977
0
    for(int i = 0; i < sk_ASN1_OBJECT_num(eku); i++) {
978
0
        ASN1_OBJECT *purpose = sk_ASN1_OBJECT_value(eku, i);
979
0
        switch(OBJ_obj2nid(purpose)) {
980
0
        case NID_server_auth:
981
0
            *extendedKeyUsage = (UA_CertificateEku)
982
0
                (*extendedKeyUsage | UA_CERTIFICATEEKU_SERVERAUTH);
983
0
            break;
984
0
        case NID_client_auth:
985
0
            *extendedKeyUsage = (UA_CertificateEku)
986
0
                (*extendedKeyUsage | UA_CERTIFICATEEKU_CLIENTAUTH);
987
0
            break;
988
0
        case NID_anyExtendedKeyUsage:
989
0
            *extendedKeyUsage = (UA_CertificateEku)
990
0
                (*extendedKeyUsage | UA_CERTIFICATEEKU_ANY);
991
0
            break;
992
0
        default:
993
0
            *extendedKeyUsage = (UA_CertificateEku)
994
0
                (*extendedKeyUsage | UA_CERTIFICATEEKU_OTHER);
995
0
            break;
996
0
        }
997
0
    }
998
999
0
    EXTENDED_KEY_USAGE_free(eku);
1000
0
    X509_free(cert);
1001
0
    return UA_STATUSCODE_GOOD;
1002
0
}
1003
1004
UA_StatusCode
1005
UA_CertificateUtils_comparePublicKeys(const UA_ByteString *certificate1,
1006
0
                                      const UA_ByteString *certificate2) {
1007
0
    if(certificate1 == NULL || certificate2 == NULL)
1008
0
        return UA_STATUSCODE_BADINTERNALERROR;
1009
1010
0
    BIO *dataBio1 = BIO_new_mem_buf(certificate1->data, certificate1->length);
1011
0
    if(!dataBio1)
1012
0
        return UA_STATUSCODE_BADINTERNALERROR;
1013
1014
0
    BIO *dataBio2 = BIO_new_mem_buf(certificate2->data, certificate2->length);
1015
0
    if(!dataBio2) {
1016
0
        BIO_free(dataBio1);
1017
0
        return UA_STATUSCODE_BADINTERNALERROR;
1018
0
    }
1019
1020
0
    X509 *cert1 = NULL;
1021
0
    X509 *cert2 = NULL;
1022
0
    X509_REQ *csr1 = NULL;
1023
0
    X509_REQ *csr2 = NULL;
1024
    /* Try to read the certificate as PEM first */
1025
0
    cert1 = PEM_read_bio_X509(dataBio1, NULL, 0, NULL);
1026
0
    if(!cert1) {
1027
        /* If PEM read fails, reset BIO and try reading as DER */
1028
0
        (void)BIO_reset(dataBio1);
1029
0
        cert1 = d2i_X509_bio(dataBio1, NULL);
1030
0
    }
1031
    /* Try to read as a csr */
1032
0
    if(!cert1) {
1033
0
        (void)BIO_reset(dataBio1);
1034
0
        csr1 = PEM_read_bio_X509_REQ(dataBio1, NULL, 0, NULL);
1035
0
        if(!csr1) {
1036
0
            (void)BIO_reset(dataBio1);
1037
0
            csr1 = d2i_X509_REQ_bio(dataBio1, NULL);
1038
0
        }
1039
0
    }
1040
0
    if(!cert1 && !csr1) {
1041
0
        BIO_free(dataBio1);
1042
0
        BIO_free(dataBio2);
1043
0
        return UA_STATUSCODE_BADINTERNALERROR;
1044
0
    }
1045
1046
0
    cert2 = PEM_read_bio_X509(dataBio2, NULL, 0, NULL);
1047
0
    if(!cert2) {
1048
        /* If PEM read fails, reset BIO and try reading as DER */
1049
0
        (void)BIO_reset(dataBio2);
1050
0
        cert2 = d2i_X509_bio(dataBio2, NULL);
1051
0
    }
1052
    /* Try to load as a csr */
1053
0
    if(!cert2) {
1054
0
        (void)BIO_reset(dataBio2);
1055
0
        csr2 = PEM_read_bio_X509_REQ(dataBio2, NULL, 0, NULL);
1056
0
        if(!csr2) {
1057
0
            (void)BIO_reset(dataBio2);
1058
0
            csr2 = d2i_X509_REQ_bio(dataBio2, NULL);
1059
0
        }
1060
0
    }
1061
0
    if(!cert2 && !csr2) {
1062
0
        X509_free(cert1);
1063
0
        X509_REQ_free(csr1);
1064
0
        BIO_free(dataBio1);
1065
0
        BIO_free(dataBio2);
1066
0
        return UA_STATUSCODE_BADINTERNALERROR;
1067
0
    }
1068
1069
0
    BIO_free(dataBio1);
1070
0
    BIO_free(dataBio2);
1071
1072
0
    EVP_PKEY *pkey1 = cert1 ? X509_get_pubkey(cert1) : X509_REQ_get_pubkey(csr1);
1073
0
    EVP_PKEY *pkey2 = cert2 ? X509_get_pubkey(cert2) : X509_REQ_get_pubkey(csr2);
1074
1075
0
    X509_free(cert1);
1076
0
    X509_free(cert2);
1077
0
    X509_REQ_free(csr1);
1078
0
    X509_REQ_free(csr2);
1079
1080
0
    if(!pkey1 || !pkey2) {
1081
0
        EVP_PKEY_free(pkey1);
1082
0
        EVP_PKEY_free(pkey2);
1083
0
        return UA_STATUSCODE_BADINTERNALERROR;
1084
0
    }
1085
1086
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
1087
0
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
1088
0
    int isEqual = EVP_PKEY_eq(pkey1, pkey2);
1089
0
    if(isEqual == 0)
1090
0
        retval = UA_STATUSCODE_BADNOMATCH;
1091
0
    if(isEqual < 0)
1092
0
        retval = UA_STATUSCODE_BADINTERNALERROR;
1093
#else
1094
    int isEqual = EVP_PKEY_cmp(pkey1, pkey2);
1095
    if(isEqual == 0)
1096
        retval = UA_STATUSCODE_BADNOMATCH;
1097
    if(isEqual < 0)
1098
        retval = UA_STATUSCODE_BADINTERNALERROR;
1099
#endif
1100
1101
0
    EVP_PKEY_free(pkey1);
1102
0
    EVP_PKEY_free(pkey2);
1103
1104
0
    return retval;
1105
0
}
1106
1107
UA_StatusCode
1108
UA_CertificateUtils_checkKeyPair(const UA_ByteString *certificate,
1109
0
                                 const UA_ByteString *privateKey) {
1110
0
    if(certificate == NULL || privateKey == NULL)
1111
0
        return UA_STATUSCODE_BADINTERNALERROR;
1112
1113
0
    X509 *cert = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
1114
0
    if(!cert)
1115
0
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
1116
1117
0
    EVP_PKEY *pkey = UA_OpenSSL_LoadPrivateKey(privateKey);
1118
0
    if(!pkey) {
1119
0
        X509_free(cert);
1120
0
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
1121
0
    }
1122
1123
    /* Verify if the private key matches the public key in the certificate */
1124
0
    if(X509_check_private_key(cert, pkey) != 1) {
1125
0
        X509_free(cert);
1126
0
        EVP_PKEY_free(pkey);
1127
0
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
1128
0
    }
1129
1130
0
    X509_free(cert);
1131
0
    EVP_PKEY_free(pkey);
1132
1133
0
    return UA_STATUSCODE_GOOD;
1134
0
}
1135
1136
UA_StatusCode
1137
1.04k
UA_CertificateUtils_checkCA(const UA_ByteString *certificate) {
1138
1.04k
    if(certificate == NULL)
1139
0
        return UA_STATUSCODE_BADINTERNALERROR;
1140
1141
1.04k
    X509 *certificateX509 = UA_OpenSSL_LoadCertificate(certificate, EVP_PKEY_NONE);
1142
1.04k
    if(!certificateX509)
1143
923
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
1144
1145
123
    UA_StatusCode retval = openSSLCheckCA(certificateX509) ?
1146
107
        UA_STATUSCODE_GOOD : UA_STATUSCODE_BADNOMATCH;
1147
123
    X509_free(certificateX509);
1148
123
    return retval;
1149
1.04k
}
1150
1151
static int
1152
0
privateKeyPasswordCallback(char *buf, int size, int rwflag, void *userdata) {
1153
0
    (void) rwflag;
1154
0
    UA_ByteString *pw = (UA_ByteString*)userdata;
1155
0
    if(pw->length <= (size_t)size)
1156
0
        memcpy(buf, pw->data, pw->length);
1157
0
    return (int)pw->length;
1158
0
}
1159
1160
UA_StatusCode
1161
UA_CertificateUtils_decryptPrivateKey(const UA_ByteString privateKey,
1162
                                      const UA_ByteString password,
1163
0
                                      UA_ByteString *outDerKey) {
1164
0
    if(!outDerKey)
1165
0
        return UA_STATUSCODE_BADINTERNALERROR;
1166
1167
0
    if(privateKey.length == 0) {
1168
0
        *outDerKey = UA_BYTESTRING_NULL;
1169
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
1170
0
    }
1171
1172
0
    EVP_PKEY *pkey = NULL;
1173
0
    const unsigned char * in = privateKey.data;
1174
1175
    /* Check if input is already in DER format */
1176
0
    pkey = d2i_AutoPrivateKey(NULL, &in, privateKey.length);
1177
0
    if(pkey != NULL) {
1178
0
        EVP_PKEY_free(pkey);
1179
0
        return UA_ByteString_copy(&privateKey, outDerKey);
1180
0
    }
1181
1182
    /* Decrypt */
1183
0
    BIO *bio = BIO_new_mem_buf((void*)privateKey.data, (int)privateKey.length);
1184
0
    pkey = PEM_read_bio_PrivateKey(bio, NULL,
1185
0
                                             privateKeyPasswordCallback,
1186
0
                                             (void*)(uintptr_t)&password);
1187
0
    BIO_free(bio);
1188
0
    if(!pkey)
1189
0
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
1190
1191
    /* Write DER encoded, allocates the new memory */
1192
0
    unsigned char *data = NULL;
1193
0
    const int numBytes = i2d_PrivateKey(pkey, &data);
1194
0
    EVP_PKEY_free(pkey);
1195
0
    if(!data)
1196
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
1197
1198
    /* Copy to the data to outDerKey
1199
     * Passing the data pointer directly causes a heap corruption on Windows
1200
     * when outDerKey is cleared.
1201
     */
1202
0
    UA_ByteString temp = UA_BYTESTRING_NULL;
1203
0
    temp.data = data;
1204
0
    temp.length = (size_t)numBytes;
1205
0
    const UA_StatusCode success = UA_ByteString_copy(&temp, outDerKey);
1206
    /* OPENSSL_clear_free() is not supported by the LibreSSL version in the CI */
1207
0
    OPENSSL_cleanse(data, numBytes);
1208
0
    OPENSSL_free(data);
1209
0
    return success;
1210
0
}
1211
1212
UA_StatusCode
1213
0
UA_CertificateUtils_getCertCommonName(const UA_ByteString *certificate, UA_String *commonName) {
1214
0
  UA_StatusCode retval = UA_STATUSCODE_BADNOTFOUND;
1215
0
    const unsigned char *p = NULL;
1216
0
  X509 *x509;
1217
0
  X509_NAME *subj;
1218
1219
0
  if(!certificate || !certificate->data || !commonName)
1220
0
    return UA_STATUSCODE_BADINVALIDARGUMENT;
1221
0
  p = certificate->data;
1222
1223
0
  x509 = d2i_X509(NULL, &p, (long)certificate->length);
1224
0
  if(!x509)
1225
0
    return UA_STATUSCODE_BADINTERNALERROR;
1226
1227
0
    subj = X509_get_subject_name(x509);
1228
1229
0
    UA_String result = UA_STRING_NULL;
1230
0
    if(subj) {
1231
0
        char buf[1024] = {0};
1232
0
        int length = X509_NAME_get_text_by_NID(subj, NID_commonName, buf, sizeof(buf));
1233
0
        if(length >= 0) {
1234
0
            UA_String tmp = {(size_t)length, (UA_Byte*)buf};
1235
0
            retval = UA_String_copy(&tmp, &result);
1236
0
        }
1237
0
    }
1238
0
  X509_free(x509);
1239
1240
0
  if(retval == UA_STATUSCODE_GOOD)
1241
0
    *commonName = result;
1242
0
  return retval;
1243
0
}
1244
1245
#endif