Coverage Report

Created: 2026-05-16 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/open62541_15/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
483
    /* Return the most specific error code. BADCERTIFICATECHAININCOMPLETE is
484
     * returned only if all possible chains are incomplete. */
485
0
    mbedtls_x509_crt *issuer = NULL;
486
0
    UA_StatusCode ret = UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
487
0
    while(ret != UA_STATUSCODE_GOOD) {
488
        /* Find the issuer. This can return the same certificate if it is
489
         * self-signed (subject == issuer). We come back here to try a different
490
         * "path" if a subsequent verification fails. */
491
0
        issuer = mbedtlsFindNextIssuer(ctx, stack, cert, issuer);
492
0
        if(!issuer)
493
0
            break;
494
495
        /* Verification Step: Certificate Usage
496
         * Can the issuer act as CA? Omit for self-signed leaf certificates. */
497
0
        if((depth > 0 || issuer != cert) && !mbedtlsCheckCA(issuer)) {
498
0
            ret = UA_STATUSCODE_BADCERTIFICATEISSUERUSENOTALLOWED;
499
0
            continue;
500
0
        }
501
502
        /* Verification Step: Signature */
503
0
        if(!mbedtlsCheckSignature(cert, issuer)) {
504
0
            ret = UA_STATUSCODE_BADCERTIFICATEINVALID;  /* Wrong issuer, try again */
505
0
            continue;
506
0
        }
507
508
        /* The certificate is self-signed. We have arrived at the top of the
509
         * chain. We check whether the certificate is trusted below. This is the
510
         * only place where we return UA_STATUSCODE_BADCERTIFICATEUNTRUSTED.
511
         * This signals that the chain is complete (but can be still
512
         * untrusted).
513
         *
514
         * Break here as we have reached the end of the chain. Omit the
515
         * Revocation Check for self-signed certificates. */
516
0
        if(issuer == cert || mbedtlsSameBuf(&cert->tbs, &issuer->tbs)) {
517
0
            ret = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED;
518
0
            break;
519
0
        }
520
521
        /* Verification Step: Revocation Check */
522
0
        ret = mbedtlsCheckRevoked(cg, ctx, cert);
523
0
        if(depth > 0) {
524
0
            if(ret == UA_STATUSCODE_BADCERTIFICATEREVOKED)
525
0
                ret = UA_STATUSCODE_BADCERTIFICATEISSUERREVOKED;
526
0
            if(ret == UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN)
527
0
                ret = UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN;
528
0
        }
529
0
        if(ret != UA_STATUSCODE_GOOD)
530
0
            continue;
531
532
        /* Detect (endless) loops of issuers */
533
0
        for(int i = 0; i < depth; i++) {
534
0
            if(old_issuers[i] == issuer)
535
0
                return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
536
0
        }
537
0
        old_issuers[depth] = issuer;
538
539
        /* We have found the issuer certificate used for the signature. Recurse
540
         * to the next certificate in the chain (verify the current issuer). */
541
0
        ret = mbedtlsVerifyChain(cg, ctx, stack, old_issuers, issuer, depth + 1);
542
0
    }
543
544
    /* The chain is complete, but we haven't yet identified a trusted
545
     * certificate "on the way down". Can we trust this certificate? */
546
0
    if(ret == UA_STATUSCODE_BADCERTIFICATEUNTRUSTED) {
547
0
        for(mbedtls_x509_crt *t = &ctx->trustedCertificates; t; t = t->next) {
548
0
            if(mbedtlsSameBuf(&cert->tbs, &t->tbs)) {
549
0
                ret = UA_STATUSCODE_GOOD;
550
0
                break;
551
0
            }
552
0
        }
553
0
    }
