X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_cdsa_utils/lib/cuOidParser.cpp diff --git a/Security/libsecurity_cdsa_utils/lib/cuOidParser.cpp b/Security/libsecurity_cdsa_utils/lib/cuOidParser.cpp new file mode 100644 index 00000000..7b2b7def --- /dev/null +++ b/Security/libsecurity_cdsa_utils/lib/cuOidParser.cpp @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2002-2003,2011-2012,2014 Apple Inc. All Rights Reserved. + * + * The contents of this file constitute Original Code as defined in and are + * subject to the Apple Public Source License Version 1.2 (the 'License'). + * You may not use this file except in compliance with the License. + * Please obtain a copy of the License at http://www.apple.com/publicsource + * and read it before using this file. + * + * This Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights + * and limitations under the License. + */ + +/* + * cuOidParser.cpp - parse an Intel-style OID, with the assistance + * of dumpasn1.cfg + */ + +#include +#include +#include +#include +#include "cuOidParser.h" +#include "cuFileIo.h" +#include +#include +#include +#include +#include +#include +#include + +/* get config file from .. or from . */ +#define CONFIG_FILE_NAME "dumpasn1.cfg" +static const char *CONFIG_FILE1 = "../"CONFIG_FILE_NAME; +static const char *CONFIG_FILE2 = CONFIG_FILE_NAME; +/* or from here via getenv */ +#define CONFIG_FILE_ENV "LOCAL_BUILD_DIR" + +static const char *OID_ENTRY_START = "OID = "; +static const char *OID_DESCR_START = "Description = "; +/* + * Read entire file with extra bytes left over in the mallocd buffer. + */ +static +int readFileExtra( + const char *fileName, + unsigned extraBytes, + unsigned char **bytes, // mallocd and returned + CSSM_SIZE *numBytes) // returned +{ + int rtn; + int fd; + unsigned char *buf; + struct stat sb; + size_t size; + + *numBytes = 0; + *bytes = NULL; + fd = open(fileName, O_RDONLY, 0); + if(fd < 0) { + return 1; + } + rtn = fstat(fd, &sb); + if(rtn) { + goto errOut; + } + size = (size_t)sb.st_size; + buf = (unsigned char *)malloc(size + extraBytes); + if(buf == NULL) { + rtn = ENOMEM; + goto errOut; + } + rtn = (int)lseek(fd, 0, SEEK_SET); + if(rtn < 0) { + goto errOut; + } + rtn = (int)read(fd, buf, (size_t)size); + if(rtn != (int)size) { + if(rtn >= 0) { + printf("readFile: short read\n"); + } + rtn = EIO; + } + else { + rtn = 0; + *bytes = buf; + *numBytes = size; + } +errOut: + close(fd); + return rtn; +} + +/* + * Attempt to read dumpasn1.cfg from various places. If we can't find it, + * printOid() function will just print raw bytes as it + * would if the .cfg file did not contain the desired OID. + */ +static CSSM_DATA_PTR readConfig() +{ + CSSM_DATA_PTR configData = NULL; + int rtn; + + configData = (CSSM_DATA_PTR)malloc(sizeof(CSSM_DATA)); + if(configData == NULL) { + return NULL; + } + /* malloc one extra byte, we'll null it later */ + rtn = readFileExtra(CONFIG_FILE1, 1, &configData->Data, + &configData->Length); + if(rtn) { + rtn = readFileExtra(CONFIG_FILE2, 1, &configData->Data, + &configData->Length); + } + if(rtn) { + char fileName[100]; + char *localBuildDir = getenv(CONFIG_FILE_ENV); + if(localBuildDir == NULL) { + rtn = 1; + } + else { + sprintf(fileName, "%s/%s", localBuildDir, CONFIG_FILE_NAME); + rtn = readFileExtra(fileName, 1, &configData->Data, + &configData->Length); + } + } + if(rtn == 0) { + /* make the whole shebang one long C string */ + configData->Data[configData->Length++] = '\0'; + return configData; + } + else { + free(configData); + return NULL; + } +} + +/* + * The heart of this module. + * + * -- Convert Intel-style OID to a string which might be found + * in the config file + * -- search config file for that string + * -- if found, use that entry in config file to output meaningful + * string and return CSSM_TRUE. Else return CSSM_FALSE. + */ +static CSSM_BOOL parseOidWithConfig( + const CSSM_DATA_PTR configData, + const CSSM_OID_PTR oid, + char *strBuf) +{ + char *fullOidStr = NULL; + char *ourEntry = NULL; + char *nextEntry = NULL; + char *descStart = NULL; + char *cp; + unsigned i; + CSSM_BOOL brtn; + char *nextCr; // next CR if any + char *nextNl; // next NL if any + char *eol; // end of line + int len; + + if(configData == NULL) { + return CSSM_FALSE; + } + + /* cook up a full OID string, with tag and length */ + fullOidStr = (char *)malloc((3 * oid->Length) + + // 2 chars plus space per byte + strlen(OID_ENTRY_START) + // "OID = " + 6 + // 06 xx - tag and length + 1); // NULL + if(fullOidStr == NULL) { + return CSSM_FALSE; + } + /* subsequent errors to errOut: */ + + sprintf(fullOidStr, "OID = 06 %02X", (unsigned)oid->Length); + cp = fullOidStr + strlen(fullOidStr); + for(i=0; iLength; i++) { + /* move cp to current end of string */ + cp += strlen(cp); + /* add one byte */ + sprintf(cp, " %02X", oid->Data[i]); + } + + /* + * Let's play it loose and assume that there are no embedded NULLs + * in the config file. Thus we can use the spiffy string functions + * in stdlib. + */ + ourEntry = strstr((char *)configData->Data, fullOidStr); + if(ourEntry == NULL) { + brtn = CSSM_FALSE; + goto errOut; + } + + /* get position of NEXT full entry - may be NULL (end of file) */ + nextEntry = strstr(ourEntry+1, OID_ENTRY_START); + + /* get position of our entry's description line */ + descStart = strstr(ourEntry+1, OID_DESCR_START); + + /* handle not found/overflow */ + if( (descStart == NULL) || // no more description lines + ( (descStart > nextEntry) && // no description in THIS entry + (nextEntry != NULL) ) ) { // make sure this is valid + brtn = CSSM_FALSE; + goto errOut; + } + + /* set descStart to after the leader */ + descStart += strlen(OID_DESCR_START); + + /* + * descStart points to the text we're interested in. + * First find end of line, any style. + */ + nextNl = strchr(descStart, '\n'); + nextCr = strchr(descStart, '\r'); + if((nextNl == NULL) && (nextCr == NULL)) { + /* no line terminator, go to eof */ + eol = (char *)configData->Data + configData->Length; + } + else if(nextCr == NULL) { + eol = nextNl; + } + else if(nextNl == NULL) { + eol = nextCr; + } + else if(nextNl < nextCr) { + /* both present, take first one */ + eol = nextNl; + } + else { + eol = nextCr; + } + + /* caller's string buf = remainder of description line */ + len = (int)(eol - descStart); + if(len > (OID_PARSER_STRING_SIZE - 1)) { + /* fixed-length output buf, avoid overflow */ + len = OID_PARSER_STRING_SIZE - 1; + } + memcpy(strBuf, descStart, len); + strBuf[len] = '\0'; + brtn = CSSM_TRUE; +errOut: + if(fullOidStr != NULL) { + free(fullOidStr); + } + return brtn; +} + +/*** OidParser class ***/ +OidParser::OidParser(bool noConfig) +{ + if(noConfig) { + configData = NULL; + } + else { + configData = readConfig(); + } +} + +OidParser::~OidParser() +{ + if(configData == NULL) { + return; + } + if(configData->Data != NULL) { + free(configData->Data); + } + free(configData); +} + +/* + * Parse an Intel-style OID, generating a C string in caller-supplied buffer. + */ +void OidParser::oidParse( + const unsigned char *oidp, + unsigned oidLen, + char *strBuf) +{ + unsigned i; + CSSM_OID oid; + + oid.Data = (uint8 *)oidp; + oid.Length = oidLen; + + if((oidLen == 0) || (oidp == NULL)) { + strcpy(strBuf, "EMPTY"); + return; + } + if(parseOidWithConfig(configData, &oid, strBuf) == CSSM_FALSE) { + /* no config file, just dump the bytes */ + char cbuf[8]; + + sprintf(strBuf, "OID : < 06 %02X ", (unsigned)oid.Length); + for(i=0; i"); + } +} + +