+++ /dev/null
-/*
- * Copyright (c) 2003-2009,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@
- *
- * keychain_utilities.c
- */
-
-#include "keychain_utilities.h"
-#include "security_tool.h"
-
-#include <Security/cssmapi.h>
-#include <Security/SecAccess.h>
-#include <Security/SecACL.h>
-#include <Security/SecTrustedApplication.h>
-#include <Security/SecKeychainItem.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/param.h>
-#include <libkern/OSByteOrder.h>
-#include <utilities/SecCFRelease.h>
-
-#include "readline_cssm.h"
-
-// SecTrustedApplicationValidateWithPath
-#include <Security/SecTrustedApplicationPriv.h>
-#include <Security/SecKeychainPriv.h>
-
-
-void check_obsolete_keychain(const char *kcName)
-{
- if(kcName == NULL) {
- return;
- }
- if(!strcmp(kcName, "/System/Library/Keychains/X509Anchors")) {
- fprintf(stderr, "***************************************************************\n");
- fprintf(stderr, " WARNING\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "The keychain you are accessing, X509Anchors, is no longer\n");
- fprintf(stderr, "used by Mac OS X as the system root certificate store.\n");
- fprintf(stderr, "Please read the security man page for information on the \n");
- fprintf(stderr, "add-trusted-cert command. New system root certificates should\n");
- fprintf(stderr, "be added to the Admin Trust Settings domain and to the \n");
- fprintf(stderr, "System keychain in /Library/Keychains.\n");
- fprintf(stderr, "***************************************************************\n");
- }
- else if(!strcmp(kcName, "/System/Library/Keychains/X509Certificates")) {
- fprintf(stderr, "***************************************************************\n");
- fprintf(stderr, " WARNING\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "The keychain you are accessing, X509Certificates, is no longer\n");
- fprintf(stderr, "used by Mac OS X as the system intermediate certificate\n");
- fprintf(stderr, "store. New system intermediate certificates should be added\n");
- fprintf(stderr, "to the System keychain in /Library/Keychains.\n");
- fprintf(stderr, "***************************************************************\n");
- }
-}
-
-SecKeychainRef CF_RETURNS_RETAINED
-keychain_open(const char *name)
-{
- SecKeychainRef keychain = NULL;
- OSStatus result;
-
- check_obsolete_keychain(name);
- if (name && name[0] != '/')
- {
- CFArrayRef dynamic = NULL;
- result = SecKeychainCopyDomainSearchList(
- kSecPreferencesDomainDynamic, &dynamic);
- if (result)
- {
- sec_error("SecKeychainCopyDomainSearchList %s: %s",
- name, sec_errstr(result));
- return NULL;
- }
- else
- {
- uint32_t i;
- CFIndex count = dynamic ? CFArrayGetCount(dynamic) : 0;
-
- for (i = 0; i < count; ++i)
- {
- char pathName[MAXPATHLEN];
- UInt32 ioPathLength = sizeof(pathName);
- bzero(pathName, ioPathLength);
- keychain = (SecKeychainRef)CFArrayGetValueAtIndex(dynamic, i);
- result = SecKeychainGetPath(keychain, &ioPathLength, pathName);
- if (result)
- {
- sec_error("SecKeychainGetPath %s: %s",
- name, sec_errstr(result));
- return NULL;
- }
- if (!strncmp(pathName, name, ioPathLength))
- {
- CFRetain(keychain);
- CFRelease(dynamic);
- return keychain;
- }
- }
- CFReleaseNull(dynamic);
- }
- }
-
- if(name) {
- result = SecKeychainOpen(name, &keychain);
- } else {
- result = errSecParam;
- }
- if (result)
- {
- sec_error("SecKeychainOpen %s: %s", name, sec_errstr(result));
- }
-
- return keychain;
-}
-
-CFTypeRef
-keychain_create_array(int argc, char * const *argv)
-{
- if (argc == 0)
- return NULL;
- else if (argc == 1)
- return keychain_open(argv[0]);
- else
- {
- CFMutableArrayRef keychains = CFArrayCreateMutable(NULL, argc, &kCFTypeArrayCallBacks);
- int ix;
- for (ix = 0; ix < argc; ++ix)
- {
- SecKeychainRef keychain = keychain_open(argv[ix]);
- if (keychain)
- {
- CFArrayAppendValue(keychains, keychain);
- CFRelease(keychain);
- }
- }
-
- return keychains;
- }
-}
-
-int
-parse_fourcharcode(const char *name, UInt32 *code)
-{
- UInt32 cc = 0;
- size_t len = (name) ? strlen(name) : 0;
-
- // error check the name
- if (len != 4)
- {
- fprintf(stderr, "Error: four-character types must be exactly 4 characters long.\n");
- if (len == 3) {
- fprintf(stderr, "(Try \"%s \" instead of \"%s\")\n", name, name);
- }
- return 1;
- }
-
- int i;
- for (i = 0; i < 4; ++i)
- {
- cc = (cc << 8) | name[i];
- }
-
- *code = cc; // note: this is in host byte order, suitable for passing to APIs
-
- return 0;
-}
-
-int
-print_keychain_name(FILE *stream, SecKeychainRef keychain)
-{
- int result = 0;
- char pathName[MAXPATHLEN];
- UInt32 ioPathLength = sizeof(pathName);
- OSStatus status = SecKeychainGetPath(keychain, &ioPathLength, pathName);
- if (status)
- {
- sec_perror("SecKeychainGetPath", status);
- result = 1;
- goto loser;
- }
-
- print_buffer(stream, ioPathLength, pathName);
-
-loser:
- return result;
-}
-
-static int
-print_keychain_version(FILE* stream, SecKeychainRef keychain)
-{
- int result = 0;
- UInt32 version;
- OSStatus status = SecKeychainGetKeychainVersion(keychain, &version);
- if(status) {
- sec_perror("SecKeychainGetKeychainVersion", status);
- result = 1;
- goto loser;
- }
-
- fprintf(stream, "%d", (uint32_t) version);
-
-loser:
- return result;
-}
-
-static void
-print_cfdata(FILE *stream, CFDataRef data)
-{
- if (data)
- return print_buffer(stream, CFDataGetLength(data), CFDataGetBytePtr(data));
- else
- fprintf(stream, "<NULL>");
-}
-
-void
-print_cfstring(FILE *stream, CFStringRef string)
-{
- if (!string)
- fprintf(stream, "<NULL>");
- else
- {
- const char *utf8 = CFStringGetCStringPtr(string, kCFStringEncodingUTF8);
- if (utf8)
- fprintf(stream, "%s", utf8);
- else
- {
- CFRange rangeToProcess = CFRangeMake(0, CFStringGetLength(string));
- while (rangeToProcess.length > 0)
- {
- UInt8 localBuffer[256];
- CFIndex usedBufferLength;
- CFIndex numChars = CFStringGetBytes(string, rangeToProcess,
- kCFStringEncodingUTF8, '?', FALSE, localBuffer,
- sizeof(localBuffer), &usedBufferLength);
- if (numChars == 0)
- break; // Failed to convert anything...
-
- fprintf(stream, "%.*s", (int)usedBufferLength, localBuffer);
- rangeToProcess.location += numChars;
- rangeToProcess.length -= numChars;
- }
- }
- }
-}
-
-static int
-print_access(FILE *stream, SecAccessRef access, Boolean interactive)
-{
- CFArrayRef aclList = NULL;
- CFIndex aclix, aclCount;
- int result = 0;
- OSStatus status;
-
- status = SecAccessCopyACLList(access, &aclList);
- if (status)
- {
- sec_perror("SecAccessCopyACLList", status);
- result = 1;
- goto loser;
- }
-
- aclCount = CFArrayGetCount(aclList);
- fprintf(stream, "access: %lu entries\n", aclCount);
- for (aclix = 0; aclix < aclCount; ++aclix)
- {
- CFArrayRef applicationList = NULL;
- CFStringRef description = NULL;
- CSSM_ACL_KEYCHAIN_PROMPT_SELECTOR promptSelector = {};
- CFIndex appix, appCount;
-
- SecACLRef acl = (SecACLRef)CFArrayGetValueAtIndex(aclList, aclix);
- CSSM_ACL_AUTHORIZATION_TAG tags[64]; // Pick some upper limit
- uint32 tagix, tagCount = sizeof(tags) / sizeof(*tags);
- status = SecACLGetAuthorizations(acl, tags, &tagCount);
- if (status)
- {
- sec_perror("SecACLGetAuthorizations", status);
- result = 1;
- goto loser;
- }
-
- fprintf(stream, " entry %lu:\n authorizations (%lu):", aclix,
- (unsigned long)tagCount);
- bool printPartitionIDList = false;
- for (tagix = 0; tagix < tagCount; ++tagix)
- {
- CSSM_ACL_AUTHORIZATION_TAG tag = tags[tagix];
- switch (tag)
- {
- case CSSM_ACL_AUTHORIZATION_ANY:
- fputs(" any", stream);
- break;
- case CSSM_ACL_AUTHORIZATION_LOGIN:
- fputs(" login", stream);
- break;
- case CSSM_ACL_AUTHORIZATION_GENKEY:
- fputs(" genkey", stream);
- break;
- case CSSM_ACL_AUTHORIZATION_DELETE:
- fputs(" delete", stream);
- break;
- case CSSM_ACL_AUTHORIZATION_EXPORT_WRAPPED:
- fputs(" export_wrapped", stream);
- break;
- case CSSM_ACL_AUTHORIZATION_EXPORT_CLEAR:
- fputs(" export_clear", stream);
- break;
- case CSSM_ACL_AUTHORIZATION_IMPORT_WRAPPED:
- fputs(" import_wrapped", stream);
- break;
- case CSSM_ACL_AUTHORIZATION_IMPORT_CLEAR:
- fputs(" import_clear", stream);
- break;
- case CSSM_ACL_AUTHORIZATION_SIGN:
- fputs(" sign", stream);
- break;
- case CSSM_ACL_AUTHORIZATION_ENCRYPT:
- fputs(" encrypt", stream);
- break;
- case CSSM_ACL_AUTHORIZATION_DECRYPT:
- fputs(" decrypt", stream);
- break;
- case CSSM_ACL_AUTHORIZATION_MAC:
- fputs(" mac", stream);
- break;
- case CSSM_ACL_AUTHORIZATION_DERIVE:
- fputs(" derive", stream);
- break;
- case CSSM_ACL_AUTHORIZATION_DBS_CREATE:
- fputs(" dbs_create", stream);
- break;
- case CSSM_ACL_AUTHORIZATION_DBS_DELETE:
- fputs(" dbs_delete", stream);
- break;
- case CSSM_ACL_AUTHORIZATION_DB_READ:
- fputs(" db_read", stream);
- break;
- case CSSM_ACL_AUTHORIZATION_DB_INSERT:
- fputs(" db_insert", stream);
- break;
- case CSSM_ACL_AUTHORIZATION_DB_MODIFY:
- fputs(" db_modify", stream);
- break;
- case CSSM_ACL_AUTHORIZATION_DB_DELETE:
- fputs(" db_delete", stream);
- break;
- case CSSM_ACL_AUTHORIZATION_CHANGE_ACL:
- fputs(" change_acl", stream);
- break;
- case CSSM_ACL_AUTHORIZATION_CHANGE_OWNER:
- fputs(" change_owner", stream);
- break;
- case CSSM_ACL_AUTHORIZATION_INTEGRITY:
- fputs(" integrity", stream);
- break;
- case CSSM_ACL_AUTHORIZATION_PARTITION_ID:
- fputs(" partition_id", stream);
- printPartitionIDList = true;
- break;
- default:
- fprintf(stream, " tag=%lu", (unsigned long)tag);
- break;
- }
- }
- fputc('\n', stream);
-
- status = SecACLCopySimpleContents(acl, &applicationList, &description, &promptSelector);
- if (status)
- {
- sec_perror("SecACLCopySimpleContents", status);
- continue;
- }
-
- if (promptSelector.flags & CSSM_ACL_KEYCHAIN_PROMPT_REQUIRE_PASSPHRASE)
- fputs(" require-password\n", stream);
- else
- fputs(" don't-require-password\n", stream);
-
- fputs(" description: ", stream);
- // special case for Partition IDs
- if(printPartitionIDList) {
- print_partition_id_list(stream, description);
- } else {
- print_cfstring(stream, description);
- }
- fputc('\n', stream);
-
- if (applicationList)
- {
- appCount = CFArrayGetCount(applicationList);
- fprintf(stream, " applications (%lu):\n", appCount);
- }
- else
- {
- appCount = 0;
- fprintf(stream, " applications: <null>\n");
- }
-
- for (appix = 0; appix < appCount; ++appix)
- {
- const UInt8* bytes;
- SecTrustedApplicationRef app = (SecTrustedApplicationRef)CFArrayGetValueAtIndex(applicationList, appix);
- CFDataRef data = NULL;
- fprintf(stream, " %lu: ", appix);
- status = SecTrustedApplicationCopyData(app, &data);
- if (status)
- {
- sec_perror("SecTrustedApplicationCopyData", status);
- continue;
- }
-
- bytes = CFDataGetBytePtr(data);
- if (bytes && bytes[0] == 0x2f) {
- fprintf(stream, "%s", (const char *)bytes);
- if ((status = SecTrustedApplicationValidateWithPath(app, (const char *)bytes)) == noErr) {
- fprintf(stream, " (OK)");
- } else {
- fprintf(stream, " (status %d)", (int)status);
- }
- fprintf(stream, "\n");
- } else {
- print_cfdata(stream, data);
- fputc('\n', stream);
- }
- if (data)
- CFRelease(data);
- }
-
- if (applicationList)
- CFRelease(applicationList);
-
- if (description)
- CFRelease(description);
-
- if (interactive)
- {
- char buffer[10] = {};
- fprintf(stderr, "Remove this acl? ");
- if (readline(buffer, sizeof(buffer)) && buffer[0] == 'y')
- {
- fprintf(stderr, "removing acl\n");
- status = SecACLRemove(acl);
- if (status)
- {
- sec_perror("SecACLRemove", status);
- continue;
- }
- }
- }
- }
-
-loser:
- if (aclList)
- CFRelease(aclList);
-
- return result;
-}
-
-int
-print_keychain_item_attributes(FILE *stream, SecKeychainItemRef item, Boolean show_data, Boolean show_raw_data, Boolean show_acl, Boolean interactive)
-{
- int result = 0;
- unsigned int ix;
- OSStatus status;
- SecKeychainRef keychain = NULL;
- SecAccessRef access = NULL;
- SecItemClass itemClass = 0;
- UInt32 itemID;
- SecKeychainAttributeList *attrList = NULL;
- SecKeychainAttributeInfo *info = NULL;
- UInt32 length = 0;
- void *data = NULL;
-
- status = SecKeychainItemCopyKeychain(item, &keychain);
- if (status)
- {
- sec_perror("SecKeychainItemCopyKeychain", status);
- result = 1;
- goto loser;
- }
-
- fputs("keychain: ", stream);
- result = print_keychain_name(stream, keychain);
- fputc('\n', stream);
- if (result)
- goto loser;
- fputs("version: ", stream);
- result = print_keychain_version(stream, keychain);
- fputc('\n', stream);
- if (result)
- goto loser;
-
- /* First find out the item class. */
- status = SecKeychainItemCopyAttributesAndData(item, NULL, &itemClass, NULL, NULL, NULL);
- if (status)
- {
- sec_perror("SecKeychainItemCopyAttributesAndData", status);
- result = 1;
- goto loser;
- }
-
- fputs("class: ", stream);
- char buffer[4];
- buffer[3] = itemClass & 0xFF;
- buffer[2] = (itemClass >> 8) & 0xFF;
- buffer[1] = (itemClass >> 16) & 0xFF;
- buffer[0] = (itemClass >> 24) & 0xFF;
-
- print_buffer(stream, 4, buffer);
- fputs("\nattributes:\n", stream);
-
- switch (itemClass)
- {
- case kSecInternetPasswordItemClass:
- itemID = CSSM_DL_DB_RECORD_INTERNET_PASSWORD;
- break;
- case kSecGenericPasswordItemClass:
- itemID = CSSM_DL_DB_RECORD_GENERIC_PASSWORD;
- break;
- case 'ashp': /* kSecAppleSharePasswordItemClass */
- itemID = CSSM_DL_DB_RECORD_APPLESHARE_PASSWORD;
- break;
- default:
- itemID = itemClass;
- break;
- }
-
- /* Now get the AttributeInfo for it. */
- status = SecKeychainAttributeInfoForItemID(keychain, itemID, &info);
- if (status)
- {
- sec_perror("SecKeychainAttributeInfoForItemID", status);
- result = 1;
- goto loser;
- }
-
- status = SecKeychainItemCopyAttributesAndData(item, info, &itemClass, &attrList,
- show_data ? &length : NULL,
- show_data ? &data : NULL);
- if (status)
- {
- sec_perror("SecKeychainItemCopyAttributesAndData", status);
- result = 1;
- goto loser;
- }
-
- if (info->count != attrList->count)
- {
- sec_error("info count: %ld != attribute count: %ld", info->count, attrList->count);
- result = 1;
- goto loser;
- }
-
- for (ix = 0; ix < info->count; ++ix)
- {
- UInt32 tag = info->tag[ix];
- UInt32 format = info->format[ix];
- SecKeychainAttribute *attribute = &attrList->attr[ix];
- if (tag != attribute->tag)
- {
- sec_error("attribute %d of %ld info tag: %ld != attribute tag: %ld", ix, info->count, tag, attribute->tag);
- result = 1;
- goto loser;
- }
-
- fputs(" ", stream);
- print_uint32(stream, tag);
- switch (format)
- {
- case CSSM_DB_ATTRIBUTE_FORMAT_STRING:
- fputs("<string>", stream);
- break;
- case CSSM_DB_ATTRIBUTE_FORMAT_SINT32:
- fputs("<sint32>", stream);
- break;
- case CSSM_DB_ATTRIBUTE_FORMAT_UINT32:
- fputs("<uint32>", stream);
- break;
- case CSSM_DB_ATTRIBUTE_FORMAT_BIG_NUM:
- fputs("<bignum>", stream);
- break;
- case CSSM_DB_ATTRIBUTE_FORMAT_REAL:
- fputs("<real>", stream);
- break;
- case CSSM_DB_ATTRIBUTE_FORMAT_TIME_DATE:
- fputs("<timedate>", stream);
- break;
- case CSSM_DB_ATTRIBUTE_FORMAT_BLOB:
- fputs("<blob>", stream);
- break;
- case CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32:
- fputs("<uint32>", stream);
- break;
- case CSSM_DB_ATTRIBUTE_FORMAT_COMPLEX:
- fputs("<complex>", stream);
- break;
- default:
- fprintf(stream, "<format: %d>", (int)format);
- break;
- }
- fputs("=", stream);
- if (!attribute->length && !attribute->data)
- fputs("<NULL>", stream);
- else
- { switch (format)
- {
- case CSSM_DB_ATTRIBUTE_FORMAT_SINT32:
- case CSSM_DB_ATTRIBUTE_FORMAT_UINT32:
- {
- print_uint32(stream, *(UInt32*) attribute->data);
- break;
- }
-
- case CSSM_DB_ATTRIBUTE_FORMAT_MULTI_UINT32:
- {
- int n = attribute->length / sizeof(UInt32);
- UInt32* ptr = (UInt32*) attribute->data;
-
- while (n--)
- {
- print_uint32(stream, *ptr++);
- }
- }
- break;
-
- default:
- {
- print_buffer(stream, attribute->length, attribute->data);
- }
- break;
- }
- }
- fputc('\n', stream);
- }
-
- if (show_data)
- {
- fputs("data:\n", stream);
- print_buffer(stream, length, data);
- fputc('\n', stream);
- }
-
- if (show_raw_data)
- {
- CSSM_DL_DB_HANDLE dldbHandle = {};
- const CSSM_DB_UNIQUE_RECORD *uniqueRecordID = NULL;
- CSSM_DATA data = {};
- status = SecKeychainItemGetDLDBHandle(item, &dldbHandle);
- if (status)
- {
- sec_perror("SecKeychainItemGetDLDBHandle", status);
- result = 1;
- goto loser;
- }
-
- status = SecKeychainItemGetUniqueRecordID(item, &uniqueRecordID);
- if (status)
- {
- sec_perror("SecKeychainItemGetUniqueRecordID", status);
- result = 1;
- goto loser;
- }
-
- status = CSSM_DL_DataGetFromUniqueRecordId(dldbHandle, uniqueRecordID, NULL, &data);
- if (status)
- {
- sec_perror("CSSM_DL_DataGetFromUniqueRecordId", status);
- result = 1;
- goto loser;
- }
-
- fputs("raw data:\n", stream);
- print_buffer(stream, data.Length, data.Data);
- fputc('\n', stream);
-
- /* @@@ Hmm which allocators should we use here? */
- free(data.Data);
- }
-
- if (show_acl)
- {
- status = SecKeychainItemCopyAccess(item, &access);
- if (status == errSecNoAccessForItem)
- fprintf(stream, "no access control for this item\n");
- else
- {
- if (status)
- {
- sec_perror("SecKeychainItemCopyAccess", status);
- result = 1;
- goto loser;
- }
-
- result = print_access(stream, access, interactive);
- if (result)
- goto loser;
-
- if (interactive)
- {
- char buffer[10] = {};
- fprintf(stderr, "Update access? ");
- if (readline(buffer, sizeof(buffer)) && buffer[0] == 'y')
- {
- fprintf(stderr, "Updating access\n");
- status = SecKeychainItemSetAccess(item, access);
- if (status)
- {
- sec_perror("SecKeychainItemSetAccess", status);
- result = 1;
- goto loser;
- }
- }
- }
- }
- }
-
-loser:
- if (access)
- CFRelease(access);
-
- if (attrList)
- {
- status = SecKeychainItemFreeAttributesAndData(attrList, data);
- if (status)
- sec_perror("SecKeychainItemFreeAttributesAndData", status);
- }
-
- if (info)
- {
- status = SecKeychainFreeAttributeInfo(info);
- if (status)
- sec_perror("SecKeychainFreeAttributeInfo", status);
- }
-
- if (keychain)
- CFRelease(keychain);
-
- return result;
-}
-
-static void
-print_buffer_hex(FILE *stream, size_t length, const void *data)
-{
- uint8 *p = (uint8 *) data;
- while (length--)
- {
- int ch = *p++;
- fprintf(stream, "%02X", ch);
- }
-}
-
-static void
-print_buffer_ascii(FILE *stream, size_t length, const void *data)
-{
- uint8 *p = (uint8 *) data;
- while (length--)
- {
- int ch = *p++;
- if (ch >= ' ' && ch <= '~' && ch != '\\')
- {
- fputc(ch, stream);
- }
- else
- {
- fputc('\\', stream);
- fputc('0' + ((ch >> 6) & 7), stream);
- fputc('0' + ((ch >> 3) & 7), stream);
- fputc('0' + ((ch >> 0) & 7), stream);
- }
- }
-}
-
-void
-print_buffer(FILE *stream, size_t length, const void *data)
-{
- uint8 *p = (uint8 *) data;
- Boolean hex = FALSE;
- Boolean ascii = FALSE;
- UInt32 ix;
- for (ix = 0; ix < length; ++ix)
- {
- int ch = *p++;
- if (ch >= ' ' && ch <= '~' && ch != '\\')
- ascii = TRUE;
- else
- hex = TRUE;
- }
-
- if (hex)
- {
- fputc('0', stream);
- fputc('x', stream);
- print_buffer_hex(stream, length, data);
- if (ascii)
- fputc(' ', stream);
- fputc(' ', stream);
- }
- if (ascii)
- {
- fputc('"', stream);
- print_buffer_ascii(stream, length, data);
- fputc('"', stream);
- }
-}
-
-void
-print_uint32(FILE *stream, uint32 n)
-{
- n = OSSwapHostToBigInt32 (n);
- print_buffer(stream, sizeof(UInt32), &n);
-}
-
-unsigned char
-hexValue(char c)
-{
- static const char digits[] = "0123456789abcdef";
- char *p;
- if ((p = strchr(digits, tolower(c))))
- return p - digits;
- else
- return 0;
-}
-
-void
-fromHex(const char *hexDigits, CSSM_DATA *data)
-{
- size_t bytes = strlen(hexDigits) / 2; // (discards malformed odd end)
- if (bytes > data->Length)
- return;
- // length(bytes); // (will assert if we try to grow it)
- size_t n;
- for (n = 0; n < bytes; n++) {
- data->Data[n] = (uint8)(hexValue(hexDigits[2*n]) << 4 | hexValue(hexDigits[2*n+1]));
- }
-}
-
-CFDataRef CF_RETURNS_RETAINED
-cfFromHex(CFStringRef hex) {
- // behavior is undefined if you pass in a non-hex string. Don't do that.
- char* chex;
- size_t len;
-
- GetCStringFromCFString(hex, &chex, &len);
- if(len == 0) {
- return NULL;
- }
-
- size_t bytes = len/2;
- CFMutableDataRef bin = CFDataCreateMutable(kCFAllocatorDefault, bytes);
- CFDataIncreaseLength(bin, bytes);
-
- if(!bin || (size_t) CFDataGetLength(bin) != bytes) {
- CFReleaseNull(bin);
- return NULL;
- }
-
- UInt8* data = CFDataGetMutableBytePtr(bin);
- for(size_t i = 0; i < bytes; i++) {
- data[i] = (uint8)(hexValue(chex[2*i]) << 4 | hexValue(chex[2*i+1]));
- }
-
- return bin;
-}
-
-CFStringRef CF_RETURNS_RETAINED cfToHex(CFDataRef bin) {
- size_t len = CFDataGetLength(bin) * 2;
- CFMutableStringRef str = CFStringCreateMutable(NULL, len);
-
- static const char* digits[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
-
- const uint8_t* data = CFDataGetBytePtr(bin);
- for (CFIndex i = 0; i < CFDataGetLength(bin); i++) {
- CFStringAppendCString(str, digits[data[i] >> 4], 1);
- CFStringAppendCString(str, digits[data[i] & 0xf], 1);
- }
- return str;
-}
-
-void
-safe_CFRelease(void *cfTypeRefPtr)
-{
- CFTypeRef *obj = (CFTypeRef *)cfTypeRefPtr;
- if (obj && *obj) {
- CFRelease(*obj);
- *obj = NULL;
- }
-}
-
-
-void
-GetCStringFromCFString(CFStringRef cfstring, char** cstr, size_t* len) {
- CFIndex strLen = CFStringGetLength(cfstring);
- CFIndex bufLen = 1 + CFStringGetMaximumSizeForEncoding(strLen, kCFStringEncodingUTF8);
- *cstr = (char *)malloc(bufLen);
- if (!CFStringGetCString(cfstring, *cstr, bufLen-1, kCFStringEncodingUTF8)) {
- (*cstr)[0]=0;
- }
- // Handle non-8-bit characters.
- *len = strnlen(*cstr, strLen);
-}
-
-CFDictionaryRef CF_RETURNS_RETAINED makeCFDictionaryFromData(CFDataRef data)
-{
- if (data) {
- CFPropertyListRef plist = CFPropertyListCreateFromXMLData(NULL, data, kCFPropertyListImmutable, NULL);
- if (plist && CFGetTypeID(plist) != CFDictionaryGetTypeID()) {
- safe_CFRelease(&plist);
- return NULL;
- }
- return (CFDictionaryRef) plist;
- } else {
- return NULL;
- }
-}
-
-void print_partition_id_list(FILE* stream, CFStringRef description) {
- CFDataRef binary = NULL;
- CFDictionaryRef partitionList = NULL;
- CFArrayRef partitionIDs = NULL;
-
- if(!description) {
- goto error;
- }
- binary = cfFromHex(description);
- if(!binary) {
- goto error;
- }
- partitionList = makeCFDictionaryFromData(binary);
- if(!partitionList) {
- goto error;
- }
-
- partitionIDs = CFDictionaryGetValue(partitionList, CFSTR("Partitions"));
- if(!partitionIDs) {
- goto error;
- }
-
- for(CFIndex i = 0; i < CFArrayGetCount(partitionIDs); i++) {
- CFStringRef s = CFArrayGetValueAtIndex(partitionIDs, i);
- if(!s) {
- goto error;
- }
-
- if(i != 0) {
- fprintf(stream, ", ");
- }
- print_cfstring(stream, s);
- }
-
- goto cleanup;
-error:
- fprintf(stream, "invalid partition ID: ");
- print_cfstring(stream, description);
-cleanup:
- // don't release partitionIDs; it's an element of partitionList
- safe_CFRelease(&binary);
- safe_CFRelease(&partitionList);
-
- return;
-}
-
-/*
- * map a 6-bit binary value to a printable character.
- */
-static const
-unsigned char bintoasc[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-/*
- * map 6 bits to a printing char
- */
-#define ENC(c) (bintoasc[((c) & 0x3f)])
-
-#define PAD '='
-
-/*
- * map one group of up to 3 bytes at inp to 4 bytes at outp.
- * Count is number of valid bytes in *inp; if less than 3, the
- * 1 or two extras must be zeros.
- */
-static void
-encChunk(const unsigned char *inp,
- unsigned char *outp,
- size_t count)
-{
- unsigned char c1, c2, c3, c4;
-
- c1 = *inp >> 2;
- c2 = ((inp[0] << 4) & 0x30) | ((inp[1] >> 4) & 0xf);
- c3 = ((inp[1] << 2) & 0x3c) | ((inp[2] >> 6) & 0x3);
- c4 = inp[2] & 0x3f;
- *outp++ = ENC(c1);
- *outp++ = ENC(c2);
- if (count == 1) {
- *outp++ = PAD;
- *outp = PAD;
- } else {
- *outp++ = ENC(c3);
- if (count == 2) {
- *outp = PAD;
- }
- else {
- *outp = ENC(c4);
- }
- }
-}
-
-static unsigned char *
-malloc_enc64_with_lines(const unsigned char *inbuf,
- size_t inlen,
- size_t linelen,
- unsigned *outlen)
-{
- unsigned outTextLen;
- unsigned len; // to malloc, liberal
- unsigned olen = 0; // actual output size
- unsigned char *outbuf;
- unsigned char endbuf[3];
- unsigned i;
- unsigned char *outp;
- unsigned numLines;
- unsigned thisLine;
-
- outTextLen = ((((unsigned)inlen) + 2) / 3) * 4;
- if(linelen) {
- /*
- * linelen must be 0 mod 4 for this to work; round up...
- */
- if((linelen & 0x03) != 0) {
- linelen = (linelen + 3) & 0xfffffffc;
- }
- numLines = (outTextLen + ((unsigned)linelen) - 1)/ linelen;
- }
- else {
- numLines = 1;
- }
-
- /*
- * Total output size = encoded text size plus one newline per
- * line of output, plus trailing NULL. We always generate newlines
- * as \n; when decoding, we tolerate \r\n (Microsoft) or \n.
- */
- len = outTextLen + (2 * numLines) + 1;
- outbuf = (unsigned char*)malloc(len);
- outp = outbuf;
- thisLine = 0;
-
- while(inlen) {
- if(inlen < 3) {
- for(i=0; i<3; i++) {
- if(i < inlen) {
- endbuf[i] = inbuf[i];
- }
- else {
- endbuf[i] = 0;
- }
- }
- encChunk(endbuf, outp, inlen);
- inlen = 0;
- }
- else {
- encChunk(inbuf, outp, 3);
- inlen -= 3;
- inbuf += 3;
- }
- outp += 4;
- thisLine += 4;
- olen += 4;
- if((linelen != 0) && (thisLine >= linelen) && inlen) {
- /*
- * last trailing newline added below
- * Note we don't split 4-byte output chunks over newlines
- */
- *outp++ = '\n';
- olen++;
- thisLine = 0;
- }
- }
- *outp++ = '\n';
- olen += 1;
- *outlen = olen;
- return outbuf;
-}
-
-void
-print_buffer_pem(FILE *stream, const char *headerString, size_t length, const void *data)
-{
- unsigned char *buf;
- unsigned bufLen;
-
- if (headerString)
- fprintf(stream, "-----BEGIN %s-----\n", headerString);
- buf = malloc_enc64_with_lines(data, length, 64, &bufLen);
- fwrite(buf, bufLen, 1, stream);
- free(buf);
- if (headerString)
- fprintf(stream, "-----END %s-----\n", headerString);
-}
-
-char*
-prompt_password(const char* keychainName) {
- const char *fmt = "password to unlock %s: ";
- const char *name = keychainName ? keychainName : "default";
- char *prompt = malloc(strlen(fmt) + strlen(name));
- sprintf(prompt, fmt, name);
- char *password = getpass(prompt);
- free(prompt);
- return password;
-}