]> git.saurik.com Git - apple/security.git/blob - OSX/sec/Security/Tool/spc.c
Security-57740.60.18.tar.gz
[apple/security.git] / OSX / sec / Security / Tool / 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_EMBEDDED
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 CFStringRef format;
220 if (CFStringGetLength(query_string) > 1)
221 format = CFSTR("&%@=%@");
222 else
223 format = CFSTR("%@=%@");
224
225 CFStringAppendFormat(query_string, NULL, format, escaped_key, escaped_value);
226 CFRelease(escaped_key);
227 CFRelease(escaped_value);
228 }
229
230 static CF_RETURNS_RETAINED CFURLRef build_url(CFStringRef base, CFDictionaryRef info)
231 {
232 CFURLRef url = NULL, base_url = NULL;
233 CFMutableStringRef query_string =
234 CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("?"));
235 require(query_string, out);
236 if (info)
237 CFDictionaryApplyFunction(info, _query_string_apply, query_string);
238 base_url = CFURLCreateWithString(kCFAllocatorDefault, base, NULL);
239 url = CFURLCreateWithString(kCFAllocatorDefault, query_string, base_url);
240 out:
241 CFReleaseSafe(query_string);
242 CFReleaseSafe(base_url);
243 return url;
244 }
245
246 static CF_RETURNS_RETAINED CFURLRef scep_url_operation(CFStringRef base, CFStringRef operation, CFStringRef message)
247 {
248 CFURLRef url = NULL;
249 const void *keys[] = { CFSTR("operation"), CFSTR("message") };
250 const void *values[] = { operation, message };
251
252 require(operation, out);
253 CFDictionaryRef dict = CFDictionaryCreate(NULL, keys, values, message ? 2 : 1, NULL, NULL);
254 url = build_url(base, dict);
255 CFRelease(dict);
256 out:
257 return url;
258 }
259
260 static bool auth_failed(CFHTTPMessageRef request, CFReadStreamRef readStream)
261 {
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);
271 CFReleaseSafe(cf_pass);
272 CFReleaseSafe(cf_user);
273 }
274 CFRelease(responseHeaders);
275 }
276 return isAuthenticationChallenge;
277 }
278
279 static CF_RETURNS_RETAINED CFHTTPMessageRef load_request(CFHTTPMessageRef request, CFMutableDataRef data, int retry)
280 {
281 CFHTTPMessageRef result = NULL;
282
283 if (retry < 0)
284 return result;
285
286 CFReadStreamRef rs;
287 rs = CFReadStreamCreateForHTTPRequest(NULL, request);
288
289 const void *keys[] = {
290 kCFStreamSSLValidatesCertificateChain,
291 // kCFStreamSSLCertificates,
292 };
293 //CFArrayRef ident = mit_identity();
294 const void *values[] = {
295 kCFBooleanFalse,
296 // ident,
297 };
298
299 CFDictionaryRef dict = CFDictionaryCreate(NULL, keys, values,
300 array_size(keys),
301 &kCFTypeDictionaryKeyCallBacks,
302 &kCFTypeDictionaryValueCallBacks);
303 CFReadStreamSetProperty(rs, kCFStreamPropertySSLSettings, dict);
304 CFRelease(dict);
305 CFReadStreamSetProperty(rs, kCFStreamPropertyHTTPAttemptPersistentConnection, kCFBooleanTrue);
306
307 if (CFReadStreamOpen(rs)) {
308 do {
309 if (auth_failed(request, rs)) {
310 CFReadStreamClose(rs);
311 CFDataSetLength(data, 0);
312 if (retry) {
313 CFReleaseSafe(rs);
314 return load_request(request, data, retry - 1);
315 }
316 break;
317 }
318 UInt8 buf[BUFSIZE];
319 CFIndex bytesRead = CFReadStreamRead(rs, buf, BUFSIZE);
320 if (bytesRead > 0) {
321 CFDataAppendBytes(data, buf, bytesRead);
322 } else if (bytesRead == 0) {
323 // Success
324 result = (CFHTTPMessageRef)CFReadStreamCopyProperty(rs, kCFStreamPropertyHTTPResponseHeader);
325 break;
326 } else {
327 // Error
328 break;
329 }
330 } while (true);
331 } else {
332 // Error
333 }
334
335 CFReadStreamClose(rs);
336 CFRelease(rs);
337 if (debug)
338 CFShow(result);
339 return result;
340 }
341
342
343 static CF_RETURNS_RETAINED CFDictionaryRef get_encrypted_profile_packet(CFStringRef base_url)
344 {
345 #if 1
346 SecCertificateRef cert = SecCertificateCreateWithBytes(NULL,
347 device_cert_der, device_cert_der_len);
348 SecKeyRef key = SecKeyCreateRSAPrivateKey(NULL,
349 device_key, device_key_len, kSecKeyEncodingPkcs1);
350 SecIdentityRef identity = SecIdentityCreate(kCFAllocatorDefault, cert, key);
351 CFRelease(cert);
352 CFRelease(key);
353 #else
354 SecIdentityRef identity = lockdown_copy_device_identity();
355 #endif
356
357 CFMutableDictionaryRef machine_dict = CFDictionaryCreateMutable(kCFAllocatorDefault,
358 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
359 CFDictionarySetValue(machine_dict, CFSTR("UDID"), CFSTR("f1f50f8122fb10146f65e90380176342add6a85c"));
360 CFStringRef cf_user = CFStringCreateWithCString(kCFAllocatorDefault, user, kCFStringEncodingUTF8);
361 if (cf_user) {
362 CFDictionarySetValue(machine_dict, CFSTR("USERNAME"), cf_user);
363 CFRelease(cf_user);
364 }
365 CFStringRef cf_pass = CFStringCreateWithCString(kCFAllocatorDefault, pass, kCFStringEncodingUTF8);
366 if (cf_pass) {
367 CFDictionarySetValue(machine_dict, CFSTR("PASSWORD"), cf_pass);
368 CFRelease(cf_pass);
369 }
370 CFDataRef machine_dict_data = CFPropertyListCreateXMLData(kCFAllocatorDefault,
371 (CFPropertyListRef)machine_dict);
372 CFMutableDataRef signed_data = CFDataCreateMutable(kCFAllocatorDefault, 0);
373 if (SecCMSSignDataAndAttributes(identity, machine_dict_data, false, signed_data, NULL))
374 errx(1, "failed to sign data");
375 CFRelease(identity);
376 CFRelease(machine_dict_data);
377 CFRelease(machine_dict);
378
379 CFURLRef url = build_url(base_url, NULL);
380 CFHTTPMessageRef request = CFHTTPMessageCreateRequest(kCFAllocatorDefault,
381 CFSTR("POST"), url, kCFHTTPVersion1_1);
382 CFRelease(url);
383 CFHTTPMessageSetBody(request, signed_data);
384 CFRelease(signed_data);
385 CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Content-Type"),
386 CFSTR("application/pkcs7-signature"));
387 CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0);
388 CFHTTPMessageRef response = load_request(request, data, 1);
389 CFRelease(request);
390 CFRelease(response);
391 CFErrorRef error = NULL;
392 CFTypeRef result = CFPropertyListCreateWithData(kCFAllocatorDefault,
393 data, kCFPropertyListImmutable, NULL, &error);
394 CFRelease(data);
395 if (error) {
396 CFShow(error);
397 errx(1, "failed to decode encrypted profile response");
398 }
399 if (CFGetTypeID(result) != CFDictionaryGetTypeID())
400 CFReleaseNull(result);
401 return (CFDictionaryRef)result;
402 }
403
404 static SecCertificateRef get_ca_cert(CFStringRef scep_base_url, CFStringRef scep_ca_name)
405 {
406 SecCertificateRef cert = NULL;
407 CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0);
408
409 CFURLRef url = scep_url_operation(scep_base_url, CFSTR("GetCACert"), scep_ca_name);
410 CFHTTPMessageRef request = CFHTTPMessageCreateRequest(kCFAllocatorDefault,
411 CFSTR("GET"), url, kCFHTTPVersion1_1);
412 CFReleaseSafe(url);
413 CFHTTPMessageRef result = load_request(request, data, 1);
414 CFReleaseSafe(request);
415
416 if (!result) {
417 CFReleaseSafe(data);
418 return NULL;
419 }
420 CFStringRef contentTypeValue = CFHTTPMessageCopyHeaderFieldValue(result, CFSTR("Content-Type"));
421 CFReleaseSafe(result);
422 // CFHTTPMessageRef response = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, false);
423 // CFHTTPMessageAppendBytes(response, CFDataGetBytePtr(data), CFDataGetLength(data));
424 // CFDataRef bodyValue = CFHTTPMessageCopyBody(response);
425 if (kCFCompareEqualTo == CFStringCompare(CFSTR("application/x-x509-ca-cert"),
426 contentTypeValue, kCFCompareCaseInsensitive)) {
427 // CA only response: application/x-x509-ca-cert
428 cert = SecCertificateCreateWithData(kCFAllocatorDefault, data);
429 if (debug)
430 write_data("/tmp/ca_cert.der", data);
431 } else if (kCFCompareEqualTo == CFStringCompare(CFSTR("application/x-x509-ca-ra-cert"),
432 contentTypeValue, kCFCompareCaseInsensitive)) {
433 // RA/CA response: application/x-x509-ca-ra-cert
434 CFArrayRef cert_array = SecCMSCertificatesOnlyMessageCopyCertificates(data);
435 if (debug)
436 write_data("/tmp/ca_cert_array.der", data);
437 cert = (SecCertificateRef)CFArrayGetValueAtIndex(cert_array, 0);
438 CFRetain(cert);
439 CFRelease(cert_array);
440 }
441 CFRelease(contentTypeValue);
442 CFRelease(data);
443 return cert;
444 }
445
446
447 static SecIdentityRef perform_scep(CFDictionaryRef scep_dict)
448 {
449 SecIdentityRef identity = NULL;
450 CFDictionaryRef parameters = NULL, csr_parameters = NULL;
451 CFStringRef scep_base_url = NULL, scep_instance_name = NULL,
452 scep_challenge = NULL, 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") };
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_subject_requested =
468 dict_get_value_of_type(scep_dict, CFSTR("SUBJECT"), CFStringGetTypeID());
469 if (scep_subject_requested) {
470 CFArrayRef scep_subject_components =
471 CFStringCreateArrayBySeparatingStrings(kCFAllocatorDefault,
472 scep_subject_requested, CFSTR("="));
473 if (CFArrayGetCount(scep_subject_components) == 2)
474 scep_subject = CFArrayGetValueAtIndex(scep_subject_components, 1);
475 }
476
477 scep_key_bitsize =
478 dict_get_value_of_type(scep_dict, CFSTR("KEYSIZE"), CFNumberGetTypeID());
479 if (!scep_key_bitsize)
480 scep_key_bitsize =
481 dict_get_value_of_type(scep_dict, CFSTR("KEYSIZE"), CFStringGetTypeID());
482 if (scep_key_bitsize)
483 keygen_vals[1] = scep_key_bitsize;
484
485 parameters = CFDictionaryCreate(kCFAllocatorDefault,
486 keygen_keys, keygen_vals, array_size(keygen_vals),
487 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
488
489 int key_usage = kSecKeyUsageDigitalSignature | kSecKeyUsageKeyEncipherment;
490 key_usage_num = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &key_usage);
491 const void *key[] = { kSecCSRChallengePassword, kSecCertificateKeyUsage };
492 const void *val[] = { scep_challenge ? scep_challenge : CFSTR("magic"), key_usage_num };
493 csr_parameters = CFDictionaryCreate(kCFAllocatorDefault, key, val, array_size(key), NULL, NULL);
494
495 ca_cert = get_ca_cert(scep_base_url, scep_instance_name ? scep_instance_name : CFSTR("test"));
496 if (!ca_cert)
497 errx(1, "no ca cert returned from scep server.");
498
499 identity = NULL; // enroll_scep(scep_base_url, scep_subject, csr_parameters, parameters, ca_cert);
500 if (!identity)
501 errx(1, "failed to get identity from scep server.");
502
503
504 out:
505 CFReleaseSafe(ca_cert);
506 CFReleaseSafe(scep_subject);
507 CFReleaseSafe(key_usage_num);
508 CFReleaseSafe(csr_parameters);
509 CFReleaseSafe(parameters);
510 return identity;
511 }
512
513 static CFDataRef CF_RETURNS_RETAINED get_profile(CFStringRef url_cfstring, SecIdentityRef identity)
514 {
515 CFURLRef url = NULL;
516 CFHTTPMessageRef request = NULL;
517 SecCertificateRef cert = NULL;
518 CFDataRef cert_data = NULL;
519 CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0);
520 CFHTTPMessageRef response = NULL;
521
522 require(url = CFURLCreateWithString(kCFAllocatorDefault, url_cfstring, NULL), out);
523 require(request = CFHTTPMessageCreateRequest(kCFAllocatorDefault,
524 CFSTR("POST"), url, kCFHTTPVersion1_1), out);
525 require_noerr(SecIdentityCopyCertificate(identity, &cert), out);
526 require(cert_data = SecCertificateCopyData(cert), out);
527 CFHTTPMessageSetBody(request, cert_data);
528 // this is technically the wrong mimetype; we'll probably switch to signed data
529 CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Content-Type"), CFSTR("application/x-x509-ca-cert"));
530 response = load_request(request, data, 1);
531 if (debug && data)
532 CFShow(data);
533 out:
534 //CFReleaseSafe(response);
535 CFReleaseSafe(request);
536 CFReleaseSafe(url);
537 CFReleaseSafe(cert_data);
538 CFReleaseSafe(cert);
539 CFReleaseSafe(response);
540 return data;
541
542 }
543
544 static bool validate_profile(CFDataRef profile_plist_data, SecIdentityRef identity)
545 {
546 CFStringRef type = NULL, uuid = NULL;
547 CFMutableDataRef dec_data = NULL;
548 CFDataRef enc_payload = NULL;
549 bool ok = false;
550 CFTypeRef result = CFPropertyListCreateWithData(kCFAllocatorDefault,
551 profile_plist_data, kCFPropertyListImmutable, NULL, NULL);
552 require(valid_cf_obj(result, CFDictionaryGetTypeID()), out);
553 require(type = dict_get_value_of_type(result, CFSTR("PayloadType"),
554 CFStringGetTypeID()), out);
555 require(uuid = dict_get_value_of_type(result, CFSTR("PayloadUUID"),
556 CFStringGetTypeID()), out);
557 enc_payload = dict_get_value_of_type(result, CFSTR("EncryptedPayloadContent"),
558 CFDataGetTypeID());
559 if (enc_payload) {
560 dec_data = CFDataCreateMutable(kCFAllocatorDefault, 0);
561 require_noerr(SecCMSDecryptEnvelopedData(enc_payload, dec_data, NULL), out);
562 ok = validate_profile(dec_data, identity);
563 } else {
564 ok = true;
565 if (debug)
566 write_data("/tmp/unencrypted_profile.mobileconfig", profile_plist_data);
567 //CFDictionaryRef sub_conf = dict_get_value_of_type(result, CFSTR("PayloadContent"), CFDictionaryGetTypeID());
568 }
569 out:
570 CFReleaseSafe(dec_data);
571 CFReleaseSafe(result);
572 return ok;
573 }
574
575 #if 0
576 static const char *auth = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
577 <!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/\n\
578 PropertyList-1.0.dtd\">\n\
579 <plist version=\"1.0\">\n\
580 <dict>\n\
581 <key>PayloadContent</key>\n\
582 <dict>\n\
583 <key>URL</key>\n\
584 <string>https://phone.vpn.apple.com/deviceid/</string>\n\
585 <key>DeviceAttributes</key>\n\
586 <array>\n\
587 <string>UDID</string>\n\
588 <string>VERSION</string>\n\
589 <string>MAC_ADDRESS_EN0</string>\n\
590 <string>MAC_ADDRESS_IP0</string>\n\
591 </array>\n\
592 <key>CHALLENGE</key>\n\
593 <string>${USER_COOKIE}</string>\n\
594 </dict>\n\
595 <key>PayloadType</key>\n\
596 <string>Device Identification</string>\n\
597 </dict>\n\
598 </plist>\n";
599
600 static void annotate_machine_info(const void *value, void *context)
601 {
602 CFDictionaryRef machine_dict = NULL;
603 CFStringRef machine_key = NULL;
604 require(machine_dict = (CFDictionaryRef)valid_cf_obj(context,
605 CFDictionaryGetTypeID()), out);
606 require(machine_key = (CFStringRef)valid_cf_obj((CFTypeRef)value,
607 CFStringGetTypeID()), out);
608 if (CFEqual(machine_key, CFSTR("UDID"))) {
609
610 }
611 out:
612 return;
613 }
614
615 static void machine_authentication(CFDataRef req, CFDataRef reply)
616 {
617 CFDataRef machine_auth_request = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault,
618 (uint8_t*)auth, strlen(auth), kCFAllocatorNull);
619 CFDictionaryRef auth_dict = NULL;
620 CFMutableDictionaryRef auth_reply_dict =
621 CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
622 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
623
624 if (req) { CFRelease(machine_auth_request); machine_auth_request = req; CFRetain(req); }
625 CFDictionaryRef auth_request_dict = CFPropertyListCreateWithData(kCFAllocatorDefault,
626 machine_auth_request, kCFPropertyListImmutable, NULL, NULL);
627
628 require(auth_reply_dict, out);
629 require(valid_cf_obj(auth_request_dict, CFDictionaryGetTypeID()), out);
630 require(auth_dict = dict_get_value_of_type(auth_request_dict, CFSTR("PayloadContent"), CFDictionaryGetTypeID()), out);
631 CFStringRef challenge = dict_get_value_of_type(auth_dict, CFSTR("CHALLENGE"), CFStringGetTypeID());
632 if (challenge)
633 CFDictionarySetValue(auth_reply_dict, CFSTR("CHALLENGE"), challenge);
634 CFArrayRef device_info = dict_get_value_of_type(auth_dict, CFSTR("DeviceAttributes"), CFArrayGetTypeID());
635 if (device_info)
636 CFArrayApplyFunction(device_info, CFRangeMake(0, CFArrayGetCount(device_info)),
637 annotate_machine_info, auth_reply_dict);
638
639 // make copy of reply dict
640 out:
641 CFReleaseSafe(machine_auth_request);
642 CFReleaseSafe(auth_request_dict);
643 }
644 #endif
645
646 extern int command_spc(int argc, char * const *argv)
647 {
648 SecIdentityRef identity = NULL;
649 extern char *optarg;
650 extern int optind;
651 int arg;
652 while ((arg = getopt(argc, argv, "du:p:")) != -1) {
653 switch (arg) {
654 case 'd':
655 debug = 1;
656 break;
657 case 'u':
658 user = optarg;
659 break;
660 case 'p':
661 pass = optarg;
662 break;
663 case 'h':
664 default:
665 return 2;
666 }
667 }
668
669 argc -= optind;
670 argv += optind;
671
672 #if 0
673 if (argc == 1) {
674 // get plist from argv[0] url
675 } else if (argc == 0) {
676 machine_authentication(NULL, NULL);
677 } else return 2;
678 #endif
679
680 if (argc != 1)
681 return 2;
682
683 int result = -1;
684 CFDictionaryRef dict = NULL;
685 CFDictionaryRef scep_config = NULL;
686 CFDictionaryRef payload_content = NULL;
687 CFStringRef profile_url = NULL;
688 CFDataRef profile_data = NULL;
689 CFDataRef profile_plist = NULL;
690 CFStringRef machine_id_url_cfstring = CFStringCreateWithCString(kCFAllocatorDefault,
691 argv[0], kCFStringEncodingUTF8);
692 CFDictionaryRef enroll_packet =
693 get_encrypted_profile_packet(machine_id_url_cfstring);
694 require(enroll_packet && CFGetTypeID(enroll_packet) == CFDictionaryGetTypeID(), out);
695 //require(payload_type(enroll_packet, "Encrypted Profile Service"), out);
696 require(payload_content = dict_get_value_of_type(enroll_packet,
697 CFSTR("PayloadContent"), CFDictionaryGetTypeID()), out);
698 require(scep_config = dict_get_value_of_type(payload_content,
699 CFSTR("SCEP"), CFDictionaryGetTypeID()), out);
700 require(identity = perform_scep(scep_config), out);
701 dict = CFDictionaryCreate(NULL, (const void **)&kSecValueRef, (const void **)&identity, 1, NULL, NULL);
702 require_noerr(SecItemAdd(dict, NULL), out);
703 CFReleaseNull(dict);
704 require(profile_url = dict_get_value_of_type(payload_content,
705 CFSTR("URL"), CFStringGetTypeID()), out);
706
707 require(profile_data = get_profile(profile_url, identity), out);
708 if (debug)
709 write_data("/tmp/profile.mobileconfig", profile_data);
710
711 require_noerr(SecCMSVerify(profile_data, NULL, NULL, NULL, &profile_plist), out);
712 CFReleaseNull(profile_data);
713 require(profile_plist, out);
714 require(validate_profile(profile_plist, identity), out);
715
716 result = 0;
717 out:
718 CFReleaseSafe(dict);
719 CFReleaseSafe(identity);
720 CFReleaseSafe(enroll_packet);
721 CFReleaseSafe(profile_data);
722 CFReleaseSafe(profile_plist);
723 CFReleaseSafe(machine_id_url_cfstring);
724
725 if (result != 0)
726 errx(1, "fail.");
727 return result;
728 }
729
730
731 #endif // TARGET_OS_EMBEDDED