1/* 2 * Copyright (c) 2006-2010 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24/* 25 * SecFramework.c - generic non API class specific functions 26 */ 27 28 29#include "SecFrameworkP.h" 30#include <pthread.h> 31#include <CoreFoundation/CFBundle.h> 32#include <CoreFoundation/CFURLAccess.h> 33#if 0 34#include "SecRandomP.h" 35#endif 36#include <CommonCrypto/CommonDigest.h> 37#include <Security/SecAsn1Coder.h> 38#include <Security/oidsalg.h> 39#include <fcntl.h> 40#include <sys/types.h> 41#include <unistd.h> 42#include <errno.h> 43#include <dlfcn.h> 44#include <string.h> 45#include <CoreFoundation/CFBundlePriv.h> 46 47#include <utilities/debugging.h> 48 49/* Security.framework's bundle id. */ 50static CFStringRef kSecFrameworkBundleID = CFSTR("com.apple.Security"); 51 52/* Security framework's own bundle used for localized string lookups. */ 53static CFBundleRef kSecFrameworkBundle; 54static pthread_once_t kSecFrameworkBundleLookup = PTHREAD_ONCE_INIT; 55 56#if 0 57// copied from SecAsn1Coder.c 58 59bool SecAsn1OidCompare(const SecAsn1Oid *oid1, const SecAsn1Oid *oid2) { 60 if (!oid1 || !oid2) 61 return oid1 == oid2; 62 if (oid1->Length != oid2->Length) 63 return false; 64 return !memcmp(oid1->Data, oid2->Data, oid1->Length); 65} 66#endif 67 68static void SecFrameworkBundleLookup(void) { 69 // figure out the path to our executable 70 Dl_info info; 71 dladdr("", &info); 72 73 // make a file URL from the returned string 74 CFURLRef urlRef = CFURLCreateFromFileSystemRepresentation(NULL, (const UInt8*) info.dli_fname, strlen(info.dli_fname), false); 75 kSecFrameworkBundle = _CFBundleCreateWithExecutableURLIfLooksLikeBundle(NULL, urlRef); 76 CFRelease(urlRef); 77 78 if (kSecFrameworkBundle) 79 CFRetain(kSecFrameworkBundle); 80} 81 82CFStringRef SecFrameworkCopyLocalizedString(CFStringRef key, 83 CFStringRef tableName) { 84 pthread_once(&kSecFrameworkBundleLookup, SecFrameworkBundleLookup); 85 if (kSecFrameworkBundle) { 86 return CFBundleCopyLocalizedString(kSecFrameworkBundle, key, key, 87 tableName); 88 } 89 90 CFRetain(key); 91 return key; 92} 93 94CFURLRef SecFrameworkCopyResourceURL(CFStringRef resourceName, 95 CFStringRef resourceType, CFStringRef subDirName) { 96 CFURLRef url = NULL; 97 pthread_once(&kSecFrameworkBundleLookup, SecFrameworkBundleLookup); 98 if (kSecFrameworkBundle) { 99 url = CFBundleCopyResourceURL(kSecFrameworkBundle, resourceName, 100 resourceType, subDirName); 101 if (!url) { 102 secdebug("SecFramework", "resource: %@.%@ in %@ not found", resourceName, 103 resourceType, subDirName); 104 } 105 } 106 107 return url; 108} 109 110 111CFDataRef SecFrameworkCopyResourceContents(CFStringRef resourceName, 112 CFStringRef resourceType, CFStringRef subDirName) { 113 CFURLRef url = SecFrameworkCopyResourceURL(resourceName, resourceType, 114 subDirName); 115 CFDataRef data = NULL; 116 if (url) { 117 SInt32 error; 118 if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, 119 url, &data, NULL, NULL, &error)) { 120 secdebug("SecFramework", "read: %d", (int)error); 121 } 122 CFRelease(url); 123 } 124 125 return data; 126} 127 128/* Return the SHA1 digest of a chunk of data as newly allocated CFDataRef. */ 129CFDataRef SecSHA1DigestCreate(CFAllocatorRef allocator, 130 const UInt8 *data, CFIndex length) { 131 CFMutableDataRef digest = CFDataCreateMutable(allocator, 132 CC_SHA1_DIGEST_LENGTH); 133 CFDataSetLength(digest, CC_SHA1_DIGEST_LENGTH); 134 CC_SHA1(data, (CC_LONG)length, CFDataGetMutableBytePtr(digest)); 135 return digest; 136} 137 138#if 0 139CFDataRef SecDigestCreate(CFAllocatorRef allocator, 140 const SecAsn1Oid *algorithm, const SecAsn1Item *params, 141 const UInt8 *data, CFIndex length) { 142 unsigned char *(*digestFcn)(const void *data, CC_LONG len, unsigned char *md); 143 CFIndex digestLen; 144 145 if (SecAsn1OidCompare(algorithm, &CSSMOID_SHA1)) { 146 digestFcn = CC_SHA1; 147 digestLen = CC_SHA1_DIGEST_LENGTH; 148 } else if (SecAsn1OidCompare(algorithm, &CSSMOID_SHA224)) { 149 digestFcn = CC_SHA224; 150 digestLen = CC_SHA224_DIGEST_LENGTH; 151 } else if (SecAsn1OidCompare(algorithm, &CSSMOID_SHA256)) { 152 digestFcn = CC_SHA256; 153 digestLen = CC_SHA256_DIGEST_LENGTH; 154 } else if (SecAsn1OidCompare(algorithm, &CSSMOID_SHA384)) { 155 digestFcn = CC_SHA384; 156 digestLen = CC_SHA384_DIGEST_LENGTH; 157 } else if (SecAsn1OidCompare(algorithm, &CSSMOID_SHA512)) { 158 digestFcn = CC_SHA512; 159 digestLen = CC_SHA512_DIGEST_LENGTH; 160 } else { 161 return NULL; 162 } 163 164 CFMutableDataRef digest = CFDataCreateMutable(allocator, digestLen); 165 CFDataSetLength(digest, digestLen); 166 digestFcn(data, length, CFDataGetMutableBytePtr(digest)); 167 return digest; 168} 169#endif 170 171#if 0 172 173/* Default random ref for /dev/random. */ 174const SecRandomRef kSecRandomDefault = NULL; 175 176/* File descriptor for "/dev/random". */ 177static int kSecRandomFD; 178static pthread_once_t kSecDevRandomOpen = PTHREAD_ONCE_INIT; 179 180static void SecDevRandomOpen(void) { 181 kSecRandomFD = open("/dev/random", O_RDONLY); 182} 183 184int SecRandomCopyBytes(SecRandomRef rnd, size_t count, uint8_t *bytes) { 185 if (rnd != kSecRandomDefault) 186 return errSecParam; 187 pthread_once(&kSecDevRandomOpen, SecDevRandomOpen); 188 if (kSecRandomFD < 0) 189 return -1; 190 while (count) { 191 ssize_t bytes_read = read(kSecRandomFD, bytes, count); 192 if (bytes_read == -1) { 193 if (errno == EINTR) 194 continue; 195 return -1; 196 } 197 if (bytes_read == 0) { 198 return -1; 199 } 200 count -= bytes_read; 201 } 202 203 return 0; 204} 205 206#include <CommonCrypto/CommonDigest.h> 207#include <stdlib.h> 208 209/* FIPS rng declarations. */ 210typedef struct __SecRandom *SecRandomRef; 211SecRandomRef SecRandomCreate(CFIndex randomAlg, CFIndex seedLength, 212 const UInt8 *seed); 213void SecRandomCopyBytes(SecRandomRef randomref, CFIndex numBytes, UInt8 *outBytes); 214 215/* FIPS Rng implementation. */ 216struct __SecRandom { 217 CC_SHA1_CTX sha1; 218 CFIndex bytesLeft; 219 UInt8 block[64]; 220}; 221 222SecRandomRef SecRandomCreate(CFIndex randomAlg, CFIndex seedLength, 223 const UInt8 *seed) { 224 SecRandomRef result = (SecRandomRef)malloc(sizeof(struct __SecRandom)); 225 CC_SHA1_Init(&result->sha1); 226 memset(result->block + 20, 0, 44); 227 result->bytesLeft = 0; 228 229 if (seedLength) { 230 /* Digest the seed and put it into output. */ 231 CC_SHA1(seed, seedLength, result->block); 232 } else { 233 /* Seed 20 bytes from "/dev/srandom". */ 234 int fd = open("/dev/srandom", O_RDONLY); 235 if (fd < 0) 236 goto errOut; 237 238 if (read(fd, result->block, 20) != 20) 239 goto errOut; 240 241 close(fd); 242 } 243 244 CC_SHA1_Update(&result->sha1, result->block, 64); 245 246 return result; 247 248errOut: 249 free(result); 250 return NULL; 251} 252 253void SecRandomCopyBytes(SecRandomRef randomref, CFIndex numBytes, 254 UInt8 *outBytes) { 255 while (numBytes > 0) { 256 if (!randomref->bytesLeft) { 257 CC_SHA1_Update(&randomref->sha1, randomref->block, 64); 258 OSWriteBigInt32(randomref->block, 0, randomref->sha1.h0); 259 OSWriteBigInt32(randomref->block, 4, randomref->sha1.h1); 260 OSWriteBigInt32(randomref->block, 8, randomref->sha1.h2); 261 OSWriteBigInt32(randomref->block, 12, randomref->sha1.h3); 262 OSWriteBigInt32(randomref->block, 16, randomref->sha1.h4); 263 randomref->bytesLeft = 20; 264 } 265 CFIndex outLength = (numBytes > randomref->bytesLeft ? 266 randomref->bytesLeft : numBytes); 267 memcpy(outBytes, randomref->block + 20 - randomref->bytesLeft, 268 outLength); 269 randomref->bytesLeft -= outLength; 270 outBytes += outLength; 271 numBytes -= outLength; 272 } 273} 274#endif 275