]> git.saurik.com Git - apple/security.git/blob - SecurityTool/sharedTool/spc.c
Security-59306.11.20.tar.gz
[apple/security.git] / SecurityTool / sharedTool / spc.c
1 /*
2 * Copyright (c) 2009-2010,2013-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
24 /*
25 * spc.c - Security
26 *
27 *
28 */
29
30 #include <TargetConditionals.h>
31 #if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
32
33 #include "SecurityCommands.h"
34
35 #include <CoreFoundation/CoreFoundation.h>
36 #include <AssertMacros.h>
37 #include <TargetConditionals.h>
38 #include <CFNetwork/CFNetwork.h>
39
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>
54 #include <err.h>
55 #include <stdio.h>
56 #include <getopt.h>
57
58 //static char *scep_url = "https://localhost:2000/cgi-bin/pkiclient.exe";
59 static char *user = "webuser";
60 static char *pass = "webpassowrd";
61 static int debug = 0;
62
63 #define BUFSIZE 1024
64
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
128 };
129 unsigned int device_cert_der_len = 739;
130
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
183 };
184 unsigned int device_key_len = 608;
185
186
187 static inline CFTypeRef valid_cf_obj(CFTypeRef obj, CFTypeID type)
188 {
189 if (obj && CFGetTypeID(obj) == type)
190 return obj;
191 return NULL;
192 }
193
194 static inline CFTypeRef dict_get_value_of_type(CFDictionaryRef dict, CFTypeRef key, CFTypeID value_type)
195 {
196 CFTypeRef value = CFDictionaryGetValue(dict, key);
197 return valid_cf_obj(value, value_type);
198 }
199
200 #include <fcntl.h>
201 static inline void write_data(const char * path, CFDataRef data)
202 {
203 int data_file = open(path, O_CREAT|O_WRONLY|O_TRUNC, 0644);
204 write(data_file, CFDataGetBytePtr(data), CFDataGetLength(data));
205 close(data_file);
206 printf("wrote intermediate result to: %s\n", path);
207 }
208
209 static void _query_string_apply(const void *key, const void *value, void *context)
210 {
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;
218
219 if (CFStringGetLength(query_string) > 1)
220 CFStringAppend(query_string, CFSTR("&"));
221
222 CFStringAppendFormat(query_string, NULL, CFSTR("%@=%@"), escaped_key, escaped_value);
223 CFRelease(escaped_key);
224 CFRelease(escaped_value);
225 }
226
227 static CF_RETURNS_RETAINED CFURLRef build_url(CFStringRef base, CFDictionaryRef info)
228 {
229 CFURLRef url = NULL, base_url = NULL;
230 CFMutableStringRef query_string =
231 CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("?"));
232 require(query_string, out);
233 if (info)
234 CFDictionaryApplyFunction(info, _query_string_apply, query_string);
235 base_url = CFURLCreateWithString(kCFAllocatorDefault, base, NULL);
236 url = CFURLCreateWithString(kCFAllocatorDefault, query_string, base_url);
237 out:
238 CFReleaseSafe(query_string);
239 CFReleaseSafe(base_url);
240 return url;
241 }
242
243 static CF_RETURNS_RETAINED CFURLRef scep_url_operation(CFStringRef base, CFStringRef operation, CFStringRef message)
244 {
245 CFURLRef url = NULL;
246 const void *keys[] = { CFSTR("operation"), CFSTR("message") };
247 const void *values[] = { operation, message };
248
249 require(operation, out);
250 CFDictionaryRef dict = CFDictionaryCreate(NULL, keys, values, message ? 2 : 1, NULL, NULL);
251 url = build_url(base, dict);
252 CFRelease(dict);
253 out:
254 return url;
255 }
256
257 static bool auth_failed(CFHTTPMessageRef request, CFReadStreamRef readStream)
258 {
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);
270 }
271 CFRelease(responseHeaders);
272 }
273 return isAuthenticationChallenge;
274 }
275
276 static CF_RETURNS_RETAINED CFHTTPMessageRef load_request(CFHTTPMessageRef request, CFMutableDataRef data, int retry)
277 {
278 CFHTTPMessageRef result = NULL;
279
280 if (retry < 0)
281 return result;
282
283 CFReadStreamRef rs;
284 rs = CFReadStreamCreateForHTTPRequest(NULL, request);
285
286 const void *keys[] = {
287 kCFStreamSSLValidatesCertificateChain,
288 // kCFStreamSSLCertificates,
289 };
290 //CFArrayRef ident = mit_identity();
291 const void *values[] = {
292 kCFBooleanFalse,
293 // ident,
294 };
295
296 CFDictionaryRef dict = CFDictionaryCreate(NULL, keys, values,
297 array_size(keys),
298 &kCFTypeDictionaryKeyCallBacks,
299 &kCFTypeDictionaryValueCallBacks);
300 CFReadStreamSetProperty(rs, kCFStreamPropertySSLSettings, dict);
301 CFRelease(dict);
302 CFReadStreamSetProperty(rs, kCFStreamPropertyHTTPAttemptPersistentConnection, kCFBooleanTrue);
303
304 if (CFReadStreamOpen(rs)) {
305 do {
306 if (auth_failed(request, rs)) {
307 CFReadStreamClose(rs);
308 CFDataSetLength(data, 0);
309 if (retry) {
310 CFReleaseSafe(rs);
311 return load_request(request, data, retry - 1);
312 }
313 break;
314 }
315 UInt8 buf[BUFSIZE];
316 CFIndex bytesRead = CFReadStreamRead(rs, buf, BUFSIZE);
317 if (bytesRead > 0) {
318 CFDataAppendBytes(data, buf, bytesRead);
319 } else if (bytesRead == 0) {
320 // Success
321 result = (CFHTTPMessageRef)CFReadStreamCopyProperty(rs, kCFStreamPropertyHTTPResponseHeader);
322 break;
323 } else {
324 // Error
325 break;
326 }
327 } while (true);
328 } else {
329 // Error
330 }
331
332 CFReadStreamClose(rs);
333 CFRelease(rs);
334 if (debug)
335 CFShow(result);
336 return result;
337 }
338
339
340 static CF_RETURNS_RETAINED CFDictionaryRef get_encrypted_profile_packet(CFStringRef base_url)
341 {
342 #if 1
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);
348 CFRelease(cert);
349 CFRelease(key);
350 #else
351 SecIdentityRef identity = lockdown_copy_device_identity();
352 #endif
353
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);
358 if (cf_user) {
359 CFDictionarySetValue(machine_dict, CFSTR("USERNAME"), cf_user);
360 CFRelease(cf_user);
361 }
362 CFStringRef cf_pass = CFStringCreateWithCString(kCFAllocatorDefault, pass, kCFStringEncodingUTF8);
363 if (cf_pass) {
364 CFDictionarySetValue(machine_dict, CFSTR("PASSWORD"), cf_pass);
365 CFRelease(cf_pass);
366 }
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");
372 CFRelease(identity);
373 CFRelease(machine_dict_data);
374 CFRelease(machine_dict);
375
376 CFURLRef url = build_url(base_url, NULL);
377 CFHTTPMessageRef request = CFHTTPMessageCreateRequest(kCFAllocatorDefault,
378 CFSTR("POST"), url, kCFHTTPVersion1_1);
379 CFRelease(url);
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);
386 CFRelease(request);
387 CFRelease(response);
388 CFErrorRef error = NULL;
389 CFTypeRef result = CFPropertyListCreateWithData(kCFAllocatorDefault,
390 data, kCFPropertyListImmutable, NULL, &error);
391 CFRelease(data);
392 if (error) {
393 CFShow(error);
394 errx(1, "failed to decode encrypted profile response");
395 }
396 if (CFGetTypeID(result) != CFDictionaryGetTypeID())
397 CFReleaseNull(result);
398 return (CFDictionaryRef)result;
399 }
400
401 static SecCertificateRef get_ca_cert(CFStringRef scep_base_url, CFStringRef scep_ca_name)
402 {
403 SecCertificateRef cert = NULL;
404 CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0);
405
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);
409 CFReleaseSafe(url);
410 CFHTTPMessageRef result = load_request(request, data, 1);
411 CFReleaseSafe(request);
412
413 if (!result) {
414 CFReleaseSafe(data);
415 return NULL;
416 }
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);
426 if (debug)
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);
432 if (debug)
433 write_data("/tmp/ca_cert_array.der", data);
434 cert = (SecCertificateRef)CFArrayGetValueAtIndex(cert_array, 0);
435 CFRetain(cert);
436 CFRelease(cert_array);
437 }
438 CFRelease(contentTypeValue);
439 CFRelease(data);
440 return cert;
441 }
442
443
444 static SecIdentityRef perform_scep(CFDictionaryRef scep_dict)
445 {
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;
450 #if 0
451 CFStringRef scep_subject = NULL, scep_subject_requested = NULL;
452 #endif
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") };
458
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);
466
467 scep_key_bitsize =
468 dict_get_value_of_type(scep_dict, CFSTR("KEYSIZE"), CFNumberGetTypeID());
469 if (!scep_key_bitsize)
470 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;
474
475 parameters = CFDictionaryCreate(kCFAllocatorDefault,
476 keygen_keys, keygen_vals, array_size(keygen_vals),
477 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
478
479 int key_usage = kSecKeyUsageDigitalSignature | kSecKeyUsageKeyEncipherment;
480 key_usage_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &key_usage);
481
482 ca_cert = get_ca_cert(scep_base_url, scep_instance_name ? scep_instance_name : CFSTR("test"));
483 if (!ca_cert)
484 errx(1, "no ca cert returned from scep server.");
485
486 identity = NULL;
487 if (!identity)
488 errx(1, "failed to get identity from scep server.");
489
490
491 out:
492 CFReleaseSafe(ca_cert);
493 CFReleaseSafe(key_usage_num);
494 CFReleaseSafe(csr_parameters);
495 CFReleaseSafe(parameters);
496 return identity;
497 }
498
499 static CFDataRef copy_profile(CFStringRef url_cfstring, SecIdentityRef identity)
500 {
501 CFURLRef url = NULL;
502 CFHTTPMessageRef request = NULL;
503 SecCertificateRef cert = NULL;
504 CFDataRef cert_data = NULL;
505 CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0);
506 CFHTTPMessageRef response = NULL;
507
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);
517 if (debug && data)
518 CFShow(data);
519 out:
520 //CFReleaseSafe(response);
521 CFReleaseSafe(request);
522 CFReleaseSafe(url);
523 CFReleaseSafe(cert_data);
524 CFReleaseSafe(cert);
525 CFReleaseSafe(response);
526 return data;
527
528 }
529
530 static bool validate_profile(CFDataRef profile_plist_data, SecIdentityRef identity)
531 {
532 CFStringRef type = NULL, uuid = NULL;
533 CFMutableDataRef dec_data = NULL;
534 CFDataRef enc_payload = NULL;
535 bool ok = false;
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"),
544 CFDataGetTypeID());
545 if (enc_payload) {
546 dec_data = CFDataCreateMutable(kCFAllocatorDefault, 0);
547 require_noerr(SecCMSDecryptEnvelopedData(enc_payload, dec_data, NULL), out);
548 ok = validate_profile(dec_data, identity);
549 } else {
550 ok = true;
551 if (debug)
552 write_data("/tmp/unencrypted_profile.mobileconfig", profile_plist_data);
553 //CFDictionaryRef sub_conf = dict_get_value_of_type(result, CFSTR("PayloadContent"), CFDictionaryGetTypeID());
554 }
555 out:
556 CFReleaseSafe(dec_data);
557 CFReleaseSafe(result);
558 return ok;
559 }
560
561 #if 0
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\
566 <dict>\n\
567 <key>PayloadContent</key>\n\
568 <dict>\n\
569 <key>URL</key>\n\
570 <string>https://phone.vpn.apple.com/deviceid/</string>\n\
571 <key>DeviceAttributes</key>\n\
572 <array>\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\
577 </array>\n\
578 <key>CHALLENGE</key>\n\
579 <string>${USER_COOKIE}</string>\n\
580 </dict>\n\
581 <key>PayloadType</key>\n\
582 <string>Device Identification</string>\n\
583 </dict>\n\
584 </plist>\n";
585
586 static void annotate_machine_info(const void *value, void *context)
587 {
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"))) {
595
596 }
597 out:
598 return;
599 }
600
601 static void machine_authentication(CFDataRef req, CFDataRef reply)
602 {
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);
609
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);
613
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());
618 if (challenge)
619 CFDictionarySetValue(auth_reply_dict, CFSTR("CHALLENGE"), challenge);
620 CFArrayRef device_info = dict_get_value_of_type(auth_dict, CFSTR("DeviceAttributes"), CFArrayGetTypeID());
621 if (device_info)
622 CFArrayApplyFunction(device_info, CFRangeMake(0, CFArrayGetCount(device_info)),
623 annotate_machine_info, auth_reply_dict);
624
625 // make copy of reply dict
626 out:
627 CFReleaseSafe(machine_auth_request);
628 CFReleaseSafe(auth_request_dict);
629 }
630 #endif
631
632 extern int command_spc(int argc, char * const *argv)
633 {
634 SecIdentityRef identity = NULL;
635 extern char *optarg;
636 extern int optind;
637 int arg;
638 while ((arg = getopt(argc, argv, "du:p:")) != -1) {
639 switch (arg) {
640 case 'd':
641 debug = 1;
642 break;
643 case 'u':
644 user = optarg;
645 break;
646 case 'p':
647 pass = optarg;
648 break;
649 case 'h':
650 default:
651 return SHOW_USAGE_MESSAGE;
652 }
653 }
654
655 argc -= optind;
656 argv += optind;
657
658 #if 0
659 if (argc == 1) {
660 // get plist from argv[0] url
661 } else if (argc == 0) {
662 machine_authentication(NULL, NULL);
663 } else return SHOW_USAGE_MESSAGE;
664 #endif
665
666 if (argc != 1)
667 return SHOW_USAGE_MESSAGE;
668
669 int result = -1;
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);
689 CFReleaseNull(dict);
690 require(profile_url = dict_get_value_of_type(payload_content,
691 CFSTR("URL"), CFStringGetTypeID()), out);
692
693 require(profile_data = copy_profile(profile_url, identity), out);
694 if (debug)
695 write_data("/tmp/profile.mobileconfig", profile_data);
696
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);
701
702 result = 0;
703 out:
704 CFReleaseSafe(dict);
705 CFReleaseSafe(identity);
706 CFReleaseSafe(enroll_packet);
707 CFReleaseSafe(profile_data);
708 CFReleaseSafe(profile_plist);
709 CFReleaseSafe(machine_id_url_cfstring);
710
711 if (result != 0)
712 errx(1, "fail.");
713 return result;
714 }
715
716
717 #endif // TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR