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#ifdef STANDALONE 29/* Allows us to build genanchors against the BaseSDK. */ 30#undef __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ 31#undef __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ 32#endif 33 34#include "SecFramework.h" 35#include <pthread.h> 36#include <CoreFoundation/CFBundle.h> 37#include <CoreFoundation/CFURLAccess.h> 38#include <Security/SecRandom.h> 39#include <CommonCrypto/CommonDigest.h> 40#include <CommonCrypto/CommonDigestSPI.h> 41#include <Security/SecAsn1Coder.h> 42#include <Security/oidsalg.h> 43#include <fcntl.h> 44#include <sys/types.h> 45#include <unistd.h> 46#include <utilities/debugging.h> 47#include <Security/SecBase.h> 48#include <errno.h> 49#include <inttypes.h> 50 51/* Security.framework's bundle id. */ 52static CFStringRef kSecFrameworkBundleID = CFSTR("com.apple.Security"); 53 54/* Security framework's own bundle used for localized string lookups. */ 55static CFBundleRef kSecFrameworkBundle; 56static pthread_once_t kSecFrameworkBundleLookup = PTHREAD_ONCE_INIT; 57 58static void SecFrameworkBundleLookup(void) { 59 kSecFrameworkBundle = CFBundleGetBundleWithIdentifier(kSecFrameworkBundleID); 60 if (kSecFrameworkBundle) 61 CFRetain(kSecFrameworkBundle); 62} 63 64CFStringRef SecFrameworkCopyLocalizedString(CFStringRef key, 65 CFStringRef tableName) { 66 pthread_once(&kSecFrameworkBundleLookup, SecFrameworkBundleLookup); 67 if (kSecFrameworkBundle) { 68 return CFBundleCopyLocalizedString(kSecFrameworkBundle, key, key, 69 tableName); 70 } 71 72 CFRetain(key); 73 return key; 74} 75 76CFURLRef SecFrameworkCopyResourceURL(CFStringRef resourceName, 77 CFStringRef resourceType, CFStringRef subDirName) { 78 CFURLRef url = NULL; 79 pthread_once(&kSecFrameworkBundleLookup, SecFrameworkBundleLookup); 80 if (kSecFrameworkBundle) { 81 url = CFBundleCopyResourceURL(kSecFrameworkBundle, resourceName, 82 resourceType, subDirName); 83 if (!url) { 84 secwarning("resource: %@.%@ in %@ not found", resourceName, 85 resourceType, subDirName); 86 } 87 } 88 89 return url; 90} 91 92 93CFDataRef SecFrameworkCopyResourceContents(CFStringRef resourceName, 94 CFStringRef resourceType, CFStringRef subDirName) { 95 CFURLRef url = SecFrameworkCopyResourceURL(resourceName, resourceType, 96 subDirName); 97 CFDataRef data = NULL; 98 if (url) { 99 SInt32 error; 100 if (!CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, 101 url, &data, NULL, NULL, &error)) { 102 secwarning("read: %ld", (long) error); 103 } 104 CFRelease(url); 105 } 106 107 return data; 108} 109 110/* Return the SHA1 digest of a chunk of data as newly allocated CFDataRef. */ 111CFDataRef SecSHA1DigestCreate(CFAllocatorRef allocator, 112 const UInt8 *data, CFIndex length) { 113 CFMutableDataRef digest = CFDataCreateMutable(allocator, 114 CC_SHA1_DIGEST_LENGTH); 115 CFDataSetLength(digest, CC_SHA1_DIGEST_LENGTH); 116 //FIXME: Cast from CFIndex to CC_LONG 117 CCDigest(kCCDigestSHA1, data, (CC_LONG)length, CFDataGetMutableBytePtr(digest)); 118 return digest; 119} 120 121CFDataRef SecDigestCreate(CFAllocatorRef allocator, 122 const SecAsn1Oid *algorithm, const SecAsn1Item *params, 123 const UInt8 *data, CFIndex length) { 124 unsigned char *(*digestFcn)(const void *data, CC_LONG len, unsigned char *md); 125 CFIndex digestLen; 126 127 if (SecAsn1OidCompare(algorithm, &CSSMOID_SHA1)) { 128 digestFcn = CC_SHA1; 129 digestLen = CC_SHA1_DIGEST_LENGTH; 130 } else if (SecAsn1OidCompare(algorithm, &CSSMOID_SHA224)) { 131 digestFcn = CC_SHA224; 132 digestLen = CC_SHA224_DIGEST_LENGTH; 133 } else if (SecAsn1OidCompare(algorithm, &CSSMOID_SHA256)) { 134 digestFcn = CC_SHA256; 135 digestLen = CC_SHA256_DIGEST_LENGTH; 136 } else if (SecAsn1OidCompare(algorithm, &CSSMOID_SHA384)) { 137 digestFcn = CC_SHA384; 138 digestLen = CC_SHA384_DIGEST_LENGTH; 139 } else if (SecAsn1OidCompare(algorithm, &CSSMOID_SHA512)) { 140 digestFcn = CC_SHA512; 141 digestLen = CC_SHA512_DIGEST_LENGTH; 142 } else { 143 return NULL; 144 } 145 146 CFMutableDataRef digest = CFDataCreateMutable(allocator, digestLen); 147 CFDataSetLength(digest, digestLen); 148 //FIXME: Cast from CFIndex to CC_LONG 149 digestFcn(data, (CC_LONG)length, CFDataGetMutableBytePtr(digest)); 150 return digest; 151} 152 153/* Default random ref for /dev/random. */ 154const SecRandomRef kSecRandomDefault = NULL; 155 156/* File descriptor for "/dev/random". */ 157static int kSecRandomFD; 158static pthread_once_t kSecDevRandomOpen = PTHREAD_ONCE_INIT; 159 160static void SecDevRandomOpen(void) { 161 kSecRandomFD = open("/dev/random", O_RDONLY); 162} 163 164int SecRandomCopyBytes(SecRandomRef rnd, size_t count, uint8_t *bytes) { 165 if (rnd != kSecRandomDefault) 166 return errSecParam; 167 pthread_once(&kSecDevRandomOpen, SecDevRandomOpen); 168 if (kSecRandomFD < 0) 169 return -1; 170 while (count) { 171 ssize_t bytes_read = read(kSecRandomFD, bytes, count); 172 if (bytes_read == -1) { 173 if (errno == EINTR) 174 continue; 175 return -1; 176 } 177 if (bytes_read == 0) { 178 return -1; 179 } 180 bytes += bytes_read; 181 count -= bytes_read; 182 } 183 184 return 0; 185} 186 187#if 0 188#include <CommonCrypto/CommonDigest.h> 189#include <stdlib.h> 190 191/* FIPS rng declarations. */ 192typedef struct __SecRandom *SecRandomRef; 193SecRandomRef SecRandomCreate(CFIndex randomAlg, CFIndex seedLength, 194 const UInt8 *seed); 195void SecRandomCopyBytes(SecRandomRef randomref, CFIndex numBytes, UInt8 *outBytes); 196 197/* FIPS Rng implementation. */ 198struct __SecRandom { 199 CC_SHA1_CTX sha1; 200 CFIndex bytesLeft; 201 UInt8 block[64]; 202}; 203 204SecRandomRef SecRandomCreate(CFIndex randomAlg, CFIndex seedLength, 205 const UInt8 *seed) { 206 SecRandomRef result = (SecRandomRef)malloc(sizeof(struct __SecRandom)); 207 CC_SHA1_Init(&result->sha1); 208 memset(result->block + 20, 0, 44); 209 result->bytesLeft = 0; 210 211 if (seedLength) { 212 /* Digest the seed and put it into output. */ 213 CCDigest(kCCDigestSHA1, seed, seedLength, result->block); 214 } else { 215 /* Seed 20 bytes from "/dev/srandom". */ 216 int fd = open("/dev/srandom", O_RDONLY); 217 if (fd < 0) 218 goto errOut; 219 220 if (read(fd, result->block, 20) != 20) 221 goto errOut; 222 223 close(fd); 224 } 225 226 CC_SHA1_Update(&result->sha1, result->block, 64); 227 228 return result; 229 230errOut: 231 free(result); 232 return NULL; 233} 234 235void SecRandomCopyBytes(SecRandomRef randomref, CFIndex numBytes, 236 UInt8 *outBytes) { 237 while (numBytes > 0) { 238 if (!randomref->bytesLeft) { 239 CC_SHA1_Update(&randomref->sha1, randomref->block, 64); 240 OSWriteBigInt32(randomref->block, 0, randomref->sha1.h0); 241 OSWriteBigInt32(randomref->block, 4, randomref->sha1.h1); 242 OSWriteBigInt32(randomref->block, 8, randomref->sha1.h2); 243 OSWriteBigInt32(randomref->block, 12, randomref->sha1.h3); 244 OSWriteBigInt32(randomref->block, 16, randomref->sha1.h4); 245 randomref->bytesLeft = 20; 246 } 247 CFIndex outLength = (numBytes > randomref->bytesLeft ? 248 randomref->bytesLeft : numBytes); 249 memcpy(outBytes, randomref->block + 20 - randomref->bytesLeft, 250 outLength); 251 randomref->bytesLeft -= outLength; 252 outBytes += outLength; 253 numBytes -= outLength; 254 } 255} 256#endif 257