X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5dd5f9ec28f304ca377c42fd7f711d6cf12b90e1..5c19dc3ae3bd8e40a9c028b0deddd50ff337692c:/Security/libsecurity_keychain/lib/SecImportExportPem.cpp?ds=inline diff --git a/Security/libsecurity_keychain/lib/SecImportExportPem.cpp b/Security/libsecurity_keychain/lib/SecImportExportPem.cpp deleted file mode 100644 index df675564..00000000 --- a/Security/libsecurity_keychain/lib/SecImportExportPem.cpp +++ /dev/null @@ -1,504 +0,0 @@ -/* - * Copyright (c) 2004,2011-2014 Apple Inc. All Rights Reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The 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. - * - * @APPLE_LICENSE_HEADER_END@ - * - * SecImportExportPem.cpp - private PEM routines for SecImportExport - */ - -#include "SecImportExportPem.h" -#include "SecExternalRep.h" -#include "SecImportExportUtils.h" -#include -#include -#include -#include -#include - -/* - * Text parsing routines. - * - * Search incoming text for specified string. Does not assume inText is - * NULL terminated. Returns pointer to start of found string in inText. - */ -static const char *findStr( - const char *inText, - unsigned inTextLen, - const char *str) // NULL terminated - search for this -{ - /* probably not the hottest string search algorithm... */ - const char *cp; - unsigned srchStrLen = (unsigned)strlen(str); - char c = str[0]; - - /* last char * we can search in inText for start of str */ - const char *endCp = inText + inTextLen - srchStrLen; - - for(cp=inText; cp<=endCp; cp++) { - if(*cp == c) { - if(!memcmp(cp, str, srchStrLen)) { - return cp; - } - } - } - return NULL; -} - -/* - * Obtain one line from current text. Returns a mallocd, NULL-terminated string - * which caller must free(). Also returns the number of chars consumed including - * the returned chars PLUS EOL terminators (\n and/or \r). - * - * ALWAYS returns a mallocd string if there is ANY data remaining per the - * incoming inTextLen. Returns NULL if inTextLen is zero. - */ -static const char *getLine( - const char *inText, - unsigned inTextLen, // RETURNED - unsigned *consumed) // RETURNED - -{ - *consumed = 0; - const char *cp = inText; - const char *newline = NULL; // if we found a newline, this points to the first one - - while(inTextLen) { - char c = *cp; - if((c == '\r') || (c == '\n')) { - if(newline == NULL) { - /* first newline */ - newline = cp; - } - } - else if(newline != NULL) { - /* non newline after newline, done */ - break; - } - (*consumed)++; - inTextLen--; - cp++; - } - unsigned linelen; - if(newline) { - linelen = (unsigned)(newline - inText); - } - else { - linelen = *consumed; - } - char *rtn = (char *)malloc(linelen + 1); - memmove(rtn, inText, linelen); - rtn[linelen] = 0; - return rtn; -} - -/* - * Table to facilitate conversion of known PEM header strings to - * the things we know about. - */ -typedef struct { - const char *pemStr; // e.g. PEM_STRING_X509, "CERTIFICATE" - SecExternalItemType itemType; - SecExternalFormat format; - CSSM_ALGORITHMS keyAlg; -} PemHeader; - -#define NOALG CSSM_ALGID_NONE - -static const PemHeader PemHeaders[] = -{ - /* from openssl/pem.h standard header */ - { PEM_STRING_X509_OLD, kSecItemTypeCertificate, kSecFormatX509Cert, NOALG}, - { PEM_STRING_X509, kSecItemTypeCertificate, kSecFormatX509Cert, NOALG }, - { PEM_STRING_EVP_PKEY, kSecItemTypePrivateKey, kSecFormatOpenSSL, NOALG}, - { PEM_STRING_PUBLIC, kSecItemTypePublicKey, kSecFormatOpenSSL, NOALG }, - { PEM_STRING_RSA, kSecItemTypePrivateKey, kSecFormatOpenSSL, CSSM_ALGID_RSA }, - { PEM_STRING_RSA_PUBLIC, kSecItemTypePublicKey, kSecFormatOpenSSL, CSSM_ALGID_RSA }, - { PEM_STRING_DSA, kSecItemTypePrivateKey, kSecFormatOpenSSL, CSSM_ALGID_DSA }, - { PEM_STRING_DSA_PUBLIC, kSecItemTypePublicKey, kSecFormatOpenSSL, CSSM_ALGID_DSA }, - { PEM_STRING_PKCS7, kSecItemTypeAggregate, kSecFormatPKCS7, NOALG }, - { PEM_STRING_PKCS8, kSecItemTypePrivateKey, kSecFormatWrappedPKCS8, NOALG }, - { PEM_STRING_PKCS8INF, kSecItemTypePrivateKey, kSecFormatUnknown, NOALG }, - /* we define these */ - { PEM_STRING_DH_PUBLIC, kSecItemTypePublicKey, kSecFormatOpenSSL, CSSM_ALGID_DH }, - { PEM_STRING_DH_PRIVATE, kSecItemTypePrivateKey, kSecFormatOpenSSL, CSSM_ALGID_DH }, - { PEM_STRING_PKCS12, kSecItemTypeAggregate, kSecFormatPKCS12, NOALG }, - { PEM_STRING_SESSION, kSecItemTypeSessionKey, kSecFormatRawKey, NOALG }, - { PEM_STRING_ECDSA_PUBLIC, kSecItemTypePublicKey, kSecFormatOpenSSL, CSSM_ALGID_ECDSA }, - { PEM_STRING_ECDSA_PRIVATE, kSecItemTypePrivateKey, kSecFormatOpenSSL, CSSM_ALGID_ECDSA } -}; -#define NUM_PEM_HEADERS (sizeof(PemHeaders) / sizeof(PemHeader)) - -/* - * 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; dexpemStr)) { - 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; -} - -/* - * PEM decode incoming data, appending SecImportRep's to specified array. - * Returned SecImportReps may or may not have a known type and format and - * (if they are keys) algorithm. - */ -OSStatus impExpParsePemToImportRefs( - CFDataRef importedData, - CFMutableArrayRef importReps, // output appended here - bool *isPem) // true means we think it was PEM regardless of - // final return code -{ - /* - * First task: is this PEM or at least base64 encoded? - */ - const char *currCp = (const char *)CFDataGetBytePtr(importedData); - const char *cp = currCp; - unsigned lenToGo = (unsigned)CFDataGetLength(importedData); - OSStatus ortn; - - *isPem = false; - unsigned dex; - bool allBlanks = true; - - for(dex=0; dex 150) { - return errSecParam; - } - - /* First base64 encode */ - enc = cuEnc64WithLines(CFDataGetBytePtr(derData), (unsigned)CFDataGetLength(derData), - 64, &encLen); - if(enc == NULL) { - /* malloc error is actually the only known failure */ - SecImpExpDbg("impExpPemEncodeExportRep: cuEnc64WithLines failure"); - return errSecAllocate; - } - - /* strip off trailing NULL */ - if((encLen != 0) && (enc[encLen - 1] == '\0')) { - encLen--; - } - sprintf(headerLine, "-----BEGIN %s-----\n", pemHeader); - CFDataAppendBytes(outData, (const UInt8 *)headerLine, strlen(headerLine)); - - /* optional PEM parameters lines (currently used for openssl wrap format only) */ - if(pemParamLines != NULL) { - CFIndex numLines = CFArrayGetCount(pemParamLines); - for(CFIndex dex=0; dex