]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cdsa_utils/lib/cuOidParser.cpp
Security-58286.200.222.tar.gz
[apple/security.git] / OSX / libsecurity_cdsa_utils / lib / cuOidParser.cpp
1 /*
2 * Copyright (c) 2002-2003,2011-2012,2014-2016 Apple Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License.
7 * Please obtain a copy of the License at http://www.apple.com/publicsource
8 * and read it before using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
12 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
13 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
14 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
15 * Please see the License for the specific language governing rights
16 * and limitations under the License.
17 */
18
19 /*
20 * cuOidParser.cpp - parse an Intel-style OID, with the assistance
21 * of dumpasn1.cfg
22 */
23
24 #include <Security/cssmtype.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include "cuOidParser.h"
29 #include "cuFileIo.h"
30 #include <fcntl.h>
31 #include <errno.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <unistd.h>
37
38 /* get config file from .. or from . */
39 #define CONFIG_FILE_NAME "dumpasn1.cfg"
40 static const char *CONFIG_FILE1 = "../" CONFIG_FILE_NAME;
41 static const char *CONFIG_FILE2 = CONFIG_FILE_NAME;
42 /* or from here via getenv */
43 #define CONFIG_FILE_ENV "LOCAL_BUILD_DIR"
44
45 static const char *OID_ENTRY_START = "OID = ";
46 static const char *OID_DESCR_START = "Description = ";
47 /*
48 * Read entire file with extra bytes left over in the mallocd buffer.
49 */
50 static
51 int readFileExtra(
52 const char *fileName,
53 unsigned extraBytes,
54 unsigned char **bytes, // mallocd and returned
55 CSSM_SIZE *numBytes) // returned
56 {
57 int rtn;
58 int fd;
59 unsigned char *buf = NULL;
60 struct stat sb;
61 size_t size;
62
63 *numBytes = 0;
64 *bytes = NULL;
65 fd = open(fileName, O_RDONLY, 0);
66 if(fd < 0) {
67 return 1;
68 }
69 rtn = fstat(fd, &sb);
70 if(rtn) {
71 goto errOut;
72 }
73 size = (size_t)sb.st_size;
74 buf = (unsigned char *)malloc(size + extraBytes);
75 if(buf == NULL) {
76 rtn = ENOMEM;
77 goto errOut;
78 }
79 rtn = (int)read(fd, buf, (size_t)size);
80 if(rtn != (int)size) {
81 free(buf);
82 if(rtn >= 0) {
83 printf("readFile: short read\n");
84 }
85 rtn = EIO;
86 }
87 else {
88 rtn = 0;
89 *bytes = buf;
90 *numBytes = size;
91 }
92 errOut:
93 close(fd);
94 return rtn;
95 }
96
97 /*
98 * Attempt to read dumpasn1.cfg from various places. If we can't find it,
99 * printOid() function will just print raw bytes as it
100 * would if the .cfg file did not contain the desired OID.
101 */
102 static CSSM_DATA_PTR readConfig()
103 {
104 CSSM_DATA_PTR configData = NULL;
105 int rtn;
106
107 configData = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA));
108 if(configData == NULL) {
109 return NULL;
110 }
111 /* malloc one extra byte, we'll null it later */
112 rtn = readFileExtra(CONFIG_FILE1, 1, &configData->Data,
113 &configData->Length);
114 if(rtn) {
115 rtn = readFileExtra(CONFIG_FILE2, 1, &configData->Data,
116 &configData->Length);
117 }
118 if(rtn) {
119 char *localBuildDir = getenv(CONFIG_FILE_ENV);
120 if(localBuildDir == NULL) {
121 rtn = 1;
122 }
123 else {
124 char *pathBuf = NULL;
125 rtn = asprintf(&pathBuf, "%s/%s", localBuildDir, CONFIG_FILE_NAME);
126 if (rtn < 1 || !pathBuf) {
127 rtn = 1;
128 }
129 else {
130 rtn = readFileExtra(pathBuf, 1, &configData->Data,
131 &configData->Length);
132 }
133 if (pathBuf) {
134 free(pathBuf);
135 }
136 }
137 }
138 if(rtn == 0) {
139 /* make the whole shebang one long C string */
140 configData->Data[configData->Length++] = '\0';
141 return configData;
142 }
143 else {
144 free(configData);
145 return NULL;
146 }
147 }
148
149 /*
150 * The heart of this module.
151 *
152 * -- Convert Intel-style OID to a string which might be found
153 * in the config file
154 * -- search config file for that string
155 * -- if found, use that entry in config file to output meaningful
156 * string and return CSSM_TRUE. Else return CSSM_FALSE.
157 */
158 static CSSM_BOOL parseOidWithConfig(
159 const CSSM_DATA_PTR configData,
160 const CSSM_OID_PTR oid,
161 char *strBuf)
162 {
163 char *fullOidStr = NULL;
164 char *ourEntry = NULL;
165 char *nextEntry = NULL;
166 char *descStart = NULL;
167 char *cp;
168 unsigned i;
169 CSSM_BOOL brtn;
170 char *nextCr; // next CR if any
171 char *nextNl; // next NL if any
172 char *eol; // end of line
173 int len;
174
175 if(configData == NULL) {
176 return CSSM_FALSE;
177 }
178
179 /* cook up a full OID string, with tag and length */
180 fullOidStr = (char *)malloc((3 * oid->Length) +
181 // 2 chars plus space per byte
182 strlen(OID_ENTRY_START) + // "OID = "
183 6 + // 06 xx - tag and length
184 1); // NULL
185 if(fullOidStr == NULL) {
186 return CSSM_FALSE;
187 }
188 /* subsequent errors to errOut: */
189
190 sprintf(fullOidStr, "OID = 06 %02X", (unsigned)oid->Length);
191 cp = fullOidStr + strlen(fullOidStr);
192 for(i=0; i<oid->Length; i++) {
193 /* move cp to current end of string */
194 cp += strlen(cp);
195 /* add one byte */
196 sprintf(cp, " %02X", oid->Data[i]);
197 }
198
199 /*
200 * Let's play it loose and assume that there are no embedded NULLs
201 * in the config file. Thus we can use the spiffy string functions
202 * in stdlib.
203 */
204 ourEntry = strstr((char *)configData->Data, fullOidStr);
205 if(ourEntry == NULL) {
206 brtn = CSSM_FALSE;
207 goto errOut;
208 }
209
210 /* get position of NEXT full entry - may be NULL (end of file) */
211 nextEntry = strstr(ourEntry+1, OID_ENTRY_START);
212
213 /* get position of our entry's description line */
214 descStart = strstr(ourEntry+1, OID_DESCR_START);
215
216 /* handle not found/overflow */
217 if( (descStart == NULL) || // no more description lines
218 ( (descStart > nextEntry) && // no description in THIS entry
219 (nextEntry != NULL) ) ) { // make sure this is valid
220 brtn = CSSM_FALSE;
221 goto errOut;
222 }
223
224 /* set descStart to after the leader */
225 descStart += strlen(OID_DESCR_START);
226
227 /*
228 * descStart points to the text we're interested in.
229 * First find end of line, any style.
230 */
231 nextNl = strchr(descStart, '\n');
232 nextCr = strchr(descStart, '\r');
233 if((nextNl == NULL) && (nextCr == NULL)) {
234 /* no line terminator, go to eof */
235 eol = (char *)configData->Data + configData->Length;
236 }
237 else if(nextCr == NULL) {
238 eol = nextNl;
239 }
240 else if(nextNl == NULL) {
241 eol = nextCr;
242 }
243 else if(nextNl < nextCr) {
244 /* both present, take first one */
245 eol = nextNl;
246 }
247 else {
248 eol = nextCr;
249 }
250
251 /* caller's string buf = remainder of description line */
252 len = (int)(eol - descStart);
253 if(len > (OID_PARSER_STRING_SIZE - 1)) {
254 /* fixed-length output buf, avoid overflow */
255 len = OID_PARSER_STRING_SIZE - 1;
256 }
257 memcpy(strBuf, descStart, len);
258 strBuf[len] = '\0';
259 brtn = CSSM_TRUE;
260 errOut:
261 if(fullOidStr != NULL) {
262 free(fullOidStr);
263 }
264 return brtn;
265 }
266
267 /*** OidParser class ***/
268 OidParser::OidParser(bool noConfig)
269 {
270 if(noConfig) {
271 configData = NULL;
272 }
273 else {
274 configData = readConfig();
275 }
276 }
277
278 OidParser::~OidParser()
279 {
280 if(configData == NULL) {
281 return;
282 }
283 if(configData->Data != NULL) {
284 free(configData->Data);
285 }
286 free(configData);
287 }
288
289 /*
290 * Parse an Intel-style OID, generating a C string in caller-supplied buffer.
291 */
292 void OidParser::oidParse(
293 const unsigned char *oidp,
294 unsigned oidLen,
295 char *strBuf)
296 {
297 unsigned i;
298 CSSM_OID oid;
299
300 oid.Data = (uint8 *)oidp;
301 oid.Length = oidLen;
302
303 if((oidLen == 0) || (oidp == NULL)) {
304 strcpy(strBuf, "EMPTY");
305 return;
306 }
307 if(parseOidWithConfig(configData, &oid, strBuf) == CSSM_FALSE) {
308 /* no config file, just dump the bytes */
309 char cbuf[8];
310
311 sprintf(strBuf, "OID : < 06 %02X ", (unsigned)oid.Length);
312 for(i=0; i<oid.Length; i++) {
313 sprintf(cbuf, "%02X ", oid.Data[i]);
314 strcat(strBuf, cbuf);
315 }
316 strcat(strBuf, ">");
317 }
318 }
319
320