X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_cdsa_utils/lib/cuPem.cpp diff --git a/Security/libsecurity_cdsa_utils/lib/cuPem.cpp b/Security/libsecurity_cdsa_utils/lib/cuPem.cpp new file mode 100644 index 00000000..cbf87203 --- /dev/null +++ b/Security/libsecurity_cdsa_utils/lib/cuPem.cpp @@ -0,0 +1,198 @@ +/* + * Copyright (c) 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. + */ + +/* + File: cuPem.h + + Description: PEM encode/decode routines + + Author: dmitch + +*/ + +#include "cuPem.h" +#include +#include +#include +#include +#include "cuEnc64.h" + +#define PEM_SCAN_LEN 8192 + +/* + * Determine if specified blob appears to be PEM format. + * Returns 1 if so, 0 if not. + */ +int isPem( + const unsigned char *inData, + unsigned inDataLen) +{ + /* + * 1. The entire blob must be printable ASCII. + */ + const unsigned char *cp = inData; + for(unsigned dex=0; dex PEM_SCAN_LEN) { + len = PEM_SCAN_LEN; + } + memcpy(buf, inData, len); + buf[len] = '\0'; + const char *p = strstr((const char *)buf, "-----BEGIN "); + if(p == NULL) { + return 0; + } + + /* + * Now the last PEM_SCAN_LEN chars or inDataLen, whichever is less. + */ + if(inDataLen > PEM_SCAN_LEN) { + memcpy(buf, inData + inDataLen - PEM_SCAN_LEN, PEM_SCAN_LEN); + buf[PEM_SCAN_LEN] = '\0'; + } + /* else we already have whole blob in buf[] */ + p = strstr((const char *)buf, "-----END "); + if(p == NULL) { + return 0; + } + /* success */ + return 1; +} + +int pemEncode( + const unsigned char *inData, + unsigned inDataLen, + unsigned char **outData, + unsigned *outDataLen, + const char *headerString) +{ + unsigned char *enc; + unsigned encLen; + + /* First base64 encode */ + enc = cuEnc64WithLines(inData, inDataLen, 64, &encLen); + if(enc == NULL) { + /* malloc error is actually the only known failure */ + printf("***pemEncode: Error encoding file. Aborting.\n"); + return -1; + } + + /* estimate outsize - just be sloppy, way conservative */ + size_t outSize = encLen + (2 * strlen(headerString)) + 200; + *outData = (unsigned char *)malloc(outSize); + sprintf((char *)*outData, "-----BEGIN %s-----\n%s-----END %s-----\n", + headerString, (char *)enc, headerString); + *outDataLen = (unsigned int)strlen((char *)*outData); + + if((*outData)[*outDataLen - 1] == '\0') { + (*outDataLen)--; + } + free(enc); + return 0; +} + +int pemDecode( + const unsigned char *inData, + unsigned inDataLen, + unsigned char **outData, + unsigned *outDataLen) +{ + char *cp; + char *curr1, *curr2; + char *startPem = NULL; + char *endPem = NULL; + unsigned char *out; + unsigned outLen; + int ourRtn = 0; + char *freeCp = NULL; + + /* make the whole thing a NULL-terminated string */ + if(inData[inDataLen - 1] != '\0') { + cp = freeCp = (char *)malloc(inDataLen + 1); + memmove(cp, inData, inDataLen); + cp[inDataLen] = '\0'; + inDataLen++; + } + else { + /* already is */ + cp = (char *)inData; + } + + /* cp is start of NULL-terminated buffer, size inDataLen */ + /* skip over everything until "-----" */ + curr1 = strstr(cp, "-----"); + if(curr1 == NULL) { + printf("***pemDecode: no terminator found\n"); + ourRtn = -1; + goto abort; + } + + /* find end of separator line, handling both flavors of terminator */ + cp = curr1; + curr1 = strchr(cp, '\n'); + curr2 = strchr(cp, '\r'); + if((curr1 == NULL) & (curr2 == NULL)) { + printf("***pemDecode: Bad PEM format (1)\n"); + ourRtn = -1; + goto abort; + } + if(curr1 == NULL) { + startPem = curr2; + } + else { + startPem = curr1; + } + + /* startPem points to end of separator line */ + /* locate ending terminator and lop it off */ + curr1 = strstr(startPem, "-----"); + if(curr1 == NULL) { + printf("***pemDecode: Bad PEM format (2)\n"); + ourRtn = -1; + goto abort; + } + endPem = curr1; + /* endPem points to last PEM data plus one */ + + out = cuDec64((unsigned char *)startPem, (unsigned int)(endPem-startPem), &outLen); + if(out == NULL) { + printf("Bad PEM format (3)\n"); + ourRtn = -1; + goto abort; + } + *outData = out; + *outDataLen = outLen; +abort: + if(freeCp) { + free(freeCp); + } + return ourRtn; +} +