]> git.saurik.com Git - apple/security.git/blob - sec/Security/Tool/spc.c
Security-55471.14.8.tar.gz
[apple/security.git] / sec / Security / Tool / spc.c
1 /*
2 * Copyright (c) 2009-2010 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 * Created by Conrad Sauerwald on 1/9/09.
28 *
29 */
30
31 #include <TargetConditionals.h>
32 #if TARGET_OS_EMBEDDED
33
34 #include "SecurityCommands.h"
35
36 #include <CoreFoundation/CoreFoundation.h>
37 #include <AssertMacros.h>
38 #include <TargetConditionals.h>
39 #include <CFNetwork/CFNetwork.h>
40
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>
55 #include <err.h>
56 #include <stdio.h>
57 #include <getopt.h>
58
59 //static char *scep_url = "https://localhost:2000/cgi-bin/pkiclient.exe";
60 static char *user = "webuser";
61 static char *pass = "webpassowrd";
62 static int debug = 0;
63
64 #define BUFSIZE 1024
65
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
129 };
130 unsigned int device_cert_der_len = 739;
131
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
184 };
185 unsigned int device_key_len = 608;
186
187
188 static inline CFTypeRef valid_cf_obj(CFTypeRef obj, CFTypeID type)
189 {
190 if (obj && CFGetTypeID(obj) == type)
191 return obj;
192 return NULL;
193 }
194
195 static inline CFTypeRef dict_get_value_of_type(CFDictionaryRef dict, CFTypeRef key, CFTypeID value_type)
196 {
197 CFTypeRef value = CFDictionaryGetValue(dict, key);
198 return valid_cf_obj(value, value_type);
199 }
200
201 #include <fcntl.h>
202 static inline void write_data(const char * path, CFDataRef data)
203 {
204 int data_file = open(path, O_CREAT|O_WRONLY|O_TRUNC, 0644);
205 write(data_file, CFDataGetBytePtr(data), CFDataGetLength(data));
206 close(data_file);
207 printf("wrote intermediate result to: %s\n", path);
208 }
209
210 static void _query_string_apply(const void *key, const void *value, void *context)
211 {
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;
219
220 CFStringRef format;
221 if (CFStringGetLength(query_string) > 1)
222 format = CFSTR("&%@=%@");
223 else
224 format = CFSTR("%@=%@");
225
226 CFStringAppendFormat(query_string, NULL, format, escaped_key, escaped_value);
227 CFRelease(escaped_key);
228 CFRelease(escaped_value);
229 }
230
231 static CFURLRef build_url(CFStringRef base, CFDictionaryRef info)
232 {
233 CFURLRef url = NULL, base_url = NULL;
234 CFMutableStringRef query_string =
235 CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("?"));
236 require(query_string, out);
237 if (info)
238 CFDictionaryApplyFunction(info, _query_string_apply, query_string);
239 base_url = CFURLCreateWithString(kCFAllocatorDefault, base, NULL);
240 url = CFURLCreateWithString(kCFAllocatorDefault, query_string, base_url);
241 out:
242 CFReleaseSafe(base_url);
243 return url;
244 }
245
246 static 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 }
272 CFRelease(responseHeaders);
273 }
274 return isAuthenticationChallenge;
275 }
276
277 static CFHTTPMessageRef load_request(CFHTTPMessageRef request, CFMutableDataRef data, int retry)
278 {
279 CFHTTPMessageRef result = NULL;
280
281 if (retry < 0)
282 return result;
283
284 CFReadStreamRef rs;
285 rs = CFReadStreamCreateForHTTPRequest(NULL, request);
286
287 const void *keys[] = {
288 kCFStreamSSLValidatesCertificateChain,
289 // kCFStreamSSLCertificates,
290 };
291 //CFArrayRef ident = mit_identity();
292 const void *values[] = {
293 kCFBooleanFalse,
294 // ident,
295 };
296
297 CFDictionaryRef dict = CFDictionaryCreate(NULL, keys, values,
298 array_size(keys),
299 &kCFTypeDictionaryKeyCallBacks,
300 &kCFTypeDictionaryValueCallBacks);
301 CFReadStreamSetProperty(rs, kCFStreamPropertySSLSettings, dict);
302 CFRelease(dict);
303 CFReadStreamSetProperty(rs, kCFStreamPropertyHTTPAttemptPersistentConnection, kCFBooleanTrue);
304
305 if (CFReadStreamOpen(rs)) {
306 do {
307 if (auth_failed(request, rs)) {
308 CFReadStreamClose(rs);
309 CFDataSetLength(data, 0);
310 if (retry)
311 return load_request(request, data, retry - 1);
312 break;
313 }
314 UInt8 buf[BUFSIZE];
315 CFIndex bytesRead = CFReadStreamRead(rs, buf, BUFSIZE);
316 if (bytesRead > 0) {
317 CFDataAppendBytes(data, buf, bytesRead);
318 } else if (bytesRead == 0) {
319 // Success
320 result = (CFHTTPMessageRef)CFReadStreamCopyProperty(rs, kCFStreamPropertyHTTPResponseHeader);
321 break;
322 } else {
323 // Error
324 break;
325 }
326 } while (true);
327 } else {
328 // Error
329 }
330
331 CFReadStreamClose(rs);
332 CFRelease(rs);
333 if (debug)
334 CFShow(result);
335 return result;
336 }
337
338
339 static CFDictionaryRef get_encrypted_profile_packet(CFStringRef base_url)
340 {
341 #if 1
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);
347 CFRelease(cert);
348 CFRelease(key);
349 #else
350 SecIdentityRef identity = lockdown_copy_device_identity();
351 #endif
352
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);
357 if (cf_user) {
358 CFDictionarySetValue(machine_dict, CFSTR("USERNAME"), cf_user);
359 CFRelease(cf_user);
360 }
361 CFStringRef cf_pass = CFStringCreateWithCString(kCFAllocatorDefault, pass, kCFStringEncodingUTF8);
362 if (cf_pass) {
363 CFDictionarySetValue(machine_dict, CFSTR("PASSWORD"), cf_pass);
364 CFRelease(cf_pass);
365 }
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");
371 CFRelease(identity);
372 CFRelease(machine_dict_data);
373 CFRelease(machine_dict);
374
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);
383 CFRelease(request);
384 CFRelease(response);
385 CFErrorRef error = NULL;
386 CFTypeRef result = CFPropertyListCreateWithData(kCFAllocatorDefault,
387 data, kCFPropertyListImmutable, NULL, &error);
388 CFRelease(data);
389 if (error) {
390 CFShow(error);
391 errx(1, "failed to decode encrypted profile response");
392 CFRelease(error);
393 }
394 if (CFGetTypeID(result) != CFDictionaryGetTypeID())
395 CFReleaseNull(result);
396 return (CFDictionaryRef)result;
397 }
398
399 static SecCertificateRef get_ca_cert(CFStringRef scep_base_url, CFStringRef scep_ca_name)
400 {
401 SecCertificateRef cert = NULL;
402 CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0);
403
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);
408
409 if (!result)
410 return NULL;
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);
419 if (debug)
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);
425 if (debug)
426 write_data("/tmp/ca_cert_array.der", data);
427 cert = (SecCertificateRef)CFArrayGetValueAtIndex(cert_array, 0);
428 CFRetain(cert);
429 CFRelease(cert_array);
430 }
431 CFRelease(contentTypeValue);
432 CFRelease(data);
433 return cert;
434 }
435
436
437 static SecIdentityRef perform_scep(CFDictionaryRef scep_dict)
438 {
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") };
446
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);
454
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);
463 }
464
465 scep_key_bitsize =
466 dict_get_value_of_type(scep_dict, CFSTR("KEYSIZE"), CFNumberGetTypeID());
467 if (!scep_key_bitsize)
468 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;
472
473 parameters = CFDictionaryCreate(kCFAllocatorDefault,
474 keygen_keys, keygen_vals, array_size(keygen_vals),
475 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
476
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);
483
484 SecCertificateRef ca_cert = get_ca_cert(scep_base_url, scep_instance_name ? scep_instance_name : CFSTR("test"));
485 if (!ca_cert)
486 errx(1, "no ca cert returned from scep server.");
487
488 identity = NULL; // enroll_scep(scep_base_url, scep_subject, csr_parameters, parameters, ca_cert);
489 if (!identity)
490 errx(1, "failed to get identity from scep server.");
491
492 out:
493 CFReleaseSafe(parameters);
494 return identity;
495 }
496
497 static CFDataRef get_profile(CFStringRef url_cfstring, SecIdentityRef identity)
498 {
499 CFURLRef url = NULL;
500 CFHTTPMessageRef request = NULL;
501 SecCertificateRef cert = NULL;
502 CFDataRef cert_data = NULL;
503 CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0);
504 CFHTTPMessageRef response = NULL;
505
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);
515 if (debug && data)
516 CFShow(data);
517 out:
518 //CFReleaseSafe(response);
519 CFReleaseSafe(request);
520 CFReleaseSafe(url);
521 CFReleaseSafe(cert_data);
522 CFReleaseSafe(cert);
523 CFReleaseSafe(response);
524 return data;
525
526 }
527
528 static bool validate_profile(CFDataRef profile_plist_data, SecIdentityRef identity)
529 {
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"),
540 CFDataGetTypeID());
541 if (enc_payload) {
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);
546 return sub;
547 } else {
548 if (debug)
549 write_data("/tmp/unencrypted_profile.mobileconfig", profile_plist_data);
550 //CFDictionaryRef sub_conf = dict_get_value_of_type(result, CFSTR("PayloadContent"), CFDictionaryGetTypeID());
551 }
552 return true;
553 out:
554 return false;
555 }
556
557 #if 0
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\
562 <dict>\n\
563 <key>PayloadContent</key>\n\
564 <dict>\n\
565 <key>URL</key>\n\
566 <string>https://phone.vpn.apple.com/deviceid/</string>\n\
567 <key>DeviceAttributes</key>\n\
568 <array>\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\
573 </array>\n\
574 <key>CHALLENGE</key>\n\
575 <string>${USER_COOKIE}</string>\n\
576 </dict>\n\
577 <key>PayloadType</key>\n\
578 <string>Device Identification</string>\n\
579 </dict>\n\
580 </plist>\n";
581
582 static void annotate_machine_info(const void *value, void *context)
583 {
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"))) {
591
592 }
593 out:
594 return;
595 }
596
597 static void machine_authentication(CFDataRef req, CFDataRef reply)
598 {
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);
605
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);
609
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());
614 if (challenge)
615 CFDictionarySetValue(auth_reply_dict, CFSTR("CHALLENGE"), challenge);
616 CFArrayRef device_info = dict_get_value_of_type(auth_dict, CFSTR("DeviceAttributes"), CFArrayGetTypeID());
617 if (device_info)
618 CFArrayApplyFunction(device_info, CFRangeMake(0, CFArrayGetCount(device_info)),
619 annotate_machine_info, auth_reply_dict);
620
621 // make copy of reply dict
622 out:
623 CFReleaseSafe(machine_auth_request);
624 CFReleaseSafe(auth_request_dict);
625 }
626 #endif
627
628 extern int command_spc(int argc, char * const *argv)
629 {
630 SecIdentityRef identity = NULL;
631 extern char *optarg;
632 extern int optind;
633 int arg;
634 while ((arg = getopt(argc, argv, "du:p:")) != -1) {
635 switch (arg) {
636 case 'd':
637 debug = 1;
638 break;
639 case 'u':
640 user = optarg;
641 break;
642 case 'p':
643 pass = optarg;
644 break;
645 case 'h':
646 default:
647 return 2;
648 }
649 }
650
651 argc -= optind;
652 argv += optind;
653
654 #if 0
655 if (argc == 1) {
656 // get plist from argv[0] url
657 } else if (argc == 0) {
658 machine_authentication(NULL, NULL);
659 } else return 2;
660 #endif
661
662 if (argc != 1)
663 return 2;
664
665 CFStringRef machine_id_url_cfstring = CFStringCreateWithCString(kCFAllocatorDefault,
666 argv[0], kCFStringEncodingUTF8);
667
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);
681 CFReleaseSafe(dict);
682 CFStringRef profile_url = NULL;
683 require(profile_url = dict_get_value_of_type(payload_content,
684 CFSTR("URL"), CFStringGetTypeID()), out);
685
686 CFDataRef profile_data = NULL;
687 require(profile_data = get_profile(profile_url, identity), out);
688 CFDataRef profile_plist = NULL;
689 if (debug)
690 write_data("/tmp/profile.mobileconfig", profile_data);
691
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);
696
697 return 0;
698 out:
699 errx(1, "fail.");
700 return -1;
701 }
702
703
704 #endif // TARGET_OS_EMBEDDED