1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** NetX Secure Component */
17 /** */
18 /** X.509 Digital Certificates */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23 #define NX_SECURE_SOURCE_CODE
24
25 #include "nx_secure_x509.h"
26
27 /**************************************************************************/
28 /* */
29 /* FUNCTION RELEASE */
30 /* */
31 /* _nx_secure_x509_certificate_chain_verify PORTABLE C */
32 /* 6.1.12 */
33 /* AUTHOR */
34 /* */
35 /* Timothy Stapko, Microsoft Corporation */
36 /* */
37 /* DESCRIPTION */
38 /* */
39 /* This function verifies a certificate chain (built using the service */
40 /* nx_secure_certificate_chain_build) by checking each issuer back to */
41 /* a certificate in the trusted store of the given X509 store. */
42 /* */
43 /* INPUT */
44 /* */
45 /* store Pointer to certificate store */
46 /* certificate Pointer to cert chain */
47 /* */
48 /* OUTPUT */
49 /* */
50 /* status Completion status */
51 /* */
52 /* CALLS */
53 /* */
54 /* _nx_secure_x509_certificate_verify Verify a certificate */
55 /* _nx_secure_x509_store_certificate_find */
56 /* Find a cert in a store */
57 /* _nx_secure_x509_distinguished_name_compare */
58 /* Compare distinguished name */
59 /* */
60 /* CALLED BY */
61 /* */
62 /* _nx_secure_tls_remote_certificate_verify */
63 /* Verify the server certificate */
64 /* _nx_secure_x509_crl_revocation_check Check revocation in crl */
65 /* */
66 /* RELEASE HISTORY */
67 /* */
68 /* DATE NAME DESCRIPTION */
69 /* */
70 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
71 /* 09-30-2020 Timothy Stapko Modified comment(s), */
72 /* resulting in version 6.1 */
73 /* 04-02-2021 Timothy Stapko Modified comment(s), */
74 /* removed dependency on TLS, */
75 /* resulting in version 6.1.6 */
76 /* 04-25-2022 Yuxin Zhou Modified comment(s), and */
77 /* reorganized internal logic, */
78 /* resulting in version 6.1.11 */
79 /* 07-29-2022 Yuxin Zhou Modified comment(s), and */
80 /* checked expiration for all */
81 /* the certs in the chain, */
82 /* resulting in version 6.1.12 */
83 /* */
84 /**************************************************************************/
_nx_secure_x509_certificate_chain_verify(NX_SECURE_X509_CERTIFICATE_STORE * store,NX_SECURE_X509_CERT * certificate,ULONG current_time)85 UINT _nx_secure_x509_certificate_chain_verify(NX_SECURE_X509_CERTIFICATE_STORE *store,
86 NX_SECURE_X509_CERT *certificate, ULONG current_time)
87 {
88 UINT status;
89 NX_SECURE_X509_CERT *current_certificate;
90 NX_SECURE_X509_CERT *issuer_certificate;
91 UINT issuer_location = NX_SECURE_X509_CERT_LOCATION_NONE;
92 INT compare_result;
93
94 /* Process, following X509 basic certificate authentication (RFC 5280):
95 * 1. Last certificate in chain is the end entity - start with it.
96 * 2. Build chain from issuer to issuer - linked list of issuers. Find in stores: [ Remote, Trusted ]
97 * 3. Walk list from end certificate back to a root CA in the trusted store, verifying each signature.
98 * Additionally, any policy enforcement should be done at each step.
99 */
100
101 /* Get working pointer to certificate chain entry. */
102 current_certificate = certificate;
103
104 while (current_certificate != NX_CRYPTO_NULL)
105 {
106
107 /* Check the certificate expiration against the current time. */
108 if (current_time != 0)
109 {
110 status = _nx_secure_x509_expiration_check(current_certificate, current_time);
111
112 if (status != NX_SECURE_X509_SUCCESS)
113 {
114 return(status);
115 }
116 }
117
118 /* See if the certificate is self-signed or not. */
119 compare_result = _nx_secure_x509_distinguished_name_compare(¤t_certificate -> nx_secure_x509_distinguished_name,
120 ¤t_certificate -> nx_secure_x509_issuer, NX_SECURE_X509_NAME_ALL_FIELDS);
121
122 if (compare_result != 0)
123 {
124 /* Find the certificate issuer in the store. */
125 status = _nx_secure_x509_store_certificate_find(store, ¤t_certificate -> nx_secure_x509_issuer, 0, &issuer_certificate, &issuer_location);
126
127 if (status != NX_SECURE_X509_SUCCESS)
128 {
129 return(NX_SECURE_X509_ISSUER_CERTIFICATE_NOT_FOUND);
130 }
131 }
132 else
133 {
134 #ifndef NX_SECURE_ALLOW_SELF_SIGNED_CERTIFICATES
135 /* The certificate is self-signed. If we don't allow that, return error. */
136 return(NX_SECURE_X509_INVALID_SELF_SIGNED_CERT);
137 #else
138 /* Certificate is self-signed and we are configured to accept them. */
139 issuer_certificate = current_certificate;
140 #endif
141 }
142
143 /* Verify the current certificate against its issuer certificate. */
144 status = _nx_secure_x509_certificate_verify(store, current_certificate, issuer_certificate);
145
146 if (status != 0)
147 {
148 return(status);
149 }
150 else
151 {
152 /* The comparison passed, so we have a valid issuer. If the issuer is in the trusted
153 store, our chain verification is complete. If the issuer is not in the trusted store,
154 then continue the verification process. */
155 if (issuer_location == NX_SECURE_X509_CERT_LOCATION_TRUSTED)
156 {
157 return(NX_SECURE_X509_SUCCESS);
158 }
159
160 #ifdef NX_SECURE_ALLOW_SELF_SIGNED_CERTIFICATES
161 /* Certificate is self-signed and we are configured to accept them. */
162 if (issuer_certificate == current_certificate)
163 {
164 /* Check for self-signed certificate in trusted store. */
165 status = _nx_secure_x509_store_certificate_find(store, ¤t_certificate -> nx_secure_x509_distinguished_name, 0, &issuer_certificate, &issuer_location);
166
167 if(status == NX_SECURE_X509_SUCCESS && issuer_location == NX_SECURE_X509_CERT_LOCATION_TRUSTED)
168 {
169 return(NX_SECURE_X509_SUCCESS);
170 }
171 /* Self-signed certificate is not trusted. */
172 break;
173 }
174 #endif
175 }
176
177 /* Advance our working pointer to the next entry in the list. */
178 current_certificate = issuer_certificate;
179 } /* End while. */
180
181 /* Certificate is invalid. */
182 return(NX_SECURE_X509_CHAIN_VERIFY_FAILURE);
183 }
184
185