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