X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/5dd5f9ec28f304ca377c42fd7f711d6cf12b90e1..5c19dc3ae3bd8e40a9c028b0deddd50ff337692c:/Security/libsecurity_transform/lib/EncodeDecodeTransforms.c diff --git a/Security/libsecurity_transform/lib/EncodeDecodeTransforms.c b/Security/libsecurity_transform/lib/EncodeDecodeTransforms.c deleted file mode 100644 index 413d7ec9..00000000 --- a/Security/libsecurity_transform/lib/EncodeDecodeTransforms.c +++ /dev/null @@ -1,1021 +0,0 @@ -/* - * Copyright (c) 2010-2012,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@ - */ - -#include "SecEncodeTransform.h" -#include "SecDecodeTransform.h" -#include "SecCustomTransform.h" -#include "CoreFoundation/CoreFoundation.h" -#include "misc.h" -#include "Utilities.h" -#include -#include - -const static CFStringRef DecodeName = CFSTR("com.apple.security.Decoder"); -const static CFStringRef EncodeName = CFSTR("com.apple.security.Encoder"); -// base32 & base64 are as per RFC 4648 -const CFStringRef kSecBase64Encoding = CFSTR("base64"); -const CFStringRef kSecBase32Encoding = CFSTR("base32"); -// kSecBase32FDEEncoding is SPI (8436055), it avoids I and O, and uses 8 and 9. -// Not good for number form dislexics, but avoids the appearance of a conflict -// between 0 and O or 1 and I (note: 0 and 1 are not used anyway, so there is -// no conflict). -const CFStringRef kSecBase32FDEEncoding = CFSTR("base32FDE"); -const CFStringRef kSecZLibEncoding = CFSTR("zlib"); -const CFStringRef kSecEncodeTypeAttribute = CFSTR("EncodeType"); -const CFStringRef kSecDecodeTypeAttribute = CFSTR("DecodeType"); -const CFStringRef kSecEncodeLineLengthAttribute = CFSTR("LineLength"); -const CFStringRef kSecCompressionRatio = CFSTR("CompressionRatio"); - -// There is no way to initialize a const CFNumberRef, so these -// either need to be non-const, or they need to be a CF type -// with a const constructor (CFStringRef). -const CFStringRef kSecLineLength64 = CFSTR("64"); -const CFStringRef kSecLineLength76 = CFSTR("76"); - -static unsigned char Base64Vals[] = -{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, - 0x3c, 0x3d, 0xff, 0xff, 0xff, 0x40, 0xff, 0xff, - 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, - 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, - 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, - 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, - 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - -static char Base64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" -"abcdefghijklmnopqrstuvwxyz" -"0123456789" -"+/="; - -static unsigned char Base32Vals[] = {0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - -static unsigned char Base32FDEVals[] = {0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x08, 0x12, - 0xff, 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x06, 0x07, 0xff, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x10, 0x11, 0xff, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - -/* -------------------------------------------------------------------------- - function: DecodeTransform - description: This function returns a block that implements the - Decode Transfrom - -------------------------------------------------------------------------- */ -static SecTransformInstanceBlock DecodeTransform(CFStringRef name, - SecTransformRef newTransform, - SecTransformImplementationRef ref) -{ - SecTransformInstanceBlock instanceBlock = - ^{ - CFErrorRef result = NULL; - SecTransformCustomSetAttribute(ref, kSecDecodeTypeAttribute, - kSecTransformMetaAttributeRequired, kCFBooleanTrue); - - SecTransformSetAttributeAction(ref, - kSecTransformActionAttributeNotification, - kSecDecodeTypeAttribute, - ^(SecTransformStringOrAttributeRef attribute, CFTypeRef value) - { - if (NULL == value || CFGetTypeID(value) != CFStringGetTypeID()) - { - CFErrorRef errorResult = fancy_error(kSecTransformErrorDomain, - kSecTransformErrorInvalidInput, - CFSTR("Decode type was not a CFStringRef")); - return (CFTypeRef)errorResult; - } - // value is a CFStringRef - if (kCFCompareEqualTo == CFStringCompare(value, kSecBase64Encoding, 0)) - { - __block struct { unsigned char a[4]; } leftover; - static const short int in_chunk_size = 4; - static const short int out_chunk_size = 3; - __block int leftover_cnt = 0; - - SecTransformSetDataAction(ref, kSecTransformActionProcessData, - ^(CFTypeRef value) - { - CFDataRef d = value; - CFIndex enc_cnt = d ? CFDataGetLength(d) : 0; - const unsigned char *enc = d ? CFDataGetBytePtr(d) : NULL; - const unsigned char *enc_end = enc + enc_cnt; - long n_chunks = (leftover_cnt + enc_cnt) / out_chunk_size + 1; - - unsigned char *out_base = malloc(n_chunks * out_chunk_size); - if (!out_base) { - return (CFTypeRef) GetNoMemoryError(); - } - unsigned char *out_end = out_base + n_chunks * out_chunk_size; - unsigned char *out = out_base; - int chunk_i = leftover_cnt; - - for(; enc < enc_end || !enc; chunk_i++) { - unsigned char ch, b; - if (enc) { - ch = *enc++; - } else { - ch = '='; - } - if (ch == ' ' || ch == '\n' || ch == '\r') { - chunk_i -= 1; - continue; - } - - b = Base64Vals[ch]; - if (b != 0xff) { - leftover.a[chunk_i] = b; - } - - if (chunk_i == in_chunk_size-1 || ch == '=') { - *out = (leftover.a[0] & 0x3f) << 2; - *out++ |= ((leftover.a[1] & 0x3f) >> 4); - *out = (leftover.a[1] & 0x0f) << 4; - *out++ |= (leftover.a[2] & 0x3f) >> 2; - *out = (leftover.a[2] & 0x03) << 6; - *out++ |= (leftover.a[3] & 0x3f); - - out -= 3 - chunk_i; - if (ch == '=') { - if (chunk_i != 0) { - out--; - } - chunk_i = -1; - break; - } - chunk_i = -1; - } - } - leftover_cnt = (chunk_i > 0) ? chunk_i : 0; - if (out > out_end) { - // We really shouldn't get here, but if we do we just smashed something. - abort(); - } - - CFDataRef ret = CFDataCreateWithBytesNoCopy(NULL, out_base, out - out_base, kCFAllocatorMalloc); - if (!d) { - SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, - kSecTransformMetaAttributeValue, ret); - CFRelease(ret); - ret = NULL; - } - return (CFTypeRef)ret; - }); - } - else if (kCFCompareEqualTo == CFStringCompare(value, kSecBase32Encoding, 0) || kCFCompareEqualTo == CFStringCompare(value, kSecBase32FDEEncoding, 0)) - { - __block struct { uint64_t a[2]; } accumulator = { .a = {0, 0}}; - __block short int bits_accumulated = 0; - //static const short int in_chunk_size = 5, out_chunk_size = 8; - static const short int out_chunk_size = 8; - const short int full_accumulator = 80; - unsigned char *base32values = NULL; - - if (kCFCompareEqualTo == CFStringCompare(value, kSecBase32Encoding, 0)) { - base32values = Base32Vals; - } else if (kCFCompareEqualTo == CFStringCompare(value, kSecBase32FDEEncoding, 0)) { - base32values = Base32FDEVals; - } - - if (NULL == base32values) { - // There is only one supported type, so we don't want to mention it in an error message - CFErrorRef bad_type = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "Unknown base32 type '%@'", value); - - SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, bad_type); - - return (CFTypeRef)bad_type; - } - - SecTransformSetDataAction(ref, kSecTransformActionProcessData, - ^(CFTypeRef value) - { - CFDataRef d = value; - CFIndex enc_cnt = d ? CFDataGetLength(d) : 0; - const unsigned char *enc = d ? CFDataGetBytePtr(d) : NULL; - const unsigned char *enc_end = enc + enc_cnt; - long n_chunks = (bits_accumulated/8 + enc_cnt) / out_chunk_size + 1; - - unsigned char *out_base = malloc(n_chunks * out_chunk_size); - if (!out_base) { - return (CFTypeRef)GetNoMemoryError(); - } - unsigned char *out_end = out_base + n_chunks * out_chunk_size; - unsigned char *out = out_base; - - for(; enc < enc_end || !d;) { - unsigned char ch, b; - if (enc) { - ch = *enc++; - } else { - ch = '='; - } - - b = base32values[ch]; - if (b == 0xff) { - continue; - } - - if (ch != '=') { - // 5 new low order bits - accumulator.a[1] = accumulator.a[1] << 5 | (0x1f & (accumulator.a[0] >> (64 -5))); - accumulator.a[0] = accumulator.a[0] << 5 | b; - bits_accumulated += 5; - } - if (bits_accumulated == full_accumulator || ch == '=') { - short shifted = 0; - for(; shifted + bits_accumulated < full_accumulator; shifted += 5) { - accumulator.a[1] = accumulator.a[1] << 5 | (0x1f & accumulator.a[0] >> (64 -5)); - accumulator.a[0] = accumulator.a[0] << 5; - } - for(; bits_accumulated >= 8; bits_accumulated -= 8) { - // Get 8 high bits - *out++ = accumulator.a[1] >> (80 - 64 - 8); - accumulator.a[1] = (accumulator.a[1] << 8 | accumulator.a[0] >> (64 - 8)) & 0xffff; - accumulator.a[0] = accumulator.a[0] << 8; - } - bits_accumulated = 0; - if (ch == '=') { - break; - } - } - } - if (out > out_end) { - // We really shouldn't get here, but if we do we just smashed something. - abort(); - } - - CFDataRef ret = CFDataCreateWithBytesNoCopy(NULL, out_base, out - out_base, kCFAllocatorMalloc); - if (!d) { - SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, - kSecTransformMetaAttributeValue, ret); - CFRelease(ret); - ret = NULL; - } - return (CFTypeRef)ret; - }); - } - else if (kCFCompareEqualTo == CFStringCompare(value, kSecZLibEncoding, 0)) - { - __block z_stream zs; - __block Boolean started = FALSE; - - CFBooleanRef hasRatio = (CFBooleanRef)SecTranformCustomGetAttribute(ref, - kSecCompressionRatio, kSecTransformMetaAttributeHasOutboundConnections); - Boolean ratio_connected = (kCFBooleanTrue == hasRatio); - - bzero(&zs, sizeof(zs)); - - SecTransformSetDataAction(ref, kSecTransformActionProcessData, - ^(CFTypeRef value) - { - CFDataRef d = value; - if (!started) { - if (!d) { - return (CFTypeRef)NULL; - } - started = TRUE; - inflateInit(&zs); - } - - if (d) { - zs.next_in = (UInt8 *)(CFDataGetBytePtr(d)); // we know that zlib will not 'futz' with the data - zs.avail_in = (uInt)CFDataGetLength(d); - } else { - zs.next_in = NULL; - zs.avail_in = 0; - } - - int rc = Z_OK; - - CFIndex buf_sz = malloc_good_size(zs.avail_in ? zs.avail_in : 1024 * 4); - - while ((d && zs.avail_in) || (d == NULL && rc != Z_STREAM_END)) { - unsigned char *buf = malloc(buf_sz); - if (!buf) { - return (CFTypeRef)GetNoMemoryError(); - } - - zs.next_out = buf; - zs.avail_out = (uInt)buf_sz; - - rc = inflate(&zs, d ? Z_NO_FLUSH : Z_FINISH); - - CFIndex buf_used = buf_sz - zs.avail_out; -#ifdef DEBUG_ZLIB_MEMORY_USE - // It might be useful to look at these and tweak things like when we should use DataCreate vs. DataCreateWithBytesNoCopy - CFfprintf(stderr, ">>zavail_in %d buf_sz %d; d %p; ", zs.avail_in, buf_sz, d); - CFfprintf(stderr, "rc=%d %s", rc, (rc == Z_OK) ? "Z_OK" : (rc == Z_STREAM_END) ? "Z_STREAM_END" : (rc == Z_BUF_ERROR) ? "Z_BUF_ERROR" : "?"); - CFfprintf(stderr, " (output used %d, input left %d)\n", buf_used, zs.avail_in); -#endif - if (rc == Z_OK || rc == Z_STREAM_END) { - CFDataRef d; - if ((4 * buf_used) / buf_sz <= 1) { - // we would waste 25%+ of the buffer, make a smaller copy and release the original - d = CFDataCreate(NULL, buf, buf_used); - free(buf); - } else { - d = CFDataCreateWithBytesNoCopy(NULL, buf, buf_used, kCFAllocatorMalloc); - } - SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, - kSecTransformMetaAttributeValue, d); - CFRelease(d); - } else if (rc == Z_BUF_ERROR) { - free(buf); - if ((int)buf_sz > (1 << Z_BEST_COMPRESSION) && 0 == zs.avail_in) { - // zlib has an odd convention about EOF and Z_BUF_ERROR, see http://www.zlib.net/zlib_how.html - // Z_BUF_ERROR can mean "you don't have a big enough output buffer, please enlarge", or "the input buffer is - // empty, please get more data". So if we get Z_BUF_ERROR, and there are 0 bytes of input, and the output - // buffer is larger the the maximum number of bytes a single symbol can decode to (2^compression level, which - // is at most Z_BEST_COMPRESSION) we KNOW the complaint isn't about the output buffer, but the input - // buffer and we are free to go. NOTE: we will only hit this if we are at the end of the stream, and the prior - // data chunk was already entirely decoded. - rc = Z_STREAM_END; - } - buf_sz = malloc_good_size(buf_sz * 2); - } else { - free(buf); - CFStringRef emsg = CFStringCreateWithFormat(NULL, NULL, CFSTR("Zlib error#%d"), rc); - CFErrorRef err = fancy_error(kSecTransformErrorDomain, kSecTransformErrorInvalidInput, emsg); - CFRelease(emsg); - return (CFTypeRef)err; - } - } - - if (ratio_connected && zs.total_in && zs.total_out) { - float r = (float)zs.total_in / zs.total_out; - CFNumberRef ratio = CFNumberCreate(NULL, kCFNumberFloatType, &r); - SecTransformCustomSetAttribute(ref, kSecCompressionRatio, - kSecTransformMetaAttributeValue, ratio); - CFRelease(ratio); - } - - if (rc == Z_OK) { - return (CFTypeRef)SecTransformNoData(); - } else if (rc == Z_STREAM_END) { - inflateEnd(&zs); - started = FALSE; - return (CFTypeRef)NULL; - } - CFStringRef emsg = CFStringCreateWithFormat(NULL, NULL, CFSTR("Zlib error#%d"), rc); - CFErrorRef err = fancy_error(kSecTransformErrorDomain, kSecTransformErrorInvalidInput, emsg); - CFRelease(emsg); - return (CFTypeRef)err; - }); - } - else - { - CFErrorRef bad_type = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "Unsupported decode type '%@', supported types are kSecBase64Encoding, kSecBase32Encoding, and kSecGZipEncoding", value); - - SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, bad_type); - - return (CFTypeRef)bad_type; - } - return value; - }); - - return result; - }; - - return Block_copy(instanceBlock); -} - - -SecTransformRef SecDecodeTransformCreate(CFTypeRef DecodeType, CFErrorRef* error) { - - static dispatch_once_t once; - __block Boolean ok = TRUE; - CFErrorRef localError = NULL; - - dispatch_block_t aBlock = ^ - { - ok = SecTransformRegister(DecodeName, &DecodeTransform, (CFErrorRef*)&localError); - }; - - dispatch_once(&once, aBlock); - - if (!ok || NULL != localError) - { - if (NULL != error) - { - *error = localError; - } - return NULL; - } - - SecTransformRef tr = SecTransformCreate(DecodeName, &localError); - if (!tr || NULL != localError) - { - // There might be a leak if tr is returned but localError is - // not NULL, but that should not happen - if (NULL != error) - { - *error = localError; - } - return NULL; - } - - SecTransformSetAttribute(tr, kSecDecodeTypeAttribute, DecodeType, &localError); - if (NULL != localError) - { - CFRelease(tr); - tr = NULL; - if (NULL != error) - { - *error = localError; - } - } - - return tr; -} - -static -unsigned char *encode_base64(const unsigned char *bin, unsigned char *base64, CFIndex bin_cnt) { - for(; bin_cnt > 0; bin_cnt -= 3, base64 += 4, bin += 3) { - switch (bin_cnt) - { - default: - case 3: - base64[0] = Base64Chars[((bin[0] >> 2) & 0x3f)]; - base64[1] = Base64Chars[((bin[0] & 0x03) << 4) | - ((bin[1] >> 4) & 0x0f)]; - base64[2] = Base64Chars[((bin[1] & 0x0f) << 2) | - ((bin[2] >> 6) & 0x03)]; - base64[3] = Base64Chars[(bin[2] & 0x3f)]; - break; - - case 2: - base64[3] = '='; - base64[0] = Base64Chars[((bin[0] >> 2) & 0x3f)]; - base64[1] = Base64Chars[((bin[0] & 0x03) << 4) | - ((bin[1] >> 4) & 0x0f)]; - base64[2] = Base64Chars[((bin[1] & 0x0f) << 2)]; - break; - - case 1: - base64[3] = base64[2] = '='; - base64[0] = Base64Chars[((bin[0] >> 2) & 0x3f)]; - base64[1] = Base64Chars[((bin[0] & 0x03) << 4)]; - break; - - case 0: - base64[0] = base64[1] = base64[2] = base64[3] = '='; - break; - } - } - - return base64; -} - - -/* -------------------------------------------------------------------------- - function: DecodeTransform - description: This function returns a block that implements the - Decode Transfrom - -------------------------------------------------------------------------- */ -static SecTransformInstanceBlock EncodeTransform(CFStringRef name, - SecTransformRef newTransform, - SecTransformImplementationRef ref) - -{ - SecTransformInstanceBlock instanceBlock = - ^{ - CFErrorRef result = NULL; - SecTransformCustomSetAttribute(ref, kSecEncodeTypeAttribute, - kSecTransformMetaAttributeRequired, kCFBooleanTrue); - - __block int line_length = 0, target_line_length = 0; - - SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, - kSecEncodeLineLengthAttribute, - ^(SecTransformStringOrAttributeRef attribute, CFTypeRef value) - { - SecTransformPushbackAttribute(ref, attribute, value); - return value; - }); - - CFTypeRef (^new_line_length)(int out_chunk_size, CFTypeRef value) = ^(int out_chunk_size, CFTypeRef value) - { - if (CFGetTypeID(value) == CFNumberGetTypeID()) { - CFNumberGetValue((CFNumberRef)value, kCFNumberIntType, &target_line_length); - } else if (CFGetTypeID(value) == CFStringGetTypeID()) { - int requested_length = CFStringGetIntValue(value); - if (requested_length == 0 && CFStringCompare(CFSTR("0"), value, kCFCompareAnchored)) { - SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "Could not convert '%@' to a number, please set %@ to a numeric value", kSecEncodeLineLengthAttribute, value)); - } else { - target_line_length = requested_length; - } - } else { - CFStringRef valueType = CFCopyTypeIDDescription(CFGetTypeID(value)); - SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, CreateSecTransformErrorRef(kSecTransformErrorInvalidType, "%@ requires a CFNumber, but was set to a %@ (%@)", kSecEncodeLineLengthAttribute, valueType, value)); - CFRelease(valueType); - } - target_line_length -= target_line_length % out_chunk_size; - - if (target_line_length < 0) { - target_line_length = 0; - } - - return value; - }; - - SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, - kSecEncodeTypeAttribute, - ^(SecTransformStringOrAttributeRef attribute, CFTypeRef value) - { - if (NULL == value || CFGetTypeID(value) != CFStringGetTypeID()) - { - CFErrorRef errorResult = fancy_error(kSecTransformErrorDomain, - kSecTransformErrorInvalidInput, - CFSTR("Encode type was not a CFStringRef")); - return (CFTypeRef)errorResult; - } - - if (kCFCompareEqualTo == CFStringCompare(value, kSecBase64Encoding, 0)) - { - __block struct { unsigned char a[3]; } leftover; - static const short int in_chunk_size = 3, out_chunk_size = 4; - __block CFIndex leftover_cnt = 0; - - SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, - kSecEncodeLineLengthAttribute, - ^(SecTransformStringOrAttributeRef attribute, CFTypeRef value) - { - return new_line_length(out_chunk_size, value); - }); - - SecTransformSetDataAction(ref, kSecTransformActionProcessData, - ^(CFTypeRef value) - { - CFDataRef d = value; - CFIndex in_len = d ? CFDataGetLength(d) : 0; - const unsigned char *in = d ? CFDataGetBytePtr(d) : NULL; - CFIndex n_chunks = in_len / in_chunk_size + 3; - CFIndex buf_len = n_chunks * out_chunk_size; - CFIndex line_len=0; - - if (target_line_length) - { - line_len=(n_chunks * out_chunk_size) / target_line_length; - } - if ( (in_len<0) - || (leftover_cnt<0) -#if __LLP64__ - || (n_chunks > LONG_LONG_MAX/out_chunk_size) - || (buf_len > LONG_LONG_MAX-line_len) -#else - || (n_chunks > LONG_MAX/out_chunk_size) - || (buf_len > LONG_MAX-line_len) -#endif - || (buf_len+line_len= leftover_cnt)) - { - CFIndex copy_len = in_chunk_size - leftover_cnt; - copy_len = (copy_len > in_len) ? in_len : copy_len; - memcpy(leftover.a + leftover_cnt, in, copy_len); - - if (copy_len + leftover_cnt == in_chunk_size || d == NULL) - { - out = encode_base64(leftover.a, out, copy_len + leftover_cnt); - if (in) - { - in += copy_len; - in_len -= copy_len; - } - } - else - { - free(out); - leftover_cnt += copy_len; - return (CFTypeRef)SecTransformNoData(); - } - } - - CFIndex chunked_in_len; - while (in_len >= in_chunk_size) - { - chunked_in_len = in_len - (in_len % in_chunk_size); - if (target_line_length) - { - if (target_line_length <= line_length + out_chunk_size) - { - *out++ = '\n'; - line_length = 0; - } - int max_process = (((target_line_length - line_length) / out_chunk_size) * in_chunk_size); - chunked_in_len = (chunked_in_len < max_process) ? chunked_in_len : max_process; - } - unsigned char *old_out = out; - out = encode_base64(in, out, chunked_in_len); - line_length += out - old_out; - in += chunked_in_len; - in_len -= chunked_in_len; - } - leftover_cnt = in_len; - if (leftover_cnt) - { - memcpy(leftover.a, in, leftover_cnt); - } - - if (out > out_end) - { - // we should never hit this, but if we do there is no recovery: we smashed past a buffer into the heap - abort(); - } - - CFTypeRef ret = CFDataCreateWithBytesNoCopy(NULL, out_base, out - out_base, kCFAllocatorMalloc); - if (!d) - { - SecTransformCustomSetAttribute(ref,kSecTransformOutputAttributeName, kSecTransformMetaAttributeValue, ret); - CFRelease(ret); - ret = NULL; - } - return ret; - }); - } - else if (kCFCompareEqualTo == CFStringCompare(value, kSecBase32Encoding, 0) || kCFCompareEqualTo == CFStringCompare(value, kSecBase32FDEEncoding, 0)) - { - __block struct { uint64_t a[2]; } accumulator = { .a = {0, 0} }; - __block short int bits_accumulated = 0; - static const short int in_chunk_size = 5; - static const short int out_chunk_size = 8; - char *base32alphabet = NULL; - - if (kCFCompareEqualTo == CFStringCompare(value, kSecBase32Encoding, 0)) { - base32alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; - } else if (kCFCompareEqualTo == CFStringCompare(value, kSecBase32FDEEncoding, 0)) { - base32alphabet = "ABCDEFGH8JKLMNOPQR9TUVWXYZ234567"; - } - - if (NULL == base32alphabet) { - // There is only one supported type, so we don't want to mention it in an error message - CFErrorRef bad_type = CreateSecTransformErrorRef(kSecTransformErrorInvalidInput, "Unknown base32 type '%@'", value); - - SecTransformCustomSetAttribute(ref, kSecTransformAbortAttributeName, kSecTransformMetaAttributeValue, bad_type); - - return (CFTypeRef)bad_type; - } - - SecTransformSetAttributeAction(ref, kSecTransformActionAttributeNotification, - kSecEncodeLineLengthAttribute, - ^(SecTransformStringOrAttributeRef attribute, CFTypeRef value) - { - return new_line_length(out_chunk_size, value); - }); - - SecTransformSetDataAction(ref, kSecTransformActionProcessData, - ^(CFTypeRef value) - { - CFDataRef d = value; - CFIndex in_len = d ? CFDataGetLength(d) : 0; - const unsigned char *in = d ? CFDataGetBytePtr(d) : NULL; - const unsigned char *in_end = in + in_len; - CFIndex n_chunks = in_len / in_chunk_size + 3; - CFIndex buf_len = n_chunks * out_chunk_size; - if (target_line_length) - { - buf_len += (n_chunks * out_chunk_size) / target_line_length; - } - __block unsigned char *out = malloc(buf_len); - unsigned char *out_end = out + buf_len, *out_base = out; - if (!out) { - return (CFTypeRef)GetNoMemoryError(); - } - - void (^chunk)(void) = ^{ - // Grab the 5 bit (log(32)==5) values from the 80 bit accumulator. Most signifigant bits first - - // (this could be done without the loop, which would save few cycles at the end of a stream) - short int shift = 80 - bits_accumulated; - for(; shift > 0; shift -= 8) { - accumulator.a[1] = accumulator.a[1] << 8 | accumulator.a[0] >> (64 - 8); - accumulator.a[0] = accumulator.a[0] << 8; - } - - for(; bits_accumulated > 0; bits_accumulated -= 5) { - *out++ = base32alphabet[(accumulator.a[1] >> 11) & 0x1f]; - accumulator.a[1] = 0xffff & (accumulator.a[1] << 5 | (accumulator.a[0] >> (64 - 5))); - accumulator.a[0] = accumulator.a[0] << 5; - if (++line_length >= target_line_length && target_line_length) { - *out++ = '\n'; - line_length = 0; - } - } - bits_accumulated = 0; - }; - - for (; in < in_end; in++) - { - accumulator.a[1] = accumulator.a[1] << 8 | accumulator.a[0] >> (64 - 8); - accumulator.a[0] = accumulator.a[0] << 8 | *in; - bits_accumulated += 8; - if (bits_accumulated == 8*in_chunk_size) - { - chunk(); - } - } - - if (!d && bits_accumulated) { - short int padding = 0; - switch(bits_accumulated) { - case 8: - padding = 6; - break; - case 16: - padding = 4; - break; - case 24: - padding = 3; - break; - case 32: - padding = 1; - break; - } - chunk(); - int i; - for(i = 0; i < padding; i++) { - *out++ = '='; - } - } - - if (out > out_end) { - // we should never hit this, but if we do there is no recovery: we smashed past a buffer into the heap - abort(); - } - - CFTypeRef ret = NULL; - if (out - out_base) { - ret = CFDataCreateWithBytesNoCopy(NULL, out_base, out - out_base, kCFAllocatorMalloc); - } else { - ret = SecTransformNoData(); - } - if (!d) { - if (ret != SecTransformNoData()) { - SecTransformCustomSetAttribute(ref, kSecTransformOutputAttributeName, - kSecTransformMetaAttributeValue, ret); - CFRelease(ret); - } - ret = NULL; - } - return ret; - }); - } - else if (kCFCompareEqualTo == CFStringCompare(value, kSecZLibEncoding, 0)) - { - __block z_stream zs; - bzero(&zs, sizeof(zs)); - __block int clevel = Z_DEFAULT_COMPRESSION; - __block Boolean started = FALSE; - - CFBooleanRef hasRatio = (CFBooleanRef)SecTranformCustomGetAttribute(ref, kSecCompressionRatio, - kSecTransformMetaAttributeHasOutboundConnections); - - Boolean ratio_connected = (kCFBooleanTrue == hasRatio); - - SecTransformSetDataAction(ref, kSecTransformActionProcessData, - ^(CFTypeRef value) - { - CFDataRef d = value; - - if (!started) { - started = TRUE; - deflateInit(&zs, clevel); - } - - if (d) { - zs.next_in = (UInt8 *)CFDataGetBytePtr(d); // We know that xLib will not 'Futz' with the data - zs.avail_in = (uInt)CFDataGetLength(d); - } else { - zs.next_in = NULL; - zs.avail_in = 0; - } - - int rc = Z_BUF_ERROR; - - CFIndex buf_sz = malloc_good_size(zs.avail_in ? zs.avail_in : 1024 * 4); - - while ((d && zs.avail_in) || (d == NULL && rc != Z_STREAM_END)) { - unsigned char *buf = malloc(buf_sz); - if (!buf) { - return (CFTypeRef)GetNoMemoryError(); - } - - zs.next_out = buf; - zs.avail_out = (uInt)buf_sz; - - rc = deflate(&zs, d ? Z_NO_FLUSH : Z_FINISH); - - CFIndex buf_used = buf_sz - zs.avail_out; - #ifdef DEBUG_ZLIB_MEMORY_USE - // It might be useful to look at these and tweak things like when we should use DataCreate vs. DataCreateWithBytesNoCopy - CFfprintf(stderr, "<