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