summaryrefslogtreecommitdiff
path: root/nx_secure/src/nx_secure_x509_certificate_chain_verify.c
blob: 16882e47814bb7a4c2feb389384a31d4c17b5740 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/***************************************************************************
 * Copyright (c) 2024 Microsoft Corporation
 * Copyright (c) 2025-present Eclipse ThreadX Contributors
 *
 * This program and the accompanying materials are made available under the
 * terms of the MIT License which is available at
 * https://opensource.org/licenses/MIT.
 *
 * SPDX-License-Identifier: MIT
 **************************************************************************/


/**************************************************************************/
/**************************************************************************/
/**                                                                       */
/** NetX Secure Component                                                 */
/**                                                                       */
/**    X.509 Digital Certificates                                         */
/**                                                                       */
/**************************************************************************/
/**************************************************************************/

#define NX_SECURE_SOURCE_CODE

#include "nx_secure_x509.h"

/**************************************************************************/
/*                                                                        */
/*  FUNCTION                                               RELEASE        */
/*                                                                        */
/*    _nx_secure_x509_certificate_chain_verify            PORTABLE C      */
/*                                                           6.1.12       */
/*  AUTHOR                                                                */
/*                                                                        */
/*    Timothy Stapko, Microsoft Corporation                               */
/*                                                                        */
/*  DESCRIPTION                                                           */
/*                                                                        */
/*    This function verifies a certificate chain (built using the service */
/*    nx_secure_certificate_chain_build) by checking each issuer back to  */
/*    a certificate in the trusted store of the given X509 store.         */
/*                                                                        */
/*  INPUT                                                                 */
/*                                                                        */
/*    store                                 Pointer to certificate store  */
/*    certificate                           Pointer to cert chain         */
/*                                                                        */
/*  OUTPUT                                                                */
/*                                                                        */
/*    status                                Completion status             */
/*                                                                        */
/*  CALLS                                                                 */
/*                                                                        */
/*    _nx_secure_x509_certificate_verify    Verify a certificate          */
/*    _nx_secure_x509_store_certificate_find                              */
/*                                          Find a cert in a store        */
/*    _nx_secure_x509_distinguished_name_compare                          */
/*                                          Compare distinguished name    */
/*                                                                        */
/*  CALLED BY                                                             */
/*                                                                        */
/*    _nx_secure_tls_remote_certificate_verify                            */
/*                                          Verify the server certificate */
/*    _nx_secure_x509_crl_revocation_check  Check revocation in crl       */
/*                                                                        */
/**************************************************************************/
UINT _nx_secure_x509_certificate_chain_verify(NX_SECURE_X509_CERTIFICATE_STORE *store,
                                              NX_SECURE_X509_CERT *certificate, ULONG current_time)
{
UINT                 status;
NX_SECURE_X509_CERT *current_certificate;
NX_SECURE_X509_CERT *issuer_certificate;
UINT                 issuer_location = NX_SECURE_X509_CERT_LOCATION_NONE;
INT                  compare_result;

    /* Process, following X509 basic certificate authentication (RFC 5280):
     *    1. Last certificate in chain is the end entity - start with it.
     *    2. Build chain from issuer to issuer - linked list of issuers. Find in stores: [ Remote, Trusted ]
     *    3. Walk list from end certificate back to a root CA in the trusted store, verifying each signature.
     *       Additionally, any policy enforcement should be done at each step.
     */

    /* Get working pointer to certificate chain entry. */
    current_certificate = certificate;

    while (current_certificate != NX_CRYPTO_NULL)
    {

        /* Check the certificate expiration against the current time. */
        if (current_time != 0)
        {
            status = _nx_secure_x509_expiration_check(current_certificate, current_time);

            if (status != NX_SECURE_X509_SUCCESS)
            {
                return(status);
            }
        }

        /* See if the certificate is self-signed or not. */
        compare_result = _nx_secure_x509_distinguished_name_compare(&current_certificate -> nx_secure_x509_distinguished_name,
                                                                    &current_certificate -> nx_secure_x509_issuer, NX_SECURE_X509_NAME_ALL_FIELDS);

        if (compare_result != 0)
        {
            /* Find the certificate issuer in the store. */
            status = _nx_secure_x509_store_certificate_find(store, &current_certificate -> nx_secure_x509_issuer, 0, &issuer_certificate, &issuer_location);

            if (status != NX_SECURE_X509_SUCCESS)
            {
                return(NX_SECURE_X509_ISSUER_CERTIFICATE_NOT_FOUND);
            }
        }
        else
        {
#ifndef NX_SECURE_ALLOW_SELF_SIGNED_CERTIFICATES
            /* The certificate is self-signed. If we don't allow that, return error. */
            return(NX_SECURE_X509_INVALID_SELF_SIGNED_CERT);
#else
            /* Certificate is self-signed and we are configured to accept them. */
            issuer_certificate = current_certificate;
#endif
        }

        /* Verify the current certificate against its issuer certificate. */
        status = _nx_secure_x509_certificate_verify(store, current_certificate, issuer_certificate);

        if (status != 0)
        {
            return(status);
        }
        else
        {
            /* The comparison passed, so we have a valid issuer. If the issuer is in the trusted
               store, our chain verification is complete. If the issuer is not in the trusted store,
               then continue the verification process. */
            if (issuer_location == NX_SECURE_X509_CERT_LOCATION_TRUSTED)
            {
                return(NX_SECURE_X509_SUCCESS);
            }

#ifdef NX_SECURE_ALLOW_SELF_SIGNED_CERTIFICATES
            /* Certificate is self-signed and we are configured to accept them. */
            if (issuer_certificate == current_certificate)
            {
                /* Check for self-signed certificate in trusted store. */
                status = _nx_secure_x509_store_certificate_find(store, &current_certificate -> nx_secure_x509_distinguished_name, 0, &issuer_certificate, &issuer_location);
                
                if(status == NX_SECURE_X509_SUCCESS && issuer_location == NX_SECURE_X509_CERT_LOCATION_TRUSTED)
                {
                    return(NX_SECURE_X509_SUCCESS);
                }
                /* Self-signed certificate is not trusted. */
                break;
            }
#endif
        }

        /* Advance our working pointer to the next entry in the list. */
        current_certificate = issuer_certificate;
    } /* End while. */

    /* Certificate is invalid. */
    return(NX_SECURE_X509_CHAIN_VERIFY_FAILURE);
}