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