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