554
555
0
    if(ret == UA_STATUSCODE_GOOD) {
556
        /* Verification Step: Validity Period */
557
0
        if(mbedtls_x509_time_is_future(&cert->valid_from) ||
558
0
        mbedtls_x509_time_is_past(&cert->valid_to))
559
0
            return (depth == 0) ? UA_STATUSCODE_BADCERTIFICATETIMEINVALID :
560
0
                UA_STATUSCODE_BADCERTIFICATEISSUERTIMEINVALID;
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 MBEDTLS_VERSION_NUMBER < 0x03040000
703
704
static const unsigned char *
705
0
UA_Bstrstr(const unsigned char *s1, size_t l1, const unsigned char *s2, size_t l2) {
706
0
    if(l2 == 0)
707
0
        return s1;
708
0
    if(l1 < l2)
709
0
        return NULL;
710
0
    size_t limit = l1 - l2 + 1;
711
0
    for(size_t i = 0; i < limit; ++i) {
712
0
        if(s1[i] == s2[0]) {
713
0
            if(memcmp(s1 + i, s2, l2) == 0)
714
0
                return s1 + i;
715
0
        }
716
0
    }
717
0
    return NULL;
718
0
}
719
720
#endif
721
722
UA_StatusCode
723
UA_CertificateUtils_verifyApplicationUri(const UA_ByteString *certificate,
724
22
                                         const UA_String *applicationURI) {
725
    /* Parse the certificate */
726
22
    mbedtls_x509_crt remoteCertificate;
727
22
    mbedtls_x509_crt_init(&remoteCertificate);
728
729
22
    UA_StatusCode retval = UA_mbedTLS_LoadCertificate(certificate, &remoteCertificate);
730
22
    if(retval != UA_STATUSCODE_GOOD)
731
22
        return retval;
732
733
#if MBEDTLS_VERSION_NUMBER >= 0x03040000
734
    /* Get the Subject Alternative Name and compare */
735
    mbedtls_x509_subject_alternative_name san;
736
    mbedtls_x509_sequence *cur = &remoteCertificate.subject_alt_names;
737
    retval = UA_STATUSCODE_BADCERTIFICATEURIINVALID;
738
    for(; cur; cur = cur->next) {
739
        int res = mbedtls_x509_parse_subject_alt_name(&cur->buf, &san);
740
        if(res != 0)
741
            continue;
742
        if(san.type != MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER) {
743
            mbedtls_x509_free_subject_alt_name(&san);
744
            continue;
745
        }
746
747
        UA_String uri = {san.san.unstructured_name.len, san.san.unstructured_name.p};
748
        UA_Boolean found = UA_String_equal(&uri, applicationURI);
749
        mbedtls_x509_free_subject_alt_name(&san);
750
        if(found) {
751
            retval = UA_STATUSCODE_GOOD;
752
            break;
753
        }
754
    }
755
#else
756
    /* Poor man's ApplicationUri verification. mbedTLS does not parse all fields
757
     * of the Alternative Subject Name. Instead test whether the URI-string is
758
     * present in the v3_ext field in general. */
759
0
    if(UA_Bstrstr(remoteCertificate.v3_ext.p, remoteCertificate.v3_ext.len,
760
0
                  applicationURI->data, applicationURI->length) == NULL)
761
0
        retval = UA_STATUSCODE_BADCERTIFICATEURIINVALID;
762
0
#endif
763
764
0
    mbedtls_x509_crt_free(&remoteCertificate);
765
0
    return retval;
766
22
}
767
768
UA_StatusCode
769
UA_CertificateUtils_getExpirationDate(UA_ByteString *certificate,
770
20
                                      UA_DateTime *expiryDateTime) {
771
20
    mbedtls_x509_crt publicKey;
772
20
    mbedtls_x509_crt_init(&publicKey);
773
774
20
    UA_StatusCode retval = UA_mbedTLS_LoadCertificate(certificate, &publicKey);
775
20
    if(retval != UA_STATUSCODE_GOOD)
776
20
        return retval;
777
778
0
    UA_DateTimeStruct ts;
779
0
    ts.year = (UA_Int16)publicKey.valid_to.year;
780
0
    ts.month = (UA_UInt16)publicKey.valid_to.mon;
781
0
    ts.day = (UA_UInt16)publicKey.valid_to.day;
782
0
    ts.hour = (UA_UInt16)publicKey.valid_to.hour;
783
0
    ts.min = (UA_UInt16)publicKey.valid_to.min;
784
0
    ts.sec = (UA_UInt16)publicKey.valid_to.sec;
785
0
    ts.milliSec = 0;
786
0
    ts.microSec = 0;
787
0
    ts.nanoSec = 0;
788
0
    *expiryDateTime = UA_DateTime_fromStruct(ts);
789
0
    mbedtls_x509_crt_free(&publicKey);
790
0
    return UA_STATUSCODE_GOOD;
791
20
}
792
793
UA_StatusCode
794
UA_CertificateUtils_getSubjectName(UA_ByteString *certificate,
795
276
                                   UA_String *subjectName) {
796
276
    mbedtls_x509_crt publicKey;
797
276
    mbedtls_x509_crt_init(&publicKey);
798
799
276
    mbedtls_x509_crl crl;
800
276
    mbedtls_x509_crl_init(&crl);
801
802
276
    char buf[1024];
803
276
    int res = 0;
804
276
    UA_StatusCode retval = UA_mbedTLS_LoadCertificate(certificate, &publicKey);
805
276
    if(retval == UA_STATUSCODE_GOOD) {
806
0
        res = mbedtls_x509_dn_gets(buf, 1024, &publicKey.subject);
807
0
        mbedtls_x509_crt_free(&publicKey);
808
276
    } else {
809
276
        retval = UA_mbedTLS_LoadCrl(certificate, &crl);
810
276
        if(retval != UA_STATUSCODE_GOOD)
811
276
            return retval;
812
0
        res = mbedtls_x509_dn_gets(buf, 1024, &crl.issuer);
813
0
        mbedtls_x509_crl_free(&crl);
814
0
    }
815
816
0
    if(res < 0)
817
0
        return UA_STATUSCODE_BADINTERNALERROR;
818
0
    UA_String tmp = {(size_t)res, (UA_Byte*)buf};
819
0
    return UA_String_copy(&tmp, subjectName);
820
0
}
821
822
UA_StatusCode
823
UA_CertificateUtils_getThumbprint(UA_ByteString *certificate,
824
6
                                  UA_String *thumbprint){
825
6
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
826
6
    if(certificate == NULL || thumbprint->length != (UA_SHA1_LENGTH * 2))
827
6
        return UA_STATUSCODE_BADINTERNALERROR;
828
829
    // prepare temporary to hold the binary thumbprint
830
0
    UA_Byte buf[UA_SHA1_LENGTH];
831
0
    UA_ByteString thumbpr = {
832
0
        /*.length =*/ sizeof(buf),
833
0
        /*.data =*/ buf
834
0
    };
835
836
0
    retval = mbedtls_thumbprint_sha1(certificate, &thumbpr);
837
838
    // convert to hexadecimal string representation
839
0
    size_t t = 0u;
840
0
    for (size_t i = 0u; i < thumbpr.length; i++) {
841
0
        UA_Byte shift = 4u;
842
        // byte consists of two nibbles: AAAABBBB
843
0
        const UA_Byte curByte = thumbpr.data[i];
844
        // convert AAAA first then BBBB
845
0
        for(size_t n = 0u; n < 2u; n++) {
846
0
            UA_Byte curNibble = (curByte >> shift) & 0x0Fu;
847
0
            if(curNibble >= 10u)
848
0
                thumbprint->data[t++] = (65u + (curNibble - 10u));  // 65 == 'A'
849
0
            else
850
0
                thumbprint->data[t++] = (48u + curNibble);          // 48 == '0'
851
0
            shift -= 4u;
852
0
        }
853
0
    }
854
855
0
    return retval;
856
6
}
857
858
UA_StatusCode
859
UA_CertificateUtils_getKeySize(UA_ByteString *certificate,
860
43
                               size_t *keySize){
861
43
    mbedtls_x509_crt publicKey;
862
43
    mbedtls_x509_crt_init(&publicKey);
863
864
43
    UA_StatusCode retval = UA_mbedTLS_LoadCertificate(certificate, &publicKey);
865
43
    if(retval != UA_STATUSCODE_GOOD)
866
43
        return retval;
867
868
0
    if(!mbedtls_pk_can_do(&publicKey.pk, MBEDTLS_PK_RSA)) {
869
0
        mbedtls_x509_crt_free(&publicKey);
870
0
        return UA_STATUSCODE_BADINTERNALERROR;
871
0
    }
872
873
0
    mbedtls_rsa_context *rsa = mbedtls_pk_rsa(publicKey.pk);
874
875
0
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
876
0
    *keySize = rsa->len * 8;
877
#else
878
    *keySize = mbedtls_rsa_get_len(rsa) * 8;
879
#endif
880
0
    mbedtls_x509_crt_free(&publicKey);
881
882
0
    return UA_STATUSCODE_GOOD;
883
0
}
884
885
UA_StatusCode
886
UA_CertificateUtils_comparePublicKeys(const UA_ByteString *certificate1,
887
0
                                      const UA_ByteString *certificate2) {
888
0
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
889
890
0
    mbedtls_x509_crt cert1;
891
0
    mbedtls_x509_crt cert2;
892
0
    mbedtls_x509_csr csr1;
893
0
    mbedtls_x509_csr csr2;
894
0
    mbedtls_mpi N1, E1;
895
0
    mbedtls_mpi N2, E2;
896
897
0
    UA_ByteString data1 = UA_mbedTLS_CopyDataFormatAware(certificate1);
898
0
    UA_ByteString data2 = UA_mbedTLS_CopyDataFormatAware(certificate2);
899
900
0
    mbedtls_x509_crt_init(&cert1);
901
0
    mbedtls_x509_crt_init(&cert2);
902
0
    mbedtls_x509_csr_init(&csr1);
903
0
    mbedtls_x509_csr_init(&csr2);
904
0
    mbedtls_mpi_init(&N1);
905
0
    mbedtls_mpi_init(&E1);
906
0
    mbedtls_mpi_init(&N2);
907
0
    mbedtls_mpi_init(&E2);
908
909
0
    int mbedErr = mbedtls_x509_crt_parse(&cert1, data1.data, data1.length);
910
0
    if(mbedErr) {
911
        /* Try to load as a csr */
912
0
        mbedErr = mbedtls_x509_csr_parse(&csr1, data1.data, data1.length);
913
0
        if(mbedErr) {
914
0
            retval = UA_STATUSCODE_BADINTERNALERROR;
915
0
            goto cleanup;
916
0
        }
917
0
    }
918
919
0
    mbedErr = mbedtls_x509_crt_parse(&cert2, data2.data, data2.length);
920
0
    if(mbedErr) {
921
        /* Try to load as a csr */
922
0
        mbedErr = mbedtls_x509_csr_parse(&csr2, data2.data, data2.length);
923
0
        if(mbedErr) {
924
0
            retval = UA_STATUSCODE_BADINTERNALERROR;
925
0
            goto cleanup;
926
0
        }
927
0
    }
928
929
0
#if MBEDTLS_VERSION_NUMBER < 0x03000000
930
0
    mbedtls_pk_context pk1 = cert1.pk.pk_info ? cert1.pk : csr1.pk;
931
0
    mbedtls_pk_context pk2 = cert2.pk.pk_info ? cert2.pk : csr2.pk;
932
#else
933
    mbedtls_pk_context pk1 = cert1.pk_raw.p ? cert1.pk : csr1.pk;
934
    mbedtls_pk_context pk2 = cert2.pk_raw.p ? cert2.pk : csr2.pk;
935
#endif
936
937
0
    if(!mbedtls_pk_rsa(pk1) || !mbedtls_pk_rsa(pk2)) {
938
0
        retval = UA_STATUSCODE_BADINTERNALERROR;
939
0
        goto cleanup;
940
0
    }
941
942
0
    if(!mbedtls_pk_can_do(&pk1, MBEDTLS_PK_RSA) &&
943
0
       !mbedtls_pk_can_do(&pk2, MBEDTLS_PK_RSA)) {
944
0
        retval = UA_STATUSCODE_BADINTERNALERROR;
945
0
        goto cleanup;
946
0
    }
947
948
#if MBEDTLS_VERSION_NUMBER < 0x02070000
949
    N1 = mbedtls_pk_rsa(pk1)->N;
950
    E1 = mbedtls_pk_rsa(pk1)->E;
951
    N2 = mbedtls_pk_rsa(pk2)->N;
952
    E2 = mbedtls_pk_rsa(pk2)->E;
953
#else
954
0
    if(mbedtls_rsa_export(mbedtls_pk_rsa(pk1), &N1, NULL, NULL, NULL, &E1) != 0) {
955
0
        retval = UA_STATUSCODE_BADINTERNALERROR;
956
0
        goto cleanup;
957
0
    }
958
0
    if(mbedtls_rsa_export(mbedtls_pk_rsa(pk2), &N2, NULL, NULL, NULL, &E2) != 0) {
959
0
        retval = UA_STATUSCODE_BADINTERNALERROR;
960
0
        goto cleanup;
961
0
    }
962
0
#endif
963
964
0
    if(mbedtls_mpi_cmp_mpi(&N1, &N2) || mbedtls_mpi_cmp_mpi(&E1, &E2))
965
0
        retval = UA_STATUSCODE_BADNOMATCH;
966
967
0
cleanup:
968
0
    mbedtls_mpi_free(&N1);
969
0
    mbedtls_mpi_free(&E1);
970
0
    mbedtls_mpi_free(&N2);
971
0
    mbedtls_mpi_free(&E2);
972
0
    mbedtls_x509_crt_free(&cert1);
973
0
    mbedtls_x509_crt_free(&cert2);
974
0
    mbedtls_x509_csr_free(&csr1);
975
0
    mbedtls_x509_csr_free(&csr2);
976
0
    UA_ByteString_clear(&data1);
977
0
    UA_ByteString_clear(&data2);
978
979
0
    return retval;
980
0
}
981
982
UA_StatusCode
983
UA_CertificateUtils_checkKeyPair(const UA_ByteString *certificate,
984
0
                                 const UA_ByteString *privateKey) {
985
0
    mbedtls_x509_crt cert;
986
0
    mbedtls_pk_context pk;
987
988
0
    mbedtls_x509_crt_init(&cert);
989
0
    mbedtls_pk_init(&pk);
990
991
0
    UA_StatusCode retval = UA_mbedTLS_LoadCertificate(certificate, &cert);
992
0
    if(retval != UA_STATUSCODE_GOOD)
993
0
        goto cleanup;
994
995
0
    retval = (UA_mbedTLS_LoadPrivateKey(privateKey, &pk, NULL)? UA_STATUSCODE_BADSECURITYCHECKSFAILED : UA_STATUSCODE_GOOD);
996
0
    if(retval != UA_STATUSCODE_GOOD)
997
0
        goto cleanup;
998
999
    /* Verify the private key matches the public key in the certificate */
1000
0
    if(!mbedtls_pk_can_do(&pk, mbedtls_pk_get_type(&cert.pk))) {
1001
0
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
1002
0
        goto cleanup;
1003
0
    }
1004
1005
    /* Check if the public key from the certificate matches the private key */
1006
0
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
1007
0
    if(mbedtls_pk_check_pair(&cert.pk, &pk) != 0) {
1008
0
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
1009
0
    }
1010
#else
1011
    if(mbedtls_pk_check_pair(&cert.pk, &pk, mbedtls_entropy_func, NULL) != 0) {
1012
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
1013
    }
1014
#endif
1015
1016
0
cleanup:
1017
0
    mbedtls_pk_free(&pk);
1018
0
    mbedtls_x509_crt_free(&cert);
1019
1020
0
    return retval;
1021
0
}
1022
1023
UA_StatusCode
1024
19
UA_CertificateUtils_checkCA(const UA_ByteString *certificate) {
1025
19
    mbedtls_x509_crt cert;
1026
19
    mbedtls_x509_crt_init(&cert);
1027
1028
19
    UA_StatusCode retval = UA_mbedTLS_LoadCertificate(certificate, &cert);
1029
19
    if(retval != UA_STATUSCODE_GOOD)
1030
19
        goto cleanup;
1031
1032
0
    retval = mbedtlsCheckCA(&cert) ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADNOMATCH;
1033
1034
19
cleanup:
1035
19
    mbedtls_x509_crt_free(&cert);
1036
1037
19
    return retval;
1038
0
}
1039
1040
UA_StatusCode
1041
UA_CertificateUtils_decryptPrivateKey(const UA_ByteString privateKey,
1042
                                      const UA_ByteString password,
1043
0
                                      UA_ByteString *outDerKey) {
1044
0
    if(!outDerKey)
1045
0
        return UA_STATUSCODE_BADINTERNALERROR;
1046
1047
0
    if (privateKey.length == 0) {
1048
0
        *outDerKey = UA_BYTESTRING_NULL;
1049
0
        return UA_STATUSCODE_BADINVALIDARGUMENT;
1050
0
    }
1051
1052
    /* Already in DER format -> return verbatim.
1053
     * DER-encoded keys start with ASN.1 SEQUENCE tag (0x30). PEM-encoded keys
1054
     * start with "-----BEGIN" (0x2D). Check only the tag byte to handle both
1055
     * short-form (< 128 bytes) and long-form length encodings. */
1056
0
    if(privateKey.length > 1 && privateKey.data[0] == 0x30)
1057
0
        return UA_ByteString_copy(&privateKey, outDerKey);
1058
1059
    /* Create a null-terminated string */
1060
0
    UA_ByteString nullTerminatedKey = UA_mbedTLS_CopyDataFormatAware(&privateKey);
1061
0
    if(nullTerminatedKey.length != privateKey.length + 1)
1062
0
        return UA_STATUSCODE_BADOUTOFMEMORY;
1063
1064
    /* Create the private-key context */
1065
0
    mbedtls_pk_context ctx;
1066
0
    mbedtls_pk_init(&ctx);
1067
0
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
1068
0
    int err = mbedtls_pk_parse_key(&ctx, nullTerminatedKey.data,
1069
0
                                   nullTerminatedKey.length,
1070
0
                                   password.data, password.length);
1071
#else
1072
    mbedtls_entropy_context entropy;
1073
    mbedtls_entropy_init(&entropy);
1074
    int err = mbedtls_pk_parse_key(&ctx, nullTerminatedKey.data,
1075
                                   nullTerminatedKey.length,
1076
                                   password.data, password.length,
1077
                                   mbedtls_entropy_func, &entropy);
1078
    mbedtls_entropy_free(&entropy);
1079
#endif
1080
0
    UA_ByteString_clear(&nullTerminatedKey);
1081
0
    if(err != 0) {
1082
0
        mbedtls_pk_free(&ctx);
1083
0
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
1084
0
    }
1085
1086
    /* Write the DER-encoded key into a local buffer */
1087
0
    unsigned char buf[1 << 14];
1088
0
    size_t pos = (size_t)mbedtls_pk_write_key_der(&ctx, buf, sizeof(buf));
1089
1090
    /* Allocate memory */
1091
0
    UA_StatusCode res = UA_ByteString_allocBuffer(outDerKey, pos);
1092
0
    if(res != UA_STATUSCODE_GOOD) {
1093
0
        mbedtls_pk_free(&ctx);
1094
0
        return res;
1095
0
    }
1096
1097
    /* Copy to the output */
1098
0
    memcpy(outDerKey->data, &buf[sizeof(buf) - pos], pos);
1099
0
    mbedtls_pk_free(&ctx);
1100
0
    return UA_STATUSCODE_GOOD;
1101
0
}
1102
1103
#endif