Coverage Report

Created: 2026-04-12 07:09

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