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;
}
/*
 * PEM decode incoming data which we've previously determined to contain
 * exactly one reasonably well formed PEM blob (it has no more than one
 * START and END line - though it may have none - and is all ASCII).
 *
 * Returned SecImportRep may or may not have a known type and format and 
 * (if it is a key) algorithm. 
 */
static OSStatus impExpImportSinglePEM(
	const char			*currCp,
	unsigned			lenToGo,
	CFMutableArrayRef	importReps)		// output appended here
{
	unsigned consumed;
	const char *currLine = NULL;		// mallocd by getLine()
	const char *lastCp = currCp;
	CFMutableArrayRef pemParamLines = NULL;
	OSStatus ortn = errSecSuccess;
	CFDataRef cdata = NULL;
	Security::KeychainCore::SecImportRep *rep = NULL;
	const char *start64;
	unsigned base64Len;	
	const char *end64;
	unsigned char *decData;
	unsigned decDataLen;
	
	/* we try to glean these from the header, but it's not fatal if we can not */
	SecExternalFormat format = kSecFormatUnknown;
	SecExternalItemType itemType = kSecItemTypeUnknown;
	CSSM_ALGORITHMS keyAlg = CSSM_ALGID_NONE;
	
	/* search to START line, parse it to get type/format/alg */
	const char *startLine = findStr(currCp, lenToGo, "-----BEGIN");
	if(startLine != NULL) {
		/* possibly skip over leading garbage */
		consumed = (unsigned)(startLine - currCp);
		lenToGo -= consumed;
		currCp = startLine;
		
		/* get C string of START line */
		currLine = getLine(startLine, lenToGo, &consumed);
		if(currLine == NULL) {
			/* somehow got here with no data */
			assert(lenToGo == 0);
			SecImpInferDbg("impExpImportSinglePEM empty data");
			ortn = errSecUnsupportedFormat;
			goto errOut;
		}
		assert(consumed <= lenToGo);
		currCp  += consumed;
		lenToGo -= consumed;

		/*
		 * Search currLine for known PEM header strings.
		 * It is not an error if we don't recognize this
		 * header.
		 */
		for(unsigned dex=0; dex<NUM_PEM_HEADERS; dex++) {
			const PemHeader *ph = &PemHeaders[dex];
			if(!strstr(currLine, ph->pemStr)) {
				continue;
			}
			/* found one! */
			format   = ph->format;
			itemType = ph->itemType;
			keyAlg   = ph->keyAlg;
			break;
		}
		
		free((void *)currLine);
	}

	/* 
	 * Skip empty lines. Save all lines containing ':' (used by openssl 
	 * to specify key wrapping parameters). These will be saved in 
	 * outgoing SecImportReps' pemParamLines.
	 */
	for( ; ; ) {
		currLine = getLine(currCp, lenToGo, &consumed);
		if(currLine == NULL || currCp == lastCp) {
			/* out of data (unable to advance to next line) */
			SecImpInferDbg("impExpImportSinglePEM out of data");
			if (currLine) free((void *)currLine);
			ortn = errSecUnsupportedFormat;
			goto errOut;
		}
		lastCp = currCp;
		
		bool skipThis = false;
		unsigned lineLen = (unsigned)strlen(currLine);
		if(lineLen == 0) {
			/* empty line */
			skipThis = true;
		}
		if(strchr(currLine, ':')) {
			/* 
			 * Save this PEM header info. Used for traditional openssl
			 * wrapped keys to indicate IV.
			 */
			SecImpInferDbg("import PEM: param line %s", currLine);
			CFStringRef cfStr = CFStringCreateWithCString(NULL, currLine,
				kCFStringEncodingASCII);
			if(pemParamLines == NULL) {
				/* first param line */
				pemParamLines = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
				
				/* 
				 * If it says "ENCRYPTED" and this is a private key,
				 * flag the fact that it's wrapped in openssl format
				 */
				if(strstr(currLine, "ENCRYPTED")) {
					if((format == kSecFormatOpenSSL) &&
					   (itemType == kSecItemTypePrivateKey)) {
						format = kSecFormatWrappedOpenSSL;
					}
				}
			}
			CFArrayAppendValue(pemParamLines, cfStr);
			CFRelease(cfStr);		// array owns it 
			skipThis = true;
		}
		free((void *)currLine);
		if(!skipThis) {
			/* looks like good stuff; process */
			break;
		}
		/* skip this line */
		assert(consumed <= lenToGo);
		currCp  += consumed;
		lenToGo -= consumed;
	}
	if(lenToGo <= 2) {
		SecImpInferDbg("impExpImportSinglePEM no valid base64 data");
		ortn = errSecUnsupportedFormat;
		goto errOut;
	}

	/* 
	 * currCP points to start of base64 data - mark it and search for end line.
	 * We skip everything after the end line.
	 */
	start64 = currCp;
	base64Len = lenToGo;			// if no END
	end64 = findStr(currCp, lenToGo, "-----END");
	if(end64 != NULL) {
		if(end64 == start64) {
			/* Empty, nothing between START and END */
			SecImpInferDbg("impExpImportSinglePEM no base64 between terminators");
			ortn = errSecUnsupportedFormat;
			goto errOut;
		}
		base64Len = (unsigned)(end64 - start64);
	}
	/* else no END, no reason to complain about that as long as base64 decode works OK */
	
	/* Base 64 decode */
	decData = cuDec64((const unsigned char *)start64, base64Len, &decDataLen);
	if(decData == NULL) {
		SecImpInferDbg("impExpImportSinglePEM bad base64 data");
		ortn = errSecUnsupportedFormat;
		goto errOut;
	}
	
	cdata = CFDataCreate(NULL, decData, decDataLen);
	free((void *)decData);
	rep = new Security::KeychainCore::SecImportRep(cdata, itemType, format, keyAlg,
		pemParamLines);
	CFArrayAppendValue(importReps, rep);
	CFRelease(cdata);		// SecImportRep holds ref
	return errSecSuccess;
	
errOut:
	if(pemParamLines != NULL) {
		CFRelease(pemParamLines);
	}
	return ortn;
}