1/*
2 * Copyright (c) 2009,2012-2014 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 * testcert.c
24 */
25
26#include <TargetConditionals.h>
27
28#if TARGET_OS_IPHONE
29
30#include <CoreFoundation/CoreFoundation.h>
31#include <Security/SecIdentityPriv.h>
32#include <Security/SecItem.h>
33#include <Security/SecCertificateRequest.h>
34#include <Security/SecInternal.h>
35#include <utilities/array_size.h>
36
37#include <AssertMacros.h>
38
39#include "testcert.h"
40
41static inline CF_RETURNS_RETAINED CFMutableArrayRef maa(CFMutableArrayRef array CF_CONSUMED, CFTypeRef a CF_CONSUMED) {
42	CFMutableArrayRef ma = array;
43	if (!ma)
44		ma = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
45	if (ma) {
46		CFArrayAppendValue(ma, a);
47	}
48    CFRelease(a);
49	return ma;
50}
51
52
53CF_RETURNS_RETAINED
54CFArrayRef test_cert_string_to_subject(CFStringRef subject)
55{
56	CFMutableArrayRef subject_array = NULL;
57	char buffer[1024];
58
59	if (!CFStringGetCString(subject, buffer, sizeof(buffer), kCFStringEncodingASCII))
60		goto out;
61
62	char *s = buffer, *e = NULL;
63	while ( (e = strchr(s, ',')) || (e = strchr(s, '\0')) ) {
64		if (s == e)
65			break;
66		if (*e && (*(e-1) == '\\'))
67			continue;
68		char *k;
69		while ((k = strchr(s, '=')) &&
70				(*(k-1) == '\\'));
71		if ( ((k - s) > 0) && ((e - k) > 1) ) {
72			CFStringRef key = CFStringCreateWithBytes(kCFAllocatorDefault, (uint8_t *)s, k - s, kCFStringEncodingASCII, false);
73			CFStringRef value = CFStringCreateWithBytes(kCFAllocatorDefault, (uint8_t *)k + 1, e - k - 1, kCFStringEncodingASCII, false);
74			subject_array = maa(subject_array, maa(NULL, maa(maa(NULL, key), value)));
75		}
76        if (*e == '\0')
77            break;
78		s = e + 1;
79	}
80
81out:
82	return subject_array;
83}
84
85
86static void test_cert_key_usage(CFMutableDictionaryRef extensions_dict, unsigned int key_usage)
87{
88	int key_usage_int = key_usage;
89	CFNumberRef key_usage_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &key_usage_int);
90	CFDictionarySetValue(extensions_dict, kSecCertificateKeyUsage, key_usage_num);
91	CFRelease(key_usage_num);
92}
93
94
95static void test_cert_path_length(CFMutableDictionaryRef extensions_dict, unsigned int path_length)
96{
97	int path_len_int = path_length;
98	CFNumberRef path_len_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &path_len_int);
99	CFDictionarySetValue(extensions_dict, kSecCSRBasicContraintsPathLen, path_len_num);
100	CFRelease(path_len_num);
101}
102
103
104SecIdentityRef test_cert_create_root_certificate(CFStringRef subject, SecKeyRef public_key, SecKeyRef private_key)
105{
106	SecCertificateRef ca_cert = NULL;
107	SecIdentityRef ca_identity = NULL;
108    CFMutableDictionaryRef extensions = NULL;
109
110	CFArrayRef ca_subject = NULL;
111	require(ca_subject = test_cert_string_to_subject(subject), out);
112	extensions = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
113	test_cert_key_usage(extensions, kSecKeyUsageKeyCertSign | kSecKeyUsageCRLSign);
114	test_cert_path_length(extensions, 0);
115	ca_cert = SecGenerateSelfSignedCertificate(ca_subject, extensions, public_key, private_key);
116	if (private_key && ca_cert)
117		ca_identity = SecIdentityCreate(kCFAllocatorDefault, ca_cert, private_key);
118
119out:
120	CFReleaseSafe(extensions);
121	CFReleaseSafe(ca_subject);
122	CFReleaseSafe(ca_cert);
123
124	return ca_identity;
125}
126
127SecCertificateRef test_cert_issue_certificate(SecIdentityRef ca_identity,
128	SecKeyRef public_key, CFStringRef subject,
129	unsigned int serial_no, unsigned int key_usage)
130{
131	SecCertificateRef cert = NULL;
132	CFArrayRef cert_subject = NULL;
133	CFDataRef serialno = NULL;
134	CFMutableDictionaryRef extensions = NULL;
135
136	unsigned int serial = htonl(serial_no);
137	unsigned int serial_length = sizeof(serial);
138	uint8_t *serial_non_zero = (uint8_t*)&serial;
139	while (!*serial_non_zero && serial_length)
140		{ serial_non_zero++; serial_length--; }
141    serialno = CFDataCreate(kCFAllocatorDefault,
142		serial_non_zero, serial_length);
143	require(cert_subject = test_cert_string_to_subject(subject), out);
144	//extensions = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
145	//require(extensions, out);
146	//test_cert_key_usage(extensions, key_usage);
147
148	cert = SecIdentitySignCertificate(ca_identity, serialno,
149	    public_key, cert_subject, NULL);
150
151out:
152	CFReleaseSafe(extensions);
153	CFReleaseSafe(cert_subject);
154	CFReleaseSafe(serialno);
155
156	return cert;
157}
158
159OSStatus
160test_cert_generate_key(uint32_t key_size_in_bits, CFTypeRef sec_attr_key_type,
161                       SecKeyRef *private_key, SecKeyRef *public_key)
162{
163	CFNumberRef key_size = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &key_size_in_bits);
164	const void *keygen_keys[] = { kSecAttrKeyType, kSecAttrKeySizeInBits };
165	const void *keygen_vals[] = { sec_attr_key_type, key_size };
166	CFDictionaryRef parameters = CFDictionaryCreate(kCFAllocatorDefault,
167                                                    keygen_keys, keygen_vals, array_size(keygen_vals),
168                                                    &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
169	CFRelease(key_size);
170
171	return SecKeyGeneratePair(parameters, public_key, private_key);
172}
173
174#endif /* TARGET_OS_IPHONE */
175