2 * Copyright (c) 2009-2010 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
27 * Created by Conrad Sauerwald on 1/9/09.
31 #include <TargetConditionals.h>
32 #if TARGET_OS_EMBEDDED
34 #include "SecurityCommands.h"
36 #include <CoreFoundation/CoreFoundation.h>
37 #include <AssertMacros.h>
38 #include <TargetConditionals.h>
39 #include <CFNetwork/CFNetwork.h>
41 extern const CFStringRef kCFStreamPropertySSLPeerTrust
;
42 #include <Security/SecTrust.h>
43 #include <Security/SecCertificate.h>
44 #include <Security/SecCertificatePriv.h>
45 #include <Security/SecImportExport.h>
46 #include <Security/SecPolicy.h>
47 #include <Security/SecIdentity.h>
48 #include <Security/SecIdentityPriv.h>
49 #include <Security/SecRSAKey.h>
50 #include <Security/SecSCEP.h>
51 #include <Security/SecCMS.h>
52 #include <Security/SecItem.h>
53 #include <Security/SecInternal.h>
54 #include <utilities/array_size.h>
59 //static char *scep_url = "https://localhost:2000/cgi-bin/pkiclient.exe";
60 static char *user
= "webuser";
61 static char *pass
= "webpassowrd";
66 unsigned char device_cert_der
[] = {
67 0x30, 0x82, 0x02, 0xdf, 0x30, 0x82, 0x02, 0x48, 0xa0, 0x03, 0x02, 0x01,
68 0x02, 0x02, 0x0a, 0x01, 0x5c, 0x0a, 0x2f, 0xfd, 0x20, 0x02, 0x00, 0xe6,
69 0x27, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
70 0x01, 0x0b, 0x05, 0x00, 0x30, 0x5a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
71 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06,
72 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20,
73 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04,
74 0x0b, 0x13, 0x0c, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x69, 0x50, 0x68,
75 0x6f, 0x6e, 0x65, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03,
76 0x13, 0x16, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x69, 0x50, 0x68, 0x6f,
77 0x6e, 0x65, 0x20, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x20, 0x43, 0x41,
78 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x38, 0x31, 0x32, 0x31, 0x32, 0x32, 0x33,
79 0x30, 0x33, 0x35, 0x36, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x31, 0x32, 0x31,
80 0x32, 0x32, 0x33, 0x30, 0x33, 0x35, 0x36, 0x5a, 0x30, 0x81, 0x87, 0x31,
81 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x28, 0x66, 0x31,
82 0x66, 0x35, 0x30, 0x66, 0x38, 0x31, 0x32, 0x32, 0x66, 0x62, 0x31, 0x30,
83 0x31, 0x34, 0x36, 0x66, 0x36, 0x35, 0x65, 0x39, 0x30, 0x33, 0x38, 0x30,
84 0x31, 0x37, 0x36, 0x33, 0x34, 0x32, 0x61, 0x64, 0x64, 0x36, 0x61, 0x38,
85 0x35, 0x63, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
86 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08,
87 0x13, 0x02, 0x43, 0x41, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04,
88 0x07, 0x13, 0x09, 0x43, 0x75, 0x70, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x6f,
89 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x41,
90 0x70, 0x70, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x0f, 0x30,
91 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x06, 0x69, 0x50, 0x68, 0x6f,
92 0x6e, 0x65, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
93 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00,
94 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xba, 0xc5, 0x2a, 0x7b, 0xb3,
95 0x29, 0x21, 0x8d, 0xbd, 0x01, 0x12, 0xff, 0x0b, 0xf6, 0x14, 0x66, 0x15,
96 0x7b, 0x99, 0xf8, 0x1e, 0x08, 0x46, 0x40, 0xd7, 0x48, 0x57, 0xf0, 0x9c,
97 0x08, 0xac, 0xbc, 0x93, 0xc3, 0xd8, 0x81, 0xd8, 0x52, 0xd7, 0x9e, 0x9b,
98 0x3e, 0x65, 0xef, 0x98, 0x8d, 0x93, 0x2e, 0x79, 0x58, 0x22, 0x98, 0xe2,
99 0xd9, 0x2f, 0x84, 0x6d, 0xf0, 0x50, 0xc6, 0xba, 0x52, 0x28, 0x29, 0xf1,
100 0x83, 0x4c, 0xad, 0xdd, 0x5a, 0x7a, 0xab, 0xd2, 0x74, 0xb2, 0x1d, 0xc1,
101 0xa9, 0xe4, 0x87, 0xbd, 0xa0, 0x94, 0x0e, 0x50, 0xa7, 0xc7, 0xf1, 0x0d,
102 0xda, 0x0c, 0x36, 0x94, 0xf4, 0x2c, 0xb8, 0x76, 0xc7, 0x7b, 0x32, 0x87,
103 0x23, 0x70, 0x9f, 0x3f, 0x19, 0xeb, 0xc3, 0xb5, 0x3a, 0x6e, 0xec, 0xa7,
104 0x9c, 0xb4, 0xdb, 0xe7, 0x6e, 0x6d, 0x5e, 0x3c, 0x14, 0xa1, 0xa6, 0xfb,
105 0x50, 0xfb, 0x17, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x7e, 0x30, 0x7c,
106 0x30, 0x1b, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x14, 0xb2, 0xfe, 0x21,
107 0x23, 0x44, 0x86, 0x95, 0x6a, 0x79, 0xd5, 0x81, 0x26, 0x8e, 0x73, 0x10,
108 0xd8, 0xa7, 0x4c, 0x8e, 0x74, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
109 0x04, 0x16, 0x04, 0x14, 0x33, 0x2f, 0xbd, 0x38, 0x86, 0xbc, 0xb0, 0xb2,
110 0x6a, 0xd3, 0x86, 0xca, 0x92, 0x7c, 0x0a, 0x6d, 0x55, 0xab, 0x34, 0x81,
111 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02,
112 0x30, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
113 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x20, 0x06, 0x03, 0x55, 0x1d,
114 0x25, 0x01, 0x01, 0xff, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06,
115 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
116 0x05, 0x07, 0x03, 0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
117 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0xe2,
118 0x0c, 0x37, 0x3e, 0x5f, 0x96, 0x10, 0x0d, 0xea, 0xa5, 0x15, 0x8f, 0xa2,
119 0x5b, 0x01, 0xe0, 0x1f, 0x15, 0x11, 0x42, 0x4b, 0x9e, 0x4b, 0x93, 0x90,
120 0x56, 0x4f, 0x4f, 0xbb, 0xc7, 0x32, 0x74, 0xfc, 0xbd, 0x1c, 0xcc, 0x06,
121 0x9f, 0xbb, 0x0b, 0x11, 0xa4, 0x8b, 0xa0, 0x52, 0x59, 0x94, 0xef, 0x87,
122 0x0c, 0xb1, 0xa8, 0xe0, 0x85, 0x96, 0xe1, 0x1b, 0x8b, 0x56, 0x12, 0x4d,
123 0x94, 0xd6, 0xa5, 0x52, 0x7f, 0x65, 0xf3, 0x21, 0x1f, 0xaa, 0x07, 0x8c,
124 0xaf, 0x69, 0xfa, 0x47, 0xbe, 0x3b, 0x74, 0x1a, 0x7c, 0xa6, 0x25, 0x63,
125 0x18, 0x5f, 0x0d, 0xda, 0xc4, 0x58, 0x01, 0xbc, 0xf2, 0x6d, 0x2d, 0xc1,
126 0x68, 0x3e, 0xa1, 0x2c, 0x59, 0x03, 0x3e, 0xa3, 0x13, 0x1b, 0xd9, 0x42,
127 0x28, 0x1e, 0x6c, 0x7f, 0x7f, 0x9d, 0x29, 0xf6, 0x43, 0x84, 0xe7, 0x60,
128 0xe3, 0x6f, 0x6a, 0x8a, 0x9f, 0x1d, 0x70
130 unsigned int device_cert_der_len
= 739;
132 unsigned char device_key
[] = {
133 0x30, 0x82, 0x02, 0x5c, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0xba,
134 0xc5, 0x2a, 0x7b, 0xb3, 0x29, 0x21, 0x8d, 0xbd, 0x01, 0x12, 0xff, 0x0b,
135 0xf6, 0x14, 0x66, 0x15, 0x7b, 0x99, 0xf8, 0x1e, 0x08, 0x46, 0x40, 0xd7,
136 0x48, 0x57, 0xf0, 0x9c, 0x08, 0xac, 0xbc, 0x93, 0xc3, 0xd8, 0x81, 0xd8,
137 0x52, 0xd7, 0x9e, 0x9b, 0x3e, 0x65, 0xef, 0x98, 0x8d, 0x93, 0x2e, 0x79,
138 0x58, 0x22, 0x98, 0xe2, 0xd9, 0x2f, 0x84, 0x6d, 0xf0, 0x50, 0xc6, 0xba,
139 0x52, 0x28, 0x29, 0xf1, 0x83, 0x4c, 0xad, 0xdd, 0x5a, 0x7a, 0xab, 0xd2,
140 0x74, 0xb2, 0x1d, 0xc1, 0xa9, 0xe4, 0x87, 0xbd, 0xa0, 0x94, 0x0e, 0x50,
141 0xa7, 0xc7, 0xf1, 0x0d, 0xda, 0x0c, 0x36, 0x94, 0xf4, 0x2c, 0xb8, 0x76,
142 0xc7, 0x7b, 0x32, 0x87, 0x23, 0x70, 0x9f, 0x3f, 0x19, 0xeb, 0xc3, 0xb5,
143 0x3a, 0x6e, 0xec, 0xa7, 0x9c, 0xb4, 0xdb, 0xe7, 0x6e, 0x6d, 0x5e, 0x3c,
144 0x14, 0xa1, 0xa6, 0xfb, 0x50, 0xfb, 0x17, 0x02, 0x03, 0x01, 0x00, 0x01,
145 0x02, 0x81, 0x80, 0x47, 0x9e, 0x91, 0xc2, 0xeb, 0x99, 0xeb, 0x26, 0xfa,
146 0x02, 0x2e, 0x71, 0xa4, 0xf9, 0x91, 0x2a, 0xf0, 0x33, 0xfc, 0x7f, 0xdb,
147 0xac, 0x5a, 0x9c, 0x44, 0xb1, 0x96, 0x1f, 0x4b, 0x06, 0x3c, 0x8e, 0xf7,
148 0xae, 0xd3, 0x18, 0x3f, 0x86, 0xcc, 0xee, 0x22, 0x23, 0xd4, 0x5d, 0x03,
149 0x47, 0xce, 0xd7, 0xb4, 0x6a, 0x6a, 0xa1, 0xeb, 0xe3, 0x52, 0xc8, 0x5a,
150 0x8c, 0x1b, 0xbd, 0x88, 0xf7, 0x36, 0x34, 0xd2, 0xfe, 0x6b, 0x75, 0x9c,
151 0xa4, 0x97, 0x2f, 0xeb, 0xa8, 0xec, 0x48, 0xb7, 0xe7, 0x53, 0x8f, 0xf1,
152 0x39, 0xca, 0xf8, 0xd2, 0xee, 0x34, 0xdc, 0x10, 0x99, 0x6f, 0xfd, 0x83,
153 0x21, 0xa9, 0xe0, 0xe9, 0x0c, 0x4e, 0x4e, 0x62, 0x5f, 0x9f, 0x0f, 0x05,
154 0xcd, 0xf4, 0x2b, 0x08, 0x06, 0x93, 0x55, 0x76, 0xaf, 0x63, 0x77, 0x80,
155 0x3e, 0xd5, 0xf2, 0xe0, 0x58, 0x7f, 0x3c, 0x41, 0x88, 0x4b, 0xc1, 0x02,
156 0x41, 0x01, 0x84, 0xfc, 0xa9, 0x26, 0x74, 0xe7, 0x4e, 0xe4, 0x39, 0xc4,
157 0x8f, 0x81, 0xe8, 0xc0, 0xd3, 0x6e, 0x01, 0x12, 0x7e, 0x12, 0x2d, 0x61,
158 0xaf, 0xe8, 0x60, 0x65, 0x8b, 0x50, 0x46, 0xdf, 0x02, 0x42, 0xe1, 0xea,
159 0xc1, 0x57, 0x9a, 0x2d, 0x90, 0xdc, 0x10, 0xf1, 0x79, 0xf0, 0xb5, 0x5c,
160 0x89, 0xef, 0x3b, 0xa8, 0x7a, 0x88, 0x3d, 0x54, 0xde, 0x35, 0x9c, 0xc3,
161 0x38, 0x4f, 0x2e, 0xb0, 0x74, 0xf7, 0x02, 0x40, 0x7a, 0xea, 0xc9, 0xfe,
162 0x48, 0xeb, 0x94, 0x20, 0x50, 0x33, 0x9d, 0x4f, 0x6f, 0x7f, 0xb1, 0x0e,
163 0xee, 0x42, 0x1c, 0xae, 0x72, 0x06, 0xb9, 0x9c, 0x80, 0x4a, 0xed, 0x07,
164 0xf8, 0x76, 0x5b, 0x37, 0x81, 0x45, 0x69, 0x09, 0xa5, 0x0d, 0x92, 0xed,
165 0xa8, 0xf0, 0x05, 0x6d, 0xb3, 0xa4, 0xef, 0xfb, 0x1b, 0xf0, 0x89, 0xea,
166 0x80, 0x2d, 0xaf, 0x9d, 0xbe, 0xc0, 0x08, 0x44, 0x58, 0x61, 0xc2, 0xe1,
167 0x02, 0x41, 0x01, 0x31, 0xaf, 0x14, 0x86, 0x82, 0x2c, 0x1c, 0x55, 0x42,
168 0x08, 0x73, 0xf6, 0x55, 0x20, 0xe3, 0x86, 0x79, 0x15, 0x3d, 0x39, 0xaf,
169 0xac, 0x2a, 0xfe, 0xe4, 0x72, 0x28, 0x2e, 0xe7, 0xe2, 0xec, 0xf5, 0xfe,
170 0x6f, 0xeb, 0x8c, 0x9a, 0x3e, 0xe0, 0xad, 0xf0, 0x2a, 0xb3, 0xf7, 0x33,
171 0xaf, 0x0b, 0x3e, 0x93, 0x95, 0x6c, 0xe5, 0x8f, 0xbd, 0x17, 0xfa, 0xed,
172 0xbc, 0x84, 0x8d, 0xc5, 0x55, 0x2a, 0x35, 0x02, 0x40, 0x6b, 0x4e, 0x1f,
173 0x4b, 0x03, 0x63, 0xcd, 0xab, 0xab, 0xf8, 0x73, 0x43, 0x8e, 0xa6, 0x1d,
174 0xef, 0x57, 0xe6, 0x95, 0x5d, 0x61, 0x24, 0x27, 0xd3, 0xcd, 0x58, 0x1b,
175 0xb7, 0x92, 0x9b, 0xd8, 0xa4, 0x0b, 0x11, 0x8a, 0x52, 0x26, 0x2a, 0x44,
176 0x73, 0x7f, 0xc1, 0x12, 0x2c, 0x23, 0xe1, 0x40, 0xb3, 0xaa, 0x3f, 0x82,
177 0x57, 0x1a, 0xd1, 0x47, 0x77, 0xe1, 0xb7, 0x89, 0x40, 0x09, 0x1c, 0x47,
178 0x61, 0x02, 0x41, 0x00, 0xa4, 0x47, 0x7d, 0x98, 0x74, 0x25, 0x95, 0x5a,
179 0xc9, 0xbe, 0x76, 0x66, 0xf8, 0x24, 0xb0, 0x83, 0x49, 0xd2, 0xce, 0x98,
180 0x75, 0x7c, 0xbb, 0xd9, 0x24, 0xe9, 0xc5, 0x53, 0xea, 0xd8, 0xec, 0x94,
181 0x79, 0xbb, 0x4e, 0x96, 0xc6, 0xd6, 0x17, 0x26, 0x77, 0xf3, 0x12, 0x3e,
182 0x15, 0x8e, 0x0c, 0x86, 0xdf, 0xa9, 0xf1, 0x34, 0x9b, 0x49, 0x28, 0x0a,
183 0x95, 0xb5, 0x29, 0x8f, 0x8a, 0x21, 0xff, 0xfc
185 unsigned int device_key_len
= 608;
188 static inline CFTypeRef
valid_cf_obj(CFTypeRef obj
, CFTypeID type
)
190 if (obj
&& CFGetTypeID(obj
) == type
)
195 static inline CFTypeRef
dict_get_value_of_type(CFDictionaryRef dict
, CFTypeRef key
, CFTypeID value_type
)
197 CFTypeRef value
= CFDictionaryGetValue(dict
, key
);
198 return valid_cf_obj(value
, value_type
);
202 static inline void write_data(const char * path
, CFDataRef data
)
204 int data_file
= open(path
, O_CREAT
|O_WRONLY
|O_TRUNC
, 0644);
205 write(data_file
, CFDataGetBytePtr(data
), CFDataGetLength(data
));
207 printf("wrote intermediate result to: %s\n", path
);
210 static void _query_string_apply(const void *key
, const void *value
, void *context
)
212 CFStringRef escaped_key
=
213 CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault
,
214 (CFStringRef
)key
, NULL
, NULL
, kCFStringEncodingUTF8
);
215 CFStringRef escaped_value
=
216 CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault
,
217 (CFStringRef
)value
, NULL
, NULL
, kCFStringEncodingUTF8
);
218 CFMutableStringRef query_string
= (CFMutableStringRef
)context
;
221 if (CFStringGetLength(query_string
) > 1)
222 format
= CFSTR("&%@=%@");
224 format
= CFSTR("%@=%@");
226 CFStringAppendFormat(query_string
, NULL
, format
, escaped_key
, escaped_value
);
227 CFRelease(escaped_key
);
228 CFRelease(escaped_value
);
231 static CFURLRef
build_url(CFStringRef base
, CFDictionaryRef info
)
233 CFURLRef url
= NULL
, base_url
= NULL
;
234 CFMutableStringRef query_string
=
235 CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, CFSTR("?"));
236 require(query_string
, out
);
238 CFDictionaryApplyFunction(info
, _query_string_apply
, query_string
);
239 base_url
= CFURLCreateWithString(kCFAllocatorDefault
, base
, NULL
);
240 url
= CFURLCreateWithString(kCFAllocatorDefault
, query_string
, base_url
);
242 CFReleaseSafe(base_url
);
246 static CFURLRef
scep_url_operation(CFStringRef base
, CFStringRef operation
, CFStringRef message
)
249 const void *keys
[] = { CFSTR("operation"), CFSTR("message") };
250 const void *values
[] = { operation
, message
};
252 require(operation
, out
);
253 CFDictionaryRef dict
= CFDictionaryCreate(NULL
, keys
, values
, message
? 2 : 1, NULL
, NULL
);
254 url
= build_url(base
, dict
);
260 static bool auth_failed(CFHTTPMessageRef request
, CFReadStreamRef readStream
)
262 bool isAuthenticationChallenge
= false;
263 CFHTTPMessageRef responseHeaders
= (CFHTTPMessageRef
)CFReadStreamCopyProperty(readStream
, kCFStreamPropertyHTTPResponseHeader
);
264 if (responseHeaders
) {
265 // Is the server response an challenge for credentials?
266 isAuthenticationChallenge
= (CFHTTPMessageGetResponseStatusCode(responseHeaders
) == 401);
267 if (isAuthenticationChallenge
) {
268 CFStringRef cf_user
= CFStringCreateWithCString(kCFAllocatorDefault
, user
, kCFStringEncodingUTF8
);
269 CFStringRef cf_pass
= CFStringCreateWithCString(kCFAllocatorDefault
, pass
, kCFStringEncodingUTF8
);
270 CFHTTPMessageAddAuthentication(request
, responseHeaders
, cf_user
, cf_pass
, NULL
, false);
272 CFRelease(responseHeaders
);
274 return isAuthenticationChallenge
;
277 static CFHTTPMessageRef
load_request(CFHTTPMessageRef request
, CFMutableDataRef data
, int retry
)
279 CFHTTPMessageRef result
= NULL
;
285 rs
= CFReadStreamCreateForHTTPRequest(NULL
, request
);
287 const void *keys
[] = {
288 kCFStreamSSLValidatesCertificateChain
,
289 // kCFStreamSSLCertificates,
291 //CFArrayRef ident = mit_identity();
292 const void *values
[] = {
297 CFDictionaryRef dict
= CFDictionaryCreate(NULL
, keys
, values
,
299 &kCFTypeDictionaryKeyCallBacks
,
300 &kCFTypeDictionaryValueCallBacks
);
301 CFReadStreamSetProperty(rs
, kCFStreamPropertySSLSettings
, dict
);
303 CFReadStreamSetProperty(rs
, kCFStreamPropertyHTTPAttemptPersistentConnection
, kCFBooleanTrue
);
305 if (CFReadStreamOpen(rs
)) {
307 if (auth_failed(request
, rs
)) {
308 CFReadStreamClose(rs
);
309 CFDataSetLength(data
, 0);
311 return load_request(request
, data
, retry
- 1);
315 CFIndex bytesRead
= CFReadStreamRead(rs
, buf
, BUFSIZE
);
317 CFDataAppendBytes(data
, buf
, bytesRead
);
318 } else if (bytesRead
== 0) {
320 result
= (CFHTTPMessageRef
)CFReadStreamCopyProperty(rs
, kCFStreamPropertyHTTPResponseHeader
);
331 CFReadStreamClose(rs
);
339 static CFDictionaryRef
get_encrypted_profile_packet(CFStringRef base_url
)
342 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
,
343 device_cert_der
, device_cert_der_len
);
344 SecKeyRef key
= SecKeyCreateRSAPrivateKey(NULL
,
345 device_key
, device_key_len
, kSecKeyEncodingPkcs1
);
346 SecIdentityRef identity
= SecIdentityCreate(kCFAllocatorDefault
, cert
, key
);
350 SecIdentityRef identity
= lockdown_copy_device_identity();
353 CFMutableDictionaryRef machine_dict
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
354 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
355 CFDictionarySetValue(machine_dict
, CFSTR("UDID"), CFSTR("f1f50f8122fb10146f65e90380176342add6a85c"));
356 CFStringRef cf_user
= CFStringCreateWithCString(kCFAllocatorDefault
, user
, kCFStringEncodingUTF8
);
358 CFDictionarySetValue(machine_dict
, CFSTR("USERNAME"), cf_user
);
361 CFStringRef cf_pass
= CFStringCreateWithCString(kCFAllocatorDefault
, pass
, kCFStringEncodingUTF8
);
363 CFDictionarySetValue(machine_dict
, CFSTR("PASSWORD"), cf_pass
);
366 CFDataRef machine_dict_data
= CFPropertyListCreateXMLData(kCFAllocatorDefault
,
367 (CFPropertyListRef
)machine_dict
);
368 CFMutableDataRef signed_data
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
369 if (SecCMSSignDataAndAttributes(identity
, machine_dict_data
, false, signed_data
, NULL
))
370 errx(1, "failed to sign data");
372 CFRelease(machine_dict_data
);
373 CFRelease(machine_dict
);
375 CFURLRef url
= build_url(base_url
, NULL
);
376 CFHTTPMessageRef request
= CFHTTPMessageCreateRequest(kCFAllocatorDefault
,
377 CFSTR("POST"), url
, kCFHTTPVersion1_1
);
378 CFHTTPMessageSetBody(request
, signed_data
);
379 CFHTTPMessageSetHeaderFieldValue(request
, CFSTR("Content-Type"),
380 CFSTR("application/pkcs7-signature"));
381 CFMutableDataRef data
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
382 CFHTTPMessageRef response
= load_request(request
, data
, 1);
385 CFErrorRef error
= NULL
;
386 CFTypeRef result
= CFPropertyListCreateWithData(kCFAllocatorDefault
,
387 data
, kCFPropertyListImmutable
, NULL
, &error
);
391 errx(1, "failed to decode encrypted profile response");
394 if (CFGetTypeID(result
) != CFDictionaryGetTypeID())
395 CFReleaseNull(result
);
396 return (CFDictionaryRef
)result
;
399 static SecCertificateRef
get_ca_cert(CFStringRef scep_base_url
, CFStringRef scep_ca_name
)
401 SecCertificateRef cert
= NULL
;
402 CFMutableDataRef data
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
404 CFURLRef url
= scep_url_operation(scep_base_url
, CFSTR("GetCACert"), scep_ca_name
);
405 CFHTTPMessageRef request
= CFHTTPMessageCreateRequest(kCFAllocatorDefault
,
406 CFSTR("GET"), url
, kCFHTTPVersion1_1
);
407 CFHTTPMessageRef result
= load_request(request
, data
, 1);
411 CFStringRef contentTypeValue
= CFHTTPMessageCopyHeaderFieldValue(result
, CFSTR("Content-Type"));
412 // CFHTTPMessageRef response = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, false);
413 // CFHTTPMessageAppendBytes(response, CFDataGetBytePtr(data), CFDataGetLength(data));
414 // CFDataRef bodyValue = CFHTTPMessageCopyBody(response);
415 if (kCFCompareEqualTo
== CFStringCompare(CFSTR("application/x-x509-ca-cert"),
416 contentTypeValue
, kCFCompareCaseInsensitive
)) {
417 // CA only response: application/x-x509-ca-cert
418 cert
= SecCertificateCreateWithData(kCFAllocatorDefault
, data
);
420 write_data("/tmp/ca_cert.der", data
);
421 } else if (kCFCompareEqualTo
== CFStringCompare(CFSTR("application/x-x509-ca-ra-cert"),
422 contentTypeValue
, kCFCompareCaseInsensitive
)) {
423 // RA/CA response: application/x-x509-ca-ra-cert
424 CFArrayRef cert_array
= SecCMSCertificatesOnlyMessageCopyCertificates(data
);
426 write_data("/tmp/ca_cert_array.der", data
);
427 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(cert_array
, 0);
429 CFRelease(cert_array
);
431 CFRelease(contentTypeValue
);
437 static SecIdentityRef
perform_scep(CFDictionaryRef scep_dict
)
439 SecIdentityRef identity
= NULL
;
440 CFDictionaryRef parameters
= NULL
, csr_parameters
= NULL
;
441 CFStringRef scep_base_url
= NULL
, scep_instance_name
= NULL
,
442 scep_challenge
= NULL
, scep_subject
= NULL
, scep_subject_requested
= NULL
;
443 CFTypeRef scep_key_bitsize
= NULL
;
444 const void *keygen_keys
[] = { kSecAttrKeyType
, kSecAttrKeySizeInBits
};
445 const void *keygen_vals
[] = { kSecAttrKeyTypeRSA
, CFSTR("512") };
447 require(valid_cf_obj(scep_dict
,CFDictionaryGetTypeID()), out
);
448 require(scep_base_url
=
449 dict_get_value_of_type(scep_dict
, CFSTR("URL"), CFStringGetTypeID()), out
);
450 require(scep_instance_name
=
451 dict_get_value_of_type(scep_dict
, CFSTR("NAME"), CFStringGetTypeID()), out
);
452 require(scep_challenge
=
453 dict_get_value_of_type(scep_dict
, CFSTR("CHALLENGE"), CFStringGetTypeID()), out
);
455 scep_subject_requested
=
456 dict_get_value_of_type(scep_dict
, CFSTR("SUBJECT"), CFStringGetTypeID());
457 if (scep_subject_requested
) {
458 CFArrayRef scep_subject_components
=
459 CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault
,
460 scep_subject_requested
, CFSTR("="));
461 if (CFArrayGetCount(scep_subject_components
) == 2)
462 scep_subject
= CFArrayGetValueAtIndex(scep_subject_components
, 1);
466 dict_get_value_of_type(scep_dict
, CFSTR("KEYSIZE"), CFNumberGetTypeID());
467 if (!scep_key_bitsize
)
469 dict_get_value_of_type(scep_dict
, CFSTR("KEYSIZE"), CFStringGetTypeID());
470 if (scep_key_bitsize
)
471 keygen_vals
[1] = scep_key_bitsize
;
473 parameters
= CFDictionaryCreate(kCFAllocatorDefault
,
474 keygen_keys
, keygen_vals
, array_size(keygen_vals
),
475 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
477 int key_usage
= kSecKeyUsageDigitalSignature
| kSecKeyUsageKeyEncipherment
;
478 CFNumberRef key_usage_num
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberIntType
, &key_usage
);
479 const void *key
[] = { kSecCSRChallengePassword
, kSecCertificateKeyUsage
};
480 const void *val
[] = { scep_challenge
? scep_challenge
: CFSTR("magic"), key_usage_num
};
481 csr_parameters
= CFDictionaryCreate(kCFAllocatorDefault
,
482 key
, val
, array_size(key
), NULL
, NULL
);
484 SecCertificateRef ca_cert
= get_ca_cert(scep_base_url
, scep_instance_name
? scep_instance_name
: CFSTR("test"));
486 errx(1, "no ca cert returned from scep server.");
488 identity
= NULL
; // enroll_scep(scep_base_url, scep_subject, csr_parameters, parameters, ca_cert);
490 errx(1, "failed to get identity from scep server.");
493 CFReleaseSafe(parameters
);
497 static CFDataRef
get_profile(CFStringRef url_cfstring
, SecIdentityRef identity
)
500 CFHTTPMessageRef request
= NULL
;
501 SecCertificateRef cert
= NULL
;
502 CFDataRef cert_data
= NULL
;
503 CFMutableDataRef data
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
504 CFHTTPMessageRef response
= NULL
;
506 require(url
= CFURLCreateWithString(kCFAllocatorDefault
, url_cfstring
, NULL
), out
);
507 require(request
= CFHTTPMessageCreateRequest(kCFAllocatorDefault
,
508 CFSTR("POST"), url
, kCFHTTPVersion1_1
), out
);
509 require_noerr(SecIdentityCopyCertificate(identity
, &cert
), out
);
510 require(cert_data
= SecCertificateCopyData(cert
), out
);
511 CFHTTPMessageSetBody(request
, cert_data
);
512 // this is technically the wrong mimetype; we'll probably switch to signed data
513 CFHTTPMessageSetHeaderFieldValue(request
, CFSTR("Content-Type"), CFSTR("application/x-x509-ca-cert"));
514 response
= load_request(request
, data
, 1);
518 //CFReleaseSafe(response);
519 CFReleaseSafe(request
);
521 CFReleaseSafe(cert_data
);
523 CFReleaseSafe(response
);
528 static bool validate_profile(CFDataRef profile_plist_data
, SecIdentityRef identity
)
530 CFStringRef type
= NULL
, uuid
= NULL
;
531 CFDataRef enc_payload
= NULL
;
532 CFTypeRef result
= CFPropertyListCreateWithData(kCFAllocatorDefault
,
533 profile_plist_data
, kCFPropertyListImmutable
, NULL
, NULL
);
534 require(valid_cf_obj(result
, CFDictionaryGetTypeID()), out
);
535 require(type
= dict_get_value_of_type(result
, CFSTR("PayloadType"),
536 CFStringGetTypeID()), out
);
537 require(uuid
= dict_get_value_of_type(result
, CFSTR("PayloadUUID"),
538 CFStringGetTypeID()), out
);
539 enc_payload
= dict_get_value_of_type(result
, CFSTR("EncryptedPayloadContent"),
542 CFMutableDataRef dec_data
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
543 require_noerr(SecCMSDecryptEnvelopedData(enc_payload
, dec_data
, NULL
), out
);
544 bool sub
= validate_profile(dec_data
, identity
);
545 CFReleaseSafe(dec_data
);
549 write_data("/tmp/unencrypted_profile.mobileconfig", profile_plist_data
);
550 //CFDictionaryRef sub_conf = dict_get_value_of_type(result, CFSTR("PayloadContent"), CFDictionaryGetTypeID());
558 static const char *auth
= "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
559 <!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/\n\
560 PropertyList-1.0.dtd\">\n\
561 <plist version=\"1.0\">\n\
563 <key>PayloadContent</key>\n\
566 <string>https://phone.vpn.apple.com/deviceid/</string>\n\
567 <key>DeviceAttributes</key>\n\
569 <string>UDID</string>\n\
570 <string>VERSION</string>\n\
571 <string>MAC_ADDRESS_EN0</string>\n\
572 <string>MAC_ADDRESS_IP0</string>\n\
574 <key>CHALLENGE</key>\n\
575 <string>${USER_COOKIE}</string>\n\
577 <key>PayloadType</key>\n\
578 <string>Device Identification</string>\n\
582 static void annotate_machine_info(const void *value
, void *context
)
584 CFDictionaryRef machine_dict
= NULL
;
585 CFStringRef machine_key
= NULL
;
586 require(machine_dict
= (CFDictionaryRef
)valid_cf_obj(context
,
587 CFDictionaryGetTypeID()), out
);
588 require(machine_key
= (CFStringRef
)valid_cf_obj((CFTypeRef
)value
,
589 CFStringGetTypeID()), out
);
590 if (CFEqual(machine_key
, CFSTR("UDID"))) {
597 static void machine_authentication(CFDataRef req
, CFDataRef reply
)
599 CFDataRef machine_auth_request
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
,
600 (uint8_t*)auth
, strlen(auth
), kCFAllocatorNull
);
601 CFDictionaryRef auth_dict
= NULL
;
602 CFMutableDictionaryRef auth_reply_dict
=
603 CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
604 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
606 if (req
) { CFRelease(machine_auth_request
); machine_auth_request
= req
; CFRetain(req
); }
607 CFDictionaryRef auth_request_dict
= CFPropertyListCreateWithData(kCFAllocatorDefault
,
608 machine_auth_request
, kCFPropertyListImmutable
, NULL
, NULL
);
610 require(auth_reply_dict
, out
);
611 require(valid_cf_obj(auth_request_dict
, CFDictionaryGetTypeID()), out
);
612 require(auth_dict
= dict_get_value_of_type(auth_request_dict
, CFSTR("PayloadContent"), CFDictionaryGetTypeID()), out
);
613 CFStringRef challenge
= dict_get_value_of_type(auth_dict
, CFSTR("CHALLENGE"), CFStringGetTypeID());
615 CFDictionarySetValue(auth_reply_dict
, CFSTR("CHALLENGE"), challenge
);
616 CFArrayRef device_info
= dict_get_value_of_type(auth_dict
, CFSTR("DeviceAttributes"), CFArrayGetTypeID());
618 CFArrayApplyFunction(device_info
, CFRangeMake(0, CFArrayGetCount(device_info
)),
619 annotate_machine_info
, auth_reply_dict
);
621 // make copy of reply dict
623 CFReleaseSafe(machine_auth_request
);
624 CFReleaseSafe(auth_request_dict
);
628 extern int command_spc(int argc
, char * const *argv
)
630 SecIdentityRef identity
= NULL
;
634 while ((arg
= getopt(argc
, argv
, "du:p:")) != -1) {
656 // get plist from argv[0] url
657 } else if (argc
== 0) {
658 machine_authentication(NULL
, NULL
);
665 CFStringRef machine_id_url_cfstring
= CFStringCreateWithCString(kCFAllocatorDefault
,
666 argv
[0], kCFStringEncodingUTF8
);
668 CFDictionaryRef enroll_packet
=
669 get_encrypted_profile_packet(machine_id_url_cfstring
);
670 require(enroll_packet
&& CFGetTypeID(enroll_packet
) == CFDictionaryGetTypeID(), out
);
671 //require(payload_type(enroll_packet, "Encrypted Profile Service"), out);
672 CFDictionaryRef scep_config
= NULL
;
673 CFDictionaryRef payload_content
= NULL
;
674 require(payload_content
= dict_get_value_of_type(enroll_packet
,
675 CFSTR("PayloadContent"), CFDictionaryGetTypeID()), out
);
676 require(scep_config
= dict_get_value_of_type(payload_content
,
677 CFSTR("SCEP"), CFDictionaryGetTypeID()), out
);
678 require(identity
= perform_scep(scep_config
), out
);
679 CFDictionaryRef dict
= CFDictionaryCreate(NULL
, &kSecValueRef
, (const void **)&identity
, 1, NULL
, NULL
);
680 require_noerr(SecItemAdd(dict
, NULL
), out
);
682 CFStringRef profile_url
= NULL
;
683 require(profile_url
= dict_get_value_of_type(payload_content
,
684 CFSTR("URL"), CFStringGetTypeID()), out
);
686 CFDataRef profile_data
= NULL
;
687 require(profile_data
= get_profile(profile_url
, identity
), out
);
688 CFDataRef profile_plist
= NULL
;
690 write_data("/tmp/profile.mobileconfig", profile_data
);
692 require_noerr(SecCMSVerify(profile_data
, NULL
, NULL
, NULL
, &profile_plist
), out
);
693 CFRelease(profile_data
);
694 require(profile_plist
, out
);
695 require(validate_profile(profile_plist
, identity
), out
);
704 #endif // TARGET_OS_EMBEDDED