Coverage Report

Created: 2025-07-01 07:01

/src/open62541/plugins/crypto/mbedtls/certificategroup.c
Line
Count
Source (jump to first uncovered line)
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 2018 (c) Mark Giraud, Fraunhofer IOSB
5
 *    Copyright 2019 (c) Kalycito Infotech Private Limited
6
 *    Copyright 2019 (c) Julius Pfrommer, Fraunhofer IOSB
7
 *    Copyright 2024 (c) Fraunhofer IOSB (Author: Noel Graf)
8
 */
9
10
#include <open62541/util.h>
11
#include <open62541/plugin/certificategroup_default.h>
12
13
#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS
14
15
#include <mbedtls/x509.h>
16
#include <mbedtls/oid.h>
17
#include <mbedtls/x509_crt.h>
18
#include <mbedtls/entropy.h>
19
#include <mbedtls/version.h>
20
#include <mbedtls/sha256.h>
21
#if defined(MBEDTLS_USE_PSA_CRYPTO)
22
#include <mbedtls/psa_util.h>
23
#endif
24
25
#include "securitypolicy_common.h"
26
27
#define REMOTECERTIFICATETRUSTED 1
28
#define ISSUERKNOWN              2
29
#define DUALPARENT               3
30
#define PARENTFOUND              4
31
32
/* Configuration parameters */
33
34
#define MEMORYCERTSTORE_PARAMETERSSIZE 2
35
0
#define MEMORYCERTSTORE_PARAMINDEX_MAXTRUSTLISTSIZE 0
36
0
#define MEMORYCERTSTORE_PARAMINDEX_MAXREJECTEDLISTSIZE 1
37
38
static const struct {
39
    UA_QualifiedName name;
40
    const UA_DataType *type;
41
    UA_Boolean required;
42
} MemoryCertStoreParameters[MEMORYCERTSTORE_PARAMETERSSIZE] = {
43
    {{0, UA_STRING_STATIC("max-trust-listsize")}, &UA_TYPES[UA_TYPES_UINT16], false},
44
    {{0, UA_STRING_STATIC("max-rejected-listsize")}, &UA_TYPES[UA_TYPES_STRING], false}
45
};
46
47
typedef struct {
48
    UA_TrustListDataType trustList;
49
    size_t rejectedCertificatesSize;
50
    UA_ByteString *rejectedCertificates;
51
52
    UA_UInt32 maxTrustListSize;
53
    UA_UInt32 maxRejectedListSize;
54
55
    UA_Boolean reloadRequired;
56
57
    mbedtls_x509_crt trustedCertificates;
58
    mbedtls_x509_crt issuerCertificates;
59
    mbedtls_x509_crl trustedCrls;
60
    mbedtls_x509_crl issuerCrls;
61
} MemoryCertStore;
62
63
static UA_Boolean mbedtlsCheckCA(mbedtls_x509_crt *cert);
64
65
static UA_StatusCode
66
0
MemoryCertStore_removeFromTrustList(UA_CertificateGroup *certGroup, const UA_TrustListDataType *trustList) {
67
    /* Check parameter */
68
0
    if(certGroup == NULL || trustList == NULL) {
69
0
        return UA_STATUSCODE_BADINTERNALERROR;
70
0
    }
71
72
0
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
73
0
    context->reloadRequired = true;
74
0
    return UA_TrustListDataType_remove(trustList, &context->trustList);
75
0
}
76
77
static UA_StatusCode
78
0
MemoryCertStore_getTrustList(UA_CertificateGroup *certGroup, UA_TrustListDataType *trustList) {
79
    /* Check parameter */
80
0
    if(certGroup == NULL || trustList == NULL) {
81
0
        return UA_STATUSCODE_BADINTERNALERROR;
82
0
    }
83
84
0
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
85
0
    return UA_TrustListDataType_copy(&context->trustList, trustList);
86
0
}
87
88
static UA_StatusCode
89
0
MemoryCertStore_setTrustList(UA_CertificateGroup *certGroup, const UA_TrustListDataType *trustList) {
90
    /* Check parameter */
91
0
    if(certGroup == NULL || trustList == NULL) {
92
0
        return UA_STATUSCODE_BADINTERNALERROR;
93
0
    }
94
95
0
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
96
0
    if(context->maxTrustListSize != 0 && UA_TrustListDataType_getSize(trustList) > context->maxTrustListSize) {
97
0
        return UA_STATUSCODE_BADINTERNALERROR;
98
0
    }
99
0
    context->reloadRequired = true;
100
    /* Remove the section of the trust list that needs to be reset, while keeping the remaining parts intact */
101
0
    return UA_TrustListDataType_set(trustList, &context->trustList);
102
0
}
103
104
static UA_StatusCode
105
0
MemoryCertStore_addToTrustList(UA_CertificateGroup *certGroup, const UA_TrustListDataType *trustList) {
106
    /* Check parameter */
107
0
    if(certGroup == NULL || trustList == NULL) {
108
0
        return UA_STATUSCODE_BADINTERNALERROR;
109
0
    }
110
111
0
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
112
0
    if(context->maxTrustListSize != 0 && UA_TrustListDataType_getSize(&context->trustList) + UA_TrustListDataType_getSize(trustList) > context->maxTrustListSize) {
113
0
        return UA_STATUSCODE_BADINTERNALERROR;
114
0
    }
115
0
    context->reloadRequired = true;
116
0
    return UA_TrustListDataType_add(trustList, &context->trustList);
117
0
}
118
119
static UA_StatusCode
120
0
MemoryCertStore_getRejectedList(UA_CertificateGroup *certGroup, UA_ByteString **rejectedList, size_t *rejectedListSize) {
121
    /* Check parameter */
122
0
    if(certGroup == NULL || rejectedList == NULL || rejectedListSize == NULL) {
123
0
        return UA_STATUSCODE_BADINTERNALERROR;
124
0
    }
125
126
0
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
127
0
    UA_StatusCode retval = UA_Array_copy(context->rejectedCertificates, context->rejectedCertificatesSize,
128
0
                                         (void**)rejectedList, &UA_TYPES[UA_TYPES_BYTESTRING]);
129
130
0
    if(retval == UA_STATUSCODE_GOOD)
131
0
        *rejectedListSize = context->rejectedCertificatesSize;
132
133
0
    return retval;
134
0
}
135
136
static UA_StatusCode
137
0
mbedtlsCheckCrlMatch(mbedtls_x509_crt *cert, mbedtls_x509_crl *crl) {
138
0
    char certSubject[MBEDTLS_X509_MAX_DN_NAME_SIZE];
139
0
    char crlIssuer[MBEDTLS_X509_MAX_DN_NAME_SIZE];
140
141
0
    mbedtls_x509_dn_gets(certSubject, sizeof(certSubject), &cert->subject);
142
0
    mbedtls_x509_dn_gets(crlIssuer, sizeof(crlIssuer), &crl->issuer);
143
144
0
    if(strncmp(certSubject, crlIssuer, MBEDTLS_X509_MAX_DN_NAME_SIZE) == 0)
145
0
        return UA_STATUSCODE_GOOD;
146
147
0
    return UA_STATUSCODE_BADNOMATCH;
148
0
}
149
150
static UA_StatusCode
151
mbedtlsFindCrls(UA_CertificateGroup *certGroup, const UA_ByteString *certificate,
152
             const UA_ByteString *crlList, const size_t crlListSize,
153
0
             UA_ByteString **crls, size_t *crlsSize) {
154
0
    mbedtls_x509_crt cert;
155
0
    mbedtls_x509_crt_init(&cert);
156
0
    UA_StatusCode retval = UA_mbedTLS_LoadCertificate(certificate, &cert);
157
0
    if(retval != UA_STATUSCODE_GOOD) {
158
0
        UA_LOG_WARNING(certGroup->logging, UA_LOGCATEGORY_SECURITYPOLICY,
159
0
            "An error occurred while parsing the certificate.");
160
0
        return retval;
161
0
    }
162
163
    /* Check if the certificate is a CA certificate.
164
     * Only a CA certificate can have a CRL. */
165
0
    if(!mbedtlsCheckCA(&cert)) {
166
0
        UA_LOG_WARNING(certGroup->logging, UA_LOGCATEGORY_SECURITYPOLICY,
167
0
               "The certificate is not a CA certificate and therefore does not have a CRL.");
168
0
        mbedtls_x509_crt_free(&cert);
169
0
        return UA_STATUSCODE_GOOD;
170
0
    }
171
172
0
    UA_Boolean foundMatch = false;
173
0
    for(size_t i = 0; i < crlListSize; i++) {
174
0
        mbedtls_x509_crl crl;
175
0
        mbedtls_x509_crl_init(&crl);
176
0
        retval = UA_mbedTLS_LoadCrl(&crlList[i], &crl);
177
0
        if(retval != UA_STATUSCODE_GOOD) {
178
0
            UA_LOG_WARNING(certGroup->logging, UA_LOGCATEGORY_SECURITYPOLICY,
179
0
                "An error occurred while parsing the crl.");
180
0
            mbedtls_x509_crt_free(&cert);
181
0
            return retval;
182
0
        }
183
184
0
        retval = mbedtlsCheckCrlMatch(&cert, &crl);
185
0
        mbedtls_x509_crl_free(&crl);
186
0
        if(retval != UA_STATUSCODE_GOOD) {
187
0
            continue;
188
0
        }
189
190
        /* Continue the search, as a certificate may be associated with multiple CRLs. */
191
0
        foundMatch = true;
192
0
        retval = UA_Array_appendCopy((void **)crls, crlsSize, &crlList[i],
193
0
                                 &UA_TYPES[UA_TYPES_BYTESTRING]);
194
0
        if(retval != UA_STATUSCODE_GOOD) {
195
0
            mbedtls_x509_crt_free(&cert);
196
0
            return retval;
197
0
        }
198
0
    }
199
0
    mbedtls_x509_crt_free(&cert);
200
201
0
    if(!foundMatch)
202
0
        return UA_STATUSCODE_BADNOMATCH;
203
204
0
    return UA_STATUSCODE_GOOD;
205
0
}
206
207
static UA_StatusCode
208
MemoryCertStore_getCertificateCrls(UA_CertificateGroup *certGroup, const UA_ByteString *certificate,
209
                                   const UA_Boolean isTrusted, UA_ByteString **crls,
210
0
                                   size_t *crlsSize) {
211
    /* Check parameter */
212
0
    if(certGroup == NULL || certificate == NULL || crls == NULL) {
213
0
        return UA_STATUSCODE_BADINTERNALERROR;
214
0
    }
215
216
0
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
217
218
0
    if(isTrusted) {
219
0
        return mbedtlsFindCrls(certGroup, certificate,
220
0
                               context->trustList.trustedCrls,
221
0
                               context->trustList.trustedCrlsSize, crls,
222
0
                               crlsSize);
223
0
    }
224
0
    return mbedtlsFindCrls(certGroup, certificate,
225
0
                           context->trustList.issuerCrls,
226
0
                           context->trustList.issuerCrlsSize, crls,
227
0
                           crlsSize);
228
0
}
229
230
static UA_StatusCode
231
0
MemoryCertStore_addToRejectedList(UA_CertificateGroup *certGroup, const UA_ByteString *certificate) {
232
    /* Check parameter */
233
0
    if(certGroup == NULL || certificate == NULL) {
234
0
        return UA_STATUSCODE_BADINTERNALERROR;
235
0
    }
236
237
0
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
238
239
    /* check duplicate certificate */
240
0
    for(size_t i = 0; i < context->rejectedCertificatesSize; i++) {
241
0
        if(UA_ByteString_equal(certificate, &context->rejectedCertificates[i]))
242
0
            return UA_STATUSCODE_GOOD; /* certificate already exist */
243
0
    }
244
245
    /* Store rejected certificate */
246
0
    if(context->maxRejectedListSize == 0 || context->rejectedCertificatesSize < context->maxRejectedListSize) {
247
0
        return UA_Array_appendCopy((void**)&context->rejectedCertificates, &context->rejectedCertificatesSize,
248
0
                                   certificate, &UA_TYPES[UA_TYPES_BYTESTRING]);
249
0
    }
250
0
    UA_Array_delete(context->rejectedCertificates, context->rejectedCertificatesSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
251
0
    context->rejectedCertificates = NULL;
252
0
    context->rejectedCertificatesSize = 0;
253
0
    return UA_Array_appendCopy((void**)&context->rejectedCertificates, &context->rejectedCertificatesSize,
254
0
                               certificate, &UA_TYPES[UA_TYPES_BYTESTRING]);
255
0
}
256
257
static void
258
0
MemoryCertStore_clear(UA_CertificateGroup *certGroup) {
259
    /* check parameter */
260
0
    if(certGroup == NULL) {
261
0
        return;
262
0
    }
263
264
0
    UA_NodeId_clear(&certGroup->certificateGroupId);
265
266
0
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
267
0
    if(context) {
268
0
        UA_TrustListDataType_clear(&context->trustList);
269
270
0
        UA_Array_delete(context->rejectedCertificates, context->rejectedCertificatesSize, &UA_TYPES[UA_TYPES_BYTESTRING]);
271
0
        context->rejectedCertificates = NULL;
272
0
        context->rejectedCertificatesSize = 0;
273
274
0
        mbedtls_x509_crt_free(&context->trustedCertificates);
275
0
        mbedtls_x509_crt_free(&context->issuerCertificates);
276
0
        mbedtls_x509_crl_free(&context->trustedCrls);
277
0
        mbedtls_x509_crl_free(&context->issuerCrls);
278
279
0
        UA_free(context);
280
0
        certGroup->context = NULL;
281
0
    }
282
0
}
283
284
static UA_StatusCode
285
0
reloadCertificates(UA_CertificateGroup *certGroup) {
286
    /* Check parameter */
287
0
    if(certGroup == NULL) {
288
0
        return UA_STATUSCODE_BADINTERNALERROR;
289
0
    }
290
291
0
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
292
0
    UA_ByteString data;
293
0
    UA_ByteString_init(&data);
294
0
    int err = 0;
295
296
0
    mbedtls_x509_crt_free(&context->trustedCertificates);
297
0
    mbedtls_x509_crt_init(&context->trustedCertificates);
298
0
    for(size_t i = 0; i < context->trustList.trustedCertificatesSize; ++i) {
299
0
        data = UA_mbedTLS_CopyDataFormatAware(&context->trustList.trustedCertificates[i]);
300
0
        err = mbedtls_x509_crt_parse(&context->trustedCertificates, data.data, data.length);
301
0
        UA_ByteString_clear(&data);
302
0
        if(err)
303
0
            return UA_STATUSCODE_BADINTERNALERROR;
304
0
    }
305
306
0
    mbedtls_x509_crt_free(&context->issuerCertificates);
307
0
    mbedtls_x509_crt_init(&context->issuerCertificates);
308
0
    for(size_t i = 0; i < context->trustList.issuerCertificatesSize; ++i) {
309
0
        data = UA_mbedTLS_CopyDataFormatAware(&context->trustList.issuerCertificates[i]);
310
0
        err = mbedtls_x509_crt_parse(&context->issuerCertificates, data.data, data.length);
311
0
        UA_ByteString_clear(&data);
312
0
        if(err)
313
0
            return UA_STATUSCODE_BADINTERNALERROR;
314
0
    }
315
316
0
    mbedtls_x509_crl_free(&context->trustedCrls);
317
0
    mbedtls_x509_crl_init(&context->trustedCrls);
318
0
    for(size_t i = 0; i < context->trustList.trustedCrlsSize; i++) {
319
0
        data = UA_mbedTLS_CopyDataFormatAware(&context->trustList.trustedCrls[i]);
320
0
        err = mbedtls_x509_crl_parse(&context->trustedCrls, data.data, data.length);
321
0
        UA_ByteString_clear(&data);
322
0
        if(err)
323
0
            return UA_STATUSCODE_BADINTERNALERROR;
324
0
    }
325
326
0
    mbedtls_x509_crl_free(&context->issuerCrls);
327
0
    mbedtls_x509_crl_init(&context->issuerCrls);
328
0
    for(size_t i = 0; i < context->trustList.issuerCrlsSize; i++) {
329
0
        data = UA_mbedTLS_CopyDataFormatAware(&context->trustList.issuerCrls[i]);
330
0
        err = mbedtls_x509_crl_parse(&context->issuerCrls, data.data, data.length);
331
0
        UA_ByteString_clear(&data);
332
0
        if(err)
333
0
            return UA_STATUSCODE_BADINTERNALERROR;
334
0
    }
335
336
0
    return UA_STATUSCODE_GOOD;
337
0
}
338
339
0
#define UA_MBEDTLS_MAX_CHAIN_LENGTH 10
340
0
#define UA_MBEDTLS_MAX_DN_LENGTH 256
341
342
/* We need to access some private fields below */
343
#ifndef MBEDTLS_PRIVATE
344
0
#define MBEDTLS_PRIVATE(x) x
345
#endif
346
347
/* Is the certificate a CA? */
348
static UA_Boolean
349
0
mbedtlsCheckCA(mbedtls_x509_crt *cert) {
350
    /* The Basic Constraints extension must be set and the cert acts as CA */
351
0
    if(!(cert->MBEDTLS_PRIVATE(ext_types) & MBEDTLS_X509_EXT_BASIC_CONSTRAINTS) ||
352
0
       !cert->MBEDTLS_PRIVATE(ca_istrue))
353
0
        return false;
354
355
    /* The Key Usage extension must be set to cert signing and CRL issuing */
356
0
    if(!(cert->MBEDTLS_PRIVATE(ext_types) & MBEDTLS_X509_EXT_KEY_USAGE) ||
357
0
       mbedtls_x509_crt_check_key_usage(cert, MBEDTLS_X509_KU_KEY_CERT_SIGN) != 0 ||
358
0
       mbedtls_x509_crt_check_key_usage(cert, MBEDTLS_X509_KU_CRL_SIGN) != 0)
359
0
        return false;
360
361
0
    return true;
362
0
}
363
364
static UA_Boolean
365
0
mbedtlsSameName(UA_String name, const mbedtls_x509_name *name2) {
366
0
    char buf[UA_MBEDTLS_MAX_DN_LENGTH];
367
0
    int len = mbedtls_x509_dn_gets(buf, UA_MBEDTLS_MAX_DN_LENGTH, name2);
368
0
    if(len < 0)
369
0
        return false;
370
0
    UA_String nameString = {(size_t)len, (UA_Byte*)buf};
371
0
    return UA_String_equal(&name, &nameString);
372
0
}
373
374
static UA_Boolean
375
0
mbedtlsSameBuf(mbedtls_x509_buf *a, mbedtls_x509_buf *b) {
376
0
    if(a->len != b->len)
377
0
        return false;
378
0
    return (memcmp(a->p, b->p, a->len) == 0);
379
0
}
380
381
/* Return the first matching issuer candidate AFTER prev.
382
 * This can return the cert itself if self-signed. */
383
static mbedtls_x509_crt *
384
mbedtlsFindNextIssuer(MemoryCertStore *ctx, mbedtls_x509_crt *stack,
385
0
                      mbedtls_x509_crt *cert, mbedtls_x509_crt *prev) {
386
0
    char inbuf[UA_MBEDTLS_MAX_DN_LENGTH];
387
0
    int nameLen = mbedtls_x509_dn_gets(inbuf, UA_MBEDTLS_MAX_DN_LENGTH, &cert->issuer);
388
0
    if(nameLen < 0)
389
0
        return NULL;
390
0
    UA_String issuerName = {(size_t)nameLen, (UA_Byte*)inbuf};
391
0
    do {
392
0
        for(mbedtls_x509_crt *i = stack; i; i = i->next) {
393
0
            if(prev) {
394
0
                if(prev == i)
395
0
                    prev = NULL; /* This was the last issuer we tried to verify */
396
0
                continue;
397
0
            }
398
            /* Compare issuer name and subject name.
399
             * Skip when the key does not match the signature. */
400
0
            if(mbedtlsSameName(issuerName, &i->subject) &&
401
0
               mbedtls_pk_can_do(&i->pk, cert->MBEDTLS_PRIVATE(sig_pk)))
402
0
                return i;
403
0
        }
404
405
        /* Switch from the stack that came with the cert to the issuer list and
406
         * then to the trust list. */
407
0
        if(stack == &ctx->trustedCertificates)
408
0
            stack = NULL;
409
0
        else if(stack == &ctx->issuerCertificates)
410
0
            stack = &ctx->trustedCertificates;
411
0
        else
412
0
            stack = &ctx->issuerCertificates;
413
0
    } while(stack);
414
0
    return NULL;
415
0
}
416
417
static UA_StatusCode
418
0
mbedtlsCheckRevoked(UA_CertificateGroup *cg, MemoryCertStore *ctx, mbedtls_x509_crt *cert) {
419
    /* Parse the Issuer Name */
420
0
    char inbuf[UA_MBEDTLS_MAX_DN_LENGTH];
421
0
    int nameLen = mbedtls_x509_dn_gets(inbuf, UA_MBEDTLS_MAX_DN_LENGTH, &cert->issuer);
422
0
    if(nameLen < 0)
423
0
        return UA_STATUSCODE_BADINTERNALERROR;
424
0
    UA_String issuerName = {(size_t)nameLen, (UA_Byte*)inbuf};
425
426
0
    if(ctx->trustedCrls.raw.len == 0 && ctx->issuerCrls.raw.len == 0) {
427
0
        UA_LOG_WARNING(cg->logging, UA_LOGCATEGORY_SECURITYPOLICY,
428
0
                       "Zero revocation lists have been loaded. "
429
0
                       "This seems intentional - omitting the check.");
430
0
        return UA_STATUSCODE_GOOD;
431
0
    }
432
433
    /* Loop over the crl and match the Issuer Name */
434
0
    UA_StatusCode res = UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN;
435
0
    for(mbedtls_x509_crl *crl = &ctx->trustedCrls; crl; crl = crl->next) {
436
        /* Is the CRL for certificates from the cert issuer?
437
         * Is the serial number of the certificate contained in the CRL? */
438
0
        if(mbedtlsSameName(issuerName, &crl->issuer)) {
439
0
            if(mbedtls_x509_crt_is_revoked(cert, crl) != 0)
440
0
                return UA_STATUSCODE_BADCERTIFICATEREVOKED;
441
0
            res = UA_STATUSCODE_GOOD; /* There was at least one crl that did not revoke (so far) */
442
0
        }
443
0
    }
444
445
    /* Loop over the issuer crls separately */
446
0
    for(mbedtls_x509_crl *crl = &ctx->issuerCrls; crl; crl = crl->next) {
447
0
        if(mbedtlsSameName(issuerName, &crl->issuer)) {
448
0
            if(mbedtls_x509_crt_is_revoked(cert, crl) != 0)
449
0
                return UA_STATUSCODE_BADCERTIFICATEREVOKED;
450
0
            res = UA_STATUSCODE_GOOD;
451
0
        }
452
0
    }
453
454
0
    return res;
455
0
}
456
457
/* Verify that the public key of the issuer was used to sign the certificate */
458
static UA_Boolean
459
0
mbedtlsCheckSignature(const mbedtls_x509_crt *cert, mbedtls_x509_crt *issuer) {
460
0
    size_t hash_len;
461
0
    unsigned char hash[MBEDTLS_MD_MAX_SIZE];
462
0
    mbedtls_md_type_t md = cert->MBEDTLS_PRIVATE(sig_md);
463
0
#if !defined(MBEDTLS_USE_PSA_CRYPTO)
464
0
    const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(md);
465
0
    hash_len = mbedtls_md_get_size(md_info);
466
0
    if(mbedtls_md(md_info, cert->tbs.p, cert->tbs.len, hash) != 0)
467
0
        return false;
468
#else
469
    if(psa_hash_compute(mbedtls_md_psa_alg_from_type(md), cert->tbs.p,
470
                        cert->tbs.len, hash, sizeof(hash), &hash_len) != PSA_SUCCESS)
471
        return false;
472
#endif
473
0
    const mbedtls_x509_buf *sig = &cert->MBEDTLS_PRIVATE(sig);
474
0
    void *sig_opts = cert->MBEDTLS_PRIVATE(sig_opts);
475
0
    mbedtls_pk_type_t pktype = cert->MBEDTLS_PRIVATE(sig_pk);
476
0
    return (mbedtls_pk_verify_ext(pktype, sig_opts, &issuer->pk, md,
477
0
                                  hash, hash_len, sig->p, sig->len) == 0);
478
0
}
479
480
static UA_StatusCode
481
mbedtlsVerifyChain(UA_CertificateGroup *cg, MemoryCertStore *ctx, mbedtls_x509_crt *stack,
482
0
                   mbedtls_x509_crt **old_issuers, mbedtls_x509_crt *cert, int depth) {
483
    /* Maxiumum chain length */
484
0
    if(depth == UA_MBEDTLS_MAX_CHAIN_LENGTH)
485
0
        return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
486
487
    /* Verification Step: Validity Period */
488
0
    if(mbedtls_x509_time_is_future(&cert->valid_from) ||
489
0
       mbedtls_x509_time_is_past(&cert->valid_to))
490
0
        return (depth == 0) ? UA_STATUSCODE_BADCERTIFICATETIMEINVALID :
491
0
            UA_STATUSCODE_BADCERTIFICATEISSUERTIMEINVALID;
492
493
    /* Return the most specific error code. BADCERTIFICATECHAININCOMPLETE is
494
     * returned only if all possible chains are incomplete. */
495
0
    mbedtls_x509_crt *issuer = NULL;
496
0
    UA_StatusCode ret = UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
497
0
    while(ret != UA_STATUSCODE_GOOD) {
498
        /* Find the issuer. This can return the same certificate if it is
499
         * self-signed (subject == issuer). We come back here to try a different
500
         * "path" if a subsequent verification fails. */
501
0
        issuer = mbedtlsFindNextIssuer(ctx, stack, cert, issuer);
502
0
        if(!issuer)
503
0
            break;
504
505
        /* Verification Step: Certificate Usage
506
         * Can the issuer act as CA? Omit for self-signed leaf certificates. */
507
0
        if((depth > 0 || issuer != cert) && !mbedtlsCheckCA(issuer)) {
508
0
            ret = UA_STATUSCODE_BADCERTIFICATEISSUERUSENOTALLOWED;
509
0
            continue;
510
0
        }
511
512
        /* Verification Step: Signature */
513
0
        if(!mbedtlsCheckSignature(cert, issuer)) {
514
0
            ret = UA_STATUSCODE_BADCERTIFICATEINVALID;  /* Wrong issuer, try again */
515
0
            continue;
516
0
        }
517
518
        /* The certificate is self-signed. We have arrived at the top of the
519
         * chain. We check whether the certificate is trusted below. This is the
520
         * only place where we return UA_STATUSCODE_BADCERTIFICATEUNTRUSTED.
521
         * This signals that the chain is complete (but can be still
522
         * untrusted).
523
         *
524
         * Break here as we have reached the end of the chain. Omit the
525
         * Revocation Check for self-signed certificates. */
526
0
        if(issuer == cert || mbedtlsSameBuf(&cert->tbs, &issuer->tbs)) {
527
0
            ret = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED;
528
0
            break;
529
0
        }
530
531
        /* Verification Step: Revocation Check */
532
0
        ret = mbedtlsCheckRevoked(cg, ctx, cert);
533
0
        if(depth > 0) {
534
0
            if(ret == UA_STATUSCODE_BADCERTIFICATEREVOKED)
535
0
                ret = UA_STATUSCODE_BADCERTIFICATEISSUERREVOKED;
536
0
            if(ret == UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN)
537
0
                ret = UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN;
538
0
        }
539
0
        if(ret != UA_STATUSCODE_GOOD)
540
0
            continue;
541
542
        /* Detect (endless) loops of issuers */
543
0
        for(int i = 0; i < depth; i++) {
544
0
            if(old_issuers[i] == issuer)
545
0
                return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
546
0
        }
547
0
        old_issuers[depth] = issuer;
548
549
        /* We have found the issuer certificate used for the signature. Recurse
550
         * to the next certificate in the chain (verify the current issuer). */
551
0
        ret = mbedtlsVerifyChain(cg, ctx, stack, old_issuers, issuer, depth + 1);
552
0
    }
553
554
    /* The chain is complete, but we haven't yet identified a trusted
555
     * certificate "on the way down". Can we trust this certificate? */
556
0
    if(ret == UA_STATUSCODE_BADCERTIFICATEUNTRUSTED) {
557
0
        for(mbedtls_x509_crt *t = &ctx->trustedCertificates; t; t = t->next) {
558
0
            if(mbedtlsSameBuf(&cert->tbs, &t->tbs))
559
0
                return UA_STATUSCODE_GOOD;
560
0
        }
561
0
    }
562
563
0
    return ret;
564
0
}
565
566
/* This follows Part 6, 6.1.3 Determining if a Certificate is trusted.
567
 * It defines a sequence of steps for certificate verification. */
568
static UA_StatusCode
569
0
verifyCertificate(UA_CertificateGroup *certGroup, const UA_ByteString *certificate) {
570
    /* Check parameter */
571
0
    if (certGroup == NULL || certGroup->context == NULL) {
572
0
        return UA_STATUSCODE_BADINTERNALERROR;
573
0
    }
574
575
0
    MemoryCertStore *context = (MemoryCertStore *)certGroup->context;
576
0
    if(context->reloadRequired) {
577
0
        UA_StatusCode retval = reloadCertificates(certGroup);
578
0
        if(retval != UA_STATUSCODE_GOOD) {
579
0
            return retval;
580
0
        }
581
0
        context->reloadRequired = false;
582
0
    }
583
584
    /* Verification Step: Certificate Structure
585
     * This parses the entire certificate chain contained in the bytestring. */
586
0
    mbedtls_x509_crt cert;
587
0
    mbedtls_x509_crt_init(&cert);
588
0
    int mbedErr = mbedtls_x509_crt_parse(&cert, certificate->data,
589
0
                                         certificate->length);
590
0
    if(mbedErr)
591
0
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
592
593
    /* Verification Step: Certificate Usage
594
     * Check whether the certificate is a User certificate or a CA certificate.
595
     * Refer the test case CTT/Security/Security Certificate Validation/029.js
596
     * for more details. */
597
0
    if(mbedtlsCheckCA(&cert)) {
598
0
        mbedtls_x509_crt_free(&cert);
599
0
        return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
600
0
    }
601
602
    /* These steps are performed outside of this method.
603
     * Because we need the server or client context.
604
     * - Security Policy
605
     * - Host Name
606
     * - URI */
607
608
    /* Verification Step: Build Certificate Chain
609
     * We perform the checks for each certificate inside. */
610
0
    mbedtls_x509_crt *old_issuers[UA_MBEDTLS_MAX_CHAIN_LENGTH];
611
0
    UA_StatusCode ret = mbedtlsVerifyChain(certGroup, context, &cert, old_issuers, &cert, 0);
612
0
    mbedtls_x509_crt_free(&cert);
613
0
    return ret;
614
0
}
615
616
static UA_StatusCode
617
MemoryCertStore_verifyCertificate(UA_CertificateGroup *certGroup,
618
0
                                  const UA_ByteString *certificate) {
619
    /* Check parameter */
620
0
    if(certGroup == NULL || certificate == NULL) {
621
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
622
0
    }
623
624
0
    UA_StatusCode retval = verifyCertificate(certGroup, certificate);
625
0
    if(retval != UA_STATUSCODE_GOOD) {
626
0
        if(MemoryCertStore_addToRejectedList(certGroup, certificate) != UA_STATUSCODE_GOOD) {
627
0
            UA_LOG_WARNING(certGroup->logging, UA_LOGCATEGORY_SECURITYPOLICY,
628
0
                           "Could not append certificate to rejected list");
629
0
        }
630
0
    }
631
0
    return retval;
632
0
}
633
634
UA_StatusCode
635
UA_CertificateGroup_Memorystore(UA_CertificateGroup *certGroup,
636
                                UA_NodeId *certificateGroupId,
637
                                const UA_TrustListDataType *trustList,
638
                                const UA_Logger *logger,
639
0
                                const UA_KeyValueMap *params) {
640
641
0
    if(certGroup == NULL || certificateGroupId == NULL) {
642
0
        return UA_STATUSCODE_BADINTERNALERROR;
643
0
    }
644
645
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
646
647
    /* Clear if the plugin is already initialized */
648
0
    if(certGroup->clear)
649
0
        certGroup->clear(certGroup);
650
651
0
    UA_NodeId_copy(certificateGroupId, &certGroup->certificateGroupId);
652
0
    certGroup->logging = logger;
653
654
0
    certGroup->getTrustList = MemoryCertStore_getTrustList;
655
0
    certGroup->setTrustList = MemoryCertStore_setTrustList;
656
0
    certGroup->addToTrustList = MemoryCertStore_addToTrustList;
657
0
    certGroup->removeFromTrustList = MemoryCertStore_removeFromTrustList;
658
0
    certGroup->getRejectedList = MemoryCertStore_getRejectedList;
659
0
    certGroup->getCertificateCrls = MemoryCertStore_getCertificateCrls;
660
0
    certGroup->verifyCertificate = MemoryCertStore_verifyCertificate;
661
0
    certGroup->clear = MemoryCertStore_clear;
662
663
    /* Set PKI Store context data */
664
0
    MemoryCertStore *context = (MemoryCertStore *)UA_calloc(1, sizeof(MemoryCertStore));
665
0
    if(!context) {
666
0
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
667
0
        goto cleanup;
668
0
    }
669
0
    certGroup->context = context;
670
    /* Default values */
671
0
    context->maxTrustListSize = 65535;
672
0
    context->maxRejectedListSize = 100;
673
674
0
    if(params) {
675
0
        const UA_UInt32 *maxTrustListSize = (const UA_UInt32*)
676
0
        UA_KeyValueMap_getScalar(params, MemoryCertStoreParameters[MEMORYCERTSTORE_PARAMINDEX_MAXTRUSTLISTSIZE].name,
677
0
                                 &UA_TYPES[UA_TYPES_UINT32]);
678
679
0
        const UA_UInt32 *maxRejectedListSize = (const UA_UInt32*)
680
0
        UA_KeyValueMap_getScalar(params, MemoryCertStoreParameters[MEMORYCERTSTORE_PARAMINDEX_MAXREJECTEDLISTSIZE].name,
681
0
                                 &UA_TYPES[UA_TYPES_UINT32]);
682
683
0
        if(maxTrustListSize) {
684
0
            context->maxTrustListSize = *maxTrustListSize;
685
0
        }
686
687
0
        if(maxRejectedListSize) {
688
0
            context->maxRejectedListSize = *maxRejectedListSize;
689
0
        }
690
0
    }
691
692
0
    UA_TrustListDataType_add(trustList, &context->trustList);
693
0
    reloadCertificates(certGroup);
694
695
0
    return UA_STATUSCODE_GOOD;
696
697
0
cleanup:
698
0
    certGroup->clear(certGroup);
699
0
    return retval;
700
0
}
701
702
#if !defined(mbedtls_x509_subject_alternative_name)
703
704
/* Find binary substring. Taken and adjusted from
705
 * http://tungchingkai.blogspot.com/2011/07/binary-strstr.html */
706
707
static const unsigned char *
708
0
bstrchr(const unsigned char *s, const unsigned char ch, size_t l) {
709
    /* find first occurrence of c in char s[] for length l*/
710
0
    for(; l > 0; ++s, --l) {
711
0
        if(*s == ch)
712
0
            return s;
713
0
    }
714
0
    return NULL;
715
0
}
716
717
static const unsigned char *
718
0
UA_Bstrstr(const unsigned char *s1, size_t l1, const unsigned char *s2, size_t l2) {
719
    /* find first occurrence of s2[] in s1[] for length l1*/
720
0
    const unsigned char *ss1 = s1;
721
0
    const unsigned char *ss2 = s2;
722
    /* handle special case */
723
0
    if(l1 == 0)
724
0
        return (NULL);
725
0
    if(l2 == 0)
726
0
        return s1;
727
728
    /* match prefix */
729
0
    for (; (s1 = bstrchr(s1, *s2, (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1)) != NULL &&
730
0
           (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1 != 0; ++s1) {
731
732
        /* match rest of prefix */
733
0
        const unsigned char *sc1, *sc2;
734
0
        for (sc1 = s1, sc2 = s2; ;)
735
0
            if (++sc2 >= ss2+l2)
736
0
                return s1;
737
0
            else if (*++sc1 != *sc2)
738
0
                break;
739
0
           }
740
0
    return NULL;
741
0
}
742
743
#endif
744
745
UA_StatusCode
746
UA_CertificateUtils_verifyApplicationURI(UA_RuleHandling ruleHandling,
747
                                         const UA_ByteString *certificate,
748
                                         const UA_String *applicationURI,
749
0
                                         UA_Logger *logger) {
750
    /* Parse the certificate */
751
0
    mbedtls_x509_crt remoteCertificate;
752
0
    mbedtls_x509_crt_init(&remoteCertificate);
753
754
0
    UA_StatusCode retval = UA_mbedTLS_LoadCertificate(certificate, &remoteCertificate);
755
0
    if(retval != UA_STATUSCODE_GOOD)
756
0
        return retval;
757
758
#if defined(mbedtls_x509_subject_alternative_name)
759
    /* Get the Subject Alternative Name and compate */
760
    mbedtls_x509_subject_alternative_name san;
761
    mbedtls_x509_sequence *cur = &remoteCertificate.subject_alt_names;
762
    retval = UA_STATUSCODE_BADCERTIFICATEURIINVALID;
763
    for(; cur; cur = cur->next) {
764
        int res = mbedtls_x509_parse_subject_alt_name(&cur->buf, &san);
765
        if(res != 0)
766
            continue;
767
        if(san.type != MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER) {
768
            mbedtls_x509_free_subject_alt_name(&san);
769
            continue;
770
        }
771
772
        UA_String uri = {san.san.unstructured_name.len, san.san.unstructured_name.p};
773
        UA_Boolean found = UA_String_equal(&uri, applicationURI);
774
        if(found) {
775
            retval = UA_STATUSCODE_GOOD;
776
        } else if(ruleHandling != UA_RULEHANDLING_ACCEPT) {
777
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURITYPOLICY,
778
                           "The certificate's Subject Alternative Name URI (%S) "
779
                           "does not match the ApplicationURI (%S)",
780
                           uri, *applicationURI);
781
        }
782
        mbedtls_x509_free_subject_alt_name(&san);
783
        break;
784
    }
785
786
    if(!cur && ruleHandling != UA_RULEHANDLING_ACCEPT) {
787
        UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURITYPOLICY,
788
                       "The certificate has no Subject Alternative Name URI defined");
789
    }
790
#else
791
    /* Poor man's ApplicationUri verification. mbedTLS does not parse all fields
792
     * of the Alternative Subject Name. Instead test whether the URI-string is
793
     * present in the v3_ext field in general. */
794
0
    if(UA_Bstrstr(remoteCertificate.v3_ext.p, remoteCertificate.v3_ext.len,
795
0
                  applicationURI->data, applicationURI->length) == NULL)
796
0
        retval = UA_STATUSCODE_BADCERTIFICATEURIINVALID;
797
798
0
    if(retval != UA_STATUSCODE_GOOD && ruleHandling != UA_RULEHANDLING_ACCEPT) {
799
0
        UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURITYPOLICY,
800
0
                       "The certificate's application URI could not be verified. StatusCode %s",
801
0
                       UA_StatusCode_name(retval));
802
0
    }
803
0
#endif
804
805
0
    if(ruleHandling != UA_RULEHANDLING_ABORT)
806
0
        retval = UA_STATUSCODE_GOOD;
807
808
0
    mbedtls_x509_crt_free(&remoteCertificate);
809
0
    return retval;
810
0
}
811
812
UA_StatusCode
813
UA_CertificateUtils_getExpirationDate(UA_ByteString *certificate,
814
0
                                      UA_DateTime *expiryDateTime) {
815
0
    mbedtls_x509_crt publicKey;
816
0
    mbedtls_x509_crt_init(&publicKey);
817
818
0
    UA_StatusCode retval = UA_mbedTLS_LoadCertificate(certificate, &publicKey);
819
0
    if(retval != UA_STATUSCODE_GOOD)
820
0
        return retval;
821
822
0
    UA_DateTimeStruct ts;
823
0
    ts.year = (UA_Int16)publicKey.valid_to.year;
824
0
    ts.month = (UA_UInt16)publicKey.valid_to.mon;
825
0
    ts.day = (UA_UInt16)publicKey.valid_to.day;
826
0
    ts.hour = (UA_UInt16)publicKey.valid_to.hour;
827
0
    ts.min = (UA_UInt16)publicKey.valid_to.min;
828
0
    ts.sec = (UA_UInt16)publicKey.valid_to.sec;
829
0
    ts.milliSec = 0;
830
0
    ts.microSec = 0;
831
0
    ts.nanoSec = 0;
832
0
    *expiryDateTime = UA_DateTime_fromStruct(ts);
833
0
    mbedtls_x509_crt_free(&publicKey);
834
0
    return UA_STATUSCODE_GOOD;
835
0
}
836
837
UA_StatusCode
838
UA_CertificateUtils_getSubjectName(UA_ByteString *certificate,
839
0
                                   UA_String *subjectName) {
840
0
    mbedtls_x509_crt publicKey;
841
0
    mbedtls_x509_crt_init(&publicKey);
842
843
0
    mbedtls_x509_crl crl;
844
0
    mbedtls_x509_crl_init(&crl);
845
846
0
    char buf[1024];
847
0
    int res = 0;
848
0
    UA_StatusCode retval = UA_mbedTLS_LoadCertificate(certificate, &publicKey);
849
0
    if(retval == UA_STATUSCODE_GOOD) {
850
0
        res = mbedtls_x509_dn_gets(buf, 1024, &publicKey.subject);
851
0
        mbedtls_x509_crt_free(&publicKey);
852
0
    } else {
853
0
        retval = UA_mbedTLS_LoadCrl(certificate, &crl);
854
0
        if(retval != UA_STATUSCODE_GOOD)
855
0
            return retval;
856
0
        res = mbedtls_x509_dn_gets(buf, 1024, &crl.issuer);
857
0
        mbedtls_x509_crl_free(&crl);
858
0
    }
859
860
0
    if(res < 0)
861
0
        return UA_STATUSCODE_BADINTERNALERROR;
862
0
    UA_String tmp = {(size_t)res, (UA_Byte*)buf};
863
0
    return UA_String_copy(&tmp, subjectName);
864
0
}
865
866
UA_StatusCode
867
UA_CertificateUtils_getThumbprint(UA_ByteString *certificate,
868
0
                                  UA_String *thumbprint){
869
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
870
0
    if(certificate == NULL || thumbprint->length != (UA_SHA1_LENGTH * 2))
871
0
        return UA_STATUSCODE_BADINTERNALERROR;
872
873
    // prepare temporary to hold the binary thumbprint
874
0
    UA_Byte buf[UA_SHA1_LENGTH];
875
0
    UA_ByteString thumbpr = {
876
0
        /*.length =*/ sizeof(buf),
877
0
        /*.data =*/ buf
878
0
    };
879
880
0
    retval = mbedtls_thumbprint_sha1(certificate, &thumbpr);
881
882
    // convert to hexadecimal string representation
883
0
    size_t t = 0u;
884
0
    for (size_t i = 0u; i < thumbpr.length; i++) {
885
0
        UA_Byte shift = 4u;
886
        // byte consists of two nibbles: AAAABBBB
887
0
        const UA_Byte curByte = thumbpr.data[i];
888
        // convert AAAA first then BBBB
889
0
        for(size_t n = 0u; n < 2u; n++) {
890
0
            UA_Byte curNibble = (curByte >> shift) & 0x0Fu;
891
0
            if(curNibble >= 10u)
892
0
                thumbprint->data[t++] = (65u + (curNibble - 10u));  // 65 == 'A'
893
0
            else
894
0
                thumbprint->data[t++] = (48u + curNibble);          // 48 == '0'
895
0
            shift -= 4u;
896
0
        }
897
0
    }
898
899
0
    return retval;
900
0
}
901
902
UA_StatusCode
903
UA_CertificateUtils_getKeySize(UA_ByteString *certificate,
904
0
                               size_t *keySize){
905
0
    mbedtls_x509_crt publicKey;
906
0
    mbedtls_x509_crt_init(&publicKey);
907
908
0
    UA_StatusCode retval = UA_mbedTLS_LoadCertificate(certificate, &publicKey);
909
0
    if(retval != UA_STATUSCODE_GOOD)
910
0
        return retval;
911
912
0
    mbedtls_rsa_context *rsa = mbedtls_pk_rsa(publicKey.pk);
913
914
0
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
915
0
    *keySize = rsa->len * 8;
916
#else
917
    *keySize = mbedtls_rsa_get_len(rsa) * 8;
918
#endif
919
0
    mbedtls_x509_crt_free(&publicKey);
920
921
0
    return UA_STATUSCODE_GOOD;
922
0
}
923
924
UA_StatusCode
925
UA_CertificateUtils_comparePublicKeys(const UA_ByteString *certificate1,
926
0
                                      const UA_ByteString *certificate2) {
927
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
928
929
0
    mbedtls_x509_crt cert1;
930
0
    mbedtls_x509_crt cert2;
931
0
    mbedtls_x509_csr csr1;
932
0
    mbedtls_x509_csr csr2;
933
0
    mbedtls_mpi N1, E1;
934
0
    mbedtls_mpi N2, E2;
935
936
0
    UA_ByteString data1 = UA_mbedTLS_CopyDataFormatAware(certificate1);
937
0
    UA_ByteString data2 = UA_mbedTLS_CopyDataFormatAware(certificate2);
938
939
0
    mbedtls_x509_crt_init(&cert1);
940
0
    mbedtls_x509_crt_init(&cert2);
941
0
    mbedtls_x509_csr_init(&csr1);
942
0
    mbedtls_x509_csr_init(&csr2);
943
0
    mbedtls_mpi_init(&N1);
944
0
    mbedtls_mpi_init(&E1);
945
0
    mbedtls_mpi_init(&N2);
946
0
    mbedtls_mpi_init(&E2);
947
948
0
    int mbedErr = mbedtls_x509_crt_parse(&cert1, data1.data, data1.length);
949
0
    if(mbedErr) {
950
        /* Try to load as a csr */
951
0
        mbedErr = mbedtls_x509_csr_parse(&csr1, data1.data, data1.length);
952
0
        if(mbedErr) {
953
0
            retval = UA_STATUSCODE_BADINTERNALERROR;
954
0
            goto cleanup;
955
0
        }
956
0
    }
957
958
0
    mbedErr = mbedtls_x509_crt_parse(&cert2, data2.data, data2.length);
959
0
    if(mbedErr) {
960
        /* Try to load as a csr */
961
0
        mbedErr = mbedtls_x509_csr_parse(&csr2, data2.data, data2.length);
962
0
        if(mbedErr) {
963
0
            retval = UA_STATUSCODE_BADINTERNALERROR;
964
0
            goto cleanup;
965
0
        }
966
0
    }
967
968
0
#if MBEDTLS_VERSION_NUMBER < 0x03000000
969
0
    mbedtls_pk_context pk1 = cert1.pk.pk_info ? cert1.pk : csr1.pk;
970
0
    mbedtls_pk_context pk2 = cert2.pk.pk_info ? cert2.pk : csr2.pk;
971
#else
972
    mbedtls_pk_context pk1 = cert1.pk_raw.p ? cert1.pk : csr1.pk;
973
    mbedtls_pk_context pk2 = cert2.pk_raw.p ? cert2.pk : csr2.pk;
974
#endif
975
976
0
    if(!mbedtls_pk_rsa(pk1) || !mbedtls_pk_rsa(pk2)) {
977
0
        retval = UA_STATUSCODE_BADINTERNALERROR;
978
0
        goto cleanup;
979
0
    }
980
981
0
    if(!mbedtls_pk_can_do(&pk1, MBEDTLS_PK_RSA) &&
982
0
       !mbedtls_pk_can_do(&pk2, MBEDTLS_PK_RSA)) {
983
0
        retval = UA_STATUSCODE_BADINTERNALERROR;
984
0
        goto cleanup;
985
0
    }
986
987
0
#if MBEDTLS_VERSION_NUMBER < 0x02070000
988
0
    N1 = mbedtls_pk_rsa(pk1)->N;
989
0
    E1 = mbedtls_pk_rsa(pk1)->E;
990
0
    N2 = mbedtls_pk_rsa(pk2)->N;
991
0
    E2 = mbedtls_pk_rsa(pk2)->E;
992
#else
993
    if(mbedtls_rsa_export(mbedtls_pk_rsa(pk1), &N1, NULL, NULL, NULL, &E1) != 0) {
994
        retval = UA_STATUSCODE_BADINTERNALERROR;
995
        goto cleanup;
996
    }
997
    if(mbedtls_rsa_export(mbedtls_pk_rsa(pk2), &N2, NULL, NULL, NULL, &E2) != 0) {
998
        retval = UA_STATUSCODE_BADINTERNALERROR;
999
        goto cleanup;
1000
    }
1001
#endif
1002
1003
0
    if(mbedtls_mpi_cmp_mpi(&N1, &N2) || mbedtls_mpi_cmp_mpi(&E1, &E2))
1004
0
        retval = UA_STATUSCODE_BADNOMATCH;
1005
1006
0
cleanup:
1007
0
    mbedtls_mpi_free(&N1);
1008
0
    mbedtls_mpi_free(&E1);
1009
0
    mbedtls_mpi_free(&N2);
1010
0
    mbedtls_mpi_free(&E2);
1011
0
    mbedtls_x509_crt_free(&cert1);
1012
0
    mbedtls_x509_crt_free(&cert2);
1013
0
    mbedtls_x509_csr_free(&csr1);
1014
0
    mbedtls_x509_csr_free(&csr2);
1015
0
    UA_ByteString_clear(&data1);
1016
0
    UA_ByteString_clear(&data2);
1017
1018
0
    return retval;
1019
0
}
1020
1021
UA_StatusCode
1022
UA_CertificateUtils_checkKeyPair(const UA_ByteString *certificate,
1023
0
                                 const UA_ByteString *privateKey) {
1024
0
    mbedtls_x509_crt cert;
1025
0
    mbedtls_pk_context pk;
1026
1027
0
    mbedtls_x509_crt_init(&cert);
1028
0
    mbedtls_pk_init(&pk);
1029
1030
0
    UA_StatusCode retval = UA_mbedTLS_LoadCertificate(certificate, &cert);
1031
0
    if(retval != UA_STATUSCODE_GOOD)
1032
0
        goto cleanup;
1033
1034
0
    retval = UA_mbedTLS_LoadPrivateKey(privateKey, &pk, NULL);
1035
0
    if(retval != UA_STATUSCODE_GOOD)
1036
0
        goto cleanup;
1037
1038
    /* Verify the private key matches the public key in the certificate */
1039
0
    if(!mbedtls_pk_can_do(&pk, mbedtls_pk_get_type(&cert.pk))) {
1040
0
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
1041
0
        goto cleanup;
1042
0
    }
1043
1044
    /* Check if the public key from the certificate matches the private key */
1045
0
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
1046
0
    if(mbedtls_pk_check_pair(&cert.pk, &pk) != 0) {
1047
0
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
1048
0
    }
1049
#else
1050
    if(mbedtls_pk_check_pair(&cert.pk, &pk, mbedtls_entropy_func, NULL) != 0) {
1051
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
1052
    }
1053
#endif
1054
1055
0
cleanup:
1056
0
    mbedtls_pk_free(&pk);
1057
0
    mbedtls_x509_crt_free(&cert);
1058
1059
0
    return retval;
1060
0
}
1061
1062
UA_StatusCode
1063
0
UA_CertificateUtils_checkCA(const UA_ByteString *certificate) {
1064
0
    mbedtls_x509_crt cert;
1065
0
    mbedtls_x509_crt_init(&cert);
1066
1067
0
    UA_StatusCode retval = UA_mbedTLS_LoadCertificate(certificate, &cert);
1068
0
    if(retval != UA_STATUSCODE_GOOD)
1069
0
        goto cleanup;
1070
1071
0
    retval = mbedtlsCheckCA(&cert) ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADNOMATCH;
1072
1073
0
cleanup:
1074
0
    mbedtls_x509_crt_free(&cert);
1075
1076
0
    return retval;
1077
0
}
1078
1079
UA_StatusCode
1080
UA_CertificateUtils_decryptPrivateKey(const UA_ByteString privateKey,
1081
                                      const UA_ByteString password,
1082
0
                                      UA_ByteString *outDerKey) {
1083
0
    if(!outDerKey)
1084
0
        return UA_STATUSCODE_BADINTERNALERROR;
1085
1086
0
    if (privateKey.length == 0) {
1087
0
        *outDerKey = UA_BYTESTRING_NULL;
1088
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
1089
0
    }
1090
1091
    /* Already in DER format -> return verbatim */
1092
0
    if(privateKey.length > 1 && privateKey.data[0] == 0x30 && privateKey.data[1] == 0x82)
1093
0
        return UA_ByteString_copy(&privateKey, outDerKey);
1094
1095
    /* Create a null-terminated string */
1096
0
    UA_ByteString nullTerminatedKey = UA_mbedTLS_CopyDataFormatAware(&privateKey);
1097
0
    if(nullTerminatedKey.length != privateKey.length + 1)
1098
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
1099
1100
    /* Create the private-key context */
1101
0
    mbedtls_pk_context ctx;
1102
0
    mbedtls_pk_init(&ctx);
1103
0
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
1104
0
    int err = mbedtls_pk_parse_key(&ctx, nullTerminatedKey.data,
1105
0
                                   nullTerminatedKey.length,
1106
0
                                   password.data, password.length);
1107
#else
1108
    mbedtls_entropy_context entropy;
1109
    mbedtls_entropy_init(&entropy);
1110
    int err = mbedtls_pk_parse_key(&ctx, nullTerminatedKey.data,
1111
                                   nullTerminatedKey.length,
1112
                                   password.data, password.length,
1113
                                   mbedtls_entropy_func, &entropy);
1114
    mbedtls_entropy_free(&entropy);
1115
#endif
1116
0
    UA_ByteString_clear(&nullTerminatedKey);
1117
0
    if(err != 0) {
1118
0
        mbedtls_pk_free(&ctx);
1119
0
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
1120
0
    }
1121
1122
    /* Write the DER-encoded key into a local buffer */
1123
0
    unsigned char buf[1 << 14];
1124
0
    size_t pos = (size_t)mbedtls_pk_write_key_der(&ctx, buf, sizeof(buf));
1125
1126
    /* Allocate memory */
1127
0
    UA_StatusCode res = UA_ByteString_allocBuffer(outDerKey, pos);
1128
0
    if(res != UA_STATUSCODE_GOOD) {
1129
0
        mbedtls_pk_free(&ctx);
1130
0
        return res;
1131
0
    }
1132
1133
    /* Copy to the output */
1134
0
    memcpy(outDerKey->data, &buf[sizeof(buf) - pos], pos);
1135
0
    mbedtls_pk_free(&ctx);
1136
0
    return UA_STATUSCODE_GOOD;
1137
0
}
1138
1139
#endif