2 * Copyright (c) 2009-2010,2013-2014 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@
30 #include <TargetConditionals.h>
31 #if TARGET_OS_EMBEDDED
33 #include "SecurityCommands.h"
35 #include <CoreFoundation/CoreFoundation.h>
36 #include <AssertMacros.h>
37 #include <TargetConditionals.h>
38 #include <CFNetwork/CFNetwork.h>
40 extern const CFStringRef kCFStreamPropertySSLPeerTrust
;
41 #include <Security/SecTrust.h>
42 #include <Security/SecCertificate.h>
43 #include <Security/SecCertificatePriv.h>
44 #include <Security/SecImportExport.h>
45 #include <Security/SecPolicy.h>
46 #include <Security/SecIdentity.h>
47 #include <Security/SecIdentityPriv.h>
48 #include <Security/SecRSAKey.h>
49 #include <Security/SecSCEP.h>
50 #include <Security/SecCMS.h>
51 #include <Security/SecItem.h>
52 #include <Security/SecInternal.h>
53 #include <utilities/array_size.h>
58 //static char *scep_url = "https://localhost:2000/cgi-bin/pkiclient.exe";
59 static char *user
= "webuser";
60 static char *pass
= "webpassowrd";
65 unsigned char device_cert_der
[] = {
66 0x30, 0x82, 0x02, 0xdf, 0x30, 0x82, 0x02, 0x48, 0xa0, 0x03, 0x02, 0x01,
67 0x02, 0x02, 0x0a, 0x01, 0x5c, 0x0a, 0x2f, 0xfd, 0x20, 0x02, 0x00, 0xe6,
68 0x27, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
69 0x01, 0x0b, 0x05, 0x00, 0x30, 0x5a, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
70 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06,
71 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20,
72 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04,
73 0x0b, 0x13, 0x0c, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x69, 0x50, 0x68,
74 0x6f, 0x6e, 0x65, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03,
75 0x13, 0x16, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x69, 0x50, 0x68, 0x6f,
76 0x6e, 0x65, 0x20, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x20, 0x43, 0x41,
77 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x38, 0x31, 0x32, 0x31, 0x32, 0x32, 0x33,
78 0x30, 0x33, 0x35, 0x36, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x31, 0x32, 0x31,
79 0x32, 0x32, 0x33, 0x30, 0x33, 0x35, 0x36, 0x5a, 0x30, 0x81, 0x87, 0x31,
80 0x31, 0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x28, 0x66, 0x31,
81 0x66, 0x35, 0x30, 0x66, 0x38, 0x31, 0x32, 0x32, 0x66, 0x62, 0x31, 0x30,
82 0x31, 0x34, 0x36, 0x66, 0x36, 0x35, 0x65, 0x39, 0x30, 0x33, 0x38, 0x30,
83 0x31, 0x37, 0x36, 0x33, 0x34, 0x32, 0x61, 0x64, 0x64, 0x36, 0x61, 0x38,
84 0x35, 0x63, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
85 0x02, 0x55, 0x53, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08,
86 0x13, 0x02, 0x43, 0x41, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04,
87 0x07, 0x13, 0x09, 0x43, 0x75, 0x70, 0x65, 0x72, 0x74, 0x69, 0x6e, 0x6f,
88 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x41,
89 0x70, 0x70, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x0f, 0x30,
90 0x0d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x06, 0x69, 0x50, 0x68, 0x6f,
91 0x6e, 0x65, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48,
92 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00,
93 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xba, 0xc5, 0x2a, 0x7b, 0xb3,
94 0x29, 0x21, 0x8d, 0xbd, 0x01, 0x12, 0xff, 0x0b, 0xf6, 0x14, 0x66, 0x15,
95 0x7b, 0x99, 0xf8, 0x1e, 0x08, 0x46, 0x40, 0xd7, 0x48, 0x57, 0xf0, 0x9c,
96 0x08, 0xac, 0xbc, 0x93, 0xc3, 0xd8, 0x81, 0xd8, 0x52, 0xd7, 0x9e, 0x9b,
97 0x3e, 0x65, 0xef, 0x98, 0x8d, 0x93, 0x2e, 0x79, 0x58, 0x22, 0x98, 0xe2,
98 0xd9, 0x2f, 0x84, 0x6d, 0xf0, 0x50, 0xc6, 0xba, 0x52, 0x28, 0x29, 0xf1,
99 0x83, 0x4c, 0xad, 0xdd, 0x5a, 0x7a, 0xab, 0xd2, 0x74, 0xb2, 0x1d, 0xc1,
100 0xa9, 0xe4, 0x87, 0xbd, 0xa0, 0x94, 0x0e, 0x50, 0xa7, 0xc7, 0xf1, 0x0d,
101 0xda, 0x0c, 0x36, 0x94, 0xf4, 0x2c, 0xb8, 0x76, 0xc7, 0x7b, 0x32, 0x87,
102 0x23, 0x70, 0x9f, 0x3f, 0x19, 0xeb, 0xc3, 0xb5, 0x3a, 0x6e, 0xec, 0xa7,
103 0x9c, 0xb4, 0xdb, 0xe7, 0x6e, 0x6d, 0x5e, 0x3c, 0x14, 0xa1, 0xa6, 0xfb,
104 0x50, 0xfb, 0x17, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x7e, 0x30, 0x7c,
105 0x30, 0x1b, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x14, 0xb2, 0xfe, 0x21,
106 0x23, 0x44, 0x86, 0x95, 0x6a, 0x79, 0xd5, 0x81, 0x26, 0x8e, 0x73, 0x10,
107 0xd8, 0xa7, 0x4c, 0x8e, 0x74, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e,
108 0x04, 0x16, 0x04, 0x14, 0x33, 0x2f, 0xbd, 0x38, 0x86, 0xbc, 0xb0, 0xb2,
109 0x6a, 0xd3, 0x86, 0xca, 0x92, 0x7c, 0x0a, 0x6d, 0x55, 0xab, 0x34, 0x81,
110 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02,
111 0x30, 0x00, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
112 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x20, 0x06, 0x03, 0x55, 0x1d,
113 0x25, 0x01, 0x01, 0xff, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06,
114 0x01, 0x05, 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
115 0x05, 0x07, 0x03, 0x02, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
116 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0xe2,
117 0x0c, 0x37, 0x3e, 0x5f, 0x96, 0x10, 0x0d, 0xea, 0xa5, 0x15, 0x8f, 0xa2,
118 0x5b, 0x01, 0xe0, 0x1f, 0x15, 0x11, 0x42, 0x4b, 0x9e, 0x4b, 0x93, 0x90,
119 0x56, 0x4f, 0x4f, 0xbb, 0xc7, 0x32, 0x74, 0xfc, 0xbd, 0x1c, 0xcc, 0x06,
120 0x9f, 0xbb, 0x0b, 0x11, 0xa4, 0x8b, 0xa0, 0x52, 0x59, 0x94, 0xef, 0x87,
121 0x0c, 0xb1, 0xa8, 0xe0, 0x85, 0x96, 0xe1, 0x1b, 0x8b, 0x56, 0x12, 0x4d,
122 0x94, 0xd6, 0xa5, 0x52, 0x7f, 0x65, 0xf3, 0x21, 0x1f, 0xaa, 0x07, 0x8c,
123 0xaf, 0x69, 0xfa, 0x47, 0xbe, 0x3b, 0x74, 0x1a, 0x7c, 0xa6, 0x25, 0x63,
124 0x18, 0x5f, 0x0d, 0xda, 0xc4, 0x58, 0x01, 0xbc, 0xf2, 0x6d, 0x2d, 0xc1,
125 0x68, 0x3e, 0xa1, 0x2c, 0x59, 0x03, 0x3e, 0xa3, 0x13, 0x1b, 0xd9, 0x42,
126 0x28, 0x1e, 0x6c, 0x7f, 0x7f, 0x9d, 0x29, 0xf6, 0x43, 0x84, 0xe7, 0x60,
127 0xe3, 0x6f, 0x6a, 0x8a, 0x9f, 0x1d, 0x70
129 unsigned int device_cert_der_len
= 739;
131 unsigned char device_key
[] = {
132 0x30, 0x82, 0x02, 0x5c, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0xba,
133 0xc5, 0x2a, 0x7b, 0xb3, 0x29, 0x21, 0x8d, 0xbd, 0x01, 0x12, 0xff, 0x0b,
134 0xf6, 0x14, 0x66, 0x15, 0x7b, 0x99, 0xf8, 0x1e, 0x08, 0x46, 0x40, 0xd7,
135 0x48, 0x57, 0xf0, 0x9c, 0x08, 0xac, 0xbc, 0x93, 0xc3, 0xd8, 0x81, 0xd8,
136 0x52, 0xd7, 0x9e, 0x9b, 0x3e, 0x65, 0xef, 0x98, 0x8d, 0x93, 0x2e, 0x79,
137 0x58, 0x22, 0x98, 0xe2, 0xd9, 0x2f, 0x84, 0x6d, 0xf0, 0x50, 0xc6, 0xba,
138 0x52, 0x28, 0x29, 0xf1, 0x83, 0x4c, 0xad, 0xdd, 0x5a, 0x7a, 0xab, 0xd2,
139 0x74, 0xb2, 0x1d, 0xc1, 0xa9, 0xe4, 0x87, 0xbd, 0xa0, 0x94, 0x0e, 0x50,
140 0xa7, 0xc7, 0xf1, 0x0d, 0xda, 0x0c, 0x36, 0x94, 0xf4, 0x2c, 0xb8, 0x76,
141 0xc7, 0x7b, 0x32, 0x87, 0x23, 0x70, 0x9f, 0x3f, 0x19, 0xeb, 0xc3, 0xb5,
142 0x3a, 0x6e, 0xec, 0xa7, 0x9c, 0xb4, 0xdb, 0xe7, 0x6e, 0x6d, 0x5e, 0x3c,
143 0x14, 0xa1, 0xa6, 0xfb, 0x50, 0xfb, 0x17, 0x02, 0x03, 0x01, 0x00, 0x01,
144 0x02, 0x81, 0x80, 0x47, 0x9e, 0x91, 0xc2, 0xeb, 0x99, 0xeb, 0x26, 0xfa,
145 0x02, 0x2e, 0x71, 0xa4, 0xf9, 0x91, 0x2a, 0xf0, 0x33, 0xfc, 0x7f, 0xdb,
146 0xac, 0x5a, 0x9c, 0x44, 0xb1, 0x96, 0x1f, 0x4b, 0x06, 0x3c, 0x8e, 0xf7,
147 0xae, 0xd3, 0x18, 0x3f, 0x86, 0xcc, 0xee, 0x22, 0x23, 0xd4, 0x5d, 0x03,
148 0x47, 0xce, 0xd7, 0xb4, 0x6a, 0x6a, 0xa1, 0xeb, 0xe3, 0x52, 0xc8, 0x5a,
149 0x8c, 0x1b, 0xbd, 0x88, 0xf7, 0x36, 0x34, 0xd2, 0xfe, 0x6b, 0x75, 0x9c,
150 0xa4, 0x97, 0x2f, 0xeb, 0xa8, 0xec, 0x48, 0xb7, 0xe7, 0x53, 0x8f, 0xf1,
151 0x39, 0xca, 0xf8, 0xd2, 0xee, 0x34, 0xdc, 0x10, 0x99, 0x6f, 0xfd, 0x83,
152 0x21, 0xa9, 0xe0, 0xe9, 0x0c, 0x4e, 0x4e, 0x62, 0x5f, 0x9f, 0x0f, 0x05,
153 0xcd, 0xf4, 0x2b, 0x08, 0x06, 0x93, 0x55, 0x76, 0xaf, 0x63, 0x77, 0x80,
154 0x3e, 0xd5, 0xf2, 0xe0, 0x58, 0x7f, 0x3c, 0x41, 0x88, 0x4b, 0xc1, 0x02,
155 0x41, 0x01, 0x84, 0xfc, 0xa9, 0x26, 0x74, 0xe7, 0x4e, 0xe4, 0x39, 0xc4,
156 0x8f, 0x81, 0xe8, 0xc0, 0xd3, 0x6e, 0x01, 0x12, 0x7e, 0x12, 0x2d, 0x61,
157 0xaf, 0xe8, 0x60, 0x65, 0x8b, 0x50, 0x46, 0xdf, 0x02, 0x42, 0xe1, 0xea,
158 0xc1, 0x57, 0x9a, 0x2d, 0x90, 0xdc, 0x10, 0xf1, 0x79, 0xf0, 0xb5, 0x5c,
159 0x89, 0xef, 0x3b, 0xa8, 0x7a, 0x88, 0x3d, 0x54, 0xde, 0x35, 0x9c, 0xc3,
160 0x38, 0x4f, 0x2e, 0xb0, 0x74, 0xf7, 0x02, 0x40, 0x7a, 0xea, 0xc9, 0xfe,
161 0x48, 0xeb, 0x94, 0x20, 0x50, 0x33, 0x9d, 0x4f, 0x6f, 0x7f, 0xb1, 0x0e,
162 0xee, 0x42, 0x1c, 0xae, 0x72, 0x06, 0xb9, 0x9c, 0x80, 0x4a, 0xed, 0x07,
163 0xf8, 0x76, 0x5b, 0x37, 0x81, 0x45, 0x69, 0x09, 0xa5, 0x0d, 0x92, 0xed,
164 0xa8, 0xf0, 0x05, 0x6d, 0xb3, 0xa4, 0xef, 0xfb, 0x1b, 0xf0, 0x89, 0xea,
165 0x80, 0x2d, 0xaf, 0x9d, 0xbe, 0xc0, 0x08, 0x44, 0x58, 0x61, 0xc2, 0xe1,
166 0x02, 0x41, 0x01, 0x31, 0xaf, 0x14, 0x86, 0x82, 0x2c, 0x1c, 0x55, 0x42,
167 0x08, 0x73, 0xf6, 0x55, 0x20, 0xe3, 0x86, 0x79, 0x15, 0x3d, 0x39, 0xaf,
168 0xac, 0x2a, 0xfe, 0xe4, 0x72, 0x28, 0x2e, 0xe7, 0xe2, 0xec, 0xf5, 0xfe,
169 0x6f, 0xeb, 0x8c, 0x9a, 0x3e, 0xe0, 0xad, 0xf0, 0x2a, 0xb3, 0xf7, 0x33,
170 0xaf, 0x0b, 0x3e, 0x93, 0x95, 0x6c, 0xe5, 0x8f, 0xbd, 0x17, 0xfa, 0xed,
171 0xbc, 0x84, 0x8d, 0xc5, 0x55, 0x2a, 0x35, 0x02, 0x40, 0x6b, 0x4e, 0x1f,
172 0x4b, 0x03, 0x63, 0xcd, 0xab, 0xab, 0xf8, 0x73, 0x43, 0x8e, 0xa6, 0x1d,
173 0xef, 0x57, 0xe6, 0x95, 0x5d, 0x61, 0x24, 0x27, 0xd3, 0xcd, 0x58, 0x1b,
174 0xb7, 0x92, 0x9b, 0xd8, 0xa4, 0x0b, 0x11, 0x8a, 0x52, 0x26, 0x2a, 0x44,
175 0x73, 0x7f, 0xc1, 0x12, 0x2c, 0x23, 0xe1, 0x40, 0xb3, 0xaa, 0x3f, 0x82,
176 0x57, 0x1a, 0xd1, 0x47, 0x77, 0xe1, 0xb7, 0x89, 0x40, 0x09, 0x1c, 0x47,
177 0x61, 0x02, 0x41, 0x00, 0xa4, 0x47, 0x7d, 0x98, 0x74, 0x25, 0x95, 0x5a,
178 0xc9, 0xbe, 0x76, 0x66, 0xf8, 0x24, 0xb0, 0x83, 0x49, 0xd2, 0xce, 0x98,
179 0x75, 0x7c, 0xbb, 0xd9, 0x24, 0xe9, 0xc5, 0x53, 0xea, 0xd8, 0xec, 0x94,
180 0x79, 0xbb, 0x4e, 0x96, 0xc6, 0xd6, 0x17, 0x26, 0x77, 0xf3, 0x12, 0x3e,
181 0x15, 0x8e, 0x0c, 0x86, 0xdf, 0xa9, 0xf1, 0x34, 0x9b, 0x49, 0x28, 0x0a,
182 0x95, 0xb5, 0x29, 0x8f, 0x8a, 0x21, 0xff, 0xfc
184 unsigned int device_key_len
= 608;
187 static inline CFTypeRef
valid_cf_obj(CFTypeRef obj
, CFTypeID type
)
189 if (obj
&& CFGetTypeID(obj
) == type
)
194 static inline CFTypeRef
dict_get_value_of_type(CFDictionaryRef dict
, CFTypeRef key
, CFTypeID value_type
)
196 CFTypeRef value
= CFDictionaryGetValue(dict
, key
);
197 return valid_cf_obj(value
, value_type
);
201 static inline void write_data(const char * path
, CFDataRef data
)
203 int data_file
= open(path
, O_CREAT
|O_WRONLY
|O_TRUNC
, 0644);
204 write(data_file
, CFDataGetBytePtr(data
), CFDataGetLength(data
));
206 printf("wrote intermediate result to: %s\n", path
);
209 static void _query_string_apply(const void *key
, const void *value
, void *context
)
211 CFStringRef escaped_key
=
212 CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault
,
213 (CFStringRef
)key
, NULL
, NULL
, kCFStringEncodingUTF8
);
214 CFStringRef escaped_value
=
215 CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault
,
216 (CFStringRef
)value
, NULL
, NULL
, kCFStringEncodingUTF8
);
217 CFMutableStringRef query_string
= (CFMutableStringRef
)context
;
219 if (CFStringGetLength(query_string
) > 1)
220 CFStringAppend(query_string
, CFSTR("&"));
222 CFStringAppendFormat(query_string
, NULL
, CFSTR("%@=%@"), escaped_key
, escaped_value
);
223 CFRelease(escaped_key
);
224 CFRelease(escaped_value
);
227 static CF_RETURNS_RETAINED CFURLRef
build_url(CFStringRef base
, CFDictionaryRef info
)
229 CFURLRef url
= NULL
, base_url
= NULL
;
230 CFMutableStringRef query_string
=
231 CFStringCreateMutableCopy(kCFAllocatorDefault
, 0, CFSTR("?"));
232 require(query_string
, out
);
234 CFDictionaryApplyFunction(info
, _query_string_apply
, query_string
);
235 base_url
= CFURLCreateWithString(kCFAllocatorDefault
, base
, NULL
);
236 url
= CFURLCreateWithString(kCFAllocatorDefault
, query_string
, base_url
);
238 CFReleaseSafe(query_string
);
239 CFReleaseSafe(base_url
);
243 static CF_RETURNS_RETAINED CFURLRef
scep_url_operation(CFStringRef base
, CFStringRef operation
, CFStringRef message
)
246 const void *keys
[] = { CFSTR("operation"), CFSTR("message") };
247 const void *values
[] = { operation
, message
};
249 require(operation
, out
);
250 CFDictionaryRef dict
= CFDictionaryCreate(NULL
, keys
, values
, message
? 2 : 1, NULL
, NULL
);
251 url
= build_url(base
, dict
);
257 static bool auth_failed(CFHTTPMessageRef request
, CFReadStreamRef readStream
)
259 bool isAuthenticationChallenge
= false;
260 CFHTTPMessageRef responseHeaders
= (CFHTTPMessageRef
)CFReadStreamCopyProperty(readStream
, kCFStreamPropertyHTTPResponseHeader
);
261 if (responseHeaders
) {
262 // Is the server response an challenge for credentials?
263 isAuthenticationChallenge
= (CFHTTPMessageGetResponseStatusCode(responseHeaders
) == 401);
264 if (isAuthenticationChallenge
) {
265 CFStringRef cf_user
= CFStringCreateWithCString(kCFAllocatorDefault
, user
, kCFStringEncodingUTF8
);
266 CFStringRef cf_pass
= CFStringCreateWithCString(kCFAllocatorDefault
, pass
, kCFStringEncodingUTF8
);
267 CFHTTPMessageAddAuthentication(request
, responseHeaders
, cf_user
, cf_pass
, NULL
, false);
268 CFReleaseSafe(cf_pass
);
269 CFReleaseSafe(cf_user
);
271 CFRelease(responseHeaders
);
273 return isAuthenticationChallenge
;
276 static CF_RETURNS_RETAINED CFHTTPMessageRef
load_request(CFHTTPMessageRef request
, CFMutableDataRef data
, int retry
)
278 CFHTTPMessageRef result
= NULL
;
284 rs
= CFReadStreamCreateForHTTPRequest(NULL
, request
);
286 const void *keys
[] = {
287 kCFStreamSSLValidatesCertificateChain
,
288 // kCFStreamSSLCertificates,
290 //CFArrayRef ident = mit_identity();
291 const void *values
[] = {
296 CFDictionaryRef dict
= CFDictionaryCreate(NULL
, keys
, values
,
298 &kCFTypeDictionaryKeyCallBacks
,
299 &kCFTypeDictionaryValueCallBacks
);
300 CFReadStreamSetProperty(rs
, kCFStreamPropertySSLSettings
, dict
);
302 CFReadStreamSetProperty(rs
, kCFStreamPropertyHTTPAttemptPersistentConnection
, kCFBooleanTrue
);
304 if (CFReadStreamOpen(rs
)) {
306 if (auth_failed(request
, rs
)) {
307 CFReadStreamClose(rs
);
308 CFDataSetLength(data
, 0);
311 return load_request(request
, data
, retry
- 1);
316 CFIndex bytesRead
= CFReadStreamRead(rs
, buf
, BUFSIZE
);
318 CFDataAppendBytes(data
, buf
, bytesRead
);
319 } else if (bytesRead
== 0) {
321 result
= (CFHTTPMessageRef
)CFReadStreamCopyProperty(rs
, kCFStreamPropertyHTTPResponseHeader
);
332 CFReadStreamClose(rs
);
340 static CF_RETURNS_RETAINED CFDictionaryRef
get_encrypted_profile_packet(CFStringRef base_url
)
343 SecCertificateRef cert
= SecCertificateCreateWithBytes(NULL
,
344 device_cert_der
, device_cert_der_len
);
345 SecKeyRef key
= SecKeyCreateRSAPrivateKey(NULL
,
346 device_key
, device_key_len
, kSecKeyEncodingPkcs1
);
347 SecIdentityRef identity
= SecIdentityCreate(kCFAllocatorDefault
, cert
, key
);
351 SecIdentityRef identity
= lockdown_copy_device_identity();
354 CFMutableDictionaryRef machine_dict
= CFDictionaryCreateMutable(kCFAllocatorDefault
,
355 0, &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
356 CFDictionarySetValue(machine_dict
, CFSTR("UDID"), CFSTR("f1f50f8122fb10146f65e90380176342add6a85c"));
357 CFStringRef cf_user
= CFStringCreateWithCString(kCFAllocatorDefault
, user
, kCFStringEncodingUTF8
);
359 CFDictionarySetValue(machine_dict
, CFSTR("USERNAME"), cf_user
);
362 CFStringRef cf_pass
= CFStringCreateWithCString(kCFAllocatorDefault
, pass
, kCFStringEncodingUTF8
);
364 CFDictionarySetValue(machine_dict
, CFSTR("PASSWORD"), cf_pass
);
367 CFDataRef machine_dict_data
= CFPropertyListCreateXMLData(kCFAllocatorDefault
,
368 (CFPropertyListRef
)machine_dict
);
369 CFMutableDataRef signed_data
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
370 if (SecCMSSignDataAndAttributes(identity
, machine_dict_data
, false, signed_data
, NULL
))
371 errx(1, "failed to sign data");
373 CFRelease(machine_dict_data
);
374 CFRelease(machine_dict
);
376 CFURLRef url
= build_url(base_url
, NULL
);
377 CFHTTPMessageRef request
= CFHTTPMessageCreateRequest(kCFAllocatorDefault
,
378 CFSTR("POST"), url
, kCFHTTPVersion1_1
);
380 CFHTTPMessageSetBody(request
, signed_data
);
381 CFRelease(signed_data
);
382 CFHTTPMessageSetHeaderFieldValue(request
, CFSTR("Content-Type"),
383 CFSTR("application/pkcs7-signature"));
384 CFMutableDataRef data
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
385 CFHTTPMessageRef response
= load_request(request
, data
, 1);
388 CFErrorRef error
= NULL
;
389 CFTypeRef result
= CFPropertyListCreateWithData(kCFAllocatorDefault
,
390 data
, kCFPropertyListImmutable
, NULL
, &error
);
394 errx(1, "failed to decode encrypted profile response");
396 if (CFGetTypeID(result
) != CFDictionaryGetTypeID())
397 CFReleaseNull(result
);
398 return (CFDictionaryRef
)result
;
401 static SecCertificateRef
get_ca_cert(CFStringRef scep_base_url
, CFStringRef scep_ca_name
)
403 SecCertificateRef cert
= NULL
;
404 CFMutableDataRef data
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
406 CFURLRef url
= scep_url_operation(scep_base_url
, CFSTR("GetCACert"), scep_ca_name
);
407 CFHTTPMessageRef request
= CFHTTPMessageCreateRequest(kCFAllocatorDefault
,
408 CFSTR("GET"), url
, kCFHTTPVersion1_1
);
410 CFHTTPMessageRef result
= load_request(request
, data
, 1);
411 CFReleaseSafe(request
);
417 CFStringRef contentTypeValue
= CFHTTPMessageCopyHeaderFieldValue(result
, CFSTR("Content-Type"));
418 CFReleaseSafe(result
);
419 // CFHTTPMessageRef response = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, false);
420 // CFHTTPMessageAppendBytes(response, CFDataGetBytePtr(data), CFDataGetLength(data));
421 // CFDataRef bodyValue = CFHTTPMessageCopyBody(response);
422 if (kCFCompareEqualTo
== CFStringCompare(CFSTR("application/x-x509-ca-cert"),
423 contentTypeValue
, kCFCompareCaseInsensitive
)) {
424 // CA only response: application/x-x509-ca-cert
425 cert
= SecCertificateCreateWithData(kCFAllocatorDefault
, data
);
427 write_data("/tmp/ca_cert.der", data
);
428 } else if (kCFCompareEqualTo
== CFStringCompare(CFSTR("application/x-x509-ca-ra-cert"),
429 contentTypeValue
, kCFCompareCaseInsensitive
)) {
430 // RA/CA response: application/x-x509-ca-ra-cert
431 CFArrayRef cert_array
= SecCMSCertificatesOnlyMessageCopyCertificates(data
);
433 write_data("/tmp/ca_cert_array.der", data
);
434 cert
= (SecCertificateRef
)CFArrayGetValueAtIndex(cert_array
, 0);
436 CFRelease(cert_array
);
438 CFRelease(contentTypeValue
);
444 static SecIdentityRef
perform_scep(CFDictionaryRef scep_dict
)
446 SecIdentityRef identity
= NULL
;
447 CFDictionaryRef parameters
= NULL
, csr_parameters
= NULL
;
448 CFStringRef scep_base_url
= NULL
, scep_instance_name
= NULL
,
449 scep_challenge
= NULL
;
451 CFStringRef scep_subject
= NULL
, scep_subject_requested
= NULL
;
453 CFTypeRef scep_key_bitsize
= NULL
;
454 CFNumberRef key_usage_num
= NULL
;
455 SecCertificateRef ca_cert
= NULL
;
456 const void *keygen_keys
[] = { kSecAttrKeyType
, kSecAttrKeySizeInBits
};
457 const void *keygen_vals
[] = { kSecAttrKeyTypeRSA
, CFSTR("512") };
459 require(valid_cf_obj(scep_dict
,CFDictionaryGetTypeID()), out
);
460 require(scep_base_url
=
461 dict_get_value_of_type(scep_dict
, CFSTR("URL"), CFStringGetTypeID()), out
);
462 require(scep_instance_name
=
463 dict_get_value_of_type(scep_dict
, CFSTR("NAME"), CFStringGetTypeID()), out
);
464 require(scep_challenge
=
465 dict_get_value_of_type(scep_dict
, CFSTR("CHALLENGE"), CFStringGetTypeID()), out
);
468 dict_get_value_of_type(scep_dict
, CFSTR("KEYSIZE"), CFNumberGetTypeID());
469 if (!scep_key_bitsize
)
471 dict_get_value_of_type(scep_dict
, CFSTR("KEYSIZE"), CFStringGetTypeID());
472 if (scep_key_bitsize
)
473 keygen_vals
[1] = scep_key_bitsize
;
475 parameters
= CFDictionaryCreate(kCFAllocatorDefault
,
476 keygen_keys
, keygen_vals
, array_size(keygen_vals
),
477 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
479 int key_usage
= kSecKeyUsageDigitalSignature
| kSecKeyUsageKeyEncipherment
;
480 key_usage_num
= CFNumberCreate(kCFAllocatorDefault
, kCFNumberIntType
, &key_usage
);
482 ca_cert
= get_ca_cert(scep_base_url
, scep_instance_name
? scep_instance_name
: CFSTR("test"));
484 errx(1, "no ca cert returned from scep server.");
488 errx(1, "failed to get identity from scep server.");
492 CFReleaseSafe(ca_cert
);
493 CFReleaseSafe(key_usage_num
);
494 CFReleaseSafe(csr_parameters
);
495 CFReleaseSafe(parameters
);
499 static CFDataRef
copy_profile(CFStringRef url_cfstring
, SecIdentityRef identity
)
502 CFHTTPMessageRef request
= NULL
;
503 SecCertificateRef cert
= NULL
;
504 CFDataRef cert_data
= NULL
;
505 CFMutableDataRef data
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
506 CFHTTPMessageRef response
= NULL
;
508 require(url
= CFURLCreateWithString(kCFAllocatorDefault
, url_cfstring
, NULL
), out
);
509 require(request
= CFHTTPMessageCreateRequest(kCFAllocatorDefault
,
510 CFSTR("POST"), url
, kCFHTTPVersion1_1
), out
);
511 require_noerr(SecIdentityCopyCertificate(identity
, &cert
), out
);
512 require(cert_data
= SecCertificateCopyData(cert
), out
);
513 CFHTTPMessageSetBody(request
, cert_data
);
514 // this is technically the wrong mimetype; we'll probably switch to signed data
515 CFHTTPMessageSetHeaderFieldValue(request
, CFSTR("Content-Type"), CFSTR("application/x-x509-ca-cert"));
516 response
= load_request(request
, data
, 1);
520 //CFReleaseSafe(response);
521 CFReleaseSafe(request
);
523 CFReleaseSafe(cert_data
);
525 CFReleaseSafe(response
);
530 static bool validate_profile(CFDataRef profile_plist_data
, SecIdentityRef identity
)
532 CFStringRef type
= NULL
, uuid
= NULL
;
533 CFMutableDataRef dec_data
= NULL
;
534 CFDataRef enc_payload
= NULL
;
536 CFTypeRef result
= CFPropertyListCreateWithData(kCFAllocatorDefault
,
537 profile_plist_data
, kCFPropertyListImmutable
, NULL
, NULL
);
538 require(valid_cf_obj(result
, CFDictionaryGetTypeID()), out
);
539 require(type
= dict_get_value_of_type(result
, CFSTR("PayloadType"),
540 CFStringGetTypeID()), out
);
541 require(uuid
= dict_get_value_of_type(result
, CFSTR("PayloadUUID"),
542 CFStringGetTypeID()), out
);
543 enc_payload
= dict_get_value_of_type(result
, CFSTR("EncryptedPayloadContent"),
546 dec_data
= CFDataCreateMutable(kCFAllocatorDefault
, 0);
547 require_noerr(SecCMSDecryptEnvelopedData(enc_payload
, dec_data
, NULL
), out
);
548 ok
= validate_profile(dec_data
, identity
);
552 write_data("/tmp/unencrypted_profile.mobileconfig", profile_plist_data
);
553 //CFDictionaryRef sub_conf = dict_get_value_of_type(result, CFSTR("PayloadContent"), CFDictionaryGetTypeID());
556 CFReleaseSafe(dec_data
);
557 CFReleaseSafe(result
);
562 static const char *auth
= "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
563 <!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/\n\
564 PropertyList-1.0.dtd\">\n\
565 <plist version=\"1.0\">\n\
567 <key>PayloadContent</key>\n\
570 <string>https://phone.vpn.apple.com/deviceid/</string>\n\
571 <key>DeviceAttributes</key>\n\
573 <string>UDID</string>\n\
574 <string>VERSION</string>\n\
575 <string>MAC_ADDRESS_EN0</string>\n\
576 <string>MAC_ADDRESS_IP0</string>\n\
578 <key>CHALLENGE</key>\n\
579 <string>${USER_COOKIE}</string>\n\
581 <key>PayloadType</key>\n\
582 <string>Device Identification</string>\n\
586 static void annotate_machine_info(const void *value
, void *context
)
588 CFDictionaryRef machine_dict
= NULL
;
589 CFStringRef machine_key
= NULL
;
590 require(machine_dict
= (CFDictionaryRef
)valid_cf_obj(context
,
591 CFDictionaryGetTypeID()), out
);
592 require(machine_key
= (CFStringRef
)valid_cf_obj((CFTypeRef
)value
,
593 CFStringGetTypeID()), out
);
594 if (CFEqual(machine_key
, CFSTR("UDID"))) {
601 static void machine_authentication(CFDataRef req
, CFDataRef reply
)
603 CFDataRef machine_auth_request
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
,
604 (uint8_t*)auth
, strlen(auth
), kCFAllocatorNull
);
605 CFDictionaryRef auth_dict
= NULL
;
606 CFMutableDictionaryRef auth_reply_dict
=
607 CFDictionaryCreateMutable(kCFAllocatorDefault
, 0,
608 &kCFTypeDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
610 if (req
) { CFRelease(machine_auth_request
); machine_auth_request
= req
; CFRetain(req
); }
611 CFDictionaryRef auth_request_dict
= CFPropertyListCreateWithData(kCFAllocatorDefault
,
612 machine_auth_request
, kCFPropertyListImmutable
, NULL
, NULL
);
614 require(auth_reply_dict
, out
);
615 require(valid_cf_obj(auth_request_dict
, CFDictionaryGetTypeID()), out
);
616 require(auth_dict
= dict_get_value_of_type(auth_request_dict
, CFSTR("PayloadContent"), CFDictionaryGetTypeID()), out
);
617 CFStringRef challenge
= dict_get_value_of_type(auth_dict
, CFSTR("CHALLENGE"), CFStringGetTypeID());
619 CFDictionarySetValue(auth_reply_dict
, CFSTR("CHALLENGE"), challenge
);
620 CFArrayRef device_info
= dict_get_value_of_type(auth_dict
, CFSTR("DeviceAttributes"), CFArrayGetTypeID());
622 CFArrayApplyFunction(device_info
, CFRangeMake(0, CFArrayGetCount(device_info
)),
623 annotate_machine_info
, auth_reply_dict
);
625 // make copy of reply dict
627 CFReleaseSafe(machine_auth_request
);
628 CFReleaseSafe(auth_request_dict
);
632 extern int command_spc(int argc
, char * const *argv
)
634 SecIdentityRef identity
= NULL
;
638 while ((arg
= getopt(argc
, argv
, "du:p:")) != -1) {
651 return SHOW_USAGE_MESSAGE
;
660 // get plist from argv[0] url
661 } else if (argc
== 0) {
662 machine_authentication(NULL
, NULL
);
663 } else return SHOW_USAGE_MESSAGE
;
667 return SHOW_USAGE_MESSAGE
;
670 CFDictionaryRef dict
= NULL
;
671 CFDictionaryRef scep_config
= NULL
;
672 CFDictionaryRef payload_content
= NULL
;
673 CFStringRef profile_url
= NULL
;
674 CFDataRef profile_data
= NULL
;
675 CFDataRef profile_plist
= NULL
;
676 CFStringRef machine_id_url_cfstring
= CFStringCreateWithCString(kCFAllocatorDefault
,
677 argv
[0], kCFStringEncodingUTF8
);
678 CFDictionaryRef enroll_packet
=
679 get_encrypted_profile_packet(machine_id_url_cfstring
);
680 require(enroll_packet
&& CFGetTypeID(enroll_packet
) == CFDictionaryGetTypeID(), out
);
681 //require(payload_type(enroll_packet, "Encrypted Profile Service"), out);
682 require(payload_content
= dict_get_value_of_type(enroll_packet
,
683 CFSTR("PayloadContent"), CFDictionaryGetTypeID()), out
);
684 require(scep_config
= dict_get_value_of_type(payload_content
,
685 CFSTR("SCEP"), CFDictionaryGetTypeID()), out
);
686 require(identity
= perform_scep(scep_config
), out
);
687 dict
= CFDictionaryCreate(NULL
, (const void **)&kSecValueRef
, (const void **)&identity
, 1, NULL
, NULL
);
688 require_noerr(SecItemAdd(dict
, NULL
), out
);
690 require(profile_url
= dict_get_value_of_type(payload_content
,
691 CFSTR("URL"), CFStringGetTypeID()), out
);
693 require(profile_data
= copy_profile(profile_url
, identity
), out
);
695 write_data("/tmp/profile.mobileconfig", profile_data
);
697 require_noerr(SecCMSVerify(profile_data
, NULL
, NULL
, NULL
, &profile_plist
), out
);
698 CFReleaseNull(profile_data
);
699 require(profile_plist
, out
);
700 require(validate_profile(profile_plist
, identity
), out
);
705 CFReleaseSafe(identity
);
706 CFReleaseSafe(enroll_packet
);
707 CFReleaseSafe(profile_data
);
708 CFReleaseSafe(profile_plist
);
709 CFReleaseSafe(machine_id_url_cfstring
);
717 #endif // TARGET_OS_EMBEDDED