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
27 /**************************************************************************/
28 /* */
29 /* FUNCTION RELEASE */
30 /* */
31 /* _nx_secure_x509_subject_alt_names_find PORTABLE C */
32 /* 6.1.6 */
33 /* AUTHOR */
34 /* */
35 /* Timothy Stapko, Microsoft Corporation */
36 /* */
37 /* DESCRIPTION */
38 /* */
39 /* This function parses through the list of names in an X.509 */
40 /* subjectAltName extension, looking for a particular name. This is */
41 /* typically used to see if a DNS name is present in a subjectAltName */
42 /* extension if the Common Name did not match. */
43 /* */
44 /* INPUT */
45 /* */
46 /* extension subjectAltName extension data */
47 /* name Name to search for */
48 /* name_length Length of name */
49 /* name_type Type of name */
50 /* */
51 /* OUTPUT */
52 /* */
53 /* status Completion status */
54 /* */
55 /* CALLS */
56 /* */
57 /* _nx_secure_x509_asn1_tlv_block_parse Parse ASN.1 block */
58 /* _nx_secure_x509_wildcard_compare Wildcard compare for names */
59 /* */
60 /* CALLED BY */
61 /* */
62 /* _nx_secure_x509_common_name_dns_check Check Common Name by DNS */
63 /* */
64 /* RELEASE HISTORY */
65 /* */
66 /* DATE NAME DESCRIPTION */
67 /* */
68 /* 05-19-2020 Timothy Stapko Initial Version 6.0 */
69 /* 09-30-2020 Timothy Stapko Modified comment(s), */
70 /* resulting in version 6.1 */
71 /* 04-02-2021 Timothy Stapko Modified comment(s), */
72 /* removed dependency on TLS, */
73 /* resulting in version 6.1.6 */
74 /* */
75 /**************************************************************************/
_nx_secure_x509_subject_alt_names_find(NX_SECURE_X509_EXTENSION * extension,const UCHAR * name,UINT name_length,USHORT name_type)76 UINT _nx_secure_x509_subject_alt_names_find(NX_SECURE_X509_EXTENSION *extension, const UCHAR *name,
77 UINT name_length, USHORT name_type)
78 {
79 USHORT tlv_type;
80 USHORT tlv_type_class;
81 ULONG tlv_length;
82 const UCHAR *tlv_data;
83 const UCHAR *current_buffer;
84 ULONG length;
85 ULONG header_length;
86 UINT status;
87 const UCHAR *compare_name;
88 ULONG compare_length;
89 INT compare_value;
90
91 /* Now, parse the subjectAltName extension. */
92 /* subjectAltName ASN.1 format:
93 SubjectAltName ::= GeneralNames
94
95 GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
96
97 GeneralName ::= CHOICE {
98 otherName [0] AnotherName,
99 rfc822Name [1] IA5String,
100 dNSName [2] IA5String,
101 x400Address [3] ORAddress,
102 directoryName [4] Name,
103 ediPartyName [5] EDIPartyName,
104 uniformResourceIdentifier [6] IA5String,
105 iPAddress [7] OCTET STRING,
106 registeredID [8] OBJECT IDENTIFIER }
107
108 AnotherName ::= SEQUENCE {
109 type-id OBJECT IDENTIFIER,
110 value [0] EXPLICIT ANY DEFINED BY type-id }
111
112 EDIPartyName ::= SEQUENCE {
113 nameAssigner [0] DirectoryString OPTIONAL,
114 partyName [1] DirectoryString }
115 */
116
117 /* The length of our extensions is the length of the sequence. */
118 current_buffer = extension -> nx_secure_x509_extension_data;
119 length = extension -> nx_secure_x509_extension_data_length;
120
121 /* First, parse the name sequence. */
122 status = _nx_secure_x509_asn1_tlv_block_parse(current_buffer, &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
123
124 /* Make sure we parsed the block alright. */
125 if (status != 0)
126 {
127 return(status);
128 }
129
130 /* If the next item up is not a sequence, then it isn't an extensions block. */
131 if (!(tlv_type_class == NX_SECURE_ASN_TAG_CLASS_UNIVERSAL && tlv_type == NX_SECURE_ASN_TAG_SEQUENCE))
132 {
133 /* The extensions sequence isn't empty and we should be seeing another extension sequence
134 but we got something else so something is amiss. */
135 return(NX_SECURE_X509_INVALID_EXTENSION_SEQUENCE);
136 }
137
138 /* The names are in the body of the sequence structure, so use our tlv_data and length. */
139 current_buffer = tlv_data;
140 length = tlv_length;
141
142
143 /* Keep looping until we run out of data to parse. */
144 while (length > 0)
145 {
146 /* First, parse the context-specific tag (if it exists). */
147 status = _nx_secure_x509_asn1_tlv_block_parse(current_buffer, &length, &tlv_type, &tlv_type_class, &tlv_length, &tlv_data, &header_length);
148
149 /* Make sure we parsed the block alright. */
150 if (status != 0)
151 {
152 return(status);
153 }
154
155 /* If the next item up is not a context-sensitive tag, then not a valid subjectAltName. */
156 if (!(tlv_type_class == NX_SECURE_ASN_TAG_CLASS_CONTEXT))
157 {
158 /* No extensions block is OK because it is non-existent in v1 and v2, and
159 OPTIONAL in v3. */
160 return(NX_SECURE_X509_ALT_NAME_NOT_FOUND);
161 }
162
163 current_buffer += header_length;
164
165 /* If the name type we are searching for doesn't match what we just parsed,
166 continue to the next entry. */
167 if (tlv_type != name_type)
168 {
169 continue;
170 }
171
172 /* Process the name type we found. */
173 switch (tlv_type)
174 {
175 case NX_SECURE_X509_SUB_ALT_NAME_TAG_DNSNAME:
176 /* Now we have an IA5 string to compare against our name. */
177 compare_name = tlv_data;
178 compare_length = tlv_length;
179 break;
180 case NX_SECURE_X509_SUB_ALT_NAME_TAG_OTHERNAME:
181 case NX_SECURE_X509_SUB_ALT_NAME_TAG_RFC822NAME:
182 case NX_SECURE_X509_SUB_ALT_NAME_TAG_X400ADDRESS:
183 case NX_SECURE_X509_SUB_ALT_NAME_TAG_DIRECTORYNAME:
184 case NX_SECURE_X509_SUB_ALT_NAME_TAG_EDIPARTYNAME:
185 case NX_SECURE_X509_SUB_ALT_NAME_TAG_UNIFORMRESOURCEIDENTIFIER:
186 case NX_SECURE_X509_SUB_ALT_NAME_TAG_IPADDRESS:
187 case NX_SECURE_X509_SUB_ALT_NAME_TAG_REGISTEREDID:
188 default:
189 /* Deliberate fall-through. These name types are not supported. */
190 continue;
191 }
192
193 /* Compare the names, using wildcard matching. */
194 compare_value = _nx_secure_x509_wildcard_compare(name, name_length,
195 compare_name, compare_length);
196
197 if (compare_value == 0)
198 {
199 /* We found a match! */
200 return(NX_SECURE_X509_SUCCESS);
201 }
202
203 current_buffer += tlv_length;
204 } /* End while-loop. */
205
206 return(NX_SECURE_X509_ALT_NAME_NOT_FOUND);
207 }
208
209