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