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 static INT _nx_secure_x509_distinguished_name_field_compare(const UCHAR *field1, UINT length1,
28 const UCHAR *field2, UINT length2);
29
30 /**************************************************************************/
31 /* */
32 /* FUNCTION RELEASE */
33 /* */
34 /* _nx_secure_x509_distinguished_name_compare PORTABLE C */
35 /* 6.1.6 */
36 /* AUTHOR */
37 /* */
38 /* Timothy Stapko, Microsoft Corporation */
39 /* */
40 /* DESCRIPTION */
41 /* */
42 /* This function compares two X509 Distinguished Names to see if they */
43 /* are equal. Returns 0 on equality, non-zero otherwise. The */
44 /* compare_fields parameter is a bitmap that indicates which fields to */
45 /* compare. In general, internal comparisons (as when validating a */
46 /* certificate chain) will use NX_SECURE_X509_NAME_ALL_FIELDS, which */
47 /* will do a full name comparison using the enabled fields (strict */
48 /* name compare and extended name fields change the behavior). For any */
49 /* calls coming from application/user API will use the bit value */
50 /* NX_SECURE_X509_NAME_COMMON_NAME so only the Common Name fields are */
51 /* compared (even if strict name comparison is enabled). Eventually, */
52 /* the bitfield may be exposed to the user level to allow users to */
53 /* have more control over X.509 distinguished name comparisons. */
54 /* */
55 /* INPUT */
56 /* */
57 /* name Pointer to an X509 name */
58 /* compare_name Name to compare against */
59 /* compare_fields Bitmap of fields to compare */
60 /* */
61 /* OUTPUT */
62 /* */
63 /* equality 0 if equal, else non-zero */
64 /* */
65 /* CALLS */
66 /* */
67 /* _nx_secure_x509_distinguished_name_field_compare */
68 /* Compare common names */
69 /* */
70 /* CALLED BY */
71 /* */
72 /* _nx_secure_tls_send_certificate Send DTLS certificate */
73 /* _nx_secure_x509_certificate_chain_verify */
74 /* Verify cert against stores */
75 /* _nx_secure_x509_certificate_list_add Add incoming cert to store */
76 /* _nx_secure_x509_certificate_list_find Find certificate by name */
77 /* _nx_secure_x509_certificate_list_remove */
78 /* Remove certificate from list */
79 /* _nx_secure_x509_crl_revocation_check Check revocation in crl */
80 /* _nx_secure_x509_remote_endpoint_certificate_get */
81 /* Get remote host certificate */
82 /* */
83 /* RELEASE HISTORY */
84 /* */
85 /* DATE NAME DESCRIPTION */
86 /* */
87 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
88 /* 09-30-2020 Timothy Stapko Modified comment(s), */
89 /* resulting in version 6.1 */
90 /* 04-02-2021 Timothy Stapko Modified comment(s), */
91 /* removed dependency on TLS, */
92 /* resulting in version 6.1.6 */
93 /* */
94 /**************************************************************************/
_nx_secure_x509_distinguished_name_compare(NX_SECURE_X509_DISTINGUISHED_NAME * name,NX_SECURE_X509_DISTINGUISHED_NAME * compare_name,ULONG compare_fields)95 INT _nx_secure_x509_distinguished_name_compare(NX_SECURE_X509_DISTINGUISHED_NAME *name,
96 NX_SECURE_X509_DISTINGUISHED_NAME *compare_name,
97 ULONG compare_fields)
98 {
99 INT status = 0;
100
101 /* NOTE: The status is updated using a binary OR operation - using addition would allow
102 someone to construct a distinguished name that falsely matches another by explioting
103 the memcmp return values (which are signed so if you had one string that returned a
104 positive value you could negate that by using a string that compared with an equal
105 magnitude negative value). */
106
107 /* Compare common names for equality. */
108 if (compare_fields & NX_SECURE_X509_NAME_COMMON_NAME)
109 {
110 status = _nx_secure_x509_distinguished_name_field_compare(name -> nx_secure_x509_common_name,
111 name -> nx_secure_x509_common_name_length,
112 compare_name -> nx_secure_x509_common_name,
113 compare_name -> nx_secure_x509_common_name_length);
114 }
115
116 /* If we are doing strict X509 comparisons, compare ALL fields. */
117 #ifdef NX_SECURE_X509_STRICT_NAME_COMPARE
118 if (compare_fields & NX_SECURE_X509_NAME_COUNTRY)
119 {
120 status |= _nx_secure_x509_distinguished_name_field_compare(name -> nx_secure_x509_country,
121 name -> nx_secure_x509_country_length,
122 compare_name -> nx_secure_x509_country,
123 compare_name -> nx_secure_x509_country_length);
124 }
125
126 if (compare_fields & NX_SECURE_X509_NAME_ORGANIZATION)
127 {
128 status |= _nx_secure_x509_distinguished_name_field_compare(name -> nx_secure_x509_organization,
129 name -> nx_secure_x509_organization_length,
130 compare_name -> nx_secure_x509_organization,
131 compare_name -> nx_secure_x509_organization_length);
132 }
133
134 if (compare_fields & NX_SECURE_X509_NAME_ORG_UNIT)
135 {
136 status |= _nx_secure_x509_distinguished_name_field_compare(name -> nx_secure_x509_org_unit,
137 name -> nx_secure_x509_org_unit_length,
138 compare_name -> nx_secure_x509_org_unit,
139 compare_name -> nx_secure_x509_org_unit_length);
140 }
141
142 if (compare_fields & NX_SECURE_X509_NAME_QUALIFIER)
143 {
144 status |= _nx_secure_x509_distinguished_name_field_compare(name -> nx_secure_x509_distinguished_name_qualifier,
145 name -> nx_secure_x509_distinguished_name_qualifier_length,
146 compare_name -> nx_secure_x509_distinguished_name_qualifier,
147 compare_name -> nx_secure_x509_distinguished_name_qualifier_length);
148 }
149
150 if (compare_fields & NX_SECURE_X509_NAME_STATE)
151 {
152 status |= _nx_secure_x509_distinguished_name_field_compare(name -> nx_secure_x509_state,
153 name -> nx_secure_x509_state_length,
154 compare_name -> nx_secure_x509_state,
155 compare_name -> nx_secure_x509_state_length);
156 }
157
158 if (compare_fields & NX_SECURE_X509_NAME_SERIAL_NUMBER)
159 {
160 status |= _nx_secure_x509_distinguished_name_field_compare(name -> nx_secure_x509_serial_number,
161 name -> nx_secure_x509_serial_number_length,
162 compare_name -> nx_secure_x509_serial_number,
163 compare_name -> nx_secure_x509_serial_number_length);
164 }
165
166
167 #ifdef NX_SECURE_X509_USE_EXTENDED_DISTINGUISHED_NAMES
168
169
170 if (compare_fields & NX_SECURE_X509_NAME_LOCALITY)
171 {
172 status |= _nx_secure_x509_distinguished_name_field_compare(name -> nx_secure_x509_locality,
173 name -> nx_secure_x509_locality_length,
174 compare_name -> nx_secure_x509_locality,
175 compare_name -> nx_secure_x509_locality_length);
176 }
177
178 if (compare_fields & NX_SECURE_X509_NAME_TITLE)
179 {
180 status |= _nx_secure_x509_distinguished_name_field_compare(name -> nx_secure_x509_title,
181 name -> nx_secure_x509_title_length,
182 compare_name -> nx_secure_x509_title,
183 compare_name -> nx_secure_x509_title_length);
184 }
185
186 if (compare_fields & NX_SECURE_X509_NAME_SURNAME)
187 {
188 status |= _nx_secure_x509_distinguished_name_field_compare(name -> nx_secure_x509_surname,
189 name -> nx_secure_x509_surname_length,
190 compare_name -> nx_secure_x509_surname,
191 compare_name -> nx_secure_x509_surname_length);
192 }
193
194 if (compare_fields & NX_SECURE_X509_NAME_GIVEN_NAME)
195 {
196 status |= _nx_secure_x509_distinguished_name_field_compare(name -> nx_secure_x509_given_name,
197 name -> nx_secure_x509_given_name_length,
198 compare_name -> nx_secure_x509_given_name,
199 compare_name -> nx_secure_x509_given_name_length);
200 }
201
202 if (compare_fields & NX_SECURE_X509_NAME_INITIALS)
203 {
204 status |= _nx_secure_x509_distinguished_name_field_compare(name -> nx_secure_x509_initials,
205 name -> nx_secure_x509_initials_length,
206 compare_name -> nx_secure_x509_initials,
207 compare_name -> nx_secure_x509_initials_length);
208 }
209
210 if (compare_fields & NX_SECURE_X509_NAME_PSEUDONYM)
211 {
212 status |= _nx_secure_x509_distinguished_name_field_compare(name -> nx_secure_x509_pseudonym,
213 name -> nx_secure_x509_pseudonym_length,
214 compare_name -> nx_secure_x509_pseudonym,
215 compare_name -> nx_secure_x509_pseudonym_length);
216 }
217
218 if (compare_fields & NX_SECURE_X509_NAME_GENERATION_QUALIFIER)
219 {
220 status |= _nx_secure_x509_distinguished_name_field_compare(name -> nx_secure_x509_generation_qualifier,
221 name -> nx_secure_x509_generation_qualifier_length,
222 compare_name -> nx_secure_x509_generation_qualifier,
223 compare_name -> nx_secure_x509_generation_qualifier_length);
224 }
225 #endif
226 #endif
227
228 return(status);
229 }
230
231 /**************************************************************************/
232 /* */
233 /* FUNCTION RELEASE */
234 /* */
235 /* _nx_secure_x509_distinguished_name_field_compare PORTABLE C */
236 /* 6.1 */
237 /* AUTHOR */
238 /* */
239 /* Timothy Stapko, Microsoft Corporation */
240 /* */
241 /* DESCRIPTION */
242 /* */
243 /* This function compares two X509 Distinguished Name fields given two */
244 /* separate lengths to see if they are equal. Handles special cases */
245 /* where lengths are not equal and when both lengths are 0. */
246 /* Returns 0 on equality or both lengths 0, non-zero otherwise. */
247 /* */
248 /* INPUT */
249 /* */
250 /* field1 Pointer to an X509 name field */
251 /* length1 Length of field1 */
252 /* field2 Pointer to an X509 name field */
253 /* length2 Length of field2 */
254 /* */
255 /* OUTPUT */
256 /* */
257 /* equality 0 if equal, else non-zero */
258 /* */
259 /* CALLS */
260 /* */
261 /* None */
262 /* */
263 /* CALLED BY */
264 /* */
265 /* _nx_secure_x509_distinguished_name_compare */
266 /* Compare distinguished name */
267 /* */
268 /* RELEASE HISTORY */
269 /* */
270 /* DATE NAME DESCRIPTION */
271 /* */
272 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
273 /* 09-30-2020 Timothy Stapko Modified comment(s), */
274 /* resulting in version 6.1 */
275 /* */
276 /**************************************************************************/
_nx_secure_x509_distinguished_name_field_compare(const UCHAR * field1,const UINT length1,const UCHAR * field2,const UINT length2)277 static INT _nx_secure_x509_distinguished_name_field_compare(const UCHAR *field1, const UINT length1,
278 const UCHAR *field2, const UINT length2)
279 {
280 INT compare_value;
281
282 if (length1 == length2)
283 {
284 /* If lengths are both 0, return equality. */
285 if (length1 == 0)
286 {
287 compare_value = 0;
288 }
289 else
290 {
291 /* Lengths are equal and non-zero, actually compare strings. */
292 compare_value = NX_SECURE_MEMCMP(field1, field2, length1);
293 }
294 }
295 else
296 {
297 /* Lengths are not equal, return inequality. */
298 compare_value = 1;
299 }
300
301 return(compare_value);
302 }
303
